diff options
Diffstat (limited to 'src/com/android/calendar/month/SimpleDayPickerFragment.kt')
-rw-r--r-- | src/com/android/calendar/month/SimpleDayPickerFragment.kt | 616 |
1 files changed, 0 insertions, 616 deletions
diff --git a/src/com/android/calendar/month/SimpleDayPickerFragment.kt b/src/com/android/calendar/month/SimpleDayPickerFragment.kt deleted file mode 100644 index 01fcbac6..00000000 --- a/src/com/android/calendar/month/SimpleDayPickerFragment.kt +++ /dev/null @@ -1,616 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.calendar.month - -import com.android.calendar.R -import com.android.calendar.Utils -import android.app.Activity -import android.app.ListFragment -import android.content.Context -import android.content.res.Resources -import android.database.DataSetObserver -import android.os.Bundle -import android.os.Handler -import android.text.TextUtils -import android.text.format.DateUtils -import android.text.format.Time -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewConfiguration -import android.view.ViewGroup -import android.view.accessibility.AccessibilityEvent -import android.widget.AbsListView -import android.widget.AbsListView.OnScrollListener -import android.widget.ListView -import android.widget.TextView -import java.util.Calendar -import java.util.HashMap -import java.util.Locale - -/** - * - * - * This displays a titled list of weeks with selectable days. It can be - * configured to display the week number, start the week on a given day, show a - * reduced number of days, or display an arbitrary number of weeks at a time. By - * overriding methods and changing variables this fragment can be customized to - * easily display a month selection component in a given style. - * - */ -open class SimpleDayPickerFragment(initialTime: Long) : ListFragment(), OnScrollListener { - protected var WEEK_MIN_VISIBLE_HEIGHT = 12 - protected var BOTTOM_BUFFER = 20 - protected var mSaturdayColor = 0 - protected var mSundayColor = 0 - protected var mDayNameColor = 0 - - // You can override these numbers to get a different appearance - @JvmField protected var mNumWeeks = 6 - @JvmField protected var mShowWeekNumber = false - @JvmField protected var mDaysPerWeek = 7 - - // These affect the scroll speed and feel - protected var mFriction = 1.0f - @JvmField protected var mContext: Context? = null - @JvmField protected var mHandler: Handler = Handler() - protected var mMinimumFlingVelocity = 0f - - // highlighted time - @JvmField protected var mSelectedDay: Time = Time() - @JvmField protected var mAdapter: SimpleWeeksAdapter? = null - @JvmField protected var mListView: ListView? = null - @JvmField protected var mDayNamesHeader: ViewGroup? = null - @JvmField protected var mDayLabels: Array<String?> = arrayOfNulls(7) - - // disposable variable used for time calculations - @JvmField protected var mTempTime: Time = Time() - - // When the week starts; numbered like Time.<WEEKDAY> (e.g. SUNDAY=0). - @JvmField protected var mFirstDayOfWeek = 0 - - // The first day of the focus month - @JvmField protected var mFirstDayOfMonth: Time = Time() - - // The first day that is visible in the view - @JvmField protected var mFirstVisibleDay: Time = Time() - - // The name of the month to display - protected var mMonthName: TextView? = null - - // The last name announced by accessibility - protected var mPrevMonthName: CharSequence? = null - - // which month should be displayed/highlighted [0-11] - protected var mCurrentMonthDisplayed = 0 - - // used for tracking during a scroll - protected var mPreviousScrollPosition: Long = 0 - - // used for tracking which direction the view is scrolling - protected var mIsScrollingUp = false - - // used for tracking what state listview is in - protected var mPreviousScrollState: Int = OnScrollListener.SCROLL_STATE_IDLE - - // used for tracking what state listview is in - protected var mCurrentScrollState: Int = OnScrollListener.SCROLL_STATE_IDLE - - // This causes an update of the view at midnight - @JvmField protected var mTodayUpdater: Runnable = object : Runnable { - @Override - override fun run() { - val midnight = Time(mFirstVisibleDay.timezone) - midnight.setToNow() - val currentMillis: Long = midnight.toMillis(true) - midnight.hour = 0 - midnight.minute = 0 - midnight.second = 0 - midnight.monthDay++ - val millisToMidnight: Long = midnight.normalize(true) - currentMillis - mHandler?.postDelayed(this, millisToMidnight) - if (mAdapter != null) { - mAdapter?.notifyDataSetChanged() - } - } - } - - // This allows us to update our position when a day is tapped - @JvmField protected var mObserver: DataSetObserver = object : DataSetObserver() { - @Override - override fun onChanged() { - val day: Time? = mAdapter!!.getSelectedDay() - if (day!!.year !== mSelectedDay!!.year || day!!.yearDay !== mSelectedDay.yearDay) { - goTo(day!!.toMillis(true), true, true, false) - } - } - } - - @Override - override fun onAttach(activity: Activity) { - super.onAttach(activity) - mContext = activity - val tz: String = Time.getCurrentTimezone() - val viewConfig: ViewConfiguration = ViewConfiguration.get(activity) - mMinimumFlingVelocity = (viewConfig.getScaledMinimumFlingVelocity()).toFloat() - - // Ensure we're in the correct time zone - mSelectedDay.switchTimezone(tz) - mSelectedDay.normalize(true) - mFirstDayOfMonth.timezone = tz - mFirstDayOfMonth.normalize(true) - mFirstVisibleDay.timezone = tz - mFirstVisibleDay.normalize(true) - mTempTime.timezone = tz - val res: Resources = activity.getResources() - mSaturdayColor = res.getColor(R.color.month_saturday) - mSundayColor = res.getColor(R.color.month_sunday) - mDayNameColor = res.getColor(R.color.month_day_names_color) - - // Adjust sizes for screen density - if (mScale == 0f) { - mScale = activity.getResources().getDisplayMetrics().density - if (mScale != 1f) { - WEEK_MIN_VISIBLE_HEIGHT *= mScale.toInt() - BOTTOM_BUFFER *= mScale.toInt() - LIST_TOP_OFFSET *= mScale.toInt() - } - } - setUpAdapter() - setListAdapter(mAdapter) - } - - /** - * Creates a new adapter if necessary and sets up its parameters. Override - * this method to provide a custom adapter. - */ - protected open fun setUpAdapter() { - val weekParams = HashMap<String?, Int?>() - weekParams?.put(SimpleWeeksAdapter.WEEK_PARAMS_NUM_WEEKS, mNumWeeks) - weekParams?.put(SimpleWeeksAdapter.WEEK_PARAMS_SHOW_WEEK, if (mShowWeekNumber) 1 else 0) - weekParams?.put(SimpleWeeksAdapter.WEEK_PARAMS_WEEK_START, mFirstDayOfWeek) - weekParams?.put(SimpleWeeksAdapter.WEEK_PARAMS_JULIAN_DAY, - Time.getJulianDay(mSelectedDay.toMillis(false), mSelectedDay.gmtoff)) - if (mAdapter == null) { - mAdapter = SimpleWeeksAdapter(getActivity(), weekParams) - mAdapter?.registerDataSetObserver(mObserver) - } else { - mAdapter?.updateParams(weekParams) - } - // refresh the view with the new parameters - mAdapter?.notifyDataSetChanged() - } - - @Override - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - } - - @Override - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - setUpListView() - setUpHeader() - mMonthName = getView()?.findViewById(R.id.month_name) as? TextView - val child = mListView?.getChildAt(0) as? SimpleWeekView - if (child == null) { - return - } - val julianDay: Int = child.getFirstJulianDay() - mFirstVisibleDay.setJulianDay(julianDay) - // set the title to the month of the second week - mTempTime.setJulianDay(julianDay + DAYS_PER_WEEK) - setMonthDisplayed(mTempTime, true) - } - - /** - * Sets up the strings to be used by the header. Override this method to use - * different strings or modify the view params. - */ - protected open fun setUpHeader() { - mDayLabels = arrayOfNulls(7) - for (i in Calendar.SUNDAY..Calendar.SATURDAY) { - mDayLabels[i - Calendar.SUNDAY] = DateUtils.getDayOfWeekString(i, - DateUtils.LENGTH_SHORTEST).toUpperCase() - } - } - - /** - * Sets all the required fields for the list view. Override this method to - * set a different list view behavior. - */ - protected fun setUpListView() { - // Configure the listview - mListView = getListView() - // Transparent background on scroll - mListView?.setCacheColorHint(0) - // No dividers - mListView?.setDivider(null) - // Items are clickable - mListView?.setItemsCanFocus(true) - // The thumb gets in the way, so disable it - mListView?.setFastScrollEnabled(false) - mListView?.setVerticalScrollBarEnabled(false) - mListView?.setOnScrollListener(this) - mListView?.setFadingEdgeLength(0) - // Make the scrolling behavior nicer - mListView?.setFriction(ViewConfiguration.getScrollFriction() * mFriction) - } - - @Override - override fun onResume() { - super.onResume() - setUpAdapter() - doResumeUpdates() - } - - @Override - override fun onPause() { - super.onPause() - mHandler.removeCallbacks(mTodayUpdater) - } - - @Override - override fun onSaveInstanceState(outState: Bundle) { - outState.putLong(KEY_CURRENT_TIME, mSelectedDay.toMillis(true)) - } - - /** - * Updates the user preference fields. Override this to use a different - * preference space. - */ - protected open fun doResumeUpdates() { - // Get default week start based on locale, subtracting one for use with android Time. - val cal: Calendar = Calendar.getInstance(Locale.getDefault()) - mFirstDayOfWeek = cal.getFirstDayOfWeek() - 1 - mShowWeekNumber = false - updateHeader() - goTo(mSelectedDay.toMillis(true), false, false, false) - mAdapter?.setSelectedDay(mSelectedDay) - mTodayUpdater.run() - } - - /** - * Fixes the day names header to provide correct spacing and updates the - * label text. Override this to set up a custom header. - */ - protected fun updateHeader() { - var label: TextView = mDayNamesHeader!!.findViewById(R.id.wk_label) as TextView - if (mShowWeekNumber) { - label.setVisibility(View.VISIBLE) - } else { - label.setVisibility(View.GONE) - } - val offset = mFirstDayOfWeek - 1 - for (i in 1..7) { - label = mDayNamesHeader!!.getChildAt(i) as TextView - if (i < mDaysPerWeek + 1) { - val position = (offset + i) % 7 - label.setText(mDayLabels[position]) - label.setVisibility(View.VISIBLE) - if (position == Time.SATURDAY) { - label.setTextColor(mSaturdayColor) - } else if (position == Time.SUNDAY) { - label.setTextColor(mSundayColor) - } else { - label.setTextColor(mDayNameColor) - } - } else { - label.setVisibility(View.GONE) - } - } - mDayNamesHeader?.invalidate() - } - - @Override - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - val v: View = inflater.inflate(R.layout.month_by_week, - container, false) - mDayNamesHeader = v.findViewById(R.id.day_names) as ViewGroup - return v - } - - /** - * Returns the UTC millis since epoch representation of the currently - * selected time. - * - * @return - */ - val selectedTime: Long - get() = mSelectedDay.toMillis(true) - - /** - * This moves to the specified time in the view. If the time is not already - * in range it will move the list so that the first of the month containing - * the time is at the top of the view. If the new time is already in view - * the list will not be scrolled unless forceScroll is true. This time may - * optionally be highlighted as selected as well. - * - * @param time The time to move to - * @param animate Whether to scroll to the given time or just redraw at the - * new location - * @param setSelected Whether to set the given time as selected - * @param forceScroll Whether to recenter even if the time is already - * visible - * @return Whether or not the view animated to the new location - */ - fun goTo(time: Long, animate: Boolean, setSelected: Boolean, forceScroll: Boolean): Boolean { - if (time == -1L) { - Log.e(TAG, "time is invalid") - return false - } - - // Set the selected day - if (setSelected) { - mSelectedDay.set(time) - mSelectedDay.normalize(true) - } - - // If this view isn't returned yet we won't be able to load the lists - // current position, so return after setting the selected day. - if (!isResumed()) { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "We're not visible yet") - } - return false - } - mTempTime.set(time) - var millis: Long = mTempTime.normalize(true) - // Get the week we're going to - // TODO push Util function into Calendar public api. - var position: Int = Utils.getWeeksSinceEpochFromJulianDay( - Time.getJulianDay(millis, mTempTime.gmtoff), mFirstDayOfWeek) - var child: View? - var i = 0 - var top = 0 - // Find a child that's completely in the view - do { - child = mListView?.getChildAt(i++) - if (child == null) { - break - } - top = child.getTop() - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "child at " + (i - 1) + " has top " + top) - } - } while (top < 0) - - // Compute the first and last position visible - val firstPosition: Int - firstPosition = if (child != null) { - mListView!!.getPositionForView(child) - } else { - 0 - } - var lastPosition = firstPosition + mNumWeeks - 1 - if (top > BOTTOM_BUFFER) { - lastPosition-- - } - if (setSelected) { - mAdapter?.setSelectedDay(mSelectedDay) - } - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "GoTo position $position") - } - // Check if the selected day is now outside of our visible range - // and if so scroll to the month that contains it - if (position < firstPosition || position > lastPosition || forceScroll) { - mFirstDayOfMonth.set(mTempTime) - mFirstDayOfMonth.monthDay = 1 - millis = mFirstDayOfMonth.normalize(true) - setMonthDisplayed(mFirstDayOfMonth, true) - position = Utils.getWeeksSinceEpochFromJulianDay( - Time.getJulianDay(millis, mFirstDayOfMonth.gmtoff), mFirstDayOfWeek) - mPreviousScrollState = OnScrollListener.SCROLL_STATE_FLING - if (animate) { - mListView?.smoothScrollToPositionFromTop( - position, LIST_TOP_OFFSET, GOTO_SCROLL_DURATION) - return true - } else { - mListView?.setSelectionFromTop(position, LIST_TOP_OFFSET) - // Perform any after scroll operations that are needed - onScrollStateChanged(mListView, OnScrollListener.SCROLL_STATE_IDLE) - } - } else if (setSelected) { - // Otherwise just set the selection - setMonthDisplayed(mSelectedDay, true) - } - return false - } - - /** - * Updates the title and selected month if the view has moved to a new - * month. - */ - @Override - override fun onScroll( - view: AbsListView, - firstVisibleItem: Int, - visibleItemCount: Int, - totalItemCount: Int - ) { - val child = view.getChildAt(0) as? SimpleWeekView - if (child == null) { - return - } - - // Figure out where we are - val currScroll: Long = (view.getFirstVisiblePosition() * child.getHeight() - - child.getBottom()).toLong() - mFirstVisibleDay.setJulianDay(child.getFirstJulianDay()) - - // If we have moved since our last call update the direction - mIsScrollingUp = if (currScroll < mPreviousScrollPosition) { - true - } else if (currScroll > mPreviousScrollPosition) { - false - } else { - return - } - mPreviousScrollPosition = currScroll - mPreviousScrollState = mCurrentScrollState - updateMonthHighlight(mListView as? AbsListView) - } - - /** - * Figures out if the month being shown has changed and updates the - * highlight if needed - * - * @param view The ListView containing the weeks - */ - private fun updateMonthHighlight(view: AbsListView?) { - var child = view?.getChildAt(0) as? SimpleWeekView - if (child == null) { - return - } - - // Figure out where we are - val offset = if (child?.getBottom() < WEEK_MIN_VISIBLE_HEIGHT) 1 else 0 - // Use some hysteresis for checking which month to highlight. This - // causes the month to transition when two full weeks of a month are - // visible. - child = view?.getChildAt(SCROLL_HYST_WEEKS + offset) as? SimpleWeekView - if (child == null) { - return - } - - // Find out which month we're moving into - val month: Int - month = if (mIsScrollingUp) { - child?.getFirstMonth() - } else { - child?.getLastMonth() - } - - // And how it relates to our current highlighted month - val monthDiff: Int - monthDiff = if (mCurrentMonthDisplayed == 11 && month == 0) { - 1 - } else if (mCurrentMonthDisplayed == 0 && month == 11) { - -1 - } else { - month - mCurrentMonthDisplayed - } - - // Only switch months if we're scrolling away from the currently - // selected month - if (monthDiff != 0) { - var julianDay: Int = child.getFirstJulianDay() - if (mIsScrollingUp) { - // Takes the start of the week - } else { - // Takes the start of the following week - julianDay += DAYS_PER_WEEK - } - mTempTime.setJulianDay(julianDay) - setMonthDisplayed(mTempTime, false) - } - } - - /** - * Sets the month displayed at the top of this view based on time. Override - * to add custom events when the title is changed. - * - * @param time A day in the new focus month. - * @param updateHighlight TODO(epastern): - */ - protected open fun setMonthDisplayed(time: Time, updateHighlight: Boolean) { - val oldMonth: CharSequence = mMonthName!!.getText() - mMonthName?.setText(Utils.formatMonthYear(mContext, time)) - mMonthName?.invalidate() - if (!TextUtils.equals(oldMonth, mMonthName?.getText())) { - mMonthName?.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED) - } - mCurrentMonthDisplayed = time.month - if (updateHighlight) { - mAdapter?.updateFocusMonth(mCurrentMonthDisplayed) - } - } - - @Override - override fun onScrollStateChanged(view: AbsListView?, scrollState: Int) { - // use a post to prevent re-entering onScrollStateChanged before it - // exits - mScrollStateChangedRunnable.doScrollStateChange(view, scrollState) - } - - @JvmField protected var mScrollStateChangedRunnable: ScrollStateRunnable = ScrollStateRunnable() - - protected inner class ScrollStateRunnable : Runnable { - private var mNewState = 0 - - /** - * Sets up the runnable with a short delay in case the scroll state - * immediately changes again. - * - * @param view The list view that changed state - * @param scrollState The new state it changed to - */ - fun doScrollStateChange(view: AbsListView?, scrollState: Int) { - mHandler.removeCallbacks(this) - mNewState = scrollState - mHandler.postDelayed(this, SCROLL_CHANGE_DELAY.toLong()) - } - - override fun run() { - mCurrentScrollState = mNewState - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, - "new scroll state: $mNewState old state: $mPreviousScrollState") - } - // Fix the position after a scroll or a fling ends - if (mNewState == OnScrollListener.SCROLL_STATE_IDLE && - mPreviousScrollState != OnScrollListener.SCROLL_STATE_IDLE) { - mPreviousScrollState = mNewState - mAdapter?.updateFocusMonth(mCurrentMonthDisplayed) - } else { - mPreviousScrollState = mNewState - } - } - } - - companion object { - private const val TAG = "MonthFragment" - private const val KEY_CURRENT_TIME = "current_time" - - // Affects when the month selection will change while scrolling up - protected const val SCROLL_HYST_WEEKS = 2 - - // How long the GoTo fling animation should last - @JvmStatic protected val GOTO_SCROLL_DURATION = 500 - - // How long to wait after receiving an onScrollStateChanged notification - // before acting on it - protected const val SCROLL_CHANGE_DELAY = 40 - - // The number of days to display in each week - const val DAYS_PER_WEEK = 7 - - // The size of the month name displayed above the week list - protected const val MINI_MONTH_NAME_TEXT_SIZE = 18 - var LIST_TOP_OFFSET = -1 // so that the top line will be under the separator - private var mScale = 0f - } - - init { - goTo(initialTime, false, true, true) - mHandler = Handler() - } -}
\ No newline at end of file |