summaryrefslogtreecommitdiff
path: root/src/com/android/calendar/month/SimpleDayPickerFragment.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/calendar/month/SimpleDayPickerFragment.kt')
-rw-r--r--src/com/android/calendar/month/SimpleDayPickerFragment.kt616
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