thellmund / Android-Week-View

Display highly customizable calendar views in your Android app
Apache License 2.0
188 stars 97 forks source link

Screen rotation - WeekView goes to today #54

Closed BorysChajdas closed 5 years ago

BorysChajdas commented 5 years ago

EDIT: Look at comments because there is a real bug. When you rotate your device WeekView goes to today. Is there an option to prevent WeekView from this? Should I do it manually? In my opinion it is a bug and it shouldn't goes to today automatically.

Steps to reproduce:

  1. Scroll to any date other than today.
  2. Rotate your device.
  3. Date has changed to today.
cs8898 commented 5 years ago

Oh i know that, but it is not a lib problem, more a Android thing https://stackoverflow.com/questions/7618703/activity-lifecycle-oncreate-called-on-every-re-orientation

You have to do a manual save Eg store the current date after an scroll and reload it from config, clear the config when you are closeing the app

Check out the lifecycle model...

BorysChajdas commented 5 years ago

@cs8898 Thanks, I have a question, have you done this using this library? Do you had any problems? I done this, the date is saved and restored after rotation but there is a problem, the scroll is trigerred or something and sometimes date jump to next or previous day... Look at the screenshot: Screenshot_20190420-001828

This problem exist only when you are on other day then today.

cs8898 commented 5 years ago

@thellmund, is there any known bug in scroll to date? Sounds like one of my Bugs with the floating point...

If i got you correctly scrolling programatically to any date in the past or future will generate a not that correct date alignement on the screen?

Or what do you explicitly mean with

the scroll is trigerred or something and sometimes date jump to next or previous day

Or interpretation no 2 You wanna block scrolling to other dates

The lib is more compareable to an calendar with endless scroll... Or use the limiting methods (some pr i did myselfe) to limit the scroll only to the above currently showing date... That wouldn't be efficient in caching and probably not that fast at drawing but should block scrolling (In Theory setting minDate and maxDate to the stored value will only display that day)

BorysChajdas commented 5 years ago

@cs8898 I will explain you what I done: I have a WeekViewWrapper class which is Singleton with attachWeekView and detachWeekView methods:

    private var weekView: WeekView<ReservationItem>? = null

    var savedDate: Calendar = Calendar.getInstance()

    fun attachWeekView(weekViewToAttach: WeekView<ReservationItem>) {
        weekView = weekViewToAttach
        prepareWeekView()
    }
    fun detachWeekView() {
        savedDate = weekView!!.firstVisibleDay
        weekView = null
    }
    private fun prepareWeekView() {
        weekView?.goToDate(savedDate)
        weekView?.goToHour(STARTING_HOUR)
    }

So when WeekView is attached it runs goToDate method with savedDate argument, when WeekView is detached it saves the firstVisibleDay. In my Activity in onCreate I'm calling this method:

    private fun initializeWeekView() {
        weekView = findViewById(R.id.weekView)
        weekView.setMonthChangeListener(oneDayViewModel)
        weekView.scrollListener = this
        weekViewWrapper.attachWeekView(weekView)
    }

And onDestroy:

    override fun onDestroy() {
        weekViewWrapper.detachWeekView()
        super.onDestroy()
    }

And yes, this is partially working because the date is saved and restored. The problem is that there is this gray line on screen (indicating scroll) you know what I'm taking about? In addition, when I rotate few times it jump to next/previous day, or sometimes few days. When I'm using goToDate method in other situations for example with buttons it is working okay.

I don't want to block scrolling or something. The problem is that app is scrolling by itself (screenshot).

cs8898 commented 5 years ago

I have some sort of idea... What is going wrong

And also some solutions

  1. Force Orientation for Activity
  2. Dont store the first visible date, use your header informations (see below)
  3. Clone the repo and try some bug hounting, it should be in the origin calculations, at least thats where my problems occure (oneplus 5t)

I should check some stuff, but you can try to set the size of the view at least for testing to a fixed width as pixels

I had a similar bug with traveling "lines" during switching between multiple view modes (single day, two days)

In my case the calculation in floating point lead to a growing computation error and flipped the displayed date (but that was like scrolling 2Year to the future)

The traveling line one should have a similar origin

Flinging also is a tricky thing its like you can only fling to Int but the canvas is aligned with floats... (see #38)

The flip will occure after you moved a bit too far, firstVisibleDate is the most left Day and that could also be a date just displaying with 3px on the most left...

BorysChajdas commented 5 years ago
  1. Unfortunately, I need both orientations
  2. I tried this, it changed nothing...
  3. Yeah, it should do the job but my android programming skills are too weak for this I think

Thanks for advice, I will try to fix it somehow. Maybe @thellmund will know something about this bug.

BorysChajdas commented 5 years ago

Changing From:

    fun attachWeekView(weekViewToAttach: WeekView<ReservationItem>) {
        weekView = weekViewToAttach
        prepareWeekView()
    }

To:

    fun attachWeekView(weekViewToAttach: WeekView<ReservationItem>) {
        weekView = weekViewToAttach
        // FIXME it's not a solution...
        Handler().postDelayed({
            prepareWeekView()
        }, 200)
    }

It's do the job... not a good solution but for now it is some workaround. Probably there is a problem when goToDate method is called on a newly created object (after 200ms it is OK).

cs8898 commented 5 years ago

You can try onResume and onPause, that should already have a completly build layout

BorysChajdas commented 5 years ago

Yeah, I try all this methods already, unfortunately it didn't do the job...

thellmund commented 5 years ago

I’ve pushed a commit (b3e4eaf7b9ee01f99f8a5aa52000a5ac59abe94e) that should address your problem, @VEndymionV. It stores the first visible day when onSaveInstanceState() is called and retrieves it in onRestoreInstanceState(). Please give it a go and let me know if anything is still wrong. I’ll close this issue for now.

BorysChajdas commented 5 years ago

@thellmund Thank you for your interest in the matter, unfortunetly there is still a problem. I noticed two things:

  1. The "gray line" disappeared but there is still a problem that sometimes (when you perform a few rotations in a row) days are changing by itself. You are for example on 29.04.2019, rotate the device and its jump to today or to 12.05.2019...
  2. I had this method:
    private fun moveActualDayBy(amount: Int) {
        weekView?.run {
            val oldFirstVisibleDay = firstVisibleDay
            firstVisibleDay.add(Calendar.DAY_OF_MONTH, amount)
            goToDate(firstVisibleDay)
            scrollListener.onFirstVisibleDayChanged(oldFirstVisibleDay, firstVisibleDay)
        }
    }

    It was working before latest commit but now firstVisibleDay.add(Calendar.DAY_OF_MONTH, amount) does nothing. So I changed it to:

    private fun moveActualDayBy(amount: Int) {
        weekView?.run {
            val oldFirstVisibleDay = firstVisibleDay
            val newFirstVisibleDay = firstVisibleDay
            newFirstVisibleDay.add(Calendar.DAY_OF_MONTH, amount)
            goToDate(newFirstVisibleDay)
            scrollListener.onFirstVisibleDayChanged(oldFirstVisibleDay, newFirstVisibleDay)
        }
    }

    Now it is working but there is still a problem described in first point. I was thinking that maybe that scrollListener call is causing this so I removed it (scrollListener is updating my header date textView) but it nothing changed.

thellmund commented 5 years ago

I can’t reproduce the issue that multiple rotations lead to days changing by themselves. Please provide me with an example (a video or better a SSCCE).

BorysChajdas commented 5 years ago

@thellmund Okay, I checked it few times, sometimes after 2 rotations, sometimes after 20 the days are changing. I will provide more details (video or SSCCE like you said), thanks.

BorysChajdas commented 5 years ago

@thellmund At this moment I can only show you the video: https://youtu.be/a2Jun_7Yp1s I'm using latest commit version.

jcogilvie commented 5 years ago

I have a bug that I think is related.

Thus far, I have had to manually persist the first visible day in onFirstVisibleDayChanged, something like this:

        // if somebody has init'd firstVisibleDay, use it
        viewModel.firstVisibleDay?.run {
            Handler().postDelayed({
                weekView.goToDate(toGregorianCalendar())
                weekView.goToHour(hourOfDay)
            }, 200)
        // failing that, check our arguments for a desired day
        } ?: arguments?.run {
            getString(ARG_START_DATE)?.let {
                val startDate = DateTime.parse(it)

                Handler().postDelayed({
                    weekView.goToDate(startDate.toGregorianCalendar())
                    weekView.goToHour(startDate.hourOfDay)
                }, 200)
            }
        // if nothing in the args, use today
        } ?: run {
            weekView.goToCurrentTime()
        }

    override fun onFirstVisibleDayChanged(newFirstVisibleDay: Calendar, oldFirstVisibleDay: Calendar?) {
        viewModel.firstVisibleDay = DateTime(newFirstVisibleDay)
    }

With that code, I'm able to retain the first visible day for most cases while handling a different initial value (e.g. from a notification/fragment args). However...

I can reproduce what seems like a "drift" issue--it doesn't seem to be actually drifting so much as an issue with not receiving the correct onFirstVisibleDayChanged callback when the velocity-based snap behavior pulls the calendar onto a different day when the fling was released earlier than half-way through the column representing a day.

thellmund commented 5 years ago

@jcogilvie I can’t reproduce the rotation issues, but I can reproduce the issue of not receiving the correct onFirstVisibleDayChanged() callback. I’ll try to have a look at in the coming week.

BorysChajdas commented 5 years ago

@thellmund Please clone this repo: https://github.com/VEndymionV/AndroidWeekViewRotationBug If you change date from today and rotate few times you should reproduce my bug (date is changing by itself).