Closed kaspychala closed 3 years ago
Please provide a sample repository that showcases the issue.
Can't, because it's company repo, but I can provide you classes from package and xml for layout.
class ScheduleFragment : BaseFragment<ScheduleViewModel, FragmentScheduleBinding>() {
override val layoutRes = R.layout.fragment_schedule
override val bindingVariable = BR.viewModel
override val viewModelClass = ScheduleViewModel::class.java
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.getUserTimetable()
viewModel.repository.isUserTimetableResultFetched.observe(viewLifecycleOwner, Observer {
viewModel.getBuildingsDetails()
})
viewModel.repository.isBuildingResultFetched.observe(viewLifecycleOwner, Observer {
viewModel.getLecturersDetails()
})
viewModel.repository.timetable.observe(viewLifecycleOwner, Observer { timetables->
timetables.forEach { timetable->
Timber.d("${timetable.courseName} - ${timetable.startTime}, ${timetable.endTime} - ${timetable.building?.name}, ${timetable.roomNumber}")
timetable.lecturers.forEach { lecturer ->
Timber.d("${lecturer?.firstName} ${lecturer?.lastName} - ${lecturer?.profileUrl}")
}
}
setUpView()
})
}
override fun showApiProgressLoading() {
//
}
private fun setUpView() {
setUpSpinner()
setUpWeekCalendar()
}
private fun setUpSpinner() {
ArrayAdapter.createFromResource(
requireContext(),
R.array.schedule_calendar_modes,
android.R.layout.simple_spinner_item
).also { adapter ->
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinner_calendar_modes.adapter = adapter
}
spinner_calendar_modes.onItemSelectedListener =
object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>,
view: View?,
pos: Int,
id: Long
) {
handleHeaderOnSpinnerItemSelected(pos)
}
override fun onNothingSelected(parent: AdapterView<*>) {}
}
spinner_calendar_modes.setSelection(ScheduleCalendarMode.DAILY.value)
}
private fun handleHeaderOnSpinnerItemSelected(pos: Int) {
when (pos) {
ScheduleCalendarMode.DAILY.value -> {
calendar_week_view.maxDate = Calendar.getInstance().apply { time = viewModel.currentDate }
calendar_week_view.minDate = Calendar.getInstance().apply { time = viewModel.currentDate }
calendar_week_view.numberOfVisibleDays = 1
}
ScheduleCalendarMode.WEEKLY.value -> {
val rangedDate = Calendar.getInstance().apply {
time = Date.from(
Instant.from(
viewModel.currentDate.toInstant().atZone(ZoneId.systemDefault())
.toLocalDate()
.with(
TemporalAdjusters.previousOrSame( DayOfWeek.MONDAY )
)
.atStartOfDay(ZoneId.systemDefault())
)
)
}
calendar_week_view.minDate = rangedDate
rangedDate.add(Calendar.DATE, 4)
calendar_week_view.maxDate = rangedDate
calendar_week_view.numberOfVisibleDays = 5
}
ScheduleCalendarMode.SET_WEEK.value -> {
//
}
}
}
//TODO: Refreshing fragment on WeekView mode crashing app
private fun setUpWeekCalendar() {
val adapter = object : WeekView.SimpleAdapter<Timetable>() {
override fun onCreateEntity(item: Timetable): WeekViewEntity {
return handleWeekCalendarOnCreateEntity(item)
}
}
calendar_week_view.adapter = adapter
viewModel.repository.timetable.value?.let {
adapter.submitList(it)
}
calendar_week_view.setTimeFormatter {
val date = Calendar.getInstance().apply {
set(Calendar.HOUR_OF_DAY, it)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}
viewModel.timeFormatter.format(date.time)
}
}
private fun handleWeekCalendarOnCreateEntity(item: Timetable): WeekViewEntity {
val backgroundColor = ContextCompat.getColor(requireContext(), R.color.colorPrimary)
val textColor = Color.WHITE
val style = WeekViewEntity.Style.Builder()
.setTextColor(textColor)
.setBackgroundColor(backgroundColor)
.setBorderWidth(2)
.setBorderColor(backgroundColor)
.build()
val title = SpannableStringBuilder(item.courseName).apply {
val titleSpan = TypefaceSpan("sans-serif-medium")
setSpan(titleSpan, 0, item.courseName.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
val subtitle = SpannableStringBuilder(item.building?.name)
return WeekViewEntity.Event.Builder(item)
.setId(item.unitId.toLong())
.setTitle(title)
.setStartTime(item.startTime)
.setEndTime(item.endTime)
.setSubtitle(subtitle)
.setAllDay(false)
.setStyle(style)
.build()
}
}
class ScheduleViewModel @Inject constructor(
var repository: USOSTimetableRepository
) : BaseViewModel() {
private val _text = MutableLiveData<String>().apply {
value = "This is schedule fragment"
}
val text: LiveData<String> = _text
private val is24HourFormat = DateFormat.is24HourFormat(App.applicationContext())
val timeFormatter = if (is24HourFormat) {
SimpleDateFormat("HH:mm", Locale.getDefault()).apply {
timeZone = TimeZone.getTimeZone(ZoneId.systemDefault())
}
} else {
SimpleDateFormat("hh:mm a", Locale.getDefault()).apply {
timeZone = TimeZone.getTimeZone(ZoneId.systemDefault())
}
}
var currentDate: Date = Date()
fun getUserTimetable(){
repository.getUserTimetable()
}
fun getBuildingsDetails() {
repository.getBuildingsDetails()
}
fun getLecturersDetails() {
repository.getLecturersDetails()
}
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="pl.americansystems.smartuj.ui.mobileusos.schedule.ScheduleViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_header"
android:layout_width="match_parent"
android:layout_height="100dp"
app:layout_constraintBottom_toTopOf="@id/cl_calendar_week_view_frame"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.text}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/spinner_calendar_modes"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Spinner
android:id="@+id/spinner_calendar_modes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/tv_title"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_calendar_week_view_frame"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cl_header">
<com.alamkanak.weekview.WeekView
android:id="@+id/calendar_week_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:adaptiveEventTextSize="true"
app:allDayEventTextSize="13sp"
app:columnGap="6dp"
app:eventCornerRadius="4dp"
app:eventMarginVertical="2dp"
app:eventPaddingHorizontal="4dp"
app:eventPaddingVertical="5dp"
app:eventTextSize="13sp"
app:headerBottomShadowRadius="1dp"
app:headerPadding="8dp"
app:headerTextColor="@color/colorPrimary"
app:hourHeight="60dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:nowLineDotRadius="5dp"
app:nowLineStrokeWidth="2dp"
app:numberOfVisibleDays="7"
app:overlappingEventGap="1dp"
app:showCurrentTimeFirst="true"
app:showHeaderBottomShadow="true"
app:showNowLine="true"
app:showNowLineDot="true"
app:showTimeColumnSeparator="true"
app:showWeekNumber="false"
app:singleDayHorizontalPadding="8dp"
app:timeColumnPadding="16dp"
app:timeColumnSeparatorStrokeWidth="1dp"
app:timeColumnTextColor="@color/colorPrimary"
app:timeColumnTextSize="12sp"
app:todayHeaderTextColor="@color/colorAccent"
app:weekNumberBackgroundCornerRadius="8dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
For me it looks like it want to add same element in the same time section, but it can't fit another entry and it's crashing. Maybe it should skip drawing element with same id? Best solution will be to have method that will clear drawn entries before submitting new list, I think.
Can't, because it's company repo
You don’t need to share the original repo. Create a new sample project (probably with sample data) that showcases the crash. Then, I can run it and see for myself.
https://github.com/kaspychala/WeekViewBugDescription
So I changed your sample app and played with WithFragmentActivity a little, now there is a handler that submits list again after some time. What is strange crash isn't happening now, but entries are disappearing. Even after submitting third list view isn't redrawing/adding new elements.
The issue you’re seeing is actually an issue in the sample app, not in the library itself. The Calendar
objects that are passed in to EventsDatabase#getEventsInRange(start, end)
(here) are actually assigned different values within that method (see here). As a result, the second and third lists that are submitted contain no events. I’m updating the sample app to be less confusing.
As for the IllegalArgumentException
mentioned at the top: I can’t fix the issue without being able to reproduce it. For that, I’d need you to provide me a sample app where this issue occurs.
Describe the bug After submitting list again in adapter application is crashing with error:
java.lang.IllegalArgumentException: Layout: -2 < 0
incom.alamkanak.weekview.TextExtensionsKt.toTextLayout(TextExtensions.kt:29)
To Reproduce Steps to reproduce the behavior:
Screenshots
Code to show content in WeekView
function setUpWeekCalendar() is called after fetching data. Fetching data again by going back to fragment causing app to crash.
Maybe there is another way to refresh layout with new data but I'm aware of it?
Thanks for any help!
Additional context