Reformated code according to official kotling style.

This commit is contained in:
Amine Bou 2018-01-21 18:08:39 +01:00
parent 3013ae4f35
commit 4d4a2039c8
37 changed files with 1315 additions and 1281 deletions

View File

@ -41,10 +41,10 @@ class AddSourceActivity : AppCompatActivity() {
try { try {
val prefs = PreferenceManager.getDefaultSharedPreferences(this) val prefs = PreferenceManager.getDefaultSharedPreferences(this)
api = SelfossApi( api = SelfossApi(
this, this,
this@AddSourceActivity, this@AddSourceActivity,
prefs.getBoolean("isSelfSignedCert", false), prefs.getBoolean("isSelfSignedCert", false),
prefs.getBoolean("should_log_everything", false) prefs.getBoolean("should_log_everything", false)
) )
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
mustLoginToAddSource() mustLoginToAddSource()
@ -69,10 +69,10 @@ class AddSourceActivity : AppCompatActivity() {
} }
private fun handleSpoutsSpinner( private fun handleSpoutsSpinner(
spoutsSpinner: Spinner, spoutsSpinner: Spinner,
api: SelfossApi?, api: SelfossApi?,
mProgress: ProgressBar, mProgress: ProgressBar,
formContainer: ConstraintLayout formContainer: ConstraintLayout
) { ) {
val spoutsKV = HashMap<String, String>() val spoutsKV = HashMap<String, String>()
spoutsSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { spoutsSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
@ -91,8 +91,8 @@ 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( override fun onResponse(
call: Call<Map<String, Spout>>, call: Call<Map<String, Spout>>,
response: Response<Map<String, Spout>> response: Response<Map<String, Spout>>
) { ) {
if (response.body() != null) { if (response.body() != null) {
items = response.body()!! items = response.body()!!
@ -106,11 +106,11 @@ class AddSourceActivity : AppCompatActivity() {
formContainer.visibility = View.VISIBLE formContainer.visibility = View.VISIBLE
val spinnerArrayAdapter = val spinnerArrayAdapter =
ArrayAdapter( ArrayAdapter(
this@AddSourceActivity, this@AddSourceActivity,
android.R.layout.simple_spinner_item, android.R.layout.simple_spinner_item,
itemsStrings itemsStrings
) )
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spoutsSpinner.adapter = spinnerArrayAdapter spoutsSpinner.adapter = spinnerArrayAdapter
} else { } else {
@ -124,9 +124,9 @@ class AddSourceActivity : AppCompatActivity() {
private fun handleProblemWithSpouts() { private fun handleProblemWithSpouts() {
Toast.makeText( Toast.makeText(
this@AddSourceActivity, this@AddSourceActivity,
R.string.cant_get_spouts, R.string.cant_get_spouts,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
mProgress.visibility = View.GONE mProgress.visibility = View.GONE
} }
@ -134,9 +134,9 @@ class AddSourceActivity : AppCompatActivity() {
} }
private fun maybeGetDetailsFromIntentSharing( private fun maybeGetDetailsFromIntentSharing(
intent: Intent, intent: Intent,
sourceUri: EditText, sourceUri: EditText,
nameInput: 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))
@ -153,38 +153,39 @@ class AddSourceActivity : AppCompatActivity() {
private fun handleSaveSource(tags: EditText, title: String, url: String, api: SelfossApi) { private fun handleSaveSource(tags: EditText, title: String, url: String, api: SelfossApi) {
val sourceDetailsAvailable = title.isEmpty() || url.isEmpty() || mSpoutsValue == null || mSpoutsValue!!.isEmpty() val sourceDetailsAvailable =
title.isEmpty() || url.isEmpty() || mSpoutsValue == null || mSpoutsValue!!.isEmpty()
if (sourceDetailsAvailable) { if (sourceDetailsAvailable) {
Toast.makeText(this, R.string.form_not_complete, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.form_not_complete, Toast.LENGTH_SHORT).show()
} else { } else {
api.createSource( api.createSource(
title, title,
url, url,
mSpoutsValue!!, mSpoutsValue!!,
tags.text.toString(), tags.text.toString(),
"" ""
).enqueue(object : Callback<SuccessResponse> { ).enqueue(object : Callback<SuccessResponse> {
override fun onResponse( override fun onResponse(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
response: Response<SuccessResponse> response: Response<SuccessResponse>
) { ) {
if (response.body() != null && response.body()!!.isSuccess) { if (response.body() != null && response.body()!!.isSuccess) {
finish() finish()
} else { } else {
Toast.makeText( Toast.makeText(
this@AddSourceActivity, this@AddSourceActivity,
R.string.cant_create_source, R.string.cant_create_source,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
} }
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
Toast.makeText( Toast.makeText(
this@AddSourceActivity, this@AddSourceActivity,
R.string.cant_create_source, R.string.cant_create_source,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
}) })

View File

@ -151,10 +151,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
sharedPref = PreferenceManager.getDefaultSharedPreferences(this) sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
api = SelfossApi( api = SelfossApi(
this, this,
this@HomeActivity, this@HomeActivity,
settings.getBoolean("isSelfSignedCert", false), settings.getBoolean("isSelfSignedCert", false),
sharedPref.getBoolean("should_log_everything", false) sharedPref.getBoolean("should_log_everything", false)
) )
items = ArrayList() items = ArrayList()
@ -168,9 +168,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
private fun handleSwipeRefreshLayout() { private fun handleSwipeRefreshLayout() {
swipeRefreshLayout.setColorSchemeResources( swipeRefreshLayout.setColorSchemeResources(
R.color.refresh_progress_1, R.color.refresh_progress_1,
R.color.refresh_progress_2, R.color.refresh_progress_2,
R.color.refresh_progress_3 R.color.refresh_progress_3
) )
swipeRefreshLayout.setOnRefreshListener { swipeRefreshLayout.setOnRefreshListener {
handleDrawerItems() handleDrawerItems()
@ -178,79 +178,79 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
} }
val simpleItemTouchCallback = val simpleItemTouchCallback =
object : ItemTouchHelper.SimpleCallback( object : ItemTouchHelper.SimpleCallback(
0, 0,
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
) { ) {
override fun getSwipeDirs( override fun getSwipeDirs(
recyclerView: RecyclerView?, recyclerView: RecyclerView?,
viewHolder: RecyclerView.ViewHolder? viewHolder: RecyclerView.ViewHolder?
): Int = ): Int =
if (elementsShown != UNREAD_SHOWN) { if (elementsShown != UNREAD_SHOWN) {
0 0
} else { } else {
super.getSwipeDirs( super.getSwipeDirs(
recyclerView, recyclerView,
viewHolder viewHolder
) )
} }
override fun onMove( override fun onMove(
recyclerView: RecyclerView, recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder, viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder target: RecyclerView.ViewHolder
): Boolean = false ): Boolean = false
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, swipeDir: Int) { override fun onSwiped(viewHolder: RecyclerView.ViewHolder, swipeDir: Int) {
try { try {
val i = items[viewHolder.adapterPosition] val i = items[viewHolder.adapterPosition]
val position = items.indexOf(i) val position = items.indexOf(i)
val adapter = recyclerView.adapter val adapter = recyclerView.adapter
when (adapter) { when (adapter) {
is ItemCardAdapter -> adapter.removeItemAtIndex(position) is ItemCardAdapter -> adapter.removeItemAtIndex(position)
is ItemListAdapter -> adapter.removeItemAtIndex(position) is ItemListAdapter -> adapter.removeItemAtIndex(position)
}
if (items.size > 0) {
badgeNew--
reloadBadgeContent()
} else {
tabNewBadge.hide()
}
val manager = recyclerView.layoutManager
val lastVisibleItem: Int = when (manager) {
is StaggeredGridLayoutManager -> manager.findLastCompletelyVisibleItemPositions(
null
).last()
is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition()
else -> 0
}
if (lastVisibleItem === items.size &&
items.size <= maxItemNumber() &&
(maxItemNumber() >= itemsNumber || !lastFetchDone)
) {
if (maxItemNumber() < itemsNumber) {
lastFetchDone = true
}
getElementsAccordingToTab(
appendResults = true,
offsetOverride = lastVisibleItem
)
}
} catch (e: IndexOutOfBoundsException) {
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(
100,
"SWIPE_INDEX_OUT_OF_BOUND",
"IndexOutOfBoundsException when swiping"
)
Crashlytics.logException(e)
} }
if (items.size > 0) {
badgeNew--
reloadBadgeContent()
} else {
tabNewBadge.hide()
}
val manager = recyclerView.layoutManager
val lastVisibleItem: Int = when (manager) {
is StaggeredGridLayoutManager -> manager.findLastCompletelyVisibleItemPositions(
null
).last()
is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition()
else -> 0
}
if (lastVisibleItem === items.size &&
items.size <= maxItemNumber() &&
(maxItemNumber() >= itemsNumber || !lastFetchDone)
) {
if (maxItemNumber() < itemsNumber) {
lastFetchDone = true
}
getElementsAccordingToTab(
appendResults = true,
offsetOverride = lastVisibleItem
)
}
} catch (e: IndexOutOfBoundsException) {
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(
100,
"SWIPE_INDEX_OUT_OF_BOUND",
"IndexOutOfBoundsException when swiping"
)
Crashlytics.logException(e)
} }
} }
}
ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(recyclerView) ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(recyclerView)
} }
@ -258,43 +258,43 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
private fun handleBottomBar() { private fun handleBottomBar() {
tabNewBadge = TextBadgeItem() tabNewBadge = TextBadgeItem()
.setText("") .setText("")
.setHideOnSelect(false).hide(false) .setHideOnSelect(false).hide(false)
.setBackgroundColor(appColors.primary) .setBackgroundColor(appColors.primary)
tabArchiveBadge = TextBadgeItem() tabArchiveBadge = TextBadgeItem()
.setText("") .setText("")
.setHideOnSelect(false).hide(false) .setHideOnSelect(false).hide(false)
.setBackgroundColor(appColors.primary) .setBackgroundColor(appColors.primary)
tabStarredBadge = TextBadgeItem() tabStarredBadge = TextBadgeItem()
.setText("") .setText("")
.setHideOnSelect(false).hide(false) .setHideOnSelect(false).hide(false)
.setBackgroundColor(appColors.primary) .setBackgroundColor(appColors.primary)
val tabNew = val tabNew =
BottomNavigationItem( BottomNavigationItem(
R.drawable.ic_fiber_new_black_24dp, R.drawable.ic_fiber_new_black_24dp,
getString(R.string.tab_new) getString(R.string.tab_new)
).setActiveColor(appColors.accent) ).setActiveColor(appColors.accent)
.setBadgeItem(tabNewBadge) .setBadgeItem(tabNewBadge)
val tabArchive = val tabArchive =
BottomNavigationItem( BottomNavigationItem(
R.drawable.ic_archive_black_24dp, R.drawable.ic_archive_black_24dp,
getString(R.string.tab_read) getString(R.string.tab_read)
).setActiveColor(appColors.dark) ).setActiveColor(appColors.dark)
.setBadgeItem(tabArchiveBadge) .setBadgeItem(tabArchiveBadge)
val tabStarred = val tabStarred =
BottomNavigationItem( BottomNavigationItem(
R.drawable.ic_favorite_black_24dp, R.drawable.ic_favorite_black_24dp,
getString(R.string.tab_favs) getString(R.string.tab_favs)
).setActiveColorResource(R.color.pink) ).setActiveColorResource(R.color.pink)
.setBadgeItem(tabStarredBadge) .setBadgeItem(tabStarredBadge)
bottomBar bottomBar
.addItem(tabNew) .addItem(tabNew)
.addItem(tabArchive) .addItem(tabArchive)
.addItem(tabStarred) .addItem(tabStarred)
.setFirstSelectedPosition(0) .setFirstSelectedPosition(0)
.initialise() .initialise()
bottomBar.setMode(BottomNavigationBar.MODE_SHIFTING) bottomBar.setMode(BottomNavigationBar.MODE_SHIFTING)
bottomBar.setBackgroundStyle(BottomNavigationBar.BACKGROUND_STYLE_STATIC) bottomBar.setBackgroundStyle(BottomNavigationBar.BACKGROUND_STYLE_STATIC)
@ -351,7 +351,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
private fun handleDrawer() { private fun handleDrawer() {
displayAccountHeader = displayAccountHeader =
PreferenceManager.getDefaultSharedPreferences(this) PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean("account_header_displaying", false) .getBoolean("account_header_displaying", false)
drawer = drawer { drawer = drawer {
rootViewRes = R.id.drawer_layout rootViewRes = R.id.drawer_layout
@ -385,17 +385,17 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
iconTintingEnabled = true iconTintingEnabled = true
onClick { _ -> onClick { _ ->
IssueReporterLauncher.forTarget( IssueReporterLauncher.forTarget(
getString(R.string.report_github_user), getString(R.string.report_github_user),
getString(R.string.report_github_repo) 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)
.minDescriptionLength(20) .minDescriptionLength(20)
.putExtraInfo("Unique ID", settings.getString("unique_id", "")) .putExtraInfo("Unique ID", settings.getString("unique_id", ""))
.putExtraInfo("From github", BuildConfig.GITHUB_VERSION) .putExtraInfo("From github", BuildConfig.GITHUB_VERSION)
.homeAsUpEnabled(true) .homeAsUpEnabled(true)
.launch(this@HomeActivity) .launch(this@HomeActivity)
false false
} }
} }
@ -405,11 +405,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
iconTintingEnabled = true iconTintingEnabled = true
onClick { _ -> onClick { _ ->
startActivityForResult( startActivityForResult(
Intent( Intent(
this@HomeActivity, this@HomeActivity,
SettingsActivity::class.java SettingsActivity::class.java
), ),
MENU_PREFERENCES MENU_PREFERENCES
) )
false false
} }
@ -424,9 +424,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
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 {
@ -443,20 +443,20 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
gd.setSize(30, 30) gd.setSize(30, 30)
gd.cornerRadius = 30F gd.cornerRadius = 30F
drawer.addItem( drawer.addItem(
PrimaryDrawerItem() PrimaryDrawerItem()
.withName(tag.tag) .withName(tag.tag)
.withIdentifier(tag.tag.longHash()) .withIdentifier(tag.tag.longHash())
.withIcon(gd) .withIcon(gd)
.withBadge("${tag.unread}") .withBadge("${tag.unread}")
.withBadgeStyle( .withBadgeStyle(
BadgeStyle().withTextColor(Color.WHITE) BadgeStyle().withTextColor(Color.WHITE)
.withColor(appColors.accent) .withColor(appColors.accent)
) )
.withOnDrawerItemClickListener { _, _, _ -> .withOnDrawerItemClickListener { _, _, _ ->
maybeTagFilter = tag maybeTagFilter = tag
getElementsAccordingToTab() getElementsAccordingToTab()
false false
} }
) )
} }
} }
@ -466,23 +466,23 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
if (maybeSources == null) { if (maybeSources == null) {
if (loadedFromCache) { if (loadedFromCache) {
drawer.addItem( drawer.addItem(
SecondaryDrawerItem() SecondaryDrawerItem()
.withName(getString(R.string.drawer_error_loading_sources)) .withName(getString(R.string.drawer_error_loading_sources))
.withSelectable(false) .withSelectable(false)
) )
} }
} else { } else {
for (tag in maybeSources) { for (tag in maybeSources) {
drawer.addItem( drawer.addItem(
CustomUrlPrimaryDrawerItem() CustomUrlPrimaryDrawerItem()
.withName(tag.title) .withName(tag.title)
.withIdentifier(tag.id.toLong()) .withIdentifier(tag.id.toLong())
.withIcon(tag.getIcon(this@HomeActivity)) .withIcon(tag.getIcon(this@HomeActivity))
.withOnDrawerItemClickListener { _, _, _ -> .withOnDrawerItemClickListener { _, _, _ ->
maybeSourceFilter = tag maybeSourceFilter = tag
getElementsAccordingToTab() getElementsAccordingToTab()
false false
} }
) )
} }
} }
@ -491,86 +491,86 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
drawer.removeAllItems() drawer.removeAllItems()
if (maybeDrawerData != null) { if (maybeDrawerData != null) {
drawer.addItem( drawer.addItem(
SecondaryDrawerItem() SecondaryDrawerItem()
.withName(getString(R.string.drawer_item_filters)) .withName(getString(R.string.drawer_item_filters))
.withSelectable(false) .withSelectable(false)
.withIdentifier(DRAWER_ID_FILTERS) .withIdentifier(DRAWER_ID_FILTERS)
.withBadge(getString(R.string.drawer_action_clear)) .withBadge(getString(R.string.drawer_action_clear))
.withOnDrawerItemClickListener { _, _, _ -> .withOnDrawerItemClickListener { _, _, _ ->
maybeSourceFilter = null maybeSourceFilter = null
maybeTagFilter = null maybeTagFilter = null
getElementsAccordingToTab() getElementsAccordingToTab()
false false
} }
) )
drawer.addItem(DividerDrawerItem()) drawer.addItem(DividerDrawerItem())
drawer.addItem( drawer.addItem(
SecondaryDrawerItem() SecondaryDrawerItem()
.withName(getString(R.string.drawer_item_tags)) .withName(getString(R.string.drawer_item_tags))
.withIdentifier(DRAWER_ID_TAGS) .withIdentifier(DRAWER_ID_TAGS)
.withSelectable(false) .withSelectable(false)
) )
handleTags(maybeDrawerData.tags) handleTags(maybeDrawerData.tags)
drawer.addItem(DividerDrawerItem()) drawer.addItem(DividerDrawerItem())
drawer.addItem( drawer.addItem(
SecondaryDrawerItem() SecondaryDrawerItem()
.withName(getString(R.string.drawer_item_sources)) .withName(getString(R.string.drawer_item_sources))
.withIdentifier(DRAWER_ID_TAGS) .withIdentifier(DRAWER_ID_TAGS)
.withBadge(getString(R.string.drawer_action_edit)) .withBadge(getString(R.string.drawer_action_edit))
.withSelectable(false) .withSelectable(false)
.withOnDrawerItemClickListener { _, _, _ -> .withOnDrawerItemClickListener { _, _, _ ->
startActivity(Intent(this, SourcesActivity::class.java)) startActivity(Intent(this, SourcesActivity::class.java))
false false
} }
) )
handleSources(maybeDrawerData.sources) handleSources(maybeDrawerData.sources)
drawer.addItem(DividerDrawerItem()) drawer.addItem(DividerDrawerItem())
drawer.addItem( drawer.addItem(
PrimaryDrawerItem() PrimaryDrawerItem()
.withName(R.string.action_about) .withName(R.string.action_about)
.withSelectable(false) .withSelectable(false)
.withIcon(R.drawable.ic_info_outline) .withIcon(R.drawable.ic_info_outline)
.withIconTintingEnabled(true) .withIconTintingEnabled(true)
.withOnDrawerItemClickListener { _, _, _ -> .withOnDrawerItemClickListener { _, _, _ ->
LibsBuilder() LibsBuilder()
.withActivityStyle( .withActivityStyle(
if (appColors.isDarkTheme) { if (appColors.isDarkTheme) {
Libs.ActivityStyle.LIGHT_DARK_TOOLBAR Libs.ActivityStyle.LIGHT_DARK_TOOLBAR
} else { } else {
Libs.ActivityStyle.DARK Libs.ActivityStyle.DARK
} }
) )
.withAboutIconShown(true) .withAboutIconShown(true)
.withAboutVersionShown(true) .withAboutVersionShown(true)
.start(this@HomeActivity) .start(this@HomeActivity)
false false
} }
) )
if (!loadedFromCache) { if (!loadedFromCache) {
Reservoir.putAsync( Reservoir.putAsync(
"drawerData", maybeDrawerData, object : ReservoirPutCallback { "drawerData", maybeDrawerData, object : ReservoirPutCallback {
override fun onSuccess() { 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)
) )
} }
} }
@ -583,8 +583,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
fun sourcesApiCall() { fun sourcesApiCall() {
api.sources.enqueue(object : Callback<List<Sources>> { api.sources.enqueue(object : Callback<List<Sources>> {
override fun onResponse( override fun onResponse(
call: Call<List<Sources>>?, call: Call<List<Sources>>?,
response: Response<List<Sources>> response: Response<List<Sources>>
) { ) {
sources = response.body() sources = response.body()
val apiDrawerData = DrawerData(tags, sources) val apiDrawerData = DrawerData(tags, sources)
@ -600,8 +600,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
api.tags.enqueue(object : Callback<List<Tag>> { api.tags.enqueue(object : Callback<List<Tag>> {
override fun onResponse( override fun onResponse(
call: Call<List<Tag>>, call: Call<List<Tag>>,
response: Response<List<Tag>> response: Response<List<Tag>>
) { ) {
tags = response.body() tags = response.body()
sourcesApiCall() sourcesApiCall()
@ -614,23 +614,23 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
} }
drawer.addItem( drawer.addItem(
PrimaryDrawerItem().withName(getString(R.string.drawer_loading)).withSelectable( PrimaryDrawerItem().withName(getString(R.string.drawer_loading)).withSelectable(
false false
) )
) )
val resultType = object : TypeToken<DrawerData>() {}.type val resultType = object : TypeToken<DrawerData>() {}.type
Reservoir.getAsync( Reservoir.getAsync(
"drawerData", resultType, object : ReservoirGetCallback<DrawerData> { "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)
} }
override fun onFailure(p0: Exception?) { override fun onFailure(p0: Exception?) {
drawerApiCalls(null) drawerApiCalls(null)
} }
}) })
} }
private fun reloadLayoutManager() { private fun reloadLayoutManager() {
@ -640,19 +640,20 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
// This will only update the layout manager if settings changed // This will only update the layout manager if settings changed
when (currentManager) { when (currentManager) {
is StaggeredGridLayoutManager -> is StaggeredGridLayoutManager ->
if (!shouldBeCardView) { if (!shouldBeCardView) {
layoutManager = GridLayoutManager(this, calculateNoOfColumns()) layoutManager = GridLayoutManager(this, calculateNoOfColumns())
recyclerView.layoutManager = layoutManager recyclerView.layoutManager = layoutManager
} }
is GridLayoutManager -> is GridLayoutManager ->
if (shouldBeCardView) { if (shouldBeCardView) {
layoutManager = StaggeredGridLayoutManager( layoutManager = StaggeredGridLayoutManager(
calculateNoOfColumns(), calculateNoOfColumns(),
StaggeredGridLayoutManager.VERTICAL StaggeredGridLayoutManager.VERTICAL
) )
layoutManager.gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS layoutManager.gapStrategy =
recyclerView.layoutManager = layoutManager StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
} recyclerView.layoutManager = layoutManager
}
else -> else ->
if (currentManager == null) { if (currentManager == null) {
if (!shouldBeCardView) { if (!shouldBeCardView) {
@ -660,10 +661,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
recyclerView.layoutManager = layoutManager recyclerView.layoutManager = layoutManager
} else { } else {
layoutManager = StaggeredGridLayoutManager( layoutManager = StaggeredGridLayoutManager(
calculateNoOfColumns(), calculateNoOfColumns(),
StaggeredGridLayoutManager.VERTICAL StaggeredGridLayoutManager.VERTICAL
) )
layoutManager.gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS layoutManager.gapStrategy =
StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
recyclerView.layoutManager = layoutManager recyclerView.layoutManager = layoutManager
} }
} else { } else {
@ -717,7 +719,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
val manager = recyclerView.layoutManager val manager = recyclerView.layoutManager
val lastVisibleItem: Int = when (manager) { val lastVisibleItem: Int = when (manager) {
is StaggeredGridLayoutManager -> manager.findLastCompletelyVisibleItemPositions( is StaggeredGridLayoutManager -> manager.findLastCompletelyVisibleItemPositions(
null null
).last() ).last()
is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition() is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition()
else -> 0 else -> 0
@ -736,17 +738,17 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
} }
private fun mayBeEmpty() = private fun mayBeEmpty() =
if (items.isEmpty()) { if (items.isEmpty()) {
emptyText.visibility = View.VISIBLE emptyText.visibility = View.VISIBLE
recyclerView.visibility = View.GONE recyclerView.visibility = View.GONE
} else { } else {
emptyText.visibility = View.GONE emptyText.visibility = View.GONE
recyclerView.visibility = View.VISIBLE recyclerView.visibility = View.VISIBLE
} }
private fun getElementsAccordingToTab( private fun getElementsAccordingToTab(
appendResults: Boolean = false, appendResults: Boolean = false,
offsetOverride: Int? = null offsetOverride: Int? = null
) { ) {
offset = if (appendResults && offsetOverride === null) { offset = if (appendResults && offsetOverride === null) {
(offset + itemsNumber) (offset + itemsNumber)
@ -764,9 +766,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
} }
private fun doCallTo( private fun doCallTo(
appendResults: Boolean, appendResults: Boolean,
toastMessage: Int, toastMessage: Int,
call: (String?, Long?, String?) -> Call<List<Item>> call: (String?, Long?, String?) -> Call<List<Item>>
) { ) {
fun handleItemsResponse(response: Response<List<Item>>) { fun handleItemsResponse(response: Response<List<Item>>) {
val shouldUpdate = (response.body() != items) val shouldUpdate = (response.body() != items)
@ -792,34 +794,34 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
} }
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( override fun onResponse(
call: Call<List<Item>>, call: Call<List<Item>>,
response: Response<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( Toast.makeText(
this@HomeActivity, this@HomeActivity,
toastMessage, toastMessage,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).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 -> doCallTo(appendResults, R.string.cant_get_new_elements) { t, id, f ->
api.newItems( api.newItems(
t, t,
id, id,
f, f,
itemsNumber, itemsNumber,
offset offset
) )
} }
} }
@ -828,11 +830,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
elementsShown = READ_SHOWN elementsShown = READ_SHOWN
doCallTo(appendResults, R.string.cant_get_read) { t, id, f -> doCallTo(appendResults, R.string.cant_get_read) { t, id, f ->
api.readItems( api.readItems(
t, t,
id, id,
f, f,
itemsNumber, itemsNumber,
offset offset
) )
} }
} }
@ -841,11 +843,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
elementsShown = FAV_SHOWN elementsShown = FAV_SHOWN
doCallTo(appendResults, R.string.cant_get_favs) { t, id, f -> doCallTo(appendResults, R.string.cant_get_favs) { t, id, f ->
api.starredItems( api.starredItems(
t, t,
id, id,
f, f,
itemsNumber, itemsNumber,
offset offset
) )
} }
} }
@ -866,36 +868,36 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
if (shouldBeCardView) { if (shouldBeCardView) {
recyclerAdapter = recyclerAdapter =
ItemCardAdapter( ItemCardAdapter(
this, this,
items, items,
api, api,
customTabActivityHelper, customTabActivityHelper,
internalBrowser, internalBrowser,
articleViewer, articleViewer,
fullHeightCards, fullHeightCards,
appColors, appColors,
debugReadingItems, debugReadingItems,
userIdentifier userIdentifier
) )
} else { } else {
recyclerAdapter = recyclerAdapter =
ItemListAdapter( ItemListAdapter(
this, this,
items, items,
api, api,
customTabActivityHelper, customTabActivityHelper,
clickBehavior, clickBehavior,
internalBrowser, internalBrowser,
articleViewer, articleViewer,
debugReadingItems, debugReadingItems,
userIdentifier userIdentifier
) )
recyclerView.addItemDecoration( recyclerView.addItemDecoration(
DividerItemDecoration( DividerItemDecoration(
this@HomeActivity, this@HomeActivity,
DividerItemDecoration.VERTICAL DividerItemDecoration.VERTICAL
) )
) )
} }
recyclerView.adapter = recyclerAdapter recyclerView.adapter = recyclerAdapter
@ -935,16 +937,16 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
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())
.maybeShow() .maybeShow()
tabStarredBadge tabStarredBadge
.setText(badgeFavs.toString()) .setText(badgeFavs.toString())
.maybeShow() .maybeShow()
} else { } else {
tabArchiveBadge.removeBadge() tabArchiveBadge.removeBadge()
tabStarredBadge.removeBadge() tabStarredBadge.removeBadge()
@ -1009,21 +1011,21 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
R.id.refresh -> { R.id.refresh -> {
api.update().enqueue(object : Callback<String> { api.update().enqueue(object : Callback<String> {
override fun onResponse( override fun onResponse(
call: Call<String>, call: Call<String>,
response: Response<String> response: Response<String>
) { ) {
Toast.makeText( Toast.makeText(
this@HomeActivity, this@HomeActivity,
R.string.refresh_success_response, Toast.LENGTH_LONG R.string.refresh_success_response, Toast.LENGTH_LONG
) )
.show() .show()
} }
override fun onFailure(call: Call<String>, t: Throwable) { override fun onFailure(call: Call<String>, t: Throwable) {
Toast.makeText( Toast.makeText(
this@HomeActivity, this@HomeActivity,
R.string.refresh_failer_message, R.string.refresh_failer_message,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
}) })
@ -1037,21 +1039,21 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
api.readAll(ids).enqueue(object : Callback<SuccessResponse> { api.readAll(ids).enqueue(object : Callback<SuccessResponse> {
override fun onResponse( override fun onResponse(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
response: Response<SuccessResponse> response: Response<SuccessResponse>
) { ) {
if (response.body() != null && response.body()!!.isSuccess) { if (response.body() != null && response.body()!!.isSuccess) {
Toast.makeText( Toast.makeText(
this@HomeActivity, this@HomeActivity,
R.string.all_posts_read, R.string.all_posts_read,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
tabNewBadge.removeBadge() tabNewBadge.removeBadge()
} else { } else {
Toast.makeText( Toast.makeText(
this@HomeActivity, this@HomeActivity,
R.string.all_posts_not_read, R.string.all_posts_not_read,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
@ -1060,9 +1062,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
Toast.makeText( Toast.makeText(
this@HomeActivity, this@HomeActivity,
R.string.all_posts_not_read, R.string.all_posts_not_read,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
swipeRefreshLayout.isRefreshing = false swipeRefreshLayout.isRefreshing = false
} }
@ -1070,9 +1072,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
items = ArrayList() items = ArrayList()
if (items.isEmpty()) { if (items.isEmpty()) {
Toast.makeText( Toast.makeText(
this@HomeActivity, this@HomeActivity,
R.string.nothing_here, R.string.nothing_here,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
handleListResult() handleListResult()
@ -1084,7 +1086,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
} }
R.id.action_share_the_app -> { R.id.action_share_the_app -> {
if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) { if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
val share = AppInviteInvitation.IntentBuilder(getString(R.string.invitation_title)) val share =
AppInviteInvitation.IntentBuilder(getString(R.string.invitation_title))
.setMessage(getString(R.string.invitation_message)) .setMessage(getString(R.string.invitation_message))
.setDeepLink(Uri.parse("https://ymbh5.app.goo.gl/qbvQ")) .setDeepLink(Uri.parse("https://ymbh5.app.goo.gl/qbvQ"))
.setCallToActionText(getString(R.string.invitation_cta)) .setCallToActionText(getString(R.string.invitation_cta))
@ -1094,8 +1097,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
val sendIntent = Intent() val sendIntent = Intent()
sendIntent.action = Intent.ACTION_SEND sendIntent.action = Intent.ACTION_SEND
sendIntent.putExtra( sendIntent.putExtra(
Intent.EXTRA_TEXT, Intent.EXTRA_TEXT,
getString(R.string.invitation_message) + " https://ymbh5.app.goo.gl/qbvQ" getString(R.string.invitation_message) + " https://ymbh5.app.goo.gl/qbvQ"
) )
sendIntent.type = "text/plain" sendIntent.type = "text/plain"
startActivityForResult(sendIntent, REQUEST_INVITE_BYMAIL) startActivityForResult(sendIntent, REQUEST_INVITE_BYMAIL)
@ -1107,10 +1110,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.
} }
} }

View File

@ -18,42 +18,42 @@ class IntroActivity : MaterialIntroActivity() {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
addSlide( addSlide(
SlideFragmentBuilder() SlideFragmentBuilder()
.backgroundColor(R.color.colorPrimary) .backgroundColor(R.color.colorPrimary)
.buttonsColor(R.color.colorAccent) .buttonsColor(R.color.colorAccent)
.image(R.drawable.web_hi_res_512) .image(R.drawable.web_hi_res_512)
.title(getString(R.string.intro_hello_title)) .title(getString(R.string.intro_hello_title))
.description(getString(R.string.intro_hello_message)) .description(getString(R.string.intro_hello_message))
.build() .build()
) )
addSlide( addSlide(
SlideFragmentBuilder() SlideFragmentBuilder()
.backgroundColor(R.color.colorAccent) .backgroundColor(R.color.colorAccent)
.buttonsColor(R.color.colorPrimary) .buttonsColor(R.color.colorPrimary)
.image(R.drawable.ic_info_outline_white_48px) .image(R.drawable.ic_info_outline_white_48px)
.title(getString(R.string.intro_needs_selfoss_title)) .title(getString(R.string.intro_needs_selfoss_title))
.description(getString(R.string.intro_needs_selfoss_message)) .description(getString(R.string.intro_needs_selfoss_message))
.build(), .build(),
MessageButtonBehaviour( MessageButtonBehaviour(
View.OnClickListener { View.OnClickListener {
val browserIntent = Intent( val browserIntent = Intent(
Intent.ACTION_VIEW, Intent.ACTION_VIEW,
Uri.parse("https://selfoss.aditu.de") Uri.parse("https://selfoss.aditu.de")
) )
startActivity(browserIntent) startActivity(browserIntent)
}, getString(R.string.intro_needs_selfoss_link) }, getString(R.string.intro_needs_selfoss_link)
) )
) )
addSlide( addSlide(
SlideFragmentBuilder() SlideFragmentBuilder()
.backgroundColor(R.color.colorPrimaryDark) .backgroundColor(R.color.colorPrimaryDark)
.buttonsColor(R.color.colorAccentDark) .buttonsColor(R.color.colorAccentDark)
.image(R.drawable.ic_thumb_up_white_48px) .image(R.drawable.ic_thumb_up_white_48px)
.title(getString(R.string.intro_all_set_title)) .title(getString(R.string.intro_all_set_title))
.description(getString(R.string.intro_all_set_message)) .description(getString(R.string.intro_all_set_message))
.build() .build()
) )
} }

View File

@ -77,13 +77,13 @@ class LoginActivity : AppCompatActivity() {
} }
passwordView.setOnEditorActionListener( passwordView.setOnEditorActionListener(
TextView.OnEditorActionListener { _, id, _ -> TextView.OnEditorActionListener { _, id, _ ->
if (id == R.id.loginView || id == EditorInfo.IME_NULL) { if (id == R.id.loginView || id == EditorInfo.IME_NULL) {
attemptLogin() attemptLogin()
return@OnEditorActionListener true return@OnEditorActionListener true
}
false
} }
false
}
) )
signInButton.setOnClickListener { attemptLogin() } signInButton.setOnClickListener { attemptLogin() }
@ -111,9 +111,9 @@ class LoginActivity : AppCompatActivity() {
alertDialog.setTitle(getString(R.string.warning_wrong_url)) alertDialog.setTitle(getString(R.string.warning_wrong_url))
alertDialog.setMessage(getString(R.string.base_url_error)) alertDialog.setMessage(getString(R.string.base_url_error))
alertDialog.setButton( alertDialog.setButton(
AlertDialog.BUTTON_NEUTRAL, AlertDialog.BUTTON_NEUTRAL,
"OK", "OK",
{ dialog, _ -> dialog.dismiss() } { dialog, _ -> dialog.dismiss() }
) )
alertDialog.show() alertDialog.show()
} }
@ -154,9 +154,9 @@ class LoginActivity : AppCompatActivity() {
alertDialog.setTitle(getString(R.string.warning_wrong_url)) alertDialog.setTitle(getString(R.string.warning_wrong_url))
alertDialog.setMessage(getString(R.string.text_wrong_url)) alertDialog.setMessage(getString(R.string.text_wrong_url))
alertDialog.setButton( alertDialog.setButton(
AlertDialog.BUTTON_NEUTRAL, AlertDialog.BUTTON_NEUTRAL,
"OK", "OK",
{ dialog, _ -> dialog.dismiss() } { dialog, _ -> dialog.dismiss() }
) )
alertDialog.show() alertDialog.show()
inValidCount = 0 inValidCount = 0
@ -191,10 +191,10 @@ class LoginActivity : AppCompatActivity() {
editor.apply() editor.apply()
val api = SelfossApi( val api = SelfossApi(
this, this,
this@LoginActivity, this@LoginActivity,
isWithSelfSignedCert, isWithSelfSignedCert,
isWithSelfSignedCert isWithSelfSignedCert
) )
api.login().enqueue(object : Callback<SuccessResponse> { api.login().enqueue(object : Callback<SuccessResponse> {
private fun preferenceError(t: Throwable) { private fun preferenceError(t: Throwable) {
@ -214,17 +214,17 @@ class LoginActivity : AppCompatActivity() {
Crashlytics.log(100, "LOGIN_DEBUG_ERRROR", t.message) Crashlytics.log(100, "LOGIN_DEBUG_ERRROR", t.message)
Crashlytics.logException(t) Crashlytics.logException(t)
Toast.makeText( Toast.makeText(
this@LoginActivity, this@LoginActivity,
t.message, t.message,
Toast.LENGTH_LONG Toast.LENGTH_LONG
).show() ).show()
} }
showProgress(false) showProgress(false)
} }
override fun onResponse( override fun onResponse(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
response: Response<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())
@ -246,28 +246,28 @@ class LoginActivity : AppCompatActivity() {
loginForm.visibility = if (show) View.GONE else View.VISIBLE loginForm.visibility = if (show) View.GONE else View.VISIBLE
loginForm loginForm
.animate() .animate()
.setDuration(shortAnimTime.toLong()) .setDuration(shortAnimTime.toLong())
.alpha( .alpha(
if (show) 0F else 1F if (show) 0F else 1F
).setListener(object : AnimatorListenerAdapter() { ).setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) { override fun onAnimationEnd(animation: Animator) {
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
.animate() .animate()
.setDuration(shortAnimTime.toLong()) .setDuration(shortAnimTime.toLong())
.alpha( .alpha(
if (show) 1F else 0F if (show) 1F else 0F
).setListener(object : AnimatorListenerAdapter() { ).setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) { override fun onAnimationEnd(animation: Animator) {
loginProgress.visibility = if (show) View.VISIBLE else View.GONE loginProgress.visibility = if (show) View.VISIBLE else View.GONE
} }
} }
) )
} }
@ -281,10 +281,10 @@ class LoginActivity : AppCompatActivity() {
when (item.itemId) { when (item.itemId) {
R.id.about -> { R.id.about -> {
LibsBuilder() LibsBuilder()
.withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR) .withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR)
.withAboutIconShown(true) .withAboutIconShown(true)
.withAboutVersionShown(true) .withAboutVersionShown(true)
.start(this) .start(this)
return true return true
} }
R.id.login_debug -> { R.id.login_debug -> {

View File

@ -14,7 +14,7 @@ class MainActivity : AppCompatActivity() {
if (PreferenceManager.getDefaultSharedPreferences(baseContext).getBoolean( if (PreferenceManager.getDefaultSharedPreferences(baseContext).getBoolean(
"firstStart", "firstStart",
true true
)) { )) {
val i = Intent(this@MainActivity, IntroActivity::class.java) val i = Intent(this@MainActivity, IntroActivity::class.java)
startActivity(i) startActivity(i)
} else { } else {

View File

@ -47,9 +47,9 @@ class MyApp : MultiDexApplication() {
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() {
@ -63,15 +63,15 @@ class MyApp : MultiDexApplication() {
private fun initDrawerImageLoader() { private fun initDrawerImageLoader() {
DrawerImageLoader.init(object : AbstractDrawerImageLoader() { DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
override fun set( override fun set(
imageView: ImageView?, imageView: ImageView?,
uri: Uri?, uri: Uri?,
placeholder: Drawable?, placeholder: Drawable?,
tag: String? tag: String?
) { ) {
Glide.with(imageView?.context) Glide.with(imageView?.context)
.load(uri) .load(uri)
.apply(RequestOptions.fitCenterTransform().placeholder(placeholder)) .apply(RequestOptions.fitCenterTransform().placeholder(placeholder))
.into(imageView) .into(imageView)
} }
override fun cancel(imageView: ImageView?) { override fun cancel(imageView: ImageView?) {
@ -86,22 +86,34 @@ 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)
.addDayNightFlavor(getString(R.string.default_dark_theme), R.style.NoBarDark) .addDayNightFlavor(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)
.addDayNightFlavor(getString(R.string.teal_orange_dark_theme), R.style.NoBarTealOrangeDark) .addDayNightFlavor(
.addFlavor(getString(R.string.cyan_pink_theme), R.style.NoBarCyanPink) getString(R.string.teal_orange_dark_theme),
.addDayNightFlavor(getString(R.string.cyan_pink_dark_theme), R.style.NoBarCyanPinkDark) R.style.NoBarTealOrangeDark
.addFlavor(getString(R.string.grey_orange_theme), R.style.NoBarGreyOrange) )
.addDayNightFlavor(getString(R.string.grey_orange_dark_theme), R.style.NoBarGreyOrangeDark) .addFlavor(getString(R.string.cyan_pink_theme), R.style.NoBarCyanPink)
.addFlavor(getString(R.string.blue_amber_theme), R.style.NoBarBlueAmber) .addDayNightFlavor(getString(R.string.cyan_pink_dark_theme), R.style.NoBarCyanPinkDark)
.addDayNightFlavor(getString(R.string.blue_amber_dark_theme), R.style.NoBarBlueAmberDark) .addFlavor(getString(R.string.grey_orange_theme), R.style.NoBarGreyOrange)
.addFlavor(getString(R.string.indigo_pink_theme), R.style.NoBarIndigoPink) .addDayNightFlavor(
.addDayNightFlavor(getString(R.string.indigo_pink_dark_theme), R.style.NoBarIndigoPinkDark) getString(R.string.grey_orange_dark_theme),
.addFlavor(getString(R.string.red_teal_theme), R.style.NoBarRedTeal) R.style.NoBarGreyOrangeDark
.addDayNightFlavor(getString(R.string.red_teal_dark_theme), R.style.NoBarRedTealDark) )
.setSharedPreferences(PreferenceManager.getDefaultSharedPreferences(this)) .addFlavor(getString(R.string.blue_amber_theme), R.style.NoBarBlueAmber)
.initialize() .addDayNightFlavor(
getString(R.string.blue_amber_dark_theme),
R.style.NoBarBlueAmberDark
)
.addFlavor(getString(R.string.indigo_pink_theme), R.style.NoBarIndigoPink)
.addDayNightFlavor(
getString(R.string.indigo_pink_dark_theme),
R.style.NoBarIndigoPinkDark
)
.addFlavor(getString(R.string.red_teal_theme), R.style.NoBarRedTeal)
.addDayNightFlavor(getString(R.string.red_teal_dark_theme), R.style.NoBarRedTealDark)
.setSharedPreferences(PreferenceManager.getDefaultSharedPreferences(this))
.initialize()
} }
private fun tryToHandleBug() { private fun tryToHandleBug() {
@ -109,8 +121,8 @@ class MyApp : MultiDexApplication() {
Thread.setDefaultUncaughtExceptionHandler { thread, e -> Thread.setDefaultUncaughtExceptionHandler { thread, e ->
if (e is java.lang.NoClassDefFoundError && e.stackTrace.asList().any { if (e is java.lang.NoClassDefFoundError && e.stackTrace.asList().any {
it.toString().contains("android.view.ViewDebug") it.toString().contains("android.view.ViewDebug")
}) { }) {
Unit Unit
} else { } else {
oldHandler.uncaughtException(thread, e) oldHandler.uncaughtException(thread, e)

View File

@ -69,9 +69,9 @@ class ReaderActivity : AppCompatActivity() {
if (allItems.isEmpty()) { if (allItems.isEmpty()) {
Crashlytics.setUserIdentifier(userIdentifier) Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log( Crashlytics.log(
100, 100,
"READER_ITEMS_EMPTY", "READER_ITEMS_EMPTY",
"Items empty when trying to open the Article Reader. Was (static) companion object field set ?" "Items empty when trying to open the Article Reader. Was (static) companion object field set ?"
) )
Crashlytics.logException(Exception("Empty items on Reader Activity.")) Crashlytics.logException(Exception("Empty items on Reader Activity."))
@ -79,10 +79,10 @@ class ReaderActivity : AppCompatActivity() {
} }
api = SelfossApi( api = SelfossApi(
this, this,
this@ReaderActivity, this@ReaderActivity,
settings.getBoolean("isSelfSignedCert", false), settings.getBoolean("isSelfSignedCert", false),
sharedPref.getBoolean("should_log_everything", false) sharedPref.getBoolean("should_log_everything", false)
) )
currentItem = intent.getIntExtra("currentItem", 0) currentItem = intent.getIntExtra("currentItem", 0)
@ -101,65 +101,65 @@ class ReaderActivity : AppCompatActivity() {
(indicator as CircleIndicator).setViewPager(pager) (indicator as CircleIndicator).setViewPager(pager)
pager.addOnPageChangeListener( pager.addOnPageChangeListener(
object : ViewPager.SimpleOnPageChangeListener() { object : ViewPager.SimpleOnPageChangeListener() {
var isLastItem = false var isLastItem = false
override fun onPageSelected(position: Int) { override fun onPageSelected(position: Int) {
isLastItem = (position === (allItems.size - 1)) isLastItem = (position === (allItems.size - 1))
if (allItems[position].starred) { if (allItems[position].starred) {
canRemoveFromFavorite() canRemoveFromFavorite()
} else { } else {
canFavorite() canFavorite()
}
}
override fun onPageScrollStateChanged(state: Int) {
if (markOnScroll && (state === ViewPager.SCROLL_STATE_DRAGGING || (state === ViewPager.SCROLL_STATE_IDLE && isLastItem))) {
api.markItem(allItems[pager.currentItem].id).enqueue(
object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
if (!response.succeeded() && debugReadingItems) {
val message =
"message: ${response.message()} " +
"response isSuccess: ${response.isSuccessful} " +
"response code: ${response.code()} " +
"response message: ${response.message()} " +
"response errorBody: ${response.errorBody()?.string()} " +
"body success: ${response.body()?.success} " +
"body isSuccess: ${response.body()?.isSuccess}"
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(
100,
"READ_DEBUG_SUCCESS",
message
)
Crashlytics.logException(Exception("Was success, but did it work ?"))
}
}
override fun onFailure(
call: Call<SuccessResponse>,
t: Throwable
) {
if (debugReadingItems) {
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(
100,
"READ_DEBUG_ERROR",
t.message
)
Crashlytics.logException(t)
}
}
}
)
}
} }
} }
override fun onPageScrollStateChanged(state: Int) {
if (markOnScroll && (state === ViewPager.SCROLL_STATE_DRAGGING || (state === ViewPager.SCROLL_STATE_IDLE && isLastItem))) {
api.markItem(allItems[pager.currentItem].id).enqueue(
object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
if (!response.succeeded() && debugReadingItems) {
val message =
"message: ${response.message()} " +
"response isSuccess: ${response.isSuccessful} " +
"response code: ${response.code()} " +
"response message: ${response.message()} " +
"response errorBody: ${response.errorBody()?.string()} " +
"body success: ${response.body()?.success} " +
"body isSuccess: ${response.body()?.isSuccess}"
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(
100,
"READ_DEBUG_SUCCESS",
message
)
Crashlytics.logException(Exception("Was success, but did it work ?"))
}
}
override fun onFailure(
call: Call<SuccessResponse>,
t: Throwable
) {
if (debugReadingItems) {
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(
100,
"READ_DEBUG_ERROR",
t.message
)
Crashlytics.logException(t)
}
}
}
)
}
}
}
) )
} }
@ -175,7 +175,8 @@ class ReaderActivity : AppCompatActivity() {
oldInstanceState!!.clear() oldInstanceState!!.clear()
} }
private inner class ScreenSlidePagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { private inner class ScreenSlidePagerAdapter(fm: FragmentManager) :
FragmentStatePagerAdapter(fm) {
override fun getCount(): Int { override fun getCount(): Int {
return allItems.size return allItems.size
} }
@ -206,48 +207,50 @@ class ReaderActivity : AppCompatActivity() {
return true return true
} }
R.id.save -> { R.id.save -> {
api.starrItem(allItems[pager.currentItem].id).enqueue(object : Callback<SuccessResponse> { api.starrItem(allItems[pager.currentItem].id)
override fun onResponse( .enqueue(object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
response: Response<SuccessResponse> response: Response<SuccessResponse>
) { ) {
allItems[pager.currentItem] = allItems[pager.currentItem].toggleStar() allItems[pager.currentItem] = allItems[pager.currentItem].toggleStar()
canRemoveFromFavorite() canRemoveFromFavorite()
} }
override fun onFailure( override fun onFailure(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
t: Throwable t: Throwable
) { ) {
Toast.makeText( Toast.makeText(
baseContext, baseContext,
R.string.cant_mark_favortie, R.string.cant_mark_favortie,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
}) })
} }
R.id.unsave -> { R.id.unsave -> {
api.unstarrItem(allItems[pager.currentItem].id).enqueue(object : Callback<SuccessResponse> { api.unstarrItem(allItems[pager.currentItem].id)
override fun onResponse( .enqueue(object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
response: Response<SuccessResponse> response: Response<SuccessResponse>
) { ) {
allItems[pager.currentItem] = allItems[pager.currentItem].toggleStar() allItems[pager.currentItem] = allItems[pager.currentItem].toggleStar()
canFavorite() canFavorite()
} }
override fun onFailure( override fun onFailure(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
t: Throwable t: Throwable
) { ) {
Toast.makeText( Toast.makeText(
baseContext, baseContext,
R.string.cant_unmark_favortie, R.string.cant_unmark_favortie,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
}) })
} }
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)

View File

@ -39,10 +39,10 @@ class SourcesActivity : AppCompatActivity() {
val prefs = PreferenceManager.getDefaultSharedPreferences(this) val prefs = PreferenceManager.getDefaultSharedPreferences(this)
val api = SelfossApi( val api = SelfossApi(
this, this,
this@SourcesActivity, this@SourcesActivity,
prefs.getBoolean("isSelfSignedCert", false), prefs.getBoolean("isSelfSignedCert", false),
prefs.getBoolean("should_log_everything", false) prefs.getBoolean("should_log_everything", false)
) )
var items: ArrayList<Sources> = ArrayList() var items: ArrayList<Sources> = ArrayList()
@ -51,8 +51,8 @@ class SourcesActivity : AppCompatActivity() {
api.sources.enqueue(object : Callback<List<Sources>> { api.sources.enqueue(object : Callback<List<Sources>> {
override fun onResponse( override fun onResponse(
call: Call<List<Sources>>, call: Call<List<Sources>>,
response: Response<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>
@ -62,18 +62,18 @@ class SourcesActivity : AppCompatActivity() {
mAdapter.notifyDataSetChanged() mAdapter.notifyDataSetChanged()
if (items.isEmpty()) { if (items.isEmpty()) {
Toast.makeText( Toast.makeText(
this@SourcesActivity, this@SourcesActivity,
R.string.nothing_here, R.string.nothing_here,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
} }
override fun onFailure(call: Call<List<Sources>>, t: Throwable) { override fun onFailure(call: Call<List<Sources>>, t: Throwable) {
Toast.makeText( Toast.makeText(
this@SourcesActivity, this@SourcesActivity,
R.string.cant_get_sources, R.string.cant_get_sources,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
}) })

View File

@ -2,8 +2,6 @@ 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.support.design.widget.Snackbar
import android.support.v7.widget.CardView import android.support.v7.widget.CardView
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.text.Html import android.text.Html
@ -11,7 +9,6 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView.ScaleType import android.widget.ImageView.ScaleType
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.Item import apps.amine.bou.readerforselfoss.api.selfoss.Item
@ -26,12 +23,10 @@ import apps.amine.bou.readerforselfoss.utils.openInBrowserAsNewTask
import apps.amine.bou.readerforselfoss.utils.openItemUrl import apps.amine.bou.readerforselfoss.utils.openItemUrl
import apps.amine.bou.readerforselfoss.utils.shareLink import apps.amine.bou.readerforselfoss.utils.shareLink
import apps.amine.bou.readerforselfoss.utils.sourceAndDateText import apps.amine.bou.readerforselfoss.utils.sourceAndDateText
import apps.amine.bou.readerforselfoss.utils.succeeded
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 com.bumptech.glide.Glide import com.bumptech.glide.Glide
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 kotlinx.android.synthetic.main.card_item.view.*
@ -40,20 +35,21 @@ import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
class ItemCardAdapter( class ItemCardAdapter(
override val app: Activity, override val app: Activity,
override var items: ArrayList<Item>, override var items: ArrayList<Item>,
override val api: SelfossApi, override val api: SelfossApi,
private val helper: CustomTabActivityHelper, private val helper: CustomTabActivityHelper,
private val internalBrowser: Boolean, private val internalBrowser: Boolean,
private val articleViewer: Boolean, private val articleViewer: Boolean,
private val fullHeightCards: Boolean, private val fullHeightCards: Boolean,
private val appColors: AppColors, private val appColors: AppColors,
override val debugReadingItems: Boolean, override val debugReadingItems: Boolean,
override val userIdentifier: String override val userIdentifier: String
) : ItemsAdapter<ItemCardAdapter.ViewHolder>() { ) : ItemsAdapter<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
private val imageMaxHeight: Int = c.resources.getDimension(R.dimen.card_image_max_height).toInt() private val imageMaxHeight: Int =
c.resources.getDimension(R.dimen.card_image_max_height).toInt()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(c).inflate(R.layout.card_item, parent, false) as CardView val v = LayoutInflater.from(c).inflate(R.layout.card_item, parent, false) as CardView
@ -87,10 +83,10 @@ class ItemCardAdapter(
val color = generator.getColor(itm.sourcetitle) val color = generator.getColor(itm.sourcetitle)
val drawable = val drawable =
TextDrawable TextDrawable
.builder() .builder()
.round() .round()
.build(itm.sourcetitle.toTextDrawableString(), color) .build(itm.sourcetitle.toTextDrawableString(), color)
holder.mView.sourceImage.setImageDrawable(drawable) holder.mView.sourceImage.setImageDrawable(drawable)
} else { } else {
c.circularBitmapDrawable(itm.getIcon(c), holder.mView.sourceImage) c.circularBitmapDrawable(itm.getIcon(c), holder.mView.sourceImage)
@ -117,20 +113,20 @@ class ItemCardAdapter(
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( override fun onResponse(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
response: Response<SuccessResponse> response: Response<SuccessResponse>
) { ) {
} }
override fun onFailure( override fun onFailure(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
t: Throwable t: Throwable
) { ) {
mView.favButton.isLiked = false mView.favButton.isLiked = false
Toast.makeText( Toast.makeText(
c, c,
R.string.cant_mark_favortie, R.string.cant_mark_favortie,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
}) })
@ -140,20 +136,20 @@ class ItemCardAdapter(
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( override fun onResponse(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
response: Response<SuccessResponse> response: Response<SuccessResponse>
) { ) {
} }
override fun onFailure( override fun onFailure(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
t: Throwable t: Throwable
) { ) {
mView.favButton.isLiked = true mView.favButton.isLiked = true
Toast.makeText( Toast.makeText(
c, c,
R.string.cant_unmark_favortie, R.string.cant_unmark_favortie,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
}) })
@ -175,13 +171,13 @@ class ItemCardAdapter(
mView.setOnClickListener { mView.setOnClickListener {
c.openItemUrl( c.openItemUrl(
items, items,
adapterPosition, adapterPosition,
items[adapterPosition].getLinkDecoded(), items[adapterPosition].getLinkDecoded(),
customTabsIntent, customTabsIntent,
internalBrowser, internalBrowser,
articleViewer, articleViewer,
app app
) )
} }
} }

View File

@ -2,16 +2,13 @@ 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.support.constraint.ConstraintLayout import android.support.constraint.ConstraintLayout
import android.support.design.widget.Snackbar
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.text.Html import android.text.Html
import android.util.TypedValue import android.util.TypedValue
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.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.Item import apps.amine.bou.readerforselfoss.api.selfoss.Item
@ -25,11 +22,9 @@ import apps.amine.bou.readerforselfoss.utils.openInBrowserAsNewTask
import apps.amine.bou.readerforselfoss.utils.openItemUrl import apps.amine.bou.readerforselfoss.utils.openItemUrl
import apps.amine.bou.readerforselfoss.utils.shareLink import apps.amine.bou.readerforselfoss.utils.shareLink
import apps.amine.bou.readerforselfoss.utils.sourceAndDateText import apps.amine.bou.readerforselfoss.utils.sourceAndDateText
import apps.amine.bou.readerforselfoss.utils.succeeded
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 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 kotlinx.android.synthetic.main.list_item.view.*
@ -40,15 +35,15 @@ import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
class ItemListAdapter( class ItemListAdapter(
override val app: Activity, override val app: Activity,
override var items: ArrayList<Item>, override var items: ArrayList<Item>,
override val api: SelfossApi, override val api: SelfossApi,
private val helper: CustomTabActivityHelper, private val helper: CustomTabActivityHelper,
private val clickBehavior: Boolean, private val clickBehavior: Boolean,
private val internalBrowser: Boolean, private val internalBrowser: Boolean,
private val articleViewer: Boolean, private val articleViewer: Boolean,
override val debugReadingItems: Boolean, override val debugReadingItems: Boolean,
override val userIdentifier: String override val userIdentifier: String
) : ItemsAdapter<ItemListAdapter.ViewHolder>() { ) : ItemsAdapter<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
@ -56,9 +51,9 @@ class ItemListAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(c).inflate( val v = LayoutInflater.from(c).inflate(
R.layout.list_item, R.layout.list_item,
parent, parent,
false false
) as ConstraintLayout ) as ConstraintLayout
return ViewHolder(v) return ViewHolder(v)
} }
@ -74,13 +69,13 @@ class ItemListAdapter(
if (itm.getThumbnail(c).isEmpty()) { if (itm.getThumbnail(c).isEmpty()) {
val sizeInInt = 46 val sizeInInt = 46
val sizeInDp = TypedValue.applyDimension( val sizeInDp = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, sizeInInt.toFloat(), c.resources TypedValue.COMPLEX_UNIT_DIP, sizeInInt.toFloat(), c.resources
.displayMetrics .displayMetrics
).toInt() ).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 .displayMetrics
).toInt() ).toInt()
@ -94,10 +89,10 @@ class ItemListAdapter(
val color = generator.getColor(itm.sourcetitle) val color = generator.getColor(itm.sourcetitle)
val drawable = val drawable =
TextDrawable TextDrawable
.builder() .builder()
.round() .round()
.build(itm.sourcetitle.toTextDrawableString(), color) .build(itm.sourcetitle.toTextDrawableString(), color)
holder.mView.itemImage.setImageDrawable(drawable) holder.mView.itemImage.setImageDrawable(drawable)
} else { } else {
@ -123,8 +118,6 @@ class ItemListAdapter(
override fun getItemCount(): Int = items.size override fun getItemCount(): Int = items.size
inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) { inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) {
init { init {
@ -139,20 +132,20 @@ class ItemListAdapter(
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( override fun onResponse(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
response: Response<SuccessResponse> response: Response<SuccessResponse>
) { ) {
} }
override fun onFailure( override fun onFailure(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
t: Throwable t: Throwable
) { ) {
mView.favButton.isLiked = false mView.favButton.isLiked = false
Toast.makeText( Toast.makeText(
c, c,
R.string.cant_mark_favortie, R.string.cant_mark_favortie,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
}) })
@ -162,20 +155,20 @@ class ItemListAdapter(
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( override fun onResponse(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
response: Response<SuccessResponse> response: Response<SuccessResponse>
) { ) {
} }
override fun onFailure( override fun onFailure(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
t: Throwable t: Throwable
) { ) {
mView.favButton.isLiked = true mView.favButton.isLiked = true
Toast.makeText( Toast.makeText(
c, c,
R.string.cant_unmark_favortie, R.string.cant_unmark_favortie,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
}) })
@ -200,13 +193,13 @@ class ItemListAdapter(
if (!clickBehavior) { if (!clickBehavior) {
mView.setOnClickListener { mView.setOnClickListener {
c.openItemUrl( c.openItemUrl(
items, items,
adapterPosition, adapterPosition,
items[adapterPosition].getLinkDecoded(), items[adapterPosition].getLinkDecoded(),
customTabsIntent, customTabsIntent,
internalBrowser, internalBrowser,
articleViewer, articleViewer,
app app
) )
} }
mView.setOnLongClickListener { mView.setOnLongClickListener {
@ -217,13 +210,13 @@ class ItemListAdapter(
mView.setOnClickListener { actionBarShowHide() } mView.setOnClickListener { actionBarShowHide() }
mView.setOnLongClickListener { mView.setOnLongClickListener {
c.openItemUrl( c.openItemUrl(
items, items,
adapterPosition, adapterPosition,
items[adapterPosition].getLinkDecoded(), items[adapterPosition].getLinkDecoded(),
customTabsIntent, customTabsIntent,
internalBrowser, internalBrowser,
articleViewer, articleViewer,
app app
) )
true true
} }
@ -239,6 +232,4 @@ class ItemListAdapter(
} }
} }
} }
} }

View File

@ -30,29 +30,29 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
private fun doUnmark(i: Item, position: Int) { private fun doUnmark(i: Item, position: Int) {
val s = Snackbar val s = Snackbar
.make( .make(
app.findViewById(R.id.coordLayout), app.findViewById(R.id.coordLayout),
R.string.marked_as_read, R.string.marked_as_read,
Snackbar.LENGTH_LONG 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( override fun onResponse(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
response: Response<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)
notifyItemRemoved(position) notifyItemRemoved(position)
doUnmark(i, position) doUnmark(i, position)
} }
}) })
} }
val view = s.view val view = s.view
val tv: TextView = view.findViewById(android.support.design.R.id.snackbar_text) val tv: TextView = view.findViewById(android.support.design.R.id.snackbar_text)
@ -69,18 +69,18 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> { api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse( override fun onResponse(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
response: Response<SuccessResponse> response: Response<SuccessResponse>
) { ) {
if (!response.succeeded() && debugReadingItems) { if (!response.succeeded() && debugReadingItems) {
val message = val message =
"message: ${response.message()} " + "message: ${response.message()} " +
"response isSuccess: ${response.isSuccessful} " + "response isSuccess: ${response.isSuccessful} " +
"response code: ${response.code()} " + "response code: ${response.code()} " +
"response message: ${response.message()} " + "response message: ${response.message()} " +
"response errorBody: ${response.errorBody()?.string()} " + "response errorBody: ${response.errorBody()?.string()} " +
"body success: ${response.body()?.success} " + "body success: ${response.body()?.success} " +
"body isSuccess: ${response.body()?.isSuccess}" "body isSuccess: ${response.body()?.isSuccess}"
Crashlytics.setUserIdentifier(userIdentifier) Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(100, "READ_DEBUG_SUCCESS", message) Crashlytics.log(100, "READ_DEBUG_SUCCESS", message)
Crashlytics.logException(Exception("Was success, but did it work ?")) Crashlytics.logException(Exception("Was success, but did it work ?"))
@ -98,9 +98,9 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
Toast.makeText(app.baseContext, t.message, Toast.LENGTH_LONG).show() Toast.makeText(app.baseContext, t.message, Toast.LENGTH_LONG).show()
} }
Toast.makeText( Toast.makeText(
app, app,
app.getString(R.string.cant_mark_read), app.getString(R.string.cant_mark_read),
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
items.add(i) items.add(i)
notifyItemInserted(position) notifyItemInserted(position)

View File

@ -22,18 +22,18 @@ import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
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 private val api: SelfossApi
) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>() { ) : 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( val v = LayoutInflater.from(c).inflate(
R.layout.source_list_item, R.layout.source_list_item,
parent, parent,
false false
) as ConstraintLayout ) as ConstraintLayout
return ViewHolder(v) return ViewHolder(v)
} }
@ -45,10 +45,10 @@ class SourcesListAdapter(
val color = generator.getColor(itm.title) val color = generator.getColor(itm.title)
val drawable = val drawable =
TextDrawable TextDrawable
.builder() .builder()
.round() .round()
.build(itm.title.toTextDrawableString(), color) .build(itm.title.toTextDrawableString(), color)
holder.mView.itemImage.setImageDrawable(drawable) holder.mView.itemImage.setImageDrawable(drawable)
} else { } else {
c.circularBitmapDrawable(itm.getIcon(c), holder.mView.itemImage) c.circularBitmapDrawable(itm.getIcon(c), holder.mView.itemImage)
@ -73,8 +73,8 @@ class SourcesListAdapter(
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( override fun onResponse(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
response: Response<SuccessResponse> response: Response<SuccessResponse>
) { ) {
if (response.body() != null && response.body()!!.isSuccess) { if (response.body() != null && response.body()!!.isSuccess) {
items.removeAt(adapterPosition) items.removeAt(adapterPosition)
@ -82,18 +82,18 @@ class SourcesListAdapter(
notifyItemRangeChanged(adapterPosition, itemCount) notifyItemRangeChanged(adapterPosition, itemCount)
} else { } else {
Toast.makeText( Toast.makeText(
app, app,
R.string.can_delete_source, R.string.can_delete_source,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
} }
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
Toast.makeText( Toast.makeText(
app, app,
R.string.can_delete_source, R.string.can_delete_source,
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
}) })

View File

@ -21,15 +21,15 @@ class MercuryApi(private val key: String, shouldLog: Boolean) {
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)
} }

View File

@ -5,39 +5,40 @@ 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 @SerializedName("next_page_url") val next_page_url: String
) : Parcelable { ) : Parcelable {
companion object { companion object {
@JvmField @JvmField
val CREATOR: Parcelable.Creator<ParsedContent> = object : Parcelable.Creator<ParsedContent> { val CREATOR: Parcelable.Creator<ParsedContent> =
override fun createFromParcel(source: Parcel): ParsedContent = ParsedContent(source) object : Parcelable.Creator<ParsedContent> {
override fun newArray(size: Int): Array<ParsedContent?> = arrayOfNulls(size) override fun createFromParcel(source: Parcel): ParsedContent = ParsedContent(source)
} 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

View File

@ -10,13 +10,13 @@ internal class BooleanTypeAdapter : JsonDeserializer<Boolean> {
@Throws(JsonParseException::class) @Throws(JsonParseException::class)
override fun deserialize( override fun deserialize(
json: JsonElement, json: JsonElement,
typeOfT: Type, typeOfT: Type,
context: JsonDeserializationContext context: JsonDeserializationContext
): Boolean? = ): Boolean? =
try { try {
json.asInt == 1 json.asInt == 1
} catch (e: Exception) { } catch (e: Exception) {
json.asBoolean json.asBoolean
} }
} }

View File

@ -20,10 +20,10 @@ import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
class SelfossApi( class SelfossApi(
c: Context, c: Context,
callingActivity: Activity, callingActivity: Activity,
isWithSelfSignedCert: Boolean, isWithSelfSignedCert: Boolean,
shouldLog: Boolean shouldLog: Boolean
) { ) {
private lateinit var service: SelfossService private lateinit var service: SelfossService
@ -32,25 +32,25 @@ class SelfossApi(
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 {
@ -58,16 +58,16 @@ class SelfossApi(
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()
@ -83,12 +83,12 @@ class SelfossApi(
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)
@ -96,59 +96,59 @@ class SelfossApi(
} }
fun login(): Call<SuccessResponse> = fun login(): Call<SuccessResponse> =
service.loginToSelfoss(config.userLogin, config.userPassword) service.loginToSelfoss(config.userLogin, config.userPassword)
fun readItems( fun readItems(
tag: String?, tag: String?,
sourceId: Long?, sourceId: Long?,
search: String?, search: String?,
itemsNumber: Int, itemsNumber: Int,
offset: Int offset: Int
): Call<List<Item>> = ): Call<List<Item>> =
getItems("read", tag, sourceId, search, itemsNumber, offset) getItems("read", tag, sourceId, search, itemsNumber, offset)
fun newItems( fun newItems(
tag: String?, tag: String?,
sourceId: Long?, sourceId: Long?,
search: String?, search: String?,
itemsNumber: Int, itemsNumber: Int,
offset: Int offset: Int
): Call<List<Item>> = ): Call<List<Item>> =
getItems("unread", tag, sourceId, search, itemsNumber, offset) getItems("unread", tag, sourceId, search, itemsNumber, offset)
fun starredItems( fun starredItems(
tag: String?, tag: String?,
sourceId: Long?, sourceId: Long?,
search: String?, search: String?,
itemsNumber: Int, itemsNumber: Int,
offset: Int offset: Int
): Call<List<Item>> = ): Call<List<Item>> =
getItems("starred", tag, sourceId, search, itemsNumber, offset) getItems("starred", tag, sourceId, search, itemsNumber, offset)
private fun getItems( private fun getItems(
type: String, type: String,
tag: String?, tag: String?,
sourceId: Long?, sourceId: Long?,
search: String?, search: String?,
items: Int, items: Int,
offset: Int offset: Int
): Call<List<Item>> = ): Call<List<Item>> =
service.getItems(type, tag, sourceId, search, userName, password, items, offset) 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)
@ -157,23 +157,23 @@ class SelfossApi(
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( fun createSource(
title: String, title: String,
url: String, url: String,
spout: String, spout: String,
tags: String, tags: String,
filter: String filter: String
): Call<SuccessResponse> = ): Call<SuccessResponse> =
service.createSource(title, url, spout, tags, filter, userName, password) service.createSource(title, url, spout, tags, filter, userName, password)
} }

View File

@ -21,9 +21,9 @@ private fun constructUrl(config: Config?, path: String, file: String): String {
} }
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) {
@ -32,23 +32,23 @@ class SuccessResponse(@SerializedName("success") val success: Boolean) {
} }
class Stats( class Stats(
@SerializedName("total") val total: Int, @SerializedName("total") val total: Int,
@SerializedName("unread") val unread: Int, @SerializedName("unread") val unread: Int,
@SerializedName("starred") val starred: Int @SerializedName("starred") val starred: Int
) )
data class Spout( data class Spout(
@SerializedName("name") val name: String, @SerializedName("name") val name: String,
@SerializedName("description") val description: String @SerializedName("description") val description: String
) )
data class Sources( data class Sources(
@SerializedName("id") val id: String, @SerializedName("id") val id: String,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@SerializedName("tags") val tags: String, @SerializedName("tags") val tags: String,
@SerializedName("spout") val spout: String, @SerializedName("spout") val spout: String,
@SerializedName("error") val error: String, @SerializedName("error") val error: String,
@SerializedName("icon") val icon: String @SerializedName("icon") val icon: String
) { ) {
var config: Config? = null var config: Config? = null
@ -61,16 +61,16 @@ data class Sources(
} }
data class Item( data class Item(
@SerializedName("id") val id: String, @SerializedName("id") val id: String,
@SerializedName("datetime") val datetime: String, @SerializedName("datetime") val datetime: String,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@SerializedName("content") val content: String, @SerializedName("content") val content: String,
@SerializedName("unread") val unread: Boolean, @SerializedName("unread") val unread: Boolean,
@SerializedName("starred") var starred: Boolean, @SerializedName("starred") var starred: Boolean,
@SerializedName("thumbnail") val thumbnail: String, @SerializedName("thumbnail") val thumbnail: String,
@SerializedName("icon") val icon: String, @SerializedName("icon") val icon: String,
@SerializedName("link") val link: String, @SerializedName("link") val link: String,
@SerializedName("sourcetitle") val sourcetitle: String @SerializedName("sourcetitle") val sourcetitle: String
) : Parcelable { ) : Parcelable {
var config: Config? = null var config: Config? = null
@ -83,16 +83,16 @@ data class Item(
} }
constructor(source: Parcel) : this( constructor(source: Parcel) : this(
id = source.readString(), id = source.readString(),
datetime = source.readString(), datetime = source.readString(),
title = source.readString(), title = source.readString(),
content = source.readString(), content = source.readString(),
unread = 0.toByte() != source.readByte(), unread = 0.toByte() != source.readByte(),
starred = 0.toByte() != source.readByte(), starred = 0.toByte() != source.readByte(),
thumbnail = source.readString(), thumbnail = source.readString(),
icon = source.readString(), icon = source.readString(),
link = source.readString(), link = source.readString(),
sourcetitle = source.readString() sourcetitle = source.readString()
) )
override fun describeContents() = 0 override fun describeContents() = 0
@ -127,15 +127,16 @@ data class Item(
// TODO: maybe find a better way to handle these kind of urls // TODO: maybe find a better way to handle these kind of urls
fun getLinkDecoded(): String { fun getLinkDecoded(): String {
var stringUrl: String var stringUrl: String
stringUrl = if (link.startsWith("http://news.google.com/news/") || link.startsWith("https://news.google.com/news/")) { stringUrl =
if (link.contains("&amp;url=")) { if (link.startsWith("http://news.google.com/news/") || link.startsWith("https://news.google.com/news/")) {
link.substringAfter("&amp;url=") if (link.contains("&amp;url=")) {
} else { link.substringAfter("&amp;url=")
this.link.replace("&amp;", "&") } else {
} this.link.replace("&amp;", "&")
} else { }
this.link.replace("&amp;", "&") } else {
} this.link.replace("&amp;", "&")
}
// handle :443 => https // handle :443 => https
if (stringUrl.contains(":443")) { if (stringUrl.contains(":443")) {

View File

@ -17,102 +17,102 @@ internal interface SelfossService {
@GET("items") @GET("items")
fun getItems( fun getItems(
@Query("type") type: String, @Query("type") type: String,
@Query("tag") tag: String?, @Query("tag") tag: String?,
@Query("source") source: Long?, @Query("source") source: Long?,
@Query("search") search: String?, @Query("search") search: String?,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String, @Query("password") password: String,
@Query("items") items: Int, @Query("items") items: Int,
@Query("offset") offset: Int @Query("offset") offset: Int
): Call<List<Item>> ): 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( fun markAsRead(
@Path("id") id: String, @Path("id") id: String,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String @Query("password") password: String
): Call<SuccessResponse> ): 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( fun unmarkAsRead(
@Path("id") id: String, @Path("id") id: String,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String @Query("password") password: String
): Call<SuccessResponse> ): Call<SuccessResponse>
@FormUrlEncoded @FormUrlEncoded
@POST("mark") @POST("mark")
fun markAllAsRead( fun markAllAsRead(
@Field("ids[]") ids: List<String>, @Field("ids[]") ids: List<String>,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String @Query("password") password: String
): Call<SuccessResponse> ): 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( fun starr(
@Path("id") id: String, @Path("id") id: String,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String @Query("password") password: String
): Call<SuccessResponse> ): 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( fun unstarr(
@Path("id") id: String, @Path("id") id: String,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String @Query("password") password: String
): Call<SuccessResponse> ): Call<SuccessResponse>
@GET("stats") @GET("stats")
fun stats( fun stats(
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String @Query("password") password: String
): Call<Stats> ): Call<Stats>
@GET("tags") @GET("tags")
fun tags( fun tags(
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String @Query("password") password: String
): Call<List<Tag>> ): Call<List<Tag>>
@GET("update") @GET("update")
fun update( fun update(
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String @Query("password") password: String
): Call<String> ): Call<String>
@GET("sources/spouts") @GET("sources/spouts")
fun spouts( fun spouts(
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String @Query("password") password: String
): Call<Map<String, Spout>> ): Call<Map<String, Spout>>
@GET("sources/list") @GET("sources/list")
fun sources( fun sources(
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String @Query("password") password: String
): Call<List<Sources>> ): Call<List<Sources>>
@DELETE("source/{id}") @DELETE("source/{id}")
fun deleteSource( fun deleteSource(
@Path("id") id: String, @Path("id") id: String,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String @Query("password") password: String
): Call<SuccessResponse> ): Call<SuccessResponse>
@FormUrlEncoded @FormUrlEncoded
@POST("source") @POST("source")
fun createSource( fun createSource(
@Field("title") title: String, @Field("title") title: String,
@Field("url") url: String, @Field("url") url: String,
@Field("spout") spout: String, @Field("spout") spout: String,
@Field("tags") tags: String, @Field("tags") tags: String,
@Field("filter") filter: String, @Field("filter") filter: String,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String @Query("password") password: String
): Call<SuccessResponse> ): Call<SuccessResponse>
} }

View File

@ -9,8 +9,6 @@ import android.support.design.widget.FloatingActionButton
import android.support.v4.app.Fragment import android.support.v4.app.Fragment
import android.support.v4.content.ContextCompat import android.support.v4.content.ContextCompat
import android.support.v4.widget.NestedScrollView import android.support.v4.widget.NestedScrollView
import android.text.Html
import android.text.method.LinkMovementMethod
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
@ -33,7 +31,6 @@ 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.fragment_article.view.* import kotlinx.android.synthetic.main.fragment_article.view.*
import org.sufficientlysecure.htmltextview.HtmlHttpImageGetter
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
@ -65,12 +62,12 @@ class ArticleFragment : Fragment() {
private lateinit var rootView: ViewGroup private lateinit var rootView: ViewGroup
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
rootView = inflater rootView = inflater
.inflate(R.layout.fragment_article, container, false) as ViewGroup .inflate(R.layout.fragment_article, container, false) as ViewGroup
url = allItems[pageNumber.toInt()].getLinkDecoded() url = allItems[pageNumber.toInt()].getLinkDecoded()
contentText = allItems[pageNumber.toInt()].content contentText = allItems[pageNumber.toInt()].content
@ -89,27 +86,27 @@ class ArticleFragment : Fragment() {
val prefs = PreferenceManager.getDefaultSharedPreferences(activity) val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
mFloatingToolbar.setClickListener( mFloatingToolbar.setClickListener(
object : FloatingToolbar.ItemClickListener { object : FloatingToolbar.ItemClickListener {
override fun onItemClick(item: MenuItem) { override fun onItemClick(item: MenuItem) {
when (item.itemId) { when (item.itemId) {
R.id.more_action -> getContentFromMercury(customTabsIntent, prefs) R.id.more_action -> getContentFromMercury(customTabsIntent, prefs)
R.id.share_action -> activity!!.shareLink(url) R.id.share_action -> activity!!.shareLink(url)
R.id.open_action -> activity!!.openItemUrl( R.id.open_action -> activity!!.openItemUrl(
allItems, allItems,
pageNumber.toInt(), pageNumber.toInt(),
url, url,
customTabsIntent, customTabsIntent,
false, false,
false, false,
activity!! activity!!
) )
else -> Unit else -> Unit
}
}
override fun onItemLongClick(item: MenuItem?) {
} }
} }
override fun onItemLongClick(item: MenuItem?) {
}
}
) )
@ -124,149 +121,153 @@ class ArticleFragment : Fragment() {
if (!contentImage.isEmptyOrNullOrNullString()) { if (!contentImage.isEmptyOrNullOrNullString()) {
rootView.imageView.visibility = View.VISIBLE rootView.imageView.visibility = View.VISIBLE
Glide Glide
.with(activity!!.baseContext) .with(activity!!.baseContext)
.asBitmap() .asBitmap()
.load(contentImage) .load(contentImage)
.apply(RequestOptions.fitCenterTransform()) .apply(RequestOptions.fitCenterTransform())
.into(rootView.imageView) .into(rootView.imageView)
} else { } else {
rootView.imageView.visibility = View.GONE rootView.imageView.visibility = View.GONE
} }
} }
rootView.nestedScrollView.setOnScrollChangeListener( rootView.nestedScrollView.setOnScrollChangeListener(
NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY -> NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
if (scrollY > oldScrollY) { if (scrollY > oldScrollY) {
fab.hide() fab.hide()
} else { } else {
if (mFloatingToolbar.isShowing) mFloatingToolbar.hide() else fab.show() if (mFloatingToolbar.isShowing) mFloatingToolbar.hide() else fab.show()
}
} }
}
) )
return rootView return rootView
} }
private fun getContentFromMercury( private fun getContentFromMercury(
customTabsIntent: CustomTabsIntent, customTabsIntent: CustomTabsIntent,
prefs: SharedPreferences prefs: SharedPreferences
) { ) {
rootView.progressBar.visibility = View.VISIBLE rootView.progressBar.visibility = View.VISIBLE
val parser = MercuryApi( val parser = MercuryApi(
BuildConfig.MERCURY_KEY, BuildConfig.MERCURY_KEY,
prefs.getBoolean("should_log_everything", false) prefs.getBoolean("should_log_everything", false)
) )
parser.parseUrl(url).enqueue( parser.parseUrl(url).enqueue(
object : Callback<ParsedContent> { object : Callback<ParsedContent> {
override fun onResponse( override fun onResponse(
call: Call<ParsedContent>, call: Call<ParsedContent>,
response: Response<ParsedContent> response: Response<ParsedContent>
) { ) {
// TODO: clean all the following after finding the mercury content issue // TODO: clean all the following after finding the mercury content issue
try { try {
if (response.body() != null && response.body()!!.content != null && !response.body()!!.content.isNullOrEmpty()) { if (response.body() != null && response.body()!!.content != null && !response.body()!!.content.isNullOrEmpty()) {
try { try {
rootView.source.text = response.body()!!.domain rootView.source.text = response.body()!!.domain
rootView.titleView.text = response.body()!!.title rootView.titleView.text = response.body()!!.title
url = response.body()!!.url url = response.body()!!.url
} catch (e: Exception) { } catch (e: Exception) {
Crashlytics.setUserIdentifier(prefs.getString("unique_id", "")) Crashlytics.setUserIdentifier(prefs.getString("unique_id", ""))
Crashlytics.log( Crashlytics.log(
100,
"MERCURY_CONTENT_EXCEPTION",
"source titleView or url issues"
)
Crashlytics.logException(e)
}
try {
htmlToWebview(response.body()!!.content.orEmpty(), prefs)
} catch (e: Exception) {
Crashlytics.setUserIdentifier(prefs.getString("unique_id", ""))
Crashlytics.log(
100,
"MERCURY_CONTENT_EXCEPTION",
"Webview issue"
)
Crashlytics.logException(e)
}
try {
if (response.body()!!.lead_image_url != null && !response.body()!!.lead_image_url.isNullOrEmpty()) {
rootView.imageView.visibility = View.VISIBLE
try {
Glide
.with(activity!!.baseContext)
.asBitmap()
.load(response.body()!!.lead_image_url)
.apply(RequestOptions.fitCenterTransform())
.into(rootView.imageView)
} catch (e: Exception) {
Crashlytics.setUserIdentifier(prefs.getString("unique_id", ""))
Crashlytics.log(
100,
"MERCURY_CONTENT_EXCEPTION",
"Glide issue"
)
Crashlytics.logException(e)
}
} else {
rootView.imageView.visibility = View.GONE
}
} catch (e: Exception) {
Crashlytics.setUserIdentifier(prefs.getString("unique_id", ""))
Crashlytics.log(
100,
"MERCURY_CONTENT_EXCEPTION",
"Glide or image issue"
)
Crashlytics.logException(e)
}
try {
rootView.nestedScrollView.scrollTo(0, 0)
rootView.progressBar.visibility = View.GONE
} catch (e: Exception) {
Crashlytics.setUserIdentifier(prefs.getString("unique_id", ""))
Crashlytics.log(
100,
"MERCURY_CONTENT_EXCEPTION",
"Scroll or visibility issues"
)
Crashlytics.logException(e)
}
} else {
try {
openInBrowserAfterFailing(customTabsIntent)
} catch (e: Exception) {
Crashlytics.setUserIdentifier(prefs.getString("unique_id", ""))
Crashlytics.log(
100,
"MERCURY_CONTENT_EXCEPTION",
"Browser after failing issue"
)
Crashlytics.logException(e)
}
}
} catch (e: Exception) {
Crashlytics.setUserIdentifier(prefs.getString("unique_id", ""))
Crashlytics.log(
100, 100,
"MERCURY_CONTENT_EXCEPTION", "MERCURY_CONTENT_EXCEPTION",
"UNCAUGHT (?) Fatal Exception on mercury response" "source titleView or url issues"
) )
Crashlytics.logException(e) Crashlytics.logException(e)
}
try {
htmlToWebview(response.body()!!.content.orEmpty(), prefs)
} catch (e: Exception) {
Crashlytics.setUserIdentifier(prefs.getString("unique_id", ""))
Crashlytics.log(
100,
"MERCURY_CONTENT_EXCEPTION",
"Webview issue"
)
Crashlytics.logException(e)
}
try {
if (response.body()!!.lead_image_url != null && !response.body()!!.lead_image_url.isNullOrEmpty()) {
rootView.imageView.visibility = View.VISIBLE
try {
Glide
.with(activity!!.baseContext)
.asBitmap()
.load(response.body()!!.lead_image_url)
.apply(RequestOptions.fitCenterTransform())
.into(rootView.imageView)
} catch (e: Exception) {
Crashlytics.setUserIdentifier(
prefs.getString(
"unique_id",
""
)
)
Crashlytics.log(
100,
"MERCURY_CONTENT_EXCEPTION",
"Glide issue"
)
Crashlytics.logException(e)
}
} else {
rootView.imageView.visibility = View.GONE
}
} catch (e: Exception) {
Crashlytics.setUserIdentifier(prefs.getString("unique_id", ""))
Crashlytics.log(
100,
"MERCURY_CONTENT_EXCEPTION",
"Glide or image issue"
)
Crashlytics.logException(e)
}
try {
rootView.nestedScrollView.scrollTo(0, 0)
rootView.progressBar.visibility = View.GONE
} catch (e: Exception) {
Crashlytics.setUserIdentifier(prefs.getString("unique_id", ""))
Crashlytics.log(
100,
"MERCURY_CONTENT_EXCEPTION",
"Scroll or visibility issues"
)
Crashlytics.logException(e)
}
} else {
try {
openInBrowserAfterFailing(customTabsIntent)
} catch (e: Exception) {
Crashlytics.setUserIdentifier(prefs.getString("unique_id", ""))
Crashlytics.log(
100,
"MERCURY_CONTENT_EXCEPTION",
"Browser after failing issue"
)
Crashlytics.logException(e)
}
} }
} catch (e: Exception) {
Crashlytics.setUserIdentifier(prefs.getString("unique_id", ""))
Crashlytics.log(
100,
"MERCURY_CONTENT_EXCEPTION",
"UNCAUGHT (?) Fatal Exception on mercury response"
)
Crashlytics.logException(e)
} }
override fun onFailure(
call: Call<ParsedContent>,
t: Throwable
) = openInBrowserAfterFailing(customTabsIntent)
} }
override fun onFailure(
call: Call<ParsedContent>,
t: Throwable
) = openInBrowserAfterFailing(customTabsIntent)
}
) )
} }
@ -277,10 +278,20 @@ class ArticleFragment : Fragment() {
rootView.webcontent.visibility = View.VISIBLE rootView.webcontent.visibility = View.VISIBLE
val textColor = if (Scoop.getInstance().currentFlavor.isDayNight) { val textColor = if (Scoop.getInstance().currentFlavor.isDayNight) {
rootView.webcontent.setBackgroundColor(ContextCompat.getColor(activity!!.baseContext, R.color.dark_webview)) rootView.webcontent.setBackgroundColor(
ContextCompat.getColor(
activity!!.baseContext,
R.color.dark_webview
)
)
ContextCompat.getColor(activity!!.baseContext, R.color.dark_webview_text) ContextCompat.getColor(activity!!.baseContext, R.color.dark_webview_text)
} else { } else {
rootView.webcontent.setBackgroundColor(ContextCompat.getColor(activity!!.baseContext, R.color.light_webview)) rootView.webcontent.setBackgroundColor(
ContextCompat.getColor(
activity!!.baseContext,
R.color.light_webview
)
)
ContextCompat.getColor(activity!!.baseContext, R.color.light_webview_text) ContextCompat.getColor(activity!!.baseContext, R.color.light_webview_text)
} }
@ -291,7 +302,8 @@ class ArticleFragment : Fragment() {
rootView.webcontent.settings.javaScriptEnabled = false rootView.webcontent.settings.javaScriptEnabled = false
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
rootView.webcontent.settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING rootView.webcontent.settings.layoutAlgorithm =
WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING
} else { } else {
rootView.webcontent.settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN rootView.webcontent.settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN
} }
@ -308,24 +320,24 @@ class ArticleFragment : Fragment() {
} }
rootView.webcontent.loadDataWithBaseURL( rootView.webcontent.loadDataWithBaseURL(
baseUrl, baseUrl,
"<style>img{display: inline-block;height: auto; width: 100%; max-width: 100%;} a{color: $stringColor;} *:not(a){color: $stringTextColor;}</style>$c", "<style>img{display: inline-block;height: auto; width: 100%; max-width: 100%;} a{color: $stringColor;} *:not(a){color: $stringTextColor;}</style>$c",
"text/html; charset=utf-8", "text/html; charset=utf-8",
"utf-8", "utf-8",
null null
) )
} }
private fun openInBrowserAfterFailing(customTabsIntent: CustomTabsIntent) { private fun openInBrowserAfterFailing(customTabsIntent: CustomTabsIntent) {
rootView.progressBar.visibility = View.GONE rootView.progressBar.visibility = View.GONE
activity!!.openItemUrl( activity!!.openItemUrl(
allItems, allItems,
pageNumber.toInt(), pageNumber.toInt(),
url, url,
customTabsIntent, customTabsIntent,
true, true,
false, false,
activity!! activity!!
) )
} }
@ -334,8 +346,8 @@ class ArticleFragment : Fragment() {
private val ARG_ITEMS = "items" private val ARG_ITEMS = "items"
fun newInstance( fun newInstance(
position: Int, position: Int,
allItems: ArrayList<Item> allItems: ArrayList<Item>
): ArticleFragment { ): ArticleFragment {
val fragment = ArticleFragment() val fragment = ArticleFragment()
val args = Bundle() val args = Bundle()

View File

@ -16,9 +16,10 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import apps.amine.bou.readerforselfoss.R;
import com.ftinc.scoop.Scoop; import com.ftinc.scoop.Scoop;
import apps.amine.bou.readerforselfoss.R;
/** /**
* A {@link PreferenceActivity} which implements and proxies the necessary calls * A {@link PreferenceActivity} which implements and proxies the necessary calls
@ -40,7 +41,7 @@ public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
protected void onPostCreate(Bundle savedInstanceState) { protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState); super.onPostCreate(savedInstanceState);
LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent(); LinearLayout root = (LinearLayout) findViewById(android.R.id.list).getParent().getParent().getParent();
AppBarLayout bar = (AppBarLayout) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false); AppBarLayout bar = (AppBarLayout) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
Toolbar toolbar = bar.findViewById(R.id.toolbar); Toolbar toolbar = bar.findViewById(R.id.toolbar);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);

View File

@ -1,8 +1,6 @@
package apps.amine.bou.readerforselfoss.settings; package apps.amine.bou.readerforselfoss.settings;
import java.util.List;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
@ -27,10 +25,13 @@ import android.text.Spanned;
import android.view.MenuItem; import android.view.MenuItem;
import android.widget.Toast; import android.widget.Toast;
import com.ftinc.scoop.ui.ScoopSettingsActivity;
import java.util.List;
import apps.amine.bou.readerforselfoss.BuildConfig; import apps.amine.bou.readerforselfoss.BuildConfig;
import apps.amine.bou.readerforselfoss.R; import apps.amine.bou.readerforselfoss.R;
import apps.amine.bou.readerforselfoss.utils.Config; import apps.amine.bou.readerforselfoss.utils.Config;
import com.ftinc.scoop.ui.ScoopSettingsActivity;
/** /**
@ -150,7 +151,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
final SwitchPreference tabOnTap = (SwitchPreference) findPreference("tab_on_tap"); final SwitchPreference tabOnTap = (SwitchPreference) findPreference("tab_on_tap");
tabOnTap.setEnabled(!cardViewActive.isChecked()); tabOnTap.setEnabled(!cardViewActive.isChecked());
cardViewActive.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { cardViewActive.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue){ public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean isEnabled = (Boolean) newValue; boolean isEnabled = (Boolean) newValue;
tabOnTap.setEnabled(!isEnabled); tabOnTap.setEnabled(!isEnabled);
return true; return true;
@ -159,20 +160,20 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
EditTextPreference itemsNumber = (EditTextPreference) findPreference("prefer_api_items_number"); EditTextPreference itemsNumber = (EditTextPreference) findPreference("prefer_api_items_number");
itemsNumber.getEditText().setFilters(new InputFilter[]{ itemsNumber.getEditText().setFilters(new InputFilter[]{
new InputFilter (){ new InputFilter() {
@Override @Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
try { try {
int input = Integer.parseInt(dest.toString() + source.toString()); int input = Integer.parseInt(dest.toString() + source.toString());
if (input <= 200 && input >0) if (input <= 200 && input > 0)
return null; return null;
} catch (NumberFormatException nfe) { } catch (NumberFormatException nfe) {
Toast.makeText(getActivity(), R.string.items_number_should_be_number, Toast.LENGTH_LONG).show(); Toast.makeText(getActivity(), R.string.items_number_should_be_number, Toast.LENGTH_LONG).show();
}
return "";
} }
return "";
} }
}
}); });
} }
@ -243,7 +244,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
addPreferencesFromResource(R.xml.pref_links); addPreferencesFromResource(R.xml.pref_links);
setHasOptionsMenu(true); setHasOptionsMenu(true);
findPreference( "trackerLink" ).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { findPreference("trackerLink").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override @Override
public boolean onPreferenceClick(Preference preference) { public boolean onPreferenceClick(Preference preference) {
openUrl(Uri.parse(BuildConfig.TRACKER_URL)); openUrl(Uri.parse(BuildConfig.TRACKER_URL));

View File

@ -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

View File

@ -9,12 +9,12 @@ 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( fun Context.checkApkVersion(
settings: SharedPreferences, settings: SharedPreferences,
editor: SharedPreferences.Editor, editor: SharedPreferences.Editor,
mFirebaseRemoteConfig: FirebaseRemoteConfig mFirebaseRemoteConfig: FirebaseRemoteConfig
) = { ) = {
fun isThereAnUpdate() { fun isThereAnUpdate() {
val APK_LINK = "github_apk" val APK_LINK = "github_apk"
@ -26,8 +26,8 @@ fun Context.checkApkVersion(
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.setButton(
AlertDialog.BUTTON_POSITIVE, AlertDialog.BUTTON_POSITIVE,
getString(R.string.new_apk_available_get) getString(R.string.new_apk_available_get)
) { _, _ -> ) { _, _ ->
editor.putString(APK_LINK, apkLink) editor.putString(APK_LINK, apkLink)
editor.apply() editor.apply()
@ -35,25 +35,25 @@ fun Context.checkApkVersion(
startActivity(browserIntent) startActivity(browserIntent)
} }
alertDialog.setButton( alertDialog.setButton(
AlertDialog.BUTTON_NEUTRAL, getString(R.string.new_apk_available_no), AlertDialog.BUTTON_NEUTRAL, getString(R.string.new_apk_available_no),
{ dialog, _ -> { dialog, _ ->
editor.putString(APK_LINK, apkLink) editor.putString(APK_LINK, apkLink)
editor.apply() editor.apply()
dialog.dismiss() 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 {
@ -68,11 +68,11 @@ fun String.longHash(): Long {
} }
fun String.toStringUriWithHttp(): String = 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()
@ -81,9 +81,9 @@ fun Context.shareLink(itemUrl: String) {
sendIntent.putExtra(Intent.EXTRA_TEXT, itemUrl.toStringUriWithHttp()) sendIntent.putExtra(Intent.EXTRA_TEXT, itemUrl.toStringUriWithHttp())
sendIntent.type = "text/plain" sendIntent.type = "text/plain"
startActivity( startActivity(
Intent.createChooser( Intent.createChooser(
sendIntent, sendIntent,
getString(R.string.share) getString(R.string.share)
).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) ).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
) )
} }

View File

@ -29,10 +29,10 @@ class Config(c: Context) {
val settingsName = "paramsselfoss" val settingsName = "paramsselfoss"
fun logoutAndRedirect( fun logoutAndRedirect(
c: Context, c: Context,
callingActivity: Activity, callingActivity: Activity,
editor: SharedPreferences.Editor, editor: SharedPreferences.Editor,
baseUrlFail: Boolean = false baseUrlFail: Boolean = false
): Boolean { ): Boolean {
editor.remove("url") editor.remove("url")
editor.remove("login") editor.remove("login")

View File

@ -8,36 +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( override fun checkClientTrusted(
chain: Array<java.security.cert.X509Certificate>, chain: Array<java.security.cert.X509Certificate>,
authType: String authType: String
) { ) {
} }
@Throws(CertificateException::class) @Throws(CertificateException::class)
override fun checkServerTrusted( override fun checkServerTrusted(
chain: Array<java.security.cert.X509Certificate>, chain: Array<java.security.cert.X509Certificate>,
authType: String authType: String
) { ) {
} }
}) })
// Install the all-trusting trust manager // Install the all-trusting trust manager
val sslContext = SSLContext.getInstance("SSL") val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, java.security.SecureRandom()) sslContext.init(null, trustAllCerts, java.security.SecureRandom())
val sslSocketFactory = sslContext.socketFactory val sslSocketFactory = sslContext.socketFactory
OkHttpClient.Builder() OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager) .sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
.hostnameVerifier { _, _ -> true } .hostnameVerifier { _, _ -> true }
} catch (e: Exception) { } catch (e: Exception) {
throw RuntimeException(e) throw RuntimeException(e)
} }

View File

@ -13,7 +13,11 @@ fun String.toTextDrawableString(): String {
try { try {
textDrawable.append(s[0]) textDrawable.append(s[0])
} catch (e: StringIndexOutOfBoundsException) { } catch (e: StringIndexOutOfBoundsException) {
Crashlytics.log(100, "TEXT_DRAWABLE_INDEX_OUT_OF_BOUND", this + " produces ${e.message}") Crashlytics.log(
100,
"TEXT_DRAWABLE_INDEX_OUT_OF_BOUND",
this + " produces ${e.message}"
)
Crashlytics.logException(e) Crashlytics.logException(e)
} }
} }
@ -23,10 +27,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()

View File

@ -20,10 +20,10 @@ 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( val createPendingShareIntent: PendingIntent = PendingIntent.getActivity(
this, this,
0, 0,
actionIntent, actionIntent,
0 0
) )
val intentBuilder = CustomTabsIntent.Builder() val intentBuilder = CustomTabsIntent.Builder()
@ -35,14 +35,14 @@ fun Context.buildCustomTabsIntent(): CustomTabsIntent {
intentBuilder.setStartAnimations( intentBuilder.setStartAnimations(
this, this,
R.anim.slide_in_right, R.anim.slide_in_right,
R.anim.slide_out_left R.anim.slide_out_left
) )
intentBuilder.setExitAnimations( intentBuilder.setExitAnimations(
this, 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)
@ -50,8 +50,8 @@ fun Context.buildCustomTabsIntent(): CustomTabsIntent {
val shareLabel = this.getString(R.string.label_share) val shareLabel = this.getString(R.string.label_share)
val icon = BitmapFactory.decodeResource( val icon = BitmapFactory.decodeResource(
resources, resources,
R.drawable.ic_share_white_24dp R.drawable.ic_share_white_24dp
) )
intentBuilder.setActionButton(icon, shareLabel, createPendingShareIntent) intentBuilder.setActionButton(icon, shareLabel, createPendingShareIntent)
@ -59,12 +59,12 @@ fun Context.buildCustomTabsIntent(): CustomTabsIntent {
} }
fun Context.openItemUrlInternally( fun Context.openItemUrlInternally(
allItems: ArrayList<Item>, allItems: ArrayList<Item>,
currentItem: Int, currentItem: Int,
linkDecoded: String, linkDecoded: String,
customTabsIntent: CustomTabsIntent, customTabsIntent: CustomTabsIntent,
articleViewer: Boolean, articleViewer: Boolean,
app: Activity app: Activity
) { ) {
if (articleViewer) { if (articleViewer) {
ReaderActivity.allItems = allItems ReaderActivity.allItems = allItems
@ -74,9 +74,9 @@ fun Context.openItemUrlInternally(
} else { } else {
try { try {
CustomTabActivityHelper.openCustomTab( CustomTabActivityHelper.openCustomTab(
app, app,
customTabsIntent, customTabsIntent,
Uri.parse(linkDecoded) 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
@ -89,32 +89,32 @@ fun Context.openItemUrlInternally(
} }
fun Context.openItemUrl( fun Context.openItemUrl(
allItems: ArrayList<Item>, allItems: ArrayList<Item>,
currentItem: Int, currentItem: Int,
linkDecoded: String, linkDecoded: String,
customTabsIntent: CustomTabsIntent, customTabsIntent: CustomTabsIntent,
internalBrowser: Boolean, internalBrowser: Boolean,
articleViewer: Boolean, articleViewer: Boolean,
app: Activity app: Activity
) { ) {
if (!linkDecoded.isUrlValid()) { if (!linkDecoded.isUrlValid()) {
Toast.makeText( Toast.makeText(
this, this,
this.getString(R.string.cant_open_invalid_url), this.getString(R.string.cant_open_invalid_url),
Toast.LENGTH_LONG Toast.LENGTH_LONG
).show() ).show()
} else { } else {
if (!internalBrowser) { if (!internalBrowser) {
openInBrowser(linkDecoded, app) openInBrowser(linkDecoded, app)
} else { } else {
this.openItemUrlInternally( this.openItemUrlInternally(
allItems, allItems,
currentItem, currentItem,
linkDecoded, linkDecoded,
customTabsIntent, customTabsIntent,
articleViewer, articleViewer,
app app
) )
} }
} }
@ -127,7 +127,7 @@ private fun openInBrowser(linkDecoded: String, app: Activity) {
} }
fun String.isUrlValid(): Boolean = fun String.isUrlValid(): Boolean =
HttpUrl.parse(this) != null && Patterns.WEB_URL.matcher(this).matches() HttpUrl.parse(this) != null && Patterns.WEB_URL.matcher(this).matches()
fun String.isBaseUrlValid(): Boolean { fun String.isBaseUrlValid(): Boolean {
val baseUrl = HttpUrl.parse(this) val baseUrl = HttpUrl.parse(this)

View File

@ -7,37 +7,37 @@ import android.util.AttributeSet
import android.view.View import android.view.View
class ScrollAwareFABBehavior( class ScrollAwareFABBehavior(
context: Context, context: Context,
attrs: AttributeSet attrs: AttributeSet
) : CoordinatorLayout.Behavior<FloatingActionButton>() { ) : CoordinatorLayout.Behavior<FloatingActionButton>() {
override fun onStartNestedScroll( override fun onStartNestedScroll(
coordinatorLayout: CoordinatorLayout, coordinatorLayout: CoordinatorLayout,
child: FloatingActionButton, child: FloatingActionButton,
directTargetChild: View, directTargetChild: View,
target: View, target: View,
nestedScrollAxes: Int nestedScrollAxes: Int
): Boolean { ): Boolean {
return true return true
} }
override fun onNestedScroll( override fun onNestedScroll(
coordinatorLayout: CoordinatorLayout, coordinatorLayout: CoordinatorLayout,
child: FloatingActionButton, child: FloatingActionButton,
target: View, target: View,
dxConsumed: Int, dxConsumed: Int,
dyConsumed: Int, dyConsumed: Int,
dxUnconsumed: Int, dxUnconsumed: Int,
dyUnconsumed: Int dyUnconsumed: Int
) { ) {
super.onNestedScroll( super.onNestedScroll(
coordinatorLayout, coordinatorLayout,
child, child,
target, target,
dxConsumed, dxConsumed,
dyConsumed, dyConsumed,
dxUnconsumed, dxUnconsumed,
dyUnconsumed 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() {

View File

@ -9,4 +9,4 @@ fun TextBadgeItem.removeBadge(): TextBadgeItem {
} }
fun TextBadgeItem.maybeShow(): TextBadgeItem = fun TextBadgeItem.maybeShow(): TextBadgeItem =
if (this.isHidden) this.show() else this if (this.isHidden) this.show() else this

View File

@ -1,8 +1,6 @@
package apps.amine.bou.readerforselfoss.utils.customtabs; package apps.amine.bou.readerforselfoss.utils.customtabs;
import java.util.List;
import android.app.Activity; import android.app.Activity;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
@ -11,6 +9,8 @@ import android.support.customtabs.CustomTabsIntent;
import android.support.customtabs.CustomTabsServiceConnection; import android.support.customtabs.CustomTabsServiceConnection;
import android.support.customtabs.CustomTabsSession; import android.support.customtabs.CustomTabsSession;
import java.util.List;
/** /**
* This is a helper class to manage the connection to the Custom Tabs Service. * This is a helper class to manage the connection to the Custom Tabs Service.
*/ */
@ -23,15 +23,15 @@ public class CustomTabActivityHelper implements ServiceConnectionCallback {
/** /**
* Opens the URL on a Custom Tab if possible. Otherwise fallsback to opening it on a WebView. * Opens the URL on a Custom Tab if possible. Otherwise fallsback to opening it on a WebView.
* *
* @param activity The host activity. * @param activity The host activity.
* @param customTabsIntent a CustomTabsIntent to be used if Custom Tabs is available. * @param customTabsIntent a CustomTabsIntent to be used if Custom Tabs is available.
* @param uri the Uri to be opened. * @param uri the Uri to be opened.
* @param fallback a CustomTabFallback to be used if Custom Tabs is not available. * @param fallback a CustomTabFallback to be used if Custom Tabs is not available.
*/ */
public static void openCustomTab(Activity activity, public static void openCustomTab(Activity activity,
CustomTabsIntent customTabsIntent, CustomTabsIntent customTabsIntent,
Uri uri, Uri uri,
CustomTabFallback fallback) { CustomTabFallback fallback) {
String packageName = CustomTabsHelper.getPackageNameToUse(activity); String packageName = CustomTabsHelper.getPackageNameToUse(activity);
//If we cant find a package name, it means theres no browser that supports //If we cant find a package name, it means theres no browser that supports
@ -48,6 +48,7 @@ public class CustomTabActivityHelper implements ServiceConnectionCallback {
/** /**
* Unbinds the Activity from the Custom Tabs Service. * Unbinds the Activity from the Custom Tabs Service.
*
* @param activity the activity that is connected to the service. * @param activity the activity that is connected to the service.
*/ */
public void unbindCustomTabsService(Activity activity) { public void unbindCustomTabsService(Activity activity) {
@ -74,6 +75,7 @@ public class CustomTabActivityHelper implements ServiceConnectionCallback {
/** /**
* Register a Callback to be called when connected or disconnected from the Custom Tabs Service. * Register a Callback to be called when connected or disconnected from the Custom Tabs Service.
*
* @param connectionCallback * @param connectionCallback
*/ */
public void setConnectionCallback(ConnectionCallback connectionCallback) { public void setConnectionCallback(ConnectionCallback connectionCallback) {
@ -82,6 +84,7 @@ public class CustomTabActivityHelper implements ServiceConnectionCallback {
/** /**
* Binds the Activity to the Custom Tabs Service. * Binds the Activity to the Custom Tabs Service.
*
* @param activity the activity to be binded to the service. * @param activity the activity to be binded to the service.
*/ */
public void bindCustomTabsService(Activity activity) { public void bindCustomTabsService(Activity activity) {
@ -95,8 +98,8 @@ public class CustomTabActivityHelper implements ServiceConnectionCallback {
} }
/** /**
* @see {@link CustomTabsSession#mayLaunchUrl(Uri, Bundle, List)}.
* @return true if call to mayLaunchUrl was accepted. * @return true if call to mayLaunchUrl was accepted.
* @see {@link CustomTabsSession#mayLaunchUrl(Uri, Bundle, List)}.
*/ */
public boolean mayLaunchUrl(Uri uri, Bundle extras, List<Bundle> otherLikelyBundles) { public boolean mayLaunchUrl(Uri uri, Bundle extras, List<Bundle> otherLikelyBundles) {
if (mClient == null) return false; if (mClient == null) return false;
@ -142,9 +145,8 @@ public class CustomTabActivityHelper implements ServiceConnectionCallback {
*/ */
public interface CustomTabFallback { public interface CustomTabFallback {
/** /**
*
* @param activity The Activity that wants to open the Uri. * @param activity The Activity that wants to open the Uri.
* @param uri The uri to be opened by the fallback. * @param uri The uri to be opened by the fallback.
*/ */
void openUri(Activity activity, Uri uri); void openUri(Activity activity, Uri uri);
} }

View File

@ -1,9 +1,6 @@
package apps.amine.bou.readerforselfoss.utils.customtabs; package apps.amine.bou.readerforselfoss.utils.customtabs;
import java.util.ArrayList;
import java.util.List;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
@ -14,6 +11,9 @@ import android.support.customtabs.CustomTabsService;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import apps.amine.bou.readerforselfoss.utils.customtabs.helpers.KeepAliveService; import apps.amine.bou.readerforselfoss.utils.customtabs.helpers.KeepAliveService;
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
@ -28,7 +28,8 @@ class CustomTabsHelper {
private static String sPackageNameToUse; private static String sPackageNameToUse;
private CustomTabsHelper() {} private CustomTabsHelper() {
}
public static void addKeepAliveExtra(Context context, Intent intent) { public static void addKeepAliveExtra(Context context, Intent intent) {
Intent keepAliveIntent = new Intent().setClassName( Intent keepAliveIntent = new Intent().setClassName(
@ -40,7 +41,7 @@ class CustomTabsHelper {
* Goes through all apps that handle VIEW intents and have a warmup service. Picks * Goes through all apps that handle VIEW intents and have a warmup service. Picks
* the one chosen by the user if there is one, otherwise makes a best effort to return a * the one chosen by the user if there is one, otherwise makes a best effort to return a
* valid package name. * valid package name.
* * <p>
* This is <strong>not</strong> threadsafe. * This is <strong>not</strong> threadsafe.
* *
* @param context {@link Context} to use for accessing {@link PackageManager}. * @param context {@link Context} to use for accessing {@link PackageManager}.
@ -94,6 +95,7 @@ class CustomTabsHelper {
/** /**
* Used to check whether there is a specialized handler for a given intent. * Used to check whether there is a specialized handler for a given intent.
*
* @param intent The intent to check with. * @param intent The intent to check with.
* @return Whether there is a specialized handler for the given intent. * @return Whether there is a specialized handler for the given intent.
*/ */

View File

@ -1,12 +1,12 @@
package apps.amine.bou.readerforselfoss.utils.customtabs; package apps.amine.bou.readerforselfoss.utils.customtabs;
import java.lang.ref.WeakReference;
import android.content.ComponentName; import android.content.ComponentName;
import android.support.customtabs.CustomTabsClient; import android.support.customtabs.CustomTabsClient;
import android.support.customtabs.CustomTabsServiceConnection; import android.support.customtabs.CustomTabsServiceConnection;
import java.lang.ref.WeakReference;
/** /**
* Implementation for the CustomTabsServiceConnection that avoids leaking the * Implementation for the CustomTabsServiceConnection that avoids leaking the
* ServiceConnectionCallback * ServiceConnectionCallback

View File

@ -7,6 +7,7 @@ import android.support.customtabs.CustomTabsClient;
public interface ServiceConnectionCallback { public interface ServiceConnectionCallback {
/** /**
* Called when the service is connected. * Called when the service is connected.
*
* @param client a CustomTabsClient * @param client a CustomTabsClient
*/ */
void onServiceConnected(CustomTabsClient client); void onServiceConnected(CustomTabsClient client);

View File

@ -15,7 +15,8 @@ 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)
return this as T return this as T
@ -76,8 +77,8 @@ abstract class CustomUrlBasePrimaryDrawerItem<T, VH : RecyclerView.ViewHolder> :
//set the background for the item //set the background for the item
UIUtils.setBackground( UIUtils.setBackground(
viewHolder.view, viewHolder.view,
UIUtils.getSelectableBackground(ctx, selectedColor, true) 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)
@ -88,9 +89,9 @@ abstract class CustomUrlBasePrimaryDrawerItem<T, VH : RecyclerView.ViewHolder> :
viewHolder.name.setTextColor(getTextColorStateList(color, selectedTextColor)) viewHolder.name.setTextColor(getTextColorStateList(color, selectedTextColor))
//set the description text color //set the description text color
ColorHolder.applyToOr( ColorHolder.applyToOr(
descriptionTextColor, descriptionTextColor,
viewHolder.description, viewHolder.description,
getTextColorStateList(color, selectedTextColor) getTextColorStateList(color, selectedTextColor)
) )
//define the typeface for our textViews //define the typeface for our textViews

View File

@ -10,7 +10,9 @@ 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,8 +66,8 @@ class CustomUrlPrimaryDrawerItem : CustomUrlBasePrimaryDrawerItem<CustomUrlPrima
//style the badge if it is visible //style the badge if it is visible
if (badgeVisible) { if (badgeVisible) {
mBadgeStyle.style( mBadgeStyle.style(
viewHolder.badge, viewHolder.badge,
getTextColorStateList(getColor(ctx), getSelectedTextColor(ctx)) getTextColorStateList(getColor(ctx), getSelectedTextColor(ctx))
) )
viewHolder.badgeContainer.visibility = View.VISIBLE viewHolder.badgeContainer.visibility = View.VISIBLE
} else { } else {

View File

@ -9,31 +9,31 @@ 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) Glide.with(this)
.asBitmap() .asBitmap()
.load(url) .load(url)
.apply(RequestOptions.centerCropTransform()) .apply(RequestOptions.centerCropTransform())
.into(iv) .into(iv)
fun Context.bitmapFitCenter(url: String, iv: ImageView) = fun Context.bitmapFitCenter(url: String, iv: ImageView) =
Glide.with(this) Glide.with(this)
.asBitmap() .asBitmap()
.load(url) .load(url)
.apply(RequestOptions.fitCenterTransform()) .apply(RequestOptions.fitCenterTransform())
.into(iv) .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( val circularBitmapDrawable = RoundedBitmapDrawableFactory.create(
resources, resources,
resource resource
) )
circularBitmapDrawable.isCircular = true circularBitmapDrawable.isCircular = true
iv.setImageDrawable(circularBitmapDrawable) iv.setImageDrawable(circularBitmapDrawable)
} }
}) })

View File

@ -23,9 +23,9 @@ class SelfSignedGlideModule : GlideModule {
val client = getUnsafeHttpClient().build() val client = getUnsafeHttpClient().build()
registry?.append( registry?.append(
GlideUrl::class.java, GlideUrl::class.java,
InputStream::class.java, InputStream::class.java,
com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader.Factory(client) com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader.Factory(client)
) )
} }
} }