Обратный вызов ActionMode никогда не вызывает onCreateActionMode при запуске в OnViewCreated фрагмента - PullRequest
0 голосов
/ 19 июня 2020
@ExperimentalCoroutinesApi
class WeekdayTimesFragment @Inject constructor(viewModelFactory: SavedStateViewModelFactory.Factory)
    :Fragment(R.layout.fragment_weekday_times), WeekdayAlarmTimesAdapter.OnWeekdayAlarmTimePressed, ActionModeListener {

    private lateinit var weekdayAlarmTimesAdapter: WeekdayAlarmTimesAdapter
    private val weekdayTimesViewModel
            by viewModels<WeekdayTimesViewModel> { viewModelFactory.create(this) }
    override val actionCallback = PrimaryActionCallback(this)
    private var weekday: Int = 0
    private val isActionModeActive: Boolean
        get() = weekdayTimesViewModel.isActionModeActive
    private val numSelected: Int
        get() = weekdayTimesViewModel.selectedTimePositions.size

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        weekday = requireArguments().get("WEEKDAY") as Int
        if(isActionModeActive) { //action mode may be active prior to rotation
            startActionMode() //for some reason, starting action mode here does not work....
        }
        initRecyclerView() //will determine what recyclerview items are selected via the viewmodel
        weekdayTimesViewModel.getTimesAndAlarmsForSelectedWeekday(Weekday[weekday])
            .observe(viewLifecycleOwner) { times->
                weekdayAlarmTimesAdapter.submitWeekdayTimes(times)
            }
    }

    override fun alarmTimePressed(wasSelected: Boolean, position: Int, time: WeekdayTime) {
        if(wasSelected) { //this item was selected prior to being selected, effectively unselecting it
            weekdayTimesViewModel.selectedTimePositions.remove(position)
        } else {
            weekdayTimesViewModel.selectedTimePositions[position] =
                Time(time.hour, time.minute, Weekday[weekday], time.alarm.alarmId, time.isDisabled, time.id)
        }

        if(numSelected == 0 && isActionModeActive) { //no more times are selected, turn off action mode
            destroyActionMode() //need to de-select recyclerview items
        } else {
            if (!isActionModeActive) {
                startActionMode()
            } else {
                actionCallback.changeTitle("$numSelected selected")
            }
        }
    }

    private fun startActionMode() {
        actionCallback
            .startActionMode(
                requireView(),
                R.menu.toolbar_contextual_menu,
                "$numSelected selected")
        //fragment hosting the viewpager
        (requireParentFragment() as ActionModeListenerController).currentActionModeListener = this
        weekdayTimesViewModel.isActionModeActive = true
    }

    override fun onActionItemClick(item: MenuItem?) {
        item?.let {
            when(it.itemId){
                R.id.toolbar_disable_alarm-> {
                    requireContext().createGenericAlertDialog(
                        message = if(numSelected == 1) "Are you sure you want to disable this alarm?"
                        else "Are you sure you want to disable these alarms?",
                        positiveListener = { _, _ ->
                            weekdayTimesViewModel.disableSelectedTimes()
                            showUndoSnackbar(true)
                        }
                    ).show()
                }
                R.id.toolbar_delete_alarms-> {
                    requireContext().createGenericAlertDialog(
                        message = if(numSelected == 1) "Are you sure you want to delete this alarm?"
                        else "Are you sure you want to delete these alarms?",
                        positiveListener = { _, _ ->
                            weekdayTimesViewModel.deleteSelectedTimes()
                            showUndoSnackbar(false)
                        }
                    ).show()
                }
            }
        }
    }

    //when we aren't destroying the view but need to end action mode (changing tab or after we confirm an action)
    //we may want to do specific things specific to certain listeners, e.g. de-select certain recyclerview items.
    override fun destroyActionMode() {
        actionCallback.finishActionMode()
        weekdayTimesViewModel.isActionModeActive = false
        //also un-select all of the elements that have been selected
        weekdayTimesViewModel.selectedTimePositions.clear()
        //redraw recyclerview as well
        rv_weekday_times.resetAdapterState()
    }

    private fun showUndoSnackbar(disablingTimes: Boolean){
        val message =
            if(disablingTimes) "Your alarm times have been disabled." else "Your alarm times have been deleted."
        Snackbar.make(requireView(), message, Snackbar.LENGTH_LONG).setAction("UNDO"){
            if(disablingTimes)
                weekdayTimesViewModel.restoreDisabledTimes()
            else
                weekdayTimesViewModel.restoreDeletedTimes()
        }.setActionTextColor(ContextCompat.getColor(requireContext(), R.color.colorPrimary))
        .setAnchorView(requireActivity().bottom_nav_view).show()
    }

    //when rotating screen or navigating we can just end action mode. The state of whether we are
    //in action mode either doesn't matter (navigation) or is already persisted, along with the selected
    //items in the viewmodel(rotation)
    override fun onDestroyView() {
        actionCallback.finishActionMode()
        super.onDestroyView()
    }

    private fun initRecyclerView() {
        weekdayAlarmTimesAdapter = WeekdayAlarmTimesAdapter(this, weekdayTimesViewModel.selectedTimePositions.keys)
        rv_weekday_times.apply {
            adapter = weekdayAlarmTimesAdapter
            layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
        }
        weekdayAlarmTimesAdapter.selectedItems.clear()
        //clears selected items as these items no longer remain consistently for the lifecycle of the view
    }
}

Итак, мой ActionMode отлично работает, когда я получаю обратный вызов (alarmTimePressed) через прослушиватель щелчков, установленный в OnBindViewHolder ресайклервью. Я запускаю свой ActionMode, и он отлично работает, я сохраняю, активен ли ActionMode в моей модели просмотра, которая хорошо работает при повороте, как если бы она была активна до поворота, она все еще остается активной. Как вы можете видеть в моем OnViewCreated, я вызываю startActionMode (), когда ActionMode должен быть активным. Проблема в том, что когда я запускаю его оттуда, обратный вызов onCreateActionMode никогда не вызывается. Это странно, потому что даже после поворота, если я выбираю элемент в RecyclerView, он правильно запускает ActionMode. Представление, которое я передаю в startActionMode, одинаково в обоих случаях. Если вам нужен код для PrimaryActionCallback, он здесь: https://hastebin.com/vepujuhefe.m. Не думал, что это очень нужно, но на случай, если захотелось посмотреть :). Кто-нибудь знает, что здесь происходит?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...