Skip to content

Commit

Permalink
Move logic from HomeActivity to ViewModel:
Browse files Browse the repository at this point in the history
* Handling of the removal/deactivation of a source
* Requesting data loading at every activity onCreate - moved to init of the ViewModel
  • Loading branch information
florina-muntenescu authored and nickbutcher committed Mar 12, 2019
1 parent a2603c5 commit 1f5bd44
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 48 deletions.
31 changes: 5 additions & 26 deletions app/src/main/java/io/plaidapp/ui/HomeActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@
import io.plaidapp.core.designernews.data.poststory.PostStoryService;
import io.plaidapp.core.designernews.data.stories.model.Story;
import io.plaidapp.core.dribbble.data.api.model.Shot;
import io.plaidapp.core.ui.ConnectivityChecker;
import io.plaidapp.core.feed.FeedAdapter;
import io.plaidapp.core.ui.ConnectivityChecker;
import io.plaidapp.core.ui.HomeGridItemAnimator;
import io.plaidapp.core.ui.PlaidItemsList;
import io.plaidapp.core.ui.filter.FilterAdapter;
Expand All @@ -85,10 +85,8 @@
import io.plaidapp.core.util.DrawableUtils;
import io.plaidapp.core.util.ShortcutHelper;
import io.plaidapp.core.util.ViewUtils;
import io.plaidapp.core.util.event.EventObserver;
import io.plaidapp.ui.recyclerview.FilterTouchHelperCallback;
import io.plaidapp.ui.recyclerview.GridItemDividerDecoration;
import kotlin.Unit;

import javax.inject.Inject;
import java.util.Collections;
Expand Down Expand Up @@ -163,10 +161,6 @@ protected void onCreate(Bundle savedInstanceState) {
}
}
});
viewModel.getSourceRemoved().observe(this, source -> {
handleDataSourceRemoved(source);
checkEmptyState();
});

viewModel.getFeedProgress().observe(this, feedProgressUiModel -> {
if(feedProgressUiModel.isLoading()){
Expand All @@ -176,13 +170,10 @@ protected void onCreate(Bundle savedInstanceState) {
}
});

viewModel.getFeed().observe(this, new EventObserver<>(feedUiModel -> {
List<PlaidItem> items = PlaidItemsList.getPlaidItemsForDisplay(adapter.getItems(), feedUiModel.getItems(), columns);
adapter.setItems(items);
viewModel.getFeed().observe(this, feedUiModel -> {
adapter.setItems(feedUiModel.getItems());
checkEmptyState();
return Unit.INSTANCE;
}));

});

drawer.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
Expand All @@ -207,8 +198,6 @@ protected void onCreate(Bundle savedInstanceState) {
filtersList.setAdapter(filtersAdapter);
filtersList.setItemAnimator(new FilterAnimator());

viewModel.loadData();

ItemTouchHelper.Callback callback = new FilterTouchHelperCallback(filtersAdapter, this);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
itemTouchHelper.attachToRecyclerView(filtersList);
Expand Down Expand Up @@ -462,17 +451,7 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
}
};

private void handleDataSourceRemoved(String dataSourceKey){
List<PlaidItem> items = adapter.getItems();
for (int i = items.size() - 1; i >= 0; i--) {
PlaidItem item = items.get(i);
if (dataSourceKey.equals(item.getDataSource())) {
items.remove(i);
}
}
PlaidItemsList.expandPopularItems(items, columns);
adapter.setItems(items);
}


protected void fabClick() {
if (viewModel.isDesignerNewsUserLoggedIn()) {
Expand Down
33 changes: 23 additions & 10 deletions app/src/main/java/io/plaidapp/ui/HomeViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ import io.plaidapp.core.data.prefs.SourcesRepository
import io.plaidapp.core.designernews.data.login.LoginRepository
import io.plaidapp.core.feed.FeedProgressUiModel
import io.plaidapp.core.feed.FeedUiModel
import io.plaidapp.core.ui.expandPopularItems
import io.plaidapp.core.ui.filter.FiltersChangedCallback
import io.plaidapp.core.ui.filter.SourceUiModel
import io.plaidapp.core.ui.filter.SourcesHighlightUiModel
import io.plaidapp.core.ui.filter.SourcesUiModel
import io.plaidapp.core.ui.getPlaidItemsForDisplay
import io.plaidapp.core.util.event.Event
import kotlinx.coroutines.launch
import java.util.Collections
Expand All @@ -51,11 +53,6 @@ class HomeViewModel(
private val dispatcherProvider: CoroutinesDispatcherProvider
) : ViewModel() {

// TODO keeping this one temporarily, until we deal with [FeedAdapter]
private val _sourceRemoved = MutableLiveData<String>()
val sourceRemoved: LiveData<String>
get() = _sourceRemoved

private val _sources = MutableLiveData<SourcesUiModel>()
val sources: LiveData<SourcesUiModel>
get() = _sources
Expand All @@ -64,26 +61,27 @@ class HomeViewModel(
val feedProgress: LiveData<FeedProgressUiModel>
get() = _feedProgress

private val _feed = MutableLiveData<Event<FeedUiModel>>()
val feed: LiveData<Event<FeedUiModel>>
private val _feed = MutableLiveData<FeedUiModel>()
val feed: LiveData<FeedUiModel>
get() = _feed

private val onDataLoadedCallback: OnDataLoadedCallback<List<PlaidItem>> =
object : OnDataLoadedCallback<List<PlaidItem>> {
override fun onDataLoaded(data: List<PlaidItem>) {
_feed.value = Event(FeedUiModel(data))
val oldItems = _feed.value?.items.orEmpty()
updateFeedData(oldItems, data)
}
}
// listener for notifying adapter when data sources are deactivated
private val filtersChangedCallbacks = object : FiltersChangedCallback() {
override fun onFiltersChanged(changedFilter: Source) {
if (!changedFilter.active) {
_sourceRemoved.value = changedFilter.key
handleDataSourceRemoved(changedFilter.key, _feed.value?.items.orEmpty())
}
}

override fun onFilterRemoved(sourceKey: String) {
_sourceRemoved.value = sourceKey
handleDataSourceRemoved(sourceKey, _feed.value?.items.orEmpty())
}

override fun onFiltersUpdated(sources: List<Source>) {
Expand All @@ -106,6 +104,7 @@ class HomeViewModel(
dataManager.setOnDataLoadedCallback(onDataLoadedCallback)
dataManager.registerCallback(dataLoadingCallbacks)
getSources()
loadData()
}

fun isDesignerNewsUserLoggedIn() = designerNewsLoginRepository.isLoggedIn
Expand Down Expand Up @@ -195,6 +194,20 @@ class HomeViewModel(
}
}

private fun updateFeedData(oldItems: List<PlaidItem>, newItems: List<PlaidItem>) {
val items = getPlaidItemsForDisplay(oldItems, newItems, 2)
_feed.value = FeedUiModel(items)
}

private fun handleDataSourceRemoved(dataSourceKey: String, oldItems: List<PlaidItem>) {
val items = oldItems.toMutableList()
items.removeAll {
dataSourceKey == it.dataSource
}
expandPopularItems(items, 2)
_feed.value = FeedUiModel(items)
}

private fun createNewSourceUiModels(sources: List<Source>): List<SourceUiModel> {
val mutableSources = sources.toMutableList()
Collections.sort(mutableSources, Source.SourceComparator())
Expand Down
33 changes: 21 additions & 12 deletions app/src/test/java/io/plaidapp/ui/HomeViewModelTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ class HomeViewModelTest {
{}
)
private val dribbbleSource = Source.DribbbleSearchSource("dribbble", true)
private val dribbbleSourceUiModel = SourceUiModel(
dribbbleSource.key,
dribbbleSource.name,
dribbbleSource.active,
dribbbleSource.iconRes,
dribbbleSource.isSwipeDismissable,
{},
{}
)
private val dataManager: DataManager = mock()
private val loginRepository: LoginRepository = mock()
private val sourcesRepository: SourcesRepository = mock()
Expand Down Expand Up @@ -260,23 +269,23 @@ class HomeViewModelTest {
@Test
fun filtersRemoved() {
// Given a view model
val homeViewModel = createViewModel()
val homeViewModel = createViewModel(listOf(designerNewsSource, dribbbleSource))
verify(sourcesRepository).registerFilterChangedCallback(
capture(filtersChangedCallback)
)

// When a source was removed
filtersChangedCallback.value.onFilterRemoved(designerNewsSource.key)
filtersChangedCallback.value.onFilterRemoved(dribbbleSource.key)

// Then source removed value is the expected one
val source = LiveDataTestUtil.getValue(homeViewModel.sourceRemoved)
assertEquals(designerNewsSource.key, source)
// Then feed emits with a new list, without the removed filter
val feed = LiveDataTestUtil.getValue(homeViewModel.feed)
assertEquals(listOf(designerNewsSourceUiModel), feed)
}

@Test
fun filtersChanged_activeSource() {
// Given a view model
val homeViewModel = createViewModel()
val homeViewModel = createViewModel(listOf(designerNewsSource, dribbbleSource))
verify(sourcesRepository).registerFilterChangedCallback(
capture(filtersChangedCallback)
)
Expand All @@ -285,15 +294,15 @@ class HomeViewModelTest {
val activeSource = Source.DribbbleSearchSource("dribbble", true)
filtersChangedCallback.value.onFiltersChanged(activeSource)

// Then source removed value is null
val source = LiveDataTestUtil.getValue(homeViewModel.sourceRemoved)
// Then feed didn't emit a new value
val source = LiveDataTestUtil.getValue(homeViewModel.feed)
assertNull(source)
}

@Test
fun filtersChanged_inactiveSource() {
// Given a view model
val homeViewModel = createViewModel()
val homeViewModel = createViewModel(listOf(designerNewsSource, dribbbleSource))
verify(sourcesRepository).registerFilterChangedCallback(
capture(filtersChangedCallback)
)
Expand All @@ -302,9 +311,9 @@ class HomeViewModelTest {
val inactiveSource = Source.DribbbleSearchSource("dribbble", false)
filtersChangedCallback.value.onFiltersChanged(inactiveSource)

// Then the source removed contains the inactive source
val source = LiveDataTestUtil.getValue(homeViewModel.sourceRemoved)
assertEquals(inactiveSource.key, source)
// Then feed emits with a new list, without the removed filter
val feed = LiveDataTestUtil.getValue(homeViewModel.feed)
assertEquals(listOf(designerNewsSourceUiModel), feed)
}

@Test
Expand Down

0 comments on commit 1f5bd44

Please sign in to comment.