Compare commits
65 Commits
Author | SHA1 | Date | |
---|---|---|---|
abe546dcda | |||
e6f367acaf | |||
a9b61853b9 | |||
5afc04a630 | |||
1da4cc2782 | |||
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 |
39
.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,40 @@ 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 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.**
|
||||||
|
- githubToken: a github token used to report issues from within the app. [Details here](https://github.com/heinrichreimer/android-issue-reporter#how-to-create-a-bot-key). **It can be empty.**
|
||||||
|
- appLoginUrl, appLoginUsername and appLoginPassword: url, username and password of a selfoss instance. **These are only used for tests. They can be empty if you don't test API calls.**
|
||||||
|
|
||||||
- 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.
|
||||||
|
githubToken="GITHUBTOKEN" # It can be empty or use https://github.com/heinrichreimer/android-issue-reporter#how-to-create-a-bot-key to generate one
|
||||||
|
```
|
||||||
|
|
||||||
|
#### As gradle parameters
|
||||||
|
|
||||||
|
```
|
||||||
|
./gradlew .... -P appLoginUrl="URL" -P appLoginUsername="LOGIN" -P appLoginPassword="PASS" -P mercuryApiKey="LONGAPIKEY" -P feedbackEmail="EMAIL" -P sourceUrl="URLSOURCE" -P trackerUrl="URLTRACKER" -P githubToken="GITHUBTOKEN"
|
||||||
|
```
|
||||||
|
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
|
141
CHANGELOG.md
@ -1,4 +1,143 @@
|
|||||||
**1.5.1.3**
|
**1.5.4.01**
|
||||||
|
|
||||||
|
- Removed the "apk downloaded from outside of playstore" message.
|
||||||
|
|
||||||
|
- Versions update.
|
||||||
|
|
||||||
|
- HTML viewer version update. It should fix an issue with images.
|
||||||
|
|
||||||
|
- Some code cleaning.
|
||||||
|
|
||||||
|
**1.5.4.00**
|
||||||
|
|
||||||
|
- Added issue reporting from within the app.
|
||||||
|
|
||||||
|
**1.5.3.06**
|
||||||
|
|
||||||
|
- 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 ?
|
||||||
|
|
||||||
|
111
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,18 @@ 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
|
||||||
|
buildConfigField "String", "GITHUB_TOKEN", githubToken
|
||||||
}
|
}
|
||||||
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 +95,80 @@ 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.1'
|
||||||
androidTestCompile 'com.android.support.test:runner:0.5'
|
androidTestCompile 'com.android.support.test:runner:1.0.1'
|
||||||
// Espresso-contrib for DatePicker, RecyclerView, Drawer actions, Accessibility checks, CountingIdlingResource
|
// Espresso-contrib for DatePicker, RecyclerView, Drawer actions, Accessibility checks, CountingIdlingResource
|
||||||
androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.2.2'
|
androidTestCompile 'com.android.support.test.espresso:espresso-contrib:3.0.1'
|
||||||
// Espresso-intents for validation and stubbing of Intents
|
// Espresso-intents for validation and stubbing of Intents
|
||||||
androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'
|
androidTestCompile 'com.android.support.test.espresso:espresso-intents:3.0.1'
|
||||||
|
|
||||||
|
|
||||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
|
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
|
||||||
|
|
||||||
// Android Support
|
// Android Support
|
||||||
compile 'com.android.support:appcompat-v7:26.0.0-beta2'
|
compile 'com.android.support:appcompat-v7:26.1.0'
|
||||||
compile 'com.android.support:design:26.0.0-beta2'
|
compile 'com.android.support:design:26.1.0'
|
||||||
compile 'com.android.support:recyclerview-v7:26.0.0-beta2'
|
compile 'com.android.support:recyclerview-v7:26.1.0'
|
||||||
compile 'com.android.support:support-v4:26.0.0-beta2'
|
compile 'com.android.support:support-v4:26.1.0'
|
||||||
compile 'com.android.support:support-vector-drawable:26.0.0-beta2'
|
compile 'com.android.support:support-vector-drawable:26.1.0'
|
||||||
compile 'com.android.support:customtabs:26.0.0-beta2'
|
compile 'com.android.support:customtabs:26.1.0'
|
||||||
compile 'com.android.support:cardview-v7:26.0.0-beta2'
|
compile 'com.android.support:cardview-v7:26.1.0'
|
||||||
compile 'com.android.support.constraint:constraint-layout:1.0.2'
|
compile 'com.android.support.constraint:constraint-layout:1.0.2'
|
||||||
|
|
||||||
// Firebase + crashlytics
|
// Firebase + crashlytics
|
||||||
compile 'com.google.firebase:firebase-core:11.0.1'
|
compile 'com.google.firebase:firebase-core:11.4.2'
|
||||||
compile 'com.google.firebase:firebase-config:11.0.1'
|
compile 'com.google.firebase:firebase-config:11.4.2'
|
||||||
compile 'com.google.firebase:firebase-invites:11.0.1'
|
compile 'com.google.firebase:firebase-invites:11.4.2'
|
||||||
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.5'
|
||||||
|
|
||||||
// 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'
|
||||||
|
|
||||||
|
// Github issues reporter
|
||||||
|
compile 'com.heinrichreimersoftware:android-issue-reporter:1.3.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'com.google.gms.google-services'
|
apply plugin: 'com.google.gms.google-services'
|
||||||
@ -144,6 +177,7 @@ apply plugin: 'com.google.gms.google-services'
|
|||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
initFabricPropertiesIfNeeded()
|
initFabricPropertiesIfNeeded()
|
||||||
initAppLoginPropertiesIfNeeded()
|
initAppLoginPropertiesIfNeeded()
|
||||||
|
initAppForSecretPropertiesIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
def initFabricPropertiesIfNeeded() {
|
def initFabricPropertiesIfNeeded() {
|
||||||
@ -168,3 +202,18 @@ 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"))
|
||||||
|
entry(key: "githubToken", value: System.getProperty("githubToken"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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.**
|
@ -23,8 +23,8 @@ import org.junit.Rule
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
import apps.amine.bou.readerforselfoss.settings.SettingsActivity
|
|
||||||
import apps.amine.bou.readerforselfoss.utils.Config
|
import apps.amine.bou.readerforselfoss.utils.Config
|
||||||
|
import com.heinrichreimersoftware.androidissuereporter.IssueReporterLauncher
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
|
|
||||||
|
|
||||||
@ -72,9 +72,6 @@ class HomeActivityEspressoTest {
|
|||||||
|
|
||||||
onView(withContentDescription(R.string.abc_toolbar_collapse_description)).perform(click())
|
onView(withContentDescription(R.string.abc_toolbar_collapse_description)).perform(click())
|
||||||
|
|
||||||
|
|
||||||
onView(withMenu(id = R.id.readAll, titleId = R.string.readAll)).perform(click())
|
|
||||||
|
|
||||||
openActionBarOverflowOrOptionsMenu(context)
|
openActionBarOverflowOrOptionsMenu(context)
|
||||||
|
|
||||||
onView(withMenu(id = R.id.refresh, titleId = R.string.menu_home_refresh))
|
onView(withMenu(id = R.id.refresh, titleId = R.string.menu_home_refresh))
|
||||||
@ -86,9 +83,6 @@ class HomeActivityEspressoTest {
|
|||||||
|
|
||||||
intended(hasComponent(LoginActivity::class.java.name), times(1))
|
intended(hasComponent(LoginActivity::class.java.name), times(1))
|
||||||
|
|
||||||
onView(isRoot()).perform(pressBack())
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -98,8 +92,9 @@ class HomeActivityEspressoTest {
|
|||||||
|
|
||||||
onView(withId(R.id.material_drawer_layout)).perform(DrawerActions.open())
|
onView(withId(R.id.material_drawer_layout)).perform(DrawerActions.open())
|
||||||
|
|
||||||
onView(withText(R.string.action_about)).perform(click())
|
onView(withText(R.string.drawer_report_bug)).perform(click())
|
||||||
intended(hasComponent(LibsActivity::class.java.name))
|
intended(hasComponent(IssueReporterLauncher.Activity::class.java.name))
|
||||||
|
onView(isRoot()).perform(pressBack())
|
||||||
onView(isRoot()).perform(pressBack())
|
onView(isRoot()).perform(pressBack())
|
||||||
intended(hasComponent(HomeActivity::class.java.name))
|
intended(hasComponent(HomeActivity::class.java.name))
|
||||||
|
|
||||||
@ -108,10 +103,6 @@ class HomeActivityEspressoTest {
|
|||||||
onView(withId(R.id.material_drawer_layout)).perform(DrawerActions.open())
|
onView(withId(R.id.material_drawer_layout)).perform(DrawerActions.open())
|
||||||
onView(withText(R.string.drawer_action_clear)).perform(click())
|
onView(withText(R.string.drawer_action_clear)).perform(click())
|
||||||
|
|
||||||
// bug
|
|
||||||
//onView(withText(R.string.title_activity_settings)).perform(scrollTo(), click())
|
|
||||||
//intended(hasComponent(SettingsActivity::class.java.name))
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test articles opening and actions for cards and lists
|
// TODO: test articles opening and actions for cards and lists
|
||||||
|
@ -91,29 +91,6 @@ class IntroActivityEspressoTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun clickSelfossUrl() {
|
|
||||||
rule.launchActivity(Intent())
|
|
||||||
|
|
||||||
onView(withText(R.string.intro_hello_title)).check(matches(isDisplayed()))
|
|
||||||
|
|
||||||
onView(withId(R.id.button_next)).perform(click())
|
|
||||||
|
|
||||||
onView(withId(R.id.button_message)).perform(click())
|
|
||||||
|
|
||||||
intended(
|
|
||||||
allOf(
|
|
||||||
hasData(
|
|
||||||
hasHost(
|
|
||||||
equalTo("selfoss.aditu.de")
|
|
||||||
)
|
|
||||||
),
|
|
||||||
hasAction(Intent.ACTION_VIEW)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
@After
|
||||||
fun releaseIntents() {
|
fun releaseIntents() {
|
||||||
Intents.release()
|
Intents.release()
|
||||||
|
@ -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.checkAndDisplayStoreApk
|
import apps.amine.bou.readerforselfoss.utils.bottombar.maybeShow
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.bottombar.removeBadge
|
||||||
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.heinrichreimersoftware.androidissuereporter.IssueReporterLauncher
|
||||||
|
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,23 +196,70 @@ 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()
|
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)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,30 +270,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 +296,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 +331,48 @@ 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()
|
|
||||||
|
if (displayAccountHeader && headerResult != null)
|
||||||
|
drawerBuilder.withAccountHeader(headerResult)
|
||||||
|
|
||||||
|
drawer = drawerBuilder.build()
|
||||||
|
|
||||||
drawer.addStickyFooterItem(
|
drawer.addStickyFooterItem(
|
||||||
PrimaryDrawerItem()
|
PrimaryDrawerItem()
|
||||||
.withName(R.string.action_about)
|
.withName(R.string.drawer_report_bug)
|
||||||
.withSelectable(false)
|
.withIcon(R.drawable.ic_bug_report)
|
||||||
.withIcon(R.drawable.ic_info_outline)
|
.withIconTintingEnabled(true)
|
||||||
.withOnDrawerItemClickListener { _, _, _ ->
|
.withOnDrawerItemClickListener { _, _, _ ->
|
||||||
LibsBuilder()
|
IssueReporterLauncher.forTarget(getString(R.string.report_github_user), getString(R.string.report_github_repo))
|
||||||
.withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR)
|
.theme(R.style.Theme_App_Light)
|
||||||
.withAboutIconShown(true)
|
.guestToken(BuildConfig.GITHUB_TOKEN)
|
||||||
.withAboutVersionShown(true)
|
.guestEmailRequired(true)
|
||||||
.start(this@HomeActivity)
|
.minDescriptionLength(20)
|
||||||
|
.putExtraInfo("Unique ID", settings.getString("unique_id", ""))
|
||||||
|
.putExtraInfo("From github", BuildConfig.GITHUB_VERSION)
|
||||||
|
.homeAsUpEnabled(true)
|
||||||
|
.launch(this)
|
||||||
false
|
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 +399,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 +412,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 +471,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 +484,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 +589,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 +696,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 +745,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 +780,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 +801,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 +875,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,19 @@ 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.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 +29,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 +47,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,10 +73,13 @@ 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 {
|
|
||||||
this@LoginActivity.checkAndDisplayStoreApk()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mFirebaseAnalytics = FirebaseAnalytics.getInstance(this)
|
mFirebaseAnalytics = FirebaseAnalytics.getInstance(this)
|
||||||
@ -91,6 +98,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 +160,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 +197,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 +219,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 +233,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 +277,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 +291,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()
|
||||||
}
|
}
|
||||||
@ -199,7 +223,7 @@ class ItemCardAdapter(private val app: Activity,
|
|||||||
}
|
}
|
||||||
|
|
||||||
browserBtn.setOnClickListener {
|
browserBtn.setOnClickListener {
|
||||||
c.openInBrowser(items[adapterPosition])
|
c.openInBrowserAsNewTask(items[adapterPosition])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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)
|
||||||
@ -209,7 +226,7 @@ class ItemListAdapter(private val app: Activity,
|
|||||||
}
|
}
|
||||||
|
|
||||||
browserBtn.setOnClickListener {
|
browserBtn.setOnClickListener {
|
||||||
c.openInBrowser(items[adapterPosition])
|
c.openInBrowserAsNewTask(items[adapterPosition])
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -5,48 +5,13 @@ import android.content.Intent
|
|||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.support.v7.app.AlertDialog
|
import android.support.v7.app.AlertDialog
|
||||||
import android.text.TextUtils
|
|
||||||
import 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.R
|
import apps.amine.bou.readerforselfoss.R
|
||||||
import apps.amine.bou.readerforselfoss.api.selfoss.Item
|
import apps.amine.bou.readerforselfoss.api.selfoss.Item
|
||||||
|
|
||||||
|
|
||||||
fun Context.checkAndDisplayStoreApk() = {
|
|
||||||
fun isStoreVersion(): Boolean =
|
|
||||||
try {
|
|
||||||
val installer = this.packageManager
|
|
||||||
.getInstallerPackageName(this.packageName)
|
|
||||||
!TextUtils.isEmpty(installer)
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isStoreVersion() && !BuildConfig.GITHUB_VERSION) {
|
|
||||||
val alertDialog = AlertDialog.Builder(this).create()
|
|
||||||
alertDialog.setTitle(getString(R.string.warning_version))
|
|
||||||
alertDialog.setMessage(getString(R.string.text_version))
|
|
||||||
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
|
|
||||||
{ dialog, _ -> dialog.dismiss() })
|
|
||||||
alertDialog.show()
|
|
||||||
} else Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
fun String.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 +59,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
|
||||||
@ -114,10 +79,3 @@ fun Context.shareLink(itemUrl: String) {
|
|||||||
sendIntent.type = "text/plain"
|
sendIntent.type = "text/plain"
|
||||||
startActivity(Intent.createChooser(sendIntent, getString(R.string.share)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
|
startActivity(Intent.createChooser(sendIntent, getString(R.string.share)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.openInBrowser(i: Item) {
|
|
||||||
val intent = Intent(Intent.ACTION_VIEW)
|
|
||||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
|
||||||
intent.data = Uri.parse(i.getLinkDecoded().toStringUriWithHttp())
|
|
||||||
startActivity(intent)
|
|
||||||
}
|
|
@ -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,14 @@ 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.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 +50,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 +68,50 @@ 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
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.openInBrowserAsNewTask(i: Item) {
|
||||||
|
val intent = Intent(Intent.ACTION_VIEW)
|
||||||
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
intent.data = Uri.parse(i.getLinkDecoded().toStringUriWithHttp())
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
@ -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 |
Before Width: | Height: | Size: 434 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 |
Before Width: | Height: | Size: 307 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 |
Before Width: | Height: | Size: 542 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 |
Before Width: | Height: | Size: 768 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 |
Before Width: | Height: | Size: 1.1 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"
|
||||||
@ -115,4 +131,6 @@
|
|||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
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"
|
||||||
@ -40,9 +55,8 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/prompt_url"
|
android:hint="@string/prompt_url"
|
||||||
android:imeActionId="@+id/login"
|
|
||||||
android:inputType="textUri"
|
|
||||||
android:imeOptions="actionUnspecified"
|
android:imeOptions="actionUnspecified"
|
||||||
|
android:inputType="textUri"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -123,6 +137,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"
|
||||||
@ -135,4 +163,6 @@
|
|||||||
|
|
||||||
</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"
|
||||||
|
@ -5,14 +5,14 @@
|
|||||||
<item android:id="@+id/action_search"
|
<item android:id="@+id/action_search"
|
||||||
android:title="@string/menu_home_search"
|
android:title="@string/menu_home_search"
|
||||||
android:icon="@drawable/ic_action_search"
|
android:icon="@drawable/ic_action_search"
|
||||||
app:showAsAction="always|collapseActionView"
|
app:showAsAction="ifRoom|collapseActionView"
|
||||||
app:actionViewClass="android.support.v7.widget.SearchView" />
|
app:actionViewClass="android.support.v7.widget.SearchView" />
|
||||||
|
|
||||||
<item android:id="@+id/readAll"
|
<item android:id="@+id/readAll"
|
||||||
android:icon="@drawable/ic_done_all_white_24dp"
|
android:icon="@drawable/ic_done_all_white_24dp"
|
||||||
android:title="@string/readAll"
|
android:title="@string/readAll"
|
||||||
android:orderInCategory="1"
|
android:orderInCategory="1"
|
||||||
app:showAsAction="always"/>
|
app:showAsAction="ifRoom"/>
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/refresh"
|
android:id="@+id/refresh"
|
||||||
|
@ -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 |