Skip to content

Commit

Permalink
Smart grid (#56)
Browse files Browse the repository at this point in the history
* Refactor classes to a more package-by-feature approach

* Fix a potential NPE

* Auto-fit grid. Fixes #45. Fixes #46.

* Fixes a visual issue
  • Loading branch information
stoyicker authored Apr 12, 2017
1 parent 361c8e0 commit c7a2e29
Show file tree
Hide file tree
Showing 11 changed files with 61 additions and 38 deletions.
43 changes: 43 additions & 0 deletions app/src/main/kotlin/app/gaming/AutoFitStaggeredGridRecyclerView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package app.gaming

import android.content.Context
import android.support.annotation.Px
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.StaggeredGridLayoutManager
import android.util.AttributeSet
import org.jorge.ms.app.R
import util.android.ext.getDimension

/**
* A recycler view that automatically attaches to itself a GridLayoutManager and performs auto-fit
* with its elements.
* @param context The context
* @param attrs The attributes
* @see <a href="http://blog.sqisland.com/2014/12/recyclerview-autofit-grid.html">
* Square Island: RecyclerView: Autofit grid</a>
*/
internal class AutoFitStaggeredGridRecyclerView(context: Context, attrs: AttributeSet?)
: RecyclerView(context, attrs) {
private @Px val columnWidth: Int

init {
@Px val defaultColumnWidth = context.getDimension(R.dimen.default_column_width).toInt()
if (attrs != null) {
val attrsArray = intArrayOf(android.R.attr.columnWidth)
val typedArray = context.obtainStyledAttributes(attrs, attrsArray)
columnWidth = typedArray.getDimensionPixelSize(0, defaultColumnWidth)
typedArray.recycle()
} else {
columnWidth = defaultColumnWidth
}
layoutManager = StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL)
}

override fun onMeasure(widthSpec: Int, heightSpec: Int) {
super.onMeasure(widthSpec, heightSpec)
if (columnWidth > 0) {
val spanCount = Math.max(1, measuredWidth / columnWidth)
(layoutManager as StaggeredGridLayoutManager).spanCount = spanCount
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package app.widget
package app.gaming

import android.content.Context
import android.graphics.Canvas
Expand All @@ -9,15 +9,15 @@ import android.view.MotionEvent
import android.view.animation.Animation
import android.view.animation.Transformation
import android.widget.LinearLayout
import org.jorge.ms.app.R
import util.android.ext.getColorCompat
import util.android.ext.getInteger
import org.jorge.ms.app.R

/**
* @see <a href="https://androidreclib.wordpress.com/2014/11/18/the-touch-ripple-on-gingerbread/">
* The touch ripple on Gingerbread | Android Rec Library</>
*/
internal class CompatRippleLinearLayout(context: Context, attrs: AttributeSet)
internal class CompatRippleLinearLayout(context: Context, attrs: AttributeSet?)
: LinearLayout(context, attrs) {
private val rippleColor = context.getColorCompat(R.color.default_ripple)
private val rippleDuration = context.getInteger(android.R.integer.config_shortAnimTime).toLong()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package app.widget
package app.gaming

/**
* An interface describing the behavior required by views bound to coordinators.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package app.gaming

import android.content.Context
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.StaggeredGridLayoutManager
Expand All @@ -12,7 +11,6 @@ import android.widget.TextView
import domain.entity.Post
import org.jorge.ms.app.R
import util.android.ext.getDimension
import util.android.ext.isPortrait

/**
* Configures the recycler view holding the post list.
Expand All @@ -25,7 +23,6 @@ internal object TopGamingAllTimePostsContentViewConfig {
internal fun dumpOnto(view: TopGamingAllTimePostsView, callback: TopGamingAllTimePostsActivity.BehaviorCallback) {
view.contentView.let { recyclerView ->
recyclerView.adapter = provideAdapter(callback)
recyclerView.layoutManager = provideLayoutManager(recyclerView.context)
recyclerView.addOnScrollListener(provideEndlessLoadListener(
recyclerView.layoutManager, callback))
recyclerView.setHasFixedSize(false)
Expand All @@ -48,27 +45,14 @@ internal object TopGamingAllTimePostsContentViewConfig {
return adapter
}

/**
* Provides a layout manager based on the size of the screen.
* @param context The context
*/
private fun provideLayoutManager(context: Context): RecyclerView.LayoutManager
= if (context.isPortrait()) {
LinearLayoutManager(context)
} else {
val ret = StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL)
ret.gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
ret
}
}

private fun provideEndlessLoadListener(layoutManager: RecyclerView.LayoutManager,
callback: TopGamingAllTimePostsActivity.BehaviorCallback)
= object : EndlessLoadListener(layoutManager) {
override fun onLoadMore() {
callback.onPageLoadRequested()
}
}
}

/**
* A very simple adapter backed by a mutable list that exposes a method to add items.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package app.gaming

import android.support.annotation.VisibleForTesting
import app.UIPostExecutionThread
import app.widget.LoadableContentView
import app.gaming.LoadableContentView
import com.google.firebase.crash.FirebaseCrash
import domain.entity.Post
import domain.interactor.TopGamingAllTimeFetchPostsUseCase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package app.gaming

import android.support.v7.widget.RecyclerView
import android.view.View
import app.widget.LoadableContentView
import app.gaming.LoadableContentView
import domain.entity.Post

/**
Expand Down
5 changes: 3 additions & 2 deletions app/src/main/res/layout/include_top_posts_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
<app.gaming.AutoFitStaggeredGridRecyclerView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never" />
android:overScrollMode="never"
android:columnWidth="@dimen/top_posts_column_width" />
<android.support.v4.widget.ContentLoadingProgressBar
android:id="@+id/progress"
android:layout_width="match_parent"
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/res/layout/item_post.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<app.widget.CompatRippleLinearLayout
<app.gaming.CompatRippleLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
Expand Down Expand Up @@ -40,4 +40,4 @@
android:textIsSelectable="false"
style="@style/AppTheme.TextSubhead" />
</LinearLayout>
</app.widget.CompatRippleLinearLayout>
</app.gaming.CompatRippleLinearLayout>
2 changes: 2 additions & 0 deletions app/src/main/res/values/dimens.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
<dimen name="item_separation">16dp</dimen>
<dimen name="section_separator">16dp</dimen>
<dimen name="text_separation">12dp</dimen>
<dimen name="default_column_width">150dp</dimen>
<dimen name="top_posts_column_width">200dp</dimen>
</resources>
2 changes: 1 addition & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
<string name="app_label">reddit</string>
<string name="top_posts_error_description">Finished loading</string>
<string name="top_posts_error_action">Retry</string>
<string name="subreddit_template">/r/%s</string>
<string name="subreddit_template">r/%s</string>
</resources>
13 changes: 3 additions & 10 deletions util-android/src/main/kotlin/util/android/ext/Context.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import android.support.annotation.DimenRes
import android.support.annotation.IntegerRes

/**
* Extension function to reduce verbosity to getInteger(...).
* Extension function to reduce verbosity to resources.getInteger(...).
* @param resId The id of the resource to get.
*/
fun Context.getInteger(@IntegerRes resId: Int) = this.resources.getInteger(resId)

/**
* Extension function to reduce verbosity to getColor(...).
* Extension function to reduce verbosity to resources.getColor(...).
* @param resId The id of the resource to get.
*/
fun Context.getColorCompat(@ColorRes resId: Int) =
Expand All @@ -24,14 +24,7 @@ fun Context.getColorCompat(@ColorRes resId: Int) =
this.resources.getColor(resId)

/**
* Extension function to reduce verbosity to getDimension(...).
* Extension function to reduce verbosity to resources.getDimension(...).
* @param resId The id of the resource to get.
*/
fun Context.getDimension(@DimenRes resId: Int) = this.resources.getDimension(resId)

/**
* Extension function to check if the device is in portrait mode.
*/
fun Context.isPortrait() = this.resources.displayMetrics.let {
it.heightPixels > it.widthPixels
}

0 comments on commit c7a2e29

Please sign in to comment.