1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.deskclock.timer 18 19 import android.annotation.SuppressLint 20 import android.util.ArrayMap 21 import android.view.View 22 import android.view.ViewGroup 23 import androidx.fragment.app.Fragment 24 import androidx.fragment.app.FragmentManager 25 import androidx.fragment.app.FragmentTransaction 26 import androidx.viewpager.widget.PagerAdapter 27 28 import com.android.deskclock.data.DataModel 29 import com.android.deskclock.data.Timer 30 import com.android.deskclock.data.TimerListener 31 32 /** 33 * This adapter produces a [TimerItemFragment] for each timer. 34 */ 35 internal class TimerPagerAdapter( 36 private val mFragmentManager: FragmentManager 37 ) : PagerAdapter(), TimerListener { 38 39 /** Maps each timer id to the corresponding [TimerItemFragment] that draws it. */ 40 private val mFragments: MutableMap<Int, TimerItemFragment?> = ArrayMap() 41 42 /** The current fragment transaction in play or `null`. */ 43 private var mCurrentTransaction: FragmentTransaction? = null 44 45 /** The [TimerItemFragment] that is current visible on screen. */ 46 private var mCurrentPrimaryItem: Fragment? = null 47 getCountnull48 override fun getCount(): Int = timers.size 49 50 override fun isViewFromObject(view: View, any: Any): Boolean { 51 return (any as Fragment).view === view 52 } 53 getItemPositionnull54 override fun getItemPosition(any: Any): Int { 55 val fragment = any as TimerItemFragment 56 val timer = fragment.timer 57 58 val position = timers.indexOf(timer) 59 return if (position == -1) POSITION_NONE else position 60 } 61 62 @SuppressLint("CommitTransaction") instantiateItemnull63 override fun instantiateItem(container: ViewGroup, position: Int): Fragment { 64 if (mCurrentTransaction == null) { 65 mCurrentTransaction = mFragmentManager.beginTransaction() 66 } 67 68 val timer = timers[position] 69 70 // Search for the existing fragment by tag. 71 val tag = javaClass.simpleName + timer.id 72 var fragment = mFragmentManager.findFragmentByTag(tag) as TimerItemFragment? 73 74 if (fragment != null) { 75 // Reattach the existing fragment. 76 mCurrentTransaction!!.attach(fragment) 77 } else { 78 // Create and add a new fragment. 79 fragment = TimerItemFragment.newInstance(timer) 80 mCurrentTransaction!!.add(container.id, fragment, tag) 81 } 82 83 if (fragment !== mCurrentPrimaryItem) { 84 setItemVisible(fragment, false) 85 } 86 87 mFragments[timer.id] = fragment 88 89 return fragment 90 } 91 92 @SuppressLint("CommitTransaction") destroyItemnull93 override fun destroyItem(container: ViewGroup, position: Int, any: Any) { 94 val fragment = any as TimerItemFragment 95 96 if (mCurrentTransaction == null) { 97 mCurrentTransaction = mFragmentManager.beginTransaction() 98 } 99 100 mFragments.remove(fragment.timerId) 101 mCurrentTransaction!!.remove(fragment) 102 } 103 setPrimaryItemnull104 override fun setPrimaryItem(container: ViewGroup, position: Int, any: Any) { 105 val fragment = any as Fragment 106 if (fragment !== mCurrentPrimaryItem) { 107 mCurrentPrimaryItem?.let { 108 setItemVisible(it, false) 109 } 110 111 mCurrentPrimaryItem = fragment 112 113 mCurrentPrimaryItem?.let { 114 setItemVisible(it, true) 115 } 116 } 117 } 118 finishUpdatenull119 override fun finishUpdate(container: ViewGroup) { 120 if (mCurrentTransaction != null) { 121 mCurrentTransaction!!.commitAllowingStateLoss() 122 mCurrentTransaction = null 123 124 if (!mFragmentManager.isDestroyed) { 125 mFragmentManager.executePendingTransactions() 126 } 127 } 128 } 129 timerAddednull130 override fun timerAdded(timer: Timer) { 131 notifyDataSetChanged() 132 } 133 timerRemovednull134 override fun timerRemoved(timer: Timer) { 135 notifyDataSetChanged() 136 } 137 timerUpdatednull138 override fun timerUpdated(before: Timer, after: Timer) { 139 val timerItemFragment = mFragments[after.id] 140 timerItemFragment?.updateTime() 141 } 142 143 /** 144 * @return `true` if at least one timer is in a state requiring continuous updates 145 */ updateTimenull146 fun updateTime(): Boolean { 147 var continuousUpdates = false 148 for (fragment in mFragments.values) { 149 continuousUpdates = continuousUpdates or fragment!!.updateTime() 150 } 151 return continuousUpdates 152 } 153 getTimernull154 fun getTimer(index: Int): Timer { 155 return timers[index] 156 } 157 158 private val timers: List<Timer> 159 get() = DataModel.dataModel.timers 160 161 companion object { setItemVisiblenull162 private fun setItemVisible(item: Fragment, visible: Boolean) { 163 item.setMenuVisibility(visible) 164 item.setUserVisibleHint(visible) 165 } 166 } 167 }