Code cleaning.

This commit is contained in:
Amine 2017-06-10 07:40:02 +02:00
parent 58a5b4a5e5
commit c14f47a74b
27 changed files with 811 additions and 697 deletions

View File

@ -25,8 +25,8 @@ android {
applicationId "apps.amine.bou.readerforselfoss"
minSdkVersion 16
targetSdkVersion 25
versionCode 1511
versionName "1.5.1.1"
versionCode 1512
versionName "1.5.1.2"
// Enabling multidex support.
multiDexEnabled true

View File

@ -6,14 +6,17 @@ import android.support.constraint.ConstraintLayout
import android.support.v7.app.AppCompatActivity
import android.view.View
import android.widget.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.Spout
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.isUrlValid
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class AddSourceActivity : AppCompatActivity() {
@ -39,15 +42,15 @@ class AddSourceActivity : AppCompatActivity() {
mustLoginToAddSource()
}
val intent = intent
if (Intent.ACTION_SEND == intent.action && "text/plain" == intent.type) {
mSourceUri.setText(intent.getStringExtra(Intent.EXTRA_TEXT))
mNameInput.setText(intent.getStringExtra(Intent.EXTRA_TITLE))
}
mSaveBtn.setOnClickListener { handleSaveSource(mTags, mNameInput.text.toString(), mSourceUri.text.toString(), api!!) }
mSaveBtn.setOnClickListener {
handleSaveSource(mTags, mNameInput.text.toString(), mSourceUri.text.toString(), api!!)
}
val spoutsKV = HashMap<String, String>()
@ -82,7 +85,11 @@ class AddSourceActivity : AppCompatActivity() {
mProgress.visibility = View.GONE
mForm.visibility = View.VISIBLE
val spinnerArrayAdapter = ArrayAdapter(this@AddSourceActivity, android.R.layout.simple_spinner_item, itemsStrings)
val spinnerArrayAdapter =
ArrayAdapter(
this@AddSourceActivity,
android.R.layout.simple_spinner_item,
itemsStrings)
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
mSpoutsSpinner.adapter = spinnerArrayAdapter
@ -115,7 +122,13 @@ class AddSourceActivity : AppCompatActivity() {
if (title.isEmpty() || url.isEmpty() || mSpoutsValue == null || mSpoutsValue!!.isEmpty()) {
Toast.makeText(this, R.string.form_not_complete, Toast.LENGTH_SHORT).show()
} else {
api.createSource(title, url, mSpoutsValue!!, mTags.text.toString(), "").enqueue(object : Callback<SuccessResponse> {
api.createSource(
title,
url,
mSpoutsValue!!,
mTags.text.toString(),
""
).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
if (response.body() != null && response.body()!!.isSuccess) {
finish()

View File

@ -1,5 +1,7 @@
package apps.amine.bou.readerforselfoss
import java.lang.Exception
import android.app.Activity
import android.content.Context
import android.content.Intent
@ -19,16 +21,7 @@ import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.Toast
import apps.amine.bou.readerforselfoss.adapters.ItemCardAdapter
import apps.amine.bou.readerforselfoss.adapters.ItemListAdapter
import apps.amine.bou.readerforselfoss.api.selfoss.*
import apps.amine.bou.readerforselfoss.settings.SettingsActivity
import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.checkAndDisplayStoreApk
import apps.amine.bou.readerforselfoss.utils.checkApkVersion
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import apps.amine.bou.readerforselfoss.utils.drawer.CustomUrlPrimaryDrawerItem
import apps.amine.bou.readerforselfoss.utils.longHash
import com.anupcowkur.reservoir.Reservoir
import com.anupcowkur.reservoir.ReservoirGetCallback
import com.anupcowkur.reservoir.ReservoirPutCallback
@ -54,7 +47,19 @@ import com.roughike.bottombar.BottomBarTab
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.lang.Exception
import apps.amine.bou.readerforselfoss.adapters.ItemCardAdapter
import apps.amine.bou.readerforselfoss.adapters.ItemListAdapter
import apps.amine.bou.readerforselfoss.api.selfoss.*
import apps.amine.bou.readerforselfoss.settings.SettingsActivity
import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.checkAndDisplayStoreApk
import apps.amine.bou.readerforselfoss.utils.checkApkVersion
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import apps.amine.bou.readerforselfoss.utils.drawer.CustomUrlPrimaryDrawerItem
import apps.amine.bou.readerforselfoss.utils.longHash
class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
@ -64,48 +69,136 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
private val DRAWER_ID_TAGS = 100101L
private val DRAWER_ID_SOURCES = 100110L
private val DRAWER_ID_FILTERS = 100111L
private var mRecyclerView: RecyclerView? = null
private var api: SelfossApi? = null
private var items: ArrayList<Item> = ArrayList()
private var mCustomTabActivityHelper: CustomTabActivityHelper? = null
private val UNREAD_SHOWN = 1
private val READ_SHOWN = 2
private val FAV_SHOWN = 3
private var items: ArrayList<Item> = ArrayList()
private var clickBehavior = false
private var internalBrowser = false
private var articleViewer = false
private var shouldBeCardView = false
private var displayUnreadCount = false
private var displayAllCount = false
private var editor: SharedPreferences.Editor? = null
private val UNREAD_SHOWN = 1
private val READ_SHOWN = 2
private val FAV_SHOWN = 3
private var elementsShown: Int = 0
private var mBottomBar: BottomBar? = null
private var mCoordinatorLayout: CoordinatorLayout? = null
private var mSwipeRefreshLayout: SwipeRefreshLayout? = null
private var sharedPref: SharedPreferences? = null
private var tabNew: BottomBarTab? = null
private var tabArchive: BottomBarTab? = null
private var tabStarred: BottomBarTab? = null
private var mFirebaseRemoteConfig: FirebaseRemoteConfig? = null
private var fullHeightCards: Boolean = false
private var toolbar: Toolbar? = null
private var drawer: Drawer? = null
private var elementsShown: Int = 0
private var maybeTagFilter: Tag? = null
private var maybeSourceFilter: Sources? = null
private var maybeSearchFilter: String? = null
private lateinit var mRecyclerView: RecyclerView
private lateinit var mBottomBar: BottomBar
private lateinit var mCoordinatorLayout: CoordinatorLayout
private lateinit var mSwipeRefreshLayout: SwipeRefreshLayout
private lateinit var tabNew: BottomBarTab
private lateinit var tabArchive: BottomBarTab
private lateinit var tabStarred: BottomBarTab
private lateinit var toolbar: Toolbar
private lateinit var drawer: Drawer
private lateinit var api: SelfossApi
private lateinit var mCustomTabActivityHelper: CustomTabActivityHelper
private lateinit var editor: SharedPreferences.Editor
private lateinit var sharedPref: SharedPreferences
private lateinit var mFirebaseRemoteConfig: FirebaseRemoteConfig
data class DrawerData(val tags: List<Tag>?, val sources: List<Sources>?)
private fun handleSharedPrefs() {
clickBehavior = this.sharedPref!!.getBoolean("tab_on_tap", false)
internalBrowser = this.sharedPref!!.getBoolean("prefer_internal_browser", true)
articleViewer = this.sharedPref!!.getBoolean("prefer_article_viewer", true)
shouldBeCardView = this.sharedPref!!.getBoolean("card_view_active", false)
displayUnreadCount = this.sharedPref!!.getBoolean("display_unread_count", true)
displayAllCount = this.sharedPref!!.getBoolean("display_other_count", false)
fullHeightCards = this.sharedPref!!.getBoolean("full_height_cards", false)
override fun onStart() {
super.onStart()
mCustomTabActivityHelper.bindCustomTabsService(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
toolbar = findViewById(R.id.toolbar) as Toolbar
setSupportActionBar(toolbar)
if (savedInstanceState == null) {
val promptView = findViewById(R.id.prompt_view) as DefaultLayoutPromptView
Amplify.getSharedInstance().promptIfReady(promptView)
}
mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance()
mFirebaseRemoteConfig.setDefaults(R.xml.default_remote_config)
mCustomTabActivityHelper = CustomTabActivityHelper()
api = SelfossApi(this)
items = ArrayList()
mBottomBar = findViewById(R.id.bottomBar) as BottomBar
handleDrawer()
// TODO: clean this hack
val listenerAlreadySet = booleanArrayOf(false)
mBottomBar.setOnTabSelectListener { tabId ->
if (listenerAlreadySet[0]) {
if (tabId == R.id.tab_new) {
getUnRead()
} else if (tabId == R.id.tab_archive) {
getRead()
} else if (tabId == R.id.tab_fav) {
getStarred()
}
getElementsAccordingToTab()
} else {
listenerAlreadySet[0] = true
}
}
mCoordinatorLayout = findViewById(R.id.coordLayout) as CoordinatorLayout
mSwipeRefreshLayout = findViewById(R.id.swipeRefreshLayout) as SwipeRefreshLayout
mRecyclerView = findViewById(R.id.my_recycler_view) as RecyclerView
reloadLayoutManager()
mSwipeRefreshLayout.setColorSchemeResources(
R.color.refresh_progress_1,
R.color.refresh_progress_2,
R.color.refresh_progress_3)
mSwipeRefreshLayout.setOnRefreshListener {
handleDrawerItems()
getElementsAccordingToTab()
}
val simpleItemTouchCallback =
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 onMove(recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder): Boolean = false
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, swipeDir: Int) {
try {
val i = items[viewHolder.adapterPosition]
val position = items.indexOf(i)
if (shouldBeCardView) {
(mRecyclerView.adapter as ItemCardAdapter).removeItemAtIndex(position)
} else {
(mRecyclerView.adapter as ItemListAdapter).removeItemAtIndex(position)
}
tabNew.setBadgeCount(items.size - 1)
} catch (e: IndexOutOfBoundsException) {}
}
}
ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(mRecyclerView)
checkAndDisplayStoreApk(this@HomeActivity)
}
override fun onResume() {
@ -119,75 +212,100 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
editor = settings.edit()
if (BuildConfig.GITHUB_VERSION) {
checkApkVersion(settings, editor!!, this@HomeActivity, mFirebaseRemoteConfig!!)
checkApkVersion(settings, editor, this@HomeActivity, mFirebaseRemoteConfig)
}
handleSharedPrefs()
tabNew = mBottomBar!!.getTabWithId(R.id.tab_new)
tabArchive = mBottomBar!!.getTabWithId(R.id.tab_archive)
tabStarred = mBottomBar!!.getTabWithId(R.id.tab_fav)
tabNew = mBottomBar.getTabWithId(R.id.tab_new)
tabArchive = mBottomBar.getTabWithId(R.id.tab_archive)
tabStarred = mBottomBar.getTabWithId(R.id.tab_fav)
getElementsAccordingToTab()
}
fun handleDrawer() {
override fun onStop() {
super.onStop()
mCustomTabActivityHelper.unbindCustomTabsService(this)
}
private fun handleSharedPrefs() {
clickBehavior = sharedPref.getBoolean("tab_on_tap", false)
internalBrowser = sharedPref.getBoolean("prefer_internal_browser", true)
articleViewer = sharedPref.getBoolean("prefer_article_viewer", true)
shouldBeCardView = sharedPref.getBoolean("card_view_active", false)
displayUnreadCount = sharedPref.getBoolean("display_unread_count", true)
displayAllCount = sharedPref.getBoolean("display_other_count", false)
fullHeightCards = sharedPref.getBoolean("full_height_cards", false)
}
private fun handleDrawer() {
drawer = DrawerBuilder()
.withActivity(this)
.withRootView(R.id.drawer_layout)
.withToolbar(toolbar!!)
.withToolbar(toolbar)
.withActionBarDrawerToggle(true)
.withActionBarDrawerToggleAnimated(true)
.withShowDrawerOnFirstLaunch(true)
.withOnDrawerListener(object: Drawer.OnDrawerListener {
override fun onDrawerSlide(p0: View?, p1: Float) {
mBottomBar!!.alpha = (1 - p1)
override fun onDrawerSlide(v: View?, p1: Float) {
mBottomBar.alpha = (1 - p1)
}
override fun onDrawerClosed(p0: View?) {
mBottomBar!!.shySettings.showBar()
override fun onDrawerClosed(v: View?) {
mBottomBar.shySettings.showBar()
}
override fun onDrawerOpened(p0: View?) {
mBottomBar!!.shySettings.hideBar()
override fun onDrawerOpened(v: View?) {
mBottomBar.shySettings.hideBar()
}
})
.build()
drawer!!.addStickyFooterItem(
drawer.addStickyFooterItem(
PrimaryDrawerItem()
.withName(R.string.action_about)
.withSelectable(false)
.withIcon(R.drawable.ic_info_outline)
.withOnDrawerItemClickListener { _, _, _ ->
LibsBuilder()
.withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR)
.withAboutIconShown(true)
.withAboutVersionShown(true)
.start(this@HomeActivity)
.withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR)
.withAboutIconShown(true)
.withAboutVersionShown(true)
.start(this@HomeActivity)
false
})
drawer!!.addStickyFooterItem(
drawer.addStickyFooterItem(
PrimaryDrawerItem()
.withName(R.string.title_activity_settings)
.withIcon(R.drawable.ic_settings)
.withOnDrawerItemClickListener { _, _, _ ->
startActivityForResult(Intent(this@HomeActivity, SettingsActivity::class.java), MENU_PREFERENCES)
startActivityForResult(
Intent(
this@HomeActivity,
SettingsActivity::class.java
),
MENU_PREFERENCES
)
false
}
)
}
fun handleDrawerItems() {
private fun handleDrawerItems() {
fun handleDrawerData(maybeDrawerData: DrawerData?, loadedFromCache: Boolean = false) {
fun handleTags(maybeTags: List<Tag>?) {
if (maybeTags == null) {
if (loadedFromCache)
drawer!!.addItem(SecondaryDrawerItem().withName(getString(R.string.drawer_error_loading_tags)).withSelectable(false))
drawer.addItem(
SecondaryDrawerItem()
.withName(getString(R.string.drawer_error_loading_tags))
.withSelectable(false))
}
else {
for (tag in maybeTags) {
@ -196,7 +314,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
gd.shape = GradientDrawable.RECTANGLE
gd.setSize(30, 30)
gd.cornerRadius = 30F
drawer!!.addItem(
drawer.addItem(
PrimaryDrawerItem()
.withName(tag.tag)
.withIdentifier(longHash(tag.tag))
@ -220,11 +338,14 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
fun handleSources(maybeSources: List<Sources>?) {
if (maybeSources == null) {
if (loadedFromCache)
drawer!!.addItem(SecondaryDrawerItem().withName(getString(R.string.drawer_error_loading_sources)).withSelectable(false))
drawer.addItem(
SecondaryDrawerItem()
.withName(getString(R.string.drawer_error_loading_sources))
.withSelectable(false))
}
else
for (tag in maybeSources)
drawer!!.addItem(
drawer.addItem(
CustomUrlPrimaryDrawerItem()
.withName(tag.title)
.withIdentifier(tag.id.toLong())
@ -238,9 +359,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
}
drawer!!.removeAllItems()
drawer.removeAllItems()
if (maybeDrawerData != null) {
drawer!!.addItem(
drawer.addItem(
SecondaryDrawerItem()
.withName(getString(R.string.drawer_item_filters))
.withSelectable(false)
@ -253,10 +374,14 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
false
}
)
drawer!!.addItem(DividerDrawerItem())
drawer!!.addItem(SecondaryDrawerItem().withName(getString(R.string.drawer_item_tags)).withIdentifier(DRAWER_ID_TAGS).withSelectable(false))
drawer.addItem(DividerDrawerItem())
drawer.addItem(
SecondaryDrawerItem()
.withName(getString(R.string.drawer_item_tags))
.withIdentifier(DRAWER_ID_TAGS)
.withSelectable(false))
handleTags(maybeDrawerData.tags)
drawer!!.addItem(
drawer.addItem(
SecondaryDrawerItem()
.withName(getString(R.string.drawer_item_sources))
.withIdentifier(DRAWER_ID_TAGS)
@ -280,8 +405,16 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
})
} else {
if (!loadedFromCache) {
drawer!!.addItem(PrimaryDrawerItem().withName(getString(R.string.no_tags_loaded)).withIdentifier(DRAWER_ID_TAGS).withSelectable(false))
drawer!!.addItem(PrimaryDrawerItem().withName(getString(R.string.no_sources_loaded)).withIdentifier(DRAWER_ID_SOURCES).withSelectable(false))
drawer.addItem(
PrimaryDrawerItem()
.withName(getString(R.string.no_tags_loaded))
.withIdentifier(DRAWER_ID_TAGS)
.withSelectable(false))
drawer.addItem(
PrimaryDrawerItem()
.withName(getString(R.string.no_sources_loaded))
.withIdentifier(DRAWER_ID_SOURCES)
.withSelectable(false))
}
}
@ -292,11 +425,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
var sources: List<Sources>?
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>>) {
sources = response.body()
val apiDrawerData = DrawerData(tags, sources)
if (maybeDrawerData == null || (maybeDrawerData != null && maybeDrawerData != apiDrawerData))
if ((maybeDrawerData != null && maybeDrawerData != apiDrawerData) || maybeDrawerData == null)
handleDrawerData(apiDrawerData)
}
@ -307,7 +440,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
})
}
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>>) {
tags = response.body()
sourcesApiCall()
@ -320,7 +453,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
})
}
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
Reservoir.getAsync("drawerData", resultType, object: ReservoirGetCallback<DrawerData> {
@ -336,102 +469,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
})
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
toolbar = findViewById(R.id.toolbar) as Toolbar?
setSupportActionBar(toolbar)
if (savedInstanceState == null) {
val promptView = findViewById(R.id.prompt_view) as DefaultLayoutPromptView
Amplify.getSharedInstance().promptIfReady(promptView)
}
mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance()
mFirebaseRemoteConfig!!.setDefaults(R.xml.default_remote_config)
mCustomTabActivityHelper = CustomTabActivityHelper()
api = SelfossApi(this)
items = ArrayList()
mBottomBar = findViewById(R.id.bottomBar) as BottomBar
handleDrawer()
// TODO: clean this hack
val listenerAlreadySet = booleanArrayOf(false)
mBottomBar!!.setOnTabSelectListener { tabId ->
if (listenerAlreadySet[0]) {
if (tabId == R.id.tab_new) {
getUnRead()
} else if (tabId == R.id.tab_archive) {
getRead()
} else if (tabId == R.id.tab_fav) {
getStarred()
}
getElementsAccordingToTab()
} else {
listenerAlreadySet[0] = true
}
}
mCoordinatorLayout = findViewById(R.id.coordLayout) as CoordinatorLayout
mSwipeRefreshLayout = findViewById(R.id.swipeRefreshLayout) as SwipeRefreshLayout
mRecyclerView = findViewById(R.id.my_recycler_view) as RecyclerView
reloadLayoutManager()
mSwipeRefreshLayout!!.setColorSchemeResources(
R.color.refresh_progress_1,
R.color.refresh_progress_2,
R.color.refresh_progress_3)
mSwipeRefreshLayout!!.setOnRefreshListener {
handleDrawerItems()
getElementsAccordingToTab()
}
val simpleItemTouchCallback = object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
override fun getSwipeDirs(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?): Int {
if (elementsShown != UNREAD_SHOWN) {
return 0
} else {
return super.getSwipeDirs(recyclerView, viewHolder)
}
}
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, swipeDir: Int) {
try {
val i = items[viewHolder.adapterPosition]
val position = items.indexOf(i)
if (shouldBeCardView) {
(mRecyclerView!!.adapter as ItemCardAdapter).removeItemAtIndex(position)
} else {
(mRecyclerView!!.adapter as ItemListAdapter).removeItemAtIndex(position)
}
tabNew!!.setBadgeCount(items.size - 1)
} catch (e: IndexOutOfBoundsException) {
}
}
}
val itemTouchHelper = ItemTouchHelper(simpleItemTouchCallback)
itemTouchHelper.attachToRecyclerView(mRecyclerView)
checkAndDisplayStoreApk(this@HomeActivity)
}
private fun reloadLayoutManager() {
val mLayoutManager: RecyclerView.LayoutManager
if (shouldBeCardView) {
@ -441,10 +478,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
mLayoutManager = GridLayoutManager(this, calculateNoOfColumns())
}
mRecyclerView!!.layoutManager = mLayoutManager
mRecyclerView!!.setHasFixedSize(true)
mRecyclerView.layoutManager = mLayoutManager
mRecyclerView.setHasFixedSize(true)
mBottomBar!!.setOnTabReselectListener {
mBottomBar.setOnTabReselectListener {
if (shouldBeCardView) {
if ((mLayoutManager as StaggeredGridLayoutManager).findFirstCompletelyVisibleItemPositions(null)[0] == 0) {
getElementsAccordingToTab()
@ -461,71 +498,56 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
}
}
private fun getElementsAccordingToTab() {
private fun getElementsAccordingToTab() =
when (elementsShown) {
UNREAD_SHOWN -> getUnRead()
READ_SHOWN -> getRead()
FAV_SHOWN -> getStarred()
else -> getUnRead()
}
private fun doCallTo(toastMessage: Int, call: (String?, Long?, String?) -> Call<List<Item>>) {
fun handleItemsResponse(response: Response<List<Item>>) {
val didUpdate = (response.body() != items)
if (response.body() != null) {
if (response.body() != items) {
items = response.body() as ArrayList<Item>
}
} else {
items = ArrayList()
}
if (didUpdate)
handleListResult()
if (items.isEmpty()) Toast.makeText(this@HomeActivity, R.string.nothing_here, Toast.LENGTH_SHORT).show()
mSwipeRefreshLayout.isRefreshing = false
}
call(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong(), maybeSearchFilter)
.enqueue(object : Callback<List<Item>> {
override fun onResponse(call: Call<List<Item>>, response: Response<List<Item>>) {
handleItemsResponse(response)
}
override fun onFailure(call: Call<List<Item>>, t: Throwable) {
mSwipeRefreshLayout.isRefreshing = false
Toast.makeText(this@HomeActivity, toastMessage, Toast.LENGTH_SHORT).show()
}
})
}
private fun getUnRead() {
elementsShown = UNREAD_SHOWN
api!!.unreadItems(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong(), maybeSearchFilter).enqueue(object : Callback<List<Item>> {
override fun onResponse(call: Call<List<Item>>, response: Response<List<Item>>) {
handleItemsResponse(response)
}
override fun onFailure(call: Call<List<Item>>, t: Throwable) {
mSwipeRefreshLayout!!.isRefreshing = false
Toast.makeText(this@HomeActivity, R.string.cant_get_new_elements, Toast.LENGTH_SHORT).show()
}
})
}
private fun handleItemsResponse(response: Response<List<Item>>) {
val didUpdate = (response.body() != items)
if (response.body() != null) {
if (response.body() != items) {
items = response.body() as ArrayList<Item>
}
} else {
items = ArrayList()
}
if (didUpdate)
handleListResult()
if (items.isEmpty()) Toast.makeText(this@HomeActivity, R.string.nothing_here, Toast.LENGTH_SHORT).show()
mSwipeRefreshLayout!!.isRefreshing = false
doCallTo(R.string.cant_get_new_elements){t, id, f -> api.unreadItems(t, id, f)}
}
private fun getRead() {
elementsShown = READ_SHOWN
api!!.readItems(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong(), maybeSearchFilter).enqueue(object : Callback<List<Item>> {
override fun onResponse(call: Call<List<Item>>, response: Response<List<Item>>) {
handleItemsResponse(response)
}
override fun onFailure(call: Call<List<Item>>, t: Throwable) {
Toast.makeText(this@HomeActivity, R.string.cant_get_read, Toast.LENGTH_SHORT).show()
mSwipeRefreshLayout!!.isRefreshing = false
}
})
doCallTo(R.string.cant_get_read){t, id, f -> api.readItems(t, id, f)}
}
private fun getStarred() {
elementsShown = FAV_SHOWN
api!!.starredItems(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong(), maybeSearchFilter).enqueue(object : Callback<List<Item>> {
override fun onResponse(call: Call<List<Item>>, response: Response<List<Item>>) {
handleItemsResponse(response)
}
override fun onFailure(call: Call<List<Item>>, t: Throwable) {
Toast.makeText(this@HomeActivity, R.string.cant_get_favs, Toast.LENGTH_SHORT).show()
mSwipeRefreshLayout!!.isRefreshing = false
}
})
doCallTo(R.string.cant_get_favs){t, id, f -> api.starredItems(t, id, f)}
}
private fun handleListResult() {
@ -533,157 +555,58 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
val mAdapter: RecyclerView.Adapter<*>
if (shouldBeCardView) {
mAdapter = ItemCardAdapter(this, items, api!!, mCustomTabActivityHelper!!, internalBrowser, articleViewer, fullHeightCards)
mAdapter =
ItemCardAdapter(
this,
items,
api,
mCustomTabActivityHelper,
internalBrowser,
articleViewer,
fullHeightCards)
} else {
mAdapter = ItemListAdapter(this, items, api!!, mCustomTabActivityHelper!!, clickBehavior, internalBrowser, articleViewer)
mAdapter =
ItemListAdapter(
this,
items,
api,
mCustomTabActivityHelper,
clickBehavior,
internalBrowser,
articleViewer)
}
mRecyclerView!!.adapter = mAdapter
mRecyclerView.adapter = mAdapter
mAdapter.notifyDataSetChanged()
reloadBadges()
}
override fun onStart() {
super.onStart()
mCustomTabActivityHelper!!.bindCustomTabsService(this)
}
override fun onStop() {
super.onStop()
mCustomTabActivityHelper!!.unbindCustomTabsService(this)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.home_menu, menu)
val searchItem = menu.findItem(R.id.action_search)
val searchView = MenuItemCompat.getActionView(searchItem) as SearchView
searchView.setOnQueryTextListener(this)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.refresh -> {
api!!.update().enqueue(object : Callback<String> {
override fun onResponse(call: Call<String>, response: Response<String>) {
Toast.makeText(this@HomeActivity,
R.string.refresh_success_response, Toast.LENGTH_LONG)
.show()
}
override fun onFailure(call: Call<String>, t: Throwable) {
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()
return true
}
R.id.readAll -> {
if (elementsShown == UNREAD_SHOWN) {
mSwipeRefreshLayout!!.isRefreshing = false
val ids = items.map { it.id }
api!!.readAll(ids).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
if (response.body() != null && response.body()!!.isSuccess) {
Toast.makeText(this@HomeActivity, R.string.all_posts_read, Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this@HomeActivity, R.string.all_posts_not_read, Toast.LENGTH_SHORT).show()
}
mSwipeRefreshLayout!!.isRefreshing = false
}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
Toast.makeText(this@HomeActivity, R.string.all_posts_not_read, Toast.LENGTH_SHORT).show()
mSwipeRefreshLayout!!.isRefreshing = false
}
})
items = ArrayList()
if (items.isEmpty()) Toast.makeText(this@HomeActivity, R.string.nothing_here, Toast.LENGTH_SHORT).show()
handleListResult()
}
return true
}
R.id.action_disconnect -> {
editor!!.remove("url")
editor!!.remove("login")
editor!!.remove("password")
editor!!.apply()
val intent = Intent(this, LoginActivity::class.java)
startActivity(intent)
finish()
return true
}
R.id.action_share_the_app -> {
if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
val share = AppInviteInvitation.IntentBuilder(getString(R.string.invitation_title))
.setMessage(getString(R.string.invitation_message))
.setDeepLink(Uri.parse("https://ymbh5.app.goo.gl/qbvQ"))
.setCallToActionText(getString(R.string.invitation_cta))
.build()
startActivityForResult(share, REQUEST_INVITE)
} else {
val sendIntent = Intent()
sendIntent.action = Intent.ACTION_SEND
sendIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.invitation_message) + " https://ymbh5.app.goo.gl/qbvQ")
sendIntent.type = "text/plain"
startActivityForResult(sendIntent, REQUEST_INVITE_BYMAIL)
}
return super.onOptionsItemSelected(item)
}
else -> return super.onOptionsItemSelected(item)
}
}
fun reloadBadges() {
private fun reloadBadges() {
if (displayUnreadCount || displayAllCount) {
api!!.stats.enqueue(object : Callback<Stats> {
api.stats.enqueue(object : Callback<Stats> {
override fun onResponse(call: Call<Stats>, response: Response<Stats>) {
if (response.body() != null) {
tabNew!!.setBadgeCount(response.body()!!.unread)
tabNew.setBadgeCount(response.body()!!.unread)
if (displayAllCount) {
tabArchive!!.setBadgeCount(response.body()!!.total)
tabStarred!!.setBadgeCount(response.body()!!.starred)
tabArchive.setBadgeCount(response.body()!!.total)
tabStarred.setBadgeCount(response.body()!!.starred)
} else {
tabArchive!!.removeBadge()
tabStarred!!.removeBadge()
tabArchive.removeBadge()
tabStarred.removeBadge()
}
}
}
override fun onFailure(call: Call<Stats>, t: Throwable) {
}
override fun onFailure(call: Call<Stats>, t: Throwable) {}
})
} else {
tabNew!!.removeBadge()
tabArchive!!.removeBadge()
tabStarred!!.removeBadge()
tabNew.removeBadge()
tabArchive.removeBadge()
tabStarred.removeBadge()
}
}
override fun onActivityResult(req: Int, result: Int, data: Intent?) {
when (req) {
MENU_PREFERENCES -> {
drawer!!.closeDrawer()
recreate()
}
REQUEST_INVITE -> if (result == Activity.RESULT_OK) {
Answers.getInstance().logInvite(InviteEvent())
}
REQUEST_INVITE_BYMAIL -> {
Answers.getInstance().logInvite(InviteEvent())
super.onActivityResult(req, result, data)
}
else -> super.onActivityResult(req, result, data)
}
}
fun calculateNoOfColumns(): Int {
private fun calculateNoOfColumns(): Int {
val displayMetrics = resources.displayMetrics
val dpWidth = displayMetrics.widthPixels / displayMetrics.density
return (dpWidth / 300).toInt()
@ -702,4 +625,111 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
getElementsAccordingToTab()
return false
}
override fun onActivityResult(req: Int, result: Int, data: Intent?) {
when (req) {
MENU_PREFERENCES -> {
drawer.closeDrawer()
recreate()
}
REQUEST_INVITE -> if (result == Activity.RESULT_OK) {
Answers.getInstance().logInvite(InviteEvent())
}
REQUEST_INVITE_BYMAIL -> {
Answers.getInstance().logInvite(InviteEvent())
super.onActivityResult(req, result, data)
}
else -> super.onActivityResult(req, result, data)
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.home_menu, menu)
val searchItem = menu.findItem(R.id.action_search)
val searchView = MenuItemCompat.getActionView(searchItem) as SearchView
searchView.setOnQueryTextListener(this)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.refresh -> {
api.update().enqueue(object : Callback<String> {
override fun onResponse(call: Call<String>, response: Response<String>) {
Toast.makeText(this@HomeActivity,
R.string.refresh_success_response, Toast.LENGTH_LONG)
.show()
}
override fun onFailure(call: Call<String>, t: Throwable) {
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()
return true
}
R.id.readAll -> {
if (elementsShown == UNREAD_SHOWN) {
mSwipeRefreshLayout.isRefreshing = false
val ids = items.map { it.id }
api.readAll(ids).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
if (response.body() != null && response.body()!!.isSuccess)
Toast.makeText(this@HomeActivity, R.string.all_posts_read, Toast.LENGTH_SHORT).show()
else
Toast.makeText(this@HomeActivity, R.string.all_posts_not_read, Toast.LENGTH_SHORT).show()
mSwipeRefreshLayout.isRefreshing = false
}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
Toast.makeText(this@HomeActivity, R.string.all_posts_not_read, Toast.LENGTH_SHORT).show()
mSwipeRefreshLayout.isRefreshing = false
}
})
items = ArrayList()
if (items.isEmpty())
Toast.makeText(this@HomeActivity, R.string.nothing_here, Toast.LENGTH_SHORT).show()
handleListResult()
}
return true
}
R.id.action_disconnect -> {
editor.remove("url")
editor.remove("login")
editor.remove("password")
editor.apply()
val intent = Intent(this, LoginActivity::class.java)
startActivity(intent)
finish()
return true
}
R.id.action_share_the_app -> {
if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
val share = AppInviteInvitation.IntentBuilder(getString(R.string.invitation_title))
.setMessage(getString(R.string.invitation_message))
.setDeepLink(Uri.parse("https://ymbh5.app.goo.gl/qbvQ"))
.setCallToActionText(getString(R.string.invitation_cta))
.build()
startActivityForResult(share, REQUEST_INVITE)
} else {
val sendIntent = Intent()
sendIntent.action = Intent.ACTION_SEND
sendIntent.putExtra(
Intent.EXTRA_TEXT,
getString(R.string.invitation_message) + " https://ymbh5.app.goo.gl/qbvQ"
)
sendIntent.type = "text/plain"
startActivityForResult(sendIntent, REQUEST_INVITE_BYMAIL)
}
return super.onOptionsItemSelected(item)
}
else -> return super.onOptionsItemSelected(item)
}
}
}

View File

@ -1,14 +1,16 @@
package apps.amine.bou.readerforselfoss
import agency.tango.materialintroscreen.MaterialIntroActivity
import agency.tango.materialintroscreen.MessageButtonBehaviour
import agency.tango.materialintroscreen.SlideFragmentBuilder
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.preference.PreferenceManager
import android.view.View
import agency.tango.materialintroscreen.MaterialIntroActivity
import agency.tango.materialintroscreen.MessageButtonBehaviour
import agency.tango.materialintroscreen.SlideFragmentBuilder
class IntroActivity : MaterialIntroActivity() {
@ -16,32 +18,32 @@ class IntroActivity : MaterialIntroActivity() {
super.onCreate(savedInstanceState)
addSlide(SlideFragmentBuilder()
.backgroundColor(R.color.colorPrimary)
.buttonsColor(R.color.colorAccent)
.image(R.mipmap.ic_launcher)
.title(getString(R.string.intro_hello_title))
.description(getString(R.string.intro_hello_message))
.build())
.backgroundColor(R.color.colorPrimary)
.buttonsColor(R.color.colorAccent)
.image(R.mipmap.ic_launcher)
.title(getString(R.string.intro_hello_title))
.description(getString(R.string.intro_hello_message))
.build())
addSlide(SlideFragmentBuilder()
.backgroundColor(R.color.colorAccent)
.buttonsColor(R.color.colorPrimary)
.image(R.drawable.ic_info_outline_white_48dp)
.title(getString(R.string.intro_needs_selfoss_title))
.description(getString(R.string.intro_needs_selfoss_message))
.build(),
MessageButtonBehaviour(View.OnClickListener {
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://selfoss.aditu.de"))
startActivity(browserIntent)
}, getString(R.string.intro_needs_selfoss_link)))
.backgroundColor(R.color.colorAccent)
.buttonsColor(R.color.colorPrimary)
.image(R.drawable.ic_info_outline_white_48dp)
.title(getString(R.string.intro_needs_selfoss_title))
.description(getString(R.string.intro_needs_selfoss_message))
.build(),
MessageButtonBehaviour(View.OnClickListener {
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://selfoss.aditu.de"))
startActivity(browserIntent)
}, getString(R.string.intro_needs_selfoss_link)))
addSlide(SlideFragmentBuilder()
.backgroundColor(R.color.colorPrimaryDark)
.buttonsColor(R.color.colorAccentDark)
.image(R.drawable.ic_thumb_up_white_48dp)
.title(getString(R.string.intro_all_set_title))
.description(getString(R.string.intro_all_set_message))
.build())
.backgroundColor(R.color.colorPrimaryDark)
.buttonsColor(R.color.colorAccentDark)
.image(R.drawable.ic_thumb_up_white_48dp)
.title(getString(R.string.intro_all_set_title))
.description(getString(R.string.intro_all_set_message))
.build())
}
override fun onFinish() {

View File

@ -18,11 +18,7 @@ import android.widget.Button
import android.widget.EditText
import android.widget.Switch
import android.widget.TextView
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.checkAndDisplayStoreApk
import apps.amine.bou.readerforselfoss.utils.isUrlValid
import com.google.firebase.analytics.FirebaseAnalytics
import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.LibsBuilder
@ -30,21 +26,29 @@ import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.checkAndDisplayStoreApk
import apps.amine.bou.readerforselfoss.utils.isUrlValid
class LoginActivity : AppCompatActivity() {
private var settings: SharedPreferences? = null
private var mProgressView: View? = null
private var mUrlView: EditText? = null
private var mLoginView: TextView? = null
private var mHTTPLoginView: TextView? = null
private var mPasswordView: EditText? = null
private var mHTTPPasswordView: EditText? = null
private var inValidCount: Int = 0
private var isWithLogin = false
private var isWithHTTPLogin = false
private var mLoginFormView: View? = null
private var mFirebaseAnalytics: FirebaseAnalytics? = null
private lateinit var settings: SharedPreferences
private lateinit var mFirebaseAnalytics: FirebaseAnalytics
private lateinit var mUrlView: EditText
private lateinit var mLoginView: TextView
private lateinit var mHTTPLoginView: TextView
private lateinit var mProgressView: View
private lateinit var mPasswordView: EditText
private lateinit var mHTTPPasswordView: EditText
private lateinit var mLoginFormView: View
@ -53,16 +57,12 @@ class LoginActivity : AppCompatActivity() {
setContentView(R.layout.activity_login)
settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
if (settings!!.getString("url", "").isNotEmpty()) {
if (settings.getString("url", "").isNotEmpty()) {
goToMain()
} else {
checkAndDisplayStoreApk(this@LoginActivity)
}
isWithLogin = false
isWithHTTPLogin = false
inValidCount = 0
mFirebaseAnalytics = FirebaseAnalytics.getInstance(this)
mUrlView = findViewById(R.id.url) as EditText
mLoginView = findViewById(R.id.login) as TextView
@ -80,7 +80,7 @@ class LoginActivity : AppCompatActivity() {
val mHTTPPasswordLayout = findViewById(R.id.httpPasswordInput) as TextInputLayout
val mEmailSignInButton = findViewById(R.id.email_sign_in_button) as Button
mPasswordView!!.setOnEditorActionListener(TextView.OnEditorActionListener { _, id, _ ->
mPasswordView.setOnEditorActionListener(TextView.OnEditorActionListener { _, id, _ ->
if (id == R.id.login || id == EditorInfo.IME_NULL) {
attemptLogin()
return@OnEditorActionListener true
@ -92,26 +92,16 @@ class LoginActivity : AppCompatActivity() {
mSwitch.setOnCheckedChangeListener { _, b ->
isWithLogin = !isWithLogin
val visi: Int
if (b) {
visi = View.VISIBLE
val visi: Int = if (b) View.VISIBLE else View.GONE
} else {
visi = View.GONE
}
mLoginLayout.visibility = visi
mPasswordLayout.visibility = visi
}
mHTTPSwitch.setOnCheckedChangeListener { _, b ->
isWithHTTPLogin = !isWithHTTPLogin
val visi: Int
if (b) {
visi = View.VISIBLE
val visi: Int = if (b) View.VISIBLE else View.GONE
} else {
visi = View.GONE
}
mHTTPLoginLayout.visibility = visi
mHTTPPasswordLayout.visibility = visi
}
@ -126,24 +116,24 @@ class LoginActivity : AppCompatActivity() {
private fun attemptLogin() {
// Reset errors.
mUrlView!!.error = null
mLoginView!!.error = null
mHTTPLoginView!!.error = null
mPasswordView!!.error = null
mHTTPPasswordView!!.error = null
mUrlView.error = null
mLoginView.error = null
mHTTPLoginView.error = null
mPasswordView.error = null
mHTTPPasswordView.error = null
// Store values at the time of the login attempt.
val url = mUrlView!!.text.toString()
val login = mLoginView!!.text.toString()
val httpLogin = mHTTPLoginView!!.text.toString()
val password = mPasswordView!!.text.toString()
val httpPassword = mHTTPPasswordView!!.text.toString()
val url = mUrlView.text.toString()
val login = mLoginView.text.toString()
val httpLogin = mHTTPLoginView.text.toString()
val password = mPasswordView.text.toString()
val httpPassword = mHTTPPasswordView.text.toString()
var cancel = false
var focusView: View? = null
if (!isUrlValid(url)) {
mUrlView!!.error = getString(R.string.login_url_problem)
mUrlView.error = getString(R.string.login_url_problem)
focusView = mUrlView
cancel = true
inValidCount++
@ -151,8 +141,10 @@ class LoginActivity : AppCompatActivity() {
val alertDialog = AlertDialog.Builder(this).create()
alertDialog.setTitle(getString(R.string.warning_wrong_url))
alertDialog.setMessage(getString(R.string.text_wrong_url))
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
{ dialog, _ -> dialog.dismiss() })
alertDialog.setButton(
AlertDialog.BUTTON_NEUTRAL,
"OK",
{ dialog, _ -> dialog.dismiss() })
alertDialog.show()
inValidCount = 0
}
@ -160,24 +152,24 @@ class LoginActivity : AppCompatActivity() {
if (isWithLogin || isWithHTTPLogin) {
if (TextUtils.isEmpty(password)) {
mPasswordView!!.error = getString(R.string.error_invalid_password)
mPasswordView.error = getString(R.string.error_invalid_password)
focusView = mPasswordView
cancel = true
}
if (TextUtils.isEmpty(login)) {
mLoginView!!.error = getString(R.string.error_field_required)
mLoginView.error = getString(R.string.error_field_required)
focusView = mLoginView
cancel = true
}
}
if (cancel) {
focusView!!.requestFocus()
focusView?.requestFocus()
} else {
showProgress(true)
val editor = settings!!.edit()
val editor = settings.edit()
editor.putString("url", url)
editor.putString("login", login)
editor.putString("httpUserName", httpLogin)
@ -194,17 +186,17 @@ class LoginActivity : AppCompatActivity() {
editor.remove("password")
editor.remove("httpPassword")
editor.apply()
mUrlView!!.error = getString(R.string.wrong_infos)
mLoginView!!.error = getString(R.string.wrong_infos)
mPasswordView!!.error = getString(R.string.wrong_infos)
mHTTPLoginView!!.error = getString(R.string.wrong_infos)
mHTTPPasswordView!!.error = getString(R.string.wrong_infos)
mUrlView.error = getString(R.string.wrong_infos)
mLoginView.error = getString(R.string.wrong_infos)
mPasswordView.error = getString(R.string.wrong_infos)
mHTTPLoginView.error = getString(R.string.wrong_infos)
mHTTPPasswordView.error = getString(R.string.wrong_infos)
showProgress(false)
}
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
if (response.body() != null && response.body()!!.isSuccess) {
mFirebaseAnalytics!!.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle())
mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle())
goToMain()
} else {
preferenceError()
@ -224,26 +216,33 @@ class LoginActivity : AppCompatActivity() {
private fun showProgress(show: Boolean) {
val shortAnimTime = resources.getInteger(android.R.integer.config_shortAnimTime)
mLoginFormView!!.visibility = if (show) View.GONE else View.VISIBLE
mLoginFormView!!.animate().setDuration(shortAnimTime.toLong()).alpha(
if (show) 0F else 1F).setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
mLoginFormView!!.visibility = if (show) View.GONE else View.VISIBLE
}
})
mLoginFormView.visibility = if (show) View.GONE else View.VISIBLE
mLoginFormView
.animate()
.setDuration(shortAnimTime.toLong())
.alpha(
if (show) 0F else 1F
).setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
mLoginFormView.visibility = if (show) View.GONE else View.VISIBLE
}
})
mProgressView!!.visibility = if (show) View.VISIBLE else View.GONE
mProgressView!!.animate().setDuration(shortAnimTime.toLong()).alpha(
if (show) 1F else 0F).setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
mProgressView!!.visibility = if (show) View.VISIBLE else View.GONE
}
})
mProgressView.visibility = if (show) View.VISIBLE else View.GONE
mProgressView
.animate()
.setDuration(shortAnimTime.toLong())
.alpha(
if (show) 1F else 0F
).setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
mProgressView.visibility = if (show) View.VISIBLE else View.GONE
}
})
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.login_menu, menu)
menuInflater.inflate(R.menu.login_menu, menu)
return true
}
@ -251,10 +250,10 @@ class LoginActivity : AppCompatActivity() {
when (item.itemId) {
R.id.about -> {
LibsBuilder()
.withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR)
.withAboutIconShown(true)
.withAboutVersionShown(true)
.start(this)
.withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR)
.withAboutIconShown(true)
.withAboutVersionShown(true)
.start(this)
return true
}
else -> return super.onOptionsItemSelected(item)

View File

@ -6,6 +6,7 @@ import android.preference.PreferenceManager
import android.support.v7.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {

View File

@ -5,14 +5,13 @@ import android.graphics.drawable.Drawable
import android.net.Uri
import android.support.multidex.MultiDexApplication
import android.widget.ImageView
import com.crashlytics.android.Crashlytics
import com.github.stkent.amplify.tracking.Amplify
import io.fabric.sdk.android.Fabric
import com.anupcowkur.reservoir.Reservoir
import com.bumptech.glide.Glide
import com.mikepenz.iconics.IconicsDrawable
import com.crashlytics.android.Crashlytics
import com.github.stkent.amplify.tracking.Amplify
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
import com.mikepenz.materialdrawer.util.DrawerImageLoader
import io.fabric.sdk.android.Fabric
import java.io.IOException

View File

@ -9,10 +9,7 @@ import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
import apps.amine.bou.readerforselfoss.api.mercury.MercuryApi
import apps.amine.bou.readerforselfoss.api.mercury.ParsedContent
import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import com.bumptech.glide.Glide
import org.sufficientlysecure.htmltextview.HtmlHttpImageGetter
import org.sufficientlysecure.htmltextview.HtmlTextView
@ -21,18 +18,24 @@ import retrofit2.Callback
import retrofit2.Response
import xyz.klinker.android.drag_dismiss.activity.DragDismissActivity
import apps.amine.bou.readerforselfoss.api.mercury.MercuryApi
import apps.amine.bou.readerforselfoss.api.mercury.ParsedContent
import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
class ReaderActivity : DragDismissActivity() {
private var mCustomTabActivityHelper: CustomTabActivityHelper? = null
private lateinit var mCustomTabActivityHelper: CustomTabActivityHelper
override fun onStart() {
super.onStart()
mCustomTabActivityHelper!!.bindCustomTabsService(this)
mCustomTabActivityHelper.bindCustomTabsService(this)
}
override fun onStop() {
super.onStop()
mCustomTabActivityHelper!!.unbindCustomTabsService(this)
mCustomTabActivityHelper.unbindCustomTabsService(this)
}
override fun onCreateContent(inflater: LayoutInflater, parent: ViewGroup, savedInstanceState: Bundle?): View {
@ -51,7 +54,7 @@ class ReaderActivity : DragDismissActivity() {
val customTabsIntent = buildCustomTabsIntent(this@ReaderActivity)
mCustomTabActivityHelper = CustomTabActivityHelper()
mCustomTabActivityHelper!!.bindCustomTabsService(this)
mCustomTabActivityHelper.bindCustomTabsService(this)
parser.parseUrl(url).enqueue(object : Callback<ParsedContent> {
@ -62,7 +65,12 @@ class ReaderActivity : DragDismissActivity() {
if (response.body()!!.content != null && !response.body()!!.content.isEmpty())
content.setHtml(response.body()!!.content, HtmlHttpImageGetter(content, null, true))
if (response.body()!!.lead_image_url != null && !response.body()!!.lead_image_url.isEmpty())
Glide.with(applicationContext).load(response.body()!!.lead_image_url).asBitmap().fitCenter().into(image)
Glide
.with(applicationContext)
.load(response.body()!!.lead_image_url)
.asBitmap()
.fitCenter()
.into(image)
shareBtn.setOnClickListener {
val sendIntent = Intent()
@ -81,14 +89,10 @@ class ReaderActivity : DragDismissActivity() {
}
hideProgressBar()
} else {
errorAfterMercuryCall()
}
} else errorAfterMercuryCall()
}
override fun onFailure(call: Call<ParsedContent>, t: Throwable) {
errorAfterMercuryCall()
}
override fun onFailure(call: Call<ParsedContent>, t: Throwable) = errorAfterMercuryCall()
private fun errorAfterMercuryCall() {
CustomTabActivityHelper.openCustomTab(this@ReaderActivity, customTabsIntent, Uri.parse(url)

View File

@ -6,14 +6,17 @@ import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.widget.Toast
import apps.amine.bou.readerforselfoss.adapters.SourcesListAdapter
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.Sources
import com.melnykov.fab.FloatingActionButton
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import apps.amine.bou.readerforselfoss.adapters.SourcesListAdapter
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.Sources
class SourcesActivity : AppCompatActivity() {

View File

@ -1,6 +1,5 @@
package apps.amine.bou.readerforselfoss.adapters
import android.app.Activity
import android.content.Context
import android.content.Intent
@ -20,13 +19,7 @@ import android.widget.ImageView
import android.widget.ImageView.ScaleType
import android.widget.TextView
import android.widget.Toast
import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.api.selfoss.Item
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import apps.amine.bou.readerforselfoss.utils.openItemUrl
import com.amulyakhare.textdrawable.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator
import com.bumptech.glide.Glide
@ -40,10 +33,21 @@ import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.*
import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.api.selfoss.Item
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import apps.amine.bou.readerforselfoss.utils.openItemUrl
class ItemCardAdapter(private val app: Activity, private val items: ArrayList<Item>, private val api: SelfossApi,
private val helper: CustomTabActivityHelper, private val internalBrowser: Boolean,
private val articleViewer: Boolean, private val fullHeightCards: Boolean) : RecyclerView.Adapter<ItemCardAdapter.ViewHolder>() {
class ItemCardAdapter(private val app: Activity,
private val items: ArrayList<Item>,
private val api: SelfossApi,
private val helper: CustomTabActivityHelper,
private val internalBrowser: Boolean,
private val articleViewer: Boolean,
private val fullHeightCards: Boolean) : RecyclerView.Adapter<ItemCardAdapter.ViewHolder>() {
private val c: Context = app.applicationContext
private val generator: ColorGenerator = ColorGenerator.MATERIAL
@ -56,8 +60,8 @@ class ItemCardAdapter(private val app: Activity, private val items: ArrayList<It
val itm = items[position]
holder.saveBtn!!.isLiked = itm.starred
holder.title!!.text = Html.fromHtml(itm.title)
holder.saveBtn.isLiked = itm.starred
holder.title.text = Html.fromHtml(itm.title)
var sourceAndDate = itm.sourcetitle
val d: Long
@ -73,11 +77,11 @@ class ItemCardAdapter(private val app: Activity, private val items: ArrayList<It
e.printStackTrace()
}
holder.sourceTitleAndDate!!.text = sourceAndDate
holder.sourceTitleAndDate.text = sourceAndDate
if (itm.getThumbnail(c).isEmpty()) {
Glide.clear(holder.itemImage)
holder.itemImage!!.setImageDrawable(null)
holder.itemImage.setImageDrawable(null)
} else {
if (fullHeightCards) {
Glide.with(c).load(itm.getThumbnail(c)).asBitmap().fitCenter().into(holder.itemImage)
@ -97,19 +101,19 @@ class ItemCardAdapter(private val app: Activity, private val items: ArrayList<It
val builder = TextDrawable.builder().round()
val drawable = builder.build(textDrawable.toString(), color)
holder.sourceImage!!.setImageDrawable(drawable)
holder.sourceImage.setImageDrawable(drawable)
} else {
Glide.with(c).load(itm.getIcon(c)).asBitmap().centerCrop().into(object : BitmapImageViewTarget(holder.sourceImage) {
override fun setResource(resource: Bitmap) {
val circularBitmapDrawable = RoundedBitmapDrawableFactory.create(c.resources, resource)
circularBitmapDrawable.isCircular = true
fHolder.sourceImage!!.setImageDrawable(circularBitmapDrawable)
fHolder.sourceImage.setImageDrawable(circularBitmapDrawable)
}
})
}
holder.saveBtn!!.isLiked = itm.starred
holder.saveBtn.isLiked = itm.starred
}
override fun getItemCount(): Int {
@ -163,13 +167,13 @@ class ItemCardAdapter(private val app: Activity, private val items: ArrayList<It
}
inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) {
var saveBtn: LikeButton? = null
var browserBtn: ImageButton? = null
var shareBtn: ImageButton? = null
var itemImage: ImageView? = null
var sourceImage: ImageView? = null
var title: TextView? = null
var sourceTitleAndDate: TextView? = null
lateinit var saveBtn: LikeButton
lateinit var browserBtn: ImageButton
lateinit var shareBtn: ImageButton
lateinit var itemImage: ImageView
lateinit var sourceImage: ImageView
lateinit var title: TextView
lateinit var sourceTitleAndDate: TextView
init {
handleClickListeners()
@ -186,18 +190,18 @@ class ItemCardAdapter(private val app: Activity, private val items: ArrayList<It
browserBtn = mView.findViewById(R.id.browserBtn) as ImageButton
if (!fullHeightCards) {
itemImage!!.maxHeight = c.resources.getDimension(R.dimen.card_image_max_height).toInt()
itemImage!!.scaleType = ScaleType.CENTER_CROP
itemImage.maxHeight = c.resources.getDimension(R.dimen.card_image_max_height).toInt()
itemImage.scaleType = ScaleType.CENTER_CROP
}
saveBtn!!.setOnLikeListener(object : OnLikeListener {
saveBtn.setOnLikeListener(object : OnLikeListener {
override fun liked(likeButton: LikeButton) {
val (id) = items[adapterPosition]
api.starrItem(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
saveBtn!!.isLiked = false
saveBtn.isLiked = false
Toast.makeText(c, R.string.cant_mark_favortie, Toast.LENGTH_SHORT).show()
}
})
@ -209,14 +213,14 @@ class ItemCardAdapter(private val app: Activity, private val items: ArrayList<It
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
saveBtn!!.isLiked = true
saveBtn.isLiked = true
Toast.makeText(c, R.string.cant_unmark_favortie, Toast.LENGTH_SHORT).show()
}
})
}
})
shareBtn!!.setOnClickListener {
shareBtn.setOnClickListener {
val i = items[adapterPosition]
val sendIntent = Intent()
sendIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
@ -226,7 +230,7 @@ class ItemCardAdapter(private val app: Activity, private val items: ArrayList<It
c.startActivity(Intent.createChooser(sendIntent, c.getString(R.string.share)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
}
browserBtn!!.setOnClickListener {
browserBtn.setOnClickListener {
val i = items[adapterPosition]
val intent = Intent(Intent.ACTION_VIEW)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
@ -241,11 +245,11 @@ class ItemCardAdapter(private val app: Activity, private val items: ArrayList<It
mView.setOnClickListener {
openItemUrl(items[adapterPosition],
customTabsIntent,
internalBrowser,
articleViewer,
app,
c)
customTabsIntent,
internalBrowser,
articleViewer,
app,
c)
}
}
}

View File

@ -18,13 +18,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.api.selfoss.Item
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import apps.amine.bou.readerforselfoss.utils.openItemUrl
import com.amulyakhare.textdrawable.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator
import com.bumptech.glide.Glide
@ -38,10 +32,23 @@ import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.*
import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.api.selfoss.Item
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import apps.amine.bou.readerforselfoss.utils.openItemUrl
class ItemListAdapter(private val app: Activity, private val items: ArrayList<Item>, private val api: SelfossApi,
private val helper: CustomTabActivityHelper, private val clickBehavior: Boolean,
private val internalBrowser: Boolean, private val articleViewer: Boolean) : RecyclerView.Adapter<ItemListAdapter.ViewHolder>() {
class ItemListAdapter(private val app: Activity,
private val items: ArrayList<Item>,
private val api: SelfossApi,
private val helper: CustomTabActivityHelper,
private val clickBehavior: Boolean,
private val internalBrowser: Boolean,
private val articleViewer: Boolean) : RecyclerView.Adapter<ItemListAdapter.ViewHolder>() {
private val generator: ColorGenerator = ColorGenerator.MATERIAL
private val c: Context = app.applicationContext
private val bars: ArrayList<Boolean> = ArrayList(Collections.nCopies(items.size + 1, false))
@ -55,41 +62,41 @@ class ItemListAdapter(private val app: Activity, private val items: ArrayList<It
val itm = items[position]
holder.saveBtn!!.isLiked = itm.starred
holder.title!!.text = Html.fromHtml(itm.title)
holder.saveBtn.isLiked = itm.starred
holder.title.text = Html.fromHtml(itm.title)
var sourceAndDate = itm.sourcetitle
val d: Long
try {
d = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(itm.datetime).time
sourceAndDate += " " + DateUtils.getRelativeTimeSpanString(
d,
Date().time,
DateUtils.MINUTE_IN_MILLIS,
DateUtils.FORMAT_ABBREV_RELATIVE
d,
Date().time,
DateUtils.MINUTE_IN_MILLIS,
DateUtils.FORMAT_ABBREV_RELATIVE
)
} catch (e: ParseException) {
e.printStackTrace()
}
holder.sourceTitleAndDate!!.text = sourceAndDate
holder.sourceTitleAndDate.text = sourceAndDate
if (itm.getThumbnail(c).isEmpty()) {
val sizeInInt = 46
val sizeInDp = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, sizeInInt.toFloat(), c.resources
.displayMetrics).toInt()
TypedValue.COMPLEX_UNIT_DIP, sizeInInt.toFloat(), c.resources
.displayMetrics).toInt()
val marginInInt = 16
val marginInDp = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, marginInInt.toFloat(), c.resources
.displayMetrics).toInt()
val params = holder.sourceImage!!.layoutParams as ViewGroup.MarginLayoutParams
val params = holder.sourceImage.layoutParams as ViewGroup.MarginLayoutParams
params.height = sizeInDp
params.width = sizeInDp
params.setMargins(marginInDp, 0, 0, 0)
holder.sourceImage!!.layoutParams = params
holder.sourceImage.layoutParams = params
if (itm.getIcon(c).isEmpty()) {
val color = generator.getColor(itm.sourcetitle)
@ -101,7 +108,7 @@ class ItemListAdapter(private val app: Activity, private val items: ArrayList<It
val builder = TextDrawable.builder().round()
val drawable = builder.build(textDrawable.toString(), color)
holder.sourceImage!!.setImageDrawable(drawable)
holder.sourceImage.setImageDrawable(drawable)
} else {
val fHolder = holder
@ -109,7 +116,7 @@ class ItemListAdapter(private val app: Activity, private val items: ArrayList<It
override fun setResource(resource: Bitmap) {
val circularBitmapDrawable = RoundedBitmapDrawableFactory.create(c.resources, resource)
circularBitmapDrawable.isCircular = true
fHolder.sourceImage!!.setImageDrawable(circularBitmapDrawable)
fHolder.sourceImage.setImageDrawable(circularBitmapDrawable)
}
})
}
@ -117,18 +124,12 @@ class ItemListAdapter(private val app: Activity, private val items: ArrayList<It
Glide.with(c).load(itm.getThumbnail(c)).asBitmap().centerCrop().into(holder.sourceImage)
}
if (bars[position]) {
holder.actionBar!!.visibility = View.VISIBLE
} else {
holder.actionBar!!.visibility = View.GONE
}
if (bars[position]) holder.actionBar.visibility = View.VISIBLE else holder.actionBar.visibility = View.GONE
holder.saveBtn!!.isLiked = itm.starred
holder.saveBtn.isLiked = itm.starred
}
override fun getItemCount(): Int {
return items.size
}
override fun getItemCount(): Int = items.size
private fun doUnmark(i: Item, position: Int) {
@ -178,13 +179,13 @@ class ItemListAdapter(private val app: Activity, private val items: ArrayList<It
}
inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) {
var saveBtn: LikeButton? = null
var browserBtn: ImageButton? = null
var shareBtn: ImageButton? = null
var actionBar: RelativeLayout? = null
var sourceImage: ImageView? = null
var title: TextView? = null
var sourceTitleAndDate: TextView? = null
lateinit var saveBtn: LikeButton
lateinit var browserBtn: ImageButton
lateinit var shareBtn: ImageButton
lateinit var actionBar: RelativeLayout
lateinit var sourceImage: ImageView
lateinit var title: TextView
lateinit var sourceTitleAndDate: TextView
init {
handleClickListeners()
@ -201,14 +202,14 @@ class ItemListAdapter(private val app: Activity, private val items: ArrayList<It
browserBtn = mView.findViewById(R.id.browserBtn) as ImageButton
saveBtn!!.setOnLikeListener(object : OnLikeListener {
saveBtn.setOnLikeListener(object : OnLikeListener {
override fun liked(likeButton: LikeButton) {
val (id) = items[adapterPosition]
api.starrItem(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
saveBtn!!.isLiked = false
saveBtn.isLiked = false
Toast.makeText(c, R.string.cant_mark_favortie, Toast.LENGTH_SHORT).show()
}
})
@ -220,14 +221,14 @@ class ItemListAdapter(private val app: Activity, private val items: ArrayList<It
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
saveBtn!!.isLiked = true
saveBtn.isLiked = true
Toast.makeText(c, R.string.cant_unmark_favortie, Toast.LENGTH_SHORT).show()
}
})
}
})
shareBtn!!.setOnClickListener {
shareBtn.setOnClickListener {
val i = items[adapterPosition]
val sendIntent = Intent()
sendIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
@ -237,7 +238,7 @@ class ItemListAdapter(private val app: Activity, private val items: ArrayList<It
c.startActivity(Intent.createChooser(sendIntent, c.getString(R.string.share)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
}
browserBtn!!.setOnClickListener {
browserBtn.setOnClickListener {
val i = items[adapterPosition]
val intent = Intent(Intent.ACTION_VIEW)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
@ -255,11 +256,11 @@ class ItemListAdapter(private val app: Activity, private val items: ArrayList<It
if (!clickBehavior) {
mView.setOnClickListener {
openItemUrl(items[adapterPosition],
customTabsIntent,
internalBrowser,
articleViewer,
app,
c)
customTabsIntent,
internalBrowser,
articleViewer,
app,
c)
}
mView.setOnLongClickListener {
actionBarShowHide()
@ -269,11 +270,11 @@ class ItemListAdapter(private val app: Activity, private val items: ArrayList<It
mView.setOnClickListener { actionBarShowHide() }
mView.setOnLongClickListener {
openItemUrl(items[adapterPosition],
customTabsIntent,
internalBrowser,
articleViewer,
app,
c)
customTabsIntent,
internalBrowser,
articleViewer,
app,
c)
true
}
}
@ -281,10 +282,7 @@ class ItemListAdapter(private val app: Activity, private val items: ArrayList<It
private fun actionBarShowHide() {
bars[adapterPosition] = true
if (actionBar!!.visibility == View.GONE)
actionBar!!.visibility = View.VISIBLE
else
actionBar!!.visibility = View.GONE
if (actionBar.visibility == View.GONE) actionBar.visibility = View.VISIBLE else actionBar.visibility = View.GONE
}
}
}

View File

@ -12,10 +12,7 @@ import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.Sources
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import com.amulyakhare.textdrawable.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator
import com.bumptech.glide.Glide
@ -24,7 +21,16 @@ import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class SourcesListAdapter(private val app: Activity, private val items: ArrayList<Sources>, private val api: SelfossApi) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>() {
import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.Sources
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
class SourcesListAdapter(private val app: Activity,
private val items: ArrayList<Sources>,
private val api: SelfossApi) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>() {
private val c: Context = app.baseContext
private val generator: ColorGenerator = ColorGenerator.MATERIAL
@ -49,13 +55,18 @@ class SourcesListAdapter(private val app: Activity, private val items: ArrayList
val drawable = builder.build(textDrawable.toString(), color)
holder.sourceImage!!.setImageDrawable(drawable)
} else {
Glide.with(c).load(itm.getIcon(c)).asBitmap().centerCrop().into(object : BitmapImageViewTarget(holder.sourceImage) {
override fun setResource(resource: Bitmap) {
val circularBitmapDrawable = RoundedBitmapDrawableFactory.create(c.resources, resource)
circularBitmapDrawable.isCircular = true
fHolder.sourceImage!!.setImageDrawable(circularBitmapDrawable)
}
})
Glide
.with(c)
.load(itm.getIcon(c))
.asBitmap()
.centerCrop()
.into(object : BitmapImageViewTarget(holder.sourceImage) {
override fun setResource(resource: Bitmap) {
val circularBitmapDrawable = RoundedBitmapDrawableFactory.create(c.resources, resource)
circularBitmapDrawable.isCircular = true
fHolder.sourceImage!!.setImageDrawable(circularBitmapDrawable)
}
})
}
holder.sourceTitle!!.text = itm.title
@ -89,12 +100,12 @@ class SourcesListAdapter(private val app: Activity, private val items: ArrayList
notifyItemRemoved(adapterPosition)
notifyItemRangeChanged(adapterPosition, itemCount)
} else {
Toast.makeText(app, "Petit soucis lors de la suppression de la 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) {
Toast.makeText(app, "Petit soucis lors de la suppression de la source.", Toast.LENGTH_SHORT).show()
Toast.makeText(app, R.string.can_delete_source, Toast.LENGTH_SHORT).show()
}
})
}

View File

@ -1,6 +1,5 @@
package apps.amine.bou.readerforselfoss.api.mercury
import com.google.gson.GsonBuilder
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
@ -9,6 +8,7 @@ import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class MercuryApi(private val key: String) {
private val service: MercuryService
@ -21,8 +21,13 @@ class MercuryApi(private val key: String) {
val gson = GsonBuilder()
.setLenient()
.create()
val retrofit = Retrofit.Builder().baseUrl("https://mercury.postlight.com").client(client)
.addConverterFactory(GsonConverterFactory.create(gson)).build()
val retrofit =
Retrofit
.Builder()
.baseUrl("https://mercury.postlight.com")
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
service = retrofit.create(MercuryService::class.java)
}

View File

@ -4,6 +4,7 @@ import android.os.Parcel
import android.os.Parcelable
class ParsedContent(val title: String,
val content: String,
val date_published: String,
@ -24,17 +25,17 @@ class ParsedContent(val title: String,
}
constructor(source: Parcel) : this(
title = source.readString(),
content = source.readString(),
date_published = source.readString(),
lead_image_url = source.readString(),
dek = source.readString(),
url = source.readString(),
domain = source.readString(),
excerpt = source.readString(),
total_pages = source.readInt(),
rendered_pages = source.readInt(),
next_page_url = source.readString()
title = source.readString(),
content = source.readString(),
date_published = source.readString(),
lead_image_url = source.readString(),
dek = source.readString(),
url = source.readString(),
domain = source.readString(),
excerpt = source.readString(),
total_pages = source.readInt(),
rendered_pages = source.readInt(),
next_page_url = source.readString()
)
override fun describeContents() = 0

View File

@ -7,6 +7,7 @@ import retrofit2.http.Header
import retrofit2.http.Query
interface MercuryService {
@GET("parser")
fun parseUrl(@Query("url") url: String, @Header("x-api-key") key: String): Call<ParsedContent>

View File

@ -1,10 +1,12 @@
package apps.amine.bou.readerforselfoss.api.selfoss
import java.lang.reflect.Type
import com.google.gson.JsonParseException
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonElement
import com.google.gson.JsonDeserializer
import java.lang.reflect.Type
internal class BooleanTypeAdapter : JsonDeserializer<Boolean> {

View File

@ -1,8 +1,8 @@
package apps.amine.bou.readerforselfoss.api.selfoss
import android.content.Context
import apps.amine.bou.readerforselfoss.utils.Config
import java.util.concurrent.ConcurrentHashMap
import com.burgstaller.okhttp.AuthenticationCacheInterceptor
import com.burgstaller.okhttp.CachingAuthenticatorDecorator
import com.burgstaller.okhttp.DispatchingAuthenticator
@ -16,7 +16,9 @@ import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.ConcurrentHashMap
import apps.amine.bou.readerforselfoss.utils.Config
class SelfossApi(c: Context) {
@ -43,28 +45,33 @@ class SelfossApi(c: Context) {
// note that all auth schemes should be registered as lowercase!
val authenticator = DispatchingAuthenticator.Builder()
.with("digest", digestAuthenticator)
.with("basic", basicAuthenticator)
.build()
.with("digest", digestAuthenticator)
.with("basic", basicAuthenticator)
.build()
val client = httpBuilder
.authenticator(CachingAuthenticatorDecorator(authenticator, authCache))
.addInterceptor(AuthenticationCacheInterceptor(authCache))
.addInterceptor(interceptor)
.build()
.authenticator(CachingAuthenticatorDecorator(authenticator, authCache))
.addInterceptor(AuthenticationCacheInterceptor(authCache))
.addInterceptor(interceptor)
.build()
val builder = GsonBuilder()
builder.registerTypeAdapter(Boolean::class.javaPrimitiveType, BooleanTypeAdapter())
val gson = builder
.setLenient()
.create()
.setLenient()
.create()
userName = config.userLogin
password = config.userPassword
val retrofit = Retrofit.Builder().baseUrl(config.baseUrl).client(client)
.addConverterFactory(GsonConverterFactory.create(gson)).build()
val retrofit =
Retrofit
.Builder()
.baseUrl(config.baseUrl)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
service = retrofit.create(SelfossService::class.java)
}

View File

@ -4,10 +4,12 @@ import android.content.Context
import android.net.Uri
import android.os.Parcel
import android.os.Parcelable
import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.isEmptyOrNullOrNullString
private fun constructUrl(config: Config?, path: String, file: String): String {
val baseUriBuilder = Uri.parse(config!!.baseUrl).buildUpon()
baseUriBuilder.appendPath(path).appendPath(file)
@ -65,15 +67,15 @@ data class Item(val id: String,
}
constructor(source: Parcel) : this(
id = source.readString(),
datetime = source.readString(),
title = source.readString(),
unread = 0.toByte() != source.readByte(),
starred = 0.toByte() != source.readByte(),
thumbnail = source.readString(),
icon = source.readString(),
link = source.readString(),
sourcetitle = source.readString()
id = source.readString(),
datetime = source.readString(),
title = source.readString(),
unread = 0.toByte() != source.readByte(),
starred = 0.toByte() != source.readByte(),
thumbnail = source.readString(),
icon = source.readString(),
link = source.readString(),
sourcetitle = source.readString()
)
override fun describeContents() = 0

View File

@ -1,6 +1,5 @@
package apps.amine.bou.readerforselfoss.api.selfoss
import retrofit2.Call
import retrofit2.http.DELETE
import retrofit2.http.Field
@ -11,6 +10,7 @@ import retrofit2.http.Path
import retrofit2.http.Query
internal interface SelfossService {
@GET("login")
fun loginToSelfoss(@Query("username") username: String, @Query("password") password: String): Call<SuccessResponse>
@ -24,47 +24,70 @@ internal interface SelfossService {
@Query("password") password: String): Call<List<Item>>
@POST("mark/{id}")
fun markAsRead(@Path("id") id: String, @Query("username") username: String, @Query("password") password: String): Call<SuccessResponse>
fun markAsRead(@Path("id") id: String,
@Query("username") username: String,
@Query("password") password: String): Call<SuccessResponse>
@POST("unmark/{id}")
fun unmarkAsRead(@Path("id") id: String, @Query("username") username: String, @Query("password") password: String): Call<SuccessResponse>
fun unmarkAsRead(@Path("id") id: String,
@Query("username") username: String,
@Query("password") password: String): Call<SuccessResponse>
@FormUrlEncoded
@POST("mark")
fun markAllAsRead(@Field("ids[]") ids: List<String>, @Query("username") username: String, @Query("password") password: String): Call<SuccessResponse>
fun markAllAsRead(@Field("ids[]") ids: List<String>,
@Query("username") username: String,
@Query("password") password: String): Call<SuccessResponse>
@POST("starr/{id}")
fun starr(@Path("id") id: String, @Query("username") username: String, @Query("password") password: String): Call<SuccessResponse>
fun starr(@Path("id") id: String,
@Query("username") username: String,
@Query("password") password: String): Call<SuccessResponse>
@POST("unstarr/{id}")
fun unstarr(@Path("id") id: String, @Query("username") username: String, @Query("password") password: String): Call<SuccessResponse>
fun unstarr(@Path("id") id: String,
@Query("username") username: String,
@Query("password") password: String): Call<SuccessResponse>
@GET("stats")
fun stats(@Query("username") username: String, @Query("password") password: String): Call<Stats>
fun stats(@Query("username") username: String,
@Query("password") password: String): Call<Stats>
@GET("tags")
fun tags(@Query("username") username: String, @Query("password") password: String): Call<List<Tag>>
fun tags(@Query("username") username: String,
@Query("password") password: String): Call<List<Tag>>
@GET("update")
fun update(@Query("username") username: String, @Query("password") password: String): Call<String>
fun update(@Query("username") username: String,
@Query("password") password: String): Call<String>
@GET("sources/spouts")
fun spouts(@Query("username") username: String, @Query("password") password: String): Call<Map<String, Spout>>
fun spouts(@Query("username") username: String,
@Query("password") password: String): Call<Map<String, Spout>>
@GET("sources/list")
fun sources(@Query("username") username: String, @Query("password") password: String): Call<List<Sources>>
fun sources(@Query("username") username: String,
@Query("password") password: String): Call<List<Sources>>
@DELETE("source/{id}")
fun deleteSource(@Path("id") id: String, @Query("username") username: String, @Query("password") password: String): Call<SuccessResponse>
fun deleteSource(@Path("id") id: String,
@Query("username") username: String,
@Query("password") password: String): Call<SuccessResponse>
@FormUrlEncoded
@POST("source")
fun createSource(@Field("title") title: String, @Field("url") url: String, @Field("spout") spout: String, @Field("tags") tags: String, @Field("filter") filter: String, @Query("username") username: String, @Query("password") password: String): Call<SuccessResponse>
fun createSource(@Field("title") title: String,
@Field("url") url: String,
@Field("spout") spout: String,
@Field("tags") tags: String,
@Field("filter") filter: String,
@Query("username") username: String,
@Query("password") password: String): Call<SuccessResponse>
}

View File

@ -7,33 +7,37 @@ import android.net.Uri
import android.support.v7.app.AlertDialog
import android.text.TextUtils
import android.util.Patterns
import apps.amine.bou.readerforselfoss.BuildConfig
import apps.amine.bou.readerforselfoss.R
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
import okhttp3.HttpUrl
private fun isStoreVersion(context: Context): Boolean {
var result = false
try {
val installer = context.packageManager
import apps.amine.bou.readerforselfoss.BuildConfig
import apps.amine.bou.readerforselfoss.R
fun checkAndDisplayStoreApk(context: Context) = {
fun isStoreVersion(context: Context): Boolean {
var result = false
try {
val installer = context.packageManager
.getInstallerPackageName(context.packageName)
result = !TextUtils.isEmpty(installer)
} catch (e: Throwable) {
result = !TextUtils.isEmpty(installer)
} catch (e: Throwable) {
}
return result
}
return result
}
fun checkAndDisplayStoreApk(context: Context) =
if (!isStoreVersion(context) && !BuildConfig.GITHUB_VERSION) {
val alertDialog = AlertDialog.Builder(context).create()
alertDialog.setTitle(context.getString(R.string.warning_version))
alertDialog.setMessage(context.getString(R.string.text_version))
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
{ dialog, _ -> dialog.dismiss() })
{ dialog, _ -> dialog.dismiss() })
alertDialog.show()
} else Unit
}
fun isUrlValid(url: String): Boolean {
val baseUrl = HttpUrl.parse(url)
@ -47,44 +51,46 @@ fun isUrlValid(url: String): Boolean {
}
fun isEmptyOrNullOrNullString(str: String?): Boolean =
str == null || str == "null" || str.isEmpty()
str == null || str == "null" || str.isEmpty()
fun checkApkVersion(settings: SharedPreferences, editor: SharedPreferences.Editor, context: Context, mFirebaseRemoteConfig: FirebaseRemoteConfig) {
mFirebaseRemoteConfig.fetch(43200)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
mFirebaseRemoteConfig.activateFetched()
} else {
fun checkApkVersion(settings: SharedPreferences,
editor: SharedPreferences.Editor,
context: Context,
mFirebaseRemoteConfig: FirebaseRemoteConfig) = {
fun isThereAnUpdate() {
val APK_LINK = "github_apk"
val apkLink = mFirebaseRemoteConfig.getString(APK_LINK)
val storedLink = settings.getString(APK_LINK, "")
if (apkLink != storedLink && !apkLink.isEmpty()) {
val alertDialog = AlertDialog.Builder(context).create()
alertDialog.setTitle(context.getString(R.string.new_apk_available_title))
alertDialog.setMessage(context.getString(R.string.new_apk_available_message))
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.new_apk_available_get)) { _, _ ->
editor.putString(APK_LINK, apkLink)
editor.apply()
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(apkLink))
context.startActivity(browserIntent)
}
isThereAnUpdate(settings, editor, context, mFirebaseRemoteConfig)
}
}
private fun isThereAnUpdate(settings: SharedPreferences, editor: SharedPreferences.Editor, context: Context, mFirebaseRemoteConfig: FirebaseRemoteConfig) {
val APK_LINK = "github_apk"
val apkLink = mFirebaseRemoteConfig.getString(APK_LINK)
val storedLink = settings.getString(APK_LINK, "")
if (apkLink != storedLink && !apkLink.isEmpty()) {
val alertDialog = AlertDialog.Builder(context).create()
alertDialog.setTitle(context.getString(R.string.new_apk_available_title))
alertDialog.setMessage(context.getString(R.string.new_apk_available_message))
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.new_apk_available_get)) { _, _ ->
editor.putString(APK_LINK, apkLink)
editor.apply()
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(apkLink))
context.startActivity(browserIntent)
}
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, context.getString(R.string.new_apk_available_no),
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, context.getString(R.string.new_apk_available_no),
{ dialog, _ ->
editor.putString(APK_LINK, apkLink)
editor.apply()
dialog.dismiss()
})
alertDialog.show()
alertDialog.show()
}
}
mFirebaseRemoteConfig.fetch(43200)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
mFirebaseRemoteConfig.activateFetched()
}
isThereAnUpdate()
}
}
fun longHash(string: String): Long {

View File

@ -7,11 +7,15 @@ import android.content.Intent
import android.graphics.BitmapFactory
import android.net.Uri
import android.support.customtabs.CustomTabsIntent
import xyz.klinker.android.drag_dismiss.DragDismissIntentBuilder
import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.ReaderActivity
import apps.amine.bou.readerforselfoss.api.selfoss.Item
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import xyz.klinker.android.drag_dismiss.DragDismissIntentBuilder
fun buildCustomTabsIntent(c: Context): CustomTabsIntent {

View File

@ -1,7 +1,6 @@
/* From https://github.com/mikepenz/MaterialDrawer/blob/develop/app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems/CustomBaseViewHolder.java */
package apps.amine.bou.readerforselfoss.utils.drawer
import android.support.v7.widget.RecyclerView
import android.view.View
import android.widget.ImageView
@ -10,6 +9,7 @@ import android.widget.TextView
import apps.amine.bou.readerforselfoss.R
open class CustomBaseViewHolder(var view: View) : RecyclerView.ViewHolder(view) {
var icon: ImageView = view.findViewById(R.id.material_drawer_icon) as ImageView
var name: TextView = view.findViewById(R.id.material_drawer_name) as TextView

View File

@ -1,8 +1,6 @@
/* From https://github.com/mikepenz/MaterialDrawer/blob/develop/app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems/CustomUrlBasePrimaryDrawerItem.java */
package apps.amine.bou.readerforselfoss.utils.drawer
import android.content.Context
import android.net.Uri
import android.support.annotation.ColorInt
import android.support.annotation.ColorRes
@ -18,6 +16,7 @@ import com.mikepenz.materialdrawer.util.DrawerUIUtils
import com.mikepenz.materialize.util.UIUtils
abstract class CustomUrlBasePrimaryDrawerItem<T, VH : RecyclerView.ViewHolder> : BaseDrawerItem<T, VH>() {
fun withIcon(url: String): T {
this.icon = ImageHolder(url)

View File

@ -1,18 +1,18 @@
/* From https://github.com/mikepenz/MaterialDrawer/blob/develop/app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems/CustomUrlPrimaryDrawerItem.java */
package apps.amine.bou.readerforselfoss.utils.drawer
import android.content.Context
import android.support.annotation.LayoutRes
import android.support.annotation.StringRes
import android.view.View
import android.widget.TextView
import apps.amine.bou.readerforselfoss.R
import com.mikepenz.materialdrawer.holder.BadgeStyle
import com.mikepenz.materialdrawer.holder.StringHolder
import com.mikepenz.materialdrawer.model.interfaces.ColorfulBadgeable
import apps.amine.bou.readerforselfoss.R
class CustomUrlPrimaryDrawerItem : CustomUrlBasePrimaryDrawerItem<CustomUrlPrimaryDrawerItem, CustomUrlPrimaryDrawerItem.ViewHolder>(), ColorfulBadgeable<CustomUrlPrimaryDrawerItem> {
protected var mBadge: StringHolder = StringHolder("")

View File

@ -15,7 +15,6 @@
<string name="label_share">"Partager"</string>
<string name="readAll">"Tout lire"</string>
<string name="action_disconnect">"Déconnecter"</string>
<string name="action_source">"Sources"</string>
<string name="title_activity_settings">"Paramètres"</string>
<string name="pref_header_general">"General"</string>
<string name="pref_switch_actions_tap_title">"Action du clique sur un article"</string>
@ -115,4 +114,5 @@
<string name="no_sources_loaded">Pas de sources chargés</string>
<string name="drawer_loading">Chargement …</string>
<string name="menu_home_search">Rechercher</string>
<string name="can_delete_source">Petit soucis lors de la suppression de la source.</string>
</resources>

View File

@ -15,7 +15,6 @@
<string name="label_share">"Delen"</string>
<string name="readAll">"Alles lezen"</string>
<string name="action_disconnect">"Verbinding verbreken"</string>
<string name="action_source">"Bronnen"</string>
<string name="title_activity_settings">"Instellingen"</string>
<string name="pref_header_general">"Algemeen"</string>
<string name="pref_switch_actions_tap_title">"Actie bij tikken op artikelen"</string>
@ -115,4 +114,5 @@
<string name="no_sources_loaded">No sources loaded</string>
<string name="drawer_loading">Loading …</string>
<string name="menu_home_search">Zoeken</string>
<string name="can_delete_source">Can\'t delete the source...</string>
</resources>

View File

@ -1,4 +1,4 @@
<resources>
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="app_name">"Reader for Selfoss"</string>
<string name="title_activity_login">"Log in"</string>
<string name="prompt_password">"Password"</string>
@ -15,7 +15,6 @@
<string name="label_share">"Share"</string>
<string name="readAll">"Read all"</string>
<string name="action_disconnect">"Disconnect"</string>
<string name="action_source">"Sources"</string>
<string name="title_activity_settings">"Settings"</string>
<string name="pref_header_general">"General"</string>
<string name="pref_switch_actions_tap_title">"Tap action on the articles"</string>
@ -112,9 +111,10 @@
<string name="drawer_item_tags">Tags</string>
<string name="drawer_item_sources">Sources</string>
<string name="drawer_action_edit">edit</string>
<string name="cache_drawer_error">Couldn\'t cache your drawer data</string>
<string name="cache_drawer_error" tools:keep="@string/cache_drawer_error">Couldn\'t cache your drawer data</string>
<string name="no_tags_loaded">No tags loaded</string>
<string name="no_sources_loaded">No sources loaded</string>
<string name="drawer_loading">Loading …</string>
<string name="menu_home_search">Search</string>
<string name="can_delete_source">Can\'t delete the source...</string>
</resources>