Compare commits

...

31 Commits

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

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Portuguese, Brazilian)

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

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Portuguese, Brazilian)

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

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Japanese)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Swedish)

* New translations strings.xml (Spanish)

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

* New translations strings.xml (Russian)

* New translations strings.xml (Romanian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Polish)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Korean)

* New translations strings.xml (Italian)

* New translations strings.xml (Arabic)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Greek)

* New translations strings.xml (German)

* New translations strings.xml (French)

* New translations strings.xml (Finnish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Danish)

* New translations strings.xml (Czech)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Catalan)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Japanese)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Swedish)

* New translations strings.xml (Spanish)

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

* New translations strings.xml (Russian)

* New translations strings.xml (Romanian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Arabic)

* New translations strings.xml (Greek)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Polish)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Korean)

* New translations strings.xml (Italian)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (German)

* New translations strings.xml (Catalan)

* New translations strings.xml (French)

* New translations strings.xml (Finnish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Danish)

* New translations strings.xml (Czech)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Portuguese, Brazilian)

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

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Japanese)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Swedish)

* New translations strings.xml (Spanish)

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

* New translations strings.xml (Russian)

* New translations strings.xml (Romanian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Polish)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Korean)

* New translations strings.xml (Italian)

* New translations strings.xml (Arabic)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Greek)

* New translations strings.xml (German)

* New translations strings.xml (French)

* New translations strings.xml (Finnish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Danish)

* New translations strings.xml (Czech)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Catalan)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Japanese)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Swedish)

* New translations strings.xml (Spanish)

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

* New translations strings.xml (Russian)

* New translations strings.xml (Romanian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Arabic)

* New translations strings.xml (Greek)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Polish)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Korean)

* New translations strings.xml (Italian)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (German)

* New translations strings.xml (Catalan)

* New translations strings.xml (French)

* New translations strings.xml (Finnish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Danish)

* New translations strings.xml (Czech)

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

View File

@ -10,7 +10,7 @@ Please read the guidelines before contributing, and follow them (or try to) when
There are many ways to contribute to this project, you could report bugs, request missing features, suggest enhancements and changes to existing ones. You also can improve the README with useful tips that could help the other users. There are many ways to contribute to this project, you could report bugs, request missing features, suggest enhancements and changes to existing ones. You also can improve the README with useful tips that could help the other users.
You can fork the repository, and [help me solve some issues](https://github.com/aminecmi/ReaderforSelfoss/labels/help%20wanted) or [develop new things](https://github.com/aminecmi/ReaderforSelfoss/issues) You can fork the repository, and [help me solve some issues](https://github.com/aminecmi/ReaderforSelfoss/issues?q=is%3Aissue+is%3Aopen+label%3A%22Up+For+Grabs%22) or [develop new things](https://github.com/aminecmi/ReaderforSelfoss/issues)
### What I can't help you with. ### What I can't help you with.
@ -31,7 +31,7 @@ Always check if the web version of your instance is working.
* Please ask before starting to work on an issue. I may be working on it, or someone else could be doing so. * Please ask before starting to work on an issue. I may be working on it, or someone else could be doing so.
* Each pull request should implement **ONE** feature or bugfix. Keep in mind that you can submit as many PR as you want. * Each pull request should implement **ONE** feature or bugfix. Keep in mind that you can submit as many PR as you want.
* Your code must be simple and clear enough to avoid using comments to explain what it does. * Your code must be simple and clear enough to avoid using comments to explain what it does.
* Follow the used coding style [the official one](https://kotlinlang.org/docs/reference/coding-conventions.html) ([some idoms for reference](http://kotlinlang.org/docs/reference/idioms.html)) with more to come. * Follow the used coding style [the android koding style](https://android.github.io/kotlin-guides/style.html) ([some idoms for reference](http://kotlinlang.org/docs/reference/idioms.html)) with more to come.
* Try as much as possible to write a test for your feature, and if you do so, run it, and make it work. * Try as much as possible to write a test for your feature, and if you do so, run it, and make it work.
* Always check your changes and discard the ones that are irrelevant to your feature or bugfix. * Always check your changes and discard the ones that are irrelevant to your feature or bugfix.
* Have meaningful commit messages. * Have meaningful commit messages.

View File

@ -1,3 +1,47 @@
**1.5.4.14**
- Fixing infinite scroll trying to load more items when there are no more.
**1.5.4.13**
- Displaying the right number of items.
- Fixing infinite scroll remaining issues. Should be stable enough.
**1.5.4.12**
- Fixed fab and toolbar issue (#113)
- Fixed links clickable (#114)
- Changed the link colors in the article viewer
**1.5.4.11**
- Hiding FABs on scroll.
- Closing #109 (code cleaning)
- Hiding fabs on scroll (#101)
**1.5.4.10**
- Displaying a loader when "reading more" in the article viewer.
- Displaying the thumbnail instead of icon on the article viewer.
- Scrolling to top when loading content with the "read more" button.
**1.5.4.09**
- Using the kotlin wrapper for the material drawer (see #98 for more details).
- Updated support libraries
- Changed the Floating Action Button to the support library version.
- New reader activity action bar #103.
**1.5.4.08** **1.5.4.08**
- Thanks @jrafaelsantana for translating the whole app in Brazilian Portuguese. - Thanks @jrafaelsantana for translating the whole app in Brazilian Portuguese.

View File

@ -31,6 +31,8 @@ apply plugin: 'io.fabric'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
repositories { repositories {
maven { maven {
url 'https://maven.fabric.io/public' url 'https://maven.fabric.io/public'
@ -38,12 +40,12 @@ repositories {
} }
android { android {
compileSdkVersion 26 compileSdkVersion 27
buildToolsVersion '26.0.2' buildToolsVersion '27.0.0'
defaultConfig { defaultConfig {
applicationId "apps.amine.bou.readerforselfoss" applicationId "apps.amine.bou.readerforselfoss"
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 26 targetSdkVersion 27
versionCode versionCodeFromGit() versionCode versionCodeFromGit()
versionName versionNameFromGit() versionName versionNameFromGit()
@ -107,13 +109,13 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
// Android Support // Android Support
compile 'com.android.support:appcompat-v7:26.1.0' compile 'com.android.support:appcompat-v7:27.0.0'
compile 'com.android.support:design:26.1.0' compile 'com.android.support:design:27.0.0'
compile 'com.android.support:recyclerview-v7:26.1.0' compile 'com.android.support:recyclerview-v7:27.0.0'
compile 'com.android.support:support-v4:26.1.0' compile 'com.android.support:support-v4:27.0.0'
compile 'com.android.support:support-vector-drawable:26.1.0' compile 'com.android.support:support-vector-drawable:27.0.0'
compile 'com.android.support:customtabs:26.1.0' compile 'com.android.support:customtabs:27.0.0'
compile 'com.android.support:cardview-v7:26.1.0' compile 'com.android.support:cardview-v7:27.0.0'
compile 'com.android.support.constraint:constraint-layout:1.0.2' compile 'com.android.support.constraint:constraint-layout:1.0.2'
// Firebase + crashlytics // Firebase + crashlytics
@ -131,7 +133,7 @@ dependencies {
compile 'agency.tango.android:material-intro-screen:0.0.5' compile 'agency.tango.android:material-intro-screen:0.0.5'
// About // About
compile('com.mikepenz:aboutlibraries:5.9.7@aar') { compile('com.mikepenz:aboutlibraries:6.0.0@aar') {
transitive = true transitive = true
} }
@ -143,7 +145,6 @@ dependencies {
// Material-ish things // Material-ish things
compile 'com.ashokvarma.android:bottom-navigation-bar:2.0.3' compile 'com.ashokvarma.android:bottom-navigation-bar:2.0.3'
compile 'com.melnykov:floatingactionbutton:1.3.0'
compile 'com.github.jd-alexander:LikeButton:0.2.1' compile 'com.github.jd-alexander:LikeButton:0.2.1'
compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
compile 'org.sufficientlysecure:html-textview:3.5' compile 'org.sufficientlysecure:html-textview:3.5'
@ -159,9 +160,7 @@ dependencies {
compile 'com.klinkerapps:drag-dismiss-activity:1.5.0' compile 'com.klinkerapps:drag-dismiss-activity:1.5.0'
// Drawer // Drawer
compile('com.mikepenz:materialdrawer:5.9.5@aar') { implementation 'co.zsmb:materialdrawer-kt:1.2.1'
transitive = true
}
compile 'com.anupcowkur:reservoir:3.1.0' compile 'com.anupcowkur:reservoir:3.1.0'
// Themes // Themes
@ -169,6 +168,8 @@ dependencies {
// Github issues reporter // Github issues reporter
compile 'com.heinrichreimersoftware:android-issue-reporter:1.3.1' compile 'com.heinrichreimersoftware:android-issue-reporter:1.3.1'
compile 'com.github.rubensousa:floatingtoolbar:1.5.1'
} }
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'

View File

@ -32,18 +32,18 @@ class LoginActivityEspressoTest {
@Rule @JvmField @Rule @JvmField
val rule = ActivityTestRule(LoginActivity::class.java, true, false) val rule = ActivityTestRule(LoginActivity::class.java, true, false)
lateinit var context: Context private lateinit var context: Context
lateinit var url: String private lateinit var url: String
lateinit var username: String private lateinit var username: String
lateinit var password: String private lateinit var password: String
@Before @Before
fun setUp() { fun setUp() {
context = InstrumentationRegistry.getInstrumentation().targetContext context = InstrumentationRegistry.getInstrumentation().targetContext
val editor = val editor =
context context
.getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE) .getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
.edit() .edit()
editor.clear() editor.clear()
editor.commit() editor.commit()
@ -77,12 +77,12 @@ class LoginActivityEspressoTest {
fun wrongLoginUrl() { fun wrongLoginUrl() {
rule.launchActivity(Intent()) rule.launchActivity(Intent())
onView(withId(R.id.login_progress)) onView(withId(R.id.loginProgress))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE))) .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)))
onView(withId(R.id.url)).perform(click()).perform(typeText("WRONGURL")) onView(withId(R.id.urlView)).perform(click()).perform(typeText("WRONGURL"))
onView(withId(R.id.email_sign_in_button)).perform(click()) onView(withId(R.id.signInButton)).perform(click())
onView(withId(R.id.urlLayout)).check(matches(isHintOrErrorEnabled())) onView(withId(R.id.urlLayout)).check(matches(isHintOrErrorEnabled()))
} }
@ -94,24 +94,24 @@ class LoginActivityEspressoTest {
rule.launchActivity(Intent()) rule.launchActivity(Intent())
onView(withId(R.id.url)).perform(click()).perform(typeText(url), closeSoftKeyboard()) onView(withId(R.id.urlView)).perform(click()).perform(typeText(url), closeSoftKeyboard())
onView(withId(R.id.withLogin)).perform(click()) onView(withId(R.id.withLogin)).perform(click())
onView(withId(R.id.email_sign_in_button)).perform(click()) onView(withId(R.id.signInButton)).perform(click())
onView(withId(R.id.loginLayout)).check(matches(isHintOrErrorEnabled())) onView(withId(R.id.loginLayout)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled())) onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.login)).perform(click()).perform(typeText(username), closeSoftKeyboard()) onView(withId(R.id.loginView)).perform(click()).perform(typeText(username), closeSoftKeyboard())
onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled())) onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.email_sign_in_button)).perform(click()) onView(withId(R.id.signInButton)).perform(click())
onView(withId(R.id.passwordLayout)).check( onView(withId(R.id.passwordLayout)).check(
matches( matches(
isHintOrErrorEnabled()) isHintOrErrorEnabled())
) )
} }
@ -121,15 +121,15 @@ class LoginActivityEspressoTest {
rule.launchActivity(Intent()) rule.launchActivity(Intent())
onView(withId(R.id.url)).perform(click()).perform(typeText(url), closeSoftKeyboard()) onView(withId(R.id.urlView)).perform(click()).perform(typeText(url), closeSoftKeyboard())
onView(withId(R.id.withLogin)).perform(click()) onView(withId(R.id.withLogin)).perform(click())
onView(withId(R.id.login)).perform(click()).perform(typeText(username), closeSoftKeyboard()) onView(withId(R.id.loginView)).perform(click()).perform(typeText(username), closeSoftKeyboard())
onView(withId(R.id.password)).perform(click()).perform(typeText("WRONGPASS"), closeSoftKeyboard()) onView(withId(R.id.passwordView)).perform(click()).perform(typeText("WRONGPASS"), closeSoftKeyboard())
onView(withId(R.id.email_sign_in_button)).perform(click()) onView(withId(R.id.signInButton)).perform(click())
onView(withId(R.id.urlLayout)).check(matches(isHintOrErrorEnabled())) onView(withId(R.id.urlLayout)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.loginLayout)).check(matches(isHintOrErrorEnabled())) onView(withId(R.id.loginLayout)).check(matches(isHintOrErrorEnabled()))
@ -142,15 +142,15 @@ class LoginActivityEspressoTest {
rule.launchActivity(Intent()) rule.launchActivity(Intent())
onView(withId(R.id.url)).perform(click()).perform(typeText(url), closeSoftKeyboard()) onView(withId(R.id.urlView)).perform(click()).perform(typeText(url), closeSoftKeyboard())
onView(withId(R.id.withLogin)).perform(click()) onView(withId(R.id.withLogin)).perform(click())
onView(withId(R.id.login)).perform(click()).perform(typeText(username), closeSoftKeyboard()) onView(withId(R.id.loginView)).perform(click()).perform(typeText(username), closeSoftKeyboard())
onView(withId(R.id.password)).perform(click()).perform(typeText(password), closeSoftKeyboard()) onView(withId(R.id.passwordView)).perform(click()).perform(typeText(password), closeSoftKeyboard())
onView(withId(R.id.email_sign_in_button)).perform(click()) onView(withId(R.id.signInButton)).perform(click())
intended(hasComponent(HomeActivity::class.java.name)) intended(hasComponent(HomeActivity::class.java.name))

View File

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

View File

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

View File

@ -9,20 +9,16 @@ import android.graphics.drawable.GradientDrawable
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.support.design.widget.CoordinatorLayout
import android.support.v4.view.MenuItemCompat import android.support.v4.view.MenuItemCompat
import android.support.v4.widget.SwipeRefreshLayout
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.GridLayoutManager import android.support.v7.widget.GridLayoutManager
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.support.v7.widget.SearchView import android.support.v7.widget.SearchView
import android.support.v7.widget.StaggeredGridLayoutManager import android.support.v7.widget.StaggeredGridLayoutManager
import android.support.v7.widget.Toolbar
import android.support.v7.widget.helper.ItemTouchHelper import android.support.v7.widget.helper.ItemTouchHelper
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import apps.amine.bou.readerforselfoss.adapters.ItemCardAdapter import apps.amine.bou.readerforselfoss.adapters.ItemCardAdapter
import apps.amine.bou.readerforselfoss.adapters.ItemListAdapter import apps.amine.bou.readerforselfoss.adapters.ItemListAdapter
@ -41,6 +37,11 @@ import apps.amine.bou.readerforselfoss.utils.checkApkVersion
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import apps.amine.bou.readerforselfoss.utils.drawer.CustomUrlPrimaryDrawerItem import apps.amine.bou.readerforselfoss.utils.drawer.CustomUrlPrimaryDrawerItem
import apps.amine.bou.readerforselfoss.utils.longHash import apps.amine.bou.readerforselfoss.utils.longHash
import co.zsmb.materialdrawerkt.builders.accountHeader
import co.zsmb.materialdrawerkt.builders.drawer
import co.zsmb.materialdrawerkt.builders.footer
import co.zsmb.materialdrawerkt.draweritems.badgeable.primaryItem
import co.zsmb.materialdrawerkt.draweritems.profile.profile
import com.anupcowkur.reservoir.Reservoir import com.anupcowkur.reservoir.Reservoir
import com.anupcowkur.reservoir.ReservoirGetCallback import com.anupcowkur.reservoir.ReservoirGetCallback
import com.anupcowkur.reservoir.ReservoirPutCallback import com.anupcowkur.reservoir.ReservoirPutCallback
@ -51,7 +52,6 @@ import com.crashlytics.android.Crashlytics
import com.crashlytics.android.answers.Answers import com.crashlytics.android.answers.Answers
import com.crashlytics.android.answers.InviteEvent import com.crashlytics.android.answers.InviteEvent
import com.ftinc.scoop.Scoop import com.ftinc.scoop.Scoop
import com.github.stkent.amplify.prompt.DefaultLayoutPromptView
import com.github.stkent.amplify.tracking.Amplify import com.github.stkent.amplify.tracking.Amplify
import com.google.android.gms.appinvite.AppInviteInvitation import com.google.android.gms.appinvite.AppInviteInvitation
import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.ConnectionResult
@ -61,20 +61,15 @@ import com.google.gson.reflect.TypeToken
import com.heinrichreimersoftware.androidissuereporter.IssueReporterLauncher import com.heinrichreimersoftware.androidissuereporter.IssueReporterLauncher
import com.mikepenz.aboutlibraries.Libs import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.LibsBuilder import com.mikepenz.aboutlibraries.LibsBuilder
import com.mikepenz.materialdrawer.AccountHeader
import com.mikepenz.materialdrawer.AccountHeaderBuilder
import com.mikepenz.materialdrawer.Drawer import com.mikepenz.materialdrawer.Drawer
import com.mikepenz.materialdrawer.DrawerBuilder
import com.mikepenz.materialdrawer.holder.BadgeStyle import com.mikepenz.materialdrawer.holder.BadgeStyle
import com.mikepenz.materialdrawer.model.DividerDrawerItem import com.mikepenz.materialdrawer.model.DividerDrawerItem
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
import com.mikepenz.materialdrawer.model.ProfileDrawerItem
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem import com.mikepenz.materialdrawer.model.SecondaryDrawerItem
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import java.lang.Exception import kotlinx.android.synthetic.main.activity_home.*
class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
@ -106,15 +101,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
private var displayAccountHeader: Boolean = false private var displayAccountHeader: Boolean = false
private var infiniteScroll: Boolean = false private var infiniteScroll: Boolean = false
private lateinit var emptyText: TextView
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 tabNewBadge: TextBadgeItem
private lateinit var tabArchiveBadge: TextBadgeItem private lateinit var tabArchiveBadge: TextBadgeItem
private lateinit var tabStarredBadge: TextBadgeItem private lateinit var tabStarredBadge: TextBadgeItem
private lateinit var toolbar: Toolbar
private lateinit var drawer: Drawer private lateinit var drawer: Drawer
private lateinit var api: SelfossApi private lateinit var api: SelfossApi
private lateinit var customTabActivityHelper: CustomTabActivityHelper private lateinit var customTabActivityHelper: CustomTabActivityHelper
@ -127,6 +116,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
private var recyclerViewScrollListener: RecyclerView.OnScrollListener? = null private var recyclerViewScrollListener: RecyclerView.OnScrollListener? = null
private lateinit var settings: SharedPreferences private lateinit var settings: SharedPreferences
private var badgeNew: Int = -1
private var badgeAll: Int = -1
private var badgeFavs: Int = -1
@ -141,16 +134,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
Scoop.getInstance().apply(this) Scoop.getInstance().apply(this)
setContentView(R.layout.activity_home) setContentView(R.layout.activity_home)
toolbar = findViewById(R.id.toolbar) setSupportActionBar(toolBar)
setSupportActionBar(toolbar)
if (savedInstanceState == null) { if (savedInstanceState == null) {
val promptView: DefaultLayoutPromptView = findViewById(R.id.prompt_view)
Amplify.getSharedInstance().promptIfReady(promptView) Amplify.getSharedInstance().promptIfReady(promptView)
} }
@ -168,122 +156,114 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
appColors = AppColors(this@HomeActivity) appColors = AppColors(this@HomeActivity)
handleBottomBar() handleBottomBar()
handleDrawer() handleDrawer()
coordinatorLayout = findViewById(R.id.coordLayout)
swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout)
recyclerView = findViewById(R.id.my_recycler_view)
emptyText = findViewById(R.id.emptyText)
reloadLayoutManager() reloadLayoutManager()
handleSwipeRefreshLayout() handleSwipeRefreshLayout()
} }
private fun handleSwipeRefreshLayout() { private fun handleSwipeRefreshLayout() {
swipeRefreshLayout.setColorSchemeResources( swipeRefreshLayout.setColorSchemeResources(
R.color.refresh_progress_1, R.color.refresh_progress_1,
R.color.refresh_progress_2, R.color.refresh_progress_2,
R.color.refresh_progress_3) R.color.refresh_progress_3)
swipeRefreshLayout.setOnRefreshListener { swipeRefreshLayout.setOnRefreshListener {
handleDrawerItems() handleDrawerItems()
getElementsAccordingToTab() getElementsAccordingToTab()
} }
val simpleItemTouchCallback = val simpleItemTouchCallback =
object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) { object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
override fun getSwipeDirs(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?): Int = override fun getSwipeDirs(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?): Int =
if (elementsShown != UNREAD_SHOWN) 0 else super.getSwipeDirs(recyclerView, viewHolder) if (elementsShown != UNREAD_SHOWN) 0 else super.getSwipeDirs(recyclerView, viewHolder)
override fun onMove(recyclerView: RecyclerView, override fun onMove(recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder, viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder): Boolean = false target: RecyclerView.ViewHolder): Boolean = false
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, swipeDir: Int) { override fun onSwiped(viewHolder: RecyclerView.ViewHolder, swipeDir: Int) {
try { try {
val i = items[viewHolder.adapterPosition] val i = items[viewHolder.adapterPosition]
val position = items.indexOf(i) val position = items.indexOf(i)
val adapter = recyclerView.adapter val adapter = recyclerView.adapter
when (adapter) { when (adapter) {
is ItemCardAdapter -> adapter.removeItemAtIndex(position) is ItemCardAdapter -> adapter.removeItemAtIndex(position)
is ItemListAdapter -> adapter.removeItemAtIndex(position) is ItemListAdapter -> adapter.removeItemAtIndex(position)
}
if (items.size > 0) {
badgeNew--
reloadBadgeContent()
}
else
tabNewBadge.hide()
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 && items.size <= maxItemNumber() && maxItemNumber() >= itemsNumber) {
getElementsAccordingToTab(appendResults = true, offsetOverride = lastVisibleItem)
}
} catch (e: IndexOutOfBoundsException) {
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(100, "SWIPE_INDEX_OUT_OF_BOUND", "IndexOutOfBoundsException when swiping")
Crashlytics.logException(e)
} }
if (items.size > 0)
tabNewBadge.setText("${items.size}").maybeShow()
else
tabNewBadge.hide()
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)
}
} catch (e: IndexOutOfBoundsException) {
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(100, "SWIPE_INDEX_OUT_OF_BOUND", "IndexOutOfBoundsException when swiping")
Crashlytics.logException(e)
} }
} }
}
ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(recyclerView) ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(recyclerView)
} }
private fun handleBottomBar() { private fun handleBottomBar() {
bottomBar = findViewById(R.id.bottomBar)
tabNewBadge = TextBadgeItem() tabNewBadge = TextBadgeItem()
.setText("") .setText("")
.setHideOnSelect(false).hide(false) .setHideOnSelect(false).hide(false)
.setBackgroundColor(appColors.primary) .setBackgroundColor(appColors.primary)
tabArchiveBadge = TextBadgeItem() tabArchiveBadge = TextBadgeItem()
.setText("") .setText("")
.setHideOnSelect(false).hide(false) .setHideOnSelect(false).hide(false)
.setBackgroundColor(appColors.primary) .setBackgroundColor(appColors.primary)
tabStarredBadge = TextBadgeItem() tabStarredBadge = TextBadgeItem()
.setText("") .setText("")
.setHideOnSelect(false).hide(false) .setHideOnSelect(false).hide(false)
.setBackgroundColor(appColors.primary) .setBackgroundColor(appColors.primary)
val tabNew = val tabNew =
BottomNavigationItem( BottomNavigationItem(
R.drawable.ic_fiber_new_black_24dp, R.drawable.ic_fiber_new_black_24dp,
getString(R.string.tab_new) getString(R.string.tab_new)
).setActiveColor(appColors.accent) ).setActiveColor(appColors.accent)
.setBadgeItem(tabNewBadge) .setBadgeItem(tabNewBadge)
val tabArchive = val tabArchive =
BottomNavigationItem( BottomNavigationItem(
R.drawable.ic_archive_black_24dp, R.drawable.ic_archive_black_24dp,
getString(R.string.tab_read) getString(R.string.tab_read)
).setActiveColor(appColors.dark) ).setActiveColor(appColors.dark)
.setBadgeItem(tabArchiveBadge) .setBadgeItem(tabArchiveBadge)
val tabStarred = val tabStarred =
BottomNavigationItem( BottomNavigationItem(
R.drawable.ic_favorite_black_24dp, R.drawable.ic_favorite_black_24dp,
getString(R.string.tab_favs) getString(R.string.tab_favs)
).setActiveColorResource(R.color.pink) ).setActiveColorResource(R.color.pink)
.setBadgeItem(tabStarredBadge) .setBadgeItem(tabStarredBadge)
bottomBar bottomBar
.addItem(tabNew) .addItem(tabNew)
.addItem(tabArchive) .addItem(tabArchive)
.addItem(tabStarred) .addItem(tabStarred)
.setFirstSelectedPosition(0) .setFirstSelectedPosition(0)
.initialise() .initialise()
bottomBar.setMode(BottomNavigationBar.MODE_SHIFTING) bottomBar.setMode(BottomNavigationBar.MODE_SHIFTING)
bottomBar.setBackgroundStyle(BottomNavigationBar.BACKGROUND_STYLE_STATIC) bottomBar.setBackgroundStyle(BottomNavigationBar.BACKGROUND_STYLE_STATIC)
@ -331,86 +311,68 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
private fun handleDrawer() { private fun handleDrawer() {
displayAccountHeader = displayAccountHeader =
PreferenceManager.getDefaultSharedPreferences(this) PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean("account_header_displaying", false) .getBoolean("account_header_displaying", false)
val headerResult: AccountHeader? = if (displayAccountHeader) {
AccountHeaderBuilder() drawer = drawer {
.withActivity(this) rootViewRes = R.id.drawer_layout
.withHeaderBackground(R.drawable.bg) toolbar = toolBar
.addProfiles( actionBarDrawerToggleEnabled = true
ProfileDrawerItem() actionBarDrawerToggleAnimated = true
.withName( showOnFirstLaunch = true
settings.getString("url", "") onSlide { _, p1 ->
bottomBar.alpha = (1 - p1)
}
onClosed {
bottomBar.show()
}
onOpened {
bottomBar.hide()
}
if (displayAccountHeader)
accountHeader {
background = R.drawable.bg
profile(settings.getString("url", "")) {
iconDrawable = resources.getDrawable(R.mipmap.ic_launcher)
}
selectionListEnabledForSingleProfile = false
}
footer {
primaryItem(R.string.drawer_report_bug) {
icon = R.drawable.ic_bug_report
iconTintingEnabled = true
onClick { _ ->
IssueReporterLauncher.forTarget(getString(R.string.report_github_user), getString(R.string.report_github_repo))
.theme(R.style.Theme_App_Light)
.guestToken(BuildConfig.GITHUB_TOKEN)
.guestEmailRequired(true)
.minDescriptionLength(20)
.putExtraInfo("Unique ID", settings.getString("unique_id", ""))
.putExtraInfo("From github", BuildConfig.GITHUB_VERSION)
.homeAsUpEnabled(true)
.launch(this@HomeActivity)
false
}
}
primaryItem(R.string.title_activity_settings) {
icon = R.drawable.ic_settings
iconTintingEnabled = true
onClick { _ ->
startActivityForResult(
Intent(
this@HomeActivity,
SettingsActivity::class.java
),
MENU_PREFERENCES
) )
.withIcon(resources.getDrawable(R.mipmap.ic_launcher)) false
)
.withSelectionListEnabledForSingleProfile(false)
.build()
} else null
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?) {
bottomBar.show()
}
override fun onDrawerOpened(v: View?) {
bottomBar.hide()
}
})
if (displayAccountHeader && headerResult != null)
drawerBuilder.withAccountHeader(headerResult)
drawer = drawerBuilder.build()
drawer.addStickyFooterItem(
PrimaryDrawerItem()
.withName(R.string.drawer_report_bug)
.withIcon(R.drawable.ic_bug_report)
.withIconTintingEnabled(true)
.withOnDrawerItemClickListener { _, _, _ ->
IssueReporterLauncher.forTarget(getString(R.string.report_github_user), getString(R.string.report_github_repo))
.theme(R.style.Theme_App_Light)
.guestToken(BuildConfig.GITHUB_TOKEN)
.guestEmailRequired(true)
.minDescriptionLength(20)
.putExtraInfo("Unique ID", settings.getString("unique_id", ""))
.putExtraInfo("From github", BuildConfig.GITHUB_VERSION)
.homeAsUpEnabled(true)
.launch(this)
false
} }
) }
}
drawer.addStickyFooterItem(
PrimaryDrawerItem()
.withName(R.string.title_activity_settings)
.withIcon(R.drawable.ic_settings)
.withIconTintingEnabled(true)
.withOnDrawerItemClickListener { _, _, _ ->
startActivityForResult(
Intent(
this@HomeActivity,
SettingsActivity::class.java
),
MENU_PREFERENCES
)
false
}
)
} }
@ -419,10 +381,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
fun handleTags(maybeTags: List<Tag>?) { fun handleTags(maybeTags: List<Tag>?) {
if (maybeTags == null) { if (maybeTags == null) {
if (loadedFromCache) if (loadedFromCache)
drawer.addItem( drawer.addItem(
SecondaryDrawerItem() SecondaryDrawerItem()
.withName(getString(R.string.drawer_error_loading_tags)) .withName(getString(R.string.drawer_error_loading_tags))
.withSelectable(false)) .withSelectable(false))
} }
else { else {
for (tag in maybeTags) { for (tag in maybeTags) {
@ -432,20 +395,20 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
gd.setSize(30, 30) gd.setSize(30, 30)
gd.cornerRadius = 30F gd.cornerRadius = 30F
drawer.addItem( drawer.addItem(
PrimaryDrawerItem() PrimaryDrawerItem()
.withName(tag.tag) .withName(tag.tag)
.withIdentifier(tag.tag.longHash()) .withIdentifier(tag.tag.longHash())
.withIcon(gd) .withIcon(gd)
.withBadge("${tag.unread}") .withBadge("${tag.unread}")
.withBadgeStyle( .withBadgeStyle(
BadgeStyle().withTextColor(Color.WHITE) BadgeStyle().withTextColor(Color.WHITE)
.withColor(appColors.accent) .withColor(appColors.accent)
) )
.withOnDrawerItemClickListener { _, _, _ -> .withOnDrawerItemClickListener { _, _, _ ->
maybeTagFilter = tag maybeTagFilter = tag
getElementsAccordingToTab() getElementsAccordingToTab()
false false
} }
) )
} }
} }
@ -456,22 +419,22 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
if (maybeSources == null) { if (maybeSources == null) {
if (loadedFromCache) if (loadedFromCache)
drawer.addItem( drawer.addItem(
SecondaryDrawerItem() SecondaryDrawerItem()
.withName(getString(R.string.drawer_error_loading_sources)) .withName(getString(R.string.drawer_error_loading_sources))
.withSelectable(false)) .withSelectable(false))
} }
else else
for (tag in maybeSources) for (tag in maybeSources)
drawer.addItem( drawer.addItem(
CustomUrlPrimaryDrawerItem() CustomUrlPrimaryDrawerItem()
.withName(tag.title) .withName(tag.title)
.withIdentifier(tag.id.toLong()) .withIdentifier(tag.id.toLong())
.withIcon(tag.getIcon(this@HomeActivity)) .withIcon(tag.getIcon(this@HomeActivity))
.withOnDrawerItemClickListener { _, _, _ -> .withOnDrawerItemClickListener { _, _, _ ->
maybeSourceFilter = tag maybeSourceFilter = tag
getElementsAccordingToTab() getElementsAccordingToTab()
false false
} }
) )
} }
@ -479,58 +442,58 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
drawer.removeAllItems() drawer.removeAllItems()
if (maybeDrawerData != null) { if (maybeDrawerData != null) {
drawer.addItem( drawer.addItem(
SecondaryDrawerItem() SecondaryDrawerItem()
.withName(getString(R.string.drawer_item_filters)) .withName(getString(R.string.drawer_item_filters))
.withSelectable(false) .withSelectable(false)
.withIdentifier(DRAWER_ID_FILTERS) .withIdentifier(DRAWER_ID_FILTERS)
.withBadge(getString(R.string.drawer_action_clear)) .withBadge(getString(R.string.drawer_action_clear))
.withOnDrawerItemClickListener { _, _, _ -> .withOnDrawerItemClickListener { _, _, _ ->
maybeSourceFilter = null maybeSourceFilter = null
maybeTagFilter = null maybeTagFilter = null
getElementsAccordingToTab() getElementsAccordingToTab()
false false
} }
) )
drawer.addItem(DividerDrawerItem()) drawer.addItem(DividerDrawerItem())
drawer.addItem( drawer.addItem(
SecondaryDrawerItem() SecondaryDrawerItem()
.withName(getString(R.string.drawer_item_tags)) .withName(getString(R.string.drawer_item_tags))
.withIdentifier(DRAWER_ID_TAGS) .withIdentifier(DRAWER_ID_TAGS)
.withSelectable(false)) .withSelectable(false))
handleTags(maybeDrawerData.tags) handleTags(maybeDrawerData.tags)
drawer.addItem(DividerDrawerItem()) drawer.addItem(DividerDrawerItem())
drawer.addItem( drawer.addItem(
SecondaryDrawerItem() SecondaryDrawerItem()
.withName(getString(R.string.drawer_item_sources)) .withName(getString(R.string.drawer_item_sources))
.withIdentifier(DRAWER_ID_TAGS) .withIdentifier(DRAWER_ID_TAGS)
.withBadge(getString(R.string.drawer_action_edit)) .withBadge(getString(R.string.drawer_action_edit))
.withSelectable(false) .withSelectable(false)
.withOnDrawerItemClickListener { _, _, _ -> .withOnDrawerItemClickListener { _, _, _ ->
startActivity(Intent(this, SourcesActivity::class.java)) startActivity(Intent(this, SourcesActivity::class.java))
false false
} }
) )
handleSources(maybeDrawerData.sources) handleSources(maybeDrawerData.sources)
drawer.addItem(DividerDrawerItem()) drawer.addItem(DividerDrawerItem())
drawer.addItem( drawer.addItem(
PrimaryDrawerItem() PrimaryDrawerItem()
.withName(R.string.action_about) .withName(R.string.action_about)
.withSelectable(false) .withSelectable(false)
.withIcon(R.drawable.ic_info_outline) .withIcon(R.drawable.ic_info_outline)
.withIconTintingEnabled(true) .withIconTintingEnabled(true)
.withOnDrawerItemClickListener { _, _, _ -> .withOnDrawerItemClickListener { _, _, _ ->
LibsBuilder() LibsBuilder()
.withActivityStyle( .withActivityStyle(
if (appColors.isDarkTheme) if (appColors.isDarkTheme)
Libs.ActivityStyle.LIGHT_DARK_TOOLBAR Libs.ActivityStyle.LIGHT_DARK_TOOLBAR
else else
Libs.ActivityStyle.DARK Libs.ActivityStyle.DARK
) )
.withAboutIconShown(true) .withAboutIconShown(true)
.withAboutVersionShown(true) .withAboutVersionShown(true)
.start(this@HomeActivity) .start(this@HomeActivity)
false false
}) })
if (!loadedFromCache) if (!loadedFromCache)
@ -544,15 +507,15 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
} else { } else {
if (!loadedFromCache) { if (!loadedFromCache) {
drawer.addItem( drawer.addItem(
PrimaryDrawerItem() PrimaryDrawerItem()
.withName(getString(R.string.no_tags_loaded)) .withName(getString(R.string.no_tags_loaded))
.withIdentifier(DRAWER_ID_TAGS) .withIdentifier(DRAWER_ID_TAGS)
.withSelectable(false)) .withSelectable(false))
drawer.addItem( drawer.addItem(
PrimaryDrawerItem() PrimaryDrawerItem()
.withName(getString(R.string.no_sources_loaded)) .withName(getString(R.string.no_sources_loaded))
.withIdentifier(DRAWER_ID_SOURCES) .withIdentifier(DRAWER_ID_SOURCES)
.withSelectable(false)) .withSelectable(false))
} }
} }
@ -631,29 +594,29 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
override fun onTabUnselected(position: Int) = Unit override fun onTabUnselected(position: Int) = Unit
override fun onTabReselected(position: Int) = override fun onTabReselected(position: Int) =
when (mLayoutManager) { when (mLayoutManager) {
is StaggeredGridLayoutManager -> is StaggeredGridLayoutManager ->
if (mLayoutManager.findFirstCompletelyVisibleItemPositions(null)[0] == 0) { if (mLayoutManager.findFirstCompletelyVisibleItemPositions(null)[0] == 0) {
getElementsAccordingToTab() getElementsAccordingToTab()
} else { } else {
mLayoutManager.scrollToPositionWithOffset(0, 0) mLayoutManager.scrollToPositionWithOffset(0, 0)
} }
is GridLayoutManager -> is GridLayoutManager ->
if (mLayoutManager.findFirstCompletelyVisibleItemPosition() == 0) { if (mLayoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
getElementsAccordingToTab() getElementsAccordingToTab()
} else { } else {
mLayoutManager.scrollToPositionWithOffset(0, 0) mLayoutManager.scrollToPositionWithOffset(0, 0)
} }
else -> Unit else -> Unit
} }
override fun onTabSelected(position: Int) = override fun onTabSelected(position: Int) =
when (position) { when (position) {
0 -> getUnRead() 0 -> getUnRead()
1 -> getRead() 1 -> getRead()
2 -> getStarred() 2 -> getStarred()
else -> Unit else -> Unit
} }
}) })
} }
@ -670,7 +633,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
else -> 0 else -> 0
} }
if (lastVisibleItem == (items.size - 1)) { if (lastVisibleItem == (items.size - 1) && items.size < maxItemNumber()) {
getElementsAccordingToTab(appendResults = true) getElementsAccordingToTab(appendResults = true)
} }
} }
@ -681,22 +644,30 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
recyclerView.addOnScrollListener(recyclerViewScrollListener) recyclerView.addOnScrollListener(recyclerViewScrollListener)
} }
fun mayBeEmpty() = private fun mayBeEmpty() =
if (items.isEmpty()) { if (items.isEmpty()) {
emptyText.visibility = View.VISIBLE emptyText.visibility = View.VISIBLE
recyclerView.visibility = View.GONE recyclerView.visibility = View.GONE
} else { } else {
emptyText.visibility = View.GONE emptyText.visibility = View.GONE
recyclerView.visibility = View.VISIBLE recyclerView.visibility = View.VISIBLE
} }
private fun getElementsAccordingToTab(appendResults: Boolean = false, offsetOverride: Int? = null) {
offset = if (appendResults && offsetOverride === null) {
(offset + itemsNumber)
} else {
offsetOverride ?: 0
}
firstVisible = if (appendResults) firstVisible else 0
private fun getElementsAccordingToTab(appendResults: Boolean = false) =
when (elementsShown) { when (elementsShown) {
UNREAD_SHOWN -> getUnRead(appendResults) UNREAD_SHOWN -> getUnRead(appendResults)
READ_SHOWN -> getRead(appendResults) READ_SHOWN -> getRead(appendResults)
FAV_SHOWN -> getStarred(appendResults) FAV_SHOWN -> getStarred(appendResults)
else -> getUnRead(appendResults) else -> getUnRead(appendResults)
} }
}
private fun doCallTo(appendResults: Boolean, toastMessage: Int, call: (String?, Long?, String?) -> Call<List<Item>>) { private fun doCallTo(appendResults: Boolean, toastMessage: Int, call: (String?, Long?, String?) -> Call<List<Item>>) {
fun handleItemsResponse(response: Response<List<Item>>) { fun handleItemsResponse(response: Response<List<Item>>) {
@ -723,38 +694,29 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
swipeRefreshLayout.post { swipeRefreshLayout.isRefreshing = true } swipeRefreshLayout.post { swipeRefreshLayout.isRefreshing = true }
call(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong(), maybeSearchFilter) call(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong(), maybeSearchFilter)
.enqueue(object : Callback<List<Item>> { .enqueue(object : Callback<List<Item>> {
override fun onResponse(call: Call<List<Item>>, response: Response<List<Item>>) { override fun onResponse(call: Call<List<Item>>, response: Response<List<Item>>) {
handleItemsResponse(response) handleItemsResponse(response)
} }
override fun onFailure(call: Call<List<Item>>, t: Throwable) { override fun onFailure(call: Call<List<Item>>, t: Throwable) {
swipeRefreshLayout.isRefreshing = false swipeRefreshLayout.isRefreshing = false
Toast.makeText(this@HomeActivity, toastMessage, Toast.LENGTH_SHORT).show() Toast.makeText(this@HomeActivity, toastMessage, Toast.LENGTH_SHORT).show()
} }
}) })
} }
private fun getUnRead(appendResults: Boolean = false) { private fun getUnRead(appendResults: Boolean = false) {
offset = if (appendResults) (offset + itemsNumber)
else 0
firstVisible = if (appendResults) firstVisible else 0
elementsShown = UNREAD_SHOWN elementsShown = UNREAD_SHOWN
doCallTo(appendResults, R.string.cant_get_new_elements){t, id, f -> api.newItems(t, id, f, itemsNumber, offset)} doCallTo(appendResults, R.string.cant_get_new_elements){t, id, f -> api.newItems(t, id, f, itemsNumber, offset)}
} }
private fun getRead(appendResults: Boolean = false) { private fun getRead(appendResults: Boolean = false) {
offset = if (appendResults) (offset + itemsNumber)
else 0
firstVisible = if (appendResults) firstVisible else 0
elementsShown = READ_SHOWN elementsShown = READ_SHOWN
doCallTo(appendResults, R.string.cant_get_read){t, id, f -> api.readItems(t, id, f, itemsNumber, offset)} doCallTo(appendResults, R.string.cant_get_read){t, id, f -> api.readItems(t, id, f, itemsNumber, offset)}
} }
private fun getStarred(appendResults: Boolean = false) { private fun getStarred(appendResults: Boolean = false) {
offset = if (appendResults) (offset + itemsNumber)
else 0
firstVisible = if (appendResults) firstVisible else 0
elementsShown = FAV_SHOWN elementsShown = FAV_SHOWN
doCallTo(appendResults, R.string.cant_get_favs){t, id, f -> api.starredItems(t, id, f, itemsNumber, offset)} doCallTo(appendResults, R.string.cant_get_favs){t, id, f -> api.starredItems(t, id, f, itemsNumber, offset)}
} }
@ -774,29 +736,29 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
val mAdapter: RecyclerView.Adapter<*> val mAdapter: RecyclerView.Adapter<*>
if (shouldBeCardView) { if (shouldBeCardView) {
mAdapter = mAdapter =
ItemCardAdapter( ItemCardAdapter(
this, this,
items, items,
api, api,
customTabActivityHelper, customTabActivityHelper,
internalBrowser, internalBrowser,
articleViewer, articleViewer,
fullHeightCards, fullHeightCards,
appColors, appColors,
debugReadingItems, debugReadingItems,
userIdentifier) userIdentifier)
} else { } else {
mAdapter = mAdapter =
ItemListAdapter( ItemListAdapter(
this, this,
items, items,
api, api,
customTabActivityHelper, customTabActivityHelper,
clickBehavior, clickBehavior,
internalBrowser, internalBrowser,
articleViewer, articleViewer,
debugReadingItems, debugReadingItems,
userIdentifier) userIdentifier)
} }
recyclerView.adapter = mAdapter recyclerView.adapter = mAdapter
mAdapter.notifyDataSetChanged() mAdapter.notifyDataSetChanged()
@ -813,26 +775,38 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
api.stats.enqueue(object : Callback<Stats> { api.stats.enqueue(object : Callback<Stats> {
override fun onResponse(call: Call<Stats>, response: Response<Stats>) { override fun onResponse(call: Call<Stats>, response: Response<Stats>) {
if (response.body() != null) { if (response.body() != null) {
if (displayUnreadCount)
tabNewBadge badgeNew = response.body()!!.unread
.setText(response.body()!!.unread.toString()) badgeAll = response.body()!!.total
.maybeShow() badgeFavs = response.body()!!.starred
if (displayAllCount) { reloadBadgeContent()
tabArchiveBadge
.setText(response.body()!!.total.toString())
.maybeShow()
tabStarredBadge
.setText(response.body()!!.starred.toString())
.maybeShow()
} else {
tabArchiveBadge.removeBadge()
tabStarredBadge.removeBadge()
}
} }
} }
override fun onFailure(call: Call<Stats>, t: Throwable) {} override fun onFailure(call: Call<Stats>, t: Throwable) {}
}) })
} else {
reloadBadgeContent(succeeded = false)
}
}
private fun reloadBadgeContent(succeeded: Boolean = true) {
if (succeeded) {
if (displayUnreadCount)
tabNewBadge
.setText(badgeNew.toString())
.maybeShow()
if (displayAllCount) {
tabArchiveBadge
.setText(badgeAll.toString())
.maybeShow()
tabStarredBadge
.setText(badgeFavs.toString())
.maybeShow()
} else {
tabArchiveBadge.removeBadge()
tabStarredBadge.removeBadge()
}
} else { } else {
tabNewBadge.removeBadge() tabNewBadge.removeBadge()
tabArchiveBadge.removeBadge() tabArchiveBadge.removeBadge()
@ -895,8 +869,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
api.update().enqueue(object : Callback<String> { api.update().enqueue(object : Callback<String> {
override fun onResponse(call: Call<String>, response: Response<String>) { override fun onResponse(call: Call<String>, response: Response<String>) {
Toast.makeText(this@HomeActivity, Toast.makeText(this@HomeActivity,
R.string.refresh_success_response, Toast.LENGTH_LONG) R.string.refresh_success_response, Toast.LENGTH_LONG)
.show() .show()
} }
override fun onFailure(call: Call<String>, t: Throwable) { override fun onFailure(call: Call<String>, t: Throwable) {
@ -941,17 +915,17 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
R.id.action_share_the_app -> { R.id.action_share_the_app -> {
if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) { if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
val share = AppInviteInvitation.IntentBuilder(getString(R.string.invitation_title)) val share = AppInviteInvitation.IntentBuilder(getString(R.string.invitation_title))
.setMessage(getString(R.string.invitation_message)) .setMessage(getString(R.string.invitation_message))
.setDeepLink(Uri.parse("https://ymbh5.app.goo.gl/qbvQ")) .setDeepLink(Uri.parse("https://ymbh5.app.goo.gl/qbvQ"))
.setCallToActionText(getString(R.string.invitation_cta)) .setCallToActionText(getString(R.string.invitation_cta))
.build() .build()
startActivityForResult(share, REQUEST_INVITE) startActivityForResult(share, REQUEST_INVITE)
} else { } else {
val sendIntent = Intent() val sendIntent = Intent()
sendIntent.action = Intent.ACTION_SEND sendIntent.action = Intent.ACTION_SEND
sendIntent.putExtra( sendIntent.putExtra(
Intent.EXTRA_TEXT, Intent.EXTRA_TEXT,
getString(R.string.invitation_message) + " https://ymbh5.app.goo.gl/qbvQ" getString(R.string.invitation_message) + " https://ymbh5.app.goo.gl/qbvQ"
) )
sendIntent.type = "text/plain" sendIntent.type = "text/plain"
startActivityForResult(sendIntent, REQUEST_INVITE_BYMAIL) startActivityForResult(sendIntent, REQUEST_INVITE_BYMAIL)
@ -961,4 +935,12 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
else -> return super.onOptionsItemSelected(item) else -> return super.onOptionsItemSelected(item)
} }
} }
private fun maxItemNumber(): Int =
when (elementsShown) {
UNREAD_SHOWN -> badgeNew
READ_SHOWN -> badgeAll
FAV_SHOWN -> badgeFavs
else -> badgeNew // if !elementsShown then unread are fetched.
}
} }

View File

@ -6,7 +6,6 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.support.design.widget.TextInputLayout
import android.support.v7.app.AlertDialog import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar import android.support.v7.widget.Toolbar
@ -15,9 +14,6 @@ import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.Button
import android.widget.EditText
import android.widget.Switch
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
@ -32,6 +28,8 @@ import com.mikepenz.aboutlibraries.LibsBuilder
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import kotlinx.android.synthetic.main.activity_login.*
class LoginActivity : AppCompatActivity() { class LoginActivity : AppCompatActivity() {
@ -43,14 +41,7 @@ class LoginActivity : AppCompatActivity() {
private lateinit var settings: SharedPreferences private lateinit var settings: SharedPreferences
private lateinit var editor: SharedPreferences.Editor private lateinit var editor: SharedPreferences.Editor
private lateinit var mFirebaseAnalytics: FirebaseAnalytics private lateinit var firebaseAnalytics: FirebaseAnalytics
private lateinit var mUrlView: EditText
private lateinit var mLoginView: TextView
private lateinit var mHTTPLoginView: TextView
private lateinit var mProgressView: View
private lateinit var mPasswordView: EditText
private lateinit var mHTTPPasswordView: EditText
private lateinit var mLoginFormView: View
private lateinit var userIdentifier: String private lateinit var userIdentifier: String
private var logErrors: Boolean = false private var logErrors: Boolean = false
@ -61,7 +52,6 @@ class LoginActivity : AppCompatActivity() {
Scoop.getInstance().apply(this) Scoop.getInstance().apply(this)
setContentView(R.layout.activity_login) setContentView(R.layout.activity_login)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
handleBaseUrlFail() handleBaseUrlFail()
@ -69,7 +59,7 @@ class LoginActivity : AppCompatActivity() {
settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE) settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
userIdentifier = settings.getString("unique_id", "") userIdentifier = settings.getString("unique_id", "")
logErrors = settings.getBoolean("loging_debug", false) logErrors = settings.getBoolean("login_debug", false)
editor = settings.edit() editor = settings.edit()
@ -77,60 +67,44 @@ class LoginActivity : AppCompatActivity() {
goToMain() goToMain()
} }
mFirebaseAnalytics = FirebaseAnalytics.getInstance(this) firebaseAnalytics = FirebaseAnalytics.getInstance(this)
mUrlView = findViewById(R.id.url)
mLoginView = findViewById(R.id.login)
mHTTPLoginView = findViewById(R.id.httpLogin)
mPasswordView = findViewById(R.id.password)
mHTTPPasswordView = findViewById(R.id.httpPassword)
mLoginFormView = findViewById(R.id.login_form)
mProgressView = findViewById(R.id.login_progress)
handleActions() handleActions()
} }
private fun handleActions() { private fun handleActions() {
val mSwitch: Switch = findViewById(R.id.withLogin)
val mHTTPSwitch: Switch = findViewById(R.id.withHttpLogin)
val mLoginLayout: TextInputLayout = findViewById(R.id.loginLayout)
val mHTTPLoginLayout: TextInputLayout = findViewById(R.id.httpLoginInput)
val mPasswordLayout: TextInputLayout = findViewById(R.id.passwordLayout)
val mHTTPPasswordLayout: TextInputLayout = findViewById(R.id.httpPasswordInput)
val mEmailSignInButton: Button = findViewById(R.id.email_sign_in_button)
val selfHostedSwitch: Switch = findViewById(R.id.withSelfhostedCert)
val warningTextview: TextView = findViewById(R.id.warningText)
selfHostedSwitch.setOnCheckedChangeListener { _, b -> withSelfhostedCert.setOnCheckedChangeListener { _, b ->
isWithSelfSignedCert = !isWithSelfSignedCert isWithSelfSignedCert = !isWithSelfSignedCert
val visi: Int = if (b) View.VISIBLE else View.GONE val visi: Int = if (b) View.VISIBLE else View.GONE
warningTextview.visibility = visi warningText.visibility = visi
} }
mPasswordView.setOnEditorActionListener(TextView.OnEditorActionListener { _, id, _ -> passwordView.setOnEditorActionListener(TextView.OnEditorActionListener { _, id, _ ->
if (id == R.id.login || id == EditorInfo.IME_NULL) { if (id == R.id.loginView || id == EditorInfo.IME_NULL) {
attemptLogin() attemptLogin()
return@OnEditorActionListener true return@OnEditorActionListener true
} }
false false
}) })
mEmailSignInButton.setOnClickListener { attemptLogin() } signInButton.setOnClickListener { attemptLogin() }
mSwitch.setOnCheckedChangeListener { _, b -> withLogin.setOnCheckedChangeListener { _, b ->
isWithLogin = !isWithLogin isWithLogin = !isWithLogin
val visi: Int = if (b) View.VISIBLE else View.GONE val visi: Int = if (b) View.VISIBLE else View.GONE
mLoginLayout.visibility = visi loginLayout.visibility = visi
mPasswordLayout.visibility = visi passwordLayout.visibility = visi
} }
mHTTPSwitch.setOnCheckedChangeListener { _, b -> withHttpLogin.setOnCheckedChangeListener { _, b ->
isWithHTTPLogin = !isWithHTTPLogin isWithHTTPLogin = !isWithHTTPLogin
val visi: Int = if (b) View.VISIBLE else View.GONE val visi: Int = if (b) View.VISIBLE else View.GONE
mHTTPLoginLayout.visibility = visi httpLoginInput.visibility = visi
mHTTPPasswordLayout.visibility = visi httpPasswordInput.visibility = visi
} }
} }
@ -140,9 +114,9 @@ class LoginActivity : AppCompatActivity() {
alertDialog.setTitle(getString(R.string.warning_wrong_url)) alertDialog.setTitle(getString(R.string.warning_wrong_url))
alertDialog.setMessage(getString(R.string.base_url_error)) alertDialog.setMessage(getString(R.string.base_url_error))
alertDialog.setButton( alertDialog.setButton(
AlertDialog.BUTTON_NEUTRAL, AlertDialog.BUTTON_NEUTRAL,
"OK", "OK",
{ dialog, _ -> dialog.dismiss() }) { dialog, _ -> dialog.dismiss() })
alertDialog.show() alertDialog.show()
} }
} }
@ -156,25 +130,25 @@ class LoginActivity : AppCompatActivity() {
private fun attemptLogin() { private fun attemptLogin() {
// Reset errors. // Reset errors.
mUrlView.error = null urlView.error = null
mLoginView.error = null loginView.error = null
mHTTPLoginView.error = null httpLoginView.error = null
mPasswordView.error = null passwordView.error = null
mHTTPPasswordView.error = null httpPasswordView.error = null
// Store values at the time of the login attempt. // Store values at the time of the login attempt.
val url = mUrlView.text.toString() val url = urlView.text.toString()
val login = mLoginView.text.toString() val login = loginView.text.toString()
val httpLogin = mHTTPLoginView.text.toString() val httpLogin = httpLoginView.text.toString()
val password = mPasswordView.text.toString() val password = passwordView.text.toString()
val httpPassword = mHTTPPasswordView.text.toString() val httpPassword = httpPasswordView.text.toString()
var cancel = false var cancel = false
var focusView: View? = null var focusView: View? = null
if (!url.isBaseUrlValid()) { if (!url.isBaseUrlValid()) {
mUrlView.error = getString(R.string.login_url_problem) urlView.error = getString(R.string.login_url_problem)
focusView = mUrlView focusView = urlView
cancel = true cancel = true
inValidCount++ inValidCount++
if (inValidCount == 3) { if (inValidCount == 3) {
@ -182,9 +156,9 @@ class LoginActivity : AppCompatActivity() {
alertDialog.setTitle(getString(R.string.warning_wrong_url)) alertDialog.setTitle(getString(R.string.warning_wrong_url))
alertDialog.setMessage(getString(R.string.text_wrong_url)) alertDialog.setMessage(getString(R.string.text_wrong_url))
alertDialog.setButton( alertDialog.setButton(
AlertDialog.BUTTON_NEUTRAL, AlertDialog.BUTTON_NEUTRAL,
"OK", "OK",
{ dialog, _ -> dialog.dismiss() }) { dialog, _ -> dialog.dismiss() })
alertDialog.show() alertDialog.show()
inValidCount = 0 inValidCount = 0
} }
@ -192,14 +166,14 @@ class LoginActivity : AppCompatActivity() {
if (isWithLogin || isWithHTTPLogin) { if (isWithLogin || isWithHTTPLogin) {
if (TextUtils.isEmpty(password)) { if (TextUtils.isEmpty(password)) {
mPasswordView.error = getString(R.string.error_invalid_password) passwordView.error = getString(R.string.error_invalid_password)
focusView = mPasswordView focusView = passwordView
cancel = true cancel = true
} }
if (TextUtils.isEmpty(login)) { if (TextUtils.isEmpty(login)) {
mLoginView.error = getString(R.string.error_field_required) loginView.error = getString(R.string.error_field_required)
focusView = mLoginView focusView = loginView
cancel = true cancel = true
} }
} }
@ -226,11 +200,11 @@ class LoginActivity : AppCompatActivity() {
editor.remove("password") editor.remove("password")
editor.remove("httpPassword") editor.remove("httpPassword")
editor.apply() editor.apply()
mUrlView.error = getString(R.string.wrong_infos) urlView.error = getString(R.string.wrong_infos)
mLoginView.error = getString(R.string.wrong_infos) loginView.error = getString(R.string.wrong_infos)
mPasswordView.error = getString(R.string.wrong_infos) passwordView.error = getString(R.string.wrong_infos)
mHTTPLoginView.error = getString(R.string.wrong_infos) httpLoginView.error = getString(R.string.wrong_infos)
mHTTPPasswordView.error = getString(R.string.wrong_infos) httpPasswordView.error = getString(R.string.wrong_infos)
if (logErrors) { if (logErrors) {
Crashlytics.setUserIdentifier(userIdentifier) Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(100, "LOGIN_DEBUG_ERRROR", t.message) Crashlytics.log(100, "LOGIN_DEBUG_ERRROR", t.message)
@ -242,7 +216,7 @@ class LoginActivity : AppCompatActivity() {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) { override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
if (response.body() != null && response.body()!!.isSuccess) { if (response.body() != null && response.body()!!.isSuccess) {
mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle()) firebaseAnalytics.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle())
goToMain() goToMain()
} else { } else {
preferenceError(Exception("No response body...")) preferenceError(Exception("No response body..."))
@ -260,34 +234,34 @@ class LoginActivity : AppCompatActivity() {
private fun showProgress(show: Boolean) { private fun showProgress(show: Boolean) {
val shortAnimTime = resources.getInteger(android.R.integer.config_shortAnimTime) val shortAnimTime = resources.getInteger(android.R.integer.config_shortAnimTime)
mLoginFormView.visibility = if (show) View.GONE else View.VISIBLE loginForm.visibility = if (show) View.GONE else View.VISIBLE
mLoginFormView loginForm
.animate() .animate()
.setDuration(shortAnimTime.toLong()) .setDuration(shortAnimTime.toLong())
.alpha( .alpha(
if (show) 0F else 1F if (show) 0F else 1F
).setListener(object : AnimatorListenerAdapter() { ).setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) { override fun onAnimationEnd(animation: Animator) {
mLoginFormView.visibility = if (show) View.GONE else View.VISIBLE loginForm.visibility = if (show) View.GONE else View.VISIBLE
} }
}) })
mProgressView.visibility = if (show) View.VISIBLE else View.GONE loginProgress.visibility = if (show) View.VISIBLE else View.GONE
mProgressView loginProgress
.animate() .animate()
.setDuration(shortAnimTime.toLong()) .setDuration(shortAnimTime.toLong())
.alpha( .alpha(
if (show) 1F else 0F if (show) 1F else 0F
).setListener(object : AnimatorListenerAdapter() { ).setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) { override fun onAnimationEnd(animation: Animator) {
mProgressView.visibility = if (show) View.VISIBLE else View.GONE loginProgress.visibility = if (show) View.VISIBLE else View.GONE
} }
}) })
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.login_menu, menu) menuInflater.inflate(R.menu.login_menu, menu)
menu.findItem(R.id.loging_debug).isChecked = logErrors menu.findItem(R.id.login_debug).isChecked = logErrors
return true return true
} }
@ -295,17 +269,17 @@ class LoginActivity : AppCompatActivity() {
when (item.itemId) { when (item.itemId) {
R.id.about -> { R.id.about -> {
LibsBuilder() LibsBuilder()
.withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR) .withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR)
.withAboutIconShown(true) .withAboutIconShown(true)
.withAboutVersionShown(true) .withAboutVersionShown(true)
.start(this) .start(this)
return true return true
} }
R.id.loging_debug -> { R.id.login_debug -> {
val newState = !item.isChecked val newState = !item.isChecked
item.isChecked = newState item.isChecked = newState
logErrors = newState logErrors = newState
editor.putBoolean("loging_debug", newState) editor.putBoolean("login_debug", newState)
editor.apply() editor.apply()
return true return true
} }

View File

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

View File

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

View File

@ -9,8 +9,6 @@ import android.support.v7.widget.RecyclerView
import android.text.Html import android.text.Html
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.ImageView.ScaleType import android.widget.ImageView.ScaleType
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
@ -38,6 +36,7 @@ import com.like.OnLikeListener
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import kotlinx.android.synthetic.main.card_item.view.*
class ItemCardAdapter(private val app: Activity, class ItemCardAdapter(private val app: Activity,
private val items: ArrayList<Item>, private val items: ArrayList<Item>,
@ -61,32 +60,32 @@ class ItemCardAdapter(private val app: Activity,
val itm = items[position] val itm = items[position]
holder.saveBtn.isLiked = itm.starred holder.mView.favButton.isLiked = itm.starred
holder.title.text = Html.fromHtml(itm.title) holder.mView.title.text = Html.fromHtml(itm.title)
holder.sourceTitleAndDate.text = itm.sourceAndDateText() holder.mView.sourceTitleAndDate.text = itm.sourceAndDateText()
if (itm.getThumbnail(c).isEmpty()) { if (itm.getThumbnail(c).isEmpty()) {
Glide.with(c).clear(holder.itemImage) Glide.with(c).clear(holder.mView.itemImage)
holder.itemImage.setImageDrawable(null) holder.mView.itemImage.setImageDrawable(null)
} else { } else {
c.bitmapCenterCrop(itm.getThumbnail(c), holder.itemImage) c.bitmapCenterCrop(itm.getThumbnail(c), holder.mView.itemImage)
} }
if (itm.getIcon(c).isEmpty()) { if (itm.getIcon(c).isEmpty()) {
val color = generator.getColor(itm.sourcetitle) val color = generator.getColor(itm.sourcetitle)
val drawable = val drawable =
TextDrawable TextDrawable
.builder() .builder()
.round() .round()
.build(itm.sourcetitle.toTextDrawableString(), color) .build(itm.sourcetitle.toTextDrawableString(), color)
holder.sourceImage.setImageDrawable(drawable) holder.mView.sourceImage.setImageDrawable(drawable)
} else { } else {
c.circularBitmapDrawable(itm.getIcon(c), holder.sourceImage) c.circularBitmapDrawable(itm.getIcon(c), holder.mView.sourceImage)
} }
holder.saveBtn.isLiked = itm.starred holder.mView.favButton.isLiked = itm.starred
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
@ -128,13 +127,13 @@ class ItemCardAdapter(private val app: Activity,
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) { override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
if (!response.succeeded() && debugReadingItems) { if (!response.succeeded() && debugReadingItems) {
val message = val message =
"message: ${response.message()} " + "message: ${response.message()} " +
"response isSuccess: ${response.isSuccessful} " + "response isSuccess: ${response.isSuccessful} " +
"response code: ${response.code()} " + "response code: ${response.code()} " +
"response message: ${response.message()} " + "response message: ${response.message()} " +
"response errorBody: ${response.errorBody()?.string()} " + "response errorBody: ${response.errorBody()?.string()} " +
"body success: ${response.body()?.success} " + "body success: ${response.body()?.success} " +
"body isSuccess: ${response.body()?.isSuccess}" "body isSuccess: ${response.body()?.isSuccess}"
Crashlytics.setUserIdentifier(userIdentifier) Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(100, "READ_DEBUG_SUCCESS", message) Crashlytics.log(100, "READ_DEBUG_SUCCESS", message)
Crashlytics.logException(Exception("Was success, but did it work ?")) Crashlytics.logException(Exception("Was success, but did it work ?"))
@ -160,14 +159,6 @@ class ItemCardAdapter(private val app: Activity,
} }
inner class ViewHolder(val mView: CardView) : RecyclerView.ViewHolder(mView) { inner class ViewHolder(val mView: CardView) : RecyclerView.ViewHolder(mView) {
lateinit var saveBtn: LikeButton
lateinit var browserBtn: ImageButton
lateinit var shareBtn: ImageButton
lateinit var itemImage: ImageView
lateinit var sourceImage: ImageView
lateinit var title: TextView
lateinit var sourceTitleAndDate: TextView
init { init {
mView.setCardBackgroundColor(appColors.cardBackground) mView.setCardBackgroundColor(appColors.cardBackground)
handleClickListeners() handleClickListeners()
@ -175,27 +166,20 @@ class ItemCardAdapter(private val app: Activity,
} }
private fun handleClickListeners() { private fun handleClickListeners() {
sourceImage = mView.findViewById(R.id.sourceImage)
itemImage = mView.findViewById(R.id.itemImage)
title = mView.findViewById(R.id.title)
sourceTitleAndDate = mView.findViewById(R.id.sourceTitleAndDate)
saveBtn = mView.findViewById(R.id.favButton)
shareBtn = mView.findViewById(R.id.shareBtn)
browserBtn = mView.findViewById(R.id.browserBtn)
if (!fullHeightCards) { if (!fullHeightCards) {
itemImage.maxHeight = c.resources.getDimension(R.dimen.card_image_max_height).toInt() mView.itemImage.maxHeight = c.resources.getDimension(R.dimen.card_image_max_height).toInt()
itemImage.scaleType = ScaleType.CENTER_CROP mView.itemImage.scaleType = ScaleType.CENTER_CROP
} }
saveBtn.setOnLikeListener(object : OnLikeListener { mView.favButton.setOnLikeListener(object : OnLikeListener {
override fun liked(likeButton: LikeButton) { override fun liked(likeButton: LikeButton) {
val (id) = items[adapterPosition] val (id) = items[adapterPosition]
api.starrItem(id).enqueue(object : Callback<SuccessResponse> { api.starrItem(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {} override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
saveBtn.isLiked = false mView.favButton.isLiked = false
Toast.makeText(c, R.string.cant_mark_favortie, Toast.LENGTH_SHORT).show() Toast.makeText(c, R.string.cant_mark_favortie, Toast.LENGTH_SHORT).show()
} }
}) })
@ -207,18 +191,18 @@ class ItemCardAdapter(private val app: Activity,
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {} override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
saveBtn.isLiked = true mView.favButton.isLiked = true
Toast.makeText(c, R.string.cant_unmark_favortie, Toast.LENGTH_SHORT).show() Toast.makeText(c, R.string.cant_unmark_favortie, Toast.LENGTH_SHORT).show()
} }
}) })
} }
}) })
shareBtn.setOnClickListener { mView.shareBtn.setOnClickListener {
c.shareLink(items[adapterPosition].getLinkDecoded()) c.shareLink(items[adapterPosition].getLinkDecoded())
} }
browserBtn.setOnClickListener { mView.browserBtn.setOnClickListener {
c.openInBrowserAsNewTask(items[adapterPosition]) c.openInBrowserAsNewTask(items[adapterPosition])
} }
} }
@ -229,10 +213,14 @@ class ItemCardAdapter(private val app: Activity,
mView.setOnClickListener { mView.setOnClickListener {
c.openItemUrl(items[adapterPosition].getLinkDecoded(), c.openItemUrl(items[adapterPosition].getLinkDecoded(),
customTabsIntent, items[adapterPosition].content,
internalBrowser, items[adapterPosition].getThumbnail(c),
articleViewer, items[adapterPosition].title,
app) items[adapterPosition].sourceAndDateText(),
customTabsIntent,
internalBrowser,
articleViewer,
app)
} }
} }
} }

View File

@ -12,9 +12,6 @@ import android.util.TypedValue
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import apps.amine.bou.readerforselfoss.R import apps.amine.bou.readerforselfoss.R
@ -40,7 +37,7 @@ import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlinx.android.synthetic.main.list_item.view.*
class ItemListAdapter(private val app: Activity, class ItemListAdapter(private val app: Activity,
private val items: ArrayList<Item>, private val items: ArrayList<Item>,
@ -64,27 +61,27 @@ class ItemListAdapter(private val app: Activity,
val itm = items[position] val itm = items[position]
holder.saveBtn.isLiked = itm.starred holder.mView.favButton.isLiked = itm.starred
holder.title.text = Html.fromHtml(itm.title) holder.mView.title.text = Html.fromHtml(itm.title)
holder.sourceTitleAndDate.text = itm.sourceAndDateText() holder.mView.sourceTitleAndDate.text = itm.sourceAndDateText()
if (itm.getThumbnail(c).isEmpty()) { if (itm.getThumbnail(c).isEmpty()) {
val sizeInInt = 46 val sizeInInt = 46
val sizeInDp = TypedValue.applyDimension( val sizeInDp = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, sizeInInt.toFloat(), c.resources TypedValue.COMPLEX_UNIT_DIP, sizeInInt.toFloat(), c.resources
.displayMetrics).toInt() .displayMetrics).toInt()
val marginInInt = 16 val marginInInt = 16
val marginInDp = TypedValue.applyDimension( val marginInDp = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, marginInInt.toFloat(), c.resources TypedValue.COMPLEX_UNIT_DIP, marginInInt.toFloat(), c.resources
.displayMetrics).toInt() .displayMetrics).toInt()
val params = holder.sourceImage.layoutParams as ViewGroup.MarginLayoutParams val params = holder.mView.itemImage.layoutParams as ViewGroup.MarginLayoutParams
params.height = sizeInDp params.height = sizeInDp
params.width = sizeInDp params.width = sizeInDp
params.setMargins(marginInDp, 0, 0, 0) params.setMargins(marginInDp, 0, 0, 0)
holder.sourceImage.layoutParams = params holder.mView.itemImage.layoutParams = params
if (itm.getIcon(c).isEmpty()) { if (itm.getIcon(c).isEmpty()) {
val color = generator.getColor(itm.sourcetitle) val color = generator.getColor(itm.sourcetitle)
@ -96,17 +93,17 @@ class ItemListAdapter(private val app: Activity,
val builder = TextDrawable.builder().round() val builder = TextDrawable.builder().round()
val drawable = builder.build(textDrawable.toString(), color) val drawable = builder.build(textDrawable.toString(), color)
holder.sourceImage.setImageDrawable(drawable) holder.mView.itemImage.setImageDrawable(drawable)
} else { } else {
c.circularBitmapDrawable(itm.getIcon(c), holder.sourceImage) c.circularBitmapDrawable(itm.getIcon(c), holder.mView.itemImage)
} }
} else { } else {
c.bitmapCenterCrop(itm.getThumbnail(c), holder.sourceImage) c.bitmapCenterCrop(itm.getThumbnail(c), holder.mView.itemImage)
} }
if (bars[position]) holder.actionBar.visibility = View.VISIBLE else holder.actionBar.visibility = View.GONE if (bars[position]) holder.mView.actionBar.visibility = View.VISIBLE else holder.mView.actionBar.visibility = View.GONE
holder.saveBtn.isLiked = itm.starred holder.mView.favButton.isLiked = itm.starred
} }
override fun getItemCount(): Int = items.size override fun getItemCount(): Int = items.size
@ -147,13 +144,13 @@ class ItemListAdapter(private val app: Activity,
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) { override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
if (!response.succeeded() && debugReadingItems) { if (!response.succeeded() && debugReadingItems) {
val message = val message =
"message: ${response.message()} " + "message: ${response.message()} " +
"response isSuccess: ${response.isSuccessful} " + "response isSuccess: ${response.isSuccessful} " +
"response code: ${response.code()} " + "response code: ${response.code()} " +
"response message: ${response.message()} " + "response message: ${response.message()} " +
"response errorBody: ${response.errorBody()?.string()} " + "response errorBody: ${response.errorBody()?.string()} " +
"body success: ${response.body()?.success} " + "body success: ${response.body()?.success} " +
"body isSuccess: ${response.body()?.isSuccess}" "body isSuccess: ${response.body()?.isSuccess}"
Crashlytics.setUserIdentifier(userIdentifier) Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(100, "READ_DEBUG_SUCCESS", message) Crashlytics.log(100, "READ_DEBUG_SUCCESS", message)
Crashlytics.logException(Exception("Was success, but did it work ?")) Crashlytics.logException(Exception("Was success, but did it work ?"))
@ -179,13 +176,6 @@ class ItemListAdapter(private val app: Activity,
} }
inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) { inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) {
lateinit var saveBtn: LikeButton
lateinit var browserBtn: ImageButton
lateinit var shareBtn: ImageButton
lateinit var actionBar: RelativeLayout
lateinit var sourceImage: ImageView
lateinit var title: TextView
lateinit var sourceTitleAndDate: TextView
init { init {
handleClickListeners() handleClickListeners()
@ -193,23 +183,15 @@ class ItemListAdapter(private val app: Activity,
} }
private fun handleClickListeners() { private fun handleClickListeners() {
actionBar = mView.findViewById(R.id.actionBar)
sourceImage = mView.findViewById(R.id.itemImage)
title = mView.findViewById(R.id.title)
sourceTitleAndDate = mView.findViewById(R.id.sourceTitleAndDate)
saveBtn = mView.findViewById(R.id.favButton)
shareBtn = mView.findViewById(R.id.shareBtn)
browserBtn = mView.findViewById(R.id.browserBtn)
mView.favButton.setOnLikeListener(object : OnLikeListener {
saveBtn.setOnLikeListener(object : OnLikeListener {
override fun liked(likeButton: LikeButton) { override fun liked(likeButton: LikeButton) {
val (id) = items[adapterPosition] val (id) = items[adapterPosition]
api.starrItem(id).enqueue(object : Callback<SuccessResponse> { api.starrItem(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {} override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
saveBtn.isLiked = false mView.favButton.isLiked = false
Toast.makeText(c, R.string.cant_mark_favortie, Toast.LENGTH_SHORT).show() Toast.makeText(c, R.string.cant_mark_favortie, Toast.LENGTH_SHORT).show()
} }
}) })
@ -221,18 +203,18 @@ class ItemListAdapter(private val app: Activity,
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {} override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
saveBtn.isLiked = true mView.favButton.isLiked = true
Toast.makeText(c, R.string.cant_unmark_favortie, Toast.LENGTH_SHORT).show() Toast.makeText(c, R.string.cant_unmark_favortie, Toast.LENGTH_SHORT).show()
} }
}) })
} }
}) })
shareBtn.setOnClickListener { mView.shareBtn.setOnClickListener {
c.shareLink(items[adapterPosition].getLinkDecoded()) c.shareLink(items[adapterPosition].getLinkDecoded())
} }
browserBtn.setOnClickListener { mView.browserBtn.setOnClickListener {
c.openInBrowserAsNewTask(items[adapterPosition]) c.openInBrowserAsNewTask(items[adapterPosition])
} }
@ -247,10 +229,14 @@ class ItemListAdapter(private val app: Activity,
if (!clickBehavior) { if (!clickBehavior) {
mView.setOnClickListener { mView.setOnClickListener {
c.openItemUrl(items[adapterPosition].getLinkDecoded(), c.openItemUrl(items[adapterPosition].getLinkDecoded(),
customTabsIntent, items[adapterPosition].content,
internalBrowser, items[adapterPosition].getThumbnail(c),
articleViewer, items[adapterPosition].title,
app) items[adapterPosition].sourceAndDateText(),
customTabsIntent,
internalBrowser,
articleViewer,
app)
} }
mView.setOnLongClickListener { mView.setOnLongClickListener {
actionBarShowHide() actionBarShowHide()
@ -260,10 +246,14 @@ class ItemListAdapter(private val app: Activity,
mView.setOnClickListener { actionBarShowHide() } mView.setOnClickListener { actionBarShowHide() }
mView.setOnLongClickListener { mView.setOnLongClickListener {
c.openItemUrl(items[adapterPosition].getLinkDecoded(), c.openItemUrl(items[adapterPosition].getLinkDecoded(),
customTabsIntent, items[adapterPosition].content,
internalBrowser, items[adapterPosition].getThumbnail(c),
articleViewer, items[adapterPosition].title,
app) items[adapterPosition].sourceAndDateText(),
customTabsIntent,
internalBrowser,
articleViewer,
app)
true true
} }
} }
@ -271,7 +261,11 @@ class ItemListAdapter(private val app: Activity,
private fun actionBarShowHide() { private fun actionBarShowHide() {
bars[adapterPosition] = true bars[adapterPosition] = true
if (actionBar.visibility == View.GONE) actionBar.visibility = View.VISIBLE else actionBar.visibility = View.GONE if (mView.actionBar.visibility == View.GONE) {
mView.actionBar.visibility = View.VISIBLE
} else {
mView.actionBar.visibility = View.GONE
}
} }
} }
} }

View File

@ -21,6 +21,7 @@ import com.amulyakhare.textdrawable.util.ColorGenerator
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import kotlinx.android.synthetic.main.source_list_item.view.*
class SourcesListAdapter(private val app: Activity, class SourcesListAdapter(private val app: Activity,
@ -41,13 +42,13 @@ class SourcesListAdapter(private val app: Activity,
val color = generator.getColor(itm.title) val color = generator.getColor(itm.title)
val drawable = val drawable =
TextDrawable TextDrawable
.builder() .builder()
.round() .round()
.build(itm.title.toTextDrawableString(), color) .build(itm.title.toTextDrawableString(), color)
holder.sourceImage.setImageDrawable(drawable) holder.itemImage.setImageDrawable(drawable)
} else { } else {
c.circularBitmapDrawable(itm.getIcon(c), holder.sourceImage) c.circularBitmapDrawable(itm.getIcon(c), holder.itemImage)
} }
holder.sourceTitle.text = itm.title holder.sourceTitle.text = itm.title
@ -58,17 +59,14 @@ class SourcesListAdapter(private val app: Activity,
} }
inner class ViewHolder(internal val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) { inner class ViewHolder(internal val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) {
lateinit var sourceImage: ImageView lateinit var itemImage: ImageView
lateinit var sourceTitle: TextView lateinit var sourceTitle: TextView
init { init {
handleClickListeners() handleClickListeners()
} }
private fun handleClickListeners() { private fun handleClickListeners() {
sourceImage = mView.findViewById(R.id.itemImage)
sourceTitle = mView.findViewById(R.id.sourceTitle)
val deleteBtn: Button = mView.findViewById(R.id.deleteBtn) val deleteBtn: Button = mView.findViewById(R.id.deleteBtn)

View File

@ -55,6 +55,7 @@ data class Sources(@SerializedName("id") val id: String,
data class Item(@SerializedName("id") val id: String, data class Item(@SerializedName("id") val id: String,
@SerializedName("datetime") val datetime: String, @SerializedName("datetime") val datetime: String,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@SerializedName("content") val content: String,
@SerializedName("unread") val unread: Boolean, @SerializedName("unread") val unread: Boolean,
@SerializedName("starred") val starred: Boolean, @SerializedName("starred") val starred: Boolean,
@SerializedName("thumbnail") val thumbnail: String, @SerializedName("thumbnail") val thumbnail: String,
@ -72,15 +73,16 @@ data class Item(@SerializedName("id") val id: String,
} }
constructor(source: Parcel) : this( constructor(source: Parcel) : this(
id = source.readString(), id = source.readString(),
datetime = source.readString(), datetime = source.readString(),
title = source.readString(), title = source.readString(),
unread = 0.toByte() != source.readByte(), content = source.readString(),
starred = 0.toByte() != source.readByte(), unread = 0.toByte() != source.readByte(),
thumbnail = source.readString(), starred = 0.toByte() != source.readByte(),
icon = source.readString(), thumbnail = source.readString(),
link = source.readString(), icon = source.readString(),
sourcetitle = source.readString() link = source.readString(),
sourcetitle = source.readString()
) )
override fun describeContents() = 0 override fun describeContents() = 0
@ -89,6 +91,7 @@ data class Item(@SerializedName("id") val id: String,
dest.writeString(id) dest.writeString(id)
dest.writeString(datetime) dest.writeString(datetime)
dest.writeString(title) dest.writeString(title)
dest.writeString(content)
dest.writeByte((if (unread) 1 else 0)) dest.writeByte((if (unread) 1 else 0))
dest.writeByte((if (starred) 1 else 0)) dest.writeByte((if (starred) 1 else 0))
dest.writeString(thumbnail) dest.writeString(thumbnail)

View File

@ -51,19 +51,28 @@ fun Context.buildCustomTabsIntent(): CustomTabsIntent {
} }
fun Context.openItemUrlInternally(linkDecoded: String, fun Context.openItemUrlInternally(linkDecoded: String,
content: String,
image: String,
title: String,
source: String,
customTabsIntent: CustomTabsIntent, customTabsIntent: CustomTabsIntent,
articleViewer: Boolean, articleViewer: Boolean,
app: Activity) { app: Activity) {
if (articleViewer) { if (articleViewer) {
val intent = Intent(this, ReaderActivity::class.java) val intent = Intent(this, ReaderActivity::class.java)
DragDismissIntentBuilder(this) /*DragDismissIntentBuilder(this)
.setFullscreenOnTablets(true) // defaults to false, tablets will have padding on each side .setFullscreenOnTablets(true) // defaults to false, tablets will have padding on each side
.setDragElasticity(DragDismissIntentBuilder.DragElasticity.NORMAL) // Larger elasticities will make it easier to dismiss. .setDragElasticity(DragDismissIntentBuilder.DragElasticity.NORMAL) // Larger elasticities will make it easier to dismiss.
.setDrawUnderStatusBar(true) .setDrawUnderStatusBar(true)
.build(intent) .build(intent)*/
intent.putExtra("url", linkDecoded) intent.putExtra("url", linkDecoded)
intent.putExtra("content", content)
intent.putExtra("title", title)
intent.putExtra("image", image)
intent.putExtra("source", source)
app.startActivity(intent) app.startActivity(intent)
} else { } else {
try { try {
@ -80,6 +89,10 @@ fun Context.openItemUrlInternally(linkDecoded: String,
} }
fun Context.openItemUrl(linkDecoded: String, fun Context.openItemUrl(linkDecoded: String,
content: String,
image: String,
title: String,
source: String,
customTabsIntent: CustomTabsIntent, customTabsIntent: CustomTabsIntent,
internalBrowser: Boolean, internalBrowser: Boolean,
articleViewer: Boolean, articleViewer: Boolean,
@ -91,7 +104,7 @@ fun Context.openItemUrl(linkDecoded: String,
if (!internalBrowser) { if (!internalBrowser) {
openInBrowser(linkDecoded, app) openInBrowser(linkDecoded, app)
} else { } else {
this.openItemUrlInternally(linkDecoded, customTabsIntent, articleViewer, app) this.openItemUrlInternally(linkDecoded, content, image, title, source, customTabsIntent, articleViewer, app)
} }
} }
} }
@ -103,7 +116,7 @@ private fun openInBrowser(linkDecoded: String, app: Activity) {
} }
fun String.isUrlValid(): Boolean = fun String.isUrlValid(): Boolean =
HttpUrl.parse(this) != null && Patterns.WEB_URL.matcher(this).matches() HttpUrl.parse(this) != null && Patterns.WEB_URL.matcher(this).matches()
fun String.isBaseUrlValid(): Boolean { fun String.isBaseUrlValid(): Boolean {
val baseUrl = HttpUrl.parse(this) val baseUrl = HttpUrl.parse(this)

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">Lurl de lélément nest pas valide. En attendant la résolution du problème, le lien ne s\'ouvrira pas.</string> <string name="cant_open_invalid_url">Lurl de lélément nest pas valide. En attendant la résolution du problème, le lien ne s\'ouvrira pas.</string>
<string name="drawer_report_bug">Signaler un bug</string> <string name="drawer_report_bug">Signaler un bug</string>
<string name="items_number_should_be_number">Le nombre d\'articles doit être un entier.</string> <string name="items_number_should_be_number">Le nombre d\'articles doit être un entier.</string>
<string name="reader_action_more">Lire plus</string>
<string name="reader_action_open">Ouvrir</string>
<string name="reader_action_share">Partager</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">A url está inválida. Estou tentando resolver esse problema para que o aplicativo não encerre.</string> <string name="cant_open_invalid_url">A url está inválida. Estou tentando resolver esse problema para que o aplicativo não encerre.</string>
<string name="drawer_report_bug">Reportar erro</string> <string name="drawer_report_bug">Reportar erro</string>
<string name="items_number_should_be_number">O número dos itens deve ser um número inteiro.</string> <string name="items_number_should_be_number">O número dos itens deve ser um número inteiro.</string>
<string name="reader_action_more">Leia mais</string>
<string name="reader_action_open">Abrir no navegador</string>
<string name="reader_action_share">Compartilhar</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -155,4 +155,7 @@
<string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string> <string name="cant_open_invalid_url">The item url is invalid. I\'m looking into solving this issue so the app won\'t crash.</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -158,4 +158,7 @@
<string name="report_github_repo" translatable="false">ReaderforSelfoss</string> <string name="report_github_repo" translatable="false">ReaderforSelfoss</string>
<string name="drawer_report_bug">Report a bug</string> <string name="drawer_report_bug">Report a bug</string>
<string name="items_number_should_be_number">The items number should be an integer.</string> <string name="items_number_should_be_number">The items number should be an integer.</string>
<string name="reader_action_more">Read more</string>
<string name="reader_action_open">Open in browser</string>
<string name="reader_action_share">Share</string>
</resources> </resources>

View File

@ -10,7 +10,7 @@
<SwitchPreference <SwitchPreference
android:defaultValue="false" android:defaultValue="false"
android:key="loging_debug" android:key="login_debug"
android:summaryOff="@string/login_debug_off" android:summaryOff="@string/login_debug_off"
android:summaryOn="@string/login_debug_on" android:summaryOn="@string/login_debug_on"
android:title="@string/login_debug_title" /> android:title="@string/login_debug_title" />

View File

@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.1.51' ext.kotlin_version = '1.1.60'
repositories { repositories {
jcenter() jcenter()
google() google()
@ -10,12 +10,12 @@ buildscript {
} }
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.0.0' classpath 'com.android.tools.build:gradle:3.0.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
classpath 'com.google.gms:google-services:3.1.0' classpath 'com.google.gms:google-services:3.1.1'
// Not the official version https://stackoverflow.com/questions/46525040/sonarqube-android-not-working-for-gradle-3-0-0/46813528#46813528 // Not the official version https://stackoverflow.com/questions/46525040/sonarqube-android-not-working-for-gradle-3-0-0/46813528#46813528
classpath "com.github.Shusshu:sonar-scanner-gradle:feature~support-android-gradle-3-SNAPSHOT" classpath "com.github.Shusshu:sonar-scanner-gradle:feature~support-android-gradle-3-SNAPSHOT"