Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
import org.wordpress.android.ui.notifications.receivers.NotificationsPendingDraftsReceiver;
import org.wordpress.android.ui.pages.PageListFragment;
import org.wordpress.android.ui.pages.PageParentFragment;
import org.wordpress.android.ui.pages.PageParentSearchFragment;
import org.wordpress.android.ui.pages.PagesFragment;
import org.wordpress.android.ui.pages.SearchListFragment;
import org.wordpress.android.ui.people.PeopleInviteFragment;
Expand Down Expand Up @@ -490,6 +491,8 @@ public interface AppComponent extends AndroidInjector<WordPress> {

void inject(AddContentAdapter object);

void inject(PageParentSearchFragment object);

// Allows us to inject the application without having to instantiate any modules, and provides the Application
// in the app graph
@Component.Builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.wordpress.android.viewmodel.history.HistoryViewModel;
import org.wordpress.android.viewmodel.main.WPMainActivityViewModel;
import org.wordpress.android.viewmodel.pages.PageListViewModel;
import org.wordpress.android.viewmodel.pages.PageParentSearchViewModel;
import org.wordpress.android.viewmodel.pages.PageParentViewModel;
import org.wordpress.android.viewmodel.pages.PagesViewModel;
import org.wordpress.android.viewmodel.pages.SearchListViewModel;
Expand Down Expand Up @@ -282,6 +283,11 @@ abstract class ViewModelModule {
@ViewModelKey(PostSignupInterstitialViewModel.class)
abstract ViewModel postSignupInterstitialViewModel(PostSignupInterstitialViewModel viewModel);

@Binds
@IntoMap
@ViewModelKey(PageParentSearchViewModel.class)
abstract ViewModel pageParentSearchViewModel(PageParentSearchViewModel viewModel);

@Binds
abstract ViewModelProvider.Factory provideViewModelFactory(ViewModelFactory viewModelFactory);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,20 @@ import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.MenuItem.OnActionExpandListener
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.pages_list_fragment.*
import kotlinx.android.synthetic.main.page_parent_fragment.*
import kotlinx.android.synthetic.main.pages_list_fragment.recyclerView
import kotlinx.coroutines.CoroutineScope
import org.wordpress.android.R
import org.wordpress.android.WordPress
Expand All @@ -37,8 +42,10 @@ class PageParentFragment : Fragment() {

private var linearLayoutManager: LinearLayoutManager? = null
private var saveButton: MenuItem? = null
private lateinit var searchAction: MenuItem

private var pageId: Long? = null
private var restorePreviousSearch = false

companion object {
fun newInstance(): PageParentFragment {
Expand All @@ -54,6 +61,7 @@ class PageParentFragment : Fragment() {
viewModel.onSaveButtonTapped()
return true
}

return super.onOptionsItemSelected(item)
}

Expand All @@ -76,10 +84,63 @@ class PageParentFragment : Fragment() {

saveButton = menu.findItem(R.id.save_parent)
viewModel.isSaveButtonVisible.value?.let { saveButton?.isVisible = it }
searchAction = checkNotNull(menu.findItem(R.id.action_search)) {
"Menu does not contain mandatory search item"
}

initializeSearchView()
}

private fun initializeSearchView() {
searchAction.setOnActionExpandListener(object : OnActionExpandListener {
override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
viewModel.onSearchExpanded(restorePreviousSearch)
return true
}

override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
viewModel.onSearchCollapsed()
return true
}
})

val searchView = searchAction.actionView as SearchView
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
viewModel.onSearch(query)
return true
}

override fun onQueryTextChange(newText: String): Boolean {
if (restorePreviousSearch) {
restorePreviousSearch = false
searchView.setQuery(viewModel.lastSearchQuery, false)
} else {
viewModel.onSearch(newText)
}
return true
}
})

val searchEditFrame = searchAction?.actionView.findViewById<LinearLayout>(R.id.search_edit_frame)
(searchEditFrame.layoutParams as LinearLayout.LayoutParams)
.apply { this.leftMargin = DisplayUtils.dpToPx(activity, -8) }
Comment thread
malinajirka marked this conversation as resolved.

viewModel.isSearchExpanded.observe(this, Observer {
if (it == true) {
showSearchList(searchAction)
} else {
hideSearchList(searchAction)
}
})
}

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.pages_list_fragment, container, false)
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.page_parent_fragment, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
Expand All @@ -92,11 +153,11 @@ class PageParentFragment : Fragment() {

(nonNullActivity.application as? WordPress)?.component()?.inject(this)

initializeViews(savedInstanceState)
initializeViewModels(nonNullPageId, savedInstanceState == null)
initializeViews(nonNullActivity, savedInstanceState)
initializeViewModels(nonNullActivity, nonNullPageId, savedInstanceState == null)
}

private fun initializeViews(savedInstanceState: Bundle?) {
private fun initializeViews(activity: FragmentActivity, savedInstanceState: Bundle?) {
val layoutManager = LinearLayoutManager(activity, RecyclerView.VERTICAL, false)
savedInstanceState?.getParcelable<Parcelable>(listStateKey)?.let {
layoutManager.onRestoreInstanceState(it)
Expand All @@ -105,17 +166,30 @@ class PageParentFragment : Fragment() {
linearLayoutManager = layoutManager
recyclerView.layoutManager = linearLayoutManager
recyclerView.addItemDecoration(RecyclerItemDecoration(0, DisplayUtils.dpToPx(activity, 1)))

val searchFragment = PageParentSearchFragment.newInstance()
activity.supportFragmentManager
.beginTransaction()
.replace(R.id.frameSearch, searchFragment)
.commit()
}

private fun initializeViewModels(pageId: Long, isFirstStart: Boolean) {
viewModel = ViewModelProviders.of(this, viewModelFactory).get(PageParentViewModel::class.java)
private fun initializeViewModels(
activity: FragmentActivity,
pageId: Long,
isFirstStart: Boolean
) {
viewModel = ViewModelProviders.of(activity, viewModelFactory)
.get(PageParentViewModel::class.java)

setupObservers()

if (isFirstStart) {
val site = activity?.intent?.getSerializableExtra(WordPress.SITE) as SiteModel?
val site = activity.intent?.getSerializableExtra(WordPress.SITE) as SiteModel?
val nonNullSite = checkNotNull(site)
viewModel.start(nonNullSite, pageId)
} else {
restorePreviousSearch = true
}
}

Expand Down Expand Up @@ -148,4 +222,24 @@ class PageParentFragment : Fragment() {
}
adapter.update(pages)
}

private fun hideSearchList(myActionMenuItem: MenuItem) {
recyclerView.visibility = View.VISIBLE
frameSearch.visibility = View.GONE
if (myActionMenuItem.isActionViewExpanded) {
myActionMenuItem.collapseActionView()
}
/**Force the recyclerview to redraw if selection has changed while in search mode*/
if (viewModel.currentParent != viewModel.initialParent) {
recyclerView.adapter?.notifyDataSetChanged()
Comment thread
malinajirka marked this conversation as resolved.
}
}

private fun showSearchList(myActionMenuItem: MenuItem) {
frameSearch.visibility = View.VISIBLE
recyclerView.visibility = View.GONE
if (!myActionMenuItem.isActionViewExpanded) {
myActionMenuItem.expandActionView()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.wordpress.android.ui.pages

import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView.Adapter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.wordpress.android.R.layout
import org.wordpress.android.ui.pages.PageItem.ParentPage
import org.wordpress.android.ui.pages.PageItemViewHolder.EmptyViewHolder
import org.wordpress.android.ui.pages.PageItemViewHolder.PageDividerViewHolder
import org.wordpress.android.ui.pages.PageItemViewHolder.PageParentViewHolder

class PageParentSearchAdapter(
private val onParentSelected: (ParentPage) -> Unit,
private val uiScope: CoroutineScope
) : Adapter<PageItemViewHolder>() {
private val items = mutableListOf<PageItem>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PageItemViewHolder {
return when (viewType) {
PageItem.Type.PARENT.viewType -> PageParentViewHolder(parent,
this::selectParent,
layout.page_parent_list_item)
PageItem.Type.TOP_LEVEL_PARENT.viewType -> PageParentViewHolder(parent,
this::selectParent,
layout.page_parent_top_level_item)
PageItem.Type.DIVIDER.viewType -> PageDividerViewHolder(parent)
PageItem.Type.EMPTY.viewType -> EmptyViewHolder(parent) { }
else -> throw Throwable("Unexpected view type")
}
}

private fun selectParent(parent: ParentPage) {
onParentSelected(parent)
uiScope.launch {
delay(200) // let the selection animation play out before refreshing the list
notifyDataSetChanged()
}
}
override fun getItemCount(): Int = items.size

override fun getItemViewType(position: Int): Int {
return items[position].type.viewType
}

override fun onBindViewHolder(holder: PageItemViewHolder, position: Int) {
holder.onBind(items[position])
}

fun update(result: List<PageItem>) {
val diffResult = DiffUtil.calculateDiff(PageItemDiffUtil(items.toList(), result))
items.clear()
items.addAll(result)
diffResult.dispatchUpdatesTo(this)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package org.wordpress.android.ui.pages

import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.pages_list_fragment.*
import kotlinx.coroutines.CoroutineScope
import org.wordpress.android.R
import org.wordpress.android.WordPress
import org.wordpress.android.modules.UI_SCOPE
import org.wordpress.android.util.DisplayUtils
import org.wordpress.android.viewmodel.pages.PageParentSearchViewModel
import org.wordpress.android.viewmodel.pages.PageParentViewModel
import org.wordpress.android.widgets.RecyclerItemDecoration
import javax.inject.Inject
import javax.inject.Named

class PageParentSearchFragment : Fragment() {
@Inject lateinit var viewModelFactory: ViewModelProvider.Factory
private lateinit var viewModel: PageParentSearchViewModel
@field:[Inject Named(UI_SCOPE)] lateinit var uiScope: CoroutineScope
private var linearLayoutManager: LinearLayoutManager? = null

private val listStateKey = "list_state"

companion object {
fun newInstance(): PageParentSearchFragment {
return PageParentSearchFragment()
}
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.pages_list_fragment, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val nonNullActivity = checkNotNull(activity)
(nonNullActivity.application as? WordPress)?.component()?.inject(this)

initializeViews(savedInstanceState)
initializeViewModels(nonNullActivity)
}

override fun onSaveInstanceState(outState: Bundle) {
linearLayoutManager?.let {
outState.putParcelable(listStateKey, it.onSaveInstanceState())
}
super.onSaveInstanceState(outState)
}

private fun initializeViewModels(activity: FragmentActivity) {
val pageParentViewModel = ViewModelProviders.of(activity, viewModelFactory)
.get(PageParentViewModel::class.java)

viewModel = ViewModelProviders.of(this, viewModelFactory)
.get(PageParentSearchViewModel::class.java)
viewModel.start(pageParentViewModel)

setupObservers()
}

private fun initializeViews(savedInstanceState: Bundle?) {
val layoutManager = LinearLayoutManager(activity, RecyclerView.VERTICAL, false)
savedInstanceState?.getParcelable<Parcelable>(listStateKey)?.let {
layoutManager.onRestoreInstanceState(it)
}

linearLayoutManager = layoutManager
recyclerView.layoutManager = linearLayoutManager
recyclerView.addItemDecoration(RecyclerItemDecoration(0, DisplayUtils.dpToPx(activity, 1)))
}

private fun setupObservers() {
viewModel.searchResult.observe(this, Observer { data ->
data?.let { setSearchResult(data) }
})
}

private fun setSearchResult(pages: List<PageItem>) {
val adapter: PageParentSearchAdapter
if (recyclerView.adapter == null) {
adapter = PageParentSearchAdapter(
{ page -> viewModel.onParentSelected(page) }, uiScope)
recyclerView.adapter = adapter
} else {
adapter = recyclerView.adapter as PageParentSearchAdapter
}
adapter.update(pages)
}
}
Loading