From dd31145f13fdc4c6512ef7a7808afa99c675c49b Mon Sep 17 00:00:00 2001 From: Philip Cohn-Cort Date: Wed, 17 Oct 2018 18:03:21 -0400 Subject: [PATCH 01/14] [Refactor] - Welcome: Use the same CellViewModels for both `home` and `all` This removes a decent amount of code duplication. --- .../edu/artic/events/AllEventsAdapter.kt | 2 +- .../edu/artic/events/AllEventsViewModel.kt | 16 ++- .../recyclerview/AllEventsItemDecoration.kt | 6 +- .../exhibitions/AllExhibitionsAdapter.kt | 4 +- .../exhibitions/AllExhibitionsViewModel.kt | 26 ++-- .../kotlin/edu/artic/tours/AllToursAdapter.kt | 4 +- .../edu/artic/tours/AllToursViewModel.kt | 10 +- .../edu/artic/welcome/WelcomeEventsAdapter.kt | 9 +- .../artic/welcome/WelcomeExhibitionAdapter.kt | 9 +- .../edu/artic/welcome/WelcomeToursAdapter.kt | 5 +- .../edu/artic/welcome/WelcomeViewModel.kt | 131 ++---------------- 11 files changed, 63 insertions(+), 159 deletions(-) diff --git a/content_listing/src/main/kotlin/edu/artic/events/AllEventsAdapter.kt b/content_listing/src/main/kotlin/edu/artic/events/AllEventsAdapter.kt index 092b858a2..e6d648142 100644 --- a/content_listing/src/main/kotlin/edu/artic/events/AllEventsAdapter.kt +++ b/content_listing/src/main/kotlin/edu/artic/events/AllEventsAdapter.kt @@ -18,7 +18,7 @@ class AllEventsAdapter : AutoHolderRecyclerViewAdapter = BehaviorSubject.createDefault(event.title) val eventDescription: Subject = BehaviorSubject.createDefault(event.short_description.orEmpty()) val eventImageUrl: Subject = BehaviorSubject.createDefault(event.imageURL) diff --git a/content_listing/src/main/kotlin/edu/artic/events/recyclerview/AllEventsItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/events/recyclerview/AllEventsItemDecoration.kt index d98b0c944..6d60ae484 100644 --- a/content_listing/src/main/kotlin/edu/artic/events/recyclerview/AllEventsItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/events/recyclerview/AllEventsItemDecoration.kt @@ -7,7 +7,7 @@ import android.view.View import edu.artic.content.listing.R import edu.artic.events.AllEventsAdapter import edu.artic.events.AllEventsCellHeaderViewModel -import edu.artic.events.AllEventsCellViewModel +import edu.artic.events.EventCellViewModel class AllEventsItemDecoration( context: Context, @@ -32,7 +32,7 @@ class AllEventsItemDecoration( outRect.top = if (position == 0) headerVerticalSpacing else verticalSpacing outRect.bottom = halfOfVertical } - is AllEventsCellViewModel -> { + is EventCellViewModel -> { val adjustedPosition = position - (it.headerPosition - 1) val column = (adjustedPosition) % spanCount // item column outRect.left = horizontalSpacing - column * horizontalSpacing / spanCount // spacing - column * ((1f / spanCount) * spacing) @@ -44,4 +44,4 @@ class AllEventsItemDecoration( } } -} \ No newline at end of file +} diff --git a/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsAdapter.kt b/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsAdapter.kt index b76f76df1..d348a42f2 100644 --- a/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsAdapter.kt +++ b/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsAdapter.kt @@ -15,9 +15,9 @@ import kotlinx.android.synthetic.main.cell_all_exhibitions_layout.view.* * @author Sameer Dhakal (Fuzz) */ -class AllExhibitionsAdapter : AutoHolderRecyclerViewAdapter() { +class AllExhibitionsAdapter : AutoHolderRecyclerViewAdapter() { - override fun View.onBindView(item: AllExhibitionsCellViewModel, position: Int) { + override fun View.onBindView(item: ExhibitionCellViewModel, position: Int) { item.exhibitionImageUrl .observeOn(AndroidSchedulers.mainThread()) .subscribe { diff --git a/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsViewModel.kt b/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsViewModel.kt index 68190385d..7be683dd5 100644 --- a/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsViewModel.kt +++ b/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsViewModel.kt @@ -29,17 +29,17 @@ class AllExhibitionsViewModel @Inject constructor( object Search: NavigationEndpoint() } - val exhibitions: Subject> = BehaviorSubject.create() + val exhibitions: Subject> = BehaviorSubject.create() init { exhibitionsDao.getAllExhibitions() .map { list -> - val viewModelList = ArrayList() + val viewModelList = ArrayList() list.forEach { exhibition -> - viewModelList.add(AllExhibitionsCellViewModel( + viewModelList.add(ExhibitionCellViewModel( disposeBag, - languageSelector, - exhibition + exhibition, + languageSelector )) } return@map viewModelList @@ -59,10 +59,13 @@ class AllExhibitionsViewModel @Inject constructor( } -class AllExhibitionsCellViewModel( +/** + * ViewModel responsible for building each item in the `On View` list (i.e. the list of exhibitions). + */ +class ExhibitionCellViewModel( adapterDisposeBag: DisposeBag, - val languageSelector: LanguageSelector, - val exhibition: ArticExhibition + val exhibition: ArticExhibition, + val languageSelector: LanguageSelector ) : CellViewModel(adapterDisposeBag) { val exhibitionTitle: Subject = BehaviorSubject.createDefault(exhibition.title) @@ -73,9 +76,10 @@ class AllExhibitionsCellViewModel( languageSelector.currentLanguage .map { - exhibition.endTime.format( - HomeExhibition.obtainFormatter(it) - ) + HomeExhibition.obtainFormatter(it) + } + .map { + exhibition.endTime.format(it) } .bindToMain(exhibitionEndDate) .disposedBy(disposeBag) diff --git a/content_listing/src/main/kotlin/edu/artic/tours/AllToursAdapter.kt b/content_listing/src/main/kotlin/edu/artic/tours/AllToursAdapter.kt index 018ec3e8f..88bcf0897 100644 --- a/content_listing/src/main/kotlin/edu/artic/tours/AllToursAdapter.kt +++ b/content_listing/src/main/kotlin/edu/artic/tours/AllToursAdapter.kt @@ -18,7 +18,7 @@ import kotlinx.android.synthetic.main.cell_all_tours_layout.view.* * @author Sameer Dhakal (Fuzz) */ -class AllToursAdapter(recyclerView : RecyclerView, introSubject: Subject, viewDisposeBag: DisposeBag) : AutoHolderRecyclerViewAdapter() { +class AllToursAdapter(recyclerView : RecyclerView, introSubject: Subject, viewDisposeBag: DisposeBag) : AutoHolderRecyclerViewAdapter() { private val introHolder = BaseViewHolder(recyclerView, R.layout.cell_all_tours_intro) @@ -32,7 +32,7 @@ class AllToursAdapter(recyclerView : RecyclerView, introSubject: Subject } } - override fun View.onBindView(item: AllToursCellViewModel, position: Int) { + override fun View.onBindView(item: TourCellViewModel, position: Int) { item.tourImageUrl.subscribe { GlideApp.with(context) diff --git a/content_listing/src/main/kotlin/edu/artic/tours/AllToursViewModel.kt b/content_listing/src/main/kotlin/edu/artic/tours/AllToursViewModel.kt index 44830a29e..50e88e1c7 100644 --- a/content_listing/src/main/kotlin/edu/artic/tours/AllToursViewModel.kt +++ b/content_listing/src/main/kotlin/edu/artic/tours/AllToursViewModel.kt @@ -28,15 +28,15 @@ class AllToursViewModel @Inject constructor( data class TourDetails(val pos: Int, val tour: ArticTour) : NavigationEndpoint() } - val tours: Subject> = BehaviorSubject.create() + val tours: Subject> = BehaviorSubject.create() val intro: Subject = BehaviorSubject.createDefault("") init { toursDao.getAllTours() .map { list -> - val viewModelList = ArrayList() + val viewModelList = ArrayList() list.forEach { tour -> - viewModelList.add(AllToursCellViewModel(disposeBag, tour, languageSelector)) + viewModelList.add(TourCellViewModel(disposeBag, tour, languageSelector)) } return@map viewModelList } @@ -67,9 +67,9 @@ class AllToursViewModel @Inject constructor( } /** - * This class is fundamentally the same as `WelcomeTourCellViewModel` in the :welcome module. + * ViewModel responsible for building each item in the tour summary list. */ -class AllToursCellViewModel( +class TourCellViewModel( adapterDisposeBag: DisposeBag, val tour: ArticTour, languageSelector: LanguageSelector diff --git a/welcome/src/main/kotlin/edu/artic/welcome/WelcomeEventsAdapter.kt b/welcome/src/main/kotlin/edu/artic/welcome/WelcomeEventsAdapter.kt index d11c9d92d..74f34ee04 100644 --- a/welcome/src/main/kotlin/edu/artic/welcome/WelcomeEventsAdapter.kt +++ b/welcome/src/main/kotlin/edu/artic/welcome/WelcomeEventsAdapter.kt @@ -6,6 +6,7 @@ import com.fuzz.rx.disposedBy import com.jakewharton.rxbinding2.widget.text import edu.artic.adapter.AutoHolderRecyclerViewAdapter import edu.artic.adapter.BaseViewHolder +import edu.artic.events.EventCellViewModel import edu.artic.image.GlideApp import kotlinx.android.synthetic.main.welcome_event_cell_layout.view.* @@ -14,8 +15,8 @@ import kotlinx.android.synthetic.main.welcome_event_cell_layout.view.* * @author Sameer Dhakal (Fuzz) */ -class WelcomeEventsAdapter : AutoHolderRecyclerViewAdapter() { - override fun View.onBindView(item: WelcomeEventCellViewModel, position: Int) { +class WelcomeEventsAdapter : AutoHolderRecyclerViewAdapter() { + override fun View.onBindView(item: EventCellViewModel, position: Int) { item.eventTitle .bindToMain(title.text()) @@ -25,11 +26,11 @@ class WelcomeEventsAdapter : AutoHolderRecyclerViewAdapter() { +class OnViewAdapter : AutoHolderRecyclerViewAdapter() { - override fun View.onBindView(item: WelcomeExhibitionCellViewModel, position: Int) { + override fun View.onBindView(item: ExhibitionCellViewModel, position: Int) { - item.exhibitionTitleStream + item.exhibitionTitle .bindToMain(exhibitionTitle.text()) .disposedBy(item.viewDisposeBag) - item.exhibitionDate + item.exhibitionEndDate .map { context.getString(R.string.throughDate, it) } diff --git a/welcome/src/main/kotlin/edu/artic/welcome/WelcomeToursAdapter.kt b/welcome/src/main/kotlin/edu/artic/welcome/WelcomeToursAdapter.kt index ecdd14943..05f230951 100644 --- a/welcome/src/main/kotlin/edu/artic/welcome/WelcomeToursAdapter.kt +++ b/welcome/src/main/kotlin/edu/artic/welcome/WelcomeToursAdapter.kt @@ -7,16 +7,17 @@ import com.jakewharton.rxbinding2.widget.text import edu.artic.adapter.AutoHolderRecyclerViewAdapter import edu.artic.adapter.BaseViewHolder import edu.artic.image.GlideApp +import edu.artic.tours.TourCellViewModel import kotlinx.android.synthetic.main.welcome_tour_summary_cell_layout.view.* /** * @author Sameer Dhakal (Fuzz) */ -class WelcomeToursAdapter : AutoHolderRecyclerViewAdapter() { +class WelcomeToursAdapter : AutoHolderRecyclerViewAdapter() { - override fun View.onBindView(item: WelcomeTourCellViewModel, position: Int) { + override fun View.onBindView(item: TourCellViewModel, position: Int) { item.tourImageUrl.subscribe { GlideApp.with(context) .load(it) diff --git a/welcome/src/main/kotlin/edu/artic/welcome/WelcomeViewModel.kt b/welcome/src/main/kotlin/edu/artic/welcome/WelcomeViewModel.kt index 67b8d073a..89eff8b83 100644 --- a/welcome/src/main/kotlin/edu/artic/welcome/WelcomeViewModel.kt +++ b/welcome/src/main/kotlin/edu/artic/welcome/WelcomeViewModel.kt @@ -5,8 +5,6 @@ import com.fuzz.rx.* import edu.artic.analytics.AnalyticsAction import edu.artic.analytics.AnalyticsTracker import edu.artic.analytics.EventCategoryName -import edu.artic.localization.util.DateTimeHelper.Purpose.* -import edu.artic.base.utils.orIfNullOrBlank import edu.artic.db.daos.ArticEventDao import edu.artic.db.daos.ArticExhibitionDao import edu.artic.db.daos.ArticTourDao @@ -14,9 +12,11 @@ import edu.artic.db.daos.GeneralInfoDao import edu.artic.db.models.ArticEvent import edu.artic.db.models.ArticExhibition import edu.artic.db.models.ArticTour +import edu.artic.events.EventCellViewModel +import edu.artic.exhibitions.ExhibitionCellViewModel import edu.artic.localization.LanguageSelector import edu.artic.membership.MemberInfoPreferencesManager -import edu.artic.viewmodel.CellViewModel +import edu.artic.tours.TourCellViewModel import edu.artic.viewmodel.NavViewViewModel import edu.artic.viewmodel.Navigate import io.reactivex.rxkotlin.Observables @@ -49,9 +49,9 @@ class WelcomeViewModel @Inject constructor(private val welcomePreferencesManager val shouldPeekTourSummary: Subject = BehaviorSubject.create() - val tours: Subject> = BehaviorSubject.create() - val exhibitions: Subject> = BehaviorSubject.create() - val events: Subject> = BehaviorSubject.create() + val tours: Subject> = BehaviorSubject.create() + val exhibitions: Subject> = BehaviorSubject.create() + val events: Subject> = BehaviorSubject.create() val welcomePrompt: Subject = BehaviorSubject.create() val currentCardHolder: Subject = BehaviorSubject.create() @@ -63,9 +63,9 @@ class WelcomeViewModel @Inject constructor(private val welcomePreferencesManager toursDao.getTourSummary() .map { - val viewModelList = ArrayList() + val viewModelList = ArrayList() it.forEach { - viewModelList.add(WelcomeTourCellViewModel(disposeBag, it, languageSelector)) + viewModelList.add(TourCellViewModel(disposeBag, it, languageSelector)) } return@map viewModelList }.bindTo(tours) @@ -73,9 +73,9 @@ class WelcomeViewModel @Inject constructor(private val welcomePreferencesManager exhibitionDao.getExhibitionSummary() .map { - val viewModelList = ArrayList() + val viewModelList = ArrayList() it.forEach { - viewModelList.add(WelcomeExhibitionCellViewModel(disposeBag, it, languageSelector)) + viewModelList.add(ExhibitionCellViewModel(disposeBag, it, languageSelector)) } return@map viewModelList }.bindTo(exhibitions) @@ -83,9 +83,9 @@ class WelcomeViewModel @Inject constructor(private val welcomePreferencesManager eventsDao.getEventSummary() .map { - val viewModelList = ArrayList() + val viewModelList = ArrayList() it.forEach { - viewModelList.add(WelcomeEventCellViewModel(disposeBag, it, languageSelector)) + viewModelList.add(EventCellViewModel(disposeBag, it, languageSelector)) } return@map viewModelList }.bindTo(events) @@ -162,111 +162,4 @@ class WelcomeViewModel @Inject constructor(private val welcomePreferencesManager } -/** - * ViewModel responsible for building each item in the tour summary list. - */ -class WelcomeTourCellViewModel( - adapterDisposeBag: DisposeBag, - val tour: ArticTour, - languageSelector: LanguageSelector -) : CellViewModel(adapterDisposeBag) { - - /** - * Which translation of [tour] currently matches the - * [App-level language selection][LanguageSelector.getAppLocale]. - */ - private val tourTranslation: Subject = BehaviorSubject.create() - - val tourTitle: Subject = BehaviorSubject.create() - val tourDescription: Subject = BehaviorSubject.create() - val tourStops: Subject = BehaviorSubject.createDefault(tour.tourStops.count().toString()) - val tourDuration: Subject = BehaviorSubject.create() - val tourImageUrl: Subject = BehaviorSubject.createDefault(tour.standardImageUrl) - - init { - - languageSelector.currentLanguage - .map { - languageSelector.selectFrom(tour.allTranslations) - } - .bindTo(tourTranslation) - .disposedBy(disposeBag) - - tourTranslation - .map { - it.description.orIfNullOrBlank(tour.description).orEmpty() - } - .bindToMain(tourDescription) - .disposedBy(disposeBag) - - tourTranslation - .map { - it.title.orIfNullOrBlank(tour.title).orEmpty() - } - .bindToMain(tourTitle) - .disposedBy(disposeBag) - tourTranslation - .map { - it.tour_duration.orIfNullOrBlank(tour.tourDuration).orEmpty() - } - .bindToMain(tourDuration) - .disposedBy(disposeBag) - } -} - -/** - * ViewModel responsible for building each item in the `On View` list (i.e. the list of exhibitions). - */ -class WelcomeExhibitionCellViewModel( - adapterDisposeBag: DisposeBag, - val exhibition: ArticExhibition, - val languageSelector: LanguageSelector -) : CellViewModel(adapterDisposeBag) { - - val exhibitionTitleStream: Subject = BehaviorSubject.createDefault(exhibition.title) - val exhibitionDate: Subject = BehaviorSubject.create() - val exhibitionImageUrl: Subject = BehaviorSubject.createDefault(exhibition.imageUrl.orEmpty()) - - init { - - languageSelector.currentLanguage - .map { - HomeExhibition.obtainFormatter(it) - } - .map { - exhibition.endTime.format(it) - } - .bindToMain(exhibitionDate) - .disposedBy(disposeBag) - - } - -} - -/** - * ViewModel responsible for building the event summary list. - */ -class WelcomeEventCellViewModel( - adapterDisposeBag: DisposeBag, - val event: ArticEvent, - val languageSelector: LanguageSelector -) : CellViewModel(adapterDisposeBag) { - - val eventTitle: Subject = BehaviorSubject.createDefault(event.title) - val eventShortDescription: Subject = BehaviorSubject.createDefault(event.short_description.orEmpty()) - val eventTime: Subject = BehaviorSubject.create() - val eventImageUrl: Subject = BehaviorSubject.createDefault(event.imageURL) - - init { - languageSelector.currentLanguage - .map { - HomeEvent.obtainFormatter(it) - } - .map { - event.startTime.format(it) - } - .bindTo(eventTime) - .disposedBy(disposeBag) - } -} \ No newline at end of file From afeb66382b742e6be9841c27f8891ef7ca4ab838 Mon Sep 17 00:00:00 2001 From: Philip Cohn-Cort Date: Wed, 17 Oct 2018 18:24:19 -0400 Subject: [PATCH 02/14] [Refactor] - AllTours: remove obsolete color-setting code --- .../main/kotlin/edu/artic/tours/AllToursFragment.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/content_listing/src/main/kotlin/edu/artic/tours/AllToursFragment.kt b/content_listing/src/main/kotlin/edu/artic/tours/AllToursFragment.kt index 64e9c79fb..356369cfd 100644 --- a/content_listing/src/main/kotlin/edu/artic/tours/AllToursFragment.kt +++ b/content_listing/src/main/kotlin/edu/artic/tours/AllToursFragment.kt @@ -1,7 +1,6 @@ package edu.artic.tours import android.os.Bundle -import android.support.v4.content.ContextCompat import android.support.v7.widget.GridLayoutManager import android.view.View import com.fuzz.rx.bindToMain @@ -35,11 +34,13 @@ class AllToursFragment : BaseViewModelFragment() { override val title = R.string.tours - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setHasOptionsMenu(true) - requireActivity().window?.statusBarColor = ContextCompat.getColor(requireContext(), R.color.colorPrimary) - } + /** + * The host activity can be trusted to use our preferred color, + * `@color/colorPrimary`, but it might have been told to hide + * the status bar. By returning `true` here we reaffirm that + * color choice. + */ + override val overrideStatusBarColor: Boolean = true override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) From 4fe20f93fe79cee052c299158a8e19d61744fd18 Mon Sep 17 00:00:00 2001 From: Philip Cohn-Cort Date: Thu, 18 Oct 2018 13:26:18 -0400 Subject: [PATCH 03/14] [AllEvents] - Refactor: don't request an options menu, as we won't use it --- .../src/main/kotlin/edu/artic/events/AllEventsFragment.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/content_listing/src/main/kotlin/edu/artic/events/AllEventsFragment.kt b/content_listing/src/main/kotlin/edu/artic/events/AllEventsFragment.kt index 710119622..00c43e661 100644 --- a/content_listing/src/main/kotlin/edu/artic/events/AllEventsFragment.kt +++ b/content_listing/src/main/kotlin/edu/artic/events/AllEventsFragment.kt @@ -33,10 +33,6 @@ class AllEventsFragment : BaseViewModelFragment() { override val title = R.string.events - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setHasOptionsMenu(true) - } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) From ae2884ba922811e3bf105fddab6357f1fe5d65d9 Mon Sep 17 00:00:00 2001 From: Philip Cohn-Cort Date: Thu, 18 Oct 2018 13:41:39 -0400 Subject: [PATCH 04/14] [Documentation] - Welcome: add class-level docs to the 3 `All` fragments --- .../kotlin/edu/artic/events/AllEventsFragment.kt | 9 +++++++++ .../artic/exhibitions/AllExhibitionsFragment.kt | 11 +++++++++++ .../kotlin/edu/artic/tours/AllToursFragment.kt | 14 ++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/content_listing/src/main/kotlin/edu/artic/events/AllEventsFragment.kt b/content_listing/src/main/kotlin/edu/artic/events/AllEventsFragment.kt index 00c43e661..621b578ff 100644 --- a/content_listing/src/main/kotlin/edu/artic/events/AllEventsFragment.kt +++ b/content_listing/src/main/kotlin/edu/artic/events/AllEventsFragment.kt @@ -21,6 +21,15 @@ import io.reactivex.rxkotlin.subscribeBy import kotlinx.android.synthetic.main.fragment_view_all.* import kotlin.reflect.KClass +/** + * This represents the `event` sub-screen of the ':welcome' module. + * + * It shows titles, descriptions, start/end times, and a simple + * promotional picture of each [event][edu.artic.db.models.ArticEvent] + * in a single-column vertical list. + * + * @see AllEventsAdapter + */ class AllEventsFragment : BaseViewModelFragment() { override val screenName: ScreenName diff --git a/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsFragment.kt b/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsFragment.kt index 7310bcf1d..6f46709b2 100644 --- a/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsFragment.kt +++ b/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsFragment.kt @@ -22,6 +22,17 @@ import io.reactivex.rxkotlin.subscribeBy import kotlinx.android.synthetic.main.fragment_view_all.* import kotlin.reflect.KClass +/** + * This represents the `exhibition` sub-screen of the ':welcome' module. + * + * It shows titles, end dates, and a simple promotional picture for + * each [exhibition][edu.artic.db.models.ArticExhibition] in a + * single-column vertical list. + * + * # `Exhibitions` are often displayed under an '`On View`' header. + * + * @see AllExhibitionsAdapter + */ class AllExhibitionsFragment : BaseViewModelFragment() { override val screenName: ScreenName diff --git a/content_listing/src/main/kotlin/edu/artic/tours/AllToursFragment.kt b/content_listing/src/main/kotlin/edu/artic/tours/AllToursFragment.kt index 356369cfd..47ae6b765 100644 --- a/content_listing/src/main/kotlin/edu/artic/tours/AllToursFragment.kt +++ b/content_listing/src/main/kotlin/edu/artic/tours/AllToursFragment.kt @@ -22,6 +22,20 @@ import io.reactivex.rxkotlin.subscribeBy import kotlinx.android.synthetic.main.fragment_view_all.* import kotlin.reflect.KClass +/** + * This represents the `tour` sub-screen of the ':welcome' module. + * + * It shows titles, descriptions, number of tour stops, and other + * essential information about each [tour][edu.artic.db.models.ArticTour] + * in a dual-column vertical grid. At the top of the list is a + * small blurb explaining the connection between tours and audio + * commentaries. + * + * Unlike events and exhibitions, tours may come with translations + * into other languages. + * + * @see AllToursAdapter + */ class AllToursFragment : BaseViewModelFragment() { override val screenName: ScreenName From 9b595eca93b3e892f5713f3caf00b54f3710be48 Mon Sep 17 00:00:00 2001 From: Philip Cohn-Cort Date: Fri, 26 Oct 2018 14:51:47 -0400 Subject: [PATCH 05/14] [ContentListing] - Refactor: rename one of the AllToursItemDecoration.kt files I don't know why this wasn't caught earlier? Must've not been reviewed properly. --- ...{AllToursItemDecoration.kt => AllExhibitionsItemDecoration.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename content_listing/src/main/kotlin/edu/artic/exhibitions/recyclerview/{AllToursItemDecoration.kt => AllExhibitionsItemDecoration.kt} (100%) diff --git a/content_listing/src/main/kotlin/edu/artic/exhibitions/recyclerview/AllToursItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/exhibitions/recyclerview/AllExhibitionsItemDecoration.kt similarity index 100% rename from content_listing/src/main/kotlin/edu/artic/exhibitions/recyclerview/AllToursItemDecoration.kt rename to content_listing/src/main/kotlin/edu/artic/exhibitions/recyclerview/AllExhibitionsItemDecoration.kt From a2f0bb0e67deeb8fd76011cafcf583537507edf5 Mon Sep 17 00:00:00 2001 From: Philip Cohn-Cort Date: Fri, 26 Oct 2018 14:54:46 -0400 Subject: [PATCH 06/14] [ContentListing] - Refactor: move some files to a new, dedicated package --- .../recyclerview => decoration}/AllEventsItemDecoration.kt | 2 +- .../recyclerview => decoration}/AllExhibitionsItemDecoration.kt | 2 +- .../recyclerview => decoration}/AllToursItemDecoration.kt | 2 +- .../src/main/kotlin/edu/artic/events/AllEventsFragment.kt | 2 +- .../main/kotlin/edu/artic/exhibitions/AllExhibitionsFragment.kt | 2 +- .../src/main/kotlin/edu/artic/tours/AllToursFragment.kt | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) rename content_listing/src/main/kotlin/edu/artic/{events/recyclerview => decoration}/AllEventsItemDecoration.kt (98%) rename content_listing/src/main/kotlin/edu/artic/{exhibitions/recyclerview => decoration}/AllExhibitionsItemDecoration.kt (97%) rename content_listing/src/main/kotlin/edu/artic/{tours/recyclerview => decoration}/AllToursItemDecoration.kt (98%) diff --git a/content_listing/src/main/kotlin/edu/artic/events/recyclerview/AllEventsItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllEventsItemDecoration.kt similarity index 98% rename from content_listing/src/main/kotlin/edu/artic/events/recyclerview/AllEventsItemDecoration.kt rename to content_listing/src/main/kotlin/edu/artic/decoration/AllEventsItemDecoration.kt index 6d60ae484..8f40c8e6a 100644 --- a/content_listing/src/main/kotlin/edu/artic/events/recyclerview/AllEventsItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllEventsItemDecoration.kt @@ -1,4 +1,4 @@ -package edu.artic.events.recyclerview +package edu.artic.decoration import android.content.Context import android.graphics.Rect diff --git a/content_listing/src/main/kotlin/edu/artic/exhibitions/recyclerview/AllExhibitionsItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt similarity index 97% rename from content_listing/src/main/kotlin/edu/artic/exhibitions/recyclerview/AllExhibitionsItemDecoration.kt rename to content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt index 99e843477..cc9581a82 100644 --- a/content_listing/src/main/kotlin/edu/artic/exhibitions/recyclerview/AllExhibitionsItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt @@ -1,4 +1,4 @@ -package edu.artic.exhibitions.recyclerview +package edu.artic.decoration import android.content.Context import android.graphics.Rect diff --git a/content_listing/src/main/kotlin/edu/artic/tours/recyclerview/AllToursItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt similarity index 98% rename from content_listing/src/main/kotlin/edu/artic/tours/recyclerview/AllToursItemDecoration.kt rename to content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt index 435b1d588..21207dbea 100644 --- a/content_listing/src/main/kotlin/edu/artic/tours/recyclerview/AllToursItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt @@ -1,4 +1,4 @@ -package edu.artic.tours.recyclerview +package edu.artic.decoration import android.content.Context import android.graphics.Rect diff --git a/content_listing/src/main/kotlin/edu/artic/events/AllEventsFragment.kt b/content_listing/src/main/kotlin/edu/artic/events/AllEventsFragment.kt index 621b578ff..ce581e764 100644 --- a/content_listing/src/main/kotlin/edu/artic/events/AllEventsFragment.kt +++ b/content_listing/src/main/kotlin/edu/artic/events/AllEventsFragment.kt @@ -13,7 +13,7 @@ import edu.artic.adapter.itemClicksWithPosition import edu.artic.analytics.ScreenName import edu.artic.base.utils.asDeepLinkIntent import edu.artic.content.listing.R -import edu.artic.events.recyclerview.AllEventsItemDecoration +import edu.artic.decoration.AllEventsItemDecoration import edu.artic.navigation.NavigationConstants import edu.artic.viewmodel.BaseViewModelFragment import edu.artic.viewmodel.Navigate diff --git a/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsFragment.kt b/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsFragment.kt index 6f46709b2..bac4605ad 100644 --- a/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsFragment.kt +++ b/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsFragment.kt @@ -13,7 +13,7 @@ import edu.artic.adapter.itemClicksWithPosition import edu.artic.analytics.ScreenName import edu.artic.base.utils.asDeepLinkIntent import edu.artic.content.listing.R -import edu.artic.exhibitions.recyclerview.AllExhibitionsItemDecoration +import edu.artic.decoration.AllExhibitionsItemDecoration import edu.artic.navigation.NavigationConstants import edu.artic.viewmodel.BaseViewModelFragment import edu.artic.viewmodel.Navigate diff --git a/content_listing/src/main/kotlin/edu/artic/tours/AllToursFragment.kt b/content_listing/src/main/kotlin/edu/artic/tours/AllToursFragment.kt index 47ae6b765..1efd14469 100644 --- a/content_listing/src/main/kotlin/edu/artic/tours/AllToursFragment.kt +++ b/content_listing/src/main/kotlin/edu/artic/tours/AllToursFragment.kt @@ -14,7 +14,7 @@ import edu.artic.analytics.ScreenName import edu.artic.base.utils.asDeepLinkIntent import edu.artic.content.listing.R import edu.artic.navigation.NavigationConstants -import edu.artic.tours.recyclerview.AllToursItemDecoration +import edu.artic.decoration.AllToursItemDecoration import edu.artic.viewmodel.BaseViewModelFragment import edu.artic.viewmodel.Navigate import io.reactivex.android.schedulers.AndroidSchedulers From 21475c76dc4efb65d42d0208d6cf41c249728057 Mon Sep 17 00:00:00 2001 From: Philip Cohn-Cort Date: Fri, 26 Oct 2018 15:01:35 -0400 Subject: [PATCH 07/14] [ContentListing] - Refactor: remove two minor rounding operations in ATID --- .../kotlin/edu/artic/decoration/AllToursItemDecoration.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt index 21207dbea..73d8539fb 100644 --- a/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt @@ -11,13 +11,13 @@ class AllToursItemDecoration( private val spanCount: Int, private val includeEdge: Boolean = true ) : RecyclerView.ItemDecoration() { - private val horizontalSpacing: Int = context.resources.getDimension(R.dimen.all_tour_cell_spacing_horizontal).toInt() - private val verticalSpacing: Int = context.resources.getDimension(R.dimen.all_tour_cell_spacing_vertical).toInt() + private val horizontalSpacing: Int = context.resources.getDimensionPixelSize(R.dimen.all_tour_cell_spacing_horizontal) + private val verticalSpacing: Int = context.resources.getDimensionPixelSize(R.dimen.all_tour_cell_spacing_vertical) override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { var position = parent.getChildAdapterPosition(view) // item position - if(position <= 0) { - outRect.set(0,0,0,0) + if (position <= 0) { + outRect.set(0, 0, 0, 0) } else { position -= 1 val column = (position) % spanCount // item column From a5cf78cfcf05f289519849bf4d57fb1596193943 Mon Sep 17 00:00:00 2001 From: Philip Cohn-Cort Date: Fri, 26 Oct 2018 15:13:35 -0400 Subject: [PATCH 08/14] [ContentListing] - Refactor: convert two `position` vars into vals With this, all of the local variables in the `decoration` package are immutable. --- .../artic/decoration/AllExhibitionsItemDecoration.kt | 9 ++++----- .../edu/artic/decoration/AllToursItemDecoration.kt | 11 +++++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt index cc9581a82..53d172de8 100644 --- a/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt @@ -15,21 +15,20 @@ class AllExhibitionsItemDecoration( private val verticalSpacing: Int = context.resources.getDimensionPixelSize(R.dimen.all_exhibitions_cell_spacing_vertical) override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { - var position = parent.getChildAdapterPosition(view) // item position - position -= 1 - val column = (position) % spanCount // item column + val adjustedPos = parent.getChildAdapterPosition(view) - 1 // item position, minus 1 for the header + val column = (adjustedPos) % spanCount // item column if (includeEdge) { outRect.left = horizontalSpacing - column * horizontalSpacing / spanCount // spacing - column * ((1f / spanCount) * spacing) outRect.right = (column + 1) * horizontalSpacing / spanCount // (column + 1) * ((1f / spanCount) * spacing) - if (position < spanCount) { // top edge + if (adjustedPos < spanCount) { // top edge outRect.top = verticalSpacing } outRect.bottom = verticalSpacing // item bottom } else { outRect.left = column * horizontalSpacing / spanCount // column * ((1f / spanCount) * spacing) outRect.right = horizontalSpacing - (column + 1) * horizontalSpacing / spanCount // spacing - (column + 1) * ((1f / spanCount) * spacing) - if (position >= spanCount) { + if (adjustedPos >= spanCount) { outRect.top = verticalSpacing // item top } } diff --git a/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt index 73d8539fb..b138ac01a 100644 --- a/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt @@ -15,24 +15,23 @@ class AllToursItemDecoration( private val verticalSpacing: Int = context.resources.getDimensionPixelSize(R.dimen.all_tour_cell_spacing_vertical) override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { - var position = parent.getChildAdapterPosition(view) // item position - if (position <= 0) { + val adjustedPos = parent.getChildAdapterPosition(view) - 1 // item position, minus 1 for the header + if (adjustedPos < 0) { outRect.set(0, 0, 0, 0) } else { - position -= 1 - val column = (position) % spanCount // item column + val column = (adjustedPos) % spanCount // item column if (includeEdge) { outRect.left = horizontalSpacing - column * horizontalSpacing / spanCount // spacing - column * ((1f / spanCount) * spacing) outRect.right = (column + 1) * horizontalSpacing / spanCount // (column + 1) * ((1f / spanCount) * spacing) - if (position < spanCount) { // top edge + if (adjustedPos < spanCount) { // top edge outRect.top = verticalSpacing } outRect.bottom = verticalSpacing // item bottom } else { outRect.left = column * horizontalSpacing / spanCount // column * ((1f / spanCount) * spacing) outRect.right = horizontalSpacing - (column + 1) * horizontalSpacing / spanCount // spacing - (column + 1) * ((1f / spanCount) * spacing) - if (position >= spanCount) { + if (adjustedPos >= spanCount) { outRect.top = verticalSpacing // item top } } From c9cf5dea0a88a1b2c2fe23b1ffaa6c4ebb100ff8 Mon Sep 17 00:00:00 2001 From: Philip Cohn-Cort Date: Fri, 26 Oct 2018 15:28:08 -0400 Subject: [PATCH 09/14] [ContentListing] - Documentation: actually attribute those files to the author --- .../decoration/AllEventsItemDecoration.kt | 5 +++++ .../AllExhibitionsItemDecoration.kt | 5 +++++ .../decoration/AllToursItemDecoration.kt | 5 +++++ .../kotlin/edu/artic/decoration/LICENSE.md | 19 +++++++++++++++++++ 4 files changed, 34 insertions(+) create mode 100644 content_listing/src/main/kotlin/edu/artic/decoration/LICENSE.md diff --git a/content_listing/src/main/kotlin/edu/artic/decoration/AllEventsItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllEventsItemDecoration.kt index 8f40c8e6a..13430b5b1 100644 --- a/content_listing/src/main/kotlin/edu/artic/decoration/AllEventsItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllEventsItemDecoration.kt @@ -9,6 +9,11 @@ import edu.artic.events.AllEventsAdapter import edu.artic.events.AllEventsCellHeaderViewModel import edu.artic.events.EventCellViewModel +/** + * The original version of this file was written by + * [edwardaa](https://stackoverflow.com/users/3414249/edwardaa) for + * [https://stackoverflow.com/a/30701422](https://stackoverflow.com/a/30701422). + */ class AllEventsItemDecoration( context: Context, private val spanCount: Int, diff --git a/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt index 53d172de8..59567cb07 100644 --- a/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt @@ -6,6 +6,11 @@ import android.support.v7.widget.RecyclerView import android.view.View import edu.artic.content.listing.R +/** + * The original version of this file was written by + * [edwardaa](https://stackoverflow.com/users/3414249/edwardaa) for + * [https://stackoverflow.com/a/30701422](https://stackoverflow.com/a/30701422). + */ class AllExhibitionsItemDecoration( context: Context, private val spanCount: Int, diff --git a/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt index b138ac01a..1c903e1d0 100644 --- a/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt @@ -6,6 +6,11 @@ import android.support.v7.widget.RecyclerView import android.view.View import edu.artic.content.listing.R +/** + * The original version of this file was written by + * [edwardaa](https://stackoverflow.com/users/3414249/edwardaa) for + * [https://stackoverflow.com/a/30701422](https://stackoverflow.com/a/30701422). + */ class AllToursItemDecoration( context: Context, private val spanCount: Int, diff --git a/content_listing/src/main/kotlin/edu/artic/decoration/LICENSE.md b/content_listing/src/main/kotlin/edu/artic/decoration/LICENSE.md new file mode 100644 index 000000000..239de568c --- /dev/null +++ b/content_listing/src/main/kotlin/edu/artic/decoration/LICENSE.md @@ -0,0 +1,19 @@ +These 'ItemDecoration' files were originally copied, without attribution, +from https://stackoverflow.com/a/30701422. By adding this file, we +restore that license: the CC BY-SA 3.0. The original author of this +`GridSpacingItemDecoration` code is +[edwardaa](https://stackoverflow.com/users/3414249/edwardaa). + +This directory is licensed under the Creative Commons +Attribution-ShareAlike 3.0 United States License. To view a copy of this +license, visit http://creativecommons.org/licenses/by-sa/3.0/us/ or send +a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. + + + +All subsequent modifications to this directory within the Art Institute +of Chicago codebase are released under a dual license, specified below. + +You may choose to use this code under the terms of either the AGPL v3 +(provided in the top-level `LICENSE` file) or under the terms of the +aforementioned Creative Commons License. \ No newline at end of file From f6bbd7e31a9f5c003d6f4dff441f3492df6091e4 Mon Sep 17 00:00:00 2001 From: Philip Cohn-Cort Date: Fri, 26 Oct 2018 15:30:15 -0400 Subject: [PATCH 10/14] [ContentListing] - Refactor: inline safe assumptions about the decoration code --- .../AllExhibitionsItemDecoration.kt | 22 ++++++------------- .../decoration/AllToursItemDecoration.kt | 22 ++++++------------- 2 files changed, 14 insertions(+), 30 deletions(-) diff --git a/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt index 59567cb07..72b836c79 100644 --- a/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt @@ -13,8 +13,7 @@ import edu.artic.content.listing.R */ class AllExhibitionsItemDecoration( context: Context, - private val spanCount: Int, - private val includeEdge: Boolean = true + private val spanCount: Int ) : RecyclerView.ItemDecoration() { private val horizontalSpacing: Int = context.resources.getDimensionPixelSize(R.dimen.all_exhibitions_cell_spacing_horizontal) private val verticalSpacing: Int = context.resources.getDimensionPixelSize(R.dimen.all_exhibitions_cell_spacing_vertical) @@ -22,21 +21,14 @@ class AllExhibitionsItemDecoration( override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { val adjustedPos = parent.getChildAdapterPosition(view) - 1 // item position, minus 1 for the header val column = (adjustedPos) % spanCount // item column - if (includeEdge) { - outRect.left = horizontalSpacing - column * horizontalSpacing / spanCount // spacing - column * ((1f / spanCount) * spacing) - outRect.right = (column + 1) * horizontalSpacing / spanCount // (column + 1) * ((1f / spanCount) * spacing) - if (adjustedPos < spanCount) { // top edge - outRect.top = verticalSpacing - } - outRect.bottom = verticalSpacing // item bottom - } else { - outRect.left = column * horizontalSpacing / spanCount // column * ((1f / spanCount) * spacing) - outRect.right = horizontalSpacing - (column + 1) * horizontalSpacing / spanCount // spacing - (column + 1) * ((1f / spanCount) * spacing) - if (adjustedPos >= spanCount) { - outRect.top = verticalSpacing // item top - } + outRect.left = horizontalSpacing - column * horizontalSpacing / spanCount // spacing - column * ((1f / spanCount) * spacing) + outRect.right = (column + 1) * horizontalSpacing / spanCount // (column + 1) * ((1f / spanCount) * spacing) + + if (adjustedPos < spanCount) { // top edge + outRect.top = verticalSpacing } + outRect.bottom = verticalSpacing // item bottom } } \ No newline at end of file diff --git a/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt index 1c903e1d0..44a7a7af1 100644 --- a/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt @@ -13,8 +13,7 @@ import edu.artic.content.listing.R */ class AllToursItemDecoration( context: Context, - private val spanCount: Int, - private val includeEdge: Boolean = true + private val spanCount: Int ) : RecyclerView.ItemDecoration() { private val horizontalSpacing: Int = context.resources.getDimensionPixelSize(R.dimen.all_tour_cell_spacing_horizontal) private val verticalSpacing: Int = context.resources.getDimensionPixelSize(R.dimen.all_tour_cell_spacing_vertical) @@ -25,21 +24,14 @@ class AllToursItemDecoration( outRect.set(0, 0, 0, 0) } else { val column = (adjustedPos) % spanCount // item column - if (includeEdge) { - outRect.left = horizontalSpacing - column * horizontalSpacing / spanCount // spacing - column * ((1f / spanCount) * spacing) - outRect.right = (column + 1) * horizontalSpacing / spanCount // (column + 1) * ((1f / spanCount) * spacing) - if (adjustedPos < spanCount) { // top edge - outRect.top = verticalSpacing - } - outRect.bottom = verticalSpacing // item bottom - } else { - outRect.left = column * horizontalSpacing / spanCount // column * ((1f / spanCount) * spacing) - outRect.right = horizontalSpacing - (column + 1) * horizontalSpacing / spanCount // spacing - (column + 1) * ((1f / spanCount) * spacing) - if (adjustedPos >= spanCount) { - outRect.top = verticalSpacing // item top - } + outRect.left = horizontalSpacing - column * horizontalSpacing / spanCount // spacing - column * ((1f / spanCount) * spacing) + outRect.right = (column + 1) * horizontalSpacing / spanCount // (column + 1) * ((1f / spanCount) * spacing) + + if (adjustedPos < spanCount) { // top edge + outRect.top = verticalSpacing } + outRect.bottom = verticalSpacing // item bottom } } From 69664c91280d734e42ee5f700aeee1363dec9f59 Mon Sep 17 00:00:00 2001 From: Philip Cohn-Cort Date: Fri, 26 Oct 2018 15:33:28 -0400 Subject: [PATCH 11/14] [Refactor] - Use prebuilt `Rect::setEmpty` instead of `Rect::set(0,0,0,0)` --- .../main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt | 2 +- .../main/java/edu/artic/search/SearchDividerItemDecoration.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt index 44a7a7af1..be904c973 100644 --- a/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt @@ -21,7 +21,7 @@ class AllToursItemDecoration( override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { val adjustedPos = parent.getChildAdapterPosition(view) - 1 // item position, minus 1 for the header if (adjustedPos < 0) { - outRect.set(0, 0, 0, 0) + outRect.setEmpty() } else { val column = (adjustedPos) % spanCount // item column diff --git a/search/src/main/java/edu/artic/search/SearchDividerItemDecoration.kt b/search/src/main/java/edu/artic/search/SearchDividerItemDecoration.kt index 4f057dead..fef2c3cbd 100644 --- a/search/src/main/java/edu/artic/search/SearchDividerItemDecoration.kt +++ b/search/src/main/java/edu/artic/search/SearchDividerItemDecoration.kt @@ -58,7 +58,7 @@ class SearchDividerItemDecoration(context: Context) : RecyclerView.ItemDecoratio } else if ((it is SearchBaseListItemViewModel || it.hasDivider) && (position < adapter.itemCount - 1 )) { outRect.set(0, 0, 0, mDividerHeight) } else { - outRect.set(0, 0, 0, 0) + outRect.setEmpty() } } } From dd1ae24dc8c95feb634fa5bee43b2b7ebad07fd1 Mon Sep 17 00:00:00 2001 From: Philip Cohn-Cort Date: Sun, 28 Oct 2018 02:03:43 -0400 Subject: [PATCH 12/14] [ContentListing] - Create new base class for the three decorations --- .../artic/decoration/GridItemDecoration.kt | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 content_listing/src/main/kotlin/edu/artic/decoration/GridItemDecoration.kt diff --git a/content_listing/src/main/kotlin/edu/artic/decoration/GridItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/GridItemDecoration.kt new file mode 100644 index 000000000..5706b5a0b --- /dev/null +++ b/content_listing/src/main/kotlin/edu/artic/decoration/GridItemDecoration.kt @@ -0,0 +1,76 @@ +package edu.artic.decoration + +import android.content.res.Resources +import android.graphics.Rect +import android.support.annotation.CallSuper +import android.support.v7.widget.RecyclerView +import android.view.View + +/** + * Simple ItemDecoration that keeps track of useful [Dimensions]. + * + * This makes it straightforward to load the best values in the current + * [Resources] - just + * 1. implement [createDimensions] + * 2. call `super.getItemOffsets(outRect, view, parent, state)` at the start of + * your override of [getItemOffsets] + * 3. use [dimensions] in the rest of [getItemOffsets] as needed + * + * @author Philip Cohn-Cort (Fuzz) + */ +abstract class GridItemDecoration(protected open val spanCount: Int = 1) : RecyclerView.ItemDecoration() { + + /** + * Use this to simplify implementations of [getItemOffsets] and [onDrawOver] (where applicable). + * + * Implementors are free to interpret these values as they see fit, but we've + * attached some recommended usage in the below docs. + */ + protected interface Dimensions { + /** + * Preferred vertical offset, in pixels. + */ + val vertical : Int + /** + * Preferred horizontal offset, in pixels. + */ + val horizontal : Int + /** + * Preferred vertical offset for the first item or row of items in the [RecyclerView]. + */ + val topMostVertical : Int + + /** + * Convenience function for subclasses which wish to use [vertical] for + * both top and bottom margins. + */ + fun halfOfVertical() : Int = (vertical / 2.0f).toInt() + } + + /** + * Access the singleton created in [createDimensions]. + */ + protected lateinit var dimensions: Dimensions + + protected abstract fun createDimensions(res: Resources) : Dimensions + + /** + * Represents information about whether [dimensions] has a value yet. + */ + private fun needsDimensions(): Boolean { + return !this::dimensions.isInitialized + } + + /** + * Initialize [dimensions] by calling [createDimensions], if appropriate. + * + * See [here][RecyclerView.ItemDecoration.getItemOffsets] for more details about + * what to add to overrides of this function. + */ + @CallSuper + override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { + if (needsDimensions()) { + dimensions = createDimensions(view.resources) + } + } +} \ No newline at end of file From 7bc88505afe9ed3c8ed54c1aa2b3e49eb5420d51 Mon Sep 17 00:00:00 2001 From: Philip Cohn-Cort Date: Sun, 28 Oct 2018 02:13:48 -0400 Subject: [PATCH 13/14] [ContentListing] - Use that new class to late-initialize dimensions --- .../decoration/AllEventsItemDecoration.kt | 24 ++++++++++++++----- .../AllExhibitionsItemDecoration.kt | 20 ++++++++++++---- .../decoration/AllToursItemDecoration.kt | 20 ++++++++++++---- 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/content_listing/src/main/kotlin/edu/artic/decoration/AllEventsItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllEventsItemDecoration.kt index 13430b5b1..3421e4493 100644 --- a/content_listing/src/main/kotlin/edu/artic/decoration/AllEventsItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllEventsItemDecoration.kt @@ -1,6 +1,7 @@ package edu.artic.decoration import android.content.Context +import android.content.res.Resources import android.graphics.Rect import android.support.v7.widget.RecyclerView import android.view.View @@ -16,19 +17,30 @@ import edu.artic.events.EventCellViewModel */ class AllEventsItemDecoration( context: Context, - private val spanCount: Int, + override val spanCount: Int, private val adapter: AllEventsAdapter -) : RecyclerView.ItemDecoration() { - private val horizontalSpacing: Int = context.resources.getDimensionPixelOffset(R.dimen.all_tour_cell_spacing_horizontal) - private val verticalSpacing: Int = context.resources.getDimensionPixelOffset(R.dimen.all_tour_cell_spacing_vertical) - private val headerVerticalSpacing: Int = context.resources.getDimensionPixelOffset(R.dimen.all_tour_cell_spacing_vertical_header) +) : GridItemDecoration(spanCount) { + + override fun createDimensions(res: Resources): Dimensions { + return object : Dimensions { + override val horizontal: Int = res.getDimensionPixelOffset(R.dimen.all_tour_cell_spacing_horizontal) + override val vertical: Int = res.getDimensionPixelOffset(R.dimen.all_tour_cell_spacing_vertical) + override val topMostVertical: Int = res.getDimensionPixelOffset(R.dimen.all_tour_cell_spacing_vertical_header) + } + } override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { + super.getItemOffsets(outRect, view, parent, state) + + val horizontalSpacing = dimensions.horizontal + val verticalSpacing = dimensions.vertical + val headerVerticalSpacing = dimensions.topMostVertical + // item position val position = parent.getChildAdapterPosition(view) adapter.getItemOrNull(position)?.let { - val halfOfVertical = (verticalSpacing / 2.0f).toInt() + val halfOfVertical = dimensions.halfOfVertical() when (it) { is AllEventsCellHeaderViewModel -> { diff --git a/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt index 72b836c79..a5596b814 100644 --- a/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt @@ -1,6 +1,7 @@ package edu.artic.decoration import android.content.Context +import android.content.res.Resources import android.graphics.Rect import android.support.v7.widget.RecyclerView import android.view.View @@ -13,12 +14,23 @@ import edu.artic.content.listing.R */ class AllExhibitionsItemDecoration( context: Context, - private val spanCount: Int -) : RecyclerView.ItemDecoration() { - private val horizontalSpacing: Int = context.resources.getDimensionPixelSize(R.dimen.all_exhibitions_cell_spacing_horizontal) - private val verticalSpacing: Int = context.resources.getDimensionPixelSize(R.dimen.all_exhibitions_cell_spacing_vertical) + override val spanCount: Int +) : GridItemDecoration(spanCount) { + + override fun createDimensions(res: Resources): Dimensions { + return object : Dimensions { + override val horizontal: Int = res.getDimensionPixelSize(R.dimen.all_exhibitions_cell_spacing_horizontal) + override val vertical: Int = res.getDimensionPixelSize(R.dimen.all_exhibitions_cell_spacing_vertical) + override val topMostVertical: Int = vertical + } + } override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { + super.getItemOffsets(outRect, view, parent, state) + + val horizontalSpacing = dimensions.horizontal + val verticalSpacing = dimensions.vertical + val adjustedPos = parent.getChildAdapterPosition(view) - 1 // item position, minus 1 for the header val column = (adjustedPos) % spanCount // item column diff --git a/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt index be904c973..9b7b6240f 100644 --- a/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt @@ -1,6 +1,7 @@ package edu.artic.decoration import android.content.Context +import android.content.res.Resources import android.graphics.Rect import android.support.v7.widget.RecyclerView import android.view.View @@ -13,12 +14,23 @@ import edu.artic.content.listing.R */ class AllToursItemDecoration( context: Context, - private val spanCount: Int -) : RecyclerView.ItemDecoration() { - private val horizontalSpacing: Int = context.resources.getDimensionPixelSize(R.dimen.all_tour_cell_spacing_horizontal) - private val verticalSpacing: Int = context.resources.getDimensionPixelSize(R.dimen.all_tour_cell_spacing_vertical) + override val spanCount: Int +) : GridItemDecoration(spanCount) { + + override fun createDimensions(res: Resources): Dimensions { + return object : Dimensions { + override val horizontal: Int = res.getDimensionPixelSize(R.dimen.all_tour_cell_spacing_horizontal) + override val vertical: Int = res.getDimensionPixelSize(R.dimen.all_tour_cell_spacing_vertical) + override val topMostVertical: Int = vertical + } + } override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { + super.getItemOffsets(outRect, view, parent, state) + + val horizontalSpacing = dimensions.horizontal + val verticalSpacing = dimensions.vertical + val adjustedPos = parent.getChildAdapterPosition(view) - 1 // item position, minus 1 for the header if (adjustedPos < 0) { outRect.setEmpty() From e4eead8c37d202911fac798c74d448b7fcc5a991 Mon Sep 17 00:00:00 2001 From: Philip Cohn-Cort Date: Sun, 28 Oct 2018 14:56:33 -0400 Subject: [PATCH 14/14] [ContentListing] - Remove now-unneccessary constructor parameter --- .../main/kotlin/edu/artic/decoration/AllEventsItemDecoration.kt | 2 -- .../kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt | 2 -- .../main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt | 2 -- .../src/main/kotlin/edu/artic/events/AllEventsFragment.kt | 2 +- .../main/kotlin/edu/artic/exhibitions/AllExhibitionsFragment.kt | 2 +- .../src/main/kotlin/edu/artic/tours/AllToursFragment.kt | 2 +- 6 files changed, 3 insertions(+), 9 deletions(-) diff --git a/content_listing/src/main/kotlin/edu/artic/decoration/AllEventsItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllEventsItemDecoration.kt index 3421e4493..570f1a898 100644 --- a/content_listing/src/main/kotlin/edu/artic/decoration/AllEventsItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllEventsItemDecoration.kt @@ -1,6 +1,5 @@ package edu.artic.decoration -import android.content.Context import android.content.res.Resources import android.graphics.Rect import android.support.v7.widget.RecyclerView @@ -16,7 +15,6 @@ import edu.artic.events.EventCellViewModel * [https://stackoverflow.com/a/30701422](https://stackoverflow.com/a/30701422). */ class AllEventsItemDecoration( - context: Context, override val spanCount: Int, private val adapter: AllEventsAdapter ) : GridItemDecoration(spanCount) { diff --git a/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt index a5596b814..eda831811 100644 --- a/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllExhibitionsItemDecoration.kt @@ -1,6 +1,5 @@ package edu.artic.decoration -import android.content.Context import android.content.res.Resources import android.graphics.Rect import android.support.v7.widget.RecyclerView @@ -13,7 +12,6 @@ import edu.artic.content.listing.R * [https://stackoverflow.com/a/30701422](https://stackoverflow.com/a/30701422). */ class AllExhibitionsItemDecoration( - context: Context, override val spanCount: Int ) : GridItemDecoration(spanCount) { diff --git a/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt b/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt index 9b7b6240f..1fbc60f2a 100644 --- a/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt +++ b/content_listing/src/main/kotlin/edu/artic/decoration/AllToursItemDecoration.kt @@ -1,6 +1,5 @@ package edu.artic.decoration -import android.content.Context import android.content.res.Resources import android.graphics.Rect import android.support.v7.widget.RecyclerView @@ -13,7 +12,6 @@ import edu.artic.content.listing.R * [https://stackoverflow.com/a/30701422](https://stackoverflow.com/a/30701422). */ class AllToursItemDecoration( - context: Context, override val spanCount: Int ) : GridItemDecoration(spanCount) { diff --git a/content_listing/src/main/kotlin/edu/artic/events/AllEventsFragment.kt b/content_listing/src/main/kotlin/edu/artic/events/AllEventsFragment.kt index ce581e764..4150ecd4d 100644 --- a/content_listing/src/main/kotlin/edu/artic/events/AllEventsFragment.kt +++ b/content_listing/src/main/kotlin/edu/artic/events/AllEventsFragment.kt @@ -66,7 +66,7 @@ class AllEventsFragment : BaseViewModelFragment() { } recyclerView.layoutManager = layoutManager recyclerView.adapter = eventsAdapter - recyclerView.addItemDecoration(AllEventsItemDecoration(view.context, 2, eventsAdapter)) + recyclerView.addItemDecoration(AllEventsItemDecoration(2, eventsAdapter)) } override fun setupBindings(viewModel: AllEventsViewModel) { diff --git a/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsFragment.kt b/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsFragment.kt index bac4605ad..7fbcb55c5 100644 --- a/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsFragment.kt +++ b/content_listing/src/main/kotlin/edu/artic/exhibitions/AllExhibitionsFragment.kt @@ -53,7 +53,7 @@ class AllExhibitionsFragment : BaseViewModelFragment() recyclerView.layoutManager = layoutManager val exhibitionsAdapter = AllExhibitionsAdapter() recyclerView.adapter = exhibitionsAdapter - recyclerView.addItemDecoration(AllExhibitionsItemDecoration(view.context, 1)) + recyclerView.addItemDecoration(AllExhibitionsItemDecoration(1)) } diff --git a/content_listing/src/main/kotlin/edu/artic/tours/AllToursFragment.kt b/content_listing/src/main/kotlin/edu/artic/tours/AllToursFragment.kt index 1efd14469..35078a8ab 100644 --- a/content_listing/src/main/kotlin/edu/artic/tours/AllToursFragment.kt +++ b/content_listing/src/main/kotlin/edu/artic/tours/AllToursFragment.kt @@ -76,7 +76,7 @@ class AllToursFragment : BaseViewModelFragment() { recyclerView.layoutManager = layoutManager val toursAdapter = AllToursAdapter(recyclerView, viewModel.intro, viewModel.viewDisposeBag) recyclerView.adapter = toursAdapter - recyclerView.addItemDecoration(AllToursItemDecoration(view.context, 2)) + recyclerView.addItemDecoration(AllToursItemDecoration(2)) /* Ensure search events go through ok. */ searchIcon