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