Kotlin style guide. (#125)
This commit is contained in:
parent
68098f4d84
commit
69ac2e2b44
@ -1,4 +1,3 @@
|
|||||||
package apps.amine.bou.readerforselfoss
|
package apps.amine.bou.readerforselfoss
|
||||||
|
|
||||||
|
|
||||||
// TODO: test source adding
|
// TODO: test source adding
|
@ -5,29 +5,33 @@ import android.content.Intent
|
|||||||
import android.support.test.InstrumentationRegistry
|
import android.support.test.InstrumentationRegistry
|
||||||
import android.support.test.espresso.Espresso.onView
|
import android.support.test.espresso.Espresso.onView
|
||||||
import android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu
|
import android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu
|
||||||
import android.support.test.espresso.action.ViewActions.*
|
import android.support.test.espresso.action.ViewActions.click
|
||||||
|
import android.support.test.espresso.action.ViewActions.closeSoftKeyboard
|
||||||
|
import android.support.test.espresso.action.ViewActions.pressBack
|
||||||
|
import android.support.test.espresso.action.ViewActions.pressKey
|
||||||
|
import android.support.test.espresso.action.ViewActions.typeText
|
||||||
import android.support.test.espresso.assertion.ViewAssertions.matches
|
import android.support.test.espresso.assertion.ViewAssertions.matches
|
||||||
import android.support.test.espresso.contrib.DrawerActions
|
import android.support.test.espresso.contrib.DrawerActions
|
||||||
import android.support.test.espresso.intent.Intents
|
import android.support.test.espresso.intent.Intents
|
||||||
import android.support.test.espresso.intent.Intents.intended
|
import android.support.test.espresso.intent.Intents.intended
|
||||||
import android.support.test.espresso.intent.Intents.times
|
import android.support.test.espresso.intent.Intents.times
|
||||||
import android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent
|
import android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent
|
||||||
import android.support.test.espresso.matcher.ViewMatchers.*
|
import android.support.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||||
|
import android.support.test.espresso.matcher.ViewMatchers.isRoot
|
||||||
|
import android.support.test.espresso.matcher.ViewMatchers.withContentDescription
|
||||||
|
import android.support.test.espresso.matcher.ViewMatchers.withId
|
||||||
|
import android.support.test.espresso.matcher.ViewMatchers.withText
|
||||||
import android.support.test.rule.ActivityTestRule
|
import android.support.test.rule.ActivityTestRule
|
||||||
import android.support.test.runner.AndroidJUnit4
|
import android.support.test.runner.AndroidJUnit4
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.Config
|
||||||
import com.mikepenz.aboutlibraries.ui.LibsActivity
|
import com.heinrichreimersoftware.androidissuereporter.IssueReporterLauncher
|
||||||
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
import apps.amine.bou.readerforselfoss.utils.Config
|
|
||||||
import com.heinrichreimersoftware.androidissuereporter.IssueReporterLauncher
|
|
||||||
import org.junit.After
|
|
||||||
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class HomeActivityEspressoTest {
|
class HomeActivityEspressoTest {
|
||||||
lateinit var context: Context
|
lateinit var context: Context
|
||||||
@ -40,9 +44,9 @@ class HomeActivityEspressoTest {
|
|||||||
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.putString("url", BuildConfig.LOGIN_URL)
|
editor.putString("url", BuildConfig.LOGIN_URL)
|
||||||
@ -60,29 +64,32 @@ class HomeActivityEspressoTest {
|
|||||||
rule.launchActivity(Intent())
|
rule.launchActivity(Intent())
|
||||||
|
|
||||||
onView(
|
onView(
|
||||||
withMenu(
|
withMenu(
|
||||||
id = R.id.action_search,
|
id = R.id.action_search,
|
||||||
titleId = R.string.menu_home_search
|
titleId = R.string.menu_home_search
|
||||||
)
|
)
|
||||||
).perform(click())
|
).perform(click())
|
||||||
|
|
||||||
onView(withId(R.id.search_bar)).check(matches(isDisplayed()))
|
onView(withId(R.id.search_bar)).check(matches(isDisplayed()))
|
||||||
|
|
||||||
onView(withId(R.id.search_src_text)).perform(typeText("android"), pressKey(KeyEvent.KEYCODE_SEARCH), closeSoftKeyboard())
|
onView(withId(R.id.search_src_text)).perform(
|
||||||
|
typeText("android"),
|
||||||
|
pressKey(KeyEvent.KEYCODE_SEARCH),
|
||||||
|
closeSoftKeyboard()
|
||||||
|
)
|
||||||
|
|
||||||
onView(withContentDescription(R.string.abc_toolbar_collapse_description)).perform(click())
|
onView(withContentDescription(R.string.abc_toolbar_collapse_description)).perform(click())
|
||||||
|
|
||||||
openActionBarOverflowOrOptionsMenu(context)
|
openActionBarOverflowOrOptionsMenu(context)
|
||||||
|
|
||||||
onView(withMenu(id = R.id.refresh, titleId = R.string.menu_home_refresh))
|
onView(withMenu(id = R.id.refresh, titleId = R.string.menu_home_refresh))
|
||||||
.perform(click())
|
.perform(click())
|
||||||
|
|
||||||
openActionBarOverflowOrOptionsMenu(context)
|
openActionBarOverflowOrOptionsMenu(context)
|
||||||
|
|
||||||
onView(withText(R.string.action_disconnect)).perform(click())
|
onView(withText(R.string.action_disconnect)).perform(click())
|
||||||
|
|
||||||
intended(hasComponent(LoginActivity::class.java.name), times(1))
|
intended(hasComponent(LoginActivity::class.java.name), times(1))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -102,7 +109,6 @@ class HomeActivityEspressoTest {
|
|||||||
|
|
||||||
onView(withId(R.id.material_drawer_layout)).perform(DrawerActions.open())
|
onView(withId(R.id.material_drawer_layout)).perform(DrawerActions.open())
|
||||||
onView(withText(R.string.drawer_action_clear)).perform(click())
|
onView(withText(R.string.drawer_action_clear)).perform(click())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test articles opening and actions for cards and lists
|
// TODO: test articles opening and actions for cards and lists
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package apps.amine.bou.readerforselfoss
|
package apps.amine.bou.readerforselfoss
|
||||||
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.support.test.InstrumentationRegistry.getInstrumentation
|
import android.support.test.InstrumentationRegistry.getInstrumentation
|
||||||
@ -11,22 +9,19 @@ import android.support.test.espresso.assertion.ViewAssertions.matches
|
|||||||
import android.support.test.espresso.intent.Intents
|
import android.support.test.espresso.intent.Intents
|
||||||
import android.support.test.espresso.intent.Intents.intended
|
import android.support.test.espresso.intent.Intents.intended
|
||||||
import android.support.test.espresso.intent.Intents.times
|
import android.support.test.espresso.intent.Intents.times
|
||||||
import android.support.test.espresso.intent.matcher.IntentMatchers.*
|
import android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent
|
||||||
import android.support.test.espresso.intent.matcher.UriMatchers.hasHost
|
import android.support.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||||
import android.support.test.espresso.matcher.ViewMatchers.*
|
import android.support.test.espresso.matcher.ViewMatchers.withId
|
||||||
|
import android.support.test.espresso.matcher.ViewMatchers.withText
|
||||||
import android.support.test.rule.ActivityTestRule
|
import android.support.test.rule.ActivityTestRule
|
||||||
import android.support.test.runner.AndroidJUnit4
|
import android.support.test.runner.AndroidJUnit4
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.Config
|
||||||
import org.hamcrest.Matchers.allOf
|
import org.junit.After
|
||||||
import org.hamcrest.Matchers.equalTo
|
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
import java.util.*
|
||||||
import apps.amine.bou.readerforselfoss.utils.Config
|
|
||||||
import org.junit.After
|
|
||||||
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class IntroActivityEspressoTest {
|
class IntroActivityEspressoTest {
|
||||||
@ -37,9 +32,9 @@ class IntroActivityEspressoTest {
|
|||||||
@Before
|
@Before
|
||||||
fun clearData() {
|
fun clearData() {
|
||||||
val editor =
|
val editor =
|
||||||
getInstrumentation().targetContext
|
getInstrumentation().targetContext
|
||||||
.getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
.getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
||||||
.edit()
|
.edit()
|
||||||
editor.clear()
|
editor.clear()
|
||||||
editor.commit()
|
editor.commit()
|
||||||
|
|
||||||
@ -60,7 +55,6 @@ class IntroActivityEspressoTest {
|
|||||||
|
|
||||||
intended(hasComponent(IntroActivity::class.java.name), times(1))
|
intended(hasComponent(IntroActivity::class.java.name), times(1))
|
||||||
intended(hasComponent(LoginActivity::class.java.name), times(1))
|
intended(hasComponent(LoginActivity::class.java.name), times(1))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -75,7 +69,7 @@ class IntroActivityEspressoTest {
|
|||||||
onView(withText(R.string.intro_hello_title)).check(matches(isDisplayed()))
|
onView(withText(R.string.intro_hello_title)).check(matches(isDisplayed()))
|
||||||
onView(withId(R.id.button_next)).perform(click())
|
onView(withId(R.id.button_next)).perform(click())
|
||||||
|
|
||||||
repeat(random) {_ ->
|
repeat(random) { _ ->
|
||||||
onView(withText(R.string.intro_needs_selfoss_message)).check(matches(isDisplayed()))
|
onView(withText(R.string.intro_needs_selfoss_message)).check(matches(isDisplayed()))
|
||||||
onView(withId(R.id.button_next)).perform(click())
|
onView(withId(R.id.button_next)).perform(click())
|
||||||
onView(withText(R.string.intro_all_set_message)).check(matches(isDisplayed()))
|
onView(withText(R.string.intro_all_set_message)).check(matches(isDisplayed()))
|
||||||
@ -88,7 +82,6 @@ class IntroActivityEspressoTest {
|
|||||||
|
|
||||||
intended(hasComponent(IntroActivity::class.java.name), times(1))
|
intended(hasComponent(IntroActivity::class.java.name), times(1))
|
||||||
intended(hasComponent(LoginActivity::class.java.name), times(1))
|
intended(hasComponent(LoginActivity::class.java.name), times(1))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
@ -5,27 +5,30 @@ import android.content.Intent
|
|||||||
import android.support.test.InstrumentationRegistry
|
import android.support.test.InstrumentationRegistry
|
||||||
import android.support.test.espresso.Espresso.onView
|
import android.support.test.espresso.Espresso.onView
|
||||||
import android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu
|
import android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu
|
||||||
import android.support.test.espresso.action.ViewActions.*
|
import android.support.test.espresso.action.ViewActions.click
|
||||||
|
import android.support.test.espresso.action.ViewActions.closeSoftKeyboard
|
||||||
|
import android.support.test.espresso.action.ViewActions.pressBack
|
||||||
|
import android.support.test.espresso.action.ViewActions.typeText
|
||||||
import android.support.test.espresso.assertion.ViewAssertions.matches
|
import android.support.test.espresso.assertion.ViewAssertions.matches
|
||||||
import android.support.test.espresso.intent.Intents
|
import android.support.test.espresso.intent.Intents
|
||||||
import android.support.test.espresso.intent.Intents.intended
|
import android.support.test.espresso.intent.Intents.intended
|
||||||
import android.support.test.espresso.intent.Intents.times
|
import android.support.test.espresso.intent.Intents.times
|
||||||
import android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent
|
import android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent
|
||||||
import android.support.test.espresso.matcher.ViewMatchers
|
import android.support.test.espresso.matcher.ViewMatchers
|
||||||
import android.support.test.espresso.matcher.ViewMatchers.*
|
import android.support.test.espresso.matcher.ViewMatchers.isRoot
|
||||||
|
import android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
||||||
|
import android.support.test.espresso.matcher.ViewMatchers.withId
|
||||||
|
import android.support.test.espresso.matcher.ViewMatchers.withText
|
||||||
import android.support.test.rule.ActivityTestRule
|
import android.support.test.rule.ActivityTestRule
|
||||||
import android.support.test.runner.AndroidJUnit4
|
import android.support.test.runner.AndroidJUnit4
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.Config
|
||||||
import com.mikepenz.aboutlibraries.ui.LibsActivity
|
import com.mikepenz.aboutlibraries.ui.LibsActivity
|
||||||
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
import apps.amine.bou.readerforselfoss.utils.Config
|
|
||||||
import org.junit.After
|
|
||||||
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class LoginActivityEspressoTest {
|
class LoginActivityEspressoTest {
|
||||||
|
|
||||||
@ -69,10 +72,8 @@ class LoginActivityEspressoTest {
|
|||||||
onView(isRoot()).perform(pressBack())
|
onView(isRoot()).perform(pressBack())
|
||||||
|
|
||||||
intended(hasComponent(LoginActivity::class.java.name))
|
intended(hasComponent(LoginActivity::class.java.name))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun wrongLoginUrl() {
|
fun wrongLoginUrl() {
|
||||||
rule.launchActivity(Intent())
|
rule.launchActivity(Intent())
|
||||||
@ -103,7 +104,10 @@ class LoginActivityEspressoTest {
|
|||||||
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.loginView)).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()))
|
||||||
|
|
||||||
@ -111,9 +115,9 @@ class LoginActivityEspressoTest {
|
|||||||
|
|
||||||
onView(withId(R.id.passwordLayout)).check(
|
onView(withId(R.id.passwordLayout)).check(
|
||||||
matches(
|
matches(
|
||||||
isHintOrErrorEnabled())
|
isHintOrErrorEnabled()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -125,16 +129,21 @@ class LoginActivityEspressoTest {
|
|||||||
|
|
||||||
onView(withId(R.id.withLogin)).perform(click())
|
onView(withId(R.id.withLogin)).perform(click())
|
||||||
|
|
||||||
onView(withId(R.id.loginView)).perform(click()).perform(typeText(username), closeSoftKeyboard())
|
onView(withId(R.id.loginView)).perform(click()).perform(
|
||||||
|
typeText(username),
|
||||||
|
closeSoftKeyboard()
|
||||||
|
)
|
||||||
|
|
||||||
onView(withId(R.id.passwordView)).perform(click()).perform(typeText("WRONGPASS"), closeSoftKeyboard())
|
onView(withId(R.id.passwordView)).perform(click()).perform(
|
||||||
|
typeText("WRONGPASS"),
|
||||||
|
closeSoftKeyboard()
|
||||||
|
)
|
||||||
|
|
||||||
onView(withId(R.id.signInButton)).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()))
|
||||||
onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled()))
|
onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled()))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -146,19 +155,23 @@ class LoginActivityEspressoTest {
|
|||||||
|
|
||||||
onView(withId(R.id.withLogin)).perform(click())
|
onView(withId(R.id.withLogin)).perform(click())
|
||||||
|
|
||||||
onView(withId(R.id.loginView)).perform(click()).perform(typeText(username), closeSoftKeyboard())
|
onView(withId(R.id.loginView)).perform(click()).perform(
|
||||||
|
typeText(username),
|
||||||
|
closeSoftKeyboard()
|
||||||
|
)
|
||||||
|
|
||||||
onView(withId(R.id.passwordView)).perform(click()).perform(typeText(password), closeSoftKeyboard())
|
onView(withId(R.id.passwordView)).perform(click()).perform(
|
||||||
|
typeText(password),
|
||||||
|
closeSoftKeyboard()
|
||||||
|
)
|
||||||
|
|
||||||
onView(withId(R.id.signInButton)).perform(click())
|
onView(withId(R.id.signInButton)).perform(click())
|
||||||
|
|
||||||
intended(hasComponent(HomeActivity::class.java.name))
|
intended(hasComponent(HomeActivity::class.java.name))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
fun releaseIntents() {
|
fun releaseIntents() {
|
||||||
Intents.release()
|
Intents.release()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -17,7 +17,6 @@ import org.junit.Rule
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class MainActivityEspressoTest {
|
class MainActivityEspressoTest {
|
||||||
|
|
||||||
@ -48,7 +47,6 @@ class MainActivityEspressoTest {
|
|||||||
intended(hasComponent(MainActivity::class.java.name))
|
intended(hasComponent(MainActivity::class.java.name))
|
||||||
intended(hasComponent(IntroActivity::class.java.name))
|
intended(hasComponent(IntroActivity::class.java.name))
|
||||||
intended(hasComponent(LoginActivity::class.java.name), times(0))
|
intended(hasComponent(LoginActivity::class.java.name), times(0))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -61,13 +59,10 @@ class MainActivityEspressoTest {
|
|||||||
intended(hasComponent(MainActivity::class.java.name))
|
intended(hasComponent(MainActivity::class.java.name))
|
||||||
intended(hasComponent(LoginActivity::class.java.name))
|
intended(hasComponent(LoginActivity::class.java.name))
|
||||||
intended(hasComponent(IntroActivity::class.java.name), times(0))
|
intended(hasComponent(IntroActivity::class.java.name), times(0))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
fun releaseIntents() {
|
fun releaseIntents() {
|
||||||
Intents.release()
|
Intents.release()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -1,31 +1,29 @@
|
|||||||
package apps.amine.bou.readerforselfoss
|
package apps.amine.bou.readerforselfoss
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import android.support.design.widget.TextInputLayout
|
import android.support.design.widget.TextInputLayout
|
||||||
import android.support.test.espresso.matcher.ViewMatchers
|
import android.support.test.espresso.matcher.ViewMatchers
|
||||||
|
import android.view.View
|
||||||
import org.hamcrest.Description
|
import org.hamcrest.Description
|
||||||
import org.hamcrest.Matcher
|
import org.hamcrest.Matcher
|
||||||
import org.hamcrest.TypeSafeMatcher
|
|
||||||
import org.hamcrest.Matchers
|
import org.hamcrest.Matchers
|
||||||
|
import org.hamcrest.TypeSafeMatcher
|
||||||
|
|
||||||
|
|
||||||
fun isHintOrErrorEnabled(): Matcher<View> =
|
fun isHintOrErrorEnabled(): Matcher<View> =
|
||||||
object : TypeSafeMatcher<View>() {
|
object : TypeSafeMatcher<View>() {
|
||||||
override fun describeTo(description: Description?) {}
|
override fun describeTo(description: Description?) {
|
||||||
|
|
||||||
override fun matchesSafely(item: View?): Boolean {
|
|
||||||
if (item !is TextInputLayout) {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return item.isHintEnabled || item.isErrorEnabled
|
override fun matchesSafely(item: View?): Boolean {
|
||||||
|
if (item !is TextInputLayout) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return item.isHintEnabled || item.isErrorEnabled
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fun withMenu(id: Int, titleId: Int): Matcher<View> =
|
fun withMenu(id: Int, titleId: Int): Matcher<View> =
|
||||||
Matchers.anyOf(
|
Matchers.anyOf(
|
||||||
ViewMatchers.withId(id),
|
ViewMatchers.withId(id),
|
||||||
ViewMatchers.withText(titleId)
|
ViewMatchers.withText(titleId)
|
||||||
)
|
)
|
||||||
|
@ -24,7 +24,6 @@ import retrofit2.Call
|
|||||||
import retrofit2.Callback
|
import retrofit2.Callback
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
|
|
||||||
|
|
||||||
class AddSourceActivity : AppCompatActivity() {
|
class AddSourceActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private var mSpoutsValue: String? = null
|
private var mSpoutsValue: String? = null
|
||||||
@ -67,7 +66,12 @@ class AddSourceActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSpoutsSpinner(spoutsSpinner: Spinner, api: SelfossApi?, mProgress: ProgressBar, formContainer: ConstraintLayout) {
|
private fun handleSpoutsSpinner(
|
||||||
|
spoutsSpinner: Spinner,
|
||||||
|
api: SelfossApi?,
|
||||||
|
mProgress: ProgressBar,
|
||||||
|
formContainer: ConstraintLayout
|
||||||
|
) {
|
||||||
val spoutsKV = HashMap<String, String>()
|
val spoutsKV = HashMap<String, String>()
|
||||||
spoutsSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
spoutsSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||||
override fun onItemSelected(adapterView: AdapterView<*>, view: View, i: Int, l: Long) {
|
override fun onItemSelected(adapterView: AdapterView<*>, view: View, i: Int, l: Long) {
|
||||||
@ -82,7 +86,10 @@ class AddSourceActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
var items: Map<String, Spout>
|
var items: Map<String, Spout>
|
||||||
api!!.spouts().enqueue(object : Callback<Map<String, Spout>> {
|
api!!.spouts().enqueue(object : Callback<Map<String, Spout>> {
|
||||||
override fun onResponse(call: Call<Map<String, Spout>>, response: Response<Map<String, Spout>>) {
|
override fun onResponse(
|
||||||
|
call: Call<Map<String, Spout>>,
|
||||||
|
response: Response<Map<String, Spout>>
|
||||||
|
) {
|
||||||
if (response.body() != null) {
|
if (response.body() != null) {
|
||||||
items = response.body()!!
|
items = response.body()!!
|
||||||
|
|
||||||
@ -98,10 +105,10 @@ class AddSourceActivity : AppCompatActivity() {
|
|||||||
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)
|
||||||
spoutsSpinner.adapter = spinnerArrayAdapter
|
spoutsSpinner.adapter = spinnerArrayAdapter
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
handleProblemWithSpouts()
|
handleProblemWithSpouts()
|
||||||
}
|
}
|
||||||
@ -112,13 +119,21 @@ class AddSourceActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleProblemWithSpouts() {
|
private fun handleProblemWithSpouts() {
|
||||||
Toast.makeText(this@AddSourceActivity, R.string.cant_get_spouts, Toast.LENGTH_SHORT).show()
|
Toast.makeText(
|
||||||
|
this@AddSourceActivity,
|
||||||
|
R.string.cant_get_spouts,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
mProgress.visibility = View.GONE
|
mProgress.visibility = View.GONE
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun maybeGetDetailsFromIntentSharing(intent: Intent, sourceUri: EditText, nameInput: 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) {
|
||||||
sourceUri.setText(intent.getStringExtra(Intent.EXTRA_TEXT))
|
sourceUri.setText(intent.getStringExtra(Intent.EXTRA_TEXT))
|
||||||
nameInput.setText(intent.getStringExtra(Intent.EXTRA_TITLE))
|
nameInput.setText(intent.getStringExtra(Intent.EXTRA_TITLE))
|
||||||
@ -146,16 +161,27 @@ class AddSourceActivity : AppCompatActivity() {
|
|||||||
tags.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) {
|
||||||
finish()
|
finish()
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(this@AddSourceActivity, R.string.cant_create_source, Toast.LENGTH_SHORT).show()
|
Toast.makeText(
|
||||||
|
this@AddSourceActivity,
|
||||||
|
R.string.cant_create_source,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
||||||
Toast.makeText(this@AddSourceActivity, R.string.cant_create_source, Toast.LENGTH_SHORT).show()
|
Toast.makeText(
|
||||||
|
this@AddSourceActivity,
|
||||||
|
R.string.cant_create_source,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,11 @@ import android.os.Bundle
|
|||||||
import android.preference.PreferenceManager
|
import android.preference.PreferenceManager
|
||||||
import android.support.v4.view.MenuItemCompat
|
import android.support.v4.view.MenuItemCompat
|
||||||
import android.support.v7.app.AppCompatActivity
|
import android.support.v7.app.AppCompatActivity
|
||||||
import android.support.v7.widget.*
|
import android.support.v7.widget.DividerItemDecoration
|
||||||
|
import android.support.v7.widget.GridLayoutManager
|
||||||
|
import android.support.v7.widget.RecyclerView
|
||||||
|
import android.support.v7.widget.SearchView
|
||||||
|
import android.support.v7.widget.StaggeredGridLayoutManager
|
||||||
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
|
||||||
@ -63,10 +67,10 @@ import com.mikepenz.materialdrawer.holder.BadgeStyle
|
|||||||
import com.mikepenz.materialdrawer.model.DividerDrawerItem
|
import com.mikepenz.materialdrawer.model.DividerDrawerItem
|
||||||
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
|
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
|
||||||
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem
|
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem
|
||||||
|
import kotlinx.android.synthetic.main.activity_home.*
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.Callback
|
import retrofit2.Callback
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
import kotlinx.android.synthetic.main.activity_home.*
|
|
||||||
|
|
||||||
class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||||
|
|
||||||
@ -117,13 +121,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
private var badgeAll: Int = -1
|
private var badgeAll: Int = -1
|
||||||
private var badgeFavs: Int = -1
|
private var badgeFavs: Int = -1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
data class DrawerData(val tags: List<Tag>?, val sources: List<Sources>?)
|
data class DrawerData(val tags: List<Tag>?, val sources: List<Sources>?)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
customTabActivityHelper.bindCustomTabsService(this)
|
customTabActivityHelper.bindCustomTabsService(this)
|
||||||
@ -147,10 +146,15 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
||||||
sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
|
sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
|
||||||
api = SelfossApi(this, this@HomeActivity, settings.getBoolean("isSelfSignedCert", false), sharedPref.getBoolean("should_log_everything", false))
|
api = SelfossApi(
|
||||||
|
this,
|
||||||
|
this@HomeActivity,
|
||||||
|
settings.getBoolean("isSelfSignedCert", false),
|
||||||
|
sharedPref.getBoolean("should_log_everything", false)
|
||||||
|
)
|
||||||
items = ArrayList()
|
items = ArrayList()
|
||||||
|
|
||||||
appColors = AppColors(this@HomeActivity)
|
appColors = AppColors(this@HomeActivity)
|
||||||
|
|
||||||
handleBottomBar()
|
handleBottomBar()
|
||||||
handleDrawer()
|
handleDrawer()
|
||||||
@ -163,21 +167,36 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
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 =
|
||||||
|
if (elementsShown != UNREAD_SHOWN) {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
super.getSwipeDirs(
|
||||||
|
recyclerView,
|
||||||
|
viewHolder
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getSwipeDirs(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?): Int =
|
override fun onMove(
|
||||||
if (elementsShown != UNREAD_SHOWN) 0 else super.getSwipeDirs(recyclerView, viewHolder)
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
override fun onMove(recyclerView: RecyclerView,
|
target: RecyclerView.ViewHolder
|
||||||
viewHolder: 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 {
|
||||||
@ -193,28 +212,37 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
if (items.size > 0) {
|
if (items.size > 0) {
|
||||||
badgeNew--
|
badgeNew--
|
||||||
reloadBadgeContent()
|
reloadBadgeContent()
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
tabNewBadge.hide()
|
tabNewBadge.hide()
|
||||||
|
}
|
||||||
|
|
||||||
val manager = recyclerView.layoutManager
|
val manager = recyclerView.layoutManager
|
||||||
val lastVisibleItem: Int = when (manager) {
|
val lastVisibleItem: Int = when (manager) {
|
||||||
is StaggeredGridLayoutManager -> manager.findLastCompletelyVisibleItemPositions(null).last()
|
is StaggeredGridLayoutManager -> manager.findLastCompletelyVisibleItemPositions(
|
||||||
|
null
|
||||||
|
).last()
|
||||||
is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition()
|
is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition()
|
||||||
else -> 0
|
else -> 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastVisibleItem === items.size && items.size <= maxItemNumber() && maxItemNumber() >= itemsNumber) {
|
if (lastVisibleItem === items.size &&
|
||||||
getElementsAccordingToTab(appendResults = true, offsetOverride = lastVisibleItem)
|
items.size <= maxItemNumber() &&
|
||||||
|
maxItemNumber() >= itemsNumber
|
||||||
|
) {
|
||||||
|
getElementsAccordingToTab(
|
||||||
|
appendResults = true,
|
||||||
|
offsetOverride = lastVisibleItem
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e: IndexOutOfBoundsException) {
|
} catch (e: IndexOutOfBoundsException) {
|
||||||
Crashlytics.setUserIdentifier(userIdentifier)
|
Crashlytics.setUserIdentifier(userIdentifier)
|
||||||
Crashlytics.log(100, "SWIPE_INDEX_OUT_OF_BOUND", "IndexOutOfBoundsException when swiping")
|
Crashlytics.log(
|
||||||
|
100,
|
||||||
|
"SWIPE_INDEX_OUT_OF_BOUND",
|
||||||
|
"IndexOutOfBoundsException when swiping"
|
||||||
|
)
|
||||||
Crashlytics.logException(e)
|
Crashlytics.logException(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +292,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
|
|
||||||
bottomBar.setMode(BottomNavigationBar.MODE_SHIFTING)
|
bottomBar.setMode(BottomNavigationBar.MODE_SHIFTING)
|
||||||
bottomBar.setBackgroundStyle(BottomNavigationBar.BACKGROUND_STYLE_STATIC)
|
bottomBar.setBackgroundStyle(BottomNavigationBar.BACKGROUND_STYLE_STATIC)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
@ -290,7 +317,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
customTabActivityHelper.unbindCustomTabsService(this)
|
customTabActivityHelper.unbindCustomTabsService(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun handleSharedPrefs() {
|
private fun handleSharedPrefs() {
|
||||||
debugReadingItems = sharedPref.getBoolean("read_debug", false)
|
debugReadingItems = sharedPref.getBoolean("read_debug", false)
|
||||||
clickBehavior = sharedPref.getBoolean("tab_on_tap", false)
|
clickBehavior = sharedPref.getBoolean("tab_on_tap", false)
|
||||||
@ -327,7 +353,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
bottomBar.hide()
|
bottomBar.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (displayAccountHeader)
|
if (displayAccountHeader) {
|
||||||
accountHeader {
|
accountHeader {
|
||||||
background = R.drawable.bg
|
background = R.drawable.bg
|
||||||
profile(settings.getString("url", "")) {
|
profile(settings.getString("url", "")) {
|
||||||
@ -335,13 +361,17 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
}
|
}
|
||||||
selectionListEnabledForSingleProfile = false
|
selectionListEnabledForSingleProfile = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
primaryItem(R.string.drawer_report_bug) {
|
primaryItem(R.string.drawer_report_bug) {
|
||||||
icon = R.drawable.ic_bug_report
|
icon = R.drawable.ic_bug_report
|
||||||
iconTintingEnabled = true
|
iconTintingEnabled = true
|
||||||
onClick { _ ->
|
onClick { _ ->
|
||||||
IssueReporterLauncher.forTarget(getString(R.string.report_github_user), getString(R.string.report_github_repo))
|
IssueReporterLauncher.forTarget(
|
||||||
|
getString(R.string.report_github_user),
|
||||||
|
getString(R.string.report_github_repo)
|
||||||
|
)
|
||||||
.theme(R.style.Theme_App_Light)
|
.theme(R.style.Theme_App_Light)
|
||||||
.guestToken(BuildConfig.GITHUB_TOKEN)
|
.guestToken(BuildConfig.GITHUB_TOKEN)
|
||||||
.guestEmailRequired(true)
|
.guestEmailRequired(true)
|
||||||
@ -370,21 +400,20 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleDrawerItems() {
|
private fun handleDrawerItems() {
|
||||||
fun handleDrawerData(maybeDrawerData: DrawerData?, loadedFromCache: Boolean = false) {
|
fun handleDrawerData(maybeDrawerData: DrawerData?, loadedFromCache: Boolean = false) {
|
||||||
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) {
|
||||||
val gd = GradientDrawable()
|
val gd = GradientDrawable()
|
||||||
gd.setColor(Color.parseColor(tag.color))
|
gd.setColor(Color.parseColor(tag.color))
|
||||||
@ -409,19 +438,19 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleSources(maybeSources: List<Sources>?) {
|
fun handleSources(maybeSources: List<Sources>?) {
|
||||||
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
|
}
|
||||||
for (tag in maybeSources)
|
} else {
|
||||||
|
for (tag in maybeSources) {
|
||||||
drawer.addItem(
|
drawer.addItem(
|
||||||
CustomUrlPrimaryDrawerItem()
|
CustomUrlPrimaryDrawerItem()
|
||||||
.withName(tag.title)
|
.withName(tag.title)
|
||||||
@ -433,7 +462,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drawer.removeAllItems()
|
drawer.removeAllItems()
|
||||||
@ -456,7 +486,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
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(
|
||||||
@ -481,41 +512,46 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
.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) {
|
||||||
Reservoir.putAsync("drawerData", maybeDrawerData, object : ReservoirPutCallback {
|
Reservoir.putAsync(
|
||||||
override fun onSuccess() {}
|
"drawerData", maybeDrawerData, object : ReservoirPutCallback {
|
||||||
|
override fun onSuccess() {
|
||||||
|
}
|
||||||
|
|
||||||
override fun onFailure(p0: Exception?) {
|
override fun onFailure(p0: Exception?) {
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
}
|
||||||
} 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)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun drawerApiCalls(maybeDrawerData: DrawerData?) {
|
fun drawerApiCalls(maybeDrawerData: DrawerData?) {
|
||||||
@ -523,23 +559,28 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
var sources: List<Sources>?
|
var sources: List<Sources>?
|
||||||
|
|
||||||
fun sourcesApiCall() {
|
fun sourcesApiCall() {
|
||||||
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>>
|
||||||
|
) {
|
||||||
sources = response.body()
|
sources = response.body()
|
||||||
val apiDrawerData = DrawerData(tags, sources)
|
val apiDrawerData = DrawerData(tags, sources)
|
||||||
if ((maybeDrawerData != null && maybeDrawerData != apiDrawerData) || maybeDrawerData == null)
|
if ((maybeDrawerData != null && maybeDrawerData != apiDrawerData) || maybeDrawerData == null) {
|
||||||
handleDrawerData(apiDrawerData)
|
handleDrawerData(apiDrawerData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<List<Sources>>?, t: Throwable?) {
|
override fun onFailure(call: Call<List<Sources>>?, t: Throwable?) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
api.tags.enqueue(object: Callback<List<Tag>> {
|
api.tags.enqueue(object : Callback<List<Tag>> {
|
||||||
override fun onResponse(call: Call<List<Tag>>, response: Response<List<Tag>>) {
|
override fun onResponse(
|
||||||
|
call: Call<List<Tag>>,
|
||||||
|
response: Response<List<Tag>>
|
||||||
|
) {
|
||||||
tags = response.body()
|
tags = response.body()
|
||||||
sourcesApiCall()
|
sourcesApiCall()
|
||||||
}
|
}
|
||||||
@ -547,14 +588,18 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
override fun onFailure(call: Call<List<Tag>>?, t: Throwable?) {
|
override fun onFailure(call: Call<List<Tag>>?, t: Throwable?) {
|
||||||
sourcesApiCall()
|
sourcesApiCall()
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
drawer.addItem(PrimaryDrawerItem().withName(getString(R.string.drawer_loading)).withSelectable(false))
|
drawer.addItem(
|
||||||
|
PrimaryDrawerItem().withName(getString(R.string.drawer_loading)).withSelectable(
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
val resultType = object : TypeToken<DrawerData>() {}.type //NOSONAR
|
val resultType = object : TypeToken<DrawerData>() {}.type //NOSONAR
|
||||||
Reservoir.getAsync("drawerData", resultType, object: ReservoirGetCallback<DrawerData> {
|
Reservoir.getAsync(
|
||||||
|
"drawerData", resultType, object : ReservoirGetCallback<DrawerData> {
|
||||||
override fun onSuccess(maybeDrawerData: DrawerData?) {
|
override fun onSuccess(maybeDrawerData: DrawerData?) {
|
||||||
handleDrawerData(maybeDrawerData, loadedFromCache = true)
|
handleDrawerData(maybeDrawerData, loadedFromCache = true)
|
||||||
drawerApiCalls(maybeDrawerData)
|
drawerApiCalls(maybeDrawerData)
|
||||||
@ -563,14 +608,16 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
override fun onFailure(p0: Exception?) {
|
override fun onFailure(p0: Exception?) {
|
||||||
drawerApiCalls(null)
|
drawerApiCalls(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun reloadLayoutManager() {
|
private fun reloadLayoutManager() {
|
||||||
val mLayoutManager: RecyclerView.LayoutManager
|
val mLayoutManager: RecyclerView.LayoutManager
|
||||||
if (shouldBeCardView) {
|
if (shouldBeCardView) {
|
||||||
mLayoutManager = StaggeredGridLayoutManager(calculateNoOfColumns(), StaggeredGridLayoutManager.VERTICAL)
|
mLayoutManager = StaggeredGridLayoutManager(
|
||||||
|
calculateNoOfColumns(),
|
||||||
|
StaggeredGridLayoutManager.VERTICAL
|
||||||
|
)
|
||||||
mLayoutManager.gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
|
mLayoutManager.gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
|
||||||
} else {
|
} else {
|
||||||
mLayoutManager = GridLayoutManager(this, calculateNoOfColumns())
|
mLayoutManager = GridLayoutManager(this, calculateNoOfColumns())
|
||||||
@ -616,18 +663,19 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleInfiniteScroll() {
|
private fun handleInfiniteScroll() {
|
||||||
if (recyclerViewScrollListener == null)
|
if (recyclerViewScrollListener == null) {
|
||||||
recyclerViewScrollListener = object : RecyclerView.OnScrollListener() {
|
recyclerViewScrollListener = object : RecyclerView.OnScrollListener() {
|
||||||
override fun onScrolled(localRecycler: RecyclerView?, dx: Int, dy: Int) {
|
override fun onScrolled(localRecycler: RecyclerView?, dx: Int, dy: Int) {
|
||||||
if (localRecycler != null && dy > 0) {
|
if (localRecycler != null && dy > 0) {
|
||||||
val manager = recyclerView.layoutManager
|
val manager = recyclerView.layoutManager
|
||||||
val lastVisibleItem: Int = when (manager) {
|
val lastVisibleItem: Int = when (manager) {
|
||||||
is StaggeredGridLayoutManager -> manager.findLastCompletelyVisibleItemPositions(null).last()
|
is StaggeredGridLayoutManager -> manager.findLastCompletelyVisibleItemPositions(
|
||||||
|
null
|
||||||
|
).last()
|
||||||
is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition()
|
is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition()
|
||||||
else -> 0
|
else -> 0
|
||||||
}
|
}
|
||||||
@ -638,6 +686,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
recyclerView.clearOnScrollListeners()
|
recyclerView.clearOnScrollListeners()
|
||||||
recyclerView.addOnScrollListener(recyclerViewScrollListener)
|
recyclerView.addOnScrollListener(recyclerViewScrollListener)
|
||||||
@ -652,8 +701,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
recyclerView.visibility = View.VISIBLE
|
recyclerView.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getElementsAccordingToTab(appendResults: Boolean = false, offsetOverride: Int? = null) {
|
private fun getElementsAccordingToTab(
|
||||||
offset = if (appendResults && offsetOverride === null) {
|
appendResults: Boolean = false,
|
||||||
|
offsetOverride: Int? = null
|
||||||
|
) {
|
||||||
|
offset = if (appendResults && offsetOverride === null) {
|
||||||
(offset + itemsNumber)
|
(offset + itemsNumber)
|
||||||
} else {
|
} else {
|
||||||
offsetOverride ?: 0
|
offsetOverride ?: 0
|
||||||
@ -668,66 +720,107 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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>>) {
|
||||||
val didUpdate = (response.body() != items)
|
val didUpdate = (response.body() != items)
|
||||||
if (response.body() != null) {
|
if (response.body() != null) {
|
||||||
if (response.body() != items) {
|
if (response.body() != items) {
|
||||||
if (appendResults)
|
if (appendResults) {
|
||||||
items.addAll(response.body() as ArrayList<Item>)
|
items.addAll(response.body() as ArrayList<Item>)
|
||||||
else
|
} else {
|
||||||
items = response.body() as ArrayList<Item>
|
items = response.body() as ArrayList<Item>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!appendResults)
|
if (!appendResults) {
|
||||||
items = ArrayList()
|
items = ArrayList()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (didUpdate)
|
if (didUpdate) {
|
||||||
handleListResult(appendResults)
|
handleListResult(appendResults)
|
||||||
|
}
|
||||||
|
|
||||||
mayBeEmpty()
|
mayBeEmpty()
|
||||||
swipeRefreshLayout.isRefreshing = false
|
swipeRefreshLayout.isRefreshing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!swipeRefreshLayout.isRefreshing)
|
if (!swipeRefreshLayout.isRefreshing) {
|
||||||
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) {
|
||||||
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) {
|
||||||
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) {
|
||||||
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
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleListResult(appendResults: Boolean = false) {
|
private fun handleListResult(appendResults: Boolean = false) {
|
||||||
if (appendResults) {
|
if (appendResults) {
|
||||||
val oldManager = recyclerView.layoutManager
|
val oldManager = recyclerView.layoutManager
|
||||||
firstVisible = if ((oldManager is StaggeredGridLayoutManager)) {
|
firstVisible = when (oldManager) {
|
||||||
oldManager.findFirstCompletelyVisibleItemPositions(null).last()
|
is StaggeredGridLayoutManager ->
|
||||||
|
oldManager.findFirstCompletelyVisibleItemPositions(null).last()
|
||||||
|
is GridLayoutManager ->
|
||||||
|
oldManager.findFirstCompletelyVisibleItemPosition()
|
||||||
|
else -> 0
|
||||||
}
|
}
|
||||||
else
|
|
||||||
(oldManager as GridLayoutManager)?.findFirstCompletelyVisibleItemPosition()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadLayoutManager()
|
reloadLayoutManager()
|
||||||
@ -745,7 +838,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
fullHeightCards,
|
fullHeightCards,
|
||||||
appColors,
|
appColors,
|
||||||
debugReadingItems,
|
debugReadingItems,
|
||||||
userIdentifier)
|
userIdentifier
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
mAdapter =
|
mAdapter =
|
||||||
ItemListAdapter(
|
ItemListAdapter(
|
||||||
@ -757,10 +851,15 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
internalBrowser,
|
internalBrowser,
|
||||||
articleViewer,
|
articleViewer,
|
||||||
debugReadingItems,
|
debugReadingItems,
|
||||||
userIdentifier)
|
userIdentifier
|
||||||
|
)
|
||||||
|
|
||||||
recyclerView.addItemDecoration(DividerItemDecoration(this@HomeActivity,
|
recyclerView.addItemDecoration(
|
||||||
DividerItemDecoration.VERTICAL))
|
DividerItemDecoration(
|
||||||
|
this@HomeActivity,
|
||||||
|
DividerItemDecoration.VERTICAL
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
recyclerView.adapter = mAdapter
|
recyclerView.adapter = mAdapter
|
||||||
mAdapter.notifyDataSetChanged()
|
mAdapter.notifyDataSetChanged()
|
||||||
@ -785,7 +884,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<Stats>, t: Throwable) {}
|
override fun onFailure(call: Call<Stats>, t: Throwable) {
|
||||||
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
reloadBadgeContent(succeeded = false)
|
reloadBadgeContent(succeeded = false)
|
||||||
@ -794,10 +894,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
|
|
||||||
private fun reloadBadgeContent(succeeded: Boolean = true) {
|
private fun reloadBadgeContent(succeeded: Boolean = true) {
|
||||||
if (succeeded) {
|
if (succeeded) {
|
||||||
if (displayUnreadCount)
|
if (displayUnreadCount) {
|
||||||
tabNewBadge
|
tabNewBadge
|
||||||
.setText(badgeNew.toString())
|
.setText(badgeNew.toString())
|
||||||
.maybeShow()
|
.maybeShow()
|
||||||
|
}
|
||||||
if (displayAllCount) {
|
if (displayAllCount) {
|
||||||
tabArchiveBadge
|
tabArchiveBadge
|
||||||
.setText(badgeAll.toString())
|
.setText(badgeAll.toString())
|
||||||
@ -851,7 +952,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
}
|
}
|
||||||
else -> super.onActivityResult(req, result, data)
|
else -> super.onActivityResult(req, result, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
@ -869,14 +969,23 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.refresh -> {
|
R.id.refresh -> {
|
||||||
api.update().enqueue(object : Callback<String> {
|
api.update().enqueue(object : Callback<String> {
|
||||||
override fun onResponse(call: Call<String>, response: Response<String>) {
|
override fun onResponse(
|
||||||
Toast.makeText(this@HomeActivity,
|
call: Call<String>,
|
||||||
R.string.refresh_success_response, Toast.LENGTH_LONG)
|
response: Response<String>
|
||||||
|
) {
|
||||||
|
Toast.makeText(
|
||||||
|
this@HomeActivity,
|
||||||
|
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) {
|
||||||
Toast.makeText(this@HomeActivity, R.string.refresh_failer_message, Toast.LENGTH_SHORT).show()
|
Toast.makeText(
|
||||||
|
this@HomeActivity,
|
||||||
|
R.string.refresh_failer_message,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
Toast.makeText(this, R.string.refresh_in_progress, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.refresh_in_progress, Toast.LENGTH_SHORT).show()
|
||||||
@ -888,25 +997,45 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
val ids = items.map { it.id }
|
val ids = items.map { it.id }
|
||||||
|
|
||||||
api.readAll(ids).enqueue(object : Callback<SuccessResponse> {
|
api.readAll(ids).enqueue(object : Callback<SuccessResponse> {
|
||||||
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
|
override fun onResponse(
|
||||||
|
call: Call<SuccessResponse>,
|
||||||
|
response: Response<SuccessResponse>
|
||||||
|
) {
|
||||||
if (response.body() != null && response.body()!!.isSuccess) {
|
if (response.body() != null && response.body()!!.isSuccess) {
|
||||||
Toast.makeText(this@HomeActivity, R.string.all_posts_read, Toast.LENGTH_SHORT).show()
|
Toast.makeText(
|
||||||
|
this@HomeActivity,
|
||||||
|
R.string.all_posts_read,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
tabNewBadge.removeBadge()
|
tabNewBadge.removeBadge()
|
||||||
|
} else {
|
||||||
|
Toast.makeText(
|
||||||
|
this@HomeActivity,
|
||||||
|
R.string.all_posts_not_read,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
}
|
}
|
||||||
else
|
|
||||||
Toast.makeText(this@HomeActivity, R.string.all_posts_not_read, Toast.LENGTH_SHORT).show()
|
|
||||||
|
|
||||||
swipeRefreshLayout.isRefreshing = false
|
swipeRefreshLayout.isRefreshing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
||||||
Toast.makeText(this@HomeActivity, R.string.all_posts_not_read, Toast.LENGTH_SHORT).show()
|
Toast.makeText(
|
||||||
|
this@HomeActivity,
|
||||||
|
R.string.all_posts_not_read,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
swipeRefreshLayout.isRefreshing = false
|
swipeRefreshLayout.isRefreshing = false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
items = ArrayList()
|
items = ArrayList()
|
||||||
if (items.isEmpty())
|
if (items.isEmpty()) {
|
||||||
Toast.makeText(this@HomeActivity, R.string.nothing_here, Toast.LENGTH_SHORT).show()
|
Toast.makeText(
|
||||||
|
this@HomeActivity,
|
||||||
|
R.string.nothing_here,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
handleListResult()
|
handleListResult()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -939,10 +1068,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun maxItemNumber(): Int =
|
private fun maxItemNumber(): Int =
|
||||||
when (elementsShown) {
|
when (elementsShown) {
|
||||||
UNREAD_SHOWN -> badgeNew
|
UNREAD_SHOWN -> badgeNew
|
||||||
READ_SHOWN -> badgeAll
|
READ_SHOWN -> badgeAll
|
||||||
FAV_SHOWN -> badgeFavs
|
FAV_SHOWN -> badgeFavs
|
||||||
else -> badgeNew // if !elementsShown then unread are fetched.
|
else -> badgeNew // if !elementsShown then unread are fetched.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ import android.preference.PreferenceManager
|
|||||||
import android.support.v7.app.AppCompatDelegate
|
import android.support.v7.app.AppCompatDelegate
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
|
||||||
|
|
||||||
class IntroActivity : MaterialIntroActivity() {
|
class IntroActivity : MaterialIntroActivity() {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@ -18,33 +17,44 @@ class IntroActivity : MaterialIntroActivity() {
|
|||||||
|
|
||||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
||||||
|
|
||||||
addSlide(SlideFragmentBuilder()
|
addSlide(
|
||||||
.backgroundColor(R.color.colorPrimary)
|
SlideFragmentBuilder()
|
||||||
.buttonsColor(R.color.colorAccent)
|
.backgroundColor(R.color.colorPrimary)
|
||||||
.image(R.drawable.web_hi_res_512)
|
.buttonsColor(R.color.colorAccent)
|
||||||
.title(getString(R.string.intro_hello_title))
|
.image(R.drawable.web_hi_res_512)
|
||||||
.description(getString(R.string.intro_hello_message))
|
.title(getString(R.string.intro_hello_title))
|
||||||
.build())
|
.description(getString(R.string.intro_hello_message))
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
|
||||||
addSlide(SlideFragmentBuilder()
|
addSlide(
|
||||||
.backgroundColor(R.color.colorAccent)
|
SlideFragmentBuilder()
|
||||||
.buttonsColor(R.color.colorPrimary)
|
.backgroundColor(R.color.colorAccent)
|
||||||
.image(R.drawable.ic_info_outline_white_48px)
|
.buttonsColor(R.color.colorPrimary)
|
||||||
.title(getString(R.string.intro_needs_selfoss_title))
|
.image(R.drawable.ic_info_outline_white_48px)
|
||||||
.description(getString(R.string.intro_needs_selfoss_message))
|
.title(getString(R.string.intro_needs_selfoss_title))
|
||||||
.build(),
|
.description(getString(R.string.intro_needs_selfoss_message))
|
||||||
MessageButtonBehaviour(View.OnClickListener {
|
.build(),
|
||||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://selfoss.aditu.de"))
|
MessageButtonBehaviour(
|
||||||
startActivity(browserIntent)
|
View.OnClickListener {
|
||||||
}, getString(R.string.intro_needs_selfoss_link)))
|
val browserIntent = Intent(
|
||||||
|
Intent.ACTION_VIEW,
|
||||||
|
Uri.parse("https://selfoss.aditu.de")
|
||||||
|
)
|
||||||
|
startActivity(browserIntent)
|
||||||
|
}, getString(R.string.intro_needs_selfoss_link)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
addSlide(SlideFragmentBuilder()
|
addSlide(
|
||||||
.backgroundColor(R.color.colorPrimaryDark)
|
SlideFragmentBuilder()
|
||||||
.buttonsColor(R.color.colorAccentDark)
|
.backgroundColor(R.color.colorPrimaryDark)
|
||||||
.image(R.drawable.ic_thumb_up_white_48px)
|
.buttonsColor(R.color.colorAccentDark)
|
||||||
.title(getString(R.string.intro_all_set_title))
|
.image(R.drawable.ic_thumb_up_white_48px)
|
||||||
.description(getString(R.string.intro_all_set_message))
|
.title(getString(R.string.intro_all_set_title))
|
||||||
.build())
|
.description(getString(R.string.intro_all_set_message))
|
||||||
|
.build()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFinish() {
|
override fun onFinish() {
|
||||||
|
@ -8,7 +8,6 @@ import android.content.SharedPreferences
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.support.v7.app.AlertDialog
|
import android.support.v7.app.AlertDialog
|
||||||
import android.support.v7.app.AppCompatActivity
|
import android.support.v7.app.AppCompatActivity
|
||||||
import android.support.v7.widget.Toolbar
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
@ -25,12 +24,10 @@ import com.ftinc.scoop.Scoop
|
|||||||
import com.google.firebase.analytics.FirebaseAnalytics
|
import com.google.firebase.analytics.FirebaseAnalytics
|
||||||
import com.mikepenz.aboutlibraries.Libs
|
import com.mikepenz.aboutlibraries.Libs
|
||||||
import com.mikepenz.aboutlibraries.LibsBuilder
|
import com.mikepenz.aboutlibraries.LibsBuilder
|
||||||
|
import kotlinx.android.synthetic.main.activity_login.*
|
||||||
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() {
|
||||||
|
|
||||||
@ -45,8 +42,6 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
private lateinit var userIdentifier: String
|
private lateinit var userIdentifier: String
|
||||||
private var logErrors: Boolean = false
|
private var logErrors: Boolean = false
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
Scoop.getInstance().apply(this)
|
Scoop.getInstance().apply(this)
|
||||||
@ -81,13 +76,15 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
warningText.visibility = visi
|
warningText.visibility = visi
|
||||||
}
|
}
|
||||||
|
|
||||||
passwordView.setOnEditorActionListener(TextView.OnEditorActionListener { _, id, _ ->
|
passwordView.setOnEditorActionListener(
|
||||||
if (id == R.id.loginView || id == EditorInfo.IME_NULL) {
|
TextView.OnEditorActionListener { _, id, _ ->
|
||||||
attemptLogin()
|
if (id == R.id.loginView || id == EditorInfo.IME_NULL) {
|
||||||
return@OnEditorActionListener true
|
attemptLogin()
|
||||||
}
|
return@OnEditorActionListener true
|
||||||
false
|
}
|
||||||
})
|
false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
signInButton.setOnClickListener { attemptLogin() }
|
signInButton.setOnClickListener { attemptLogin() }
|
||||||
|
|
||||||
@ -116,7 +113,8 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
alertDialog.setButton(
|
alertDialog.setButton(
|
||||||
AlertDialog.BUTTON_NEUTRAL,
|
AlertDialog.BUTTON_NEUTRAL,
|
||||||
"OK",
|
"OK",
|
||||||
{ dialog, _ -> dialog.dismiss() })
|
{ dialog, _ -> dialog.dismiss() }
|
||||||
|
)
|
||||||
alertDialog.show()
|
alertDialog.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,7 +156,8 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
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
|
||||||
}
|
}
|
||||||
@ -191,7 +190,12 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
editor.putBoolean("isSelfSignedCert", isWithSelfSignedCert)
|
editor.putBoolean("isSelfSignedCert", isWithSelfSignedCert)
|
||||||
editor.apply()
|
editor.apply()
|
||||||
|
|
||||||
val api = SelfossApi(this, this@LoginActivity, isWithSelfSignedCert, isWithSelfSignedCert)
|
val api = SelfossApi(
|
||||||
|
this,
|
||||||
|
this@LoginActivity,
|
||||||
|
isWithSelfSignedCert,
|
||||||
|
isWithSelfSignedCert
|
||||||
|
)
|
||||||
api.login().enqueue(object : Callback<SuccessResponse> {
|
api.login().enqueue(object : Callback<SuccessResponse> {
|
||||||
private fun preferenceError(t: Throwable) {
|
private fun preferenceError(t: Throwable) {
|
||||||
editor.remove("url")
|
editor.remove("url")
|
||||||
@ -209,12 +213,19 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
Crashlytics.setUserIdentifier(userIdentifier)
|
Crashlytics.setUserIdentifier(userIdentifier)
|
||||||
Crashlytics.log(100, "LOGIN_DEBUG_ERRROR", t.message)
|
Crashlytics.log(100, "LOGIN_DEBUG_ERRROR", t.message)
|
||||||
Crashlytics.logException(t)
|
Crashlytics.logException(t)
|
||||||
Toast.makeText(this@LoginActivity, t.message, Toast.LENGTH_LONG).show()
|
Toast.makeText(
|
||||||
|
this@LoginActivity,
|
||||||
|
t.message,
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
).show()
|
||||||
}
|
}
|
||||||
showProgress(false)
|
showProgress(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
firebaseAnalytics.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle())
|
firebaseAnalytics.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle())
|
||||||
goToMain()
|
goToMain()
|
||||||
@ -230,7 +241,6 @@ 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)
|
||||||
|
|
||||||
@ -241,10 +251,11 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
.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) {
|
||||||
loginForm.visibility = if (show) View.GONE else View.VISIBLE
|
loginForm.visibility = if (show) View.GONE else View.VISIBLE
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
loginProgress.visibility = if (show) View.VISIBLE else View.GONE
|
loginProgress.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
loginProgress
|
loginProgress
|
||||||
@ -253,10 +264,11 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
.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) {
|
||||||
loginProgress.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 {
|
||||||
|
@ -5,15 +5,16 @@ import android.os.Bundle
|
|||||||
import android.preference.PreferenceManager
|
import android.preference.PreferenceManager
|
||||||
import android.support.v7.app.AppCompatActivity
|
import android.support.v7.app.AppCompatActivity
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
if (PreferenceManager.getDefaultSharedPreferences(baseContext).getBoolean("firstStart", true)) {
|
if (PreferenceManager.getDefaultSharedPreferences(baseContext).getBoolean(
|
||||||
|
"firstStart",
|
||||||
|
true
|
||||||
|
)) {
|
||||||
val i = Intent(this@MainActivity, IntroActivity::class.java)
|
val i = Intent(this@MainActivity, IntroActivity::class.java)
|
||||||
startActivity(i)
|
startActivity(i)
|
||||||
} else {
|
} else {
|
||||||
@ -22,6 +23,5 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
finish()
|
finish()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,6 @@ import io.fabric.sdk.android.Fabric
|
|||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.UUID.randomUUID
|
import java.util.UUID.randomUUID
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MyApp : MultiDexApplication() {
|
class MyApp : MultiDexApplication() {
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
@ -46,14 +43,13 @@ class MyApp : MultiDexApplication() {
|
|||||||
initTheme()
|
initTheme()
|
||||||
|
|
||||||
tryToHandleBug()
|
tryToHandleBug()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initAmplify() {
|
private fun initAmplify() {
|
||||||
Amplify.initSharedInstance(this)
|
Amplify.initSharedInstance(this)
|
||||||
.setPositiveFeedbackCollectors(GooglePlayStoreFeedbackCollector())
|
.setPositiveFeedbackCollectors(GooglePlayStoreFeedbackCollector())
|
||||||
.setCriticalFeedbackCollectors(DefaultEmailFeedbackCollector(BuildConfig.FEEDBACK_EMAIL))
|
.setCriticalFeedbackCollectors(DefaultEmailFeedbackCollector(BuildConfig.FEEDBACK_EMAIL))
|
||||||
.applyAllDefaultRules()
|
.applyAllDefaultRules()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initCache() {
|
private fun initCache() {
|
||||||
@ -66,12 +62,16 @@ class MyApp : MultiDexApplication() {
|
|||||||
|
|
||||||
private fun initDrawerImageLoader() {
|
private fun initDrawerImageLoader() {
|
||||||
DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
|
DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
|
||||||
override fun set(imageView: ImageView?, uri: Uri?, placeholder: Drawable?, tag: String?) {
|
override fun set(
|
||||||
|
imageView: ImageView?,
|
||||||
|
uri: Uri?,
|
||||||
|
placeholder: Drawable?,
|
||||||
|
tag: String?
|
||||||
|
) {
|
||||||
Glide.with(imageView?.context)
|
Glide.with(imageView?.context)
|
||||||
.load(uri)
|
.load(uri)
|
||||||
.apply(RequestOptions.fitCenterTransform()
|
.apply(RequestOptions.fitCenterTransform().placeholder(placeholder))
|
||||||
.placeholder(placeholder))
|
.into(imageView)
|
||||||
.into(imageView)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cancel(imageView: ImageView?) {
|
override fun cancel(imageView: ImageView?) {
|
||||||
@ -86,33 +86,35 @@ class MyApp : MultiDexApplication() {
|
|||||||
|
|
||||||
private fun initTheme() {
|
private fun initTheme() {
|
||||||
Scoop.waffleCone()
|
Scoop.waffleCone()
|
||||||
.addFlavor(getString(R.string.default_theme), R.style.NoBar, true)
|
.addFlavor(getString(R.string.default_theme), R.style.NoBar, true)
|
||||||
.addFlavor(getString(R.string.default_dark_theme), R.style.NoBarDark)
|
.addFlavor(getString(R.string.default_dark_theme), R.style.NoBarDark)
|
||||||
.addFlavor(getString(R.string.teal_orange_theme), R.style.NoBarTealOrange)
|
.addFlavor(getString(R.string.teal_orange_theme), R.style.NoBarTealOrange)
|
||||||
.addFlavor(getString(R.string.teal_orange_dark_theme), R.style.NoBarTealOrangeDark)
|
.addFlavor(getString(R.string.teal_orange_dark_theme), R.style.NoBarTealOrangeDark)
|
||||||
.addFlavor(getString(R.string.cyan_pink_theme), R.style.NoBarCyanPink)
|
.addFlavor(getString(R.string.cyan_pink_theme), R.style.NoBarCyanPink)
|
||||||
.addFlavor(getString(R.string.cyan_pink_dark_theme), R.style.NoBarCyanPinkDark)
|
.addFlavor(getString(R.string.cyan_pink_dark_theme), R.style.NoBarCyanPinkDark)
|
||||||
.addFlavor(getString(R.string.grey_orange_theme), R.style.NoBarGreyOrange)
|
.addFlavor(getString(R.string.grey_orange_theme), R.style.NoBarGreyOrange)
|
||||||
.addFlavor(getString(R.string.grey_orange_dark_theme), R.style.NoBarGreyOrangeDark)
|
.addFlavor(getString(R.string.grey_orange_dark_theme), R.style.NoBarGreyOrangeDark)
|
||||||
.addFlavor(getString(R.string.blue_amber_theme), R.style.NoBarBlueAmber)
|
.addFlavor(getString(R.string.blue_amber_theme), R.style.NoBarBlueAmber)
|
||||||
.addFlavor(getString(R.string.blue_amber_dark_theme), R.style.NoBarBlueAmberDark)
|
.addFlavor(getString(R.string.blue_amber_dark_theme), R.style.NoBarBlueAmberDark)
|
||||||
.addFlavor(getString(R.string.indigo_pink_theme), R.style.NoBarIndigoPink)
|
.addFlavor(getString(R.string.indigo_pink_theme), R.style.NoBarIndigoPink)
|
||||||
.addFlavor(getString(R.string.indigo_pink_dark_theme), R.style.NoBarIndigoPinkDark)
|
.addFlavor(getString(R.string.indigo_pink_dark_theme), R.style.NoBarIndigoPinkDark)
|
||||||
.addFlavor(getString(R.string.red_teal_theme), R.style.NoBarRedTeal)
|
.addFlavor(getString(R.string.red_teal_theme), R.style.NoBarRedTeal)
|
||||||
.addFlavor(getString(R.string.red_teal_dark_theme), R.style.NoBarRedTealDark)
|
.addFlavor(getString(R.string.red_teal_dark_theme), R.style.NoBarRedTealDark)
|
||||||
.setSharedPreferences(PreferenceManager.getDefaultSharedPreferences(this))
|
.setSharedPreferences(PreferenceManager.getDefaultSharedPreferences(this))
|
||||||
.initialize()
|
.initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun tryToHandleBug() {
|
private fun tryToHandleBug() {
|
||||||
val oldHandler = Thread.getDefaultUncaughtExceptionHandler()
|
val oldHandler = Thread.getDefaultUncaughtExceptionHandler()
|
||||||
|
|
||||||
Thread.setDefaultUncaughtExceptionHandler { thread, e ->
|
Thread.setDefaultUncaughtExceptionHandler { thread, e ->
|
||||||
if (e is java.lang.NoClassDefFoundError && e.stackTrace.asList().any { it.toString().contains("android.view.ViewDebug") })
|
if (e is java.lang.NoClassDefFoundError && e.stackTrace.asList().any {
|
||||||
|
it.toString().contains("android.view.ViewDebug")
|
||||||
|
}) {
|
||||||
Unit
|
Unit
|
||||||
else
|
} else {
|
||||||
oldHandler.uncaughtException(thread, e)
|
oldHandler.uncaughtException(thread, e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -23,12 +23,11 @@ import com.bumptech.glide.request.RequestOptions
|
|||||||
import com.crashlytics.android.Crashlytics
|
import com.crashlytics.android.Crashlytics
|
||||||
import com.ftinc.scoop.Scoop
|
import com.ftinc.scoop.Scoop
|
||||||
import com.github.rubensousa.floatingtoolbar.FloatingToolbar
|
import com.github.rubensousa.floatingtoolbar.FloatingToolbar
|
||||||
|
import kotlinx.android.synthetic.main.activity_reader.*
|
||||||
import org.sufficientlysecure.htmltextview.HtmlHttpImageGetter
|
import org.sufficientlysecure.htmltextview.HtmlHttpImageGetter
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.Callback
|
import retrofit2.Callback
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
import kotlinx.android.synthetic.main.activity_reader.*
|
|
||||||
|
|
||||||
|
|
||||||
class ReaderActivity : AppCompatActivity() {
|
class ReaderActivity : AppCompatActivity() {
|
||||||
private lateinit var mCustomTabActivityHelper: CustomTabActivityHelper
|
private lateinit var mCustomTabActivityHelper: CustomTabActivityHelper
|
||||||
@ -40,7 +39,6 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
private lateinit var contentTitle: String
|
private lateinit var contentTitle: String
|
||||||
private lateinit var fab: FloatingActionButton
|
private lateinit var fab: FloatingActionButton
|
||||||
|
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
super.onStop()
|
super.onStop()
|
||||||
mCustomTabActivityHelper.unbindCustomTabsService(this)
|
mCustomTabActivityHelper.unbindCustomTabsService(this)
|
||||||
@ -81,7 +79,8 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
customTabsIntent,
|
customTabsIntent,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
this@ReaderActivity)
|
this@ReaderActivity
|
||||||
|
)
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,23 +110,34 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nestedScrollView.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
nestedScrollView.setOnScrollChangeListener(
|
||||||
if (scrollY > oldScrollY) {
|
NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
||||||
fab.hide()
|
if (scrollY > oldScrollY) {
|
||||||
} else {
|
fab.hide()
|
||||||
if (mFloatingToolbar.isShowing) mFloatingToolbar.hide() else fab.show()
|
} else {
|
||||||
}
|
if (mFloatingToolbar.isShowing) mFloatingToolbar.hide() else fab.show()
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
content.movementMethod = LinkMovementMethod.getInstance()
|
content.movementMethod = LinkMovementMethod.getInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getContentFromMercury(customTabsIntent: CustomTabsIntent, prefs: SharedPreferences) {
|
private fun getContentFromMercury(
|
||||||
|
customTabsIntent: CustomTabsIntent,
|
||||||
|
prefs: SharedPreferences
|
||||||
|
) {
|
||||||
progressBar.visibility = View.VISIBLE
|
progressBar.visibility = View.VISIBLE
|
||||||
val parser = MercuryApi(BuildConfig.MERCURY_KEY, prefs.getBoolean("should_log_everything", false))
|
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
|
||||||
titleView.text = response.body()!!.title
|
titleView.text = response.body()!!.title
|
||||||
@ -152,14 +162,23 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
nestedScrollView.scrollTo(0, 0)
|
nestedScrollView.scrollTo(0, 0)
|
||||||
|
|
||||||
progressBar.visibility = View.GONE
|
progressBar.visibility = View.GONE
|
||||||
} else openInBrowserAfterFailing(customTabsIntent)
|
} else {
|
||||||
|
openInBrowserAfterFailing(customTabsIntent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<ParsedContent>, t: Throwable) = openInBrowserAfterFailing(customTabsIntent)
|
override fun onFailure(
|
||||||
|
call: Call<ParsedContent>,
|
||||||
|
t: Throwable
|
||||||
|
) = openInBrowserAfterFailing(customTabsIntent)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun tryToHandleHtml(c: String, customTabsIntent: CustomTabsIntent, prefs: SharedPreferences) {
|
private fun tryToHandleHtml(
|
||||||
|
c: String,
|
||||||
|
customTabsIntent: CustomTabsIntent,
|
||||||
|
prefs: SharedPreferences
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
content.text = Html.fromHtml(c, HtmlHttpImageGetter(content, null, true), null)
|
content.text = Html.fromHtml(c, HtmlHttpImageGetter(content, null, true), null)
|
||||||
|
|
||||||
|
@ -10,14 +10,13 @@ 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 kotlinx.android.synthetic.main.activity_sources.*
|
||||||
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)
|
||||||
@ -39,25 +38,43 @@ class SourcesActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
|
||||||
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()
|
||||||
|
|
||||||
recyclerView.setHasFixedSize(true)
|
recyclerView.setHasFixedSize(true)
|
||||||
recyclerView.layoutManager = mLayoutManager
|
recyclerView.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>>
|
||||||
|
) {
|
||||||
if (response.body() != null && response.body()!!.isNotEmpty()) {
|
if (response.body() != null && response.body()!!.isNotEmpty()) {
|
||||||
items = response.body() as ArrayList<Sources>
|
items = response.body() as ArrayList<Sources>
|
||||||
}
|
}
|
||||||
val mAdapter = SourcesListAdapter(this@SourcesActivity, items, api)
|
val mAdapter = SourcesListAdapter(this@SourcesActivity, items, api)
|
||||||
recyclerView.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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<List<Sources>>, t: Throwable) {
|
override fun onFailure(call: Call<List<Sources>>, t: Throwable) {
|
||||||
Toast.makeText(this@SourcesActivity, R.string.cant_get_sources, Toast.LENGTH_SHORT).show()
|
Toast.makeText(
|
||||||
|
this@SourcesActivity,
|
||||||
|
R.string.cant_get_sources,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -33,21 +33,23 @@ import com.bumptech.glide.Glide
|
|||||||
import com.crashlytics.android.Crashlytics
|
import com.crashlytics.android.Crashlytics
|
||||||
import com.like.LikeButton
|
import com.like.LikeButton
|
||||||
import com.like.OnLikeListener
|
import com.like.OnLikeListener
|
||||||
|
import kotlinx.android.synthetic.main.card_item.view.*
|
||||||
import 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 items: ArrayList<Item>,
|
private val app: Activity,
|
||||||
private val api: SelfossApi,
|
private val items: ArrayList<Item>,
|
||||||
private val helper: CustomTabActivityHelper,
|
private val api: SelfossApi,
|
||||||
private val internalBrowser: Boolean,
|
private val helper: CustomTabActivityHelper,
|
||||||
private val articleViewer: Boolean,
|
private val internalBrowser: Boolean,
|
||||||
private val fullHeightCards: Boolean,
|
private val articleViewer: Boolean,
|
||||||
private val appColors: AppColors,
|
private val fullHeightCards: Boolean,
|
||||||
val debugReadingItems: Boolean,
|
private val appColors: AppColors,
|
||||||
val userIdentifier: String) : RecyclerView.Adapter<ItemCardAdapter.ViewHolder>() {
|
val debugReadingItems: Boolean,
|
||||||
|
val userIdentifier: String
|
||||||
|
) : RecyclerView.Adapter<ItemCardAdapter.ViewHolder>() {
|
||||||
private val c: Context = app.baseContext
|
private val c: Context = app.baseContext
|
||||||
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
||||||
|
|
||||||
@ -94,13 +96,21 @@ class ItemCardAdapter(private val app: Activity,
|
|||||||
|
|
||||||
private fun doUnmark(i: Item, position: Int) {
|
private fun doUnmark(i: Item, position: Int) {
|
||||||
val s = Snackbar
|
val s = Snackbar
|
||||||
.make(app.findViewById(R.id.coordLayout), R.string.marked_as_read, Snackbar.LENGTH_LONG)
|
.make(
|
||||||
|
app.findViewById(R.id.coordLayout),
|
||||||
|
R.string.marked_as_read,
|
||||||
|
Snackbar.LENGTH_LONG
|
||||||
|
)
|
||||||
.setAction(R.string.undo_string) {
|
.setAction(R.string.undo_string) {
|
||||||
items.add(position, i)
|
items.add(position, i)
|
||||||
notifyItemInserted(position)
|
notifyItemInserted(position)
|
||||||
|
|
||||||
api.unmarkItem(i.id).enqueue(object : Callback<SuccessResponse> {
|
api.unmarkItem(i.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) {
|
||||||
items.remove(i)
|
items.remove(i)
|
||||||
@ -124,7 +134,10 @@ class ItemCardAdapter(private val app: Activity,
|
|||||||
notifyItemRemoved(position)
|
notifyItemRemoved(position)
|
||||||
|
|
||||||
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
|
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
|
||||||
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
|
override fun onResponse(
|
||||||
|
call: Call<SuccessResponse>,
|
||||||
|
response: Response<SuccessResponse>
|
||||||
|
) {
|
||||||
if (!response.succeeded() && debugReadingItems) {
|
if (!response.succeeded() && debugReadingItems) {
|
||||||
val message =
|
val message =
|
||||||
"message: ${response.message()} " +
|
"message: ${response.message()} " +
|
||||||
@ -150,12 +163,15 @@ class ItemCardAdapter(private val app: Activity,
|
|||||||
Crashlytics.logException(t)
|
Crashlytics.logException(t)
|
||||||
Toast.makeText(c, t.message, Toast.LENGTH_LONG).show()
|
Toast.makeText(c, t.message, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
Toast.makeText(app, app.getString(R.string.cant_mark_read), Toast.LENGTH_SHORT).show()
|
Toast.makeText(
|
||||||
|
app,
|
||||||
|
app.getString(R.string.cant_mark_read),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
items.add(i)
|
items.add(i)
|
||||||
notifyItemInserted(position)
|
notifyItemInserted(position)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ViewHolder(val mView: CardView) : RecyclerView.ViewHolder(mView) {
|
inner class ViewHolder(val mView: CardView) : RecyclerView.ViewHolder(mView) {
|
||||||
@ -176,11 +192,22 @@ class ItemCardAdapter(private val app: Activity,
|
|||||||
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
|
||||||
|
) {
|
||||||
mView.favButton.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()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -188,11 +215,22 @@ class ItemCardAdapter(private val app: Activity,
|
|||||||
override fun unLiked(likeButton: LikeButton) {
|
override fun unLiked(likeButton: LikeButton) {
|
||||||
val (id) = items[adapterPosition]
|
val (id) = items[adapterPosition]
|
||||||
api.unstarrItem(id).enqueue(object : Callback<SuccessResponse> {
|
api.unstarrItem(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
|
||||||
|
) {
|
||||||
mView.favButton.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()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -212,7 +250,8 @@ class ItemCardAdapter(private val app: Activity,
|
|||||||
helper.bindCustomTabsService(app)
|
helper.bindCustomTabsService(app)
|
||||||
|
|
||||||
mView.setOnClickListener {
|
mView.setOnClickListener {
|
||||||
c.openItemUrl(items[adapterPosition].getLinkDecoded(),
|
c.openItemUrl(
|
||||||
|
items[adapterPosition].getLinkDecoded(),
|
||||||
items[adapterPosition].content,
|
items[adapterPosition].content,
|
||||||
items[adapterPosition].getThumbnail(c),
|
items[adapterPosition].getThumbnail(c),
|
||||||
items[adapterPosition].title,
|
items[adapterPosition].title,
|
||||||
@ -220,7 +259,8 @@ class ItemCardAdapter(private val app: Activity,
|
|||||||
customTabsIntent,
|
customTabsIntent,
|
||||||
internalBrowser,
|
internalBrowser,
|
||||||
articleViewer,
|
articleViewer,
|
||||||
app)
|
app
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package apps.amine.bou.readerforselfoss.adapters
|
package apps.amine.bou.readerforselfoss.adapters
|
||||||
|
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
@ -32,28 +31,34 @@ import com.amulyakhare.textdrawable.util.ColorGenerator
|
|||||||
import com.crashlytics.android.Crashlytics
|
import com.crashlytics.android.Crashlytics
|
||||||
import com.like.LikeButton
|
import com.like.LikeButton
|
||||||
import com.like.OnLikeListener
|
import com.like.OnLikeListener
|
||||||
|
import kotlinx.android.synthetic.main.list_item.view.*
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.Callback
|
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 items: ArrayList<Item>,
|
private val app: Activity,
|
||||||
private val api: SelfossApi,
|
private val items: ArrayList<Item>,
|
||||||
private val helper: CustomTabActivityHelper,
|
private val api: SelfossApi,
|
||||||
private val clickBehavior: Boolean,
|
private val helper: CustomTabActivityHelper,
|
||||||
private val internalBrowser: Boolean,
|
private val clickBehavior: Boolean,
|
||||||
private val articleViewer: Boolean,
|
private val internalBrowser: Boolean,
|
||||||
val debugReadingItems: Boolean,
|
private val articleViewer: Boolean,
|
||||||
val userIdentifier: String) : RecyclerView.Adapter<ItemListAdapter.ViewHolder>() {
|
val debugReadingItems: Boolean,
|
||||||
|
val userIdentifier: String
|
||||||
|
) : RecyclerView.Adapter<ItemListAdapter.ViewHolder>() {
|
||||||
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
||||||
private val c: Context = app.baseContext
|
private val c: Context = app.baseContext
|
||||||
private val bars: ArrayList<Boolean> = ArrayList(Collections.nCopies(items.size + 1, false))
|
private val bars: ArrayList<Boolean> = ArrayList(Collections.nCopies(items.size + 1, false))
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
val v = LayoutInflater.from(c).inflate(R.layout.list_item, parent, false) as ConstraintLayout
|
val v = LayoutInflater.from(c).inflate(
|
||||||
|
R.layout.list_item,
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
) as ConstraintLayout
|
||||||
return ViewHolder(v)
|
return ViewHolder(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,12 +75,14 @@ class ItemListAdapter(private val app: Activity,
|
|||||||
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.mView.itemImage.layoutParams as ViewGroup.MarginLayoutParams
|
val params = holder.mView.itemImage.layoutParams as ViewGroup.MarginLayoutParams
|
||||||
params.height = sizeInDp
|
params.height = sizeInDp
|
||||||
@ -101,23 +108,34 @@ class ItemListAdapter(private val app: Activity,
|
|||||||
c.bitmapCenterCrop(itm.getThumbnail(c), holder.mView.itemImage)
|
c.bitmapCenterCrop(itm.getThumbnail(c), holder.mView.itemImage)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bars[position]) holder.mView.actionBar.visibility = View.VISIBLE else holder.mView.actionBar.visibility = View.GONE
|
if (bars[position]) {
|
||||||
|
holder.mView.actionBar.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
holder.mView.actionBar.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
holder.mView.favButton.isLiked = itm.starred
|
holder.mView.favButton.isLiked = itm.starred
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int = items.size
|
override fun getItemCount(): Int = items.size
|
||||||
|
|
||||||
|
|
||||||
private fun doUnmark(i: Item, position: Int) {
|
private fun doUnmark(i: Item, position: Int) {
|
||||||
val s = Snackbar
|
val s = Snackbar
|
||||||
.make(app.findViewById(R.id.coordLayout), R.string.marked_as_read, Snackbar.LENGTH_LONG)
|
.make(
|
||||||
|
app.findViewById(R.id.coordLayout),
|
||||||
|
R.string.marked_as_read,
|
||||||
|
Snackbar.LENGTH_LONG
|
||||||
|
)
|
||||||
.setAction(R.string.undo_string) {
|
.setAction(R.string.undo_string) {
|
||||||
items.add(position, i)
|
items.add(position, i)
|
||||||
notifyItemInserted(position)
|
notifyItemInserted(position)
|
||||||
|
|
||||||
api.unmarkItem(i.id).enqueue(object : Callback<SuccessResponse> {
|
api.unmarkItem(i.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) {
|
||||||
items.remove(i)
|
items.remove(i)
|
||||||
@ -141,7 +159,10 @@ class ItemListAdapter(private val app: Activity,
|
|||||||
notifyItemRemoved(position)
|
notifyItemRemoved(position)
|
||||||
|
|
||||||
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
|
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
|
||||||
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
|
override fun onResponse(
|
||||||
|
call: Call<SuccessResponse>,
|
||||||
|
response: Response<SuccessResponse>
|
||||||
|
) {
|
||||||
if (!response.succeeded() && debugReadingItems) {
|
if (!response.succeeded() && debugReadingItems) {
|
||||||
val message =
|
val message =
|
||||||
"message: ${response.message()} " +
|
"message: ${response.message()} " +
|
||||||
@ -157,7 +178,6 @@ class ItemListAdapter(private val app: Activity,
|
|||||||
Toast.makeText(c, message, Toast.LENGTH_LONG).show()
|
Toast.makeText(c, message, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
doUnmark(i, position)
|
doUnmark(i, position)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
||||||
@ -167,12 +187,15 @@ class ItemListAdapter(private val app: Activity,
|
|||||||
Crashlytics.logException(t)
|
Crashlytics.logException(t)
|
||||||
Toast.makeText(c, t.message, Toast.LENGTH_LONG).show()
|
Toast.makeText(c, t.message, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
Toast.makeText(app, app.getString(R.string.cant_mark_read), Toast.LENGTH_SHORT).show()
|
Toast.makeText(
|
||||||
|
app,
|
||||||
|
app.getString(R.string.cant_mark_read),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
items.add(i)
|
items.add(i)
|
||||||
notifyItemInserted(position)
|
notifyItemInserted(position)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) {
|
inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) {
|
||||||
@ -188,11 +211,22 @@ class ItemListAdapter(private val app: Activity,
|
|||||||
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
|
||||||
|
) {
|
||||||
mView.favButton.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()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -200,11 +234,22 @@ class ItemListAdapter(private val app: Activity,
|
|||||||
override fun unLiked(likeButton: LikeButton) {
|
override fun unLiked(likeButton: LikeButton) {
|
||||||
val (id) = items[adapterPosition]
|
val (id) = items[adapterPosition]
|
||||||
api.unstarrItem(id).enqueue(object : Callback<SuccessResponse> {
|
api.unstarrItem(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
|
||||||
|
) {
|
||||||
mView.favButton.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()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -220,7 +265,6 @@ class ItemListAdapter(private val app: Activity,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun handleCustomTabActions() {
|
private fun handleCustomTabActions() {
|
||||||
val customTabsIntent = c.buildCustomTabsIntent()
|
val customTabsIntent = c.buildCustomTabsIntent()
|
||||||
helper.bindCustomTabsService(app)
|
helper.bindCustomTabsService(app)
|
||||||
@ -228,7 +272,8 @@ class ItemListAdapter(private val app: Activity,
|
|||||||
|
|
||||||
if (!clickBehavior) {
|
if (!clickBehavior) {
|
||||||
mView.setOnClickListener {
|
mView.setOnClickListener {
|
||||||
c.openItemUrl(items[adapterPosition].getLinkDecoded(),
|
c.openItemUrl(
|
||||||
|
items[adapterPosition].getLinkDecoded(),
|
||||||
items[adapterPosition].content,
|
items[adapterPosition].content,
|
||||||
items[adapterPosition].getThumbnail(c),
|
items[adapterPosition].getThumbnail(c),
|
||||||
items[adapterPosition].title,
|
items[adapterPosition].title,
|
||||||
@ -236,7 +281,8 @@ class ItemListAdapter(private val app: Activity,
|
|||||||
customTabsIntent,
|
customTabsIntent,
|
||||||
internalBrowser,
|
internalBrowser,
|
||||||
articleViewer,
|
articleViewer,
|
||||||
app)
|
app
|
||||||
|
)
|
||||||
}
|
}
|
||||||
mView.setOnLongClickListener {
|
mView.setOnLongClickListener {
|
||||||
actionBarShowHide()
|
actionBarShowHide()
|
||||||
@ -245,7 +291,8 @@ class ItemListAdapter(private val app: Activity,
|
|||||||
} else {
|
} else {
|
||||||
mView.setOnClickListener { actionBarShowHide() }
|
mView.setOnClickListener { actionBarShowHide() }
|
||||||
mView.setOnLongClickListener {
|
mView.setOnLongClickListener {
|
||||||
c.openItemUrl(items[adapterPosition].getLinkDecoded(),
|
c.openItemUrl(
|
||||||
|
items[adapterPosition].getLinkDecoded(),
|
||||||
items[adapterPosition].content,
|
items[adapterPosition].content,
|
||||||
items[adapterPosition].getThumbnail(c),
|
items[adapterPosition].getThumbnail(c),
|
||||||
items[adapterPosition].title,
|
items[adapterPosition].title,
|
||||||
@ -253,7 +300,8 @@ class ItemListAdapter(private val app: Activity,
|
|||||||
customTabsIntent,
|
customTabsIntent,
|
||||||
internalBrowser,
|
internalBrowser,
|
||||||
articleViewer,
|
articleViewer,
|
||||||
app)
|
app
|
||||||
|
)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,6 @@ import android.support.v7.widget.RecyclerView
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.TextView
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import apps.amine.bou.readerforselfoss.R
|
import apps.amine.bou.readerforselfoss.R
|
||||||
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
|
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
|
||||||
@ -18,20 +16,25 @@ import apps.amine.bou.readerforselfoss.utils.glide.circularBitmapDrawable
|
|||||||
import apps.amine.bou.readerforselfoss.utils.toTextDrawableString
|
import apps.amine.bou.readerforselfoss.utils.toTextDrawableString
|
||||||
import com.amulyakhare.textdrawable.TextDrawable
|
import com.amulyakhare.textdrawable.TextDrawable
|
||||||
import com.amulyakhare.textdrawable.util.ColorGenerator
|
import com.amulyakhare.textdrawable.util.ColorGenerator
|
||||||
|
import kotlinx.android.synthetic.main.source_list_item.view.*
|
||||||
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(
|
||||||
class SourcesListAdapter(private val app: Activity,
|
private val app: Activity,
|
||||||
private val items: ArrayList<Sources>,
|
private val items: ArrayList<Sources>,
|
||||||
private val api: SelfossApi) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>() {
|
private val api: SelfossApi
|
||||||
|
) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>() {
|
||||||
private val c: Context = app.baseContext
|
private val c: Context = app.baseContext
|
||||||
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
val v = LayoutInflater.from(c).inflate(R.layout.source_list_item, parent, false) as ConstraintLayout
|
val v = LayoutInflater.from(c).inflate(
|
||||||
|
R.layout.source_list_item,
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
) as ConstraintLayout
|
||||||
return ViewHolder(v)
|
return ViewHolder(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,23 +72,32 @@ class SourcesListAdapter(private val app: Activity,
|
|||||||
deleteBtn.setOnClickListener {
|
deleteBtn.setOnClickListener {
|
||||||
val (id) = items[adapterPosition]
|
val (id) = items[adapterPosition]
|
||||||
api.deleteSource(id).enqueue(object : Callback<SuccessResponse> {
|
api.deleteSource(id).enqueue(object : Callback<SuccessResponse> {
|
||||||
override fun onResponse(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) {
|
||||||
items.removeAt(adapterPosition)
|
items.removeAt(adapterPosition)
|
||||||
notifyItemRemoved(adapterPosition)
|
notifyItemRemoved(adapterPosition)
|
||||||
notifyItemRangeChanged(adapterPosition, itemCount)
|
notifyItemRangeChanged(adapterPosition, itemCount)
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(app, R.string.can_delete_source, Toast.LENGTH_SHORT).show()
|
Toast.makeText(
|
||||||
|
app,
|
||||||
|
R.string.can_delete_source,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
||||||
Toast.makeText(app, R.string.can_delete_source, Toast.LENGTH_SHORT).show()
|
Toast.makeText(
|
||||||
|
app,
|
||||||
|
R.string.can_delete_source,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,30 +7,29 @@ import retrofit2.Call
|
|||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import retrofit2.converter.gson.GsonConverterFactory
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MercuryApi(private val key: String, shouldLog: Boolean) {
|
class MercuryApi(private val key: String, shouldLog: Boolean) {
|
||||||
private val service: MercuryService
|
private val service: MercuryService
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
||||||
val interceptor = HttpLoggingInterceptor()
|
val interceptor = HttpLoggingInterceptor()
|
||||||
interceptor.level = if (shouldLog)
|
interceptor.level = if (shouldLog) {
|
||||||
HttpLoggingInterceptor.Level.BODY
|
HttpLoggingInterceptor.Level.BODY
|
||||||
else
|
} else {
|
||||||
HttpLoggingInterceptor.Level.NONE
|
HttpLoggingInterceptor.Level.NONE
|
||||||
|
}
|
||||||
val client = OkHttpClient.Builder().addInterceptor(interceptor).build()
|
val client = OkHttpClient.Builder().addInterceptor(interceptor).build()
|
||||||
|
|
||||||
val gson = GsonBuilder()
|
val gson = GsonBuilder()
|
||||||
.setLenient()
|
.setLenient()
|
||||||
.create()
|
.create()
|
||||||
val retrofit =
|
val retrofit =
|
||||||
Retrofit
|
Retrofit
|
||||||
.Builder()
|
.Builder()
|
||||||
.baseUrl("https://mercury.postlight.com")
|
.baseUrl("https://mercury.postlight.com")
|
||||||
.client(client)
|
.client(client)
|
||||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
.addConverterFactory(GsonConverterFactory.create(gson))
|
||||||
.build()
|
.build()
|
||||||
service = retrofit.create(MercuryService::class.java)
|
service = retrofit.create(MercuryService::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,38 +4,40 @@ import android.os.Parcel
|
|||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
class ParsedContent(
|
||||||
class ParsedContent(@SerializedName("title") val title: String,
|
@SerializedName("title") val title: String,
|
||||||
@SerializedName("content") val content: String,
|
@SerializedName("content") val content: String,
|
||||||
@SerializedName("date_published") val date_published: String,
|
@SerializedName("date_published") val date_published: String,
|
||||||
@SerializedName("lead_image_url") val lead_image_url: String,
|
@SerializedName("lead_image_url") val lead_image_url: String,
|
||||||
@SerializedName("dek") val dek: String,
|
@SerializedName("dek") val dek: String,
|
||||||
@SerializedName("url") val url: String,
|
@SerializedName("url") val url: String,
|
||||||
@SerializedName("domain") val domain: String,
|
@SerializedName("domain") val domain: String,
|
||||||
@SerializedName("excerpt") val excerpt: String,
|
@SerializedName("excerpt") val excerpt: String,
|
||||||
@SerializedName("total_pages") val total_pages: Int,
|
@SerializedName("total_pages") val total_pages: Int,
|
||||||
@SerializedName("rendered_pages") val rendered_pages: Int,
|
@SerializedName("rendered_pages") val rendered_pages: Int,
|
||||||
@SerializedName("next_page_url") val next_page_url: String) : Parcelable {
|
@SerializedName("next_page_url") val next_page_url: String
|
||||||
|
) : Parcelable {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField val CREATOR: Parcelable.Creator<ParsedContent> = object : Parcelable.Creator<ParsedContent> {
|
@JvmField
|
||||||
|
val CREATOR: Parcelable.Creator<ParsedContent> = object : Parcelable.Creator<ParsedContent> {
|
||||||
override fun createFromParcel(source: Parcel): ParsedContent = ParsedContent(source)
|
override fun createFromParcel(source: Parcel): ParsedContent = ParsedContent(source)
|
||||||
override fun newArray(size: Int): Array<ParsedContent?> = arrayOfNulls(size)
|
override fun newArray(size: Int): Array<ParsedContent?> = arrayOfNulls(size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(source: Parcel) : this(
|
constructor(source: Parcel) : this(
|
||||||
title = source.readString(),
|
title = source.readString(),
|
||||||
content = source.readString(),
|
content = source.readString(),
|
||||||
date_published = source.readString(),
|
date_published = source.readString(),
|
||||||
lead_image_url = source.readString(),
|
lead_image_url = source.readString(),
|
||||||
dek = source.readString(),
|
dek = source.readString(),
|
||||||
url = source.readString(),
|
url = source.readString(),
|
||||||
domain = source.readString(),
|
domain = source.readString(),
|
||||||
excerpt = source.readString(),
|
excerpt = source.readString(),
|
||||||
total_pages = source.readInt(),
|
total_pages = source.readInt(),
|
||||||
rendered_pages = source.readInt(),
|
rendered_pages = source.readInt(),
|
||||||
next_page_url = source.readString()
|
next_page_url = source.readString()
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun describeContents() = 0
|
override fun describeContents() = 0
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
package apps.amine.bou.readerforselfoss.api.mercury
|
package apps.amine.bou.readerforselfoss.api.mercury
|
||||||
|
|
||||||
|
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Header
|
import retrofit2.http.Header
|
||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface MercuryService {
|
interface MercuryService {
|
||||||
@GET("parser")
|
@GET("parser")
|
||||||
fun parseUrl(@Query("url") url: String, @Header("x-api-key") key: String): Call<ParsedContent>
|
fun parseUrl(@Query("url") url: String, @Header("x-api-key") key: String): Call<ParsedContent>
|
||||||
|
@ -6,14 +6,17 @@ import com.google.gson.JsonElement
|
|||||||
import com.google.gson.JsonParseException
|
import com.google.gson.JsonParseException
|
||||||
import java.lang.reflect.Type
|
import java.lang.reflect.Type
|
||||||
|
|
||||||
|
|
||||||
internal class BooleanTypeAdapter : JsonDeserializer<Boolean> {
|
internal class BooleanTypeAdapter : JsonDeserializer<Boolean> {
|
||||||
|
|
||||||
@Throws(JsonParseException::class)
|
@Throws(JsonParseException::class)
|
||||||
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Boolean? =
|
override fun deserialize(
|
||||||
try {
|
json: JsonElement,
|
||||||
json.asInt == 1
|
typeOfT: Type,
|
||||||
} catch (e: Exception) {
|
context: JsonDeserializationContext
|
||||||
json.asBoolean
|
): Boolean? =
|
||||||
}
|
try {
|
||||||
|
json.asInt == 1
|
||||||
|
} catch (e: Exception) {
|
||||||
|
json.asBoolean
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,12 @@ import retrofit2.Retrofit
|
|||||||
import retrofit2.converter.gson.GsonConverterFactory
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
class SelfossApi(
|
||||||
class SelfossApi(c: Context, callingActivity: Activity, isWithSelfSignedCert: Boolean, shouldLog: Boolean) {
|
c: Context,
|
||||||
|
callingActivity: Activity,
|
||||||
|
isWithSelfSignedCert: Boolean,
|
||||||
|
shouldLog: Boolean
|
||||||
|
) {
|
||||||
|
|
||||||
private lateinit var service: SelfossService
|
private lateinit var service: SelfossService
|
||||||
private val config: Config = Config(c)
|
private val config: Config = Config(c)
|
||||||
@ -28,50 +32,50 @@ class SelfossApi(c: Context, callingActivity: Activity, isWithSelfSignedCert: Bo
|
|||||||
private val password: String
|
private val password: String
|
||||||
|
|
||||||
fun OkHttpClient.Builder.maybeWithSelfSigned(isWithSelfSignedCert: Boolean): OkHttpClient.Builder =
|
fun OkHttpClient.Builder.maybeWithSelfSigned(isWithSelfSignedCert: Boolean): OkHttpClient.Builder =
|
||||||
if (isWithSelfSignedCert) {
|
if (isWithSelfSignedCert) {
|
||||||
getUnsafeHttpClient()
|
getUnsafeHttpClient()
|
||||||
} else {
|
} else {
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Credentials.createAuthenticator(): DispatchingAuthenticator =
|
fun Credentials.createAuthenticator(): DispatchingAuthenticator =
|
||||||
DispatchingAuthenticator.Builder()
|
DispatchingAuthenticator.Builder()
|
||||||
.with("digest", DigestAuthenticator(this))
|
.with("digest", DigestAuthenticator(this))
|
||||||
.with("basic", BasicAuthenticator(this))
|
.with("basic", BasicAuthenticator(this))
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
fun DispatchingAuthenticator.getHttpClien(isWithSelfSignedCert: Boolean): OkHttpClient.Builder {
|
fun DispatchingAuthenticator.getHttpClien(isWithSelfSignedCert: Boolean): OkHttpClient.Builder {
|
||||||
val authCache = ConcurrentHashMap<String, CachingAuthenticator>()
|
val authCache = ConcurrentHashMap<String, CachingAuthenticator>()
|
||||||
return OkHttpClient
|
return OkHttpClient
|
||||||
.Builder()
|
.Builder()
|
||||||
.maybeWithSelfSigned(isWithSelfSignedCert)
|
.maybeWithSelfSigned(isWithSelfSignedCert)
|
||||||
.authenticator(CachingAuthenticatorDecorator(this, authCache))
|
.authenticator(CachingAuthenticatorDecorator(this, authCache))
|
||||||
.addInterceptor(AuthenticationCacheInterceptor(authCache))
|
.addInterceptor(AuthenticationCacheInterceptor(authCache))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
userName = config.userLogin
|
userName = config.userLogin
|
||||||
password = config.userPassword
|
password = config.userPassword
|
||||||
|
|
||||||
val authenticator =
|
val authenticator =
|
||||||
Credentials(
|
Credentials(
|
||||||
config.httpUserLogin,
|
config.httpUserLogin,
|
||||||
config.httpUserPassword
|
config.httpUserPassword
|
||||||
).createAuthenticator()
|
).createAuthenticator()
|
||||||
|
|
||||||
val gson =
|
val gson =
|
||||||
GsonBuilder()
|
GsonBuilder()
|
||||||
.registerTypeAdapter(Boolean::class.javaPrimitiveType, BooleanTypeAdapter())
|
.registerTypeAdapter(Boolean::class.javaPrimitiveType, BooleanTypeAdapter())
|
||||||
.setLenient()
|
.setLenient()
|
||||||
.create()
|
.create()
|
||||||
|
|
||||||
val logging = HttpLoggingInterceptor()
|
val logging = HttpLoggingInterceptor()
|
||||||
|
|
||||||
logging.level = if (shouldLog)
|
logging.level = if (shouldLog) {
|
||||||
HttpLoggingInterceptor.Level.BODY
|
HttpLoggingInterceptor.Level.BODY
|
||||||
else
|
} else {
|
||||||
HttpLoggingInterceptor.Level.NONE
|
HttpLoggingInterceptor.Level.NONE
|
||||||
|
}
|
||||||
|
|
||||||
val httpClient = authenticator.getHttpClien(isWithSelfSignedCert)
|
val httpClient = authenticator.getHttpClien(isWithSelfSignedCert)
|
||||||
|
|
||||||
@ -79,12 +83,12 @@ class SelfossApi(c: Context, callingActivity: Activity, isWithSelfSignedCert: Bo
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
val retrofit =
|
val retrofit =
|
||||||
Retrofit
|
Retrofit
|
||||||
.Builder()
|
.Builder()
|
||||||
.baseUrl(config.baseUrl)
|
.baseUrl(config.baseUrl)
|
||||||
.client(httpClient.build())
|
.client(httpClient.build())
|
||||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
.addConverterFactory(GsonConverterFactory.create(gson))
|
||||||
.build()
|
.build()
|
||||||
service = retrofit.create(SelfossService::class.java)
|
service = retrofit.create(SelfossService::class.java)
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (e: IllegalArgumentException) {
|
||||||
Config.logoutAndRedirect(c, callingActivity, config.settings.edit(), baseUrlFail = true)
|
Config.logoutAndRedirect(c, callingActivity, config.settings.edit(), baseUrlFail = true)
|
||||||
@ -92,34 +96,59 @@ class SelfossApi(c: Context, callingActivity: Activity, isWithSelfSignedCert: Bo
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun login(): Call<SuccessResponse> =
|
fun login(): Call<SuccessResponse> =
|
||||||
service.loginToSelfoss(config.userLogin, config.userPassword)
|
service.loginToSelfoss(config.userLogin, config.userPassword)
|
||||||
|
|
||||||
fun readItems(tag: String?, sourceId: Long?, search: String?, itemsNumber: Int, offset: Int): Call<List<Item>> =
|
fun readItems(
|
||||||
getItems("read", tag, sourceId, search, itemsNumber, offset)
|
tag: String?,
|
||||||
|
sourceId: Long?,
|
||||||
|
search: String?,
|
||||||
|
itemsNumber: Int,
|
||||||
|
offset: Int
|
||||||
|
): Call<List<Item>> =
|
||||||
|
getItems("read", tag, sourceId, search, itemsNumber, offset)
|
||||||
|
|
||||||
fun newItems(tag: String?, sourceId: Long?, search: String?, itemsNumber: Int, offset: Int): Call<List<Item>> =
|
fun newItems(
|
||||||
getItems("unread", tag, sourceId, search, itemsNumber, offset)
|
tag: String?,
|
||||||
|
sourceId: Long?,
|
||||||
|
search: String?,
|
||||||
|
itemsNumber: Int,
|
||||||
|
offset: Int
|
||||||
|
): Call<List<Item>> =
|
||||||
|
getItems("unread", tag, sourceId, search, itemsNumber, offset)
|
||||||
|
|
||||||
fun starredItems(tag: String?, sourceId: Long?, search: String?, itemsNumber: Int, offset: Int): Call<List<Item>> =
|
fun starredItems(
|
||||||
getItems("starred", tag, sourceId, search, itemsNumber, offset)
|
tag: String?,
|
||||||
|
sourceId: Long?,
|
||||||
|
search: String?,
|
||||||
|
itemsNumber: Int,
|
||||||
|
offset: Int
|
||||||
|
): Call<List<Item>> =
|
||||||
|
getItems("starred", tag, sourceId, search, itemsNumber, offset)
|
||||||
|
|
||||||
private fun getItems(type: String, tag: String?, sourceId: Long?, search: String?, items: Int, offset: Int): Call<List<Item>> =
|
private fun getItems(
|
||||||
service.getItems(type, tag, sourceId, search, userName, password, items, offset)
|
type: String,
|
||||||
|
tag: String?,
|
||||||
|
sourceId: Long?,
|
||||||
|
search: String?,
|
||||||
|
items: Int,
|
||||||
|
offset: Int
|
||||||
|
): Call<List<Item>> =
|
||||||
|
service.getItems(type, tag, sourceId, search, userName, password, items, offset)
|
||||||
|
|
||||||
fun markItem(itemId: String): Call<SuccessResponse> =
|
fun markItem(itemId: String): Call<SuccessResponse> =
|
||||||
service.markAsRead(itemId, userName, password)
|
service.markAsRead(itemId, userName, password)
|
||||||
|
|
||||||
fun unmarkItem(itemId: String): Call<SuccessResponse> =
|
fun unmarkItem(itemId: String): Call<SuccessResponse> =
|
||||||
service.unmarkAsRead(itemId, userName, password)
|
service.unmarkAsRead(itemId, userName, password)
|
||||||
|
|
||||||
fun readAll(ids: List<String>): Call<SuccessResponse> =
|
fun readAll(ids: List<String>): Call<SuccessResponse> =
|
||||||
service.markAllAsRead(ids, userName, password)
|
service.markAllAsRead(ids, userName, password)
|
||||||
|
|
||||||
fun starrItem(itemId: String): Call<SuccessResponse> =
|
fun starrItem(itemId: String): Call<SuccessResponse> =
|
||||||
service.starr(itemId, userName, password)
|
service.starr(itemId, userName, password)
|
||||||
|
|
||||||
fun unstarrItem(itemId: String): Call<SuccessResponse> =
|
fun unstarrItem(itemId: String): Call<SuccessResponse> =
|
||||||
service.unstarr(itemId, userName, password)
|
service.unstarr(itemId, userName, password)
|
||||||
|
|
||||||
val stats: Call<Stats>
|
val stats: Call<Stats>
|
||||||
get() = service.stats(userName, password)
|
get() = service.stats(userName, password)
|
||||||
@ -128,18 +157,23 @@ class SelfossApi(c: Context, callingActivity: Activity, isWithSelfSignedCert: Bo
|
|||||||
get() = service.tags(userName, password)
|
get() = service.tags(userName, password)
|
||||||
|
|
||||||
fun update(): Call<String> =
|
fun update(): Call<String> =
|
||||||
service.update(userName, password)
|
service.update(userName, password)
|
||||||
|
|
||||||
val sources: Call<List<Sources>>
|
val sources: Call<List<Sources>>
|
||||||
get() = service.sources(userName, password)
|
get() = service.sources(userName, password)
|
||||||
|
|
||||||
fun deleteSource(id: String): Call<SuccessResponse> =
|
fun deleteSource(id: String): Call<SuccessResponse> =
|
||||||
service.deleteSource(id, userName, password)
|
service.deleteSource(id, userName, password)
|
||||||
|
|
||||||
fun spouts(): Call<Map<String, Spout>> =
|
fun spouts(): Call<Map<String, Spout>> =
|
||||||
service.spouts(userName, password)
|
service.spouts(userName, password)
|
||||||
|
|
||||||
fun createSource(title: String, url: String, spout: String, tags: String, filter: String): Call<SuccessResponse> =
|
|
||||||
service.createSource(title, url, spout, tags, filter, userName, password)
|
|
||||||
|
|
||||||
|
fun createSource(
|
||||||
|
title: String,
|
||||||
|
url: String,
|
||||||
|
spout: String,
|
||||||
|
tags: String,
|
||||||
|
filter: String
|
||||||
|
): Call<SuccessResponse> =
|
||||||
|
service.createSource(title, url, spout, tags, filter, userName, password)
|
||||||
}
|
}
|
||||||
|
@ -9,59 +9,69 @@ import apps.amine.bou.readerforselfoss.utils.Config
|
|||||||
import apps.amine.bou.readerforselfoss.utils.isEmptyOrNullOrNullString
|
import apps.amine.bou.readerforselfoss.utils.isEmptyOrNullOrNullString
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
|
||||||
private fun constructUrl(config: Config?, path: String, file: String): String {
|
private fun constructUrl(config: Config?, path: String, file: String): String {
|
||||||
val baseUriBuilder = Uri.parse(config!!.baseUrl).buildUpon()
|
val baseUriBuilder = Uri.parse(config!!.baseUrl).buildUpon()
|
||||||
baseUriBuilder.appendPath(path).appendPath(file)
|
baseUriBuilder.appendPath(path).appendPath(file)
|
||||||
|
|
||||||
return if (file.isEmptyOrNullOrNullString()) ""
|
return if (file.isEmptyOrNullOrNullString()) {
|
||||||
else baseUriBuilder.toString()
|
""
|
||||||
|
} else {
|
||||||
|
baseUriBuilder.toString()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class Tag(
|
||||||
data class Tag(@SerializedName("tag") val tag: String,
|
@SerializedName("tag") val tag: String,
|
||||||
@SerializedName("color") val color: String,
|
@SerializedName("color") val color: String,
|
||||||
@SerializedName("unread") val unread: Int)
|
@SerializedName("unread") val unread: Int
|
||||||
|
)
|
||||||
|
|
||||||
class SuccessResponse(@SerializedName("success") val success: Boolean) {
|
class SuccessResponse(@SerializedName("success") val success: Boolean) {
|
||||||
val isSuccess: Boolean
|
val isSuccess: Boolean
|
||||||
get() = success
|
get() = success
|
||||||
}
|
}
|
||||||
|
|
||||||
class Stats(@SerializedName("total") val total: Int,
|
class Stats(
|
||||||
@SerializedName("unread") val unread: Int,
|
@SerializedName("total") val total: Int,
|
||||||
@SerializedName("starred") val starred: Int)
|
@SerializedName("unread") val unread: Int,
|
||||||
|
@SerializedName("starred") val starred: Int
|
||||||
|
)
|
||||||
|
|
||||||
data class Spout(@SerializedName("name") val name: String,
|
data class Spout(
|
||||||
@SerializedName("description") val description: String)
|
@SerializedName("name") val name: String,
|
||||||
|
@SerializedName("description") val description: String
|
||||||
|
)
|
||||||
|
|
||||||
data class Sources(@SerializedName("id") val id: String,
|
data class Sources(
|
||||||
@SerializedName("title") val title: String,
|
@SerializedName("id") val id: String,
|
||||||
@SerializedName("tags") val tags: String,
|
@SerializedName("title") val title: String,
|
||||||
@SerializedName("spout") val spout: String,
|
@SerializedName("tags") val tags: String,
|
||||||
@SerializedName("error") val error: String,
|
@SerializedName("spout") val spout: String,
|
||||||
@SerializedName("icon") val icon: String) {
|
@SerializedName("error") val error: String,
|
||||||
|
@SerializedName("icon") val icon: String
|
||||||
|
) {
|
||||||
var config: Config? = null
|
var config: Config? = null
|
||||||
|
|
||||||
fun getIcon(app: Context): String {
|
fun getIcon(app: Context): String {
|
||||||
if (config == null) {
|
if (config == null) {
|
||||||
config = Config(app)
|
config = Config(app)
|
||||||
}
|
}
|
||||||
return constructUrl(config,"favicons", icon)
|
return constructUrl(config, "favicons", icon)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Item(@SerializedName("id") val id: String,
|
data class Item(
|
||||||
@SerializedName("datetime") val datetime: String,
|
@SerializedName("id") val id: String,
|
||||||
@SerializedName("title") val title: String,
|
@SerializedName("datetime") val datetime: String,
|
||||||
@SerializedName("content") val content: String,
|
@SerializedName("title") val title: String,
|
||||||
@SerializedName("unread") val unread: Boolean,
|
@SerializedName("content") val content: String,
|
||||||
@SerializedName("starred") val starred: Boolean,
|
@SerializedName("unread") val unread: Boolean,
|
||||||
@SerializedName("thumbnail") val thumbnail: String,
|
@SerializedName("starred") val starred: Boolean,
|
||||||
@SerializedName("icon") val icon: String,
|
@SerializedName("thumbnail") val thumbnail: String,
|
||||||
@SerializedName("link") val link: String,
|
@SerializedName("icon") val icon: String,
|
||||||
@SerializedName("sourcetitle") val sourcetitle: String) : Parcelable {
|
@SerializedName("link") val link: String,
|
||||||
|
@SerializedName("sourcetitle") val sourcetitle: String
|
||||||
|
) : Parcelable {
|
||||||
|
|
||||||
var config: Config? = null
|
var config: Config? = null
|
||||||
|
|
||||||
@ -139,5 +149,4 @@ data class Item(@SerializedName("id") val id: String,
|
|||||||
|
|
||||||
return stringUrl
|
return stringUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -10,97 +10,109 @@ import retrofit2.http.POST
|
|||||||
import retrofit2.http.Path
|
import retrofit2.http.Path
|
||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
|
|
||||||
|
|
||||||
internal interface SelfossService {
|
internal interface SelfossService {
|
||||||
|
|
||||||
@GET("login")
|
@GET("login")
|
||||||
fun loginToSelfoss(@Query("username") username: String, @Query("password") password: String): Call<SuccessResponse>
|
fun loginToSelfoss(@Query("username") username: String, @Query("password") password: String): Call<SuccessResponse>
|
||||||
|
|
||||||
|
|
||||||
@GET("items")
|
@GET("items")
|
||||||
fun getItems(@Query("type") type: String,
|
fun getItems(
|
||||||
@Query("tag") tag: String?,
|
@Query("type") type: String,
|
||||||
@Query("source") source: Long?,
|
@Query("tag") tag: String?,
|
||||||
@Query("search") search: String?,
|
@Query("source") source: Long?,
|
||||||
@Query("username") username: String,
|
@Query("search") search: String?,
|
||||||
@Query("password") password: String,
|
@Query("username") username: String,
|
||||||
@Query("items") items: Int,
|
@Query("password") password: String,
|
||||||
@Query("offset") offset: Int): Call<List<Item>>
|
@Query("items") items: Int,
|
||||||
|
@Query("offset") offset: Int
|
||||||
|
): Call<List<Item>>
|
||||||
|
|
||||||
@Headers("Content-Type: application/x-www-form-urlencoded")
|
@Headers("Content-Type: application/x-www-form-urlencoded")
|
||||||
@POST("mark/{id}")
|
@POST("mark/{id}")
|
||||||
fun markAsRead(@Path("id") id: String,
|
fun markAsRead(
|
||||||
@Query("username") username: String,
|
@Path("id") id: String,
|
||||||
@Query("password") password: String): Call<SuccessResponse>
|
@Query("username") username: String,
|
||||||
|
@Query("password") password: String
|
||||||
|
): Call<SuccessResponse>
|
||||||
|
|
||||||
@Headers("Content-Type: application/x-www-form-urlencoded")
|
@Headers("Content-Type: application/x-www-form-urlencoded")
|
||||||
@POST("unmark/{id}")
|
@POST("unmark/{id}")
|
||||||
fun unmarkAsRead(@Path("id") id: String,
|
fun unmarkAsRead(
|
||||||
@Query("username") username: String,
|
@Path("id") id: String,
|
||||||
@Query("password") password: String): Call<SuccessResponse>
|
@Query("username") username: String,
|
||||||
|
@Query("password") password: String
|
||||||
|
): Call<SuccessResponse>
|
||||||
|
|
||||||
@FormUrlEncoded
|
@FormUrlEncoded
|
||||||
@POST("mark")
|
@POST("mark")
|
||||||
fun markAllAsRead(@Field("ids[]") ids: List<String>,
|
fun markAllAsRead(
|
||||||
@Query("username") username: String,
|
@Field("ids[]") ids: List<String>,
|
||||||
@Query("password") password: String): Call<SuccessResponse>
|
@Query("username") username: String,
|
||||||
|
@Query("password") password: String
|
||||||
|
): Call<SuccessResponse>
|
||||||
|
|
||||||
@Headers("Content-Type: application/x-www-form-urlencoded")
|
@Headers("Content-Type: application/x-www-form-urlencoded")
|
||||||
@POST("starr/{id}")
|
@POST("starr/{id}")
|
||||||
fun starr(@Path("id") id: String,
|
fun starr(
|
||||||
@Query("username") username: String,
|
@Path("id") id: String,
|
||||||
@Query("password") password: String): Call<SuccessResponse>
|
@Query("username") username: String,
|
||||||
|
@Query("password") password: String
|
||||||
|
): Call<SuccessResponse>
|
||||||
|
|
||||||
@Headers("Content-Type: application/x-www-form-urlencoded")
|
@Headers("Content-Type: application/x-www-form-urlencoded")
|
||||||
@POST("unstarr/{id}")
|
@POST("unstarr/{id}")
|
||||||
fun unstarr(@Path("id") id: String,
|
fun unstarr(
|
||||||
@Query("username") username: String,
|
@Path("id") id: String,
|
||||||
@Query("password") password: String): Call<SuccessResponse>
|
@Query("username") username: String,
|
||||||
|
@Query("password") password: String
|
||||||
|
): Call<SuccessResponse>
|
||||||
|
|
||||||
@GET("stats")
|
@GET("stats")
|
||||||
fun stats(@Query("username") username: String,
|
fun stats(
|
||||||
@Query("password") password: String): Call<Stats>
|
@Query("username") username: String,
|
||||||
|
@Query("password") password: String
|
||||||
|
): Call<Stats>
|
||||||
|
|
||||||
@GET("tags")
|
@GET("tags")
|
||||||
fun tags(@Query("username") username: String,
|
fun tags(
|
||||||
@Query("password") password: String): Call<List<Tag>>
|
@Query("username") username: String,
|
||||||
|
@Query("password") password: String
|
||||||
|
): Call<List<Tag>>
|
||||||
|
|
||||||
@GET("update")
|
@GET("update")
|
||||||
fun update(@Query("username") username: String,
|
fun update(
|
||||||
@Query("password") password: String): Call<String>
|
@Query("username") username: String,
|
||||||
|
@Query("password") password: String
|
||||||
|
): Call<String>
|
||||||
|
|
||||||
@GET("sources/spouts")
|
@GET("sources/spouts")
|
||||||
fun spouts(@Query("username") username: String,
|
fun spouts(
|
||||||
@Query("password") password: String): Call<Map<String, Spout>>
|
@Query("username") username: String,
|
||||||
|
@Query("password") password: String
|
||||||
|
): Call<Map<String, Spout>>
|
||||||
|
|
||||||
@GET("sources/list")
|
@GET("sources/list")
|
||||||
fun sources(@Query("username") username: String,
|
fun sources(
|
||||||
@Query("password") password: String): Call<List<Sources>>
|
@Query("username") username: String,
|
||||||
|
@Query("password") password: String
|
||||||
|
): Call<List<Sources>>
|
||||||
|
|
||||||
@DELETE("source/{id}")
|
@DELETE("source/{id}")
|
||||||
fun deleteSource(@Path("id") id: String,
|
fun deleteSource(
|
||||||
@Query("username") username: String,
|
@Path("id") id: String,
|
||||||
@Query("password") password: String): Call<SuccessResponse>
|
@Query("username") username: String,
|
||||||
|
@Query("password") password: String
|
||||||
|
): Call<SuccessResponse>
|
||||||
|
|
||||||
@FormUrlEncoded
|
@FormUrlEncoded
|
||||||
@POST("source")
|
@POST("source")
|
||||||
fun createSource(@Field("title") title: String,
|
fun createSource(
|
||||||
@Field("url") url: String,
|
@Field("title") title: String,
|
||||||
@Field("spout") spout: String,
|
@Field("url") url: String,
|
||||||
@Field("tags") tags: String,
|
@Field("spout") spout: String,
|
||||||
@Field("filter") filter: String,
|
@Field("tags") tags: String,
|
||||||
@Query("username") username: String,
|
@Field("filter") filter: String,
|
||||||
@Query("password") password: String): Call<SuccessResponse>
|
@Query("username") username: String,
|
||||||
|
@Query("password") password: String
|
||||||
|
): Call<SuccessResponse>
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import android.support.annotation.ColorInt
|
|||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import apps.amine.bou.readerforselfoss.R
|
import apps.amine.bou.readerforselfoss.R
|
||||||
|
|
||||||
|
|
||||||
class AppColors(a: Activity) {
|
class AppColors(a: Activity) {
|
||||||
@ColorInt val accent: Int
|
@ColorInt val accent: Int
|
||||||
@ColorInt val dark: Int
|
@ColorInt val dark: Int
|
||||||
@ -20,7 +19,7 @@ class AppColors(a: Activity) {
|
|||||||
val method = wrapper!!.getMethod("getThemeResId")
|
val method = wrapper!!.getMethod("getThemeResId")
|
||||||
method.isAccessible = true
|
method.isAccessible = true
|
||||||
|
|
||||||
isDarkTheme = when(method.invoke(a.baseContext)) {
|
isDarkTheme = when (method.invoke(a.baseContext)) {
|
||||||
R.style.NoBarTealOrangeDark,
|
R.style.NoBarTealOrangeDark,
|
||||||
R.style.NoBarDark,
|
R.style.NoBarDark,
|
||||||
R.style.NoBarBlueAmberDark,
|
R.style.NoBarBlueAmberDark,
|
||||||
|
@ -4,4 +4,4 @@ import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
|
|||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
|
|
||||||
fun Response<SuccessResponse>.succeeded(): Boolean =
|
fun Response<SuccessResponse>.succeeded(): Boolean =
|
||||||
this.code() === 200 && this.body() != null && this.body()!!.isSuccess
|
this.code() === 200 && this.body() != null && this.body()!!.isSuccess
|
@ -8,13 +8,14 @@ import android.support.v7.app.AlertDialog
|
|||||||
import apps.amine.bou.readerforselfoss.R
|
import apps.amine.bou.readerforselfoss.R
|
||||||
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
|
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
|
||||||
|
|
||||||
|
|
||||||
fun String?.isEmptyOrNullOrNullString(): Boolean =
|
fun String?.isEmptyOrNullOrNullString(): Boolean =
|
||||||
this == null || this == "null" || this.isEmpty()
|
this == null || this == "null" || this.isEmpty()
|
||||||
|
|
||||||
fun Context.checkApkVersion(settings: SharedPreferences,
|
fun Context.checkApkVersion(
|
||||||
editor: SharedPreferences.Editor,
|
settings: SharedPreferences,
|
||||||
mFirebaseRemoteConfig: FirebaseRemoteConfig) = {
|
editor: SharedPreferences.Editor,
|
||||||
|
mFirebaseRemoteConfig: FirebaseRemoteConfig
|
||||||
|
) = {
|
||||||
fun isThereAnUpdate() {
|
fun isThereAnUpdate() {
|
||||||
val APK_LINK = "github_apk"
|
val APK_LINK = "github_apk"
|
||||||
|
|
||||||
@ -24,31 +25,35 @@ fun Context.checkApkVersion(settings: SharedPreferences,
|
|||||||
val alertDialog = AlertDialog.Builder(this).create()
|
val alertDialog = AlertDialog.Builder(this).create()
|
||||||
alertDialog.setTitle(getString(R.string.new_apk_available_title))
|
alertDialog.setTitle(getString(R.string.new_apk_available_title))
|
||||||
alertDialog.setMessage(getString(R.string.new_apk_available_message))
|
alertDialog.setMessage(getString(R.string.new_apk_available_message))
|
||||||
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.new_apk_available_get)) { _, _ ->
|
alertDialog.setButton(
|
||||||
|
AlertDialog.BUTTON_POSITIVE,
|
||||||
|
getString(R.string.new_apk_available_get)
|
||||||
|
) { _, _ ->
|
||||||
editor.putString(APK_LINK, apkLink)
|
editor.putString(APK_LINK, apkLink)
|
||||||
editor.apply()
|
editor.apply()
|
||||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(apkLink))
|
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(apkLink))
|
||||||
startActivity(browserIntent)
|
startActivity(browserIntent)
|
||||||
}
|
}
|
||||||
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, getString(R.string.new_apk_available_no),
|
alertDialog.setButton(
|
||||||
{ dialog, _ ->
|
AlertDialog.BUTTON_NEUTRAL, getString(R.string.new_apk_available_no),
|
||||||
editor.putString(APK_LINK, apkLink)
|
{ dialog, _ ->
|
||||||
editor.apply()
|
editor.putString(APK_LINK, apkLink)
|
||||||
dialog.dismiss()
|
editor.apply()
|
||||||
})
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
)
|
||||||
alertDialog.show()
|
alertDialog.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mFirebaseRemoteConfig.fetch(43200)
|
mFirebaseRemoteConfig.fetch(43200)
|
||||||
.addOnCompleteListener { task ->
|
.addOnCompleteListener { task ->
|
||||||
if (task.isSuccessful) {
|
if (task.isSuccessful) {
|
||||||
mFirebaseRemoteConfig.activateFetched()
|
mFirebaseRemoteConfig.activateFetched()
|
||||||
}
|
}
|
||||||
|
|
||||||
isThereAnUpdate()
|
isThereAnUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.longHash(): Long {
|
fun String.longHash(): Long {
|
||||||
@ -62,11 +67,12 @@ fun String.longHash(): Long {
|
|||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.toStringUriWithHttp() =
|
fun String.toStringUriWithHttp(): String =
|
||||||
if (!this.startsWith("https://") && !this.startsWith("http://"))
|
if (!this.startsWith("https://") && !this.startsWith("http://")) {
|
||||||
"http://" + this
|
"http://" + this
|
||||||
else
|
} else {
|
||||||
this
|
this
|
||||||
|
}
|
||||||
|
|
||||||
fun Context.shareLink(itemUrl: String) {
|
fun Context.shareLink(itemUrl: String) {
|
||||||
val sendIntent = Intent()
|
val sendIntent = Intent()
|
||||||
@ -74,5 +80,10 @@ fun Context.shareLink(itemUrl: String) {
|
|||||||
sendIntent.action = Intent.ACTION_SEND
|
sendIntent.action = Intent.ACTION_SEND
|
||||||
sendIntent.putExtra(Intent.EXTRA_TEXT, itemUrl.toStringUriWithHttp())
|
sendIntent.putExtra(Intent.EXTRA_TEXT, itemUrl.toStringUriWithHttp())
|
||||||
sendIntent.type = "text/plain"
|
sendIntent.type = "text/plain"
|
||||||
startActivity(Intent.createChooser(sendIntent, getString(R.string.share)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
|
startActivity(
|
||||||
|
Intent.createChooser(
|
||||||
|
sendIntent,
|
||||||
|
getString(R.string.share)
|
||||||
|
).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
)
|
||||||
}
|
}
|
@ -6,7 +6,6 @@ import android.content.Intent
|
|||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import apps.amine.bou.readerforselfoss.LoginActivity
|
import apps.amine.bou.readerforselfoss.LoginActivity
|
||||||
|
|
||||||
|
|
||||||
class Config(c: Context) {
|
class Config(c: Context) {
|
||||||
|
|
||||||
val settings: SharedPreferences = c.getSharedPreferences(settingsName, Context.MODE_PRIVATE)
|
val settings: SharedPreferences = c.getSharedPreferences(settingsName, Context.MODE_PRIVATE)
|
||||||
@ -26,21 +25,23 @@ class Config(c: Context) {
|
|||||||
val httpUserPassword: String
|
val httpUserPassword: String
|
||||||
get() = settings.getString("httpPassword", "")
|
get() = settings.getString("httpPassword", "")
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val settingsName = "paramsselfoss"
|
val settingsName = "paramsselfoss"
|
||||||
|
|
||||||
fun logoutAndRedirect(c: Context,
|
fun logoutAndRedirect(
|
||||||
callingActivity: Activity,
|
c: Context,
|
||||||
editor: SharedPreferences.Editor,
|
callingActivity: Activity,
|
||||||
baseUrlFail: Boolean = false): Boolean {
|
editor: SharedPreferences.Editor,
|
||||||
|
baseUrlFail: Boolean = false
|
||||||
|
): Boolean {
|
||||||
editor.remove("url")
|
editor.remove("url")
|
||||||
editor.remove("login")
|
editor.remove("login")
|
||||||
editor.remove("password")
|
editor.remove("password")
|
||||||
editor.apply()
|
editor.apply()
|
||||||
val intent = Intent(c, LoginActivity::class.java)
|
val intent = Intent(c, LoginActivity::class.java)
|
||||||
if (baseUrlFail)
|
if (baseUrlFail) {
|
||||||
intent.putExtra("baseUrlFail", baseUrlFail)
|
intent.putExtra("baseUrlFail", baseUrlFail)
|
||||||
|
}
|
||||||
c.startActivity(intent)
|
c.startActivity(intent)
|
||||||
callingActivity.finish()
|
callingActivity.finish()
|
||||||
return true
|
return true
|
||||||
|
@ -8,32 +8,36 @@ import javax.net.ssl.TrustManager
|
|||||||
import javax.net.ssl.X509TrustManager
|
import javax.net.ssl.X509TrustManager
|
||||||
|
|
||||||
fun getUnsafeHttpClient() =
|
fun getUnsafeHttpClient() =
|
||||||
try {
|
try {
|
||||||
// Create a trust manager that does not validate certificate chains
|
// Create a trust manager that does not validate certificate chains
|
||||||
val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
|
val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
|
||||||
override fun getAcceptedIssuers(): Array<X509Certificate> =
|
override fun getAcceptedIssuers(): Array<X509Certificate> =
|
||||||
arrayOf()
|
arrayOf()
|
||||||
|
|
||||||
@Throws(CertificateException::class)
|
@Throws(CertificateException::class)
|
||||||
override fun checkClientTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) {
|
override fun checkClientTrusted(
|
||||||
}
|
chain: Array<java.security.cert.X509Certificate>,
|
||||||
|
authType: String
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(CertificateException::class)
|
@Throws(CertificateException::class)
|
||||||
override fun checkServerTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) {
|
override fun checkServerTrusted(
|
||||||
}
|
chain: Array<java.security.cert.X509Certificate>,
|
||||||
|
authType: String
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
})
|
// Install the all-trusting trust manager
|
||||||
|
val sslContext = SSLContext.getInstance("SSL")
|
||||||
|
sslContext.init(null, trustAllCerts, java.security.SecureRandom())
|
||||||
|
|
||||||
// Install the all-trusting trust manager
|
val sslSocketFactory = sslContext.socketFactory
|
||||||
val sslContext = SSLContext.getInstance("SSL")
|
|
||||||
sslContext.init(null, trustAllCerts, java.security.SecureRandom())
|
|
||||||
|
|
||||||
val sslSocketFactory = sslContext.socketFactory
|
OkHttpClient.Builder()
|
||||||
|
.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
|
||||||
OkHttpClient.Builder()
|
.hostnameVerifier { _, _ -> true }
|
||||||
.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
|
} catch (e: Exception) {
|
||||||
.hostnameVerifier { _, _ -> true }
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
}
|
|
@ -6,7 +6,6 @@ import java.text.ParseException
|
|||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
fun String.toTextDrawableString(): String {
|
fun String.toTextDrawableString(): String {
|
||||||
val textDrawable = StringBuilder()
|
val textDrawable = StringBuilder()
|
||||||
for (s in this.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) {
|
for (s in this.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) {
|
||||||
@ -18,10 +17,10 @@ fun String.toTextDrawableString(): String {
|
|||||||
fun Item.sourceAndDateText(): String {
|
fun Item.sourceAndDateText(): String {
|
||||||
val formattedDate: String = try {
|
val formattedDate: String = try {
|
||||||
" " + DateUtils.getRelativeTimeSpanString(
|
" " + DateUtils.getRelativeTimeSpanString(
|
||||||
SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(this.datetime).time,
|
SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(this.datetime).time,
|
||||||
Date().time,
|
Date().time,
|
||||||
DateUtils.MINUTE_IN_MILLIS,
|
DateUtils.MINUTE_IN_MILLIS,
|
||||||
DateUtils.FORMAT_ABBREV_RELATIVE
|
DateUtils.FORMAT_ABBREV_RELATIVE
|
||||||
)
|
)
|
||||||
} catch (e: ParseException) {
|
} catch (e: ParseException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
|
@ -14,15 +14,17 @@ import apps.amine.bou.readerforselfoss.ReaderActivity
|
|||||||
import apps.amine.bou.readerforselfoss.api.selfoss.Item
|
import apps.amine.bou.readerforselfoss.api.selfoss.Item
|
||||||
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
|
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
import xyz.klinker.android.drag_dismiss.DragDismissIntentBuilder
|
|
||||||
|
|
||||||
|
|
||||||
fun Context.buildCustomTabsIntent(): CustomTabsIntent {
|
fun Context.buildCustomTabsIntent(): CustomTabsIntent {
|
||||||
|
|
||||||
val actionIntent = Intent(Intent.ACTION_SEND)
|
val actionIntent = Intent(Intent.ACTION_SEND)
|
||||||
actionIntent.type = "text/plain"
|
actionIntent.type = "text/plain"
|
||||||
val createPendingShareIntent: PendingIntent = PendingIntent.getActivity(this, 0, actionIntent, 0)
|
val createPendingShareIntent: PendingIntent = PendingIntent.getActivity(
|
||||||
|
this,
|
||||||
|
0,
|
||||||
|
actionIntent,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
|
||||||
val intentBuilder = CustomTabsIntent.Builder()
|
val intentBuilder = CustomTabsIntent.Builder()
|
||||||
|
|
||||||
@ -32,32 +34,40 @@ fun Context.buildCustomTabsIntent(): CustomTabsIntent {
|
|||||||
intentBuilder.setShowTitle(true)
|
intentBuilder.setShowTitle(true)
|
||||||
|
|
||||||
|
|
||||||
intentBuilder.setStartAnimations(this,
|
intentBuilder.setStartAnimations(
|
||||||
|
this,
|
||||||
R.anim.slide_in_right,
|
R.anim.slide_in_right,
|
||||||
R.anim.slide_out_left)
|
R.anim.slide_out_left
|
||||||
intentBuilder.setExitAnimations(this,
|
)
|
||||||
|
intentBuilder.setExitAnimations(
|
||||||
|
this,
|
||||||
android.R.anim.slide_in_left,
|
android.R.anim.slide_in_left,
|
||||||
android.R.anim.slide_out_right)
|
android.R.anim.slide_out_right
|
||||||
|
)
|
||||||
|
|
||||||
val closeicon = BitmapFactory.decodeResource(resources, R.drawable.ic_close_white_24dp)
|
val closeicon = BitmapFactory.decodeResource(resources, R.drawable.ic_close_white_24dp)
|
||||||
intentBuilder.setCloseButtonIcon(closeicon)
|
intentBuilder.setCloseButtonIcon(closeicon)
|
||||||
|
|
||||||
val shareLabel = this.getString(R.string.label_share)
|
val shareLabel = this.getString(R.string.label_share)
|
||||||
val icon = BitmapFactory.decodeResource(resources,
|
val icon = BitmapFactory.decodeResource(
|
||||||
R.drawable.ic_share_white_24dp)
|
resources,
|
||||||
|
R.drawable.ic_share_white_24dp
|
||||||
|
)
|
||||||
intentBuilder.setActionButton(icon, shareLabel, createPendingShareIntent)
|
intentBuilder.setActionButton(icon, shareLabel, createPendingShareIntent)
|
||||||
|
|
||||||
return intentBuilder.build()
|
return intentBuilder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.openItemUrlInternally(linkDecoded: String,
|
fun Context.openItemUrlInternally(
|
||||||
content: String,
|
linkDecoded: String,
|
||||||
image: String,
|
content: String,
|
||||||
title: String,
|
image: String,
|
||||||
source: String,
|
title: String,
|
||||||
customTabsIntent: CustomTabsIntent,
|
source: String,
|
||||||
articleViewer: Boolean,
|
customTabsIntent: CustomTabsIntent,
|
||||||
app: Activity) {
|
articleViewer: Boolean,
|
||||||
|
app: Activity
|
||||||
|
) {
|
||||||
if (articleViewer) {
|
if (articleViewer) {
|
||||||
val intent = Intent(this, ReaderActivity::class.java)
|
val intent = Intent(this, ReaderActivity::class.java)
|
||||||
|
|
||||||
@ -76,7 +86,10 @@ fun Context.openItemUrlInternally(linkDecoded: String,
|
|||||||
app.startActivity(intent)
|
app.startActivity(intent)
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
CustomTabActivityHelper.openCustomTab(app, customTabsIntent, Uri.parse(linkDecoded)
|
CustomTabActivityHelper.openCustomTab(
|
||||||
|
app,
|
||||||
|
customTabsIntent,
|
||||||
|
Uri.parse(linkDecoded)
|
||||||
) { _, uri ->
|
) { _, uri ->
|
||||||
val intent = Intent(Intent.ACTION_VIEW, uri)
|
val intent = Intent(Intent.ACTION_VIEW, uri)
|
||||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
@ -88,23 +101,38 @@ fun Context.openItemUrlInternally(linkDecoded: String,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.openItemUrl(linkDecoded: String,
|
fun Context.openItemUrl(
|
||||||
content: String,
|
linkDecoded: String,
|
||||||
image: String,
|
content: String,
|
||||||
title: String,
|
image: String,
|
||||||
source: String,
|
title: String,
|
||||||
customTabsIntent: CustomTabsIntent,
|
source: String,
|
||||||
internalBrowser: Boolean,
|
customTabsIntent: CustomTabsIntent,
|
||||||
articleViewer: Boolean,
|
internalBrowser: Boolean,
|
||||||
app: Activity) {
|
articleViewer: Boolean,
|
||||||
|
app: Activity
|
||||||
|
) {
|
||||||
|
|
||||||
if (!linkDecoded.isUrlValid()) {
|
if (!linkDecoded.isUrlValid()) {
|
||||||
Toast.makeText(this, this.getString(R.string.cant_open_invalid_url), Toast.LENGTH_LONG).show()
|
Toast.makeText(
|
||||||
|
this,
|
||||||
|
this.getString(R.string.cant_open_invalid_url),
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
).show()
|
||||||
} else {
|
} else {
|
||||||
if (!internalBrowser) {
|
if (!internalBrowser) {
|
||||||
openInBrowser(linkDecoded, app)
|
openInBrowser(linkDecoded, app)
|
||||||
} else {
|
} else {
|
||||||
this.openItemUrlInternally(linkDecoded, content, image, title, source, customTabsIntent, articleViewer, app)
|
this.openItemUrlInternally(
|
||||||
|
linkDecoded,
|
||||||
|
content,
|
||||||
|
image,
|
||||||
|
title,
|
||||||
|
source,
|
||||||
|
customTabsIntent,
|
||||||
|
articleViewer,
|
||||||
|
app
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,18 +6,39 @@ import android.support.design.widget.FloatingActionButton
|
|||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
|
||||||
class ScrollAwareFABBehavior(context: Context, attrs: AttributeSet) : CoordinatorLayout.Behavior<FloatingActionButton>() {
|
class ScrollAwareFABBehavior(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet
|
||||||
|
) : CoordinatorLayout.Behavior<FloatingActionButton>() {
|
||||||
|
|
||||||
override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout, child: FloatingActionButton,
|
override fun onStartNestedScroll(
|
||||||
directTargetChild: View, target: View, nestedScrollAxes: Int): Boolean {
|
coordinatorLayout: CoordinatorLayout,
|
||||||
|
child: FloatingActionButton,
|
||||||
|
directTargetChild: View,
|
||||||
|
target: View,
|
||||||
|
nestedScrollAxes: Int
|
||||||
|
): Boolean {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNestedScroll(coordinatorLayout: CoordinatorLayout,
|
override fun onNestedScroll(
|
||||||
child: FloatingActionButton,
|
coordinatorLayout: CoordinatorLayout,
|
||||||
target: View, dxConsumed: Int, dyConsumed: Int,
|
child: FloatingActionButton,
|
||||||
dxUnconsumed: Int, dyUnconsumed: Int) {
|
target: View,
|
||||||
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed)
|
dxConsumed: Int,
|
||||||
|
dyConsumed: Int,
|
||||||
|
dxUnconsumed: Int,
|
||||||
|
dyUnconsumed: Int
|
||||||
|
) {
|
||||||
|
super.onNestedScroll(
|
||||||
|
coordinatorLayout,
|
||||||
|
child,
|
||||||
|
target,
|
||||||
|
dxConsumed,
|
||||||
|
dyConsumed,
|
||||||
|
dxUnconsumed,
|
||||||
|
dyUnconsumed
|
||||||
|
)
|
||||||
if (dyConsumed > 0 && child.visibility == View.VISIBLE) {
|
if (dyConsumed > 0 && child.visibility == View.VISIBLE) {
|
||||||
child.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
|
child.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
|
||||||
override fun onHidden(fab: FloatingActionButton?) {
|
override fun onHidden(fab: FloatingActionButton?) {
|
||||||
@ -25,7 +46,6 @@ class ScrollAwareFABBehavior(context: Context, attrs: AttributeSet) : Coordinato
|
|||||||
fab!!.visibility = View.INVISIBLE
|
fab!!.visibility = View.INVISIBLE
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
} else if (dyConsumed < 0 && child.visibility != View.VISIBLE) {
|
} else if (dyConsumed < 0 && child.visibility != View.VISIBLE) {
|
||||||
child.show()
|
child.show()
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package apps.amine.bou.readerforselfoss.utils.bottombar
|
|||||||
|
|
||||||
import com.ashokvarma.bottomnavigation.TextBadgeItem
|
import com.ashokvarma.bottomnavigation.TextBadgeItem
|
||||||
|
|
||||||
|
|
||||||
fun TextBadgeItem.removeBadge(): TextBadgeItem {
|
fun TextBadgeItem.removeBadge(): TextBadgeItem {
|
||||||
this.setText("")
|
this.setText("")
|
||||||
this.hide()
|
this.hide()
|
||||||
@ -10,7 +9,4 @@ fun TextBadgeItem.removeBadge(): TextBadgeItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun TextBadgeItem.maybeShow(): TextBadgeItem =
|
fun TextBadgeItem.maybeShow(): TextBadgeItem =
|
||||||
if (this.isHidden)
|
if (this.isHidden) this.show() else this
|
||||||
this.show()
|
|
||||||
else
|
|
||||||
this
|
|
||||||
|
@ -8,8 +8,6 @@ import android.widget.TextView
|
|||||||
|
|
||||||
import apps.amine.bou.readerforselfoss.R
|
import apps.amine.bou.readerforselfoss.R
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
open class CustomBaseViewHolder(var view: View) : RecyclerView.ViewHolder(view) {
|
open class CustomBaseViewHolder(var view: View) : RecyclerView.ViewHolder(view) {
|
||||||
var icon: ImageView = view.findViewById(R.id.material_drawer_icon)
|
var icon: ImageView = view.findViewById(R.id.material_drawer_icon)
|
||||||
var name: TextView = view.findViewById(R.id.material_drawer_name)
|
var name: TextView = view.findViewById(R.id.material_drawer_name)
|
||||||
|
@ -15,8 +15,6 @@ import com.mikepenz.materialdrawer.util.DrawerImageLoader
|
|||||||
import com.mikepenz.materialdrawer.util.DrawerUIUtils
|
import com.mikepenz.materialdrawer.util.DrawerUIUtils
|
||||||
import com.mikepenz.materialize.util.UIUtils
|
import com.mikepenz.materialize.util.UIUtils
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
abstract class CustomUrlBasePrimaryDrawerItem<T, VH : RecyclerView.ViewHolder> : BaseDrawerItem<T, VH>() {
|
abstract class CustomUrlBasePrimaryDrawerItem<T, VH : RecyclerView.ViewHolder> : BaseDrawerItem<T, VH>() {
|
||||||
fun withIcon(url: String): T {
|
fun withIcon(url: String): T {
|
||||||
this.icon = ImageHolder(url)
|
this.icon = ImageHolder(url)
|
||||||
@ -77,7 +75,10 @@ abstract class CustomUrlBasePrimaryDrawerItem<T, VH : RecyclerView.ViewHolder> :
|
|||||||
val selectedIconColor = getSelectedIconColor(ctx)
|
val selectedIconColor = getSelectedIconColor(ctx)
|
||||||
|
|
||||||
//set the background for the item
|
//set the background for the item
|
||||||
UIUtils.setBackground(viewHolder.view, UIUtils.getSelectableBackground(ctx, selectedColor, true))
|
UIUtils.setBackground(
|
||||||
|
viewHolder.view,
|
||||||
|
UIUtils.getSelectableBackground(ctx, selectedColor, true)
|
||||||
|
)
|
||||||
//set the text for the name
|
//set the text for the name
|
||||||
StringHolder.applyTo(this.getName(), viewHolder.name)
|
StringHolder.applyTo(this.getName(), viewHolder.name)
|
||||||
//set the text for the description or hide
|
//set the text for the description or hide
|
||||||
@ -86,8 +87,11 @@ abstract class CustomUrlBasePrimaryDrawerItem<T, VH : RecyclerView.ViewHolder> :
|
|||||||
//set the colors for textViews
|
//set the colors for textViews
|
||||||
viewHolder.name.setTextColor(getTextColorStateList(color, selectedTextColor))
|
viewHolder.name.setTextColor(getTextColorStateList(color, selectedTextColor))
|
||||||
//set the description text color
|
//set the description text color
|
||||||
ColorHolder.applyToOr(descriptionTextColor,
|
ColorHolder.applyToOr(
|
||||||
viewHolder.description, getTextColorStateList(color, selectedTextColor))
|
descriptionTextColor,
|
||||||
|
viewHolder.description,
|
||||||
|
getTextColorStateList(color, selectedTextColor)
|
||||||
|
)
|
||||||
|
|
||||||
//define the typeface for our textViews
|
//define the typeface for our textViews
|
||||||
if (getTypeface() != null) {
|
if (getTypeface() != null) {
|
||||||
|
@ -10,7 +10,6 @@ import com.mikepenz.materialdrawer.holder.BadgeStyle
|
|||||||
import com.mikepenz.materialdrawer.holder.StringHolder
|
import com.mikepenz.materialdrawer.holder.StringHolder
|
||||||
import com.mikepenz.materialdrawer.model.interfaces.ColorfulBadgeable
|
import com.mikepenz.materialdrawer.model.interfaces.ColorfulBadgeable
|
||||||
|
|
||||||
|
|
||||||
class CustomUrlPrimaryDrawerItem : CustomUrlBasePrimaryDrawerItem<CustomUrlPrimaryDrawerItem, CustomUrlPrimaryDrawerItem.ViewHolder>(), ColorfulBadgeable<CustomUrlPrimaryDrawerItem> {
|
class CustomUrlPrimaryDrawerItem : CustomUrlBasePrimaryDrawerItem<CustomUrlPrimaryDrawerItem, CustomUrlPrimaryDrawerItem.ViewHolder>(), ColorfulBadgeable<CustomUrlPrimaryDrawerItem> {
|
||||||
protected var mBadge: StringHolder = StringHolder("")
|
protected var mBadge: StringHolder = StringHolder("")
|
||||||
protected var mBadgeStyle = BadgeStyle()
|
protected var mBadgeStyle = BadgeStyle()
|
||||||
@ -64,7 +63,10 @@ class CustomUrlPrimaryDrawerItem : CustomUrlBasePrimaryDrawerItem<CustomUrlPrima
|
|||||||
val badgeVisible = StringHolder.applyToOrHide(mBadge, viewHolder.badge)
|
val badgeVisible = StringHolder.applyToOrHide(mBadge, viewHolder.badge)
|
||||||
//style the badge if it is visible
|
//style the badge if it is visible
|
||||||
if (badgeVisible) {
|
if (badgeVisible) {
|
||||||
mBadgeStyle.style(viewHolder.badge, getTextColorStateList(getColor(ctx), getSelectedTextColor(ctx)))
|
mBadgeStyle.style(
|
||||||
|
viewHolder.badge,
|
||||||
|
getTextColorStateList(getColor(ctx), getSelectedTextColor(ctx))
|
||||||
|
)
|
||||||
viewHolder.badgeContainer.visibility = View.VISIBLE
|
viewHolder.badgeContainer.visibility = View.VISIBLE
|
||||||
} else {
|
} else {
|
||||||
viewHolder.badgeContainer.visibility = View.GONE
|
viewHolder.badgeContainer.visibility = View.GONE
|
||||||
@ -86,6 +88,5 @@ class CustomUrlPrimaryDrawerItem : CustomUrlBasePrimaryDrawerItem<CustomUrlPrima
|
|||||||
class ViewHolder(view: View) : CustomBaseViewHolder(view) {
|
class ViewHolder(view: View) : CustomBaseViewHolder(view) {
|
||||||
val badgeContainer: View = view.findViewById(R.id.material_drawer_badge_container)
|
val badgeContainer: View = view.findViewById(R.id.material_drawer_badge_container)
|
||||||
val badge: TextView = view.findViewById(R.id.material_drawer_badge)
|
val badge: TextView = view.findViewById(R.id.material_drawer_badge)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,22 +8,32 @@ import com.bumptech.glide.Glide
|
|||||||
import com.bumptech.glide.request.RequestOptions
|
import com.bumptech.glide.request.RequestOptions
|
||||||
import com.bumptech.glide.request.target.BitmapImageViewTarget
|
import com.bumptech.glide.request.target.BitmapImageViewTarget
|
||||||
|
|
||||||
|
|
||||||
fun Context.bitmapCenterCrop(url: String, iv: ImageView) =
|
fun Context.bitmapCenterCrop(url: String, iv: ImageView) =
|
||||||
Glide.with(this).asBitmap().load(url).apply(RequestOptions.centerCropTransform()).into(iv)
|
Glide.with(this)
|
||||||
|
.asBitmap()
|
||||||
|
.load(url)
|
||||||
|
.apply(RequestOptions.centerCropTransform())
|
||||||
|
.into(iv)
|
||||||
|
|
||||||
fun Context.bitmapFitCenter(url: String, iv: ImageView) =
|
fun Context.bitmapFitCenter(url: String, iv: ImageView) =
|
||||||
Glide.with(this).asBitmap().load(url).apply(RequestOptions.fitCenterTransform()).into(iv)
|
Glide.with(this)
|
||||||
|
.asBitmap()
|
||||||
|
.load(url)
|
||||||
|
.apply(RequestOptions.fitCenterTransform())
|
||||||
|
.into(iv)
|
||||||
|
|
||||||
fun Context.circularBitmapDrawable(url: String, iv: ImageView) =
|
fun Context.circularBitmapDrawable(url: String, iv: ImageView) =
|
||||||
Glide.with(this)
|
Glide.with(this)
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
.load(url)
|
.load(url)
|
||||||
.apply(RequestOptions.centerCropTransform()).
|
.apply(RequestOptions.centerCropTransform())
|
||||||
into(object : BitmapImageViewTarget(iv) {
|
.into(object : BitmapImageViewTarget(iv) {
|
||||||
override fun setResource(resource: Bitmap?) {
|
override fun setResource(resource: Bitmap?) {
|
||||||
val circularBitmapDrawable = RoundedBitmapDrawableFactory.create(resources, resource)
|
val circularBitmapDrawable = RoundedBitmapDrawableFactory.create(
|
||||||
circularBitmapDrawable.isCircular = true
|
resources,
|
||||||
iv.setImageDrawable(circularBitmapDrawable)
|
resource
|
||||||
}
|
)
|
||||||
})
|
circularBitmapDrawable.isCircular = true
|
||||||
|
iv.setImageDrawable(circularBitmapDrawable)
|
||||||
|
}
|
||||||
|
})
|
@ -10,10 +10,10 @@ import com.bumptech.glide.load.model.GlideUrl
|
|||||||
import com.bumptech.glide.module.GlideModule
|
import com.bumptech.glide.module.GlideModule
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
|
|
||||||
class SelfSignedGlideModule : GlideModule {
|
class SelfSignedGlideModule : GlideModule {
|
||||||
|
|
||||||
override fun applyOptions(context: Context?, builder: GlideBuilder?) {}
|
override fun applyOptions(context: Context?, builder: GlideBuilder?) {
|
||||||
|
}
|
||||||
|
|
||||||
override fun registerComponents(context: Context?, glide: Glide?, registry: Registry?) {
|
override fun registerComponents(context: Context?, glide: Glide?, registry: Registry?) {
|
||||||
|
|
||||||
@ -22,11 +22,12 @@ class SelfSignedGlideModule : GlideModule {
|
|||||||
if (pref.getBoolean("isSelfSignedCert", false)) {
|
if (pref.getBoolean("isSelfSignedCert", false)) {
|
||||||
val client = getUnsafeHttpClient().build()
|
val client = getUnsafeHttpClient().build()
|
||||||
|
|
||||||
registry?.append(GlideUrl::class.java, InputStream::class.java,
|
registry?.append(
|
||||||
com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader.Factory(client))
|
GlideUrl::class.java,
|
||||||
|
InputStream::class.java,
|
||||||
|
com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader.Factory(client)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user