Commit ffdb56e4 authored by Vladislav Bogdashkin's avatar Vladislav Bogdashkin 🎣

Merge branch 'feature/article_photos' into develop

parents 76e62401 ddbb760d
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<AndroidXmlCodeStyleSettings>
<option name="ARRANGEMENT_SETTINGS_MIGRATED_TO_191" value="true" />
</AndroidXmlCodeStyleSettings>
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
......
......@@ -13,6 +13,10 @@ class ArticlesInteractor @Inject constructor(
fun fetchArticles(feed:String) =
uc.getArticles(feed)
fun fetchArticlesPage(feed:String,pageSize:Int,current:Int) =
uc.fetchArticlesPage(feed,pageSize,current)
}
......
package com.biganto.visual.roompark.presentation.screen.article
import com.biganto.visual.roompark.conductor.BigantoBaseContract
import com.biganto.visual.roompark.domain.model.FeedModel
import io.reactivex.Observable
/**
* Created by Vladislav Bogdashkin on 30.09.2019.
......
......@@ -13,9 +13,14 @@ import com.biganto.visual.roompark.R
import com.biganto.visual.roompark.base.RoomParkApplication
import com.biganto.visual.roompark.base.RoomParkMainActivity
import com.biganto.visual.roompark.conductor.BigantoBaseController
import com.biganto.visual.roompark.conductor.dialogs.PhotoDialogController
import com.biganto.visual.roompark.conductor.dialogs.change_handler.DialogChangeHandler
import com.biganto.visual.roompark.presentation.screen.article.util.ArticleBottomPhotoAdapter
import com.biganto.visual.roompark.presentation.screen.article.util.HtmlPageAdapter
import com.biganto.visual.roompark.presentation.screen.article.util.HtmlTag
import com.biganto.visual.roompark.util.extensions.formatToSimple
import com.biganto.visual.roompark.util.extensions.setGone
import com.bluelinelabs.conductor.RouterTransaction
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.google.android.material.textview.MaterialTextView
......@@ -44,6 +49,7 @@ class ArticleScreenController :
getComponent()
}
@Inject
override lateinit var injectedPresenter: ArticleScreenPresenter
......@@ -56,6 +62,9 @@ class ArticleScreenController :
@BindView(R.id.articleBodyRecyclerView)
lateinit var articleRecyclerView: RecyclerView
@BindView(R.id.article_photos_recylcerView)
lateinit var bottomPhotosRecyclerView: RecyclerView
private val blurPreview:ImageView by lazy {
headerBlock.findViewById<ImageView>(R.id.articlePreviewBlurred)
}
......@@ -79,12 +88,28 @@ class ArticleScreenController :
LinearLayoutManager(activity, RecyclerView.VERTICAL, false)
articleRecyclerView.adapter = HtmlPageAdapter()
articleRecyclerView.itemAnimator = null
bottomPhotosRecyclerView.layoutManager =
LinearLayoutManager(activity, RecyclerView.HORIZONTAL, false)
bottomPhotosRecyclerView.adapter = ArticleBottomPhotoAdapter()
bottomPhotosRecyclerView.itemAnimator = null
}
override fun onViewBound(v: View) {
toolBar.setToolbar()
bottomNavigationController.hide()
bindRecycler()
detachDisposable.add(
(bottomPhotosRecyclerView.adapter as ArticleBottomPhotoAdapter)
.onItemClicked
.subscribe { router.pushController(
RouterTransaction.with(PhotoDialogController(it.url))
.pushChangeHandler(DialogChangeHandler())
.popChangeHandler(DialogChangeHandler())
)
}
)
}
override fun render(viewState: ArticleScreenViewState) {
......@@ -121,6 +146,11 @@ class ArticleScreenController :
articleDate.text = viewState.item.published.formatToSimple
bottomPhotosRecyclerView.setGone(viewState.item.bottomPhotoList.isNullOrEmpty())
viewState.item.bottomPhotoList?.let {
(bottomPhotosRecyclerView.adapter as ArticleBottomPhotoAdapter).setItems(it)
}
Glide.with(blurPreview)
.load(viewState.item.previewUrl)
.transform(BlurTransformation(40,4))
......
package com.biganto.visual.roompark.presentation.screen.article.util
import android.view.View
import com.biganto.visual.roompark.R
import com.biganto.visual.roompark.data.repository.db.requrey.TitledPhoto
import com.biganto.visual.roompark.presentation.screen.settings.util.CommonRecyclerAdapter
import com.biganto.visual.roompark.presentation.screen.settings.util.CommonViewHolder
import com.biganto.visual.roompark.util.view_utils.image_view.RoundedImageView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import kotlin.reflect.KClass
/**
* Created by Vladislav Bogdashkin on 29.01.2020.
*/
class ArticleBottomPhotoAdapter : CommonRecyclerAdapter<ArticleBottomPhotoViewHolder,TitledPhoto>() {
override val vhKlazz: KClass<ArticleBottomPhotoViewHolder>
get() = ArticleBottomPhotoViewHolder::class
override fun getVhLayout(): Int = R.layout.photo_article_slider_viewholder
}
class ArticleBottomPhotoViewHolder(itemView: View) : CommonViewHolder<TitledPhoto>(itemView){
override fun onViewBound(model: TitledPhoto) {
// articleTitle.text = model.title
Glide.with(itemView)
.load(model.url)
.centerCrop()
.fitCenter()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into((itemView as RoundedImageView))
}
}
package com.biganto.visual.roompark.presentation.screen.feed_list
import com.biganto.visual.roompark.conductor.BigantoBaseContract
import io.reactivex.Observable
/**
* Created by Vladislav Bogdashkin on 30.09.2019.
*/
interface ArticlesScreen : BigantoBaseContract<ArticlesScreenViewState> {
fun requsetsNewArticles(): Observable<Int>
}
......@@ -3,6 +3,7 @@ package com.biganto.visual.roompark.presentation.screen.feed_list
import android.view.View
import android.widget.ProgressBar
import androidx.core.os.bundleOf
import androidx.core.view.isNotEmpty
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import butterknife.BindView
......@@ -17,7 +18,11 @@ import com.biganto.visual.roompark.util.extensions.setGone
import com.biganto.visual.roompark.util.view_utils.grid.CeilsDecoration
import com.bluelinelabs.conductor.RouterTransaction
import com.google.android.material.textview.MaterialTextView
import com.jakewharton.rxbinding3.recyclerview.scrollStateChanges
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import timber.log.Timber
import java.util.concurrent.TimeUnit
import javax.inject.Inject
/**
......@@ -37,6 +42,17 @@ class ArticlesScreenController :
constructor(feedAlias:String):super(bundleOf(FEED_ALIAS to feedAlias))
override fun requsetsNewArticles(): Observable<Int> =
articlesRecyclerView.scrollStateChanges()
.filter { it == RecyclerView.SCROLL_STATE_IDLE}
.map { articlesRecyclerView.layoutManager as LinearLayoutManager }
.map { it.findLastCompletelyVisibleItemPosition() }
.filter{ articlesRecyclerView.isNotEmpty() }
.filter { it>(articlesRecyclerView.adapter?.itemCount?:0)-4 }
.map { articlesRecyclerView.adapter?.itemCount?:0 }
.debounce(120L, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
override fun injectDependencies() {
getComponent()
}
......@@ -106,6 +122,8 @@ class ArticlesScreenController :
when(viewState){
is ArticlesScreenViewState.Idle -> render(viewState)
is ArticlesScreenViewState.ArticlesLoaded -> render(viewState)
is ArticlesScreenViewState.ArticlesScrollPage -> render(viewState)
is ArticlesScreenViewState.RestoreView -> render(viewState)
is ArticlesScreenViewState.SomeError -> render(viewState)
}
}
......@@ -122,6 +140,29 @@ class ArticlesScreenController :
}
private fun render(viewState: ArticlesScreenViewState.ArticlesScrollPage){
Timber.d("got items: ${viewState.items.size}")
(articlesRecyclerView.adapter as ArticlesAdapter).addItems(viewState.items)
}
private fun render(viewState: ArticlesScreenViewState.RestoreView){
progressBar.setGone(true)
emptyListNotice.setGone(true)
articlesRecyclerView.setGone(true)
if (viewState.restore.articles.isNullOrEmpty())
{
emptyListNotice.setGone(false)
articlesRecyclerView.setGone(true)
}
else{
emptyListNotice.setGone(true)
articlesRecyclerView.setGone(false)
(articlesRecyclerView.adapter as ArticlesAdapter).setItems(viewState.restore.articles)
}
}
private fun render(viewState: ArticlesScreenViewState.ArticlesLoaded) {
progressBar.setGone(true)
emptyListNotice.setGone(true)
......
......@@ -14,6 +14,8 @@ import javax.inject.Named
* Created by Vladislav Bogdashkin on 30.09.2019.
*/
private const val FEED_PAGE_SIZE = 10
class ArticlesScreenPresenter @Inject constructor(
@Named(FEED_ALIAS) private val feedId:String,
......@@ -21,6 +23,14 @@ class ArticlesScreenPresenter @Inject constructor(
)
: BigantoBasePresenter<ArticlesScreen, ArticlesScreenViewState>() {
private val restoreModel = RestoreModel(mutableListOf())
override fun detachView() {
super.detachView()
restoreStateObservable.accept(ArticlesScreenViewState.RestoreView(restoreModel))
}
override fun defaultErrorViewStateHandler() =
{e: ExceptionString -> ArticlesScreenViewState.SomeError(e)}
......@@ -31,8 +41,21 @@ class ArticlesScreenPresenter @Inject constructor(
.map<ArticlesScreenViewState>{ ArticlesScreenViewState.ArticlesLoaded(it.articles) }
.startWith(Observable.just<ArticlesScreenViewState>(ArticlesScreenViewState.Idle()))
val getNewArticlesPage = intent(ArticlesScreen::requsetsNewArticles)
.flatMap { interactor.fetchArticlesPage(feedId, FEED_PAGE_SIZE,it) }
.map<ArticlesScreenViewState> {articlePage ->
articlePage.articles
.asSequence()
.filter { !restoreModel.articles.contains(it) }
.toList()
.let {uniqueItems->restoreModel.articles.addAll(uniqueItems)}
ArticlesScreenViewState.ArticlesScrollPage(articlePage.articles.toList())
}
.onErrorReturn (::parseError)
val state = restoreStateObservable
.mergeWith(prefetchCards)
.mergeWith(getNewArticlesPage)
.doOnError{ Timber.e(it)}
.onErrorReturn(::parseError)
.subscribeOn(Schedulers.io())
......
......@@ -13,4 +13,11 @@ sealed class ArticlesScreenViewState : BigantoBaseViewState() {
class Idle : ArticlesScreenViewState()
class ArticlesLoaded(val items: List<ArticlePreviewModel>) : ArticlesScreenViewState()
class SomeError(val exception: ExceptionString) : ArticlesScreenViewState()
class ArticlesScrollPage(val items:List<ArticlePreviewModel>) : ArticlesScreenViewState()
class RestoreView(val restore:RestoreModel) : ArticlesScreenViewState()
}
data class RestoreModel(
var articles:MutableList<ArticlePreviewModel>
)
\ No newline at end of file
......@@ -96,9 +96,8 @@ class FeedsScreenController :
.filter { it == RecyclerView.SCROLL_STATE_IDLE}
.map { feedsRecyclerView.layoutManager as LinearLayoutManager }
.map { it.findLastCompletelyVisibleItemPosition() }
.doOnNext { Timber.d("Visible items $it of ${(feedsRecyclerView.adapter?.itemCount?:0) - 3}") }
.filter{ storedFeedsList.isNotEmpty() }
.filter { it>(feedsRecyclerView.adapter?.itemCount?:0)-2 }
.filter { it>(feedsRecyclerView.adapter?.itemCount?:0)-4 }
.map { feedsRecyclerView.adapter?.itemCount?:0 }
.map { Pair(storedFeedsList[feedsTabs.selectedTabPosition],it)}
.debounce(120L,TimeUnit.MILLISECONDS)
......
......@@ -13,7 +13,7 @@ import javax.inject.Inject
* Created by Vladislav Bogdashkin on 30.09.2019.
*/
const val FEED_PREVIEW_PAGE_SIZE = 10
private const val FEED_PREVIEW_PAGE_SIZE = 10
class FeedsScreenPresenter @Inject constructor(
private val interactor: FeedsInteractor
......@@ -28,7 +28,8 @@ class FeedsScreenPresenter @Inject constructor(
arrayListOf(),
arrayListOf(),
arrayListOf(),
arrayListOf())
mutableListOf()
)
override fun attachView(view: FeedsScreen) {
......@@ -67,9 +68,13 @@ class FeedsScreenPresenter @Inject constructor(
val getFeedArticlesPreview = intent(FeedsScreen::feedsTabSelected)
.flatMap { interactor.fetchArticles(it) }
.map<FeedsScreenViewState> {
restoreModel.articles = it.articles
FeedsScreenViewState.GetFeedArticlesPreview(it.articles.toList())
.map<FeedsScreenViewState> {articlePage ->
articlePage.articles
.asSequence()
.filter { !restoreModel.articles.contains(it) }
.toList()
.let {uniqueItems->restoreModel.articles.addAll(uniqueItems)}
FeedsScreenViewState.GetFeedArticlesPreview(articlePage.articles.toList())
}
.onErrorReturn (::parseError)
......@@ -95,10 +100,14 @@ class FeedsScreenPresenter @Inject constructor(
val getNewArticlesPage = intent(FeedsScreen::requsetsNewArticles)
.flatMap { interactor.fetchArticles(it.first.alias, FEED_PREVIEW_PAGE_SIZE,it.second) }
.map<FeedsScreenViewState> {
restoreModel.articles = it.articles
Timber.d("arrived list: ${it.articles.size}")
FeedsScreenViewState.ArticlesScrollPage(it.articles.toList())
.map<FeedsScreenViewState> {articlePage ->
articlePage.articles
.asSequence()
.filter { !restoreModel.articles.contains(it) }
.toList()
.let {uniqueItems->restoreModel.articles.addAll(uniqueItems)}
FeedsScreenViewState.ArticlesScrollPage(articlePage.articles.toList())
}
.onErrorReturn (::parseError)
......
......@@ -38,5 +38,5 @@ data class RestoreModel(
var feeds:List<FeedModel>,
var albums:List<AlbumPreviewModel>,
var cams:List<WebCamModel>,
var articles:List<ArticlePreviewModel>
var articles:MutableList <ArticlePreviewModel>
)
\ No newline at end of file
......@@ -16,19 +16,17 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/default_image_placeholder" />
app:layout_constraintTop_toTopOf="parent" />
<com.biganto.visual.roompark.util.view_utils.image_view.RoundedImageView
android:id="@+id/articlePreview"
app:image_corner_radius="4dp"
android:layout_width="125dp"
android:layout_height="125dp"
android:layout_marginStart="16dp"
android:layout_marginTop="44dp"
app:image_corner_radius="4dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_favorites" />
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/articleDate"
......@@ -37,7 +35,6 @@
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:includeFontPadding="false"
android:text="22 / 02 / 2019"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
......
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools">
<androidx.core.widget.NestedScrollView
......@@ -35,8 +35,18 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/articleBodyRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/article_photos_recylcerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:background="@color/colorOpacityBackground"
android:orientation="horizontal"
android:paddingBottom="16dp"
tools:listitem="@layout/photo_viewholder" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
......
<?xml version="1.0" encoding="utf-8"?>
<com.biganto.visual.roompark.util.view_utils.image_view.RoundedImageView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="256dp"
android:layout_height="228dp"
android:layout_margin="16dp"
android:scaleType="centerCrop"
app:image_corner_radius="4dp" />
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment