Compare commits
60 Commits
Author | SHA1 | Date | |
---|---|---|---|
c5ebc89e4f | |||
dfc1719cce | |||
0812259470 | |||
e1476c5840 | |||
e30ea28e3f | |||
4a6d3aab7f | |||
8157146498 | |||
94d23888b1 | |||
737fe9bb4a | |||
0051ed2e73 | |||
e0595957e2 | |||
8d09ff7fdb | |||
04feb66b07 | |||
54b2ac7f24 | |||
12356a35fa | |||
12262304ac | |||
c58f97452e | |||
eb3872f7a6 | |||
9fa178d513 | |||
043b184065 | |||
10559bb894 | |||
d0000d66b2 | |||
b447ac738a | |||
faebfc238c | |||
c28fbd37cc | |||
4b8396959d | |||
b39d510e07 | |||
286dda7f80 | |||
7bda896e2d | |||
ba4feeea87 | |||
6f52eae3c6 | |||
40ea8d56e6 | |||
72e562e8a8 | |||
6fa01bfe19 | |||
0ef59c9b91 | |||
d768d2232b | |||
b44a200731 | |||
016815e0d1 | |||
590534e4a6 | |||
7ea9d4e519 | |||
e0ab09f533 | |||
fbe98f1b16 | |||
d0675b8443 | |||
3ea1ed02ae | |||
ba120b1e0b | |||
acf6995c2d | |||
8306860f90 | |||
65974166be | |||
ee8924f986 | |||
170e575465 | |||
b7d5317b10 | |||
f12e7748c5 | |||
69a2418afc | |||
4924ddd172 | |||
1889b43786 | |||
f2e38a4203 | |||
90a8fac8d4 | |||
04402c5ab9 | |||
f8f710df99 | |||
b8105bb6fb |
37
.github/CONTRIBUTING.md
vendored
@ -22,7 +22,8 @@ Always check if the web version of your instance is working.
|
|||||||
### Bug reports/Feature request
|
### Bug reports/Feature request
|
||||||
|
|
||||||
* Always search before reporting an issue or asking for a feature to avoid duplicates.
|
* Always search before reporting an issue or asking for a feature to avoid duplicates.
|
||||||
* Include every usefull details (app version, phone model, Android version and screenshots when possible)
|
* Include your unique user id. It's displayed on the debug settings page. (You can tap it, it'll be copied to your clipboard)
|
||||||
|
* Include every other useful details (app version, phone model, Android version and screenshots when possible).
|
||||||
* Avoid bumping non-fatal issues, or feature requests. I'll try to fix them as soon as possible, and try to prioritize the requests. (You may wan to use the [reactions](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments) for that)
|
* Avoid bumping non-fatal issues, or feature requests. I'll try to fix them as soon as possible, and try to prioritize the requests. (You may wan to use the [reactions](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments) for that)
|
||||||
|
|
||||||
### Pull requests
|
### Pull requests
|
||||||
@ -38,18 +39,38 @@ Always check if the web version of your instance is working.
|
|||||||
* Be willing to accept criticism on your PRs (as I am on mine).
|
* Be willing to accept criticism on your PRs (as I am on mine).
|
||||||
* Remember that PR review can take time.
|
* Remember that PR review can take time.
|
||||||
|
|
||||||
|
|
||||||
# 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:
|
||||||
|
|
||||||
- [Create your own launcher icon](https://developer.android.com/studio/write/image-asset-studio.html#creating-launcher)
|
- 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 the following some parameters either in `~/.gradle/gradle.properties` or as gradle parameters (see the examples)
|
||||||
|
|
||||||
- Configure Fabric, or [remove it](https://docs.fabric.io/android/fabric/settings/removing.html#).
|
- mercuryApiKey: A [Mercury](https://mercury.postlight.com/web-parser/) web parser api key for the internal browser
|
||||||
- Define the following in `res/values/strings.xml` or create `res/values/secrets.xml`
|
- 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.**
|
||||||
|
- 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.**
|
||||||
|
|
||||||
- mercury: A [Mercury](https://mercury.postlight.com/web-parser/) web parser api key for the internal browser
|
### Examples:
|
||||||
- feedback_email: An email to receive users feedback.
|
#### Inside ~/.gradle/gradle.properties
|
||||||
- source_url: an url to the source code, used in the settings
|
|
||||||
- tracker_url: an url to the tracker, used in the settings
|
```
|
||||||
|
appLoginUrl="URL" # It can be empty.
|
||||||
|
appLoginUsername="LOGIN" # 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.
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 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"
|
||||||
|
```
|
||||||
|
5
.gitignore
vendored
@ -214,7 +214,6 @@ gradle-app.setting
|
|||||||
|
|
||||||
# End of https://www.gitignore.io/api/java,gradle,android,androidstudio
|
# End of https://www.gitignore.io/api/java,gradle,android,androidstudio
|
||||||
|
|
||||||
secrets.xml
|
|
||||||
|
|
||||||
mipmap-*
|
|
||||||
release/
|
release/
|
||||||
|
|
||||||
|
crowdin.properties
|
127
CHANGELOG.md
@ -1,4 +1,129 @@
|
|||||||
**1.5.1.3**
|
**1.5.3.06**
|
||||||
|
|
||||||
|
- Fixed infinite scroll not working.
|
||||||
|
|
||||||
|
- Fixed logs not working.
|
||||||
|
|
||||||
|
- Temporary workaround handling opening invalid urls. Waiting to solve #83.
|
||||||
|
|
||||||
|
**1.5.3.05**
|
||||||
|
|
||||||
|
- Fixed an issue on older versions of Android.
|
||||||
|
|
||||||
|
- Libs update.
|
||||||
|
|
||||||
|
**1.5.3.04**
|
||||||
|
|
||||||
|
- Crowdin translations
|
||||||
|
|
||||||
|
**1.5.3.03**
|
||||||
|
|
||||||
|
- Libs updates.
|
||||||
|
|
||||||
|
- Translation fix.
|
||||||
|
|
||||||
|
**1.5.3.01/02**
|
||||||
|
|
||||||
|
- Added translation link to the settings page.
|
||||||
|
|
||||||
|
- Added the translation link to the README.
|
||||||
|
|
||||||
|
**1.5.3.00**
|
||||||
|
|
||||||
|
- (BETA) Added pull from bottom to load more pages of results. May be buggy.
|
||||||
|
|
||||||
|
**1.5.2.18/19**
|
||||||
|
|
||||||
|
- APK minification finally working. That means less space taken !
|
||||||
|
- Added an option to log every API call.
|
||||||
|
|
||||||
|
**1.5.2.17**
|
||||||
|
|
||||||
|
- Source code and tracker links weren't being set, and updated the contributing doc.
|
||||||
|
|
||||||
|
**1.5.2.15/16**
|
||||||
|
|
||||||
|
- Adding an account header on the lateral drawer.
|
||||||
|
|
||||||
|
- The account header is only displayed when the setting is enabled.
|
||||||
|
|
||||||
|
**1.5.2.13/14**
|
||||||
|
|
||||||
|
- Updated glide.
|
||||||
|
|
||||||
|
- Loading images from self signed certificate now working.
|
||||||
|
|
||||||
|
**1.5.2.12**
|
||||||
|
|
||||||
|
- Self signed certificates are now working for loading data. Image are not loading yet.
|
||||||
|
|
||||||
|
**1.5.2.11**
|
||||||
|
|
||||||
|
- Added a random unique identifier to be used in the logs.
|
||||||
|
|
||||||
|
**1.5.2.08/09/10**
|
||||||
|
|
||||||
|
- Added settable logs for reading articles problems.
|
||||||
|
|
||||||
|
**1.5.2.07**
|
||||||
|
|
||||||
|
- Added the ability to choose the number of items loaded (the maximum value is 200 and is imposed by the selfoss api)
|
||||||
|
|
||||||
|
**1.5.2.06**
|
||||||
|
|
||||||
|
- Fix problem introduced in 1.5.2.04. SVG file not working on older versions of android.
|
||||||
|
|
||||||
|
**1.5.2.05**
|
||||||
|
|
||||||
|
- Versions updates
|
||||||
|
|
||||||
|
**1.5.2.04**
|
||||||
|
|
||||||
|
- Reverted to the old icon.
|
||||||
|
|
||||||
|
- Better icon for the intro activity.
|
||||||
|
|
||||||
|
- Updated gradle version.
|
||||||
|
|
||||||
|
**1.5.2.03**
|
||||||
|
|
||||||
|
- Added the ability to accept self signed certificates. (Needs more testing)
|
||||||
|
|
||||||
|
**1.5.2.02**
|
||||||
|
|
||||||
|
- Added optional login option.
|
||||||
|
|
||||||
|
**1.5.2.01**
|
||||||
|
|
||||||
|
- New (Better) Icon !
|
||||||
|
|
||||||
|
**1.5.2.0**
|
||||||
|
|
||||||
|
- New Icon !
|
||||||
|
|
||||||
|
**1.5.1.9/10/11**
|
||||||
|
|
||||||
|
- Hiding the unread badge when marking all items as read.
|
||||||
|
|
||||||
|
**1.5.1.8**
|
||||||
|
|
||||||
|
- Fixes and libs updates.
|
||||||
|
|
||||||
|
**1.5.1.7**
|
||||||
|
|
||||||
|
- Bug fixes.
|
||||||
|
|
||||||
|
- Code cleaning
|
||||||
|
|
||||||
|
**1.5.1.6**
|
||||||
|
|
||||||
|
- Added back the badges after it was fixed on the library side.
|
||||||
|
|
||||||
|
**1.5.1.5**
|
||||||
|
|
||||||
|
- THEMES !!!! For now, the app has predefined themes. You can ask for new ones until I make them dynamic.
|
||||||
|
|
||||||
|
**1.5.1.3/4**
|
||||||
|
|
||||||
- Fixes introduces by the previous alpha (1.5.1.2)
|
- Fixes introduces by the previous alpha (1.5.1.2)
|
||||||
|
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
# ReaderForSelfoss
|
# ReaderForSelfoss
|
||||||
|
|
||||||
[](https://circleci.com/gh/aminecmi/ReaderforSelfoss/tree/master)
|
[](https://crowdin.com/project/readerforselfoss) [](https://gitter.im/amine-bou/ReaderForSelfoss)
|
||||||
|
|
||||||
[](https://codebeat.co/projects/github-com-aminecmi-readerforselfoss-master)
|
[](http://jenkins.amine-bou.fr/job/ReaderForSelfoss/)
|
||||||
|
|
||||||
[](https://www.codetriage.com/aminecmi/readerforselfoss)
|
[](https://codebeat.co/projects/github-com-aminecmi-readerforselfoss-master) [](https://www.codetriage.com/aminecmi/readerforselfoss)
|
||||||
|
|
||||||
This is the repo of [Reader For Selfoss](https://play.google.com/store/apps/details?id=apps.amine.bou.readerforselfoss&hl=en).
|
This is the repo of [Reader For Selfoss](https://play.google.com/store/apps/details?id=apps.amine.bou.readerforselfoss&hl=en).
|
||||||
|
|
||||||
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).
|
||||||
|
|
||||||
|
|
||||||
## Want to help ?
|
## Want to help ?
|
||||||
|
|
||||||
|
105
app/build.gradle
@ -8,6 +8,23 @@ buildscript {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def gitVersion() {
|
||||||
|
def process = "git describe --abbrev=0 --tags".execute()
|
||||||
|
return process.text.substring(1).replaceAll("\\.", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
def versionCodeFromGit() {
|
||||||
|
println "version code " + gitVersion().toInteger()
|
||||||
|
return gitVersion().toInteger()
|
||||||
|
}
|
||||||
|
|
||||||
|
def versionNameFromGit() {
|
||||||
|
println "version code " + gitVersion().trim()
|
||||||
|
return gitVersion().trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'org.sonarqube'
|
||||||
|
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
apply plugin: 'io.fabric'
|
apply plugin: 'io.fabric'
|
||||||
@ -15,18 +32,20 @@ apply plugin: 'io.fabric'
|
|||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven { url 'https://maven.fabric.io/public' }
|
maven {
|
||||||
|
url 'https://maven.fabric.io/public'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 26
|
compileSdkVersion 26
|
||||||
buildToolsVersion "26.0.0"
|
buildToolsVersion '26.0.2'
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "apps.amine.bou.readerforselfoss"
|
applicationId "apps.amine.bou.readerforselfoss"
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 25
|
targetSdkVersion 26
|
||||||
versionCode 1513
|
versionCode versionCodeFromGit()
|
||||||
versionName "1.5.1.3"
|
versionName versionNameFromGit()
|
||||||
|
|
||||||
// Enabling multidex support.
|
// Enabling multidex support.
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
@ -38,10 +57,17 @@ android {
|
|||||||
|
|
||||||
// tests
|
// tests
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
|
buildConfigField "String", "MERCURY_KEY", mercuryApiKey
|
||||||
|
buildConfigField "String", "FEEDBACK_EMAIL", feedbackEmail
|
||||||
|
buildConfigField "String", "SOURCE_URL", sourceUrl
|
||||||
|
buildConfigField "String", "TRACKER_URL", trackerUrl
|
||||||
|
buildConfigField "String", "TRANSLATION_URL", translationUrl
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled false
|
minifyEnabled true
|
||||||
|
shrinkResources true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'),
|
proguardFiles getDefaultProguardFile('proguard-android.txt'),
|
||||||
'proguard-rules.pro'
|
'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
@ -68,74 +94,78 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// Testing
|
// Testing
|
||||||
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
|
androidTestCompile 'com.android.support.test.espresso:espresso-core:3.0.0'
|
||||||
androidTestCompile 'com.android.support.test:runner:0.5'
|
androidTestCompile 'com.android.support.test:runner:1.0.0'
|
||||||
// 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:2.2.2'
|
androidTestCompile 'com.android.support.test.espresso:espresso-contrib:3.0.0'
|
||||||
// Espresso-intents for validation and stubbing of Intents
|
// Espresso-intents for validation and stubbing of Intents
|
||||||
androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'
|
androidTestCompile 'com.android.support.test.espresso:espresso-intents:3.0.0'
|
||||||
|
|
||||||
|
|
||||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
|
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
|
||||||
|
|
||||||
// Android Support
|
// Android Support
|
||||||
compile 'com.android.support:appcompat-v7:26.0.0-beta2'
|
compile 'com.android.support:appcompat-v7:26.0.1'
|
||||||
compile 'com.android.support:design:26.0.0-beta2'
|
compile 'com.android.support:design:26.0.1'
|
||||||
compile 'com.android.support:recyclerview-v7:26.0.0-beta2'
|
compile 'com.android.support:recyclerview-v7:26.0.1'
|
||||||
compile 'com.android.support:support-v4:26.0.0-beta2'
|
compile 'com.android.support:support-v4:26.0.1'
|
||||||
compile 'com.android.support:support-vector-drawable:26.0.0-beta2'
|
compile 'com.android.support:support-vector-drawable:26.0.1'
|
||||||
compile 'com.android.support:customtabs:26.0.0-beta2'
|
compile 'com.android.support:customtabs:26.0.1'
|
||||||
compile 'com.android.support:cardview-v7:26.0.0-beta2'
|
compile 'com.android.support:cardview-v7:26.0.1'
|
||||||
compile 'com.android.support.constraint:constraint-layout:1.0.2'
|
compile 'com.android.support.constraint:constraint-layout:1.0.2'
|
||||||
|
|
||||||
// Firebase + crashlytics
|
// Firebase + crashlytics
|
||||||
compile 'com.google.firebase:firebase-core:11.0.1'
|
compile 'com.google.firebase:firebase-core:11.2.0'
|
||||||
compile 'com.google.firebase:firebase-config:11.0.1'
|
compile 'com.google.firebase:firebase-config:11.2.0'
|
||||||
compile 'com.google.firebase:firebase-invites:11.0.1'
|
compile 'com.google.firebase:firebase-invites:11.2.0'
|
||||||
compile('com.crashlytics.sdk.android:crashlytics:2.6.8@aar') {
|
compile('com.crashlytics.sdk.android:crashlytics:2.7.1@aar') {
|
||||||
transitive = true
|
transitive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//multidex
|
//multidex
|
||||||
compile 'com.android.support:multidex:1.0.1'
|
compile 'com.android.support:multidex:1.0.2'
|
||||||
|
|
||||||
// Intro
|
// Intro
|
||||||
compile 'agency.tango.android:material-intro-screen:0.0.5'
|
compile 'agency.tango.android:material-intro-screen:0.0.5'
|
||||||
|
|
||||||
// About
|
// About
|
||||||
compile('com.mikepenz:aboutlibraries:5.9.6@aar') {
|
compile('com.mikepenz:aboutlibraries:5.9.7@aar') {
|
||||||
transitive = true
|
transitive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrofit + http logging + okhttp
|
// Retrofit + http logging + okhttp
|
||||||
compile 'com.squareup.retrofit2:retrofit:2.3.0'
|
compile 'com.squareup.retrofit2:retrofit:2.3.0'
|
||||||
compile 'com.squareup.okhttp3:logging-interceptor:3.8.0'
|
compile 'com.squareup.okhttp3:logging-interceptor:3.9.0'
|
||||||
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
|
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
|
||||||
compile 'com.burgstaller:okhttp-digest:1.12'
|
compile 'com.burgstaller:okhttp-digest:1.12'
|
||||||
|
|
||||||
// Material-ish things
|
// Material-ish things
|
||||||
compile 'com.roughike:bottom-bar:2.3.1'
|
compile 'com.ashokvarma.android:bottom-navigation-bar:2.0.3'
|
||||||
compile 'com.melnykov:floatingactionbutton:1.3.0'
|
compile 'com.melnykov:floatingactionbutton:1.3.0'
|
||||||
compile 'com.github.jd-alexander:LikeButton:0.2.1'
|
compile 'com.github.jd-alexander:LikeButton:0.2.1'
|
||||||
compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
|
compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
|
||||||
compile 'org.sufficientlysecure:html-textview:3.3'
|
compile 'org.sufficientlysecure:html-textview:3.3'
|
||||||
|
|
||||||
// glide
|
// glide
|
||||||
compile 'com.github.bumptech.glide:glide:3.7.0'
|
compile 'com.github.bumptech.glide:glide:4.1.1'
|
||||||
|
compile 'com.github.bumptech.glide:okhttp3-integration:4.1.1'
|
||||||
|
|
||||||
// Asking politely users to rate the app
|
// Asking politely users to rate the app
|
||||||
compile 'com.github.stkent:amplify:1.5.0'
|
compile 'com.github.stkent:amplify:2.1.0'
|
||||||
|
|
||||||
// For the article reader
|
// For the article reader
|
||||||
compile 'com.klinkerapps:drag-dismiss-activity:1.4.1'
|
compile 'com.klinkerapps:drag-dismiss-activity:1.5.0'
|
||||||
|
|
||||||
// Drawer
|
// Drawer
|
||||||
compile('com.mikepenz:materialdrawer:5.9.3@aar') {
|
compile('com.mikepenz:materialdrawer:5.9.5@aar') {
|
||||||
transitive = true
|
transitive = true
|
||||||
}
|
}
|
||||||
compile 'com.anupcowkur:reservoir:3.1.0'
|
compile 'com.anupcowkur:reservoir:3.1.0'
|
||||||
|
|
||||||
|
// Themes
|
||||||
|
compile 'com.52inc:scoops:1.0.0'
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'com.google.gms.google-services'
|
apply plugin: 'com.google.gms.google-services'
|
||||||
@ -144,6 +174,7 @@ apply plugin: 'com.google.gms.google-services'
|
|||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
initFabricPropertiesIfNeeded()
|
initFabricPropertiesIfNeeded()
|
||||||
initAppLoginPropertiesIfNeeded()
|
initAppLoginPropertiesIfNeeded()
|
||||||
|
initAppForSecretPropertiesIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
def initFabricPropertiesIfNeeded() {
|
def initFabricPropertiesIfNeeded() {
|
||||||
@ -168,3 +199,17 @@ def initAppLoginPropertiesIfNeeded() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
13
app/proguard-rules.pro
vendored
@ -57,3 +57,16 @@
|
|||||||
|
|
||||||
#Bottom bar lib
|
#Bottom bar lib
|
||||||
-dontwarn com.roughike.bottombar.**
|
-dontwarn com.roughike.bottombar.**
|
||||||
|
|
||||||
|
|
||||||
|
# self signed glidemodule
|
||||||
|
-keep public class * implements com.bumptech.glide.module.GlideModule
|
||||||
|
-keep public class * extends com.bumptech.glide.AppGlideModule
|
||||||
|
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
|
||||||
|
**[] $VALUES;
|
||||||
|
public *;
|
||||||
|
}
|
||||||
|
|
||||||
|
-dontwarn com.anupcowkur.reservoir.**
|
||||||
|
|
||||||
|
-dontwarn javax.annotation.**
|
@ -86,7 +86,7 @@ class HomeActivityEspressoTest {
|
|||||||
|
|
||||||
intended(hasComponent(LoginActivity::class.java.name), times(1))
|
intended(hasComponent(LoginActivity::class.java.name), times(1))
|
||||||
|
|
||||||
onView(isRoot()).perform(pressBack())
|
//onView(isRoot()).perform(pressBack())
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ class IntroActivityEspressoTest {
|
|||||||
Intents.init()
|
Intents.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
/*@Test
|
||||||
fun nextEachTimes() {
|
fun nextEachTimes() {
|
||||||
|
|
||||||
rule.launchActivity(Intent())
|
rule.launchActivity(Intent())
|
||||||
@ -61,7 +61,7 @@ class IntroActivityEspressoTest {
|
|||||||
intended(hasComponent(IntroActivity::class.java.name), times(1))
|
intended(hasComponent(IntroActivity::class.java.name), times(1))
|
||||||
intended(hasComponent(LoginActivity::class.java.name), times(1))
|
intended(hasComponent(LoginActivity::class.java.name), times(1))
|
||||||
|
|
||||||
}
|
}*/
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun nextBackRandomTimes() {
|
fun nextBackRandomTimes() {
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
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:theme="@style/AppTheme">
|
android:theme="@style/NoBar">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:theme="@style/SplashTheme">
|
android:theme="@style/SplashTheme">
|
||||||
@ -28,11 +28,11 @@
|
|||||||
android:name=".IntroActivity"
|
android:name=".IntroActivity"
|
||||||
android:theme="@style/Theme.Intro">
|
android:theme="@style/Theme.Intro">
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".LoginActivity"
|
<activity
|
||||||
|
android:name=".LoginActivity"
|
||||||
android:label="@string/title_activity_login">
|
android:label="@string/title_activity_login">
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".HomeActivity"
|
<activity android:name=".HomeActivity">
|
||||||
android:theme="@style/NoBar">
|
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".settings.SettingsActivity"
|
android:name=".settings.SettingsActivity"
|
||||||
@ -42,13 +42,15 @@
|
|||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="apps.amine.bou.readerforselfoss.HomeActivity" />
|
android:value="apps.amine.bou.readerforselfoss.HomeActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".SourcesActivity"
|
<activity
|
||||||
|
android:name=".SourcesActivity"
|
||||||
android:parentActivityName=".HomeActivity">
|
android:parentActivityName=".HomeActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".HomeActivity" />
|
android:value=".HomeActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".AddSourceActivity"
|
<activity
|
||||||
|
android:name=".AddSourceActivity"
|
||||||
android:parentActivityName=".SourcesActivity">
|
android:parentActivityName=".SourcesActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
@ -62,9 +64,14 @@
|
|||||||
<data android:mimeType="text/plain" />
|
<data android:mimeType="text/plain" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".ReaderActivity"
|
<activity
|
||||||
|
android:name=".ReaderActivity"
|
||||||
android:theme="@style/DragDismissTheme">
|
android:theme="@style/DragDismissTheme">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="apps.amine.bou.readerforselfoss.utils.glide.SelfSignedGlideModule"
|
||||||
|
android:value="GlideModule" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
BIN
app/src/main/ic_launcher-web.png
Normal file
After Width: | Height: | Size: 20 KiB |
@ -2,8 +2,10 @@ 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.support.constraint.ConstraintLayout
|
import android.support.constraint.ConstraintLayout
|
||||||
import android.support.v7.app.AppCompatActivity
|
import android.support.v7.app.AppCompatActivity
|
||||||
|
import android.support.v7.widget.Toolbar
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
|
|
||||||
@ -15,8 +17,8 @@ import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
|
|||||||
import apps.amine.bou.readerforselfoss.api.selfoss.Spout
|
import apps.amine.bou.readerforselfoss.api.selfoss.Spout
|
||||||
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
|
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
|
||||||
import apps.amine.bou.readerforselfoss.utils.Config
|
import apps.amine.bou.readerforselfoss.utils.Config
|
||||||
import apps.amine.bou.readerforselfoss.utils.isUrlValid
|
import apps.amine.bou.readerforselfoss.utils.isBaseUrlValid
|
||||||
|
import com.ftinc.scoop.Scoop
|
||||||
|
|
||||||
|
|
||||||
class AddSourceActivity : AppCompatActivity() {
|
class AddSourceActivity : AppCompatActivity() {
|
||||||
@ -25,7 +27,12 @@ class AddSourceActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
Scoop.getInstance().apply(this)
|
||||||
setContentView(R.layout.activity_add_source)
|
setContentView(R.layout.activity_add_source)
|
||||||
|
val toolbar: Toolbar = findViewById(R.id.toolbar)
|
||||||
|
setSupportActionBar(toolbar)
|
||||||
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||||
|
|
||||||
val mProgress: ProgressBar = findViewById(R.id.progress)
|
val mProgress: ProgressBar = findViewById(R.id.progress)
|
||||||
val mForm: ConstraintLayout = findViewById(R.id.formContainer)
|
val mForm: ConstraintLayout = findViewById(R.id.formContainer)
|
||||||
@ -37,7 +44,8 @@ class AddSourceActivity : AppCompatActivity() {
|
|||||||
var api: SelfossApi? = null
|
var api: SelfossApi? = null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
api = SelfossApi(this, this@AddSourceActivity)
|
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
api = SelfossApi(this, this@AddSourceActivity, prefs.getBoolean("isSelfSignedCert", false), prefs.getBoolean("should_log_everything", false))
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (e: IllegalArgumentException) {
|
||||||
mustLoginToAddSource()
|
mustLoginToAddSource()
|
||||||
}
|
}
|
||||||
@ -67,7 +75,7 @@ class AddSourceActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
val config = Config(this)
|
val config = Config(this)
|
||||||
|
|
||||||
if (config.baseUrl.isEmpty() || !config.baseUrl.isUrlValid()) {
|
if (config.baseUrl.isEmpty() || !config.baseUrl.isBaseUrlValid()) {
|
||||||
mustLoginToAddSource()
|
mustLoginToAddSource()
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
@ -43,8 +43,6 @@ import com.mikepenz.materialdrawer.holder.BadgeStyle
|
|||||||
import com.mikepenz.materialdrawer.model.DividerDrawerItem
|
import com.mikepenz.materialdrawer.model.DividerDrawerItem
|
||||||
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
|
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
|
||||||
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem
|
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem
|
||||||
import com.roughike.bottombar.BottomBar
|
|
||||||
import com.roughike.bottombar.BottomBarTab
|
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.Callback
|
import retrofit2.Callback
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
@ -53,13 +51,22 @@ import apps.amine.bou.readerforselfoss.adapters.ItemCardAdapter
|
|||||||
import apps.amine.bou.readerforselfoss.adapters.ItemListAdapter
|
import apps.amine.bou.readerforselfoss.adapters.ItemListAdapter
|
||||||
import apps.amine.bou.readerforselfoss.api.selfoss.*
|
import apps.amine.bou.readerforselfoss.api.selfoss.*
|
||||||
import apps.amine.bou.readerforselfoss.settings.SettingsActivity
|
import apps.amine.bou.readerforselfoss.settings.SettingsActivity
|
||||||
|
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.bottombar.maybeShow
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.bottombar.removeBadge
|
||||||
import apps.amine.bou.readerforselfoss.utils.checkAndDisplayStoreApk
|
import apps.amine.bou.readerforselfoss.utils.checkAndDisplayStoreApk
|
||||||
import apps.amine.bou.readerforselfoss.utils.checkApkVersion
|
import apps.amine.bou.readerforselfoss.utils.checkApkVersion
|
||||||
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
|
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
|
||||||
import apps.amine.bou.readerforselfoss.utils.drawer.CustomUrlPrimaryDrawerItem
|
import apps.amine.bou.readerforselfoss.utils.drawer.CustomUrlPrimaryDrawerItem
|
||||||
import apps.amine.bou.readerforselfoss.utils.longHash
|
import apps.amine.bou.readerforselfoss.utils.longHash
|
||||||
|
import com.ashokvarma.bottomnavigation.BottomNavigationBar
|
||||||
|
import com.ashokvarma.bottomnavigation.BottomNavigationItem
|
||||||
|
import com.ashokvarma.bottomnavigation.TextBadgeItem
|
||||||
|
import com.ftinc.scoop.Scoop
|
||||||
|
import com.mikepenz.materialdrawer.AccountHeader
|
||||||
|
import com.mikepenz.materialdrawer.AccountHeaderBuilder
|
||||||
|
import com.mikepenz.materialdrawer.model.ProfileDrawerItem
|
||||||
|
|
||||||
|
|
||||||
class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||||
@ -76,32 +83,43 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
|
|
||||||
private var items: ArrayList<Item> = ArrayList()
|
private var items: ArrayList<Item> = ArrayList()
|
||||||
private var clickBehavior = false
|
private var clickBehavior = false
|
||||||
|
private var debugReadingItems = false
|
||||||
private var internalBrowser = false
|
private var internalBrowser = false
|
||||||
private var articleViewer = false
|
private var articleViewer = false
|
||||||
private var shouldBeCardView = false
|
private var shouldBeCardView = false
|
||||||
private var displayUnreadCount = false
|
private var displayUnreadCount = false
|
||||||
private var displayAllCount = false
|
private var displayAllCount = false
|
||||||
private var fullHeightCards: Boolean = false
|
private var fullHeightCards: Boolean = false
|
||||||
|
private var itemsNumber: Int = 200
|
||||||
private var elementsShown: Int = 0
|
private var elementsShown: Int = 0
|
||||||
private var maybeTagFilter: Tag? = null
|
private var maybeTagFilter: Tag? = null
|
||||||
private var maybeSourceFilter: Sources? = null
|
private var maybeSourceFilter: Sources? = null
|
||||||
private var maybeSearchFilter: String? = null
|
private var maybeSearchFilter: String? = null
|
||||||
|
private var userIdentifier: String = ""
|
||||||
|
private var displayAccountHeader: Boolean = false
|
||||||
|
private var infiniteScroll: Boolean = false
|
||||||
|
|
||||||
private lateinit var emptyText: TextView
|
private lateinit var emptyText: TextView
|
||||||
private lateinit var mRecyclerView: RecyclerView
|
private lateinit var recyclerView: RecyclerView
|
||||||
private lateinit var mBottomBar: BottomBar
|
private lateinit var bottomBar: BottomNavigationBar
|
||||||
private lateinit var mCoordinatorLayout: CoordinatorLayout
|
private lateinit var coordinatorLayout: CoordinatorLayout
|
||||||
private lateinit var mSwipeRefreshLayout: SwipeRefreshLayout
|
private lateinit var swipeRefreshLayout: SwipeRefreshLayout
|
||||||
private lateinit var tabNew: BottomBarTab
|
private lateinit var tabNewBadge: TextBadgeItem
|
||||||
private lateinit var tabArchive: BottomBarTab
|
private lateinit var tabArchiveBadge: TextBadgeItem
|
||||||
private lateinit var tabStarred: BottomBarTab
|
private lateinit var tabStarredBadge: TextBadgeItem
|
||||||
private lateinit var toolbar: Toolbar
|
private lateinit var toolbar: Toolbar
|
||||||
private lateinit var drawer: Drawer
|
private lateinit var drawer: Drawer
|
||||||
private lateinit var api: SelfossApi
|
private lateinit var api: SelfossApi
|
||||||
private lateinit var mCustomTabActivityHelper: CustomTabActivityHelper
|
private lateinit var customTabActivityHelper: CustomTabActivityHelper
|
||||||
private lateinit var editor: SharedPreferences.Editor
|
private lateinit var editor: SharedPreferences.Editor
|
||||||
private lateinit var sharedPref: SharedPreferences
|
private lateinit var sharedPref: SharedPreferences
|
||||||
private lateinit var mFirebaseRemoteConfig: FirebaseRemoteConfig
|
private lateinit var firebaseRemoteConfig: FirebaseRemoteConfig
|
||||||
|
private lateinit var appColors: AppColors
|
||||||
|
private var offset: Int = 0
|
||||||
|
private var firstVisible: Int = 0
|
||||||
|
private var recyclerViewScrollListener: RecyclerView.OnScrollListener? = null
|
||||||
|
private lateinit var settings: SharedPreferences
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -111,11 +129,14 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
mCustomTabActivityHelper.bindCustomTabsService(this)
|
customTabActivityHelper.bindCustomTabsService(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
Scoop.getInstance().apply(this)
|
||||||
|
|
||||||
setContentView(R.layout.activity_home)
|
setContentView(R.layout.activity_home)
|
||||||
|
|
||||||
toolbar = findViewById(R.id.toolbar)
|
toolbar = findViewById(R.id.toolbar)
|
||||||
@ -126,48 +147,36 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
Amplify.getSharedInstance().promptIfReady(promptView)
|
Amplify.getSharedInstance().promptIfReady(promptView)
|
||||||
}
|
}
|
||||||
|
|
||||||
mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance()
|
firebaseRemoteConfig = FirebaseRemoteConfig.getInstance()
|
||||||
mFirebaseRemoteConfig.setDefaults(R.xml.default_remote_config)
|
firebaseRemoteConfig.setDefaults(R.xml.default_remote_config)
|
||||||
|
|
||||||
mCustomTabActivityHelper = CustomTabActivityHelper()
|
customTabActivityHelper = CustomTabActivityHelper()
|
||||||
|
|
||||||
api = SelfossApi(this, this@HomeActivity)
|
settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
||||||
|
sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
|
||||||
|
api = SelfossApi(this, this@HomeActivity, settings.getBoolean("isSelfSignedCert", false), sharedPref.getBoolean("should_log_everything", false))
|
||||||
items = ArrayList()
|
items = ArrayList()
|
||||||
|
|
||||||
mBottomBar = findViewById(R.id.bottomBar)
|
appColors = AppColors(this@HomeActivity)
|
||||||
|
|
||||||
|
handleBottomBar()
|
||||||
|
|
||||||
handleDrawer()
|
handleDrawer()
|
||||||
|
|
||||||
// TODO: clean this hack
|
coordinatorLayout = findViewById(R.id.coordLayout)
|
||||||
val listenerAlreadySet = booleanArrayOf(false)
|
swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout)
|
||||||
mBottomBar.setOnTabSelectListener { tabId ->
|
recyclerView = findViewById(R.id.my_recycler_view)
|
||||||
if (listenerAlreadySet[0]) {
|
|
||||||
if (tabId == R.id.tab_new) {
|
|
||||||
getUnRead()
|
|
||||||
} else if (tabId == R.id.tab_archive) {
|
|
||||||
getRead()
|
|
||||||
} else if (tabId == R.id.tab_fav) {
|
|
||||||
getStarred()
|
|
||||||
}
|
|
||||||
getElementsAccordingToTab()
|
|
||||||
} else {
|
|
||||||
listenerAlreadySet[0] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mCoordinatorLayout = findViewById(R.id.coordLayout)
|
|
||||||
mSwipeRefreshLayout = findViewById(R.id.swipeRefreshLayout)
|
|
||||||
mRecyclerView = findViewById(R.id.my_recycler_view)
|
|
||||||
|
|
||||||
emptyText = findViewById(R.id.emptyText)
|
emptyText = findViewById(R.id.emptyText)
|
||||||
|
|
||||||
reloadLayoutManager()
|
reloadLayoutManager()
|
||||||
|
|
||||||
mSwipeRefreshLayout.setColorSchemeResources(
|
swipeRefreshLayout.setColorSchemeResources(
|
||||||
R.color.refresh_progress_1,
|
R.color.refresh_progress_1,
|
||||||
R.color.refresh_progress_2,
|
R.color.refresh_progress_2,
|
||||||
R.color.refresh_progress_3)
|
R.color.refresh_progress_3)
|
||||||
mSwipeRefreshLayout.setOnRefreshListener {
|
swipeRefreshLayout.setOnRefreshListener {
|
||||||
handleDrawerItems()
|
handleDrawerItems()
|
||||||
getElementsAccordingToTab()
|
getElementsAccordingToTab()
|
||||||
}
|
}
|
||||||
@ -187,26 +196,76 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
val i = items[viewHolder.adapterPosition]
|
val i = items[viewHolder.adapterPosition]
|
||||||
val position = items.indexOf(i)
|
val position = items.indexOf(i)
|
||||||
|
|
||||||
if (shouldBeCardView) {
|
val adapter = recyclerView.adapter
|
||||||
(mRecyclerView.adapter as ItemCardAdapter).removeItemAtIndex(position)
|
when (adapter) {
|
||||||
} else {
|
is ItemCardAdapter -> adapter.removeItemAtIndex(position)
|
||||||
(mRecyclerView.adapter as ItemListAdapter).removeItemAtIndex(position)
|
is ItemListAdapter -> adapter.removeItemAtIndex(position)
|
||||||
}
|
}
|
||||||
tabNew.setBadgeCount(items.size - 1)
|
|
||||||
|
|
||||||
mayBeEmpty()
|
if (items.size > 0)
|
||||||
|
tabNewBadge.setText("${items.size}").maybeShow()
|
||||||
|
else
|
||||||
|
tabNewBadge.hide()
|
||||||
|
|
||||||
} catch (e: IndexOutOfBoundsException) {}
|
} catch (e: IndexOutOfBoundsException) {}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(mRecyclerView)
|
ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(recyclerView)
|
||||||
|
|
||||||
this@HomeActivity.checkAndDisplayStoreApk()
|
this@HomeActivity.checkAndDisplayStoreApk()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleBottomBar() {
|
||||||
|
|
||||||
|
bottomBar = findViewById(R.id.bottomBar)
|
||||||
|
|
||||||
|
tabNewBadge = TextBadgeItem()
|
||||||
|
.setText("")
|
||||||
|
.setHideOnSelect(false).hide(false)
|
||||||
|
.setBackgroundColor(appColors.primary)
|
||||||
|
tabArchiveBadge = TextBadgeItem()
|
||||||
|
.setText("")
|
||||||
|
.setHideOnSelect(false).hide(false)
|
||||||
|
.setBackgroundColor(appColors.primary)
|
||||||
|
tabStarredBadge = TextBadgeItem()
|
||||||
|
.setText("")
|
||||||
|
.setHideOnSelect(false).hide(false)
|
||||||
|
.setBackgroundColor(appColors.primary)
|
||||||
|
|
||||||
|
val tabNew =
|
||||||
|
BottomNavigationItem(
|
||||||
|
R.drawable.ic_fiber_new_black_24dp,
|
||||||
|
getString(R.string.tab_new)
|
||||||
|
).setActiveColor(appColors.accent)
|
||||||
|
.setBadgeItem(tabNewBadge)
|
||||||
|
val tabArchive =
|
||||||
|
BottomNavigationItem(
|
||||||
|
R.drawable.ic_archive_black_24dp,
|
||||||
|
getString(R.string.tab_read)
|
||||||
|
).setActiveColor(appColors.dark)
|
||||||
|
.setBadgeItem(tabArchiveBadge)
|
||||||
|
val tabStarred =
|
||||||
|
BottomNavigationItem(
|
||||||
|
R.drawable.ic_favorite_black_24dp,
|
||||||
|
getString(R.string.tab_favs)
|
||||||
|
).setActiveColorResource(R.color.pink)
|
||||||
|
.setBadgeItem(tabStarredBadge)
|
||||||
|
|
||||||
|
bottomBar
|
||||||
|
.addItem(tabNew)
|
||||||
|
.addItem(tabArchive)
|
||||||
|
.addItem(tabStarred)
|
||||||
|
.setFirstSelectedPosition(0)
|
||||||
|
.initialise()
|
||||||
|
|
||||||
|
bottomBar.setMode(BottomNavigationBar.MODE_SHIFTING)
|
||||||
|
bottomBar.setBackgroundStyle(BottomNavigationBar.BACKGROUND_STYLE_STATIC)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
@ -214,30 +273,25 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
|
|
||||||
sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
|
sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
|
||||||
val settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
|
||||||
editor = settings.edit()
|
editor = settings.edit()
|
||||||
|
|
||||||
if (BuildConfig.GITHUB_VERSION) {
|
if (BuildConfig.GITHUB_VERSION) {
|
||||||
this@HomeActivity.checkApkVersion(settings, editor, mFirebaseRemoteConfig)
|
this@HomeActivity.checkApkVersion(settings, editor, firebaseRemoteConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSharedPrefs()
|
handleSharedPrefs()
|
||||||
|
|
||||||
tabNew = mBottomBar.getTabWithId(R.id.tab_new)
|
|
||||||
tabArchive = mBottomBar.getTabWithId(R.id.tab_archive)
|
|
||||||
tabStarred = mBottomBar.getTabWithId(R.id.tab_fav)
|
|
||||||
|
|
||||||
|
|
||||||
getElementsAccordingToTab()
|
getElementsAccordingToTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
super.onStop()
|
super.onStop()
|
||||||
mCustomTabActivityHelper.unbindCustomTabsService(this)
|
customTabActivityHelper.unbindCustomTabsService(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun handleSharedPrefs() {
|
private fun handleSharedPrefs() {
|
||||||
|
debugReadingItems = sharedPref.getBoolean("read_debug", false)
|
||||||
clickBehavior = sharedPref.getBoolean("tab_on_tap", false)
|
clickBehavior = sharedPref.getBoolean("tab_on_tap", false)
|
||||||
internalBrowser = sharedPref.getBoolean("prefer_internal_browser", true)
|
internalBrowser = sharedPref.getBoolean("prefer_internal_browser", true)
|
||||||
articleViewer = sharedPref.getBoolean("prefer_article_viewer", true)
|
articleViewer = sharedPref.getBoolean("prefer_article_viewer", true)
|
||||||
@ -245,11 +299,33 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
displayUnreadCount = sharedPref.getBoolean("display_unread_count", true)
|
displayUnreadCount = sharedPref.getBoolean("display_unread_count", true)
|
||||||
displayAllCount = sharedPref.getBoolean("display_other_count", false)
|
displayAllCount = sharedPref.getBoolean("display_other_count", false)
|
||||||
fullHeightCards = sharedPref.getBoolean("full_height_cards", false)
|
fullHeightCards = sharedPref.getBoolean("full_height_cards", false)
|
||||||
|
itemsNumber = sharedPref.getString("prefer_api_items_number", "200").toInt()
|
||||||
|
userIdentifier = sharedPref.getString("unique_id", "")
|
||||||
|
displayAccountHeader = sharedPref.getBoolean("account_header_displaying", false)
|
||||||
|
infiniteScroll = sharedPref.getBoolean("infinite_loading", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleDrawer() {
|
private fun handleDrawer() {
|
||||||
|
displayAccountHeader =
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
.getBoolean("account_header_displaying", false)
|
||||||
|
val headerResult: AccountHeader? = if (displayAccountHeader) {
|
||||||
|
AccountHeaderBuilder()
|
||||||
|
.withActivity(this)
|
||||||
|
.withHeaderBackground(R.drawable.bg)
|
||||||
|
.addProfiles(
|
||||||
|
ProfileDrawerItem()
|
||||||
|
.withName(
|
||||||
|
settings.getString("url", "")
|
||||||
|
)
|
||||||
|
.withIcon(resources.getDrawable(R.mipmap.ic_launcher))
|
||||||
|
)
|
||||||
|
.withSelectionListEnabledForSingleProfile(false)
|
||||||
|
.build()
|
||||||
|
} else null
|
||||||
|
|
||||||
drawer = DrawerBuilder()
|
val drawerBuilder =
|
||||||
|
DrawerBuilder()
|
||||||
.withActivity(this)
|
.withActivity(this)
|
||||||
.withRootView(R.id.drawer_layout)
|
.withRootView(R.id.drawer_layout)
|
||||||
.withToolbar(toolbar)
|
.withToolbar(toolbar)
|
||||||
@ -258,37 +334,29 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
.withShowDrawerOnFirstLaunch(true)
|
.withShowDrawerOnFirstLaunch(true)
|
||||||
.withOnDrawerListener(object: Drawer.OnDrawerListener {
|
.withOnDrawerListener(object: Drawer.OnDrawerListener {
|
||||||
override fun onDrawerSlide(v: View?, p1: Float) {
|
override fun onDrawerSlide(v: View?, p1: Float) {
|
||||||
mBottomBar.alpha = (1 - p1)
|
bottomBar.alpha = (1 - p1)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDrawerClosed(v: View?) {
|
override fun onDrawerClosed(v: View?) {
|
||||||
mBottomBar.shySettings.showBar()
|
bottomBar.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDrawerOpened(v: View?) {
|
override fun onDrawerOpened(v: View?) {
|
||||||
mBottomBar.shySettings.hideBar()
|
bottomBar.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
.build()
|
|
||||||
|
|
||||||
drawer.addStickyFooterItem(
|
if (displayAccountHeader && headerResult != null)
|
||||||
PrimaryDrawerItem()
|
drawerBuilder.withAccountHeader(headerResult)
|
||||||
.withName(R.string.action_about)
|
|
||||||
.withSelectable(false)
|
drawer = drawerBuilder.build()
|
||||||
.withIcon(R.drawable.ic_info_outline)
|
|
||||||
.withOnDrawerItemClickListener { _, _, _ ->
|
|
||||||
LibsBuilder()
|
|
||||||
.withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR)
|
|
||||||
.withAboutIconShown(true)
|
|
||||||
.withAboutVersionShown(true)
|
|
||||||
.start(this@HomeActivity)
|
|
||||||
false
|
|
||||||
})
|
|
||||||
drawer.addStickyFooterItem(
|
drawer.addStickyFooterItem(
|
||||||
PrimaryDrawerItem()
|
PrimaryDrawerItem()
|
||||||
.withName(R.string.title_activity_settings)
|
.withName(R.string.title_activity_settings)
|
||||||
.withIcon(R.drawable.ic_settings)
|
.withIcon(R.drawable.ic_settings)
|
||||||
|
.withIconTintingEnabled(true)
|
||||||
.withOnDrawerItemClickListener { _, _, _ ->
|
.withOnDrawerItemClickListener { _, _, _ ->
|
||||||
startActivityForResult(
|
startActivityForResult(
|
||||||
Intent(
|
Intent(
|
||||||
@ -315,7 +383,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (tag in maybeTags) {
|
for (tag in maybeTags) {
|
||||||
val gd: GradientDrawable = GradientDrawable()
|
val gd = GradientDrawable()
|
||||||
gd.setColor(Color.parseColor(tag.color))
|
gd.setColor(Color.parseColor(tag.color))
|
||||||
gd.shape = GradientDrawable.RECTANGLE
|
gd.shape = GradientDrawable.RECTANGLE
|
||||||
gd.setSize(30, 30)
|
gd.setSize(30, 30)
|
||||||
@ -328,7 +396,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
.withBadge("${tag.unread}")
|
.withBadge("${tag.unread}")
|
||||||
.withBadgeStyle(
|
.withBadgeStyle(
|
||||||
BadgeStyle().withTextColor(Color.WHITE)
|
BadgeStyle().withTextColor(Color.WHITE)
|
||||||
.withColorRes(R.color.colorAccent)
|
.withColor(appColors.accent)
|
||||||
)
|
)
|
||||||
.withOnDrawerItemClickListener { _, _, _ ->
|
.withOnDrawerItemClickListener { _, _, _ ->
|
||||||
maybeTagFilter = tag
|
maybeTagFilter = tag
|
||||||
@ -387,6 +455,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
.withIdentifier(DRAWER_ID_TAGS)
|
.withIdentifier(DRAWER_ID_TAGS)
|
||||||
.withSelectable(false))
|
.withSelectable(false))
|
||||||
handleTags(maybeDrawerData.tags)
|
handleTags(maybeDrawerData.tags)
|
||||||
|
drawer.addItem(DividerDrawerItem())
|
||||||
drawer.addItem(
|
drawer.addItem(
|
||||||
SecondaryDrawerItem()
|
SecondaryDrawerItem()
|
||||||
.withName(getString(R.string.drawer_item_sources))
|
.withName(getString(R.string.drawer_item_sources))
|
||||||
@ -399,6 +468,26 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
handleSources(maybeDrawerData.sources)
|
handleSources(maybeDrawerData.sources)
|
||||||
|
drawer.addItem(DividerDrawerItem())
|
||||||
|
drawer.addItem(
|
||||||
|
PrimaryDrawerItem()
|
||||||
|
.withName(R.string.action_about)
|
||||||
|
.withSelectable(false)
|
||||||
|
.withIcon(R.drawable.ic_info_outline)
|
||||||
|
.withIconTintingEnabled(true)
|
||||||
|
.withOnDrawerItemClickListener { _, _, _ ->
|
||||||
|
LibsBuilder()
|
||||||
|
.withActivityStyle(
|
||||||
|
if (appColors.isDarkTheme)
|
||||||
|
Libs.ActivityStyle.LIGHT_DARK_TOOLBAR
|
||||||
|
else
|
||||||
|
Libs.ActivityStyle.DARK
|
||||||
|
)
|
||||||
|
.withAboutIconShown(true)
|
||||||
|
.withAboutVersionShown(true)
|
||||||
|
.start(this@HomeActivity)
|
||||||
|
false
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
if (!loadedFromCache)
|
if (!loadedFromCache)
|
||||||
@ -484,61 +573,105 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
mLayoutManager = GridLayoutManager(this, calculateNoOfColumns())
|
mLayoutManager = GridLayoutManager(this, calculateNoOfColumns())
|
||||||
}
|
}
|
||||||
|
|
||||||
mRecyclerView.layoutManager = mLayoutManager
|
recyclerView.layoutManager = mLayoutManager
|
||||||
mRecyclerView.setHasFixedSize(true)
|
recyclerView.setHasFixedSize(true)
|
||||||
|
|
||||||
mBottomBar.setOnTabReselectListener {
|
if (infiniteScroll) {
|
||||||
if (shouldBeCardView) {
|
if (recyclerViewScrollListener == null)
|
||||||
if ((mLayoutManager as StaggeredGridLayoutManager).findFirstCompletelyVisibleItemPositions(null)[0] == 0) {
|
recyclerViewScrollListener = object: RecyclerView.OnScrollListener() {
|
||||||
|
override fun onScrolled(localRecycler: RecyclerView?, dx: Int, dy: Int) {
|
||||||
|
if (dy > 0) {
|
||||||
|
if (localRecycler != null) {
|
||||||
|
val manager = recyclerView.layoutManager
|
||||||
|
val lastVisibleItem: Int = when (manager) {
|
||||||
|
is StaggeredGridLayoutManager -> manager.findLastCompletelyVisibleItemPositions(null).last()
|
||||||
|
is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition()
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastVisibleItem == (items.size - 1)) {
|
||||||
|
getElementsAccordingToTab(appendResults = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
recyclerView.clearOnScrollListeners()
|
||||||
|
recyclerView.addOnScrollListener(recyclerViewScrollListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
bottomBar.setTabSelectedListener(object: BottomNavigationBar.OnTabSelectedListener {
|
||||||
|
override fun onTabUnselected(position: Int) = Unit
|
||||||
|
|
||||||
|
override fun onTabReselected(position: Int) =
|
||||||
|
when (mLayoutManager) {
|
||||||
|
is StaggeredGridLayoutManager ->
|
||||||
|
if (mLayoutManager.findFirstCompletelyVisibleItemPositions(null)[0] == 0) {
|
||||||
getElementsAccordingToTab()
|
getElementsAccordingToTab()
|
||||||
} else {
|
} else {
|
||||||
mLayoutManager.scrollToPositionWithOffset(0, 0)
|
mLayoutManager.scrollToPositionWithOffset(0, 0)
|
||||||
}
|
}
|
||||||
} else {
|
is GridLayoutManager ->
|
||||||
if ((mLayoutManager as GridLayoutManager).findFirstCompletelyVisibleItemPosition() == 0) {
|
if (mLayoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
|
||||||
getElementsAccordingToTab()
|
getElementsAccordingToTab()
|
||||||
} else {
|
} else {
|
||||||
mLayoutManager.scrollToPositionWithOffset(0, 0)
|
mLayoutManager.scrollToPositionWithOffset(0, 0)
|
||||||
}
|
}
|
||||||
|
else -> Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onTabSelected(position: Int) =
|
||||||
|
when(position) {
|
||||||
|
0 -> getUnRead()
|
||||||
|
1 -> getRead()
|
||||||
|
2 -> getStarred()
|
||||||
|
else -> Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fun mayBeEmpty() =
|
fun mayBeEmpty() =
|
||||||
if (items.isEmpty()) {
|
if (items.isEmpty()) {
|
||||||
emptyText.visibility = View.VISIBLE
|
emptyText.visibility = View.VISIBLE
|
||||||
mRecyclerView.visibility = View.GONE
|
recyclerView.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
emptyText.visibility = View.GONE
|
emptyText.visibility = View.GONE
|
||||||
mRecyclerView.visibility = View.VISIBLE
|
recyclerView.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getElementsAccordingToTab() =
|
private fun getElementsAccordingToTab(appendResults: Boolean = false) =
|
||||||
when (elementsShown) {
|
when (elementsShown) {
|
||||||
UNREAD_SHOWN -> getUnRead()
|
UNREAD_SHOWN -> getUnRead(appendResults)
|
||||||
READ_SHOWN -> getRead()
|
READ_SHOWN -> getRead(appendResults)
|
||||||
FAV_SHOWN -> getStarred()
|
FAV_SHOWN -> getStarred(appendResults)
|
||||||
else -> getUnRead()
|
else -> getUnRead(appendResults)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doCallTo(toastMessage: Int, call: (String?, Long?, String?) -> Call<List<Item>>) {
|
private fun doCallTo(appendResults: Boolean, toastMessage: Int, call: (String?, Long?, String?) -> Call<List<Item>>) {
|
||||||
fun handleItemsResponse(response: Response<List<Item>>) {
|
fun handleItemsResponse(response: Response<List<Item>>) {
|
||||||
val didUpdate = (response.body() != items)
|
val didUpdate = (response.body() != items)
|
||||||
if (response.body() != null) {
|
if (response.body() != null) {
|
||||||
if (response.body() != items) {
|
if (response.body() != items) {
|
||||||
|
if (appendResults)
|
||||||
|
items.addAll(response.body() as ArrayList<Item>)
|
||||||
|
else
|
||||||
items = response.body() as ArrayList<Item>
|
items = response.body() as ArrayList<Item>
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (!appendResults)
|
||||||
items = ArrayList()
|
items = ArrayList()
|
||||||
}
|
}
|
||||||
if (didUpdate)
|
if (didUpdate)
|
||||||
handleListResult()
|
handleListResult(appendResults)
|
||||||
|
|
||||||
mayBeEmpty()
|
mayBeEmpty()
|
||||||
mSwipeRefreshLayout.isRefreshing = false
|
swipeRefreshLayout.isRefreshing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mSwipeRefreshLayout.isRefreshing)
|
if (!swipeRefreshLayout.isRefreshing)
|
||||||
mSwipeRefreshLayout.post { mSwipeRefreshLayout.isRefreshing = true }
|
swipeRefreshLayout.post { swipeRefreshLayout.isRefreshing = true }
|
||||||
|
|
||||||
call(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong(), maybeSearchFilter)
|
call(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong(), maybeSearchFilter)
|
||||||
.enqueue(object : Callback<List<Item>> {
|
.enqueue(object : Callback<List<Item>> {
|
||||||
@ -547,28 +680,46 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<List<Item>>, t: Throwable) {
|
override fun onFailure(call: Call<List<Item>>, t: Throwable) {
|
||||||
mSwipeRefreshLayout.isRefreshing = false
|
swipeRefreshLayout.isRefreshing = false
|
||||||
Toast.makeText(this@HomeActivity, toastMessage, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this@HomeActivity, toastMessage, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getUnRead() {
|
private fun getUnRead(appendResults: Boolean = false) {
|
||||||
|
offset = if (appendResults) (offset + itemsNumber)
|
||||||
|
else 0
|
||||||
|
firstVisible = if (appendResults) firstVisible else 0
|
||||||
elementsShown = UNREAD_SHOWN
|
elementsShown = UNREAD_SHOWN
|
||||||
doCallTo(R.string.cant_get_new_elements){t, id, f -> api.newItems(t, id, f)}
|
doCallTo(appendResults, R.string.cant_get_new_elements){t, id, f -> api.newItems(t, id, f, itemsNumber, offset)}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getRead() {
|
private fun getRead(appendResults: Boolean = false) {
|
||||||
|
offset = if (appendResults) (offset + itemsNumber)
|
||||||
|
else 0
|
||||||
|
firstVisible = if (appendResults) firstVisible else 0
|
||||||
elementsShown = READ_SHOWN
|
elementsShown = READ_SHOWN
|
||||||
doCallTo(R.string.cant_get_read){t, id, f -> api.readItems(t, id, f)}
|
doCallTo(appendResults, R.string.cant_get_read){t, id, f -> api.readItems(t, id, f, itemsNumber, offset)}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getStarred() {
|
private fun getStarred(appendResults: Boolean = false) {
|
||||||
|
offset = if (appendResults) (offset + itemsNumber)
|
||||||
|
else 0
|
||||||
|
firstVisible = if (appendResults) firstVisible else 0
|
||||||
elementsShown = FAV_SHOWN
|
elementsShown = FAV_SHOWN
|
||||||
doCallTo(R.string.cant_get_favs){t, id, f -> api.starredItems(t, id, f)}
|
doCallTo(appendResults, R.string.cant_get_favs){t, id, f -> api.starredItems(t, id, f, itemsNumber, offset)}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleListResult(appendResults: Boolean = false) {
|
||||||
|
if (appendResults) {
|
||||||
|
val oldManager = recyclerView.layoutManager
|
||||||
|
firstVisible = if ((oldManager is StaggeredGridLayoutManager)) {
|
||||||
|
oldManager.findFirstCompletelyVisibleItemPositions(null).last()
|
||||||
|
}
|
||||||
|
else
|
||||||
|
(oldManager as GridLayoutManager)?.findFirstCompletelyVisibleItemPosition()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleListResult() {
|
|
||||||
reloadLayoutManager()
|
reloadLayoutManager()
|
||||||
|
|
||||||
val mAdapter: RecyclerView.Adapter<*>
|
val mAdapter: RecyclerView.Adapter<*>
|
||||||
@ -578,24 +729,33 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
this,
|
this,
|
||||||
items,
|
items,
|
||||||
api,
|
api,
|
||||||
mCustomTabActivityHelper,
|
customTabActivityHelper,
|
||||||
internalBrowser,
|
internalBrowser,
|
||||||
articleViewer,
|
articleViewer,
|
||||||
fullHeightCards)
|
fullHeightCards,
|
||||||
|
appColors,
|
||||||
|
debugReadingItems,
|
||||||
|
userIdentifier)
|
||||||
} else {
|
} else {
|
||||||
mAdapter =
|
mAdapter =
|
||||||
ItemListAdapter(
|
ItemListAdapter(
|
||||||
this,
|
this,
|
||||||
items,
|
items,
|
||||||
api,
|
api,
|
||||||
mCustomTabActivityHelper,
|
customTabActivityHelper,
|
||||||
clickBehavior,
|
clickBehavior,
|
||||||
internalBrowser,
|
internalBrowser,
|
||||||
articleViewer)
|
articleViewer,
|
||||||
|
debugReadingItems,
|
||||||
|
userIdentifier)
|
||||||
}
|
}
|
||||||
mRecyclerView.adapter = mAdapter
|
recyclerView.adapter = mAdapter
|
||||||
mAdapter.notifyDataSetChanged()
|
mAdapter.notifyDataSetChanged()
|
||||||
|
|
||||||
|
if (appendResults) {
|
||||||
|
recyclerView.scrollToPosition(firstVisible!!)
|
||||||
|
}
|
||||||
|
|
||||||
reloadBadges()
|
reloadBadges()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -604,13 +764,20 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
api.stats.enqueue(object : Callback<Stats> {
|
api.stats.enqueue(object : Callback<Stats> {
|
||||||
override fun onResponse(call: Call<Stats>, response: Response<Stats>) {
|
override fun onResponse(call: Call<Stats>, response: Response<Stats>) {
|
||||||
if (response.body() != null) {
|
if (response.body() != null) {
|
||||||
tabNew.setBadgeCount(response.body()!!.unread)
|
if (displayUnreadCount)
|
||||||
|
tabNewBadge
|
||||||
|
.setText(response.body()!!.unread.toString())
|
||||||
|
.maybeShow()
|
||||||
if (displayAllCount) {
|
if (displayAllCount) {
|
||||||
tabArchive.setBadgeCount(response.body()!!.total)
|
tabArchiveBadge
|
||||||
tabStarred.setBadgeCount(response.body()!!.starred)
|
.setText(response.body()!!.total.toString())
|
||||||
|
.maybeShow()
|
||||||
|
tabStarredBadge
|
||||||
|
.setText(response.body()!!.starred.toString())
|
||||||
|
.maybeShow()
|
||||||
} else {
|
} else {
|
||||||
tabArchive.removeBadge()
|
tabArchiveBadge.removeBadge()
|
||||||
tabStarred.removeBadge()
|
tabStarredBadge.removeBadge()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -618,9 +785,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
override fun onFailure(call: Call<Stats>, t: Throwable) {}
|
override fun onFailure(call: Call<Stats>, t: Throwable) {}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
tabNew.removeBadge()
|
tabNewBadge.removeBadge()
|
||||||
tabArchive.removeBadge()
|
tabArchiveBadge.removeBadge()
|
||||||
tabStarred.removeBadge()
|
tabStarredBadge.removeBadge()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -692,22 +859,24 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
}
|
}
|
||||||
R.id.readAll -> {
|
R.id.readAll -> {
|
||||||
if (elementsShown == UNREAD_SHOWN) {
|
if (elementsShown == UNREAD_SHOWN) {
|
||||||
mSwipeRefreshLayout.isRefreshing = false
|
swipeRefreshLayout.isRefreshing = false
|
||||||
val ids = items.map { it.id }
|
val ids = items.map { it.id }
|
||||||
|
|
||||||
api.readAll(ids).enqueue(object : Callback<SuccessResponse> {
|
api.readAll(ids).enqueue(object : Callback<SuccessResponse> {
|
||||||
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
|
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
|
||||||
if (response.body() != null && response.body()!!.isSuccess)
|
if (response.body() != null && response.body()!!.isSuccess) {
|
||||||
Toast.makeText(this@HomeActivity, R.string.all_posts_read, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this@HomeActivity, R.string.all_posts_read, Toast.LENGTH_SHORT).show()
|
||||||
|
tabNewBadge.removeBadge()
|
||||||
|
}
|
||||||
else
|
else
|
||||||
Toast.makeText(this@HomeActivity, R.string.all_posts_not_read, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this@HomeActivity, R.string.all_posts_not_read, Toast.LENGTH_SHORT).show()
|
||||||
|
|
||||||
mSwipeRefreshLayout.isRefreshing = false
|
swipeRefreshLayout.isRefreshing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
||||||
Toast.makeText(this@HomeActivity, R.string.all_posts_not_read, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this@HomeActivity, R.string.all_posts_not_read, Toast.LENGTH_SHORT).show()
|
||||||
mSwipeRefreshLayout.isRefreshing = false
|
swipeRefreshLayout.isRefreshing = false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
items = ArrayList()
|
items = ArrayList()
|
||||||
|
@ -9,7 +9,7 @@ import android.view.View
|
|||||||
import agency.tango.materialintroscreen.MaterialIntroActivity
|
import agency.tango.materialintroscreen.MaterialIntroActivity
|
||||||
import agency.tango.materialintroscreen.MessageButtonBehaviour
|
import agency.tango.materialintroscreen.MessageButtonBehaviour
|
||||||
import agency.tango.materialintroscreen.SlideFragmentBuilder
|
import agency.tango.materialintroscreen.SlideFragmentBuilder
|
||||||
|
import android.support.v7.app.AppCompatDelegate
|
||||||
|
|
||||||
|
|
||||||
class IntroActivity : MaterialIntroActivity() {
|
class IntroActivity : MaterialIntroActivity() {
|
||||||
@ -17,10 +17,12 @@ class IntroActivity : MaterialIntroActivity() {
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
||||||
|
|
||||||
addSlide(SlideFragmentBuilder()
|
addSlide(SlideFragmentBuilder()
|
||||||
.backgroundColor(R.color.colorPrimary)
|
.backgroundColor(R.color.colorPrimary)
|
||||||
.buttonsColor(R.color.colorAccent)
|
.buttonsColor(R.color.colorAccent)
|
||||||
.image(R.mipmap.ic_launcher)
|
.image(R.drawable.web_hi_res_512)
|
||||||
.title(getString(R.string.intro_hello_title))
|
.title(getString(R.string.intro_hello_title))
|
||||||
.description(getString(R.string.intro_hello_message))
|
.description(getString(R.string.intro_hello_message))
|
||||||
.build())
|
.build())
|
||||||
@ -28,7 +30,7 @@ class IntroActivity : MaterialIntroActivity() {
|
|||||||
addSlide(SlideFragmentBuilder()
|
addSlide(SlideFragmentBuilder()
|
||||||
.backgroundColor(R.color.colorAccent)
|
.backgroundColor(R.color.colorAccent)
|
||||||
.buttonsColor(R.color.colorPrimary)
|
.buttonsColor(R.color.colorPrimary)
|
||||||
.image(R.drawable.ic_info_outline_white_48dp)
|
.image(R.drawable.ic_info_outline_white_48px)
|
||||||
.title(getString(R.string.intro_needs_selfoss_title))
|
.title(getString(R.string.intro_needs_selfoss_title))
|
||||||
.description(getString(R.string.intro_needs_selfoss_message))
|
.description(getString(R.string.intro_needs_selfoss_message))
|
||||||
.build(),
|
.build(),
|
||||||
@ -40,7 +42,7 @@ class IntroActivity : MaterialIntroActivity() {
|
|||||||
addSlide(SlideFragmentBuilder()
|
addSlide(SlideFragmentBuilder()
|
||||||
.backgroundColor(R.color.colorPrimaryDark)
|
.backgroundColor(R.color.colorPrimaryDark)
|
||||||
.buttonsColor(R.color.colorAccentDark)
|
.buttonsColor(R.color.colorAccentDark)
|
||||||
.image(R.drawable.ic_thumb_up_white_48dp)
|
.image(R.drawable.ic_thumb_up_white_48px)
|
||||||
.title(getString(R.string.intro_all_set_title))
|
.title(getString(R.string.intro_all_set_title))
|
||||||
.description(getString(R.string.intro_all_set_message))
|
.description(getString(R.string.intro_all_set_message))
|
||||||
.build())
|
.build())
|
||||||
|
@ -9,16 +9,20 @@ import android.os.Bundle
|
|||||||
import android.support.design.widget.TextInputLayout
|
import android.support.design.widget.TextInputLayout
|
||||||
import android.support.v7.app.AlertDialog
|
import android.support.v7.app.AlertDialog
|
||||||
import android.support.v7.app.AppCompatActivity
|
import android.support.v7.app.AppCompatActivity
|
||||||
|
import android.support.v7.widget.Toolbar
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.widget.Button
|
import android.widget.*
|
||||||
import android.widget.EditText
|
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
|
||||||
import android.widget.Switch
|
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
|
||||||
import android.widget.TextView
|
import apps.amine.bou.readerforselfoss.utils.Config
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.checkAndDisplayStoreApk
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.isBaseUrlValid
|
||||||
|
import com.crashlytics.android.Crashlytics
|
||||||
|
import com.ftinc.scoop.Scoop
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics
|
import com.google.firebase.analytics.FirebaseAnalytics
|
||||||
import com.mikepenz.aboutlibraries.Libs
|
import com.mikepenz.aboutlibraries.Libs
|
||||||
import com.mikepenz.aboutlibraries.LibsBuilder
|
import com.mikepenz.aboutlibraries.LibsBuilder
|
||||||
@ -26,21 +30,16 @@ import retrofit2.Call
|
|||||||
import retrofit2.Callback
|
import retrofit2.Callback
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
|
|
||||||
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
|
|
||||||
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
|
|
||||||
import apps.amine.bou.readerforselfoss.utils.Config
|
|
||||||
import apps.amine.bou.readerforselfoss.utils.checkAndDisplayStoreApk
|
|
||||||
import apps.amine.bou.readerforselfoss.utils.isUrlValid
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LoginActivity : AppCompatActivity() {
|
class LoginActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private var inValidCount: Int = 0
|
private var inValidCount: Int = 0
|
||||||
|
private var isWithSelfSignedCert = false
|
||||||
private var isWithLogin = false
|
private var isWithLogin = false
|
||||||
private var isWithHTTPLogin = false
|
private var isWithHTTPLogin = false
|
||||||
|
|
||||||
private lateinit var settings: SharedPreferences
|
private lateinit var settings: SharedPreferences
|
||||||
|
private lateinit var editor: SharedPreferences.Editor
|
||||||
private lateinit var mFirebaseAnalytics: FirebaseAnalytics
|
private lateinit var mFirebaseAnalytics: FirebaseAnalytics
|
||||||
private lateinit var mUrlView: EditText
|
private lateinit var mUrlView: EditText
|
||||||
private lateinit var mLoginView: TextView
|
private lateinit var mLoginView: TextView
|
||||||
@ -49,13 +48,19 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
private lateinit var mPasswordView: EditText
|
private lateinit var mPasswordView: EditText
|
||||||
private lateinit var mHTTPPasswordView: EditText
|
private lateinit var mHTTPPasswordView: EditText
|
||||||
private lateinit var mLoginFormView: View
|
private lateinit var mLoginFormView: View
|
||||||
|
private lateinit var userIdentifier: String
|
||||||
|
private var logErrors: Boolean = false
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
Scoop.getInstance().apply(this)
|
||||||
setContentView(R.layout.activity_login)
|
setContentView(R.layout.activity_login)
|
||||||
|
|
||||||
|
val toolbar: Toolbar = findViewById(R.id.toolbar)
|
||||||
|
setSupportActionBar(toolbar)
|
||||||
|
|
||||||
if (intent.getBooleanExtra("baseUrlFail", false)) {
|
if (intent.getBooleanExtra("baseUrlFail", false)) {
|
||||||
val alertDialog = AlertDialog.Builder(this).create()
|
val alertDialog = AlertDialog.Builder(this).create()
|
||||||
alertDialog.setTitle(getString(R.string.warning_wrong_url))
|
alertDialog.setTitle(getString(R.string.warning_wrong_url))
|
||||||
@ -69,6 +74,11 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
|
|
||||||
settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
||||||
|
userIdentifier = settings.getString("unique_id", "")
|
||||||
|
logErrors = settings.getBoolean("loging_debug", false)
|
||||||
|
|
||||||
|
editor = settings.edit()
|
||||||
|
|
||||||
if (settings.getString("url", "").isNotEmpty()) {
|
if (settings.getString("url", "").isNotEmpty()) {
|
||||||
goToMain()
|
goToMain()
|
||||||
} else {
|
} else {
|
||||||
@ -91,6 +101,15 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
val mPasswordLayout: TextInputLayout = findViewById(R.id.passwordLayout)
|
val mPasswordLayout: TextInputLayout = findViewById(R.id.passwordLayout)
|
||||||
val mHTTPPasswordLayout: TextInputLayout = findViewById(R.id.httpPasswordInput)
|
val mHTTPPasswordLayout: TextInputLayout = findViewById(R.id.httpPasswordInput)
|
||||||
val mEmailSignInButton: Button = findViewById(R.id.email_sign_in_button)
|
val mEmailSignInButton: Button = findViewById(R.id.email_sign_in_button)
|
||||||
|
val selfHostedSwitch: Switch = findViewById(R.id.withSelfhostedCert)
|
||||||
|
val warningTextview: TextView = findViewById(R.id.warningText)
|
||||||
|
|
||||||
|
selfHostedSwitch.setOnCheckedChangeListener {_, b ->
|
||||||
|
isWithSelfSignedCert = !isWithSelfSignedCert
|
||||||
|
val visi: Int = if (b) View.VISIBLE else View.GONE
|
||||||
|
|
||||||
|
warningTextview.visibility = visi
|
||||||
|
}
|
||||||
|
|
||||||
mPasswordView.setOnEditorActionListener(TextView.OnEditorActionListener { _, id, _ ->
|
mPasswordView.setOnEditorActionListener(TextView.OnEditorActionListener { _, id, _ ->
|
||||||
if (id == R.id.login || id == EditorInfo.IME_NULL) {
|
if (id == R.id.login || id == EditorInfo.IME_NULL) {
|
||||||
@ -144,7 +163,7 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
var cancel = false
|
var cancel = false
|
||||||
var focusView: View? = null
|
var focusView: View? = null
|
||||||
|
|
||||||
if (!url.isUrlValid()) {
|
if (!url.isBaseUrlValid()) {
|
||||||
mUrlView.error = getString(R.string.login_url_problem)
|
mUrlView.error = getString(R.string.login_url_problem)
|
||||||
focusView = mUrlView
|
focusView = mUrlView
|
||||||
cancel = true
|
cancel = true
|
||||||
@ -181,17 +200,17 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
} else {
|
} else {
|
||||||
showProgress(true)
|
showProgress(true)
|
||||||
|
|
||||||
val editor = settings.edit()
|
|
||||||
editor.putString("url", url)
|
editor.putString("url", url)
|
||||||
editor.putString("login", login)
|
editor.putString("login", login)
|
||||||
editor.putString("httpUserName", httpLogin)
|
editor.putString("httpUserName", httpLogin)
|
||||||
editor.putString("password", password)
|
editor.putString("password", password)
|
||||||
editor.putString("httpPassword", httpPassword)
|
editor.putString("httpPassword", httpPassword)
|
||||||
|
editor.putBoolean("isSelfSignedCert", isWithSelfSignedCert)
|
||||||
editor.apply()
|
editor.apply()
|
||||||
|
|
||||||
val api = SelfossApi(this, this@LoginActivity)
|
val api = SelfossApi(this, this@LoginActivity, isWithSelfSignedCert, isWithSelfSignedCert)
|
||||||
api.login().enqueue(object : Callback<SuccessResponse> {
|
api.login().enqueue(object : Callback<SuccessResponse> {
|
||||||
private fun preferenceError() {
|
private fun preferenceError(t: Throwable) {
|
||||||
editor.remove("url")
|
editor.remove("url")
|
||||||
editor.remove("login")
|
editor.remove("login")
|
||||||
editor.remove("httpUserName")
|
editor.remove("httpUserName")
|
||||||
@ -203,6 +222,12 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
mPasswordView.error = getString(R.string.wrong_infos)
|
mPasswordView.error = getString(R.string.wrong_infos)
|
||||||
mHTTPLoginView.error = getString(R.string.wrong_infos)
|
mHTTPLoginView.error = getString(R.string.wrong_infos)
|
||||||
mHTTPPasswordView.error = getString(R.string.wrong_infos)
|
mHTTPPasswordView.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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,12 +236,12 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle())
|
mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle())
|
||||||
goToMain()
|
goToMain()
|
||||||
} else {
|
} else {
|
||||||
preferenceError()
|
preferenceError(Exception("No response body..."))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
||||||
preferenceError()
|
preferenceError(t)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -255,6 +280,7 @@ 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.loging_debug).isChecked = logErrors
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,6 +294,14 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
.start(this)
|
.start(this)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
R.id.loging_debug -> {
|
||||||
|
val newState = !item.isChecked
|
||||||
|
item.isChecked = newState
|
||||||
|
logErrors = newState
|
||||||
|
editor.putBoolean("loging_debug", newState)
|
||||||
|
editor.apply()
|
||||||
|
return true
|
||||||
|
}
|
||||||
else -> return super.onOptionsItemSelected(item)
|
else -> return super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,47 +3,116 @@ package apps.amine.bou.readerforselfoss
|
|||||||
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.preference.PreferenceManager
|
||||||
import android.support.multidex.MultiDexApplication
|
import android.support.multidex.MultiDexApplication
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.Config
|
||||||
import com.anupcowkur.reservoir.Reservoir
|
import com.anupcowkur.reservoir.Reservoir
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
|
import com.bumptech.glide.request.RequestOptions
|
||||||
import com.crashlytics.android.Crashlytics
|
import com.crashlytics.android.Crashlytics
|
||||||
|
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.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 io.fabric.sdk.android.Fabric
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.util.UUID.randomUUID
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MyApp : MultiDexApplication() {
|
class MyApp : MultiDexApplication() {
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
if (!BuildConfig.DEBUG)
|
|
||||||
Fabric.with(this, Crashlytics())
|
Fabric.with(this, Crashlytics())
|
||||||
|
|
||||||
Amplify.initSharedInstance(this)
|
initAmplify()
|
||||||
.setFeedbackEmailAddress(getString(R.string.feedback_email))
|
|
||||||
.setAlwaysShow(BuildConfig.DEBUG)
|
|
||||||
.applyAllDefaultRules()
|
|
||||||
|
|
||||||
|
initCache()
|
||||||
|
|
||||||
|
val prefs = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
||||||
|
if (prefs.getString("unique_id", "").isEmpty()) {
|
||||||
|
val editor = prefs.edit()
|
||||||
|
editor.putString("unique_id", randomUUID().toString())
|
||||||
|
editor.apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
initDrawerImageLoader()
|
||||||
|
|
||||||
|
initTheme()
|
||||||
|
|
||||||
|
tryToHandleBug()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initAmplify() {
|
||||||
|
Amplify.initSharedInstance(this)
|
||||||
|
.setPositiveFeedbackCollectors(GooglePlayStoreFeedbackCollector())
|
||||||
|
.setCriticalFeedbackCollectors(DefaultEmailFeedbackCollector(BuildConfig.FEEDBACK_EMAIL))
|
||||||
|
.applyAllDefaultRules()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initCache() {
|
||||||
try {
|
try {
|
||||||
Reservoir.init(this, 8192) //in bytes
|
Reservoir.init(this, 8192) //in bytes
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
//failure
|
//failure
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initDrawerImageLoader() {
|
||||||
DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
|
DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
|
||||||
override fun set(imageView: ImageView?, uri: Uri?, placeholder: Drawable?, tag: String?) {
|
override fun set(imageView: ImageView?, uri: Uri?, placeholder: Drawable?, tag: String?) {
|
||||||
Glide.with(imageView?.context).load(uri).placeholder(placeholder).into(imageView)
|
Glide.with(imageView?.context)
|
||||||
|
.load(uri)
|
||||||
|
.apply(RequestOptions.fitCenterTransform()
|
||||||
|
.placeholder(placeholder))
|
||||||
|
.into(imageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cancel(imageView: ImageView?) {
|
override fun cancel(imageView: ImageView?) {
|
||||||
Glide.clear(imageView)
|
Glide.with(imageView?.context).clear(imageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun placeholder(ctx: Context?, tag: String?): Drawable {
|
override fun placeholder(ctx: Context?, tag: String?): Drawable {
|
||||||
return applicationContext.resources.getDrawable(R.mipmap.ic_launcher)
|
return baseContext.resources.getDrawable(R.mipmap.ic_launcher)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun initTheme() {
|
||||||
|
Scoop.waffleCone()
|
||||||
|
.addFlavor(getString(R.string.default_theme), R.style.NoBar, true)
|
||||||
|
.addFlavor(getString(R.string.default_dark_theme), R.style.NoBarDark)
|
||||||
|
.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))
|
||||||
|
.initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tryToHandleBug() {
|
||||||
|
val oldHandler = Thread.getDefaultUncaughtExceptionHandler()
|
||||||
|
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler { thread, e ->
|
||||||
|
if (e is java.lang.NoClassDefFoundError && e.stackTrace.asList().any { it.toString().contains("android.view.ViewDebug") })
|
||||||
|
Unit
|
||||||
|
else
|
||||||
|
oldHandler.uncaughtException(thread, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,16 +1,22 @@
|
|||||||
package apps.amine.bou.readerforselfoss
|
package apps.amine.bou.readerforselfoss
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.preference.PreferenceManager
|
||||||
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.ImageButton
|
import android.widget.ImageButton
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import apps.amine.bou.readerforselfoss.api.mercury.MercuryApi
|
||||||
|
import apps.amine.bou.readerforselfoss.api.mercury.ParsedContent
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.openItemUrl
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.shareLink
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
|
import com.bumptech.glide.request.RequestOptions
|
||||||
|
import com.ftinc.scoop.Scoop
|
||||||
import org.sufficientlysecure.htmltextview.HtmlHttpImageGetter
|
import org.sufficientlysecure.htmltextview.HtmlHttpImageGetter
|
||||||
import org.sufficientlysecure.htmltextview.HtmlTextView
|
import org.sufficientlysecure.htmltextview.HtmlTextView
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
@ -18,12 +24,6 @@ import retrofit2.Callback
|
|||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
import xyz.klinker.android.drag_dismiss.activity.DragDismissActivity
|
import xyz.klinker.android.drag_dismiss.activity.DragDismissActivity
|
||||||
|
|
||||||
import apps.amine.bou.readerforselfoss.api.mercury.MercuryApi
|
|
||||||
import apps.amine.bou.readerforselfoss.api.mercury.ParsedContent
|
|
||||||
import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent
|
|
||||||
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
|
|
||||||
import apps.amine.bou.readerforselfoss.utils.shareLink
|
|
||||||
|
|
||||||
|
|
||||||
class ReaderActivity : DragDismissActivity() {
|
class ReaderActivity : DragDismissActivity() {
|
||||||
private lateinit var mCustomTabActivityHelper: CustomTabActivityHelper
|
private lateinit var mCustomTabActivityHelper: CustomTabActivityHelper
|
||||||
@ -39,15 +39,17 @@ class ReaderActivity : DragDismissActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateContent(inflater: LayoutInflater, parent: ViewGroup, savedInstanceState: Bundle?): View {
|
override fun onCreateContent(inflater: LayoutInflater, parent: ViewGroup, savedInstanceState: Bundle?): View {
|
||||||
|
Scoop.getInstance().apply(this)
|
||||||
val v = inflater.inflate(R.layout.activity_reader, parent, false)
|
val v = inflater.inflate(R.layout.activity_reader, parent, false)
|
||||||
showProgressBar()
|
showProgressBar()
|
||||||
|
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
|
||||||
val image: ImageView = v.findViewById(R.id.imageView)
|
val image: ImageView = v.findViewById(R.id.imageView)
|
||||||
val source: TextView = v.findViewById(R.id.source)
|
val source: TextView = v.findViewById(R.id.source)
|
||||||
val title: TextView = v.findViewById(R.id.title)
|
val title: TextView = v.findViewById(R.id.title)
|
||||||
val content: HtmlTextView = v.findViewById(R.id.content)
|
val content: HtmlTextView = v.findViewById(R.id.content)
|
||||||
val url = intent.getStringExtra("url")
|
val url = intent.getStringExtra("url")
|
||||||
val parser = MercuryApi(getString(R.string.mercury))
|
val parser = MercuryApi(BuildConfig.MERCURY_KEY, prefs.getBoolean("should_log_everything", false))
|
||||||
val browserBtn: ImageButton = v.findViewById(R.id.browserBtn)
|
val browserBtn: ImageButton = v.findViewById(R.id.browserBtn)
|
||||||
val shareBtn: ImageButton = v.findViewById(R.id.shareBtn)
|
val shareBtn: ImageButton = v.findViewById(R.id.shareBtn)
|
||||||
|
|
||||||
@ -71,10 +73,10 @@ class ReaderActivity : DragDismissActivity() {
|
|||||||
}
|
}
|
||||||
if (response.body()!!.lead_image_url != null && !response.body()!!.lead_image_url.isEmpty())
|
if (response.body()!!.lead_image_url != null && !response.body()!!.lead_image_url.isEmpty())
|
||||||
Glide
|
Glide
|
||||||
.with(applicationContext)
|
.with(baseContext)
|
||||||
.load(response.body()!!.lead_image_url)
|
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
.fitCenter()
|
.load(response.body()!!.lead_image_url)
|
||||||
|
.apply(RequestOptions.fitCenterTransform())
|
||||||
.into(image)
|
.into(image)
|
||||||
|
|
||||||
shareBtn.setOnClickListener {
|
shareBtn.setOnClickListener {
|
||||||
@ -82,10 +84,12 @@ class ReaderActivity : DragDismissActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
browserBtn.setOnClickListener {
|
browserBtn.setOnClickListener {
|
||||||
val intent = Intent(Intent.ACTION_VIEW)
|
this@ReaderActivity.openItemUrl(
|
||||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
response.body()!!.url,
|
||||||
intent.data = Uri.parse(response.body()!!.url)
|
customTabsIntent,
|
||||||
startActivity(intent)
|
false,
|
||||||
|
false,
|
||||||
|
this@ReaderActivity)
|
||||||
}
|
}
|
||||||
|
|
||||||
hideProgressBar()
|
hideProgressBar()
|
||||||
@ -95,12 +99,13 @@ class ReaderActivity : DragDismissActivity() {
|
|||||||
override fun onFailure(call: Call<ParsedContent>, t: Throwable) = openInBrowserAfterFailing()
|
override fun onFailure(call: Call<ParsedContent>, t: Throwable) = openInBrowserAfterFailing()
|
||||||
|
|
||||||
private fun openInBrowserAfterFailing() {
|
private fun openInBrowserAfterFailing() {
|
||||||
CustomTabActivityHelper.openCustomTab(this@ReaderActivity, customTabsIntent, Uri.parse(url)
|
this@ReaderActivity.openItemUrl(
|
||||||
) { _, uri ->
|
url,
|
||||||
val intent = Intent(Intent.ACTION_VIEW, uri)
|
customTabsIntent,
|
||||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
true,
|
||||||
startActivity(intent)
|
false,
|
||||||
}
|
this@ReaderActivity
|
||||||
|
)
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -2,9 +2,11 @@ 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.support.v7.app.AppCompatActivity
|
import android.support.v7.app.AppCompatActivity
|
||||||
import android.support.v7.widget.LinearLayoutManager
|
import android.support.v7.widget.LinearLayoutManager
|
||||||
import android.support.v7.widget.RecyclerView
|
import android.support.v7.widget.RecyclerView
|
||||||
|
import android.support.v7.widget.Toolbar
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
|
||||||
import com.melnykov.fab.FloatingActionButton
|
import com.melnykov.fab.FloatingActionButton
|
||||||
@ -15,14 +17,19 @@ import retrofit2.Response
|
|||||||
import apps.amine.bou.readerforselfoss.adapters.SourcesListAdapter
|
import apps.amine.bou.readerforselfoss.adapters.SourcesListAdapter
|
||||||
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
|
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
|
||||||
import apps.amine.bou.readerforselfoss.api.selfoss.Sources
|
import apps.amine.bou.readerforselfoss.api.selfoss.Sources
|
||||||
|
import com.ftinc.scoop.Scoop
|
||||||
|
|
||||||
|
|
||||||
class SourcesActivity : AppCompatActivity() {
|
class SourcesActivity : AppCompatActivity() {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
Scoop.getInstance().apply(this)
|
||||||
setContentView(R.layout.activity_sources)
|
setContentView(R.layout.activity_sources)
|
||||||
|
val toolbar: Toolbar = findViewById(R.id.toolbar)
|
||||||
|
setSupportActionBar(toolbar)
|
||||||
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
@ -30,7 +37,10 @@ class SourcesActivity : AppCompatActivity() {
|
|||||||
val mFab: FloatingActionButton = findViewById(R.id.fab)
|
val mFab: FloatingActionButton = findViewById(R.id.fab)
|
||||||
val mRecyclerView: RecyclerView = findViewById(R.id.activity_sources)
|
val mRecyclerView: RecyclerView = findViewById(R.id.activity_sources)
|
||||||
val mLayoutManager = LinearLayoutManager(this)
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
val api = SelfossApi(this, this@SourcesActivity)
|
|
||||||
|
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
|
||||||
|
val api = SelfossApi(this, this@SourcesActivity, prefs.getBoolean("isSelfSignedCert", false), prefs.getBoolean("should_log_everything", false))
|
||||||
var items: ArrayList<Sources> = ArrayList()
|
var items: ArrayList<Sources> = ArrayList()
|
||||||
|
|
||||||
mFab.attachToRecyclerView(mRecyclerView)
|
mFab.attachToRecyclerView(mRecyclerView)
|
||||||
|
@ -2,14 +2,12 @@ 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.Bitmap
|
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.support.constraint.ConstraintLayout
|
import android.support.constraint.ConstraintLayout
|
||||||
import android.support.design.widget.Snackbar
|
import android.support.design.widget.Snackbar
|
||||||
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory
|
import android.support.v7.widget.CardView
|
||||||
import android.support.v7.widget.RecyclerView
|
import android.support.v7.widget.RecyclerView
|
||||||
import android.text.Html
|
import android.text.Html
|
||||||
import android.text.format.DateUtils
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageButton
|
import android.widget.ImageButton
|
||||||
@ -21,22 +19,24 @@ import android.widget.Toast
|
|||||||
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.bumptech.glide.request.target.BitmapImageViewTarget
|
|
||||||
import com.like.LikeButton
|
import com.like.LikeButton
|
||||||
import com.like.OnLikeListener
|
import com.like.OnLikeListener
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.Callback
|
import retrofit2.Callback
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
import java.text.ParseException
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
import apps.amine.bou.readerforselfoss.R
|
import apps.amine.bou.readerforselfoss.R
|
||||||
import apps.amine.bou.readerforselfoss.api.selfoss.Item
|
import apps.amine.bou.readerforselfoss.api.selfoss.Item
|
||||||
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
|
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
|
||||||
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
|
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
|
||||||
|
import apps.amine.bou.readerforselfoss.themes.AppColors
|
||||||
import apps.amine.bou.readerforselfoss.utils.*
|
import apps.amine.bou.readerforselfoss.utils.*
|
||||||
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.bitmapFitCenter
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.glide.circularBitmapDrawable
|
||||||
|
import com.crashlytics.android.Crashlytics
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
class ItemCardAdapter(private val app: Activity,
|
class ItemCardAdapter(private val app: Activity,
|
||||||
private val items: ArrayList<Item>,
|
private val items: ArrayList<Item>,
|
||||||
@ -44,8 +44,11 @@ class ItemCardAdapter(private val app: Activity,
|
|||||||
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) : RecyclerView.Adapter<ItemCardAdapter.ViewHolder>() {
|
private val fullHeightCards: Boolean,
|
||||||
private val c: Context = app.applicationContext
|
private val appColors: AppColors,
|
||||||
|
val debugReadingItems: Boolean,
|
||||||
|
val userIdentifier: String) : RecyclerView.Adapter<ItemCardAdapter.ViewHolder>() {
|
||||||
|
private val c: Context = app.baseContext
|
||||||
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
@ -63,7 +66,7 @@ class ItemCardAdapter(private val app: Activity,
|
|||||||
holder.sourceTitleAndDate.text = itm.sourceAndDateText()
|
holder.sourceTitleAndDate.text = itm.sourceAndDateText()
|
||||||
|
|
||||||
if (itm.getThumbnail(c).isEmpty()) {
|
if (itm.getThumbnail(c).isEmpty()) {
|
||||||
Glide.clear(holder.itemImage)
|
Glide.with(c).clear(holder.itemImage)
|
||||||
holder.itemImage.setImageDrawable(null)
|
holder.itemImage.setImageDrawable(null)
|
||||||
} else {
|
} else {
|
||||||
if (fullHeightCards) {
|
if (fullHeightCards) {
|
||||||
@ -127,11 +130,31 @@ class ItemCardAdapter(private val app: Activity,
|
|||||||
|
|
||||||
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
|
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
|
||||||
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
|
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
|
||||||
|
if (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)
|
doUnmark(i, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
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()
|
Toast.makeText(app, app.getString(R.string.cant_mark_read), Toast.LENGTH_SHORT).show()
|
||||||
items.add(i)
|
items.add(i)
|
||||||
notifyItemInserted(position)
|
notifyItemInserted(position)
|
||||||
@ -150,6 +173,7 @@ class ItemCardAdapter(private val app: Activity,
|
|||||||
lateinit var sourceTitleAndDate: TextView
|
lateinit var sourceTitleAndDate: TextView
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
(mView.findViewById<CardView>(R.id.card)).setCardBackgroundColor(appColors.cardBackground)
|
||||||
handleClickListeners()
|
handleClickListeners()
|
||||||
handleCustomTabActions()
|
handleCustomTabActions()
|
||||||
}
|
}
|
||||||
@ -208,7 +232,7 @@ class ItemCardAdapter(private val app: Activity,
|
|||||||
helper.bindCustomTabsService(app)
|
helper.bindCustomTabsService(app)
|
||||||
|
|
||||||
mView.setOnClickListener {
|
mView.setOnClickListener {
|
||||||
c.openItemUrl(items[adapterPosition],
|
c.openItemUrl(items[adapterPosition].getLinkDecoded(),
|
||||||
customTabsIntent,
|
customTabsIntent,
|
||||||
internalBrowser,
|
internalBrowser,
|
||||||
articleViewer,
|
articleViewer,
|
||||||
|
@ -3,16 +3,11 @@ package apps.amine.bou.readerforselfoss.adapters
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.net.Uri
|
|
||||||
import android.support.constraint.ConstraintLayout
|
import android.support.constraint.ConstraintLayout
|
||||||
import android.support.design.widget.Snackbar
|
import android.support.design.widget.Snackbar
|
||||||
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory
|
|
||||||
import android.support.v7.widget.RecyclerView
|
import android.support.v7.widget.RecyclerView
|
||||||
import android.text.Html
|
import android.text.Html
|
||||||
import android.text.format.DateUtils
|
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -21,15 +16,11 @@ import android.widget.*
|
|||||||
|
|
||||||
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.request.target.BitmapImageViewTarget
|
|
||||||
import com.like.LikeButton
|
import com.like.LikeButton
|
||||||
import com.like.OnLikeListener
|
import com.like.OnLikeListener
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.Callback
|
import retrofit2.Callback
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
import java.text.ParseException
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
import apps.amine.bou.readerforselfoss.R
|
import apps.amine.bou.readerforselfoss.R
|
||||||
@ -38,6 +29,10 @@ import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
|
|||||||
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
|
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
|
||||||
import apps.amine.bou.readerforselfoss.utils.*
|
import apps.amine.bou.readerforselfoss.utils.*
|
||||||
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.circularBitmapDrawable
|
||||||
|
import com.crashlytics.android.Crashlytics
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
|
||||||
class ItemListAdapter(private val app: Activity,
|
class ItemListAdapter(private val app: Activity,
|
||||||
@ -46,9 +41,11 @@ class ItemListAdapter(private val app: Activity,
|
|||||||
private val helper: CustomTabActivityHelper,
|
private val helper: CustomTabActivityHelper,
|
||||||
private val clickBehavior: Boolean,
|
private val clickBehavior: Boolean,
|
||||||
private val internalBrowser: Boolean,
|
private val internalBrowser: Boolean,
|
||||||
private val articleViewer: Boolean) : RecyclerView.Adapter<ItemListAdapter.ViewHolder>() {
|
private val articleViewer: Boolean,
|
||||||
|
val debugReadingItems: Boolean,
|
||||||
|
val userIdentifier: String) : RecyclerView.Adapter<ItemListAdapter.ViewHolder>() {
|
||||||
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
||||||
private val c: Context = app.applicationContext
|
private val c: Context = app.baseContext
|
||||||
private val bars: ArrayList<Boolean> = ArrayList(Collections.nCopies(items.size + 1, false))
|
private val bars: ArrayList<Boolean> = ArrayList(Collections.nCopies(items.size + 1, false))
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
@ -141,11 +138,31 @@ class ItemListAdapter(private val app: Activity,
|
|||||||
|
|
||||||
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
|
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
|
||||||
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
|
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
|
||||||
|
if (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)
|
doUnmark(i, position)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
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()
|
Toast.makeText(app, app.getString(R.string.cant_mark_read), Toast.LENGTH_SHORT).show()
|
||||||
items.add(i)
|
items.add(i)
|
||||||
notifyItemInserted(position)
|
notifyItemInserted(position)
|
||||||
@ -222,7 +239,7 @@ class ItemListAdapter(private val app: Activity,
|
|||||||
|
|
||||||
if (!clickBehavior) {
|
if (!clickBehavior) {
|
||||||
mView.setOnClickListener {
|
mView.setOnClickListener {
|
||||||
c.openItemUrl(items[adapterPosition],
|
c.openItemUrl(items[adapterPosition].getLinkDecoded(),
|
||||||
customTabsIntent,
|
customTabsIntent,
|
||||||
internalBrowser,
|
internalBrowser,
|
||||||
articleViewer,
|
articleViewer,
|
||||||
@ -235,7 +252,7 @@ class ItemListAdapter(private val app: Activity,
|
|||||||
} else {
|
} else {
|
||||||
mView.setOnClickListener { actionBarShowHide() }
|
mView.setOnClickListener { actionBarShowHide() }
|
||||||
mView.setOnLongClickListener {
|
mView.setOnLongClickListener {
|
||||||
c.openItemUrl(items[adapterPosition],
|
c.openItemUrl(items[adapterPosition].getLinkDecoded(),
|
||||||
customTabsIntent,
|
customTabsIntent,
|
||||||
internalBrowser,
|
internalBrowser,
|
||||||
articleViewer,
|
articleViewer,
|
||||||
|
@ -21,7 +21,7 @@ import apps.amine.bou.readerforselfoss.R
|
|||||||
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
|
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
|
||||||
import apps.amine.bou.readerforselfoss.api.selfoss.Sources
|
import apps.amine.bou.readerforselfoss.api.selfoss.Sources
|
||||||
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
|
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
|
||||||
import apps.amine.bou.readerforselfoss.utils.circularBitmapDrawable
|
import apps.amine.bou.readerforselfoss.utils.glide.circularBitmapDrawable
|
||||||
import apps.amine.bou.readerforselfoss.utils.toTextDrawableString
|
import apps.amine.bou.readerforselfoss.utils.toTextDrawableString
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,13 +9,16 @@ import retrofit2.converter.gson.GsonConverterFactory
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MercuryApi(private val key: String) {
|
class MercuryApi(private val key: String, shouldLog: Boolean) {
|
||||||
private val service: MercuryService
|
private val service: MercuryService
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
||||||
val interceptor = HttpLoggingInterceptor()
|
val interceptor = HttpLoggingInterceptor()
|
||||||
interceptor.level = HttpLoggingInterceptor.Level.BODY
|
interceptor.level = if (shouldLog)
|
||||||
|
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()
|
||||||
|
@ -2,20 +2,20 @@ package apps.amine.bou.readerforselfoss.api.mercury
|
|||||||
|
|
||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
|
||||||
|
class ParsedContent(@SerializedName("title") val title: String,
|
||||||
class ParsedContent(val title: String,
|
@SerializedName("content") val content: String,
|
||||||
val content: String,
|
@SerializedName("date_published") val date_published: String,
|
||||||
val date_published: String,
|
@SerializedName("lead_image_url") val lead_image_url: String,
|
||||||
val lead_image_url: String,
|
@SerializedName("dek") val dek: String,
|
||||||
val dek: String,
|
@SerializedName("url") val url: String,
|
||||||
val url: String,
|
@SerializedName("domain") val domain: String,
|
||||||
val domain: String,
|
@SerializedName("excerpt") val excerpt: String,
|
||||||
val excerpt: String,
|
@SerializedName("total_pages") val total_pages: Int,
|
||||||
val total_pages: Int,
|
@SerializedName("rendered_pages") val rendered_pages: Int,
|
||||||
val rendered_pages: Int,
|
@SerializedName("next_page_url") val next_page_url: String) : Parcelable {
|
||||||
val next_page_url: String) : Parcelable {
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField val CREATOR: Parcelable.Creator<ParsedContent> = object : Parcelable.Creator<ParsedContent> {
|
@JvmField val CREATOR: Parcelable.Creator<ParsedContent> = object : Parcelable.Creator<ParsedContent> {
|
||||||
|
@ -2,11 +2,6 @@ package apps.amine.bou.readerforselfoss.api.selfoss
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.support.v7.app.AlertDialog
|
|
||||||
import android.widget.Toast
|
|
||||||
import apps.amine.bou.readerforselfoss.LoginActivity
|
|
||||||
import apps.amine.bou.readerforselfoss.R
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
import com.burgstaller.okhttp.AuthenticationCacheInterceptor
|
import com.burgstaller.okhttp.AuthenticationCacheInterceptor
|
||||||
@ -23,29 +18,40 @@ import retrofit2.Retrofit
|
|||||||
import retrofit2.converter.gson.GsonConverterFactory
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
|
||||||
import apps.amine.bou.readerforselfoss.utils.Config
|
import apps.amine.bou.readerforselfoss.utils.Config
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.getUnsafeHttpClient
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// codebeat:disable[ARITY,TOO_MANY_FUNCTIONS]
|
// codebeat:disable[ARITY,TOO_MANY_FUNCTIONS]
|
||||||
class SelfossApi(c: Context, callingActivity: Activity) {
|
class SelfossApi(c: Context, callingActivity: Activity, isWithSelfSignedCert: Boolean, shouldLog: Boolean) {
|
||||||
|
|
||||||
private lateinit var service: SelfossService
|
private lateinit var service: SelfossService
|
||||||
private val config: Config = Config(c)
|
private val config: Config = Config(c)
|
||||||
private val userName: String
|
private val userName: String
|
||||||
private val password: String
|
private val password: String
|
||||||
|
|
||||||
|
fun OkHttpClient.Builder.maybeWithSelfSigned(isWithSelfSignedCert: Boolean): OkHttpClient.Builder =
|
||||||
|
if (isWithSelfSignedCert) {
|
||||||
|
getUnsafeHttpClient()
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
fun Credentials.createAuthenticator(): DispatchingAuthenticator =
|
fun Credentials.createAuthenticator(): DispatchingAuthenticator =
|
||||||
DispatchingAuthenticator.Builder()
|
DispatchingAuthenticator.Builder()
|
||||||
.with("digest", DigestAuthenticator(this))
|
.with("digest", DigestAuthenticator(this))
|
||||||
.with("basic", BasicAuthenticator(this))
|
.with("basic", BasicAuthenticator(this))
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
fun DispatchingAuthenticator.getHttpClien(): OkHttpClient {
|
fun DispatchingAuthenticator.getHttpClien(isWithSelfSignedCert: Boolean): OkHttpClient.Builder {
|
||||||
val authCache = ConcurrentHashMap<String, CachingAuthenticator>()
|
val authCache = ConcurrentHashMap<String, CachingAuthenticator>()
|
||||||
return OkHttpClient
|
return OkHttpClient
|
||||||
.Builder()
|
.Builder()
|
||||||
|
.maybeWithSelfSigned(isWithSelfSignedCert)
|
||||||
.authenticator(CachingAuthenticatorDecorator(this, authCache))
|
.authenticator(CachingAuthenticatorDecorator(this, authCache))
|
||||||
.addInterceptor(AuthenticationCacheInterceptor(authCache))
|
.addInterceptor(AuthenticationCacheInterceptor(authCache))
|
||||||
.build()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -65,13 +71,23 @@ class SelfossApi(c: Context, callingActivity: Activity) {
|
|||||||
.setLenient()
|
.setLenient()
|
||||||
.create()
|
.create()
|
||||||
|
|
||||||
|
val logging = HttpLoggingInterceptor()
|
||||||
|
|
||||||
|
logging.level = if (shouldLog)
|
||||||
|
HttpLoggingInterceptor.Level.BODY
|
||||||
|
else
|
||||||
|
HttpLoggingInterceptor.Level.NONE
|
||||||
|
|
||||||
|
val httpClient = authenticator.getHttpClien(isWithSelfSignedCert)
|
||||||
|
|
||||||
|
httpClient.addInterceptor(logging)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val retrofit =
|
val retrofit =
|
||||||
Retrofit
|
Retrofit
|
||||||
.Builder()
|
.Builder()
|
||||||
.baseUrl(config.baseUrl)
|
.baseUrl(config.baseUrl)
|
||||||
.client(authenticator.getHttpClien())
|
.client(httpClient.build())
|
||||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
.addConverterFactory(GsonConverterFactory.create(gson))
|
||||||
.build()
|
.build()
|
||||||
service = retrofit.create(SelfossService::class.java)
|
service = retrofit.create(SelfossService::class.java)
|
||||||
@ -83,17 +99,17 @@ class SelfossApi(c: Context, callingActivity: Activity) {
|
|||||||
fun login(): Call<SuccessResponse> =
|
fun login(): Call<SuccessResponse> =
|
||||||
service.loginToSelfoss(config.userLogin, config.userPassword)
|
service.loginToSelfoss(config.userLogin, config.userPassword)
|
||||||
|
|
||||||
fun readItems(tag: String?, sourceId: Long?, search: String?): Call<List<Item>> =
|
fun readItems(tag: String?, sourceId: Long?, search: String?, itemsNumber: Int, offset: Int): Call<List<Item>> =
|
||||||
getItems("read", tag, sourceId, search)
|
getItems("read", tag, sourceId, search, itemsNumber, offset)
|
||||||
|
|
||||||
fun newItems(tag: String?, sourceId: Long?, search: String?): Call<List<Item>> =
|
fun newItems(tag: String?, sourceId: Long?, search: String?, itemsNumber: Int, offset: Int): Call<List<Item>> =
|
||||||
getItems("unread", tag, sourceId, search)
|
getItems("unread", tag, sourceId, search, itemsNumber, offset)
|
||||||
|
|
||||||
fun starredItems(tag: String?, sourceId: Long?, search: String?): Call<List<Item>> =
|
fun starredItems(tag: String?, sourceId: Long?, search: String?, itemsNumber: Int, offset: Int): Call<List<Item>> =
|
||||||
getItems("starred", tag, sourceId, search)
|
getItems("starred", tag, sourceId, search, itemsNumber, offset)
|
||||||
|
|
||||||
private fun getItems(type: String, tag: String?, sourceId: Long?, search: String?): Call<List<Item>> =
|
private fun getItems(type: String, tag: String?, sourceId: Long?, search: String?, items: Int, offset: Int): Call<List<Item>> =
|
||||||
service.getItems(type, tag, sourceId, search, userName, password)
|
service.getItems(type, tag, sourceId, search, userName, password, items, offset)
|
||||||
|
|
||||||
fun markItem(itemId: String): Call<SuccessResponse> =
|
fun markItem(itemId: String): Call<SuccessResponse> =
|
||||||
service.markAsRead(itemId, userName, password)
|
service.markAsRead(itemId, userName, password)
|
||||||
|
@ -7,7 +7,7 @@ import android.os.Parcelable
|
|||||||
|
|
||||||
import apps.amine.bou.readerforselfoss.utils.Config
|
import apps.amine.bou.readerforselfoss.utils.Config
|
||||||
import apps.amine.bou.readerforselfoss.utils.isEmptyOrNullOrNullString
|
import apps.amine.bou.readerforselfoss.utils.isEmptyOrNullOrNullString
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
|
||||||
private fun constructUrl(config: Config?, path: String, file: String): String {
|
private fun constructUrl(config: Config?, path: String, file: String): String {
|
||||||
@ -19,23 +19,28 @@ private fun constructUrl(config: Config?, path: String, file: String): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
data class Tag(val tag: String, val color: String, val unread: Int)
|
data class Tag(@SerializedName("tag") val tag: String,
|
||||||
|
@SerializedName("color") val color: String,
|
||||||
|
@SerializedName("unread") val unread: Int)
|
||||||
|
|
||||||
class SuccessResponse(val success: Boolean) {
|
class SuccessResponse(@SerializedName("success") val success: Boolean) {
|
||||||
val isSuccess: Boolean
|
val isSuccess: Boolean
|
||||||
get() = success
|
get() = success
|
||||||
}
|
}
|
||||||
|
|
||||||
class Stats(val total: Int, val unread: Int, val starred: Int)
|
class Stats(@SerializedName("total") val total: Int,
|
||||||
|
@SerializedName("unread") val unread: Int,
|
||||||
|
@SerializedName("starred") val starred: Int)
|
||||||
|
|
||||||
data class Spout(val name: String, val description: String)
|
data class Spout(@SerializedName("name") val name: String,
|
||||||
|
@SerializedName("description") val description: String)
|
||||||
|
|
||||||
data class Sources(val id: String,
|
data class Sources(@SerializedName("id") val id: String,
|
||||||
val title: String,
|
@SerializedName("title") val title: String,
|
||||||
val tags: String,
|
@SerializedName("tags") val tags: String,
|
||||||
val spout: String,
|
@SerializedName("spout") val spout: String,
|
||||||
val error: String,
|
@SerializedName("error") val error: String,
|
||||||
val icon: String) {
|
@SerializedName("icon") val icon: String) {
|
||||||
var config: Config? = null
|
var config: Config? = null
|
||||||
|
|
||||||
fun getIcon(app: Context): String {
|
fun getIcon(app: Context): String {
|
||||||
@ -47,15 +52,15 @@ data class Sources(val id: String,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Item(val id: String,
|
data class Item(@SerializedName("id") val id: String,
|
||||||
val datetime: String,
|
@SerializedName("datetime") val datetime: String,
|
||||||
val title: String,
|
@SerializedName("title") val title: String,
|
||||||
val unread: Boolean,
|
@SerializedName("unread") val unread: Boolean,
|
||||||
val starred: Boolean,
|
@SerializedName("starred") val starred: Boolean,
|
||||||
val thumbnail: String,
|
@SerializedName("thumbnail") val thumbnail: String,
|
||||||
val icon: String,
|
@SerializedName("icon") val icon: String,
|
||||||
val link: String,
|
@SerializedName("link") val link: String,
|
||||||
val sourcetitle: String) : Parcelable {
|
@SerializedName("sourcetitle") val sourcetitle: String) : Parcelable {
|
||||||
|
|
||||||
var config: Config? = null
|
var config: Config? = null
|
||||||
|
|
||||||
@ -109,20 +114,26 @@ data class Item(val id: String,
|
|||||||
// TODO: maybe find a better way to handle these kind of urls
|
// TODO: maybe find a better way to handle these kind of urls
|
||||||
fun getLinkDecoded(): String {
|
fun getLinkDecoded(): String {
|
||||||
var stringUrl: String
|
var stringUrl: String
|
||||||
if (link.startsWith("http://news.google.com/news/") || link.startsWith("https://news.google.com/news/")) {
|
stringUrl = if (link.startsWith("http://news.google.com/news/") || link.startsWith("https://news.google.com/news/")) {
|
||||||
if (link.contains("&url=")) {
|
if (link.contains("&url=")) {
|
||||||
stringUrl = link.substringAfter("&url=")
|
link.substringAfter("&url=")
|
||||||
} else {
|
} else {
|
||||||
stringUrl = this.link.replace("&", "&")
|
this.link.replace("&", "&")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
stringUrl = this.link.replace("&", "&")
|
this.link.replace("&", "&")
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle :443 => https
|
// handle :443 => https
|
||||||
if (stringUrl.contains(":443")) {
|
if (stringUrl.contains(":443")) {
|
||||||
stringUrl = stringUrl.replace(":443", "").replace("http://", "https://")
|
stringUrl = stringUrl.replace(":443", "").replace("http://", "https://")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle url not starting with http
|
||||||
|
if (stringUrl.startsWith("//")) {
|
||||||
|
stringUrl = "http:" + stringUrl
|
||||||
|
}
|
||||||
|
|
||||||
return stringUrl
|
return stringUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,9 @@ internal interface SelfossService {
|
|||||||
@Query("source") source: Long?,
|
@Query("source") source: Long?,
|
||||||
@Query("search") search: String?,
|
@Query("search") search: String?,
|
||||||
@Query("username") username: String,
|
@Query("username") username: String,
|
||||||
@Query("password") password: String): Call<List<Item>>
|
@Query("password") password: String,
|
||||||
|
@Query("items") items: Int,
|
||||||
|
@Query("offset") offset: Int): Call<List<Item>>
|
||||||
|
|
||||||
@POST("mark/{id}")
|
@POST("mark/{id}")
|
||||||
fun markAsRead(@Path("id") id: String,
|
fun markAsRead(@Path("id") id: String,
|
||||||
|
@ -6,12 +6,19 @@ import android.preference.PreferenceActivity;
|
|||||||
import android.support.annotation.LayoutRes;
|
import android.support.annotation.LayoutRes;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.design.widget.AppBarLayout;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.support.v7.app.AppCompatDelegate;
|
import android.support.v7.app.AppCompatDelegate;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
import apps.amine.bou.readerforselfoss.R;
|
||||||
|
import com.ftinc.scoop.Scoop;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link PreferenceActivity} which implements and proxies the necessary calls
|
* A {@link PreferenceActivity} which implements and proxies the necessary calls
|
||||||
@ -25,12 +32,23 @@ public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
getDelegate().installViewFactory();
|
getDelegate().installViewFactory();
|
||||||
getDelegate().onCreate(savedInstanceState);
|
getDelegate().onCreate(savedInstanceState);
|
||||||
|
Scoop.getInstance().apply(this);
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostCreate(Bundle savedInstanceState) {
|
protected void onPostCreate(Bundle savedInstanceState) {
|
||||||
super.onPostCreate(savedInstanceState);
|
super.onPostCreate(savedInstanceState);
|
||||||
|
|
||||||
|
LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
|
||||||
|
AppBarLayout bar = (AppBarLayout) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
|
||||||
|
Toolbar toolbar = bar.findViewById(R.id.toolbar);
|
||||||
|
setSupportActionBar(toolbar);
|
||||||
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
|
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
||||||
|
|
||||||
|
root.addView(bar, 0);
|
||||||
|
|
||||||
getDelegate().onPostCreate(savedInstanceState);
|
getDelegate().onPostCreate(savedInstanceState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,24 +2,35 @@ package apps.amine.bou.readerforselfoss.settings;
|
|||||||
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
|
import android.content.ClipData;
|
||||||
|
import android.content.ClipboardManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.preference.EditTextPreference;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.Preference.OnPreferenceChangeListener;
|
import android.preference.Preference.OnPreferenceChangeListener;
|
||||||
|
import android.preference.Preference.OnPreferenceClickListener;
|
||||||
import android.preference.PreferenceActivity;
|
import android.preference.PreferenceActivity;
|
||||||
import android.preference.SwitchPreference;
|
import android.preference.SwitchPreference;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.preference.PreferenceFragment;
|
import android.preference.PreferenceFragment;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
import android.text.InputFilter;
|
||||||
|
import android.text.Spanned;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import apps.amine.bou.readerforselfoss.BuildConfig;
|
||||||
import apps.amine.bou.readerforselfoss.R;
|
import apps.amine.bou.readerforselfoss.R;
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.Config;
|
||||||
|
import com.ftinc.scoop.ui.ScoopSettingsActivity;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,6 +129,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
|
|||||||
protected boolean isValidFragment(String fragmentName) {
|
protected boolean isValidFragment(String fragmentName) {
|
||||||
return PreferenceFragment.class.getName().equals(fragmentName)
|
return PreferenceFragment.class.getName().equals(fragmentName)
|
||||||
|| GeneralPreferenceFragment.class.getName().equals(fragmentName)
|
|| GeneralPreferenceFragment.class.getName().equals(fragmentName)
|
||||||
|
|| DebugPreferenceFragment.class.getName().equals(fragmentName)
|
||||||
|| LinksPreferenceFragment.class.getName().equals(fragmentName);
|
|| LinksPreferenceFragment.class.getName().equals(fragmentName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,6 +155,61 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
EditTextPreference itemsNumber = (EditTextPreference) findPreference("prefer_api_items_number");
|
||||||
|
itemsNumber.getEditText().setFilters(new InputFilter[]{
|
||||||
|
new InputFilter (){
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
|
||||||
|
try {
|
||||||
|
int input = Integer.parseInt(dest.toString() + source.toString());
|
||||||
|
if (input <= 200 && input >0)
|
||||||
|
return null;
|
||||||
|
} catch (NumberFormatException nfe) { }
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
int id = item.getItemId();
|
||||||
|
if (id == android.R.id.home) {
|
||||||
|
getActivity().finish();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||||
|
public static class DebugPreferenceFragment extends PreferenceFragment {
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
addPreferencesFromResource(R.xml.pref_debug);
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
|
||||||
|
SharedPreferences pref = getActivity().getSharedPreferences(Config.Companion.getSettingsName(), Context.MODE_PRIVATE);
|
||||||
|
final String id = pref.getString("unique_id", "...");
|
||||||
|
|
||||||
|
final Preference identifier = findPreference("debug_identifier");
|
||||||
|
final ClipboardManager clipboard = (ClipboardManager)
|
||||||
|
getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||||
|
|
||||||
|
identifier.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
|
ClipData clip = ClipData.newPlainText("Selfoss unique id", id);
|
||||||
|
clipboard.setPrimaryClip(clip);
|
||||||
|
|
||||||
|
Toast.makeText(getActivity(), R.string.unique_id_to_clipboard, Toast.LENGTH_LONG).show();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
identifier.setTitle(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -176,7 +243,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
|
|||||||
findPreference( "trackerLink" ).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
findPreference( "trackerLink" ).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
openUrl(Uri.parse(getString(R.string.tracker_url)));
|
openUrl(Uri.parse(BuildConfig.TRACKER_URL));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -184,7 +251,15 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
|
|||||||
findPreference("sourceLink").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
findPreference("sourceLink").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
openUrl(Uri.parse(getString(R.string.source_url)));
|
openUrl(Uri.parse(BuildConfig.SOURCE_URL));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
findPreference("translation").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
|
openUrl(Uri.parse(BuildConfig.TRANSLATION_URL));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -201,6 +276,17 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onHeaderClick(Header header, int position) {
|
||||||
|
super.onHeaderClick(header, position);
|
||||||
|
if (header.id == R.id.theme_change) {
|
||||||
|
Intent intent = ScoopSettingsActivity.createIntent(getApplicationContext());
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
getApplicationContext().startActivity(intent);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
int id = item.getItemId();
|
int id = item.getItemId();
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
package apps.amine.bou.readerforselfoss.themes
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.support.annotation.ColorInt
|
||||||
|
import android.util.TypedValue
|
||||||
|
import apps.amine.bou.readerforselfoss.R
|
||||||
|
|
||||||
|
|
||||||
|
class AppColors(a: Activity) {
|
||||||
|
@ColorInt val accent: Int
|
||||||
|
@ColorInt val dark: Int
|
||||||
|
@ColorInt val primary: Int
|
||||||
|
@ColorInt val cardBackground: Int
|
||||||
|
@ColorInt val windowBackground: Int
|
||||||
|
val isDarkTheme: Boolean
|
||||||
|
|
||||||
|
init {
|
||||||
|
val wrapper = Context::class.java
|
||||||
|
val method = wrapper!!.getMethod("getThemeResId")
|
||||||
|
method.isAccessible = true
|
||||||
|
|
||||||
|
isDarkTheme = when(method.invoke(a.baseContext)) {
|
||||||
|
R.style.NoBarTealOrangeDark,
|
||||||
|
R.style.NoBarDark,
|
||||||
|
R.style.NoBarBlueAmberDark,
|
||||||
|
R.style.NoBarGreyOrangeDark,
|
||||||
|
R.style.NoBarIndigoPinkDark,
|
||||||
|
R.style.NoBarRedTealDark,
|
||||||
|
R.style.NoBarCyanPinkDark -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
|
val typedAccent = TypedValue()
|
||||||
|
val typedAccentDark = TypedValue()
|
||||||
|
val typedPrimary = TypedValue()
|
||||||
|
val typedCardBackground = TypedValue()
|
||||||
|
val typedWindowBackground = TypedValue()
|
||||||
|
|
||||||
|
a.theme.resolveAttribute(R.attr.colorAccent, typedAccent, true)
|
||||||
|
a.theme.resolveAttribute(R.attr.colorAccent, typedAccent, true)
|
||||||
|
a.theme.resolveAttribute(R.attr.colorPrimary, typedPrimary, true)
|
||||||
|
a.theme.resolveAttribute(R.attr.cardBackgroundColor, typedCardBackground, true)
|
||||||
|
a.theme.resolveAttribute(android.R.attr.colorBackground, typedWindowBackground, true)
|
||||||
|
accent = typedAccent.data
|
||||||
|
dark = typedAccentDark.data
|
||||||
|
primary = typedPrimary.data
|
||||||
|
cardBackground = typedCardBackground.data
|
||||||
|
windowBackground = typedWindowBackground.data
|
||||||
|
}
|
||||||
|
}
|
@ -6,10 +6,8 @@ import android.content.SharedPreferences
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.support.v7.app.AlertDialog
|
import android.support.v7.app.AlertDialog
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.util.Patterns
|
|
||||||
|
|
||||||
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
|
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
|
||||||
import okhttp3.HttpUrl
|
|
||||||
|
|
||||||
import apps.amine.bou.readerforselfoss.BuildConfig
|
import apps.amine.bou.readerforselfoss.BuildConfig
|
||||||
import apps.amine.bou.readerforselfoss.R
|
import apps.amine.bou.readerforselfoss.R
|
||||||
@ -36,17 +34,6 @@ fun Context.checkAndDisplayStoreApk() = {
|
|||||||
} else Unit
|
} else Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.isUrlValid(): Boolean {
|
|
||||||
val baseUrl = HttpUrl.parse(this)
|
|
||||||
var existsAndEndsWithSlash = false
|
|
||||||
if (baseUrl != null) {
|
|
||||||
val pathSegments = baseUrl.pathSegments()
|
|
||||||
existsAndEndsWithSlash = "" == pathSegments[pathSegments.size - 1]
|
|
||||||
}
|
|
||||||
|
|
||||||
return Patterns.WEB_URL.matcher(this).matches() && existsAndEndsWithSlash
|
|
||||||
}
|
|
||||||
|
|
||||||
fun String?.isEmptyOrNullOrNullString(): Boolean =
|
fun String?.isEmptyOrNullOrNullString(): Boolean =
|
||||||
this == null || this == "null" || this.isEmpty()
|
this == null || this == "null" || this.isEmpty()
|
||||||
|
|
||||||
@ -94,7 +81,7 @@ fun String.longHash(): Long {
|
|||||||
val l = this.length
|
val l = this.length
|
||||||
val chars = this.toCharArray()
|
val chars = this.toCharArray()
|
||||||
|
|
||||||
for (i in 0..l - 1) {
|
for (i in 0 until l) {
|
||||||
h = 31 * h + chars[i].toLong()
|
h = 31 * h + chars[i].toLong()
|
||||||
}
|
}
|
||||||
return h
|
return h
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
package apps.amine.bou.readerforselfoss.utils
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory
|
|
||||||
import android.widget.ImageView
|
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import com.bumptech.glide.request.target.BitmapImageViewTarget
|
|
||||||
|
|
||||||
|
|
||||||
fun Context.bitmapCenterCrop(url: String, iv: ImageView) =
|
|
||||||
Glide.with(this).load(url).asBitmap().centerCrop().into(iv)
|
|
||||||
|
|
||||||
fun Context.bitmapFitCenter(url: String, iv: ImageView) =
|
|
||||||
Glide.with(this).load(url).asBitmap().fitCenter().into(iv)
|
|
||||||
|
|
||||||
fun Context.circularBitmapDrawable(url: String, iv: ImageView) =
|
|
||||||
Glide.with(this).load(url).asBitmap().centerCrop().into(object : BitmapImageViewTarget(iv) {
|
|
||||||
override fun setResource(resource: Bitmap) {
|
|
||||||
val circularBitmapDrawable = RoundedBitmapDrawableFactory.create(resources, resource)
|
|
||||||
circularBitmapDrawable.isCircular = true
|
|
||||||
iv.setImageDrawable(circularBitmapDrawable)
|
|
||||||
}
|
|
||||||
})
|
|
@ -0,0 +1,39 @@
|
|||||||
|
package apps.amine.bou.readerforselfoss.utils
|
||||||
|
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import java.security.cert.CertificateException
|
||||||
|
import java.security.cert.X509Certificate
|
||||||
|
import javax.net.ssl.SSLContext
|
||||||
|
import javax.net.ssl.TrustManager
|
||||||
|
import javax.net.ssl.X509TrustManager
|
||||||
|
|
||||||
|
fun getUnsafeHttpClient() =
|
||||||
|
try {
|
||||||
|
// Create a trust manager that does not validate certificate chains
|
||||||
|
val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
|
||||||
|
override fun getAcceptedIssuers(): Array<X509Certificate> =
|
||||||
|
arrayOf()
|
||||||
|
|
||||||
|
@Throws(CertificateException::class)
|
||||||
|
override fun checkClientTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(CertificateException::class)
|
||||||
|
override fun checkServerTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) {
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
// Install the all-trusting trust manager
|
||||||
|
val sslContext = SSLContext.getInstance("SSL")
|
||||||
|
sslContext.init(null, trustAllCerts, java.security.SecureRandom())
|
||||||
|
|
||||||
|
val sslSocketFactory = sslContext.socketFactory
|
||||||
|
|
||||||
|
OkHttpClient.Builder()
|
||||||
|
.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
|
||||||
|
.hostnameVerifier { _, _ -> true }
|
||||||
|
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
@ -16,7 +16,7 @@ fun String.toTextDrawableString(): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun Item.sourceAndDateText(): String {
|
fun Item.sourceAndDateText(): String {
|
||||||
var formattedDate: String = try {
|
val formattedDate: String = try {
|
||||||
" " + DateUtils.getRelativeTimeSpanString(
|
" " + DateUtils.getRelativeTimeSpanString(
|
||||||
SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(this.datetime).time,
|
SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(this.datetime).time,
|
||||||
Date().time,
|
Date().time,
|
||||||
|
@ -7,14 +7,13 @@ import android.content.Intent
|
|||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.support.customtabs.CustomTabsIntent
|
import android.support.customtabs.CustomTabsIntent
|
||||||
|
import android.util.Patterns
|
||||||
import xyz.klinker.android.drag_dismiss.DragDismissIntentBuilder
|
import android.widget.Toast
|
||||||
|
|
||||||
import apps.amine.bou.readerforselfoss.R
|
import apps.amine.bou.readerforselfoss.R
|
||||||
import apps.amine.bou.readerforselfoss.ReaderActivity
|
import apps.amine.bou.readerforselfoss.ReaderActivity
|
||||||
import apps.amine.bou.readerforselfoss.api.selfoss.Item
|
|
||||||
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
|
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
|
||||||
|
import okhttp3.HttpUrl
|
||||||
|
import xyz.klinker.android.drag_dismiss.DragDismissIntentBuilder
|
||||||
|
|
||||||
|
|
||||||
fun Context.buildCustomTabsIntent(): CustomTabsIntent {
|
fun Context.buildCustomTabsIntent(): CustomTabsIntent {
|
||||||
@ -50,15 +49,17 @@ fun Context.buildCustomTabsIntent(): CustomTabsIntent {
|
|||||||
return intentBuilder.build()
|
return intentBuilder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.openItemUrl(i: Item,
|
fun Context.openItemUrl(linkDecoded: String,
|
||||||
customTabsIntent: CustomTabsIntent,
|
customTabsIntent: CustomTabsIntent,
|
||||||
internalBrowser: Boolean,
|
internalBrowser: Boolean,
|
||||||
articleViewer: Boolean,
|
articleViewer: Boolean,
|
||||||
app: Activity) {
|
app: Activity) {
|
||||||
|
|
||||||
|
if (!linkDecoded.isUrlValid()) {
|
||||||
|
Toast.makeText(this, this.getString(R.string.cant_open_invalid_url), Toast.LENGTH_LONG).show()
|
||||||
|
} else {
|
||||||
if (!internalBrowser) {
|
if (!internalBrowser) {
|
||||||
val intent = Intent(Intent.ACTION_VIEW)
|
openInBrowser(linkDecoded, app)
|
||||||
intent.data = Uri.parse(i.getLinkDecoded())
|
|
||||||
app.startActivity(intent)
|
|
||||||
} else {
|
} else {
|
||||||
if (articleViewer) {
|
if (articleViewer) {
|
||||||
val intent = Intent(this, ReaderActivity::class.java)
|
val intent = Intent(this, ReaderActivity::class.java)
|
||||||
@ -66,17 +67,43 @@ fun Context.openItemUrl(i: Item,
|
|||||||
DragDismissIntentBuilder(this)
|
DragDismissIntentBuilder(this)
|
||||||
.setFullscreenOnTablets(true) // defaults to false, tablets will have padding on each side
|
.setFullscreenOnTablets(true) // defaults to false, tablets will have padding on each side
|
||||||
.setDragElasticity(DragDismissIntentBuilder.DragElasticity.NORMAL) // Larger elasticities will make it easier to dismiss.
|
.setDragElasticity(DragDismissIntentBuilder.DragElasticity.NORMAL) // Larger elasticities will make it easier to dismiss.
|
||||||
|
.setDrawUnderStatusBar(true)
|
||||||
.build(intent)
|
.build(intent)
|
||||||
|
|
||||||
intent.putExtra("url", i.getLinkDecoded())
|
intent.putExtra("url", linkDecoded)
|
||||||
app.startActivity(intent)
|
app.startActivity(intent)
|
||||||
} else {
|
} else {
|
||||||
CustomTabActivityHelper.openCustomTab(app, customTabsIntent, Uri.parse(i.getLinkDecoded())
|
try {
|
||||||
|
CustomTabActivityHelper.openCustomTab(app, customTabsIntent, Uri.parse(linkDecoded)
|
||||||
) { _, uri ->
|
) { _, uri ->
|
||||||
val intent = Intent(Intent.ACTION_VIEW, uri)
|
val intent = Intent(Intent.ACTION_VIEW, uri)
|
||||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
openInBrowser(linkDecoded, app)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun openInBrowser(linkDecoded: String, app: Activity) {
|
||||||
|
val intent = Intent(Intent.ACTION_VIEW)
|
||||||
|
intent.data = Uri.parse(linkDecoded)
|
||||||
|
app.startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.isUrlValid(): Boolean =
|
||||||
|
HttpUrl.parse(this) != null && Patterns.WEB_URL.matcher(this).matches()
|
||||||
|
|
||||||
|
fun String.isBaseUrlValid(): Boolean {
|
||||||
|
val baseUrl = HttpUrl.parse(this)
|
||||||
|
var existsAndEndsWithSlash = false
|
||||||
|
if (baseUrl != null) {
|
||||||
|
val pathSegments = baseUrl.pathSegments()
|
||||||
|
existsAndEndsWithSlash = "" == pathSegments[pathSegments.size - 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return Patterns.WEB_URL.matcher(this).matches() && existsAndEndsWithSlash
|
||||||
|
}
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package apps.amine.bou.readerforselfoss.utils.bottombar
|
||||||
|
|
||||||
|
import com.ashokvarma.bottomnavigation.TextBadgeItem
|
||||||
|
|
||||||
|
|
||||||
|
fun TextBadgeItem.removeBadge(): TextBadgeItem {
|
||||||
|
this.setText("")
|
||||||
|
this.hide()
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun TextBadgeItem.maybeShow(): TextBadgeItem =
|
||||||
|
if (this.isHidden)
|
||||||
|
this.show()
|
||||||
|
else
|
||||||
|
this
|
@ -0,0 +1,29 @@
|
|||||||
|
package apps.amine.bou.readerforselfoss.utils.glide
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory
|
||||||
|
import android.widget.ImageView
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import com.bumptech.glide.request.RequestOptions
|
||||||
|
import com.bumptech.glide.request.target.BitmapImageViewTarget
|
||||||
|
|
||||||
|
|
||||||
|
fun Context.bitmapCenterCrop(url: String, iv: ImageView) =
|
||||||
|
Glide.with(this).asBitmap().load(url).apply(RequestOptions.centerCropTransform()).into(iv)
|
||||||
|
|
||||||
|
fun Context.bitmapFitCenter(url: String, iv: ImageView) =
|
||||||
|
Glide.with(this).asBitmap().load(url).apply(RequestOptions.fitCenterTransform()).into(iv)
|
||||||
|
|
||||||
|
fun Context.circularBitmapDrawable(url: String, iv: ImageView) =
|
||||||
|
Glide.with(this)
|
||||||
|
.asBitmap()
|
||||||
|
.load(url)
|
||||||
|
.apply(RequestOptions.centerCropTransform()).
|
||||||
|
into(object : BitmapImageViewTarget(iv) {
|
||||||
|
override fun setResource(resource: Bitmap?) {
|
||||||
|
val circularBitmapDrawable = RoundedBitmapDrawableFactory.create(resources, resource)
|
||||||
|
circularBitmapDrawable.isCircular = true
|
||||||
|
iv.setImageDrawable(circularBitmapDrawable)
|
||||||
|
}
|
||||||
|
})
|
@ -0,0 +1,32 @@
|
|||||||
|
package apps.amine.bou.readerforselfoss.utils.glide
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.Config
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.getUnsafeHttpClient
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import com.bumptech.glide.GlideBuilder
|
||||||
|
import com.bumptech.glide.Registry
|
||||||
|
import com.bumptech.glide.module.GlideModule
|
||||||
|
import com.bumptech.glide.load.model.GlideUrl
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
|
|
||||||
|
class SelfSignedGlideModule : GlideModule {
|
||||||
|
|
||||||
|
override fun applyOptions(context: Context?, builder: GlideBuilder?) {}
|
||||||
|
|
||||||
|
override fun registerComponents(context: Context?, glide: Glide?, registry: Registry?) {
|
||||||
|
|
||||||
|
if (context != null) {
|
||||||
|
val pref = context?.getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
||||||
|
if (pref.getBoolean("isSelfSignedCert", false)) {
|
||||||
|
val client = getUnsafeHttpClient().build()
|
||||||
|
|
||||||
|
registry?.append(GlideUrl::class.java, InputStream::class.java,
|
||||||
|
com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader.Factory(client))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24.0"
|
|
||||||
android:viewportHeight="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
|
|
||||||
</vector>
|
|
@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24.0"
|
|
||||||
android:viewportHeight="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/>
|
|
||||||
</vector>
|
|
BIN
app/src/main/res/drawable-hdpi/ic_bug_report.png
Normal file
After Width: | Height: | Size: 271 B |
BIN
app/src/main/res/drawable-hdpi/ic_color_lens_black_24dp.png
Normal file
After Width: | Height: | Size: 458 B |
BIN
app/src/main/res/drawable-hdpi/ic_info_outline.png
Normal file
After Width: | Height: | Size: 551 B |
Before Width: | Height: | Size: 953 B |
BIN
app/src/main/res/drawable-hdpi/ic_settings.png
Normal file
After Width: | Height: | Size: 498 B |
BIN
app/src/main/res/drawable-mdpi/ic_bug_report.png
Normal file
After Width: | Height: | Size: 212 B |
BIN
app/src/main/res/drawable-mdpi/ic_color_lens_black_24dp.png
Normal file
After Width: | Height: | Size: 268 B |
BIN
app/src/main/res/drawable-mdpi/ic_info_outline.png
Normal file
After Width: | Height: | Size: 355 B |
Before Width: | Height: | Size: 655 B |
BIN
app/src/main/res/drawable-mdpi/ic_settings.png
Normal file
After Width: | Height: | Size: 339 B |
BIN
app/src/main/res/drawable-xhdpi/ic_bug_report.png
Normal file
After Width: | Height: | Size: 312 B |
BIN
app/src/main/res/drawable-xhdpi/ic_color_lens_black_24dp.png
Normal file
After Width: | Height: | Size: 504 B |
BIN
app/src/main/res/drawable-xhdpi/ic_info_outline.png
Normal file
After Width: | Height: | Size: 725 B |
Before Width: | Height: | Size: 1.2 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_settings.png
Normal file
After Width: | Height: | Size: 606 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_bug_report.png
Normal file
After Width: | Height: | Size: 466 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_color_lens_black_24dp.png
Normal file
After Width: | Height: | Size: 741 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_info_outline.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.9 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_settings.png
Normal file
After Width: | Height: | Size: 907 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_bug_report.png
Normal file
After Width: | Height: | Size: 573 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_color_lens_black_24dp.png
Normal file
After Width: | Height: | Size: 966 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_info_outline.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.6 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_settings.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
@ -2,12 +2,12 @@
|
|||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:drawable="@color/white"/>
|
android:drawable="@color/ic_launcher_background"/>
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<bitmap
|
<bitmap
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:src="@mipmap/ic_launcher"/>
|
android:src="@mipmap/ic_launcher_foreground"/>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
</layer-list>
|
</layer-list>
|
BIN
app/src/main/res/drawable/bg.png
Normal file
After Width: | Height: | Size: 406 B |
4
app/src/main/res/drawable/ic_info_outline_white_48px.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<vector android:height="24dp" android:viewportHeight="24.0"
|
||||||
|
android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FFFFFF" android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
|
||||||
|
</vector>
|
4
app/src/main/res/drawable/ic_thumb_up_white_48px.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<vector android:height="24dp" android:viewportHeight="24.0"
|
||||||
|
android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FFFFFF" android:pathData="M1,21h4L5,9L1,9v12zM23,10c0,-1.1 -0.9,-2 -2,-2h-6.31l0.95,-4.57 0.03,-0.32c0,-0.41 -0.17,-0.79 -0.44,-1.06L14.17,1 7.59,7.59C7.22,7.95 7,8.45 7,9v10c0,1.1 0.9,2 2,2h9c0.83,0 1.54,-0.5 1.84,-1.22l3.02,-7.05c0.09,-0.23 0.14,-0.47 0.14,-0.73v-1.91l-0.01,-0.01L23,10z"/>
|
||||||
|
</vector>
|
BIN
app/src/main/res/drawable/web_hi_res_512.png
Normal file
After Width: | Height: | Size: 20 KiB |
@ -1,130 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<RelativeLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:fitsSystemWindows="true"
|
|
||||||
tools:context="apps.amine.bou.readerforselfoss.HomeActivity">
|
|
||||||
|
|
||||||
<com.roughike.bottombar.BottomBar
|
|
||||||
android:id="@+id/bottomBar"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
app:bb_tabletMode="true"
|
|
||||||
app:bb_tabXmlResource="@xml/bottombar"
|
|
||||||
app:bb_activeTabColor="@color/white"
|
|
||||||
app:bb_inActiveTabColor="@color/black"
|
|
||||||
app:bb_badgeBackgroundColor="@color/colorPrimary"/>
|
|
||||||
|
|
||||||
<com.github.stkent.amplify.prompt.DefaultLayoutPromptView
|
|
||||||
android:id="@+id/prompt_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:prompt_view_user_opinion_question_title="@string/rating_prompt_title"
|
|
||||||
app:prompt_view_user_opinion_question_positive_button_label="@string/rating_prompt_yes"
|
|
||||||
app:prompt_view_user_opinion_question_negative_button_label="@string/rating_prompt_no"
|
|
||||||
app:prompt_view_positive_feedback_question_title="@string/rating_prompt_rating_title"
|
|
||||||
app:prompt_view_positive_feedback_question_positive_button_label="@string/rating_prompt_rating_yes"
|
|
||||||
app:prompt_view_positive_feedback_question_negative_button_label="@string/rating_prompt_rating_no"
|
|
||||||
app:prompt_view_critical_feedback_question_title="@string/rating_prompt_feedback_title"
|
|
||||||
app:prompt_view_critical_feedback_question_positive_button_label="@string/rating_prompt_feedback_yes"
|
|
||||||
app:prompt_view_critical_feedback_question_negative_button_label="@string/rating_prompt_feedback_no"
|
|
||||||
app:prompt_view_thanks_title="@string/rating_prompt_thanks"
|
|
||||||
app:prompt_view_positive_button_background_color="@color/colorPrimary"
|
|
||||||
app:prompt_view_positive_button_text_color="@color/white"
|
|
||||||
app:prompt_view_positive_button_border_color="@color/colorPrimary"
|
|
||||||
app:prompt_view_negative_button_background_color="@color/colorAccent"
|
|
||||||
app:prompt_view_negative_button_border_color="@color/white"
|
|
||||||
app:prompt_view_thanks_display_time_ms="2000"
|
|
||||||
android:layout_toEndOf="@+id/bottomBar"
|
|
||||||
android:layout_toRightOf="@+id/bottomBar"/>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- This could be your fragment container, or something -->
|
|
||||||
<android.support.design.widget.CoordinatorLayout
|
|
||||||
android:id="@+id/coordLayout"
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_toEndOf="@+id/bottomBar"
|
|
||||||
android:layout_toRightOf="@+id/bottomBar"
|
|
||||||
android:layout_below="@id/prompt_view">
|
|
||||||
|
|
||||||
<android.support.design.widget.CoordinatorLayout
|
|
||||||
android:id="@+id/intern_coordLayout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<android.support.design.widget.AppBarLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<android.support.v7.widget.Toolbar
|
|
||||||
android:id="@+id/toolbar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="?attr/actionBarSize"
|
|
||||||
app:theme="@style/ToolBarStyle"
|
|
||||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
|
|
||||||
|
|
||||||
</android.support.design.widget.AppBarLayout>
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/drawer_layout"
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<android.support.v4.widget.SwipeRefreshLayout
|
|
||||||
android:id="@+id/swipeRefreshLayout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/emptyText"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="fill"
|
|
||||||
android:paddingTop="100dp"
|
|
||||||
android:text="@string/nothing_here"
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
|
|
||||||
android:textColor="@color/about_libraries_card_dark"
|
|
||||||
android:visibility="gone" />
|
|
||||||
<android.support.v7.widget.RecyclerView
|
|
||||||
android:id="@+id/my_recycler_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@color/background_grey"
|
|
||||||
android:scrollbars="vertical"
|
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
|
||||||
</android.support.v4.widget.SwipeRefreshLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</android.support.design.widget.CoordinatorLayout>
|
|
||||||
|
|
||||||
</android.support.design.widget.CoordinatorLayout>
|
|
||||||
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
@ -1,16 +1,32 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<android.support.constraint.ConstraintLayout
|
<LinearLayout
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
tools:context="apps.amine.bou.readerforselfoss.AddSourceActivity"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<android.support.design.widget.AppBarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<android.support.v7.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
app:theme="@style/ToolBarStyle" />
|
||||||
|
|
||||||
|
</android.support.design.widget.AppBarLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<android.support.constraint.ConstraintLayout
|
||||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||||
android:paddingTop="@dimen/activity_vertical_margin"
|
android:paddingTop="@dimen/activity_vertical_margin"
|
||||||
tools:context="apps.amine.bou.readerforselfoss.AddSourceActivity">
|
android:layout_height="match_parent"
|
||||||
|
android:layout_width="match_parent">
|
||||||
<android.support.constraint.ConstraintLayout
|
<android.support.constraint.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
@ -90,7 +106,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/saveBtn"
|
android:id="@+id/saveBtn"
|
||||||
android:elevation="5dp"
|
android:elevation="5dp"
|
||||||
android:textColor="@color/colorAccent"
|
android:textColor="?attr/colorAccent"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
android:layout_marginRight="16dp"
|
android:layout_marginRight="16dp"
|
||||||
@ -116,3 +132,5 @@
|
|||||||
android:visibility="visible"/>
|
android:visibility="visible"/>
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
</android.support.constraint.ConstraintLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -27,6 +27,7 @@
|
|||||||
app:prompt_view_positive_button_border_color="@color/colorPrimary"
|
app:prompt_view_positive_button_border_color="@color/colorPrimary"
|
||||||
app:prompt_view_negative_button_background_color="@color/colorAccent"
|
app:prompt_view_negative_button_background_color="@color/colorAccent"
|
||||||
app:prompt_view_negative_button_border_color="@color/white"
|
app:prompt_view_negative_button_border_color="@color/white"
|
||||||
|
app:prompt_view_background_color="?attr/colorAccent"
|
||||||
app:prompt_view_thanks_display_time_ms="2000"/>
|
app:prompt_view_thanks_display_time_ms="2000"/>
|
||||||
|
|
||||||
<android.support.design.widget.CoordinatorLayout
|
<android.support.design.widget.CoordinatorLayout
|
||||||
@ -53,8 +54,7 @@
|
|||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
app:theme="@style/ToolBarStyle"
|
app:theme="@style/ToolBarStyle" />
|
||||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
|
|
||||||
|
|
||||||
</android.support.design.widget.AppBarLayout>
|
</android.support.design.widget.AppBarLayout>
|
||||||
|
|
||||||
@ -74,7 +74,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:background="@color/background_grey">
|
android:background="?android:attr/windowBackground">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/emptyText"
|
android:id="@+id/emptyText"
|
||||||
@ -85,7 +85,6 @@
|
|||||||
android:text="@string/nothing_here"
|
android:text="@string/nothing_here"
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
|
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
|
||||||
android:textColor="@color/about_libraries_card_dark"
|
|
||||||
android:background="@color/transparent"
|
android:background="@color/transparent"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
<android.support.v7.widget.RecyclerView
|
<android.support.v7.widget.RecyclerView
|
||||||
@ -104,17 +103,10 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</android.support.design.widget.CoordinatorLayout>
|
</android.support.design.widget.CoordinatorLayout>
|
||||||
<com.roughike.bottombar.BottomBar
|
<com.ashokvarma.bottomnavigation.BottomNavigationBar
|
||||||
|
android:layout_gravity="bottom"
|
||||||
android:id="@+id/bottomBar"
|
android:id="@+id/bottomBar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="60dp"
|
android:layout_height="60dp"/>
|
||||||
android:layout_gravity="bottom"
|
|
||||||
app:bb_behavior="shy"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
app:bb_tabXmlResource="@xml/bottombar"
|
|
||||||
app:bb_activeTabColor="@color/white"
|
|
||||||
app:bb_badgeBackgroundColor="@color/colorPrimary"
|
|
||||||
app:bb_inActiveTabColor="@color/black"
|
|
||||||
app:bb_badgesHideWhenActive="false" />
|
|
||||||
</android.support.design.widget.CoordinatorLayout>
|
</android.support.design.widget.CoordinatorLayout>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
@ -2,14 +2,29 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
tools:context="apps.amine.bou.readerforselfoss.LoginActivity">
|
||||||
|
<android.support.design.widget.AppBarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<android.support.v7.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
app:theme="@style/ToolBarStyle" />
|
||||||
|
|
||||||
|
</android.support.design.widget.AppBarLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||||
android:paddingTop="@dimen/activity_vertical_margin"
|
android:paddingTop="@dimen/activity_vertical_margin">
|
||||||
tools:context="apps.amine.bou.readerforselfoss.LoginActivity">
|
|
||||||
|
|
||||||
<!-- Login progress -->
|
<!-- Login progress -->
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/login_progress"
|
android:id="@+id/login_progress"
|
||||||
@ -123,6 +138,20 @@
|
|||||||
android:hint="@string/prompt_http_password" />
|
android:hint="@string/prompt_http_password" />
|
||||||
</android.support.design.widget.TextInputLayout>
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
android:id="@+id/withSelfhostedCert"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/self_hosted_cert_switch" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/warningText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/self_signed_cert_warning"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/email_sign_in_button"
|
android:id="@+id/email_sign_in_button"
|
||||||
style="?android:textAppearanceSmall"
|
style="?android:textAppearanceSmall"
|
||||||
@ -136,3 +165,5 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context="apps.amine.bou.readerforselfoss.ReaderActivity">
|
tools:context="apps.amine.bou.readerforselfoss.ReaderActivity"
|
||||||
|
android:background="?android:attr/windowBackground">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/imageView"
|
android:id="@+id/imageView"
|
||||||
@ -96,7 +97,7 @@
|
|||||||
android:padding="4dp"
|
android:padding="4dp"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
android:src="@drawable/ic_open_in_browser_black_24dp"
|
android:src="@drawable/ic_open_in_browser_black_24dp"
|
||||||
android:tint="#000000"
|
android:tint="@android:color/black"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/shareBtn"
|
app:layout_constraintEnd_toStartOf="@+id/shareBtn"
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
@ -113,7 +114,7 @@
|
|||||||
android:padding="4dp"
|
android:padding="4dp"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
android:src="@drawable/ic_share_black_24dp"
|
android:src="@drawable/ic_share_black_24dp"
|
||||||
android:tint="#000000"
|
android:tint="@android:color/black"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
@ -8,12 +8,22 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context="apps.amine.bou.readerforselfoss.SourcesActivity"
|
tools:context="apps.amine.bou.readerforselfoss.SourcesActivity"
|
||||||
xmlns:fab="http://schemas.android.com/apk/res-auto">
|
xmlns:fab="http://schemas.android.com/apk/res-auto">
|
||||||
|
<android.support.design.widget.AppBarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<android.support.v7.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
app:theme="@style/ToolBarStyle" />
|
||||||
|
|
||||||
|
</android.support.design.widget.AppBarLayout>
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView
|
<android.support.v7.widget.RecyclerView
|
||||||
android:id="@+id/activity_sources"
|
android:id="@+id/activity_sources"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/background_grey"
|
|
||||||
android:scrollbars="vertical"
|
android:scrollbars="vertical"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||||
</android.support.v7.widget.RecyclerView>
|
</android.support.v7.widget.RecyclerView>
|
||||||
@ -24,8 +34,9 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="end|bottom|right"
|
android:layout_gravity="end|bottom|right"
|
||||||
android:src="@drawable/ic_add_black_24dp"
|
android:src="@drawable/ic_add_black_24dp"
|
||||||
fab:fab_colorNormal="@color/colorAccent"
|
android:tint="?android:textColorPrimary"
|
||||||
fab:fab_colorPressed="@color/colorAccentDark"
|
fab:fab_colorNormal="?attr/colorAccent"
|
||||||
|
fab:fab_colorPressed="?attr/colorAccentDark"
|
||||||
fab:fab_colorRipple="@color/pink"
|
fab:fab_colorRipple="@color/pink"
|
||||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
android:paddingTop="@dimen/activity_vertical_margin"
|
android:paddingTop="@dimen/activity_vertical_margin"
|
||||||
|
@ -6,13 +6,15 @@
|
|||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<android.support.v7.widget.CardView
|
<android.support.v7.widget.CardView
|
||||||
|
android:id="@+id/card"
|
||||||
|
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.62"
|
app:layout_constraintHorizontal_bias="0.62"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:cardElevation="2dp"
|
card_view:cardElevation="2dp"
|
||||||
app:cardUseCompatPadding="true"
|
card_view:cardUseCompatPadding="true"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginLeft="8dp"
|
android:layout_marginLeft="8dp"
|
||||||
@ -60,24 +62,21 @@
|
|||||||
android:layout_width="40dp" />
|
android:layout_width="40dp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/title"
|
|
||||||
tools:text="Titre"
|
|
||||||
android:fontFamily="sans-serif"
|
|
||||||
android:textSize="16sp"
|
|
||||||
android:textAllCaps="false"
|
|
||||||
android:textAlignment="viewStart"
|
|
||||||
android:textColor="@color/black"
|
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
android:layout_marginLeft="8dp"
|
||||||
android:layout_marginRight="8dp"
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:gravity="start"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
android:textStyle="bold"
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
app:layout_constraintLeft_toRightOf="@+id/sourceImage"
|
app:layout_constraintLeft_toRightOf="@+id/sourceImage"
|
||||||
android:layout_marginStart="8dp"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
android:layout_marginLeft="8dp"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/sourceImage"
|
app:layout_constraintTop_toTopOf="@+id/sourceImage"
|
||||||
android:gravity="start" />
|
tools:text="Titre" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -85,7 +84,6 @@
|
|||||||
android:id="@+id/sourceTitleAndDate"
|
android:id="@+id/sourceTitleAndDate"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
tools:text="Google Actualité Il y a 5h"
|
tools:text="Google Actualité Il y a 5h"
|
||||||
android:textColor="#868686"
|
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
app:layout_constraintTop_toBottomOf="@+id/title"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
@ -117,38 +115,38 @@
|
|||||||
android:layout_marginEnd="8dp"/>
|
android:layout_marginEnd="8dp"/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
android:id="@+id/shareBtn"
|
||||||
android:layout_width="35dp"
|
android:layout_width="35dp"
|
||||||
android:layout_height="35dp"
|
android:layout_height="35dp"
|
||||||
android:src="@drawable/ic_share_black_24dp"
|
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
android:layout_toLeftOf="@+id/favButton"
|
android:layout_toLeftOf="@+id/favButton"
|
||||||
android:layout_toStartOf="@+id/favButton"
|
android:layout_toStartOf="@+id/favButton"
|
||||||
android:id="@+id/shareBtn"
|
android:adjustViewBounds="true"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:elevation="5dp"
|
android:elevation="5dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:padding="4dp"
|
||||||
android:layout_marginRight="16dp"
|
|
||||||
android:tint="#000000"
|
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
android:padding="4dp"/>
|
android:src="@drawable/ic_share_black_24dp"
|
||||||
|
android:tint="?android:attr/textColorPrimary" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
android:id="@+id/browserBtn"
|
||||||
android:layout_width="35dp"
|
android:layout_width="35dp"
|
||||||
android:layout_height="35dp"
|
android:layout_height="35dp"
|
||||||
android:src="@drawable/ic_open_in_browser_black_24dp"
|
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:layout_toLeftOf="@+id/shareBtn"
|
|
||||||
android:layout_toStartOf="@+id/shareBtn"
|
|
||||||
android:id="@+id/browserBtn"
|
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginRight="16dp"
|
android:layout_marginRight="16dp"
|
||||||
android:elevation="5dp"
|
android:layout_toLeftOf="@+id/shareBtn"
|
||||||
android:background="@android:color/transparent"
|
android:layout_toStartOf="@+id/shareBtn"
|
||||||
android:tint="#000000"
|
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:elevation="5dp"
|
||||||
|
android:padding="4dp"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
android:padding="4dp"/>
|
android:src="@drawable/ic_open_in_browser_black_24dp"
|
||||||
|
android:tint="?android:attr/textColorPrimary" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
@ -3,11 +3,10 @@
|
|||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:orientation="horizontal"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:minHeight="88dp"
|
android:minHeight="88dp">
|
||||||
android:background="#EDEDED">
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/itemImage"
|
android:id="@+id/itemImage"
|
||||||
@ -20,25 +19,25 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/title"
|
|
||||||
tools:text="Titre"
|
|
||||||
android:fontFamily="sans-serif"
|
|
||||||
android:textSize="16sp"
|
|
||||||
android:textAllCaps="false"
|
|
||||||
android:textAlignment="viewStart"
|
|
||||||
app:layout_constraintLeft_toRightOf="@+id/itemImage"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginLeft="16dp"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
android:textColor="@color/black"
|
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
android:layout_marginLeft="16dp"
|
||||||
android:layout_marginRight="16dp"
|
android:layout_marginRight="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:fontFamily="sans-serif"
|
||||||
|
android:gravity="start"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
android:gravity="start" />
|
app:layout_constraintLeft_toRightOf="@+id/itemImage"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="Titre" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -46,7 +45,6 @@
|
|||||||
android:id="@+id/sourceTitleAndDate"
|
android:id="@+id/sourceTitleAndDate"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
tools:text="Google Actualité Il y a 5h"
|
tools:text="Google Actualité Il y a 5h"
|
||||||
android:textColor="#868686"
|
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
app:layout_constraintTop_toBottomOf="@+id/title"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
@ -90,11 +88,11 @@
|
|||||||
android:layout_toStartOf="@+id/favButton"
|
android:layout_toStartOf="@+id/favButton"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
|
android:backgroundTint="?android:attr/textColorPrimary"
|
||||||
android:elevation="5dp"
|
android:elevation="5dp"
|
||||||
android:padding="4dp"
|
android:padding="4dp"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
android:src="@drawable/ic_share_black_24dp"
|
android:src="@drawable/ic_share_black_24dp" />
|
||||||
android:tint="#000000" />
|
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/browserBtn"
|
android:id="@+id/browserBtn"
|
||||||
@ -107,11 +105,11 @@
|
|||||||
android:layout_toStartOf="@+id/shareBtn"
|
android:layout_toStartOf="@+id/shareBtn"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
|
android:backgroundTint="?android:attr/textColorPrimary"
|
||||||
android:elevation="5dp"
|
android:elevation="5dp"
|
||||||
android:padding="4dp"
|
android:padding="4dp"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
android:src="@drawable/ic_open_in_browser_black_24dp"
|
android:src="@drawable/ic_open_in_browser_black_24dp" />
|
||||||
android:tint="#000000" />
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|
||||||
|
14
app/src/main/res/layout/settings_toolbar.xml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<android.support.design.widget.AppBarLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<android.support.v7.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
app:theme="@style/ToolBarStyle" />
|
||||||
|
|
||||||
|
</android.support.design.widget.AppBarLayout>
|
@ -5,7 +5,6 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:background="#EDEDED"
|
|
||||||
android:layout_height="48dp">
|
android:layout_height="48dp">
|
||||||
|
|
||||||
|
|
||||||
@ -37,6 +36,7 @@
|
|||||||
android:id="@+id/deleteBtn"
|
android:id="@+id/deleteBtn"
|
||||||
android:background="@drawable/ic_remove_circle_outline_black_24dp"
|
android:background="@drawable/ic_remove_circle_outline_black_24dp"
|
||||||
style="@style/Widget.AppCompat.Button.Borderless"
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
|
android:backgroundTint="?android:textColorSecondary"
|
||||||
android:elevation="4dp"
|
android:elevation="4dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
11
app/src/main/res/layout/switch_item.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<RelativeLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_centerVertical="true" />
|
||||||
|
</RelativeLayout>
|
@ -2,6 +2,14 @@
|
|||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/loging_debug"
|
||||||
|
android:checkable="true"
|
||||||
|
android:checked="false"
|
||||||
|
android:icon="@drawable/ic_bug_report"
|
||||||
|
android:title="@string/login_menu_debug"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
|
||||||
<item android:id="@+id/about"
|
<item android:id="@+id/about"
|
||||||
android:title="@string/action_about"
|
android:title="@string/action_about"
|
||||||
android:orderInCategory="102"
|
android:orderInCategory="102"
|
||||||
|
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
|
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||||
|
</adaptive-icon>
|
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
|
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||||
|
</adaptive-icon>
|
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_background.png
Normal file
After Width: | Height: | Size: 182 B |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_background.png
Normal file
After Width: | Height: | Size: 125 B |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_background.png
Normal file
After Width: | Height: | Size: 261 B |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png
Normal file
After Width: | Height: | Size: 487 B |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png
Normal file
After Width: | Height: | Size: 803 B |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 11 KiB |
158
app/src/main/res/values-af/strings.xml
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--Generated by crowdin.com-->
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<string name="app_name">"Reader for Selfoss"</string>
|
||||||
|
<string name="title_activity_login">"Log in"</string>
|
||||||
|
<string name="prompt_password">"Password"</string>
|
||||||
|
<string name="prompt_http_password">"HTTP Password"</string>
|
||||||
|
<string name="action_sign_in">"Go"</string>
|
||||||
|
<string name="error_invalid_password">"Password not long enough"</string>
|
||||||
|
<string name="error_field_required">"Field required"</string>
|
||||||
|
<string name="prompt_url">"Url"</string>
|
||||||
|
<string name="withLoginSwitch">"Login required ?"</string>
|
||||||
|
<string name="withHttpLoginSwitch">"HTTP Login required ?"</string>
|
||||||
|
<string name="login_url_problem">"Oops. You may need to add a \"/\" at the end of the url."</string>
|
||||||
|
<string name="prompt_login">"Username"</string>
|
||||||
|
<string name="prompt_http_login">"HTTP Username"</string>
|
||||||
|
<string name="label_share">"Share"</string>
|
||||||
|
<string name="readAll">"Read all"</string>
|
||||||
|
<string name="action_disconnect">"Disconnect"</string>
|
||||||
|
<string name="title_activity_settings">"Settings"</string>
|
||||||
|
<string name="pref_header_general">"General"</string>
|
||||||
|
<string name="pref_switch_actions_tap_title">"Tap action on the articles"</string>
|
||||||
|
<string name="add_source_hint_tags">"Tag1, Tag2, Tag3"</string>
|
||||||
|
<string name="add_source_hint_url">"Link"</string>
|
||||||
|
<string name="add_source_hint_name">"Name"</string>
|
||||||
|
<string name="add_source">"Add a source"</string>
|
||||||
|
<string name="add_source_save">"Save"</string>
|
||||||
|
<string name="wrong_infos">"Check your details again."</string>
|
||||||
|
<string name="all_posts_not_read">"All posts weren't read"</string>
|
||||||
|
<string name="all_posts_read">"All posts were read"</string>
|
||||||
|
<string name="cant_get_favs">"Can't get favorites"</string>
|
||||||
|
<string name="cant_get_new_elements">"Can't get new articles"</string>
|
||||||
|
<string name="cant_get_read">"Can't get read articles"</string>
|
||||||
|
<string name="nothing_here">"Nothing here"</string>
|
||||||
|
<string name="tab_new">"New"</string>
|
||||||
|
<string name="tab_read">"All"</string>
|
||||||
|
<string name="tab_favs">"Favorites"</string>
|
||||||
|
<string name="action_about">"About"</string>
|
||||||
|
<string name="marked_as_read">"Item read"</string>
|
||||||
|
<string name="undo_string">"Undo"</string>
|
||||||
|
<string name="addStringNoUrl">"Log in to add sources."</string>
|
||||||
|
<string name="cant_get_sources">"Can't get sources list."</string>
|
||||||
|
<string name="cant_create_source">"Can't create source."</string>
|
||||||
|
<string name="cant_get_spouts">"Can't get spouts list."</string>
|
||||||
|
<string name="form_not_complete">"The form is not complete"</string>
|
||||||
|
<string name="pref_header_links">"Links"</string>
|
||||||
|
<string name="issue_tracker_link">"Issue Tracker"</string>
|
||||||
|
<string name="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
|
||||||
|
<string name="warning_version">"WARNING"</string>
|
||||||
|
<string name="warning_wrong_url">"WARNING"</string>
|
||||||
|
<string name="text_version">"You seem to be using a version of the app that doesn't come from the store. The app could have been tampered with. I will not be responsible if it causes any damage to your device. Consider using the ReaderForSelfoss app from the Play Store."</string>
|
||||||
|
<string name="pref_switch_card_view_title">"Card View"</string>
|
||||||
|
<string name="cant_mark_favortie">"Can't mark article as favorite"</string>
|
||||||
|
<string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
|
||||||
|
<string name="share">"Share"</string>
|
||||||
|
<string name="rating_prompt_title">"Enjoying the app ?"</string>
|
||||||
|
<string name="rating_prompt_yes">"Yes !"</string>
|
||||||
|
<string name="rating_prompt_no">"Not really …"</string>
|
||||||
|
<string name="rating_prompt_feedback_title">"Can you tell us why ?"</string>
|
||||||
|
<string name="rating_prompt_feedback_yes">"OK !"</string>
|
||||||
|
<string name="rating_prompt_feedback_no">"Not now."</string>
|
||||||
|
<string name="rating_prompt_rating_title">"Great ! Can you rate us on the Store ?"</string>
|
||||||
|
<string name="rating_prompt_rating_yes">"Sure !"</string>
|
||||||
|
<string name="rating_prompt_rating_no">"Not right now."</string>
|
||||||
|
<string name="rating_prompt_thanks">"Thanks, your feedback help enhance the app !"</string>
|
||||||
|
<string name="switch_unread_count">"Display the unread count as a badge for the bottom bar."</string>
|
||||||
|
<string name="switch_unread_count_title">"Display unread count"</string>
|
||||||
|
<string name="display_all_counts_title">"Display count for favorite and read"</string>
|
||||||
|
<string name="menu_share_the_app">"Invite friends"</string>
|
||||||
|
<string name="invitation_title">"Try this app for your Selfoss RSS feeds !"</string>
|
||||||
|
<string name="invitation_message">"I use this app for my Selfoss RSS feeds. You may like it too !"</string>
|
||||||
|
<string name="invitation_cta">"Try the app"</string>
|
||||||
|
<string name="text_wrong_url">"You seem to be trying to use an invalid URL. Make sure it is correct, and if the problem persists, contact me (via the store contact link). Please note that the app needs you to be using Selfoss. You can't access RSS feeds without it."</string>
|
||||||
|
<string name="pref_general_internal_browser_title">"Open links inside the app"</string>
|
||||||
|
<string name="pref_general_internal_browser_on">"Articles will open inside the app"</string>
|
||||||
|
<string name="pref_general_internal_browser_off">"Articles will open with your default browser"</string>
|
||||||
|
<string name="prefer_article_viewer_title">"Use the article viewer"</string>
|
||||||
|
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
|
||||||
|
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
|
||||||
|
<string name="pref_general_category_links">"Link handeling"</string>
|
||||||
|
<string name="pref_general_category_displaying">"Displaying"</string>
|
||||||
|
<string name="pref_general_category_actions">"Actions"</string>
|
||||||
|
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
|
||||||
|
<string name="pref_switch_card_view_off">"The articles will be displayed as a list"</string>
|
||||||
|
<string name="pref_switch_actions_tap_on">"Displays the action bar under the article"</string>
|
||||||
|
<string name="pref_switch_actions_tap_off">"When selecting an article it will open in your selected browser"</string>
|
||||||
|
<string name="menu_home_refresh">"Update remote"</string>
|
||||||
|
<string name="refresh_success_response">"The remote is updated, you can now reload the articles list"</string>
|
||||||
|
<string name="refresh_failer_message">"The update didn't work, try again later, or check your selfoss logs."</string>
|
||||||
|
<string name="refresh_in_progress">"Refresh in progress"</string>
|
||||||
|
<string name="new_apk_available_title">"A new APK is available."</string>
|
||||||
|
<string name="new_apk_available_message">"A new APK is available to download on the official repository."</string>
|
||||||
|
<string name="new_apk_available_get">"Download now"</string>
|
||||||
|
<string name="new_apk_available_no">"Ignore version"</string>
|
||||||
|
<string name="intro_hello_title">"Hi there !"</string>
|
||||||
|
<string name="intro_hello_message">"Thanks for downloading the app !"</string>
|
||||||
|
<string name="intro_needs_selfoss_title">"Before you start…"</string>
|
||||||
|
<string name="intro_needs_selfoss_message">"You can't use the app without a Selfoss instance."</string>
|
||||||
|
<string name="intro_needs_selfoss_link">"What is Selfoss ?"</string>
|
||||||
|
<string name="intro_all_set_title">"All set !"</string>
|
||||||
|
<string name="intro_all_set_message">"You are ready to use the app. Don't forget to go to the settings page to configure your app, and where you'll find some useful links."</string>
|
||||||
|
<string name="card_height_title">Full height cards</string>
|
||||||
|
<string name="card_height_on">Cards height will adjust to its content</string>
|
||||||
|
<string name="card_height_off">Card height will be fixed</string>
|
||||||
|
<string name="source_code">Source code</string>
|
||||||
|
<string name="cant_mark_read">Can\'t mark article as read</string>
|
||||||
|
<string name="drawer_error_loading_tags">Error loading tags…</string>
|
||||||
|
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||||
|
<string name="drawer_item_filters">Filters</string>
|
||||||
|
<string name="drawer_action_clear">clear</string>
|
||||||
|
<string name="drawer_item_tags">Tags</string>
|
||||||
|
<string name="drawer_item_sources">Sources</string>
|
||||||
|
<string name="drawer_action_edit">edit</string>
|
||||||
|
<string name="cache_drawer_error" tools:keep="@string/cache_drawer_error">Couldn\'t cache your drawer data</string>
|
||||||
|
<string name="no_tags_loaded">No tags loaded</string>
|
||||||
|
<string name="no_sources_loaded">No sources loaded</string>
|
||||||
|
<string name="drawer_loading">Loading …</string>
|
||||||
|
<string name="menu_home_search">Search</string>
|
||||||
|
<string name="can_delete_source">Can\'t delete the source...</string>
|
||||||
|
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
|
||||||
|
<string name="pref_header_theme">Themes</string>
|
||||||
|
<string name="default_theme">Default</string>
|
||||||
|
<string name="teal_orange_theme">Teal/Orange/Light</string>
|
||||||
|
<string name="cyan_pink_theme">Cyan/Pink/Light</string>
|
||||||
|
<string name="grey_orange_theme">Grey/Orange/Light</string>
|
||||||
|
<string name="blue_amber_theme">Blue/Amber/Light</string>
|
||||||
|
<string name="indigo_pink_theme">Indigo/Pink/Light</string>
|
||||||
|
<string name="red_teal_theme">Red/Teal/Light</string>
|
||||||
|
<string name="teal_orange_dark_theme">Teal/Orange/Dark</string>
|
||||||
|
<string name="cyan_pink_dark_theme">Cyan/Pink/Dark</string>
|
||||||
|
<string name="default_dark_theme">Default/Dark</string>
|
||||||
|
<string name="grey_orange_dark_theme">Grey/Orange/Dark</string>
|
||||||
|
<string name="blue_amber_dark_theme">Blue/Amber/Dark</string>
|
||||||
|
<string name="indigo_pink_dark_theme">Indigo/Pink/Dark</string>
|
||||||
|
<string name="red_teal_dark_theme">Red/Teal/Dark</string>
|
||||||
|
<string name="pref_header_debug">Debug</string>
|
||||||
|
<string name="login_debug_title">Activate to log login errors</string>
|
||||||
|
<string name="login_debug_on">Any error on the login page will be logged</string>
|
||||||
|
<string name="login_debug_off">No log on the login page</string>
|
||||||
|
<string name="login_menu_debug">Debug</string>
|
||||||
|
<string name="self_hosted_cert_switch">Using a self hosted certificate ?</string>
|
||||||
|
<string name="self_signed_cert_warning">Due to security reasons, self signed certificates are not supported by default. By activating this, I\'ll not be responsible of any security problem you encounter.</string>
|
||||||
|
<string name="pref_selfoss_category">Selfoss Api</string>
|
||||||
|
<string name="pref_api_items_number_title">Loaded items number</string>
|
||||||
|
<string name="read_debug_title">Read articles appearing as unread ?</string>
|
||||||
|
<string name="read_debug_off">No log when marking an item as read</string>
|
||||||
|
<string name="read_debug_on">Api calls will be logged when marking an article as read</string>
|
||||||
|
<string name="summary_debug_identifier">Debug identifier</string>
|
||||||
|
<string name="unique_id_to_clipboard">Identifier copied to your clipboard</string>
|
||||||
|
<string name="display_header_drawer_summary">Display a header with the selfoss instance url on the lateral drawer.</string>
|
||||||
|
<string name="display_header_drawer_title">Account header</string>
|
||||||
|
<string name="login_everything_title">Logging every api calls</string>
|
||||||
|
<string name="login_everything_on">This will log every api call for debug purpose.</string>
|
||||||
|
<string name="login_everything_off">No api call will be logged</string>
|
||||||
|
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string>
|
||||||
|
<string name="translation">Translation</string>
|
||||||
|
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
|
||||||
|
</resources>
|
158
app/src/main/res/values-ar/strings.xml
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--Generated by crowdin.com-->
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<string name="app_name">"Reader for Selfoss"</string>
|
||||||
|
<string name="title_activity_login">"Log in"</string>
|
||||||
|
<string name="prompt_password">"Password"</string>
|
||||||
|
<string name="prompt_http_password">"HTTP Password"</string>
|
||||||
|
<string name="action_sign_in">"Go"</string>
|
||||||
|
<string name="error_invalid_password">"Password not long enough"</string>
|
||||||
|
<string name="error_field_required">"Field required"</string>
|
||||||
|
<string name="prompt_url">"Url"</string>
|
||||||
|
<string name="withLoginSwitch">"Login required ?"</string>
|
||||||
|
<string name="withHttpLoginSwitch">"HTTP Login required ?"</string>
|
||||||
|
<string name="login_url_problem">"Oops. You may need to add a \"/\" at the end of the url."</string>
|
||||||
|
<string name="prompt_login">"Username"</string>
|
||||||
|
<string name="prompt_http_login">"HTTP Username"</string>
|
||||||
|
<string name="label_share">"Share"</string>
|
||||||
|
<string name="readAll">"Read all"</string>
|
||||||
|
<string name="action_disconnect">"Disconnect"</string>
|
||||||
|
<string name="title_activity_settings">"Settings"</string>
|
||||||
|
<string name="pref_header_general">"General"</string>
|
||||||
|
<string name="pref_switch_actions_tap_title">"Tap action on the articles"</string>
|
||||||
|
<string name="add_source_hint_tags">"Tag1, Tag2, Tag3"</string>
|
||||||
|
<string name="add_source_hint_url">"Link"</string>
|
||||||
|
<string name="add_source_hint_name">"Name"</string>
|
||||||
|
<string name="add_source">"Add a source"</string>
|
||||||
|
<string name="add_source_save">"Save"</string>
|
||||||
|
<string name="wrong_infos">"Check your details again."</string>
|
||||||
|
<string name="all_posts_not_read">"All posts weren't read"</string>
|
||||||
|
<string name="all_posts_read">"All posts were read"</string>
|
||||||
|
<string name="cant_get_favs">"Can't get favorites"</string>
|
||||||
|
<string name="cant_get_new_elements">"Can't get new articles"</string>
|
||||||
|
<string name="cant_get_read">"Can't get read articles"</string>
|
||||||
|
<string name="nothing_here">"Nothing here"</string>
|
||||||
|
<string name="tab_new">"New"</string>
|
||||||
|
<string name="tab_read">"All"</string>
|
||||||
|
<string name="tab_favs">"Favorites"</string>
|
||||||
|
<string name="action_about">"About"</string>
|
||||||
|
<string name="marked_as_read">"Item read"</string>
|
||||||
|
<string name="undo_string">"Undo"</string>
|
||||||
|
<string name="addStringNoUrl">"Log in to add sources."</string>
|
||||||
|
<string name="cant_get_sources">"Can't get sources list."</string>
|
||||||
|
<string name="cant_create_source">"Can't create source."</string>
|
||||||
|
<string name="cant_get_spouts">"Can't get spouts list."</string>
|
||||||
|
<string name="form_not_complete">"The form is not complete"</string>
|
||||||
|
<string name="pref_header_links">"Links"</string>
|
||||||
|
<string name="issue_tracker_link">"Issue Tracker"</string>
|
||||||
|
<string name="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
|
||||||
|
<string name="warning_version">"WARNING"</string>
|
||||||
|
<string name="warning_wrong_url">"WARNING"</string>
|
||||||
|
<string name="text_version">"You seem to be using a version of the app that doesn't come from the store. The app could have been tampered with. I will not be responsible if it causes any damage to your device. Consider using the ReaderForSelfoss app from the Play Store."</string>
|
||||||
|
<string name="pref_switch_card_view_title">"Card View"</string>
|
||||||
|
<string name="cant_mark_favortie">"Can't mark article as favorite"</string>
|
||||||
|
<string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
|
||||||
|
<string name="share">"Share"</string>
|
||||||
|
<string name="rating_prompt_title">"Enjoying the app ?"</string>
|
||||||
|
<string name="rating_prompt_yes">"Yes !"</string>
|
||||||
|
<string name="rating_prompt_no">"Not really …"</string>
|
||||||
|
<string name="rating_prompt_feedback_title">"Can you tell us why ?"</string>
|
||||||
|
<string name="rating_prompt_feedback_yes">"OK !"</string>
|
||||||
|
<string name="rating_prompt_feedback_no">"Not now."</string>
|
||||||
|
<string name="rating_prompt_rating_title">"Great ! Can you rate us on the Store ?"</string>
|
||||||
|
<string name="rating_prompt_rating_yes">"Sure !"</string>
|
||||||
|
<string name="rating_prompt_rating_no">"Not right now."</string>
|
||||||
|
<string name="rating_prompt_thanks">"Thanks, your feedback help enhance the app !"</string>
|
||||||
|
<string name="switch_unread_count">"Display the unread count as a badge for the bottom bar."</string>
|
||||||
|
<string name="switch_unread_count_title">"Display unread count"</string>
|
||||||
|
<string name="display_all_counts_title">"Display count for favorite and read"</string>
|
||||||
|
<string name="menu_share_the_app">"Invite friends"</string>
|
||||||
|
<string name="invitation_title">"Try this app for your Selfoss RSS feeds !"</string>
|
||||||
|
<string name="invitation_message">"I use this app for my Selfoss RSS feeds. You may like it too !"</string>
|
||||||
|
<string name="invitation_cta">"Try the app"</string>
|
||||||
|
<string name="text_wrong_url">"You seem to be trying to use an invalid URL. Make sure it is correct, and if the problem persists, contact me (via the store contact link). Please note that the app needs you to be using Selfoss. You can't access RSS feeds without it."</string>
|
||||||
|
<string name="pref_general_internal_browser_title">"Open links inside the app"</string>
|
||||||
|
<string name="pref_general_internal_browser_on">"Articles will open inside the app"</string>
|
||||||
|
<string name="pref_general_internal_browser_off">"Articles will open with your default browser"</string>
|
||||||
|
<string name="prefer_article_viewer_title">"Use the article viewer"</string>
|
||||||
|
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
|
||||||
|
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
|
||||||
|
<string name="pref_general_category_links">"Link handeling"</string>
|
||||||
|
<string name="pref_general_category_displaying">"Displaying"</string>
|
||||||
|
<string name="pref_general_category_actions">"Actions"</string>
|
||||||
|
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
|
||||||
|
<string name="pref_switch_card_view_off">"The articles will be displayed as a list"</string>
|
||||||
|
<string name="pref_switch_actions_tap_on">"Displays the action bar under the article"</string>
|
||||||
|
<string name="pref_switch_actions_tap_off">"When selecting an article it will open in your selected browser"</string>
|
||||||
|
<string name="menu_home_refresh">"Update remote"</string>
|
||||||
|
<string name="refresh_success_response">"The remote is updated, you can now reload the articles list"</string>
|
||||||
|
<string name="refresh_failer_message">"The update didn't work, try again later, or check your selfoss logs."</string>
|
||||||
|
<string name="refresh_in_progress">"Refresh in progress"</string>
|
||||||
|
<string name="new_apk_available_title">"A new APK is available."</string>
|
||||||
|
<string name="new_apk_available_message">"A new APK is available to download on the official repository."</string>
|
||||||
|
<string name="new_apk_available_get">"Download now"</string>
|
||||||
|
<string name="new_apk_available_no">"Ignore version"</string>
|
||||||
|
<string name="intro_hello_title">"Hi there !"</string>
|
||||||
|
<string name="intro_hello_message">"Thanks for downloading the app !"</string>
|
||||||
|
<string name="intro_needs_selfoss_title">"Before you start…"</string>
|
||||||
|
<string name="intro_needs_selfoss_message">"You can't use the app without a Selfoss instance."</string>
|
||||||
|
<string name="intro_needs_selfoss_link">"What is Selfoss ?"</string>
|
||||||
|
<string name="intro_all_set_title">"All set !"</string>
|
||||||
|
<string name="intro_all_set_message">"You are ready to use the app. Don't forget to go to the settings page to configure your app, and where you'll find some useful links."</string>
|
||||||
|
<string name="card_height_title">Full height cards</string>
|
||||||
|
<string name="card_height_on">Cards height will adjust to its content</string>
|
||||||
|
<string name="card_height_off">Card height will be fixed</string>
|
||||||
|
<string name="source_code">Source code</string>
|
||||||
|
<string name="cant_mark_read">Can\'t mark article as read</string>
|
||||||
|
<string name="drawer_error_loading_tags">Error loading tags…</string>
|
||||||
|
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||||
|
<string name="drawer_item_filters">Filters</string>
|
||||||
|
<string name="drawer_action_clear">clear</string>
|
||||||
|
<string name="drawer_item_tags">Tags</string>
|
||||||
|
<string name="drawer_item_sources">Sources</string>
|
||||||
|
<string name="drawer_action_edit">edit</string>
|
||||||
|
<string name="cache_drawer_error" tools:keep="@string/cache_drawer_error">Couldn\'t cache your drawer data</string>
|
||||||
|
<string name="no_tags_loaded">No tags loaded</string>
|
||||||
|
<string name="no_sources_loaded">No sources loaded</string>
|
||||||
|
<string name="drawer_loading">Loading …</string>
|
||||||
|
<string name="menu_home_search">Search</string>
|
||||||
|
<string name="can_delete_source">Can\'t delete the source...</string>
|
||||||
|
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
|
||||||
|
<string name="pref_header_theme">Themes</string>
|
||||||
|
<string name="default_theme">Default</string>
|
||||||
|
<string name="teal_orange_theme">Teal/Orange/Light</string>
|
||||||
|
<string name="cyan_pink_theme">Cyan/Pink/Light</string>
|
||||||
|
<string name="grey_orange_theme">Grey/Orange/Light</string>
|
||||||
|
<string name="blue_amber_theme">Blue/Amber/Light</string>
|
||||||
|
<string name="indigo_pink_theme">Indigo/Pink/Light</string>
|
||||||
|
<string name="red_teal_theme">Red/Teal/Light</string>
|
||||||
|
<string name="teal_orange_dark_theme">Teal/Orange/Dark</string>
|
||||||
|
<string name="cyan_pink_dark_theme">Cyan/Pink/Dark</string>
|
||||||
|
<string name="default_dark_theme">Default/Dark</string>
|
||||||
|
<string name="grey_orange_dark_theme">Grey/Orange/Dark</string>
|
||||||
|
<string name="blue_amber_dark_theme">Blue/Amber/Dark</string>
|
||||||
|
<string name="indigo_pink_dark_theme">Indigo/Pink/Dark</string>
|
||||||
|
<string name="red_teal_dark_theme">Red/Teal/Dark</string>
|
||||||
|
<string name="pref_header_debug">Debug</string>
|
||||||
|
<string name="login_debug_title">Activate to log login errors</string>
|
||||||
|
<string name="login_debug_on">Any error on the login page will be logged</string>
|
||||||
|
<string name="login_debug_off">No log on the login page</string>
|
||||||
|
<string name="login_menu_debug">Debug</string>
|
||||||
|
<string name="self_hosted_cert_switch">Using a self hosted certificate ?</string>
|
||||||
|
<string name="self_signed_cert_warning">Due to security reasons, self signed certificates are not supported by default. By activating this, I\'ll not be responsible of any security problem you encounter.</string>
|
||||||
|
<string name="pref_selfoss_category">Selfoss Api</string>
|
||||||
|
<string name="pref_api_items_number_title">Loaded items number</string>
|
||||||
|
<string name="read_debug_title">Read articles appearing as unread ?</string>
|
||||||
|
<string name="read_debug_off">No log when marking an item as read</string>
|
||||||
|
<string name="read_debug_on">Api calls will be logged when marking an article as read</string>
|
||||||
|
<string name="summary_debug_identifier">Debug identifier</string>
|
||||||
|
<string name="unique_id_to_clipboard">Identifier copied to your clipboard</string>
|
||||||
|
<string name="display_header_drawer_summary">Display a header with the selfoss instance url on the lateral drawer.</string>
|
||||||
|
<string name="display_header_drawer_title">Account header</string>
|
||||||
|
<string name="login_everything_title">Logging every api calls</string>
|
||||||
|
<string name="login_everything_on">This will log every api call for debug purpose.</string>
|
||||||
|
<string name="login_everything_off">No api call will be logged</string>
|
||||||
|
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string>
|
||||||
|
<string name="translation">Translation</string>
|
||||||
|
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
|
||||||
|
</resources>
|
158
app/src/main/res/values-ca/strings.xml
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--Generated by crowdin.com-->
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<string name="app_name">"Reader for Selfoss"</string>
|
||||||
|
<string name="title_activity_login">"Log in"</string>
|
||||||
|
<string name="prompt_password">"Password"</string>
|
||||||
|
<string name="prompt_http_password">"HTTP Password"</string>
|
||||||
|
<string name="action_sign_in">"Go"</string>
|
||||||
|
<string name="error_invalid_password">"Password not long enough"</string>
|
||||||
|
<string name="error_field_required">"Field required"</string>
|
||||||
|
<string name="prompt_url">"Url"</string>
|
||||||
|
<string name="withLoginSwitch">"Login required ?"</string>
|
||||||
|
<string name="withHttpLoginSwitch">"HTTP Login required ?"</string>
|
||||||
|
<string name="login_url_problem">"Oops. You may need to add a \"/\" at the end of the url."</string>
|
||||||
|
<string name="prompt_login">"Username"</string>
|
||||||
|
<string name="prompt_http_login">"HTTP Username"</string>
|
||||||
|
<string name="label_share">"Share"</string>
|
||||||
|
<string name="readAll">"Read all"</string>
|
||||||
|
<string name="action_disconnect">"Disconnect"</string>
|
||||||
|
<string name="title_activity_settings">"Settings"</string>
|
||||||
|
<string name="pref_header_general">"General"</string>
|
||||||
|
<string name="pref_switch_actions_tap_title">"Tap action on the articles"</string>
|
||||||
|
<string name="add_source_hint_tags">"Tag1, Tag2, Tag3"</string>
|
||||||
|
<string name="add_source_hint_url">"Link"</string>
|
||||||
|
<string name="add_source_hint_name">"Name"</string>
|
||||||
|
<string name="add_source">"Add a source"</string>
|
||||||
|
<string name="add_source_save">"Save"</string>
|
||||||
|
<string name="wrong_infos">"Check your details again."</string>
|
||||||
|
<string name="all_posts_not_read">"All posts weren't read"</string>
|
||||||
|
<string name="all_posts_read">"All posts were read"</string>
|
||||||
|
<string name="cant_get_favs">"Can't get favorites"</string>
|
||||||
|
<string name="cant_get_new_elements">"Can't get new articles"</string>
|
||||||
|
<string name="cant_get_read">"Can't get read articles"</string>
|
||||||
|
<string name="nothing_here">"Nothing here"</string>
|
||||||
|
<string name="tab_new">"New"</string>
|
||||||
|
<string name="tab_read">"All"</string>
|
||||||
|
<string name="tab_favs">"Favorites"</string>
|
||||||
|
<string name="action_about">"About"</string>
|
||||||
|
<string name="marked_as_read">"Item read"</string>
|
||||||
|
<string name="undo_string">"Undo"</string>
|
||||||
|
<string name="addStringNoUrl">"Log in to add sources."</string>
|
||||||
|
<string name="cant_get_sources">"Can't get sources list."</string>
|
||||||
|
<string name="cant_create_source">"Can't create source."</string>
|
||||||
|
<string name="cant_get_spouts">"Can't get spouts list."</string>
|
||||||
|
<string name="form_not_complete">"The form is not complete"</string>
|
||||||
|
<string name="pref_header_links">"Links"</string>
|
||||||
|
<string name="issue_tracker_link">"Issue Tracker"</string>
|
||||||
|
<string name="issue_tracker_summary">"Report a bug or ask for a new feature"</string>
|
||||||
|
<string name="warning_version">"WARNING"</string>
|
||||||
|
<string name="warning_wrong_url">"WARNING"</string>
|
||||||
|
<string name="text_version">"You seem to be using a version of the app that doesn't come from the store. The app could have been tampered with. I will not be responsible if it causes any damage to your device. Consider using the ReaderForSelfoss app from the Play Store."</string>
|
||||||
|
<string name="pref_switch_card_view_title">"Card View"</string>
|
||||||
|
<string name="cant_mark_favortie">"Can't mark article as favorite"</string>
|
||||||
|
<string name="cant_unmark_favortie">"Can't remove item from favorite"</string>
|
||||||
|
<string name="share">"Share"</string>
|
||||||
|
<string name="rating_prompt_title">"Enjoying the app ?"</string>
|
||||||
|
<string name="rating_prompt_yes">"Yes !"</string>
|
||||||
|
<string name="rating_prompt_no">"Not really …"</string>
|
||||||
|
<string name="rating_prompt_feedback_title">"Can you tell us why ?"</string>
|
||||||
|
<string name="rating_prompt_feedback_yes">"OK !"</string>
|
||||||
|
<string name="rating_prompt_feedback_no">"Not now."</string>
|
||||||
|
<string name="rating_prompt_rating_title">"Great ! Can you rate us on the Store ?"</string>
|
||||||
|
<string name="rating_prompt_rating_yes">"Sure !"</string>
|
||||||
|
<string name="rating_prompt_rating_no">"Not right now."</string>
|
||||||
|
<string name="rating_prompt_thanks">"Thanks, your feedback help enhance the app !"</string>
|
||||||
|
<string name="switch_unread_count">"Display the unread count as a badge for the bottom bar."</string>
|
||||||
|
<string name="switch_unread_count_title">"Display unread count"</string>
|
||||||
|
<string name="display_all_counts_title">"Display count for favorite and read"</string>
|
||||||
|
<string name="menu_share_the_app">"Invite friends"</string>
|
||||||
|
<string name="invitation_title">"Try this app for your Selfoss RSS feeds !"</string>
|
||||||
|
<string name="invitation_message">"I use this app for my Selfoss RSS feeds. You may like it too !"</string>
|
||||||
|
<string name="invitation_cta">"Try the app"</string>
|
||||||
|
<string name="text_wrong_url">"You seem to be trying to use an invalid URL. Make sure it is correct, and if the problem persists, contact me (via the store contact link). Please note that the app needs you to be using Selfoss. You can't access RSS feeds without it."</string>
|
||||||
|
<string name="pref_general_internal_browser_title">"Open links inside the app"</string>
|
||||||
|
<string name="pref_general_internal_browser_on">"Articles will open inside the app"</string>
|
||||||
|
<string name="pref_general_internal_browser_off">"Articles will open with your default browser"</string>
|
||||||
|
<string name="prefer_article_viewer_title">"Use the article viewer"</string>
|
||||||
|
<string name="prefer_article_viewer_on">"Will use the article viewer instead of the internal browser"</string>
|
||||||
|
<string name="prefer_article_viewer_off">"Will use the internal browser instead of the article viewer"</string>
|
||||||
|
<string name="pref_general_category_links">"Link handeling"</string>
|
||||||
|
<string name="pref_general_category_displaying">"Displaying"</string>
|
||||||
|
<string name="pref_general_category_actions">"Actions"</string>
|
||||||
|
<string name="pref_switch_card_view_on">"The articles will be displayed as cards"</string>
|
||||||
|
<string name="pref_switch_card_view_off">"The articles will be displayed as a list"</string>
|
||||||
|
<string name="pref_switch_actions_tap_on">"Displays the action bar under the article"</string>
|
||||||
|
<string name="pref_switch_actions_tap_off">"When selecting an article it will open in your selected browser"</string>
|
||||||
|
<string name="menu_home_refresh">"Update remote"</string>
|
||||||
|
<string name="refresh_success_response">"The remote is updated, you can now reload the articles list"</string>
|
||||||
|
<string name="refresh_failer_message">"The update didn't work, try again later, or check your selfoss logs."</string>
|
||||||
|
<string name="refresh_in_progress">"Refresh in progress"</string>
|
||||||
|
<string name="new_apk_available_title">"A new APK is available."</string>
|
||||||
|
<string name="new_apk_available_message">"A new APK is available to download on the official repository."</string>
|
||||||
|
<string name="new_apk_available_get">"Download now"</string>
|
||||||
|
<string name="new_apk_available_no">"Ignore version"</string>
|
||||||
|
<string name="intro_hello_title">"Hi there !"</string>
|
||||||
|
<string name="intro_hello_message">"Thanks for downloading the app !"</string>
|
||||||
|
<string name="intro_needs_selfoss_title">"Before you start…"</string>
|
||||||
|
<string name="intro_needs_selfoss_message">"You can't use the app without a Selfoss instance."</string>
|
||||||
|
<string name="intro_needs_selfoss_link">"What is Selfoss ?"</string>
|
||||||
|
<string name="intro_all_set_title">"All set !"</string>
|
||||||
|
<string name="intro_all_set_message">"You are ready to use the app. Don't forget to go to the settings page to configure your app, and where you'll find some useful links."</string>
|
||||||
|
<string name="card_height_title">Full height cards</string>
|
||||||
|
<string name="card_height_on">Cards height will adjust to its content</string>
|
||||||
|
<string name="card_height_off">Card height will be fixed</string>
|
||||||
|
<string name="source_code">Source code</string>
|
||||||
|
<string name="cant_mark_read">Can\'t mark article as read</string>
|
||||||
|
<string name="drawer_error_loading_tags">Error loading tags…</string>
|
||||||
|
<string name="drawer_error_loading_sources">Error loading sources…</string>
|
||||||
|
<string name="drawer_item_filters">Filters</string>
|
||||||
|
<string name="drawer_action_clear">clear</string>
|
||||||
|
<string name="drawer_item_tags">Tags</string>
|
||||||
|
<string name="drawer_item_sources">Sources</string>
|
||||||
|
<string name="drawer_action_edit">edit</string>
|
||||||
|
<string name="cache_drawer_error" tools:keep="@string/cache_drawer_error">Couldn\'t cache your drawer data</string>
|
||||||
|
<string name="no_tags_loaded">No tags loaded</string>
|
||||||
|
<string name="no_sources_loaded">No sources loaded</string>
|
||||||
|
<string name="drawer_loading">Loading …</string>
|
||||||
|
<string name="menu_home_search">Search</string>
|
||||||
|
<string name="can_delete_source">Can\'t delete the source...</string>
|
||||||
|
<string name="base_url_error">There was an issue when trying to communicate with your Selfoss Instance. If the issue persists, please get in touch with me.</string>
|
||||||
|
<string name="pref_header_theme">Themes</string>
|
||||||
|
<string name="default_theme">Default</string>
|
||||||
|
<string name="teal_orange_theme">Teal/Orange/Light</string>
|
||||||
|
<string name="cyan_pink_theme">Cyan/Pink/Light</string>
|
||||||
|
<string name="grey_orange_theme">Grey/Orange/Light</string>
|
||||||
|
<string name="blue_amber_theme">Blue/Amber/Light</string>
|
||||||
|
<string name="indigo_pink_theme">Indigo/Pink/Light</string>
|
||||||
|
<string name="red_teal_theme">Red/Teal/Light</string>
|
||||||
|
<string name="teal_orange_dark_theme">Teal/Orange/Dark</string>
|
||||||
|
<string name="cyan_pink_dark_theme">Cyan/Pink/Dark</string>
|
||||||
|
<string name="default_dark_theme">Default/Dark</string>
|
||||||
|
<string name="grey_orange_dark_theme">Grey/Orange/Dark</string>
|
||||||
|
<string name="blue_amber_dark_theme">Blue/Amber/Dark</string>
|
||||||
|
<string name="indigo_pink_dark_theme">Indigo/Pink/Dark</string>
|
||||||
|
<string name="red_teal_dark_theme">Red/Teal/Dark</string>
|
||||||
|
<string name="pref_header_debug">Debug</string>
|
||||||
|
<string name="login_debug_title">Activate to log login errors</string>
|
||||||
|
<string name="login_debug_on">Any error on the login page will be logged</string>
|
||||||
|
<string name="login_debug_off">No log on the login page</string>
|
||||||
|
<string name="login_menu_debug">Debug</string>
|
||||||
|
<string name="self_hosted_cert_switch">Using a self hosted certificate ?</string>
|
||||||
|
<string name="self_signed_cert_warning">Due to security reasons, self signed certificates are not supported by default. By activating this, I\'ll not be responsible of any security problem you encounter.</string>
|
||||||
|
<string name="pref_selfoss_category">Selfoss Api</string>
|
||||||
|
<string name="pref_api_items_number_title">Loaded items number</string>
|
||||||
|
<string name="read_debug_title">Read articles appearing as unread ?</string>
|
||||||
|
<string name="read_debug_off">No log when marking an item as read</string>
|
||||||
|
<string name="read_debug_on">Api calls will be logged when marking an article as read</string>
|
||||||
|
<string name="summary_debug_identifier">Debug identifier</string>
|
||||||
|
<string name="unique_id_to_clipboard">Identifier copied to your clipboard</string>
|
||||||
|
<string name="display_header_drawer_summary">Display a header with the selfoss instance url on the lateral drawer.</string>
|
||||||
|
<string name="display_header_drawer_title">Account header</string>
|
||||||
|
<string name="login_everything_title">Logging every api calls</string>
|
||||||
|
<string name="login_everything_on">This will log every api call for debug purpose.</string>
|
||||||
|
<string name="login_everything_off">No api call will be logged</string>
|
||||||
|
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string>
|
||||||
|
<string name="translation">Translation</string>
|
||||||
|
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
|
||||||
|
</resources>
|