View
@@ -2,27 +2,35 @@ package com.zhuinden.simplestackdemoexamplefragments.presentation.paths.taskdeta
import android.view.MenuItem
import com.zhuinden.simplestackdemoexamplefragments.R
import com.zhuinden.simplestackdemoexamplefragments.application.Injector
import com.zhuinden.simplestackdemoexamplefragments.presentation.objects.Task
import com.zhuinden.simplestackdemoexamplefragments.util.BaseFragment
import com.zhuinden.simplestackdemoexamplefragments.util.Strings
import com.zhuinden.simplestackdemoexamplefragments.util.hide
import com.zhuinden.simplestackdemoexamplefragments.util.show
import com.zhuinden.simplestackdemoexamplefragments.util.*
import kotlinx.android.synthetic.main.path_taskdetail.*
/**
* Created by Zhuinden on 2018. 08. 20.
*/
// UNSCOPED!
class TaskDetailFragment : BaseFragment<TaskDetailPresenter.ViewContract, TaskDetailPresenter>(), TaskDetailPresenter.ViewContract {
private val taskDetailPresenter = Injector.get().taskDetailPresenter()
class TaskDetailFragment : BaseFragment<TaskDetailFragment, TaskDetailFragment.Presenter>() {
companion object {
const val CONTROLLER_TAG = "TaskDetailView.Presenter"
}
interface Presenter: MvpPresenter<TaskDetailFragment> {
fun onTaskChecked(task: Task, checked: Boolean)
override val presenter: TaskDetailPresenter = taskDetailPresenter
fun onTaskEditButtonClicked()
override fun getThis(): TaskDetailPresenter.ViewContract = this
fun onTaskDeleteButtonClicked()
}
override val presenter: Presenter by lazy {
backstackDelegate.lookupService<TaskDetailFragment.Presenter>(CONTROLLER_TAG)
}
override fun getThis(): TaskDetailFragment = this
fun editTask() {
taskDetailPresenter.editTask()
presenter.onTaskEditButtonClicked()
}
fun showTitle(title: String) {
@@ -43,12 +51,12 @@ class TaskDetailFragment : BaseFragment<TaskDetailPresenter.ViewContract, TaskDe
textTaskDetailDescription.hide()
}
override fun showMissingTask() {
fun showMissingTask() {
textTaskDetailTitle.text = ""
textTaskDetailDescription.text = activity!!.getString(R.string.no_data)
}
override fun showTask(task: Task) {
fun showTask(task: Task) {
val title = task.title
val description = task.description
@@ -69,22 +77,14 @@ class TaskDetailFragment : BaseFragment<TaskDetailPresenter.ViewContract, TaskDe
private fun showCompletionStatus(task: Task, completed: Boolean) {
checkboxTaskDetailComplete.isChecked = completed
checkboxTaskDetailComplete.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
presenter.completeTask(task)
} else {
presenter.activateTask(task)
}
presenter.onTaskChecked(task, isChecked)
}
}
fun deleteTask() {
taskDetailPresenter.deleteTask()
}
override fun onOptionsItemSelected(menuItem: MenuItem): Boolean {
when (menuItem.itemId) {
R.id.menu_delete -> {
deleteTask()
presenter.onTaskDeleteButtonClicked()
return true
}
}
View
@@ -2,16 +2,25 @@ package com.zhuinden.simplestackdemoexamplefragments.presentation.paths.taskdeta
import android.support.v4.app.Fragment
import android.view.View
import com.zhuinden.simplestack.ScopedServices
import com.zhuinden.simplestackdemoexamplefragments.R
import com.zhuinden.simplestackdemoexamplefragments.application.BaseKey
import com.zhuinden.simplestackdemoexamplefragments.application.Injector
import com.zhuinden.simplestackdemoexamplefragments.util.scopedservices.HasServices
import kotlinx.android.parcel.Parcelize
/**
* Created by Zhuinden on 2018. 08. 20.
*/
@Parcelize
data class TaskDetailKey(val taskId: String) : BaseKey() {
data class TaskDetailKey(val taskId: String) : BaseKey(), HasServices {
override fun bindServices(serviceBinder: ScopedServices.ServiceBinder) {
serviceBinder.add(TaskDetailFragment.CONTROLLER_TAG, Injector.get().taskDetailPresenter())
}
override fun getScopeTag(): String = "TaskDetail[$taskId]"
override fun layout(): Int = R.layout.path_taskdetail
override val isFabVisible: Boolean
View
@@ -6,8 +6,6 @@ import com.zhuinden.simplestackdemoexamplefragments.data.repository.TaskReposito
import com.zhuinden.simplestackdemoexamplefragments.presentation.objects.Task
import com.zhuinden.simplestackdemoexamplefragments.presentation.paths.addoredittask.AddOrEditTaskKey
import com.zhuinden.simplestackdemoexamplefragments.util.BasePresenter
import com.zhuinden.simplestackdemoexamplefragments.util.BaseViewContract
import com.zhuinden.statebundle.StateBundle
import io.reactivex.android.schedulers.AndroidSchedulers
import javax.inject.Inject
@@ -18,11 +16,21 @@ import javax.inject.Inject
class TaskDetailPresenter @Inject constructor(
private val taskRepository: TaskRepository,
private val backstack: Backstack
) : BasePresenter<TaskDetailPresenter.ViewContract>() {
interface ViewContract: BaseViewContract {
fun showTask(task: Task)
) : BasePresenter<TaskDetailFragment>(), TaskDetailFragment.Presenter {
override fun onTaskChecked(task: Task, checked: Boolean) {
if (checked) {
completeTask(task)
} else {
activateTask(task)
}
}
override fun onTaskEditButtonClicked() {
editTask()
}
fun showMissingTask()
override fun onTaskDeleteButtonClicked() {
deleteTask()
}
lateinit var taskDetailKey: TaskDetailKey
@@ -32,7 +40,7 @@ class TaskDetailPresenter @Inject constructor(
var task: Task? = null
@SuppressLint("CheckResult")
override fun onAttach(view: ViewContract) {
override fun onAttach(view: TaskDetailFragment) {
this.taskDetailKey = view.getKey()
this.taskId = taskDetailKey.taskId
@@ -49,35 +57,31 @@ class TaskDetailPresenter @Inject constructor(
}
}
override fun onDetach(view: ViewContract) {
override fun onDetach(view: TaskDetailFragment) {
}
fun editTask() {
private fun editTask() {
if (task == null) {
view?.showMissingTask()
return
}
backstack.goTo(AddOrEditTaskKey.EditTaskKey(view!!.getKey(), taskId))
}
fun completeTask(task: Task) {
private fun completeTask(task: Task) {
taskRepository.setTaskCompleted(task)
}
fun activateTask(task: Task) {
private fun activateTask(task: Task) {
taskRepository.setTaskActive(task)
}
fun deleteTask() {
private fun deleteTask() {
val task = task
if (task != null) {
taskRepository.deleteTask(task)
backstack.goBack()
}
}
override fun toBundle(): StateBundle = StateBundle()
override fun fromBundle(bundle: StateBundle?) {}
}
View
@@ -34,18 +34,14 @@ class TasksAdapter(
) : LayoutContainer, RecyclerView.ViewHolder(containerView) {
lateinit var task: Task
private val rowClickListener = View.OnClickListener { _ -> itemListener.openTask(task) }
private val rowClickListener = View.OnClickListener { _ -> itemListener.onTaskRowClicked(task) }
private val context = containerView.context
init {
containerView.setOnClickListener(rowClickListener)
complete.onClick {
if (!task.isCompleted) {
itemListener.completeTask(task)
} else {
itemListener.uncompleteTask(task)
}
itemListener.onTaskCheckClicked(task)
}
}
@@ -61,11 +57,9 @@ class TasksAdapter(
}
interface TaskItemListener {
fun openTask(task: Task)
fun onTaskRowClicked(task: Task)
fun completeTask(task: Task)
fun uncompleteTask(task: Task)
fun onTaskCheckClicked(task: Task)
}
init {
View
@@ -43,7 +43,7 @@ sealed class TasksFilterType: Parcelable {
override fun filterTask(taskRepository: TaskRepository): Observable<List<Task>> =
taskRepository.tasksWithChanges
override fun showEmptyViews(tasksFragment: TasksPresenter.ViewContract) {
override fun showEmptyViews(tasksFragment: TasksFragment) {
tasksFragment.showNoTasks()
}
}
@@ -62,7 +62,7 @@ sealed class TasksFilterType: Parcelable {
taskRepository.activeTasksWithChanges
override fun showEmptyViews(tasksFragment: TasksPresenter.ViewContract) {
override fun showEmptyViews(tasksFragment: TasksFragment) {
tasksFragment.showNoActiveTasks()
}
}
@@ -80,7 +80,7 @@ sealed class TasksFilterType: Parcelable {
override fun filterTask(taskRepository: TaskRepository): Observable<List<Task>> =
taskRepository.completedTasksWithChanges
override fun showEmptyViews(tasksFragment: TasksPresenter.ViewContract) {
override fun showEmptyViews(tasksFragment: TasksFragment) {
tasksFragment.showNoCompletedTasks()
}
}
@@ -89,5 +89,5 @@ sealed class TasksFilterType: Parcelable {
abstract fun filterTask(taskRepository: TaskRepository): Observable<List<Task>>
abstract fun showEmptyViews(tasksFragment: TasksPresenter.ViewContract)
abstract fun showEmptyViews(tasksFragment: TasksFragment)
}
View
@@ -1,6 +1,5 @@
package com.zhuinden.simplestackdemoexamplefragments.presentation.paths.tasks
import android.annotation.SuppressLint
import android.os.Bundle
import android.support.design.widget.Snackbar
import android.support.v4.content.ContextCompat
@@ -17,41 +16,57 @@ import com.zhuinden.simplestackdemoexamplefragments.application.Key
import com.zhuinden.simplestackdemoexamplefragments.application.MainActivity
import com.zhuinden.simplestackdemoexamplefragments.presentation.objects.Task
import com.zhuinden.simplestackdemoexamplefragments.util.*
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.synthetic.main.path_tasks.*
import org.jetbrains.anko.sdk15.listeners.onClick
import java.util.*
import java.util.concurrent.TimeUnit
/**
* Created by Zhuinden on 2018. 08. 20.
*/
// UNSCOPED!
class TasksFragment : BaseFragment<TasksPresenter.ViewContract, TasksPresenter>(), MessageQueue.Receiver, TasksPresenter.ViewContract {
private val tasksPresenter = Injector.get().tasksPresenter()
class TasksFragment : BaseFragment<TasksFragment, TasksFragment.Presenter>(), MessageQueue.Receiver {
companion object {
const val CONTROLLER_TAG = "TasksView.Presenter"
}
interface Presenter: MvpPresenter<TasksFragment> {
fun onTaskCheckClicked(task: Task)
fun onTaskRowClicked(task: Task)
fun onNoTasksAddButtonClicked()
fun onFilterActiveSelected()
fun onFilterCompletedSelected()
fun onFilterAllSelected()
fun onClearCompletedClicked()
fun onRefreshClicked()
}
private val myResources = Injector.get().resources()
private val messageQueue = Injector.get().messageQueue()
lateinit var tasksAdapter: TasksAdapter
var taskItemListener: TasksAdapter.TaskItemListener = object : TasksAdapter.TaskItemListener {
override fun openTask(task: Task) {
tasksPresenter.openTaskDetails(task)
override fun onTaskRowClicked(task: Task) {
presenter.onTaskRowClicked(task)
}
override fun completeTask(task: Task) {
tasksPresenter.completeTask(task)
}
override fun uncompleteTask(task: Task) {
tasksPresenter.uncompleteTask(task)
override fun onTaskCheckClicked(task: Task) {
presenter.onTaskCheckClicked(task)
}
}
class SavedSuccessfullyMessage
override val presenter: TasksPresenter = tasksPresenter
override val presenter: Presenter by lazy {
backstackDelegate.lookupService<TasksFragment.Presenter>(CONTROLLER_TAG)
}
override fun getThis(): TasksFragment = this
@@ -65,24 +80,20 @@ class TasksFragment : BaseFragment<TasksPresenter.ViewContract, TasksPresenter>(
recyclerTasks.layoutManager = LinearLayoutManager(view.context, LinearLayoutManager.VERTICAL, false)
recyclerTasks.adapter = tasksAdapter
swipeRefreshLayout.setColorSchemeColors(ContextCompat.getColor(context!!, R.color.colorPrimary),
ContextCompat.getColor(context!!, R.color.colorAccent),
ContextCompat.getColor(context!!, R.color.colorPrimaryDark))
swipeRefreshLayout.setColorSchemeColors(ContextCompat.getColor(requireContext(), R.color.colorPrimary),
ContextCompat.getColor(requireContext(), R.color.colorAccent),
ContextCompat.getColor(requireContext(), R.color.colorPrimaryDark))
// Set the scrolling view in the custom SwipeRefreshLayout.
swipeRefreshLayout.setScrollUpChild(recyclerTasks)
swipeRefreshLayout.setOnRefreshListener { this.refresh() }
swipeRefreshLayout.setOnRefreshListener { presenter.onRefreshClicked() }
buttonNoTasksAdd.onClick {
openAddNewTask()
addTaskButtonClicked()
}
messageQueue.requestMessages(getKey<Key>(), this)
}
fun openAddNewTask() {
tasksPresenter.openAddNewTask()
}
override fun onHiddenChanged(hidden: Boolean) {
super.onHiddenChanged(hidden)
if(!hidden) {
@@ -103,16 +114,19 @@ class TasksFragment : BaseFragment<TasksPresenter.ViewContract, TasksPresenter>(
}
}
override fun calculateDiff(tasks: List<Task>): Pair<DiffUtil.DiffResult, List<Task>> {
return Pair(DiffUtil.calculateDiff(TasksDiffCallback(tasksAdapter.data, tasks)), tasks)
fun addTaskButtonClicked() {
presenter.onNoTasksAddButtonClicked()
}
fun calculateDiff(tasks: List<Task>): Pair<DiffUtil.DiffResult, List<Task>> =
Pair(DiffUtil.calculateDiff(TasksDiffCallback(tasksAdapter.data, tasks)), tasks)
fun hideEmptyViews() {
containerTasks.show()
viewNoTasks.hide()
}
override fun showTasks(pairOfDiffResultAndTasks: Pair<DiffUtil.DiffResult, List<Task>>, filterType: TasksFilterType) {
fun showTasks(pairOfDiffResultAndTasks: Pair<DiffUtil.DiffResult, List<Task>>, filterType: TasksFilterType) {
val (diffResult, tasks) = pairOfDiffResultAndTasks
tasksAdapter.data = tasks
@@ -129,57 +143,43 @@ class TasksFragment : BaseFragment<TasksPresenter.ViewContract, TasksPresenter>(
popup.menuInflater.inflate(R.menu.filter_tasks, popup.menu)
popup.setOnMenuItemClickListener { item ->
tasksPresenter.setFiltering(when(item.itemId) {
R.id.active -> TasksFilterType.ActiveTasks()
R.id.completed -> TasksFilterType.CompletedTasks()
else -> TasksFilterType.AllTasks()
})
when(item.itemId) {
R.id.active -> presenter.onFilterActiveSelected()
R.id.completed -> presenter.onFilterCompletedSelected()
else -> presenter.onFilterAllSelected()
}
//loadTasks(false); // reactive data source ftw
true
}
popup.show()
}
fun clearCompletedTasks() {
tasksPresenter.deleteCompletedTasks()
}
@SuppressLint("CheckResult")
fun refresh() {
swipeRefreshLayout.isRefreshing = true
Single.just("")
.delay(2500, TimeUnit.MILLISECONDS)
.subscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { _ ->
if (swipeRefreshLayout != null) {
swipeRefreshLayout.isRefreshing = false
}
}
fun setRefreshing(isRefreshing: Boolean) {
swipeRefreshLayout.isRefreshing = isRefreshing
}
override fun showNoActiveTasks() {
fun showNoActiveTasks() {
showNoTasksViews(myResources.getString(R.string.no_tasks_active), R.drawable.ic_check_circle_24dp, false)
}
override fun showNoTasks() {
fun showNoTasks() {
showNoTasksViews(myResources.getString(R.string.no_tasks_all), R.drawable.ic_assignment_turned_in_24dp, false)
}
override fun showNoCompletedTasks() {
fun showNoCompletedTasks() {
showNoTasksViews(myResources.getString(R.string.no_tasks_completed), R.drawable.ic_verified_user_24dp, false)
}
override fun showTaskMarkedComplete() {
fun showTaskMarkedComplete() {
showMessage(myResources.getString(R.string.task_marked_complete))
}
override fun showTaskMarkedActive() {
fun showTaskMarkedActive() {
showMessage(myResources.getString(R.string.task_marked_active))
}
override fun showCompletedTasksCleared() {
fun showCompletedTasksCleared() {
showMessage(myResources.getString(R.string.completed_tasks_cleared))
}
@@ -207,7 +207,7 @@ class TasksFragment : BaseFragment<TasksPresenter.ViewContract, TasksPresenter>(
buttonNoTasksAdd.showIf { showAddView }
}
override fun setFilterLabelText(filterText: Int) {
fun setFilterLabelText(filterText: Int) {
textFilteringLabel.setText(filterText)
}
@@ -218,11 +218,11 @@ class TasksFragment : BaseFragment<TasksPresenter.ViewContract, TasksPresenter>(
return true
}
R.id.menu_clear -> {
clearCompletedTasks()
presenter.onClearCompletedClicked()
return true
}
R.id.menu_refresh -> {
refresh()
presenter.onRefreshClicked()
return true
}
}
View
@@ -2,16 +2,25 @@ package com.zhuinden.simplestackdemoexamplefragments.presentation.paths.tasks
import android.support.v4.app.Fragment
import android.view.View
import com.zhuinden.simplestack.ScopedServices
import com.zhuinden.simplestackdemoexamplefragments.R
import com.zhuinden.simplestackdemoexamplefragments.application.BaseKey
import com.zhuinden.simplestackdemoexamplefragments.application.Injector
import com.zhuinden.simplestackdemoexamplefragments.util.scopedservices.HasServices
import kotlinx.android.parcel.Parcelize
/**
* Created by Zhuinden on 2018. 08. 20.
*/
@Parcelize
data class TasksKey(val placeholder: String = "") : BaseKey() {
data class TasksKey(val placeholder: String = "") : BaseKey(), HasServices {
override fun bindServices(serviceBinder: ScopedServices.ServiceBinder) {
serviceBinder.add(TasksFragment.CONTROLLER_TAG, Injector.get().tasksPresenter())
}
override fun getScopeTag(): String = "Tasks"
constructor() : this("")
override fun layout(): Int = R.layout.path_tasks
@@ -30,7 +39,7 @@ data class TasksKey(val placeholder: String = "") : BaseKey() {
override fun fabClickListener(f: Fragment): View.OnClickListener =
View.OnClickListener { v ->
val fragment = f as TasksFragment
fragment.openAddNewTask()
fragment.addTaskButtonClicked()
}
override fun fabDrawableIcon(): Int = R.drawable.ic_add
View
@@ -10,11 +10,12 @@ import com.zhuinden.simplestackdemoexamplefragments.presentation.objects.Task
import com.zhuinden.simplestackdemoexamplefragments.presentation.paths.addoredittask.AddOrEditTaskKey
import com.zhuinden.simplestackdemoexamplefragments.presentation.paths.taskdetail.TaskDetailKey
import com.zhuinden.simplestackdemoexamplefragments.util.BasePresenter
import com.zhuinden.simplestackdemoexamplefragments.util.BaseViewContract
import com.zhuinden.statebundle.StateBundle
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@@ -25,25 +26,48 @@ import javax.inject.Inject
class TasksPresenter @Inject constructor(
private val backstack: Backstack,
private val taskRepository: TaskRepository
) : BasePresenter<TasksPresenter.ViewContract>(), Bundleable {
interface ViewContract : BaseViewContract {
fun showNoActiveTasks()
fun showNoTasks()
fun showNoCompletedTasks()
) : BasePresenter<TasksFragment>(), TasksFragment.Presenter, Bundleable {
override fun onTaskCheckClicked(task: Task) {
if (!task.isCompleted) {
completeTask(task)
} else {
uncompleteTask(task)
}
}
override fun onTaskRowClicked(task: Task) {
openTaskDetails(task)
}
override fun onNoTasksAddButtonClicked() {
openAddNewTask()
}
override fun onFilterActiveSelected() {
setFiltering(TasksFilterType.ActiveTasks())
}
override fun onFilterCompletedSelected() {
setFiltering(TasksFilterType.CompletedTasks())
}
override fun onFilterAllSelected() {
setFiltering(TasksFilterType.AllTasks())
}
override fun onClearCompletedClicked() {
deleteCompletedTasks()
}
fun setFilterLabelText(filterText: Int)
fun calculateDiff(tasks: List<Task>): Pair<DiffUtil.DiffResult, List<Task>>
fun showTasks(pairOfDiffResultAndTasks: Pair<DiffUtil.DiffResult, List<Task>>, tasksFilterType: TasksFilterType)
fun showTaskMarkedComplete()
fun showTaskMarkedActive()
fun showCompletedTasksCleared()
override fun onRefreshClicked() {
refresh()
}
var filterType: BehaviorRelay<TasksFilterType> = BehaviorRelay.createDefault(TasksFilterType.AllTasks())
lateinit var subscription: Disposable
public override fun onAttach(view: TasksPresenter.ViewContract) {
public override fun onAttach(view: TasksFragment) {
subscription = filterType
.doOnNext { tasksFilterType -> view.setFilterLabelText(tasksFilterType.filterText) } //
.switchMap { tasksFilterType -> tasksFilterType.filterTask(taskRepository) } //
@@ -55,36 +79,47 @@ class TasksPresenter @Inject constructor(
}
}
public override fun onDetach(view: TasksPresenter.ViewContract) {
public override fun onDetach(view: TasksFragment) {
subscription.dispose()
}
fun openAddNewTask() {
private fun openAddNewTask() {
val tasksFragment = view
val parentKey = tasksFragment!!.getKey<Key>()
backstack.goTo(AddOrEditTaskKey.AddTaskKey(parentKey))
}
fun openTaskDetails(task: Task) {
private fun refresh() {
view?.setRefreshing(true)
Single.just("")
.delay(2500, TimeUnit.MILLISECONDS)
.subscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { _ ->
view?.setRefreshing(false)
}
}
private fun openTaskDetails(task: Task) {
backstack.goTo(TaskDetailKey(task.id))
}
fun completeTask(task: Task) {
private fun completeTask(task: Task) {
taskRepository.setTaskCompleted(task)
view?.showTaskMarkedComplete()
}
fun uncompleteTask(task: Task) {
private fun uncompleteTask(task: Task) {
taskRepository.setTaskActive(task)
view?.showTaskMarkedActive()
}
fun deleteCompletedTasks() {
private fun deleteCompletedTasks() {
taskRepository.deleteCompletedTasks()
view?.showCompletedTasksCleared()
}
fun setFiltering(filterType: TasksFilterType) {
private fun setFiltering(filterType: TasksFilterType) {
this.filterType.accept(filterType)
}
View
@@ -5,50 +5,39 @@ import android.support.v4.app.Fragment
import android.view.*
import com.zhuinden.simplestack.KeyContextWrapper
import com.zhuinden.simplestackdemoexamplefragments.application.Key
import com.zhuinden.statebundle.StateBundle
/**
* Created by Zhuinden on 2017.01.26..
*/
abstract class BaseFragment<V : BaseViewContract, P : BasePresenter<V>> : Fragment() {
abstract val presenter: P
abstract class BaseFragment<V, P : MvpPresenter<V>> : Fragment() {
private lateinit var key: Key
abstract fun getThis(): V
protected abstract val presenter: P
private lateinit var key: Key
protected abstract fun getThis(): V
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
if (savedInstanceState != null) {
presenter.fromBundle(savedInstanceState.getParcelable<StateBundle>("PRESENTER_STATE"))
}
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
inflater!!.inflate(getKey<Key>().menu(), menu)
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(getKey<Key>().menu(), menu)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = arguments!!.getParcelable<Key>(KEY_TAG).let { key ->
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = requireArguments.getParcelable<Key>(KEY_TAG).let { key ->
this.key = key
LayoutInflater.from(KeyContextWrapper(inflater.context, key)).inflate(key.layout(), container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
presenter.attachFragment(getThis())
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putParcelable("PRESENTER_STATE", presenter.toBundle())
presenter.attachView(getThis())
}
override fun onDestroyView() {
presenter.detachFragment(getThis())
presenter.detachView(getThis())
super.onDestroyView()
}
View
@@ -1,25 +1,23 @@
package com.zhuinden.simplestackdemoexamplefragments.util
import com.zhuinden.simplestack.Bundleable
/**
* Created by Zhuinden on 2018. 08. 20.
*/
abstract class BasePresenter<V : BaseViewContract> : Bundleable {
abstract class BasePresenter<V> : MvpPresenter<V> {
var view: V? = null
fun attachFragment(fragment: V) {
this.view = fragment
onAttach(fragment)
override final fun attachView(view: V) {
this.view = view
onAttach(view)
}
fun detachFragment(fragment: V) {
onDetach(fragment)
override final fun detachView(view: V) {
onDetach(view)
this.view = null
}
protected abstract fun onAttach(view: V)
protected open fun onAttach(view: V) {}
protected abstract fun onDetach(view: V)
protected open fun onDetach(view: V) {}
}
View
@@ -0,0 +1,7 @@
package com.zhuinden.simplestackdemoexamplefragments.util
interface MvpPresenter<V> {
fun attachView(view: V)
fun detachView(view: V)
}
View
@@ -1,9 +1,13 @@
package com.zhuinden.simplestackdemoexamplefragments.util
import android.os.Bundle
import android.support.annotation.LayoutRes
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.zhuinden.simplestack.BackstackDelegate
import com.zhuinden.simplestackdemoexamplefragments.application.MainActivity
import io.reactivex.Observable
import io.reactivex.functions.BiFunction
@@ -15,6 +19,12 @@ fun View.hide() {
this.visibility = View.GONE
}
val Fragment.requireArguments: Bundle
get() = arguments ?: throw Exception("No arguments found!")
val Fragment.backstackDelegate: BackstackDelegate
get() = MainActivity.getBackstackDelegate(requireActivity())
inline fun <T: View> T.showIf(predicate: (T) -> Boolean) {
if(predicate(this)) {
show()
View

This file was deleted.

Oops, something went wrong.
View
@@ -0,0 +1,8 @@
package com.zhuinden.simplestackdemoexamplefragments.util.scopedservices
import com.zhuinden.simplestack.ScopeKey
import com.zhuinden.simplestack.ScopedServices
interface HasServices : ScopeKey {
fun bindServices(serviceBinder: ScopedServices.ServiceBinder)
}
View
@@ -249,6 +249,10 @@ boolean canFindService(@NonNull String serviceTag) {
return getService(scopeTag, serviceTag);
}
}
throw new IllegalStateException("The service [" + serviceTag + "] does not exist in any scopes! Is the scope tag registered via a ScopeKey?");
throw new IllegalStateException("The service [" + serviceTag + "] does not exist in any scopes! " +
"Is the scope tag registered via a ScopeKey? " +
"If yes, make sure the StateChanger has been set by this time, " +
"and that you've bound and are trying to lookup the service with the correct service tag. " +
"Otherwise, it is likely that the scope you intend to inherit the service from does not exist.");
}
}