Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,15 @@ import com.rusili.superstreet.common.models.Type
import com.rusili.superstreet.common.models.footer.Author
import com.rusili.superstreet.common.models.header.HeaderImage
import com.rusili.superstreet.common.models.header.Title
import com.rusili.superstreet.database.favorites.FavoriteEntity
import com.rusili.superstreet.database.favorites.FavoriteModelMapper
import com.rusili.superstreet.database.favorites.model.FavoriteModelMapper
import com.rusili.superstreet.previewlist.domain.ArticlePreviewModel
import com.rusili.superstreet.previewlist.domain.CardSize
import io.reactivex.functions.Predicate
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.util.Date
import java.util.concurrent.TimeUnit

@RunWith(AndroidJUnit4::class)
class FavoriteDaoTest {
Expand Down
14 changes: 12 additions & 2 deletions app/src/main/java/com/rusili/superstreet/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.rusili.superstreet

import android.accounts.NetworkErrorException
import android.content.Intent
import android.os.Bundle
import android.view.View
Expand All @@ -8,6 +9,7 @@ import androidx.core.view.ViewCompat
import androidx.fragment.app.Fragment
import com.rusili.superstreet.article.ui.ArticleActivity
import com.rusili.superstreet.common.base.BaseActivity
import com.rusili.superstreet.common.extensions.isNetworkConnected
import com.rusili.superstreet.common.models.Header
import com.squareup.moshi.Moshi
import dagger.android.AndroidInjector
Expand All @@ -18,8 +20,8 @@ import javax.inject.Inject

class MainActivity : BaseActivity(), MainNavigator, HasSupportFragmentInjector {
@Inject protected lateinit var fragmentInjector: DispatchingAndroidInjector<Fragment>
@Inject protected lateinit var moshi: Moshi

@Inject protected lateinit var moshi: Moshi
override fun supportFragmentInjector(): AndroidInjector<Fragment> = fragmentInjector

override fun onCreate(savedInstanceState: Bundle?) {
Expand All @@ -33,6 +35,10 @@ class MainActivity : BaseActivity(), MainNavigator, HasSupportFragmentInjector {
view: View,
header: Header
) {
if (!isNetworkConnected()) {
showError(NetworkErrorException())
}

Intent(this, ArticleActivity::class.java).apply {
putExtra(
ArticleActivity.ARTICLE_HEADER_BUNDLE_KEY,
Expand All @@ -42,9 +48,13 @@ class MainActivity : BaseActivity(), MainNavigator, HasSupportFragmentInjector {
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
this,
view,
ViewCompat.getTransitionName(view)!!
ViewCompat.getTransitionName(view).orEmpty()
)
startActivity(it, options.toBundle())
}
}

override fun shareLink(link: String) {
// TODO
}
}
3 changes: 3 additions & 0 deletions app/src/main/java/com/rusili/superstreet/MainNavigator.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.rusili.superstreet

import android.content.Intent
import android.view.View
import com.rusili.superstreet.common.models.Header

Expand All @@ -9,4 +10,6 @@ interface MainNavigator {
view: View,
header: Header
)

fun shareLink(link: String)
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.rusili.superstreet.article.domain

import com.rusili.superstreet.article.ui.ArticleUsecase
import io.reactivex.Single
import javax.inject.Inject

class ArticleUsecaseImpl @Inject constructor(private val repository: ArticleRepository) : ArticleUsecase {
class ArticleUsecaseImpl @Inject constructor(private val repository: ArticleRepository) :
ArticleUsecase {

override fun getArticle(href: String) = repository.getArticle(href)
override fun getArticle(href: String): Single<ArticleFullModel> =
repository.getArticle(href)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.content.IntentSender
import android.os.Bundle
import android.view.View
import androidx.core.app.ActivityOptionsCompat
import androidx.core.content.ContextCompat.startActivity
import androidx.core.view.ViewCompat
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
Expand All @@ -21,6 +22,7 @@ import com.rusili.superstreet.common.models.Header
import com.rusili.superstreet.common.models.body.Image
import com.rusili.superstreet.common.models.body.ImageSize
import com.rusili.superstreet.common.ui.SimpleRequestListener
import com.rusili.superstreet.common.ui.actions.HasActionsView
import com.rusili.superstreet.image.ImageActivity
import com.rusili.superstreet.image.ImageActivity.Companion.IMAGE_BUNDLE_KEY
import com.rusili.superstreet.image.ImageActivity.Companion.IMAGE_SIZE_BUNDLE_KEY
Expand All @@ -29,18 +31,15 @@ import com.squareup.moshi.Moshi
import kotlinx.android.synthetic.main.activity_article.*
import javax.inject.Inject

class ArticleActivity : BaseActivity() {
class ArticleActivity : BaseActivity(), HasActionsView {
@Inject protected lateinit var viewModelFactory: ArticleViewModelFactory
@Inject protected lateinit var moshi: Moshi

private val viewModel: ArticleViewModel by lazy {
ViewModelProviders.of(this, viewModelFactory).get(ArticleViewModel::class.java)
}

private val adapter: ArticleAdapter by lazy {
ArticleAdapter(::onImageClicked, Glide.with(this)).apply {
setHasStableIds(true)
}
ArticleAdapter(::onImageClicked, Glide.with(this))
}

companion object {
Expand All @@ -55,6 +54,7 @@ class ArticleActivity : BaseActivity() {
intent?.getStringExtra(ARTICLE_HEADER_BUNDLE_KEY)?.let { json ->
moshi.adapter<Header>(Header::class.java).fromJson(json)?.let { header ->
setupViews(header)
setActionsView(header.title.href)
articleProgressBar.show()
viewModel.getArticle(header.title.href)
}
Expand All @@ -72,6 +72,13 @@ class ArticleActivity : BaseActivity() {
})
}

override fun setActionsView(link: String) {
articleActionsView.apply {
setFavoriteAction()
setShareLink(link)
}
}

private fun setupViews(header: Header) {
articleHeaderImageView.transitionName = header.headerImage.title
articleHeaderTitle.text = header.title.value
Expand Down Expand Up @@ -113,7 +120,7 @@ class ArticleActivity : BaseActivity() {
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
this@ArticleActivity,
view,
ViewCompat.getTransitionName(view)!!
ViewCompat.getTransitionName(view) ?: ""
)
startActivity(this, options.toBundle())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ class ArticleViewModel(private val usecase: ArticleUsecase) : BaseViewModel() {
.subscribeBy(
onSuccess = { livedata.postValue(LiveDataWrapper(it)) },
onError = {
livedata.postValue(LiveDataWrapper(null, it))
Timber.e(it, "Error getting preview articles.")
livedata.postValue(LiveDataWrapper(null, it))
}
))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class ArticleAdapter(
private val glide: RequestManager
) : ListAdapter<AbstractBodyModel, RecyclerView.ViewHolder>(ArticleDiffCallback()) {

init {
setHasStableIds(true)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
when (viewType) {
ArticleViewType.Paragraph.viewType -> ParagraphViewHolder(parent.inflate(R.layout.viewholder_article_paragraph))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ class ImageGroupViewHolder(
ViewCompat.setTransitionName(view, image.id.toString())

glide.load(image.getGroupSizeUrl())
.override(IMAGE_GROUP_WIDTH, IMAGE_GROUP_HEIGHT)
.into(view)

view.setOnClickListener { onClick(it, image, ImageSize.GROUP) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ class ImageViewHolder(

glide.load(model.getDefaultSizeUrl())
.listener(glideListener)
.override(IMAGE_DEFAULT_WIDTH, IMAGE_DEFAULT_HEIGHT)
.into(articleImageView)

articleImageView.setOnClickListener { onClick(it, model, ImageSize.DEFAULT) }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.rusili.superstreet.common.base

import android.accounts.NetworkErrorException
import android.content.Intent
import android.content.IntentSender
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
Expand All @@ -14,7 +15,7 @@ import java.net.UnknownHostException

abstract class BaseActivity : AppCompatActivity() {
protected val disposable = CompositeDisposable()
var container = 0
protected var container = 0

override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
Expand All @@ -32,12 +33,12 @@ abstract class BaseActivity : AppCompatActivity() {
super.onStop()
}

fun inflateFragment(fragment: BaseFragment) =
protected fun inflateFragment(fragment: BaseFragment) =
supportFragmentManager.beginTransaction()
.add(container, fragment)
.commit()

fun showError(error: Throwable?) {
protected fun showError(error: Throwable?) {
when (error) {
is IntentSender.SendIntentException -> showErrorDialogToFinish()
is NetworkErrorException -> showNetworkError()
Expand All @@ -47,7 +48,7 @@ abstract class BaseActivity : AppCompatActivity() {
}
}

fun showSnackbar(
protected fun showSnackbar(
message: String,
length: Int = 0
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,31 @@
package com.rusili.superstreet.common.extensions

import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import com.rusili.superstreet.jsoup.api.BASE_HTML

private const val STRING_SHARE_TYPE = "text/plain"
private const val STRING_SHARE_SUBJECT = "Sharing URL"
private const val STRING_SHARE_VIA = "Share via: "

fun Context?.isNetworkConnected(): Boolean =
this?.let {
(it.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).activeNetworkInfo?.isConnected ?: false
} ?: false

fun Context?.shareLink(link: String) {
this?.startActivity(
Intent.createChooser(
Intent(Intent.ACTION_SEND).apply {
setType(STRING_SHARE_TYPE)
putExtra(
Intent.EXTRA_SUBJECT,
STRING_SHARE_SUBJECT
)
putExtra(Intent.EXTRA_TEXT, BASE_HTML.plus(link))
},
STRING_SHARE_VIA
)
)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
package com.rusili.superstreet.common.extensions

import com.rusili.superstreet.jsoup.api.BASE_HTML

fun String.remove(toRemove: String) =
replace(toRemove, "")
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.rusili.superstreet.common.extensions

import android.content.res.TypedArray

fun TypedArray.getDimen(id: Int) =
resources.getDimensionPixelSize(id)
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.rusili.superstreet.common.ui

import android.annotation.SuppressLint
import android.content.Context
import android.content.res.ColorStateList
import android.content.res.TypedArray
import android.graphics.drawable.Drawable
import android.graphics.drawable.RippleDrawable
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.OvalShape
import android.graphics.drawable.shapes.Shape
import android.os.Build
import android.util.AttributeSet
import android.widget.ImageButton
import androidx.annotation.ColorInt
import androidx.core.content.res.getColorOrThrow
import androidx.core.content.withStyledAttributes
import com.rusili.superstreet.R

@SuppressLint("ResourceAsColor")
private const @ColorInt val MASK_COLOR_DEFAULT: Int = R.color.black_10_1000

class ShapedRippleImageButton @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ImageButton(context, attrs, defStyleAttr) {

init {
context.withStyledAttributes(
attrs,
R.styleable.ShapedRippleImageButton,
defStyleAttr,
0
) {
setupViews()
}
}

private fun TypedArray.setupViews() {
val buttonShape = OvalShape()

@ColorInt val fillColor = resources.getColor(android.R.color.transparent)
@ColorInt val maskColor = getColor(
R.styleable.ShapedRippleImageButton_ripple_color,
MASK_COLOR_DEFAULT
)

background?.let {
setBackgroundRippleShape(it, buttonShape)
} ?: setForegroundRippleShape(buttonShape, fillColor, maskColor)
}

private fun setBackgroundRippleShape(
background: Drawable,
buttonShape: Shape
) {
(background as RippleDrawable).apply {
(getDrawable(0) as ShapeDrawable).apply { shape = buttonShape }
(getDrawable(1) as ShapeDrawable).apply { shape = buttonShape }
}
}

private fun setForegroundRippleShape(
buttonShape: Shape,
fillColor: Int,
maskColor: Int
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
foreground = RippleDrawable(
ColorStateList.valueOf(maskColor),
ShapeDrawable(buttonShape).apply { paint.color = fillColor },
ShapeDrawable(buttonShape).apply { paint.color = maskColor }
)
}
}
}
Loading