diff --git a/CHANGELOG.md b/CHANGELOG.md index f7870902d..d115460d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Widget for weekly view ([#470]) ## [1.10.2] - 2026-02-04 ### Fixed diff --git a/app/detekt-baseline.xml b/app/detekt-baseline.xml index 65084db15..95c34e10c 100644 --- a/app/detekt-baseline.xml +++ b/app/detekt-baseline.xml @@ -16,7 +16,6 @@ ComplexCondition:SettingsActivity.kt$SettingsActivity$requestCode == PICK_SETTINGS_IMPORT_SOURCE_INTENT && resultCode == RESULT_OK && resultData != null && resultData.data != null ComplexCondition:TaskActivity.kt$TaskActivity$config.wasAlarmWarningShown || (mReminder1Minutes == REMINDER_OFF && mReminder2Minutes == REMINDER_OFF && mReminder3Minutes == REMINDER_OFF) ComplexCondition:TaskActivity.kt$TaskActivity$day == MONDAY_BIT || day == TUESDAY_BIT || day == WEDNESDAY_BIT || day == THURSDAY_BIT || day == FRIDAY_BIT || day == SATURDAY_BIT || day == SUNDAY_BIT - ComplexCondition:WeekFragment.kt$WeekFragment$doesEventFit && (!isRepeatingOverlappingEvent || isAllDayEvent || isRowValidForEvent) ConstructorParameterNaming:Task.kt$Task$@ColumnInfo(name = "task_id") var task_id: Long CyclomaticComplexMethod:CalDAVHelper.kt$CalDAVHelper$@SuppressLint("MissingPermission") private fun fetchCalDAVCalendarEvents( calendar: CalDAVCalendar, localCalendarId: Long, showToasts: Boolean, ) CyclomaticComplexMethod:Context.kt$@SuppressLint("NewApi") fun Context.getNotification( pendingIntent: PendingIntent, event: Event, content: String, publicVersion: Boolean = false ): Notification? @@ -45,8 +44,8 @@ CyclomaticComplexMethod:TaskActivity.kt$TaskActivity$private fun getOrderString(repeatRule: Int): String CyclomaticComplexMethod:TaskActivity.kt$TaskActivity$private fun gotTask(savedInstanceState: Bundle?, localCalendar: CalendarEntity?, task: Event?) CyclomaticComplexMethod:TaskActivity.kt$TaskActivity$private fun saveTask() - CyclomaticComplexMethod:WeekFragment.kt$WeekFragment$@SuppressLint("NewApi") private fun addAllDayEvent(event: Event) - CyclomaticComplexMethod:WeekFragment.kt$WeekFragment$private fun addEvents(events: ArrayList<Event>) + CyclomaticComplexMethod:WeekFragment.kt$WeekFragment$@SuppressLint("NewApi") private fun addAllDayEvent(dayOfWeek: Int, event: Event) + CyclomaticComplexMethod:WeekFragment.kt$WeekFragment$private fun addDays(days: ArrayList<DayWeekly>) EmptyCatchBlock:EventsHelper.kt$EventsHelper${ } EmptyCatchBlock:MainActivity.kt$MainActivity${ } EmptyFunctionBlock:DayEventsAdapter.kt$DayEventsAdapter${} @@ -79,7 +78,7 @@ LongMethod:EventActivity.kt$EventActivity$private fun saveEvent() LongMethod:IcsImporter.kt$IcsImporter$fun importEvents( path: String, defaultCalendarId: Long, calDAVCalendarId: Int, overrideFileCalendars: Boolean, eventReminders: ArrayList<Int>? = null, loadFromAssets: Boolean = false, ): ImportResult LongMethod:MyTimeZones.kt$fun getAllTimeZones() - LongMethod:WeekFragment.kt$WeekFragment$private fun addEvents(events: ArrayList<Event>) + LongMethod:WeekFragment.kt$WeekFragment$private fun addDays(days: ArrayList<DayWeekly>) LongParameterList:SelectCalendarDialog.kt$SelectCalendarDialog$( val activity: Activity, val currCalendar: Long, val showCalDAVCalendars: Boolean, val showNewCalendarOption: Boolean, val addLastUsedOneAsFirstOption: Boolean, val showOnlyWritable: Boolean, var showManageCalendars: Boolean, val callback: (calendar: CalendarEntity) -> Unit ) LoopWithTooManyJumpStatements:IcsImporter.kt$IcsImporter$while LoopWithTooManyJumpStatements:ManageCalendarsAdapter.kt$ManageCalendarsAdapter$for @@ -173,6 +172,7 @@ MagicNumber:MyWidgetMonthlyProvider.kt$MyWidgetMonthlyProvider$7 MagicNumber:MyWidgetMonthlyProvider.kt$MyWidgetMonthlyProvider.<no name provided>$3f MagicNumber:MyWidgetMonthlyProvider.kt$MyWidgetMonthlyProvider.<no name provided>$6 + MagicNumber:MyWidgetWeeklyProvider.kt$MyWidgetWeeklyProvider$3 MagicNumber:NotificationReceiver.kt$NotificationReceiver$3000 MagicNumber:Parser.kt$Parser$14 MagicNumber:Parser.kt$Parser$24 @@ -242,6 +242,9 @@ MagicNumber:WidgetMonthlyConfigureActivity.kt$WidgetMonthlyConfigureActivity$255f MagicNumber:WidgetMonthlyConfigureActivity.kt$WidgetMonthlyConfigureActivity$3 MagicNumber:WidgetMonthlyConfigureActivity.kt$WidgetMonthlyConfigureActivity$7 + MagicNumber:WidgetWeeklyConfigureActivity.kt$WidgetWeeklyConfigureActivity$100 + MagicNumber:WidgetWeeklyConfigureActivity.kt$WidgetWeeklyConfigureActivity$100f + MagicNumber:WidgetWeeklyConfigureActivity.kt$WidgetWeeklyConfigureActivity$255f MagicNumber:YearFragment.kt$YearFragment$12 MagicNumber:YearFragmentsHolder.kt$YearFragmentsHolder$100000 MagicNumber:YearFragmentsHolder.kt$YearFragmentsHolder$61 @@ -363,11 +366,7 @@ MaxLineLength:TaskActivity.kt$TaskActivity$if (usePreviousEventReminders && lastEventReminderMinutes1 >= -1) lastEventReminderMinutes1 else defaultReminder1 MaxLineLength:TaskActivity.kt$TaskActivity$if (usePreviousEventReminders && lastEventReminderMinutes2 >= -1) lastEventReminderMinutes2 else defaultReminder2 MaxLineLength:TaskActivity.kt$TaskActivity$if (usePreviousEventReminders && lastEventReminderMinutes3 >= -1) lastEventReminderMinutes3 else defaultReminder3 - MaxLineLength:WeekFragment.kt$WeekFragment$((currentEventWeeklyView.range.upper - currentEventWeeklyView.range.lower) * minuteHeight).toInt() - 1 - MaxLineLength:WeekFragment.kt$WeekFragment$// fix a visual glitch with all-day events or events lasting multiple days starting at midnight on monday, being shown the previous week too MaxLineLength:WeekFragment.kt$WeekFragment$// we need to refresh all fragments because they can contain future occurrences - MaxLineLength:WeekFragment.kt$WeekFragment$dayColumns.indexOfFirst { it.tag.toInt() == dayCodeStart || it.tag.toInt() in (dayCodeStart + 1)..dayCodeEnd } - MaxLineLength:WeekFragment.kt$WeekFragment$eventWeeklyView.range.upper > eventWeeklyViewToCheck.range.lower MaxLineLength:WeekFragmentsHolder.kt$WeekFragmentsHolder$binding.weekViewDaysCount.text = requireContext().resources.getQuantityString(org.fossify.commons.R.plurals.days, cnt, cnt) MaxLineLength:WidgetDateConfigureActivity.kt$WidgetDateConfigureActivity$if MaxLineLength:WidgetListConfigureActivity.kt$WidgetListConfigureActivity$EventListAdapter(this@WidgetListConfigureActivity, getListItems(), false, null, configWidgetPreview.configEventsList) {} @@ -396,11 +395,11 @@ NestedBlockDepth:MainActivity.kt$MainActivity$private fun checkIsViewIntent() NestedBlockDepth:MonthView.kt$MonthView$override fun onDraw(canvas: Canvas) NestedBlockDepth:MyWidgetMonthlyProvider.kt$MyWidgetMonthlyProvider$private fun updateDays(context: Context, views: RemoteViews, days: List<DayMonthly>) + NestedBlockDepth:MyWidgetWeeklyProvider.kt$MyWidgetWeeklyProvider$private fun updateDays(context: Context, views: RemoteViews) NestedBlockDepth:Parser.kt$Parser$fun parseRepeatInterval(fullString: String, startTS: Long): EventRepetition NestedBlockDepth:SettingsActivity.kt$SettingsActivity$private fun parseFile(inputStream: InputStream?) NestedBlockDepth:SmallMonthView.kt$SmallMonthView$override fun onDraw(canvas: Canvas) - NestedBlockDepth:WeekFragment.kt$WeekFragment$@SuppressLint("NewApi") private fun addAllDayEvent(event: Event) - NestedBlockDepth:WeekFragment.kt$WeekFragment$private fun addEvents(events: ArrayList<Event>) + NestedBlockDepth:WeekFragment.kt$WeekFragment$private fun addDays(days: ArrayList<DayWeekly>) ReturnCount:HsvColorComparator.kt$HsvColorComparator$override fun compare(lhs: Int?, rhs: Int?): Int SwallowedException:CalDAVHelper.kt$CalDAVHelper$e: Exception SwallowedException:Converters.kt$Converters$e: Exception @@ -447,6 +446,7 @@ TooManyFunctions:WeekFragmentsHolder.kt$WeekFragmentsHolder : MyFragmentHolderWeekFragmentListener TooManyFunctions:WidgetListConfigureActivity.kt$WidgetListConfigureActivity : SimpleActivity TooManyFunctions:WidgetMonthlyConfigureActivity.kt$WidgetMonthlyConfigureActivity : SimpleActivityMonthlyCalendar + TooManyFunctions:WidgetWeeklyConfigureActivity.kt$WidgetWeeklyConfigureActivity : SimpleActivityWeeklyCalendar TooManyFunctions:YearFragmentsHolder.kt$YearFragmentsHolder : MyFragmentHolderNavigationListener UnusedPrivateProperty:YearlyCalendarImpl.kt$YearlyCalendarImpl$i VariableNaming:CalendarPickerActivity.kt$CalendarPickerActivity$private val TYPE_EVENT = 0 @@ -503,6 +503,8 @@ WildcardImport:MyWidgetListProvider.kt$import org.fossify.commons.extensions.* WildcardImport:MyWidgetMonthlyProvider.kt$import org.fossify.calendar.extensions.* WildcardImport:MyWidgetMonthlyProvider.kt$import org.fossify.commons.extensions.* + WildcardImport:MyWidgetWeeklyProvider.kt$import org.fossify.calendar.extensions.* + WildcardImport:MyWidgetWeeklyProvider.kt$import org.fossify.commons.extensions.* WildcardImport:Parser.kt$import org.fossify.commons.helpers.* WildcardImport:ReminderWarningDialog.kt$import org.fossify.commons.extensions.* WildcardImport:RepeatLimitTypePickerDialog.kt$import org.fossify.commons.extensions.* @@ -513,5 +515,6 @@ WildcardImport:WidgetListConfigureActivity.kt$import org.fossify.commons.extensions.* WildcardImport:WidgetListConfigureActivity.kt$import org.fossify.commons.helpers.* WildcardImport:WidgetMonthlyConfigureActivity.kt$import org.fossify.commons.extensions.* + WildcardImport:WidgetWeeklyConfigureActivity.kt$import org.fossify.commons.extensions.* diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7c6cbf715..16b4a2c9a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -94,6 +94,17 @@ + + + + + + + + + + + + + + + = ArrayList() + private var earliestEventStartHour = 0 + private var latestEventEndHour = WeeklyCalendarImpl.HOURS_PER_DAY + + private var mBgAlpha = 0f + private var mWidgetId = 0 + private var mBgColorWithoutTransparency = 0 + private var mBgColor = 0 + private var mTextColor = 0 + + private val binding by viewBinding(WidgetConfigWeeklyBinding::inflate) + + public override fun onCreate(savedInstanceState: Bundle?) { + useDynamicTheme = false + super.onCreate(savedInstanceState) + setResult(RESULT_CANCELED) + setContentView(binding.root) + setupEdgeToEdge(padTopSystem = listOf(binding.configHolder), padBottomSystem = listOf(binding.root)) + initVariables() + + val isCustomizingColors = intent.extras?.getBoolean(IS_CUSTOMIZING_COLORS) ?: false + mWidgetId = intent.extras?.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID) ?: AppWidgetManager.INVALID_APPWIDGET_ID + + if (mWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID && !isCustomizingColors) { + finish() + } + + val primaryColor = getProperPrimaryColor() + binding.apply { + configSave.setOnClickListener { saveConfig() } + configBgColor.setOnClickListener { pickBackgroundColor() } + configTextColor.setOnClickListener { pickTextColor() } + configBgSeekbar.setColors(mTextColor, primaryColor, primaryColor) + } + setupDayLabels() + setupDayColumns() + } + + private fun initVariables() { + mBgColor = config.widgetBgColor + mBgAlpha = Color.alpha(mBgColor) / 255f + + mBgColorWithoutTransparency = Color.rgb(Color.red(mBgColor), Color.green(mBgColor), Color.blue(mBgColor)) + binding.configBgSeekbar.apply { + progress = (mBgAlpha * 100).toInt() + + onSeekBarChangeListener { progress -> + mBgAlpha = progress / 100f + updateBackgroundColor() + } + } + updateBackgroundColor() + + mTextColor = config.widgetTextColor + if (mTextColor == resources.getColor(R.color.default_widget_text_color) && isDynamicTheme()) { + mTextColor = resources.getColor(R.color.you_primary_color, theme) + } + + updateTextColor() + + WeeklyCalendarImpl(this, this).updateWeeklyCalendar(DateTime()) + } + + private fun saveConfig() { + storeWidgetColors() + requestWidgetUpdate() + + Intent().apply { + putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mWidgetId) + setResult(RESULT_OK, this) + } + finish() + } + + private fun storeWidgetColors() { + config.apply { + widgetBgColor = mBgColor + widgetTextColor = mTextColor + } + } + + private fun setupDayLabels() { + val dayLetters = resources.getStringArray(org.fossify.commons.R.array.week_days_short) + .toMutableList() as ArrayList + binding.configCalendar.weekLettersHolder.apply { + removeAllViews() + val smallerFontSize = context.getWidgetFontSize() + var curDay = context.getFirstDayOfWeekDt(DateTime()) + for (i in 0 until config.weeklyViewDays) { + val dayLetter = dayLetters[curDay.dayOfWeek - 1] + + val newView = WidgetWeekDayLetterBinding.inflate( + layoutInflater, + binding.configCalendar.weekLettersHolder, + false + ).root + newView.text = dayLetter + newView.setTextColor(mTextColor) + newView.textSize = smallerFontSize + addView(newView) + curDay = curDay.plusDays(1) + } + } + } + + private fun setupDayColumns() { + binding.configCalendar.weekEventsDayLines.removeAllViews() + // columns that will contain events + binding.configCalendar.weekEventsColumnsHolder.apply { + removeAllViews() + for (i in 0 until context.config.weeklyViewDays) { + addView(WidgetWeekColumnBinding.inflate(layoutInflater, + binding.configCalendar.weekEventsColumnsHolder, false).root) + } + } + // column on the left showing the time + binding.configCalendar.timeColumn.apply { + removeAllViews() + addView(Vertical1Binding.inflate(layoutInflater, + binding.configCalendar.timeColumn, false).root) + for (i in earliestEventStartHour + 1 until latestEventEndHour) { + val time = DateTime().withHourOfDay(i) + addView(WidgetWeekHourBinding.inflate(layoutInflater, + binding.configCalendar.timeColumn, false).root.apply { + text = time.toString(Formatter.getHourPattern(context)) + setTextColor(mTextColor) + }) + } + addView(Vertical1Binding.inflate(layoutInflater, binding.configCalendar.timeColumn, false).root) + } + binding.configCalendar.weekEventsHourLines.apply { + removeAllViews() + addView(Vertical1Binding.inflate(layoutInflater, binding.configCalendar.weekEventsHourLines, false).root) + for (i in earliestEventStartHour + 1 until latestEventEndHour) { + addView(HorizontalLineBinding.inflate(layoutInflater, + binding.configCalendar.weekEventsHourLines, false).root) + addView(Vertical1Binding.inflate(layoutInflater, + binding.configCalendar.weekEventsHourLines, false).root) + } + } + } + + private fun pickBackgroundColor() { + ColorPickerDialog(this, mBgColorWithoutTransparency) { wasPositivePressed, color -> + if (wasPositivePressed) { + mBgColorWithoutTransparency = color + updateBackgroundColor() + } + } + } + + private fun pickTextColor() { + ColorPickerDialog(this, mTextColor) { wasPositivePressed, color -> + if (wasPositivePressed) { + mTextColor = color + updateTextColor() + updateDays() + } + } + } + + private fun requestWidgetUpdate() { + Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null, this, MyWidgetWeeklyProvider::class.java).apply { + putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, intArrayOf(mWidgetId)) + sendBroadcast(this) + } + } + + private fun updateTextColor() { + binding.configTextColor.setFillWithStroke(mTextColor, mTextColor) + binding.configSave.setTextColor(getProperPrimaryColor().getContrastColor()) + val weekendsTextColor = config.highlightWeekendsColor + for ((i, view) in binding.configCalendar.weekLettersHolder.children.withIndex()) { + if (view is TextView) { + val textColor = if (config.highlightWeekends && isWeekend(mDays!![i].start.dayOfWeek)) { + weekendsTextColor + } else { + mTextColor + } + view.setTextColor(textColor) + } + } + for (view in binding.configCalendar.timeColumn.children) { + if (view is TextView) { + view.setTextColor(mTextColor) + } + } + } + + private fun updateBackgroundColor() { + mBgColor = mBgColorWithoutTransparency.adjustAlpha(mBgAlpha) + binding.configCalendar.widgetWeekBackground.applyColorFilter(mBgColor) + binding.configBgColor.setFillWithStroke(mBgColor, mBgColor) + binding.configSave.backgroundTintList = ColorStateList.valueOf(getProperPrimaryColor()) + } + + private fun updateDays() { + mDays.forEach { + binding.configCalendar.weekEventsDayLines.apply { + addView(VerticalLineBinding.inflate(layoutInflater, + binding.configCalendar.weekEventsDayLines, false).root) + addView(Horizontal1Binding.inflate(layoutInflater, + binding.configCalendar.weekEventsDayLines, false).root) + } + } + } + + override fun updateWeeklyCalendar( + context: Context, + days: ArrayList, + earliestStartHour: Int, + latestEndHour: Int, + ) { + runOnUiThread { + mDays = days + earliestEventStartHour = earliestStartHour + latestEventEndHour = latestEndHour + setupDayLabels() + setupDayColumns() + updateDays() + } + } + +} diff --git a/app/src/main/kotlin/org/fossify/calendar/extensions/Context.kt b/app/src/main/kotlin/org/fossify/calendar/extensions/Context.kt index f9dd6af1e..2ac20ae41 100644 --- a/app/src/main/kotlin/org/fossify/calendar/extensions/Context.kt +++ b/app/src/main/kotlin/org/fossify/calendar/extensions/Context.kt @@ -57,6 +57,7 @@ import org.fossify.calendar.helpers.MONTH import org.fossify.calendar.helpers.MyWidgetDateProvider import org.fossify.calendar.helpers.MyWidgetListProvider import org.fossify.calendar.helpers.MyWidgetMonthlyProvider +import org.fossify.calendar.helpers.MyWidgetWeeklyProvider import org.fossify.calendar.helpers.NEW_EVENT_START_TS import org.fossify.calendar.helpers.REMINDER_NOTIFICATION import org.fossify.calendar.helpers.REMINDER_OFF @@ -153,10 +154,25 @@ fun Context.updateWidgets() { } } + updateWeeklyWidget() updateListWidget() updateDateWidget() } +private fun Context.updateWeeklyWidget() { + val widgetIDs = AppWidgetManager.getInstance(applicationContext) + ?.getAppWidgetIds(ComponentName(applicationContext, MyWidgetWeeklyProvider::class.java)) + ?: return + + if (widgetIDs.isNotEmpty()) { + Intent(applicationContext, MyWidgetWeeklyProvider::class.java).apply { + action = AppWidgetManager.ACTION_APPWIDGET_UPDATE + putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIDs) + sendBroadcast(this) + } + } +} + fun Context.updateListWidget() { val widgetIDs = AppWidgetManager.getInstance(applicationContext) ?.getAppWidgetIds(ComponentName(applicationContext, MyWidgetListProvider::class.java)) diff --git a/app/src/main/kotlin/org/fossify/calendar/fragments/WeekFragment.kt b/app/src/main/kotlin/org/fossify/calendar/fragments/WeekFragment.kt index 67fe929d0..86d0b0fac 100644 --- a/app/src/main/kotlin/org/fossify/calendar/fragments/WeekFragment.kt +++ b/app/src/main/kotlin/org/fossify/calendar/fragments/WeekFragment.kt @@ -3,12 +3,12 @@ package org.fossify.calendar.fragments import android.annotation.SuppressLint import android.content.ClipData import android.content.ClipDescription +import android.content.Context import android.content.Intent import android.content.res.Resources import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.os.Handler -import android.util.Range import android.view.DragEvent import android.view.GestureDetector import android.view.LayoutInflater @@ -37,7 +37,6 @@ import org.fossify.calendar.extensions.config import org.fossify.calendar.extensions.eventsDB import org.fossify.calendar.extensions.eventsHelper import org.fossify.calendar.extensions.getWeeklyViewItemHeight -import org.fossify.calendar.extensions.intersects import org.fossify.calendar.extensions.seconds import org.fossify.calendar.extensions.shouldStrikeThrough import org.fossify.calendar.helpers.Config @@ -59,8 +58,8 @@ import org.fossify.calendar.helpers.getActivityToOpen import org.fossify.calendar.helpers.isWeekend import org.fossify.calendar.interfaces.WeekFragmentListener import org.fossify.calendar.interfaces.WeeklyCalendar +import org.fossify.calendar.models.DayWeekly import org.fossify.calendar.models.Event -import org.fossify.calendar.models.EventWeeklyView import org.fossify.calendar.views.MyScrollView import org.fossify.commons.dialogs.RadioGroupDialog import org.fossify.commons.extensions.adjustAlpha @@ -75,17 +74,14 @@ import org.fossify.commons.extensions.hideKeyboard import org.fossify.commons.extensions.onGlobalLayout import org.fossify.commons.extensions.realScreenSize import org.fossify.commons.extensions.removeBit -import org.fossify.commons.extensions.toInt import org.fossify.commons.extensions.usableScreenSize import org.fossify.commons.helpers.HIGHER_ALPHA import org.fossify.commons.helpers.LOWER_ALPHA import org.fossify.commons.helpers.MEDIUM_ALPHA -import org.fossify.commons.helpers.WEEK_SECONDS import org.fossify.commons.helpers.ensureBackgroundThread import org.fossify.commons.helpers.isNougatPlus import org.fossify.commons.models.RadioItem import org.joda.time.DateTime -import org.joda.time.Days import java.util.Calendar import kotlin.math.max import kotlin.math.min @@ -125,12 +121,10 @@ class WeekFragment : Fragment(), WeeklyCalendar { private var currentTimeView: ImageView? = null private var fadeOutHandler = Handler() private var allDayHolders = ArrayList() - private var allDayRows = ArrayList>() - private var allDayEventToRow = LinkedHashMap() - private var currEvents = ArrayList() + private var allDayRows = ArrayList() + private var currDays = ArrayList() private var dayColumns = ArrayList() private var calendarColors = LongSparseArray() - private var eventTimeRanges = LinkedHashMap>() private var currentlyDraggedView: View? = null private lateinit var binding: FragmentWeekBinding @@ -150,7 +144,6 @@ class WeekFragment : Fragment(), WeeklyCalendar { dimCompletedTasks = config.dimCompletedTasks highlightWeekends = config.highlightWeekends primaryColor = requireContext().getProperPrimaryColor() - allDayRows.add(HashSet()) } @SuppressLint("ClickableViewAccessibility") @@ -252,7 +245,7 @@ class WeekFragment : Fragment(), WeeklyCalendar { fun updateCalendar() { if (context != null) { currentlyDraggedView = null - WeeklyCalendarImpl(this, requireContext()).updateWeeklyCalendar(weekTimestamp) + WeeklyCalendarImpl(this, requireContext()).updateWeeklyCalendar(weekDateTime) } } @@ -264,7 +257,6 @@ class WeekFragment : Fragment(), WeeklyCalendar { binding.weekEventsColumnsHolder, false ).root - column.tag = Formatter.getDayCodeFromDateTime(weekDateTime.plusDays(it)) binding.weekEventsColumnsHolder.addView(column) dayColumns.add(column) } @@ -547,24 +539,23 @@ class WeekFragment : Fragment(), WeeklyCalendar { return fullContentHeight * visibleRatio } - override fun updateWeeklyCalendar(events: ArrayList) { - val newHash = events.hashCode() - if (newHash == lastHash || mWasDestroyed || context == null) { + override fun updateWeeklyCalendar( + context: Context, + days: ArrayList, + earliestStartHour: Int, + latestEndHour: Int, + ) { + val newHash = days.hashCode() + if (newHash == lastHash || mWasDestroyed) { return } lastHash = newHash requireActivity().runOnUiThread { - if (context != null && activity != null && isAdded) { - val replaceDescription = config.replaceDescription - val sorted = events.sortedWith( - compareBy { it.startTS }.thenBy { it.endTS }.thenBy { it.title } - .thenBy { if (replaceDescription) it.location else it.description } - ).toMutableList() as ArrayList - - currEvents = sorted - addEvents(sorted) + if (activity != null && isAdded) { + currDays = days + addDays(days) } } } @@ -577,245 +568,108 @@ class WeekFragment : Fragment(), WeeklyCalendar { scrollView.layoutParams.height = fullHeight - oneDp binding.weekHorizontalGridHolder.layoutParams.height = fullHeight binding.weekEventsColumnsHolder.layoutParams.height = fullHeight - addEvents(currEvents) + addDays(currDays) } - private fun addEvents(events: ArrayList) { + private fun addDays(days: ArrayList) { initGrid() allDayHolders.clear() allDayRows.clear() - eventTimeRanges.clear() - allDayRows.add(HashSet()) binding.weekAllDayHolder.removeAllViews() - addNewLine() - allDayEventToRow.clear() val minuteHeight = rowHeight / 60 val minimalHeight = res.getDimension(R.dimen.weekly_view_minimal_event_height).toInt() val density = res.displayMetrics.density.roundToInt() - for (event in events) { - val startDateTime = Formatter.getDateTimeFromTS(event.startTS) - val startDayCode = Formatter.getDayCodeFromDateTime(startDateTime) - val endDateTime = Formatter.getDateTimeFromTS(event.endTS) - val endDayCode = Formatter.getDayCodeFromDateTime(endDateTime) - val isAllDay = event.getIsAllDay() - - if (shouldAddEventOnTopBar(isAllDay, startDayCode, endDayCode)) { - continue + for ((dayOfWeek, day) in days.withIndex()) { + for (event in day.topBarEvents) { + addAllDayEvent(dayOfWeek, event) } - - var currentDateTime = startDateTime - var currentDayCode = Formatter.getDayCodeFromDateTime(currentDateTime) - do { - // all-day events always start at the 0 minutes and end at the end of the day (1440 minutes) - val startMinutes = when { - currentDayCode == startDayCode && !isAllDay -> (startDateTime.minuteOfDay) - else -> 0 - } - val duration = when { - currentDayCode == endDayCode && !isAllDay -> (endDateTime.minuteOfDay - startMinutes) - else -> 1440 - } - - var endMinutes = startMinutes + duration - if ((endMinutes - startMinutes) * minuteHeight < minimalHeight) { - endMinutes = startMinutes + (minimalHeight / minuteHeight).toInt() - } - - val range = Range(startMinutes, endMinutes) - val eventWeekly = EventWeeklyView(range) - - if (!eventTimeRanges.containsKey(currentDayCode)) { - eventTimeRanges[currentDayCode] = LinkedHashMap() - } - eventTimeRanges[currentDayCode]?.put(event.id!!, eventWeekly) - - currentDateTime = currentDateTime.plusDays(1) - currentDayCode = Formatter.getDayCodeFromDateTime(currentDateTime) - } while (currentDayCode.toInt() <= endDayCode.toInt()) - } - - for ((_, eventDayList) in eventTimeRanges) { - val eventsCollisionChecked = ArrayList() - for ((eventId, eventWeeklyView) in eventDayList) { - if (eventWeeklyView.slot == 0) { - eventWeeklyView.slot = 1 - eventWeeklyView.slotMax = 1 - } - - eventsCollisionChecked.add(eventId) - val eventWeeklyViewsToCheck = - eventDayList.filterNot { eventsCollisionChecked.contains(it.key) } - for ((toCheckId, eventWeeklyViewToCheck) in eventWeeklyViewsToCheck) { - val areTouching = eventWeeklyView.range.intersects(eventWeeklyViewToCheck.range) - val doHaveCommonMinutes = if (areTouching) { - eventWeeklyView.range.upper > eventWeeklyViewToCheck.range.lower || (eventWeeklyView.range.lower == eventWeeklyView.range.upper && - eventWeeklyView.range.upper == eventWeeklyViewToCheck.range.lower) + for (ews in day.dayEvents) { + val dayColumn = dayColumns[dayOfWeek] + val event = ews.event + WeekEventMarkerBinding.inflate(layoutInflater).apply { + var backgroundColor = if (event.color == 0) { + calendarColors.get(event.calendarId, primaryColor) } else { - false + event.color } + var textColor = backgroundColor.getContrastColor() - if (areTouching && doHaveCommonMinutes) { - if (eventWeeklyViewToCheck.slot == 0) { - val collisionEventWeeklyViews = eventDayList - .filter { eventWeeklyView.collisions.contains(it.key) } - var currentSlotMax = max( - eventWeeklyView.slotMax.coerceAtLeast(1), - eventWeeklyView.slot.coerceAtLeast(1) - ) - val maxCollisionSlot = collisionEventWeeklyViews - .maxOfOrNull { it.value.slot.coerceAtLeast(1) } ?: 1 - currentSlotMax = max(currentSlotMax, maxCollisionSlot) - val nextSlot = currentSlotMax + 1 - val slotRange = IntArray(currentSlotMax) { it + 1 } - for ((_, collisionEventWeeklyView) in collisionEventWeeklyViews) { - if ( - collisionEventWeeklyView.range.intersects(eventWeeklyViewToCheck.range) - && collisionEventWeeklyView.slot in 1..currentSlotMax - ) { - slotRange[collisionEventWeeklyView.slot - 1] = nextSlot - } - } - if (eventWeeklyView.slot in 1..currentSlotMax) { - slotRange[eventWeeklyView.slot - 1] = nextSlot - } - - val slot = slotRange.minOrNull() ?: nextSlot - eventWeeklyViewToCheck.slot = slot - - if (slot == nextSlot) { - eventWeeklyViewToCheck.slotMax = nextSlot - eventWeeklyView.slotMax = nextSlot - for ((_, collisionEventWeeklyView) in collisionEventWeeklyViews) { - collisionEventWeeklyView.slotMax = - max(collisionEventWeeklyView.slotMax, nextSlot) - } - } else { - eventWeeklyViewToCheck.slotMax = currentSlotMax - } - } - eventWeeklyView.collisions.add(toCheckId) - eventWeeklyViewToCheck.collisions.add(eventId) + val adjustAlpha = if (event.isTask()) { + dimCompletedTasks && event.isTaskCompleted() + } else { + dimPastEvents && event.isPastEvent && !isPrintVersion } - } - } - } - - dayevents@ for (event in events) { - val startDateTime = Formatter.getDateTimeFromTS(event.startTS) - val startDayCode = Formatter.getDayCodeFromDateTime(startDateTime) - val endDateTime = Formatter.getDateTimeFromTS(event.endTS) - val endDayCode = Formatter.getDayCodeFromDateTime(endDateTime) - if (shouldAddEventOnTopBar(event.getIsAllDay(), startDayCode, endDayCode)) { - addAllDayEvent(event) - } else { - var currentDateTime = startDateTime - var currentDayCode = Formatter.getDayCodeFromDateTime(currentDateTime) - do { - val dayOfWeek = dayColumns.indexOfFirst { it.tag == currentDayCode } - if (dayOfWeek == -1 || dayOfWeek >= config.weeklyViewDays) { - if (startDayCode != endDayCode) { - currentDateTime = currentDateTime.plusDays(1) - currentDayCode = Formatter.getDayCodeFromDateTime(currentDateTime) - continue - } else { - continue@dayevents - } + if (adjustAlpha) { + backgroundColor = backgroundColor.adjustAlpha(MEDIUM_ALPHA) + textColor = textColor.adjustAlpha(HIGHER_ALPHA) } - val dayColumn = dayColumns[dayOfWeek] - WeekEventMarkerBinding.inflate(layoutInflater).apply { - var backgroundColor = if (event.color == 0) { - calendarColors.get(event.calendarId, primaryColor) - } else { - event.color - } - var textColor = backgroundColor.getContrastColor() - val currentEventWeeklyView = eventTimeRanges[currentDayCode]!![event.id] - - val adjustAlpha = if (event.isTask()) { - dimCompletedTasks && event.isTaskCompleted() - } else { - dimPastEvents && event.isPastEvent && !isPrintVersion - } - - if (adjustAlpha) { - backgroundColor = backgroundColor.adjustAlpha(MEDIUM_ALPHA) - textColor = textColor.adjustAlpha(HIGHER_ALPHA) - } + root.background = ColorDrawable(backgroundColor) + dayColumn.addView(root) + root.y = ews.startMinute * minuteHeight - root.background = ColorDrawable(backgroundColor) - dayColumn.addView(root) - root.y = currentEventWeeklyView!!.range.lower * minuteHeight + // compensate grid offset + root.y -= (ews.startMinute / 60) / 2 - // compensate grid offset - root.y -= (currentEventWeeklyView.range.lower / 60) / 2 + weekEventTaskImage.beVisibleIf(event.isTask()) + if (event.isTask()) { + weekEventTaskImage.applyColorFilter(textColor) + } - weekEventTaskImage.beVisibleIf(event.isTask()) - if (event.isTask()) { - weekEventTaskImage.applyColorFilter(textColor) + weekEventLabel.apply { + setTextColor(textColor) + maxLines = if (event.isTask() || event.startTS == event.endTS) { + 1 + } else { + 3 } - weekEventLabel.apply { - setTextColor(textColor) - maxLines = if (event.isTask() || event.startTS == event.endTS) { - 1 - } else { - 3 - } + text = event.title + checkViewStrikeThrough(event.shouldStrikeThrough()) + contentDescription = text - text = event.title - checkViewStrikeThrough(event.shouldStrikeThrough()) - contentDescription = text - - minHeight = if (event.startTS == event.endTS) { - minimalHeight - } else { - ((currentEventWeeklyView.range.upper - currentEventWeeklyView.range.lower) * minuteHeight).toInt() - 1 - } - } + val durationMinutes = ews.endMinute - ews.startMinute + minHeight = minimalHeight.coerceAtLeast((durationMinutes * minuteHeight).toInt() - 1) + } - (root.layoutParams as RelativeLayout.LayoutParams).apply { - width = (dayColumn.width - 1) / currentEventWeeklyView.slotMax - root.x = (width * (currentEventWeeklyView.slot - 1)).toFloat() - if (currentEventWeeklyView.slot > 1) { - root.x += density - width -= density - } + (root.layoutParams as RelativeLayout.LayoutParams).apply { + width = (dayColumn.width - 1) / ews.slotMax + root.x = (width * ews.slot).toFloat() + if (ews.slot > 0) { + root.x += density + width -= density } + } - root.setOnClickListener { - Intent(context, getActivityToOpen(event.isTask())).apply { - putExtra(EVENT_ID, event.id!!) - putExtra(EVENT_OCCURRENCE_TS, event.startTS) - putExtra(IS_TASK_COMPLETED, event.isTaskCompleted()) - startActivity(this) - } + root.setOnClickListener { + Intent(context, getActivityToOpen(event.isTask())).apply { + putExtra(EVENT_ID, event.id!!) + putExtra(EVENT_OCCURRENCE_TS, event.startTS) + putExtra(IS_TASK_COMPLETED, event.isTaskCompleted()) + startActivity(this) } + } - root.setOnLongClickListener { view -> - currentlyDraggedView = view - val shadowBuilder = View.DragShadowBuilder(view) - val clipData = ClipData.newPlainText( - WEEKLY_EVENT_ID_LABEL, - "${event.id};${event.startTS};${event.endTS}" - ) - if (isNougatPlus()) { - view.startDragAndDrop(clipData, shadowBuilder, null, 0) - } else { - view.startDrag(clipData, shadowBuilder, null, 0) - } - true + root.setOnLongClickListener { view -> + currentlyDraggedView = view + val shadowBuilder = View.DragShadowBuilder(view) + val clipData = ClipData.newPlainText( + WEEKLY_EVENT_ID_LABEL, + "${event.id};${event.startTS};${event.endTS}" + ) + if (isNougatPlus()) { + view.startDragAndDrop(clipData, shadowBuilder, null, 0) + } else { + view.startDrag(clipData, shadowBuilder, null, 0) } - - root.setOnDragListener(DragListener()) + true } - currentDateTime = currentDateTime.plusDays(1) - currentDayCode = Formatter.getDayCodeFromDateTime(currentDateTime) - } while (currentDayCode.toInt() <= endDayCode.toInt()) + root.setOnDragListener(DragListener()) + } } } @@ -823,7 +677,7 @@ class WeekFragment : Fragment(), WeeklyCalendar { addCurrentTimeIndicator() } - private fun addNewLine() { + private fun addTopEventLine() { val allDaysLine = AllDayEventsHolderLineBinding.inflate(layoutInflater).root binding.weekAllDayHolder.addView(allDaysLine) allDayHolders.add(allDaysLine) @@ -878,17 +732,8 @@ class WeekFragment : Fragment(), WeeklyCalendar { } } - private fun shouldAddEventOnTopBar( - isAllDay: Boolean, - startDayCode: String, - endDayCode: String - ): Boolean { - val spansMultipleDays = startDayCode != endDayCode - return isAllDay || (spansMultipleDays && config.showMidnightSpanningEventsAtTop) - } - @SuppressLint("NewApi") - private fun addAllDayEvent(event: Event) { + private fun addAllDayEvent(dayOfWeek: Int, event: Event) { WeekAllDayEventMarkerBinding.inflate(layoutInflater).apply { var backgroundColor = if (event.color == 0) { calendarColors.get(event.calendarId, primaryColor) @@ -923,95 +768,30 @@ class WeekFragment : Fragment(), WeeklyCalendar { weekEventTaskImage.applyColorFilter(textColor) } - val startDateTime = Formatter.getDateTimeFromTS(event.startTS) + // horizontal positioning + val dayWidth = binding.root.width / config.weeklyViewDays val endDateTime = Formatter.getDateTimeFromTS(event.endTS) - val eventStartDayStartTime = startDateTime.withTimeAtStartOfDay().seconds() - val eventEndDayStartTime = endDateTime.withTimeAtStartOfDay().seconds() - - val minTS = max(startDateTime.seconds(), weekTimestamp) - val maxTS = min(endDateTime.seconds(), weekTimestamp + 2 * WEEK_SECONDS) - - // fix a visual glitch with all-day events or events lasting multiple days starting at midnight on monday, being shown the previous week too - if (minTS == maxTS && (minTS - weekTimestamp == WEEK_SECONDS.toLong())) { - return - } - - val isStartTimeDay = - Formatter.getDateTimeFromTS(maxTS) == Formatter.getDateTimeFromTS(maxTS) - .withTimeAtStartOfDay() - val numDays = Days.daysBetween( - Formatter.getDateTimeFromTS(minTS).toLocalDate(), - Formatter.getDateTimeFromTS(maxTS).toLocalDate() - ).days - val daysCnt = if (numDays == 1 && isStartTimeDay) 0 else numDays - val startDateTimeInWeek = Formatter.getDateTimeFromTS(minTS) - val firstDayIndex = - startDateTimeInWeek.dayOfMonth // indices must be unique for the visible range (2 weeks) - val lastDayIndex = firstDayIndex + daysCnt - val dayIndices = firstDayIndex..lastDayIndex - val isAllDayEvent = firstDayIndex == lastDayIndex - val isRepeatingOverlappingEvent = - eventEndDayStartTime - eventStartDayStartTime >= event.repeatInterval - - var doesEventFit: Boolean - var wasEventHandled = false - var drawAtLine = 0 - - for (index in allDayRows.indices) { - drawAtLine = index - - val row = allDayRows[index] - doesEventFit = dayIndices.all { !row.contains(it) } - - val firstEvent = allDayEventToRow.keys.firstOrNull { it.id == event.id } - val lastEvent = allDayEventToRow.keys.lastOrNull { it.id == event.id } - val firstEventRowIdx = allDayEventToRow[firstEvent] - val lastEventRowIdx = allDayEventToRow[lastEvent] - val adjacentEvents = currEvents.filter { event.id == it.id } - val repeatingEventIndex = adjacentEvents.indexOf(event) - val isRowValidForEvent = - lastEvent == null || firstEventRowIdx!! + repeatingEventIndex == index && lastEventRowIdx!! < index - - if (doesEventFit && (!isRepeatingOverlappingEvent || isAllDayEvent || isRowValidForEvent)) { - dayIndices.forEach { - row.add(it) - } - allDayEventToRow[event] = index - wasEventHandled = true - } else { - // create new row - if (index == allDayRows.lastIndex) { - allDayRows.add(HashSet()) - addNewLine() - drawAtLine++ - val lastRow = allDayRows.last() - dayIndices.forEach { - lastRow.add(it) - } - allDayEventToRow[event] = allDayRows.lastIndex - wasEventHandled = true - } - } - - if (wasEventHandled) { - break - } - } - - val dayCodeStart = Formatter.getDayCodeFromDateTime(startDateTime).toInt() - val dayCodeEnd = Formatter.getDayCodeFromDateTime(endDateTime).toInt() - val dayOfWeek = - dayColumns.indexOfFirst { it.tag.toInt() == dayCodeStart || it.tag.toInt() in (dayCodeStart + 1)..dayCodeEnd } - if (dayOfWeek == -1) { - return + var lastDay = currDays.indexOfLast { it.start < endDateTime } + if (lastDay == -1) { + lastDay = config.weeklyViewDays + } + lastDay = lastDay.coerceAtLeast(dayOfWeek) + + // vertical positioning (i.e. find a row where this event fits) + var drawAtLine = allDayRows.indexOfFirst { it < dayOfWeek } + if (drawAtLine < 0) { + drawAtLine = allDayRows.size + addTopEventLine() + allDayRows.add(lastDay) + } else { + allDayRows[drawAtLine] = lastDay } - allDayHolders[drawAtLine].addView(root) - val dayWidth = binding.root.width / config.weeklyViewDays + (root.layoutParams as RelativeLayout.LayoutParams).apply { leftMargin = dayOfWeek * dayWidth bottomMargin = 1 - width = (dayWidth) * (daysCnt + 1) + width = (dayWidth) * (lastDay - dayOfWeek + 1) } calculateExtraHeight() @@ -1057,7 +837,7 @@ class WeekFragment : Fragment(), WeeklyCalendar { isPrintVersion = !isPrintVersion updateCalendar() setupDayLabels() - addEvents(currEvents) + addDays(currDays) } inner class DragListener : View.OnDragListener { diff --git a/app/src/main/kotlin/org/fossify/calendar/helpers/MyWidgetWeeklyProvider.kt b/app/src/main/kotlin/org/fossify/calendar/helpers/MyWidgetWeeklyProvider.kt new file mode 100644 index 000000000..ee6ea998b --- /dev/null +++ b/app/src/main/kotlin/org/fossify/calendar/helpers/MyWidgetWeeklyProvider.kt @@ -0,0 +1,431 @@ +package org.fossify.calendar.helpers + +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProvider +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.res.Resources +import android.graphics.Paint +import android.widget.RemoteViews +import org.fossify.calendar.R +import org.fossify.calendar.activities.SplashActivity +import org.fossify.calendar.extensions.* +import org.fossify.calendar.extensions.config +import org.fossify.calendar.interfaces.WeeklyCalendar +import org.fossify.calendar.models.DayWeekly +import org.fossify.calendar.models.Event +import org.fossify.commons.extensions.* +import org.fossify.commons.helpers.HIGHER_ALPHA +import org.fossify.commons.helpers.MEDIUM_ALPHA +import org.joda.time.DateTime + +class MyWidgetWeeklyProvider : AppWidgetProvider() { + + private var dayColumns = ArrayList() + private var mDays = ArrayList() + private var earliestEventStartHour = 0 + private var latestEventEndHour = WeeklyCalendarImpl.HOURS_PER_DAY + + companion object { + private val vertical_spaces = arrayOf( + R.layout.vertical_1, + R.layout.vertical_2, + R.layout.vertical_3, + R.layout.vertical_4, + R.layout.vertical_5, + R.layout.vertical_6, + R.layout.vertical_7, + R.layout.vertical_8, + R.layout.vertical_9, + R.layout.vertical_10, + R.layout.vertical_11, + R.layout.vertical_12, + R.layout.vertical_13, + R.layout.vertical_14, + R.layout.vertical_15, + R.layout.vertical_16, + R.layout.vertical_17, + R.layout.vertical_18, + R.layout.vertical_19, + R.layout.vertical_20, + R.layout.vertical_21, + R.layout.vertical_22, + R.layout.vertical_23, + R.layout.vertical_24, + R.layout.vertical_25, + R.layout.vertical_26, + R.layout.vertical_27, + R.layout.vertical_28, + R.layout.vertical_29, + R.layout.vertical_30, + R.layout.vertical_31, + R.layout.vertical_32, + R.layout.vertical_33, + R.layout.vertical_34, + R.layout.vertical_35, + R.layout.vertical_36, + R.layout.vertical_37, + R.layout.vertical_38, + R.layout.vertical_39, + R.layout.vertical_40, + R.layout.vertical_41, + R.layout.vertical_42, + R.layout.vertical_43, + R.layout.vertical_44, + R.layout.vertical_45, + R.layout.vertical_46, + R.layout.vertical_47, + R.layout.vertical_48, + R.layout.vertical_49, + R.layout.vertical_50, + R.layout.vertical_51, + R.layout.vertical_52, + R.layout.vertical_53, + R.layout.vertical_54, + R.layout.vertical_55, + R.layout.vertical_56, + R.layout.vertical_57, + R.layout.vertical_58, + R.layout.vertical_59, + R.layout.vertical_60, + R.layout.vertical_61, + R.layout.vertical_62, + R.layout.vertical_63, + R.layout.vertical_64, + R.layout.vertical_65, + R.layout.vertical_66, + R.layout.vertical_67, + R.layout.vertical_68, + R.layout.vertical_69, + R.layout.vertical_70, + R.layout.vertical_71, + R.layout.vertical_72, + R.layout.vertical_73, + R.layout.vertical_74, + R.layout.vertical_75, + R.layout.vertical_76, + R.layout.vertical_77, + R.layout.vertical_78, + R.layout.vertical_79, + R.layout.vertical_80, + R.layout.vertical_81, + R.layout.vertical_82, + R.layout.vertical_83, + R.layout.vertical_84, + R.layout.vertical_85, + R.layout.vertical_86, + R.layout.vertical_87, + R.layout.vertical_88, + R.layout.vertical_89, + R.layout.vertical_90, + R.layout.vertical_91, + R.layout.vertical_92, + R.layout.vertical_93, + R.layout.vertical_94, + R.layout.vertical_95, + R.layout.vertical_96, + ) + private val horizontal_spaces = arrayOf( + R.layout.horizontal_1, + R.layout.horizontal_2, + R.layout.horizontal_3, + R.layout.horizontal_4, + R.layout.horizontal_5, + R.layout.horizontal_6, + R.layout.horizontal_7, + R.layout.horizontal_8, + R.layout.horizontal_9, + R.layout.horizontal_10, + R.layout.horizontal_11, + R.layout.horizontal_12, + R.layout.horizontal_13, + R.layout.horizontal_14, + ) + // 15 minute chunks + private val timeStepMinutes = 24 * 60 / vertical_spaces.size + } + + override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { + performUpdate(context) + } + + private fun performUpdate(context: Context) { + WeeklyCalendarImpl(weeklyCalendar, context, timeStepMinutes).getWeek(DateTime.now()) + } + + private fun getComponentName(context: Context) = ComponentName(context, MyWidgetWeeklyProvider::class.java) + + private fun setupDayColumns(context: Context, views: RemoteViews) { + val textColor = context.config.widgetTextColor + dayColumns.clear() + views.removeAllViews(R.id.week_events_columns_holder) + views.removeAllViews(R.id.time_column) + views.removeAllViews(R.id.week_events_hour_lines) + views.removeAllViews(R.id.week_events_day_lines) + val packageName = context.packageName + // columns that will contain events + for (i in 0 until context.config.weeklyViewDays) { + val column = RemoteViews(packageName, R.layout.widget_week_column) + dayColumns.add(column) + } + // column on the left showing the time + views.addView(R.id.time_column, RemoteViews(packageName, R.layout.vertical_1)) + views.addView(R.id.week_events_hour_lines, RemoteViews(packageName, R.layout.vertical_1)) + for (i in earliestEventStartHour + 1 until latestEventEndHour) { + val hour = RemoteViews(packageName, R.layout.widget_week_hour) + val time = DateTime().withHourOfDay(i) + hour.setText(R.id.hour_textview, time.toString(Formatter.getHourPattern(context))) + hour.setTextColor(R.id.hour_textview, textColor) + views.addView(R.id.time_column, hour) + views.addView(R.id.week_events_hour_lines, RemoteViews(packageName, R.layout.horizontal_line)) + views.addView(R.id.week_events_hour_lines, RemoteViews(packageName, R.layout.vertical_1)) + } + views.addView(R.id.time_column, RemoteViews(packageName, R.layout.vertical_1)) + } + + private fun updateDays(context: Context, views: RemoteViews) { + views.removeAllViews(R.id.week_all_day_holder) + + val config = context.config + val packageName = context.packageName + val allDayEventRows = ArrayList() + val allDayEventNextStart = ArrayList() + + setupDayColumns(context, views) + + // add events to the view + for ((dayOfWeek, day) in mDays.withIndex()) { + for (event in day.topBarEvents) { + addAllDayEvent(context, packageName, dayOfWeek, event, allDayEventRows, allDayEventNextStart) + } + val dayColumn = dayColumns[dayOfWeek] + var subColumnStartMinute = earliestEventStartHour * WeeklyCalendarImpl.MINUTES_PER_HOUR + val subColumns = ArrayList() + val subColumnLastMinutes = ArrayList() + subColumns.add(dayColumn) + subColumnLastMinutes.add(subColumnStartMinute) + for (ews in day.dayEvents) { + if (ews.slotMax != subColumns.size) { + // the number of subColumns has to be changed + fillEmptyEventColumns(packageName, dayColumn, ews.startMinute, + subColumns, subColumnStartMinute, subColumnLastMinutes) + subColumns.clear() + subColumnLastMinutes.clear() + subColumnStartMinute = ews.startMinute + if (ews.slotMax == 1) { + // it would be pointless to add a row containing only one subColumn + // so instead pretend as if dayColumn was a subColumn + subColumns.add(dayColumn) + } else { + // subColumns will be shown side-by-side for events with overlapping timing + for (i in 0 until ews.slotMax) { + val column = RemoteViews(packageName, R.layout.widget_week_column) + subColumns.add(column) + } + } + for (i in 0 until ews.slotMax) { + subColumnLastMinutes.add(ews.startMinute) + } + } + fillEmptySpace(packageName, subColumns[ews.slot], ews.startMinute - subColumnLastMinutes[ews.slot]) + subColumnLastMinutes[ews.slot] = ews.endMinute + val eventView = eventView(context, packageName, ews.event) + val height = (ews.endMinute - ews.startMinute) / timeStepMinutes + val container = RemoteViews(packageName, vertical_spaces[height - 1]) + container.addView(R.id.space_vertical, eventView) + subColumns[ews.slot].addView(R.id.week_column, container) + } + fillEmptyEventColumns(packageName, dayColumn, latestEventEndHour * WeeklyCalendarImpl.MINUTES_PER_HOUR, + subColumns,subColumnStartMinute, subColumnLastMinutes) + // add vertical grid line + views.addView(R.id.week_events_day_lines, RemoteViews(packageName, R.layout.vertical_line)) + views.addView(R.id.week_events_day_lines, RemoteViews(packageName, R.layout.horizontal_1)) + views.addView(R.id.week_events_columns_holder, dayColumn) + } + // add rows containing all-day events to the view + for ((i, row) in allDayEventRows.withIndex()) { + if (allDayEventNextStart[i] < config.weeklyViewDays) { + val space = RemoteViews(packageName, + horizontal_spaces[config.weeklyViewDays - allDayEventNextStart[i] - 1]) + allDayEventRows[i].addView(R.id.week_all_day_row, space) + } + views.addView(R.id.week_all_day_holder, row) + } + } + + /** + * create a RemoteViews displaying the given event + * for all-day events in the top-bar and normal events in the dayColumns + */ + private fun eventView(context: Context, packageName: String, event: Event): RemoteViews { + val config = context.config + val eventView = RemoteViews(packageName, R.layout.widget_week_event_marker) + var backgroundColor = event.color + var textColor = backgroundColor.getContrastColor() + + val adjustAlpha = if (event.isTask()) { + config.dimCompletedTasks && event.isTaskCompleted() + } else { + config.dimPastEvents && event.isPastEvent + } + + if (adjustAlpha) { + backgroundColor = backgroundColor.adjustAlpha(MEDIUM_ALPHA) + textColor = textColor.adjustAlpha(HIGHER_ALPHA) + } + + eventView.setInt(R.id.week_event_background, "setColorFilter", backgroundColor) + + eventView.setVisibleIf(R.id.week_event_task_image, event.isTask()) + if (event.isTask()) { + eventView.applyColorFilter(R.id.week_event_task_image, textColor) + } + + // week_event_label + eventView.setTextColor(R.id.week_event_label, textColor) + val maxLines = if (event.isTask() || event.startTS == event.endTS) { + 1 + } else { + 3 + } + eventView.setInt(R.id.week_event_label, "setMaxLines", maxLines) + eventView.setText(R.id.week_event_label, event.title) + if (event.shouldStrikeThrough()) { + eventView.setInt(R.id.week_event_label, "setPaintFlags", Paint.STRIKE_THRU_TEXT_FLAG) + } + eventView.setContentDescription(R.id.week_event_label, event.title) + + val intent = context.getLaunchIntent() ?: Intent(context, SplashActivity::class.java) + intent.putExtra(EVENT_ID, event.id) + intent.putExtra(EVENT_OCCURRENCE_TS, event.startTS) + val pendingIntent = PendingIntent.getActivity( + context, + event.id!!.toInt(), + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + eventView.setOnClickPendingIntent(R.id.week_event_holder, pendingIntent) + return eventView + } + + private fun addAllDayEvent( + context: Context, + packageName: String, + dayOfWeek: Int, + event: Event, + allDayEventRows: ArrayList, + allDayEventNextStart: ArrayList, + ) { + val endDateTime = Formatter.getDateTimeFromTS(event.endTS) + var eventEndsOnDay = mDays.indexOfLast { endDateTime > it.start } + if (eventEndsOnDay < 0) { + eventEndsOnDay = mDays.size - 1 + } + var rowIndex = allDayEventNextStart.indexOfFirst { it <= dayOfWeek } + if (rowIndex < 0) { + rowIndex = allDayEventRows.size + val row = RemoteViews(packageName, R.layout.widget_week_all_day_row) + allDayEventRows.add(row) + allDayEventNextStart.add(0) + } + if (allDayEventNextStart[rowIndex] < dayOfWeek) { + val space = RemoteViews(packageName, horizontal_spaces[dayOfWeek - allDayEventNextStart[rowIndex] - 1]) + allDayEventRows[rowIndex].addView(R.id.week_all_day_row, space) + } + allDayEventNextStart[rowIndex] = eventEndsOnDay + 1 + val container = RemoteViews(packageName, horizontal_spaces[eventEndsOnDay - dayOfWeek]) + val eventView = eventView(context, packageName, event) + container.addView(R.id.space_horizontal, eventView) + allDayEventRows[rowIndex].addView(R.id.week_all_day_row, container) + } + + private val weeklyCalendar = object : WeeklyCalendar { + override fun updateWeeklyCalendar( + context: Context, + days: ArrayList, + earliestStartHour: Int, + latestEndHour: Int, + ) { + val textColor = context.config.widgetTextColor + val resources = context.resources + mDays = days + earliestEventStartHour = earliestStartHour + latestEventEndHour = latestEndHour + + val appWidgetManager = AppWidgetManager.getInstance(context) ?: return + appWidgetManager.getAppWidgetIds(getComponentName(context)).forEach { + val views = RemoteViews(context.packageName, R.layout.fragment_week_widget) + + views.applyColorFilter(R.id.widget_week_background, context.config.widgetBgColor) + + updateDayLabels(context, views, resources, textColor) + updateDays(context, views) + + try { + appWidgetManager.updateAppWidget(it, views) + } catch (ignored: RuntimeException) { + } + } + } + } + + private fun updateDayLabels(context: Context, views: RemoteViews, resources: Resources, textColor: Int) { + val config = context.config + val smallerFontSize = context.getWidgetFontSize() + val packageName = context.packageName + val dayLetters = resources.getStringArray(org.fossify.commons.R.array.week_days_short) + .toMutableList() as ArrayList + + views.removeAllViews(R.id.week_letters_holder) + for (i in 0 until config.weeklyViewDays) { + val curDay = mDays[i].start + val dayLetter = dayLetters[curDay.dayOfWeek - 1] + + val newRemoteView = RemoteViews(packageName, R.layout.widget_week_day_letter).apply { + setText(R.id.week_day_label, dayLetter) + setTextColor(R.id.week_day_label, textColor) + setTextSize(R.id.week_day_label, smallerFontSize) + } + val dayCode = Formatter.getDayCodeFromDateTime(curDay) + (context.getLaunchIntent() ?: Intent(context, SplashActivity::class.java)).apply { + putExtra(DAY_CODE, dayCode) + putExtra(VIEW_TO_OPEN, DAILY_VIEW) + val pendingIntent = PendingIntent.getActivity(context, Integer.parseInt(dayCode), + this, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) + newRemoteView.setOnClickPendingIntent(R.id.week_day_label, pendingIntent) + } + views.addView(R.id.week_letters_holder, newRemoteView) + } + } + + private fun fillEmptySpace(packageName: String, column: RemoteViews, minutes: Int) { + val height = minutes / timeStepMinutes + if (height <= 0) + return + val space = RemoteViews(packageName, vertical_spaces[height - 1]) + column.addView(R.id.week_column, space) + } + + private fun fillEmptyEventColumns( + packageName: String, + dayColumn: RemoteViews, + fillToMinute: Int, + subColumns: ArrayList, + subColumnStartMinute: Int, + subColumnLastMinutes: ArrayList, + ) { + val lastMinute = subColumnLastMinutes.max() + if (subColumns.size > 1) { + val height = (lastMinute - subColumnStartMinute) / timeStepMinutes + val subColumnRow = RemoteViews(packageName, vertical_spaces[height - 1]) + for ((i, column) in subColumns.withIndex()) { + fillEmptySpace(packageName, column, lastMinute - subColumnLastMinutes[i]) + subColumnRow.addView(R.id.space_vertical, column) + } + dayColumn.addView(R.id.week_column, subColumnRow) + } + fillEmptySpace(packageName, dayColumn, fillToMinute - lastMinute) + } +} diff --git a/app/src/main/kotlin/org/fossify/calendar/helpers/WeeklyCalendarImpl.kt b/app/src/main/kotlin/org/fossify/calendar/helpers/WeeklyCalendarImpl.kt index 284e9ce70..6637ac376 100644 --- a/app/src/main/kotlin/org/fossify/calendar/helpers/WeeklyCalendarImpl.kt +++ b/app/src/main/kotlin/org/fossify/calendar/helpers/WeeklyCalendarImpl.kt @@ -1,20 +1,217 @@ package org.fossify.calendar.helpers import android.content.Context +import org.fossify.calendar.extensions.config import org.fossify.calendar.extensions.eventsHelper +import org.fossify.calendar.extensions.getFirstDayOfWeekDt +import org.fossify.calendar.extensions.seconds import org.fossify.calendar.interfaces.WeeklyCalendar +import org.fossify.calendar.models.DayWeekly import org.fossify.calendar.models.Event -import org.fossify.commons.helpers.DAY_SECONDS -import org.fossify.commons.helpers.WEEK_SECONDS +import org.fossify.calendar.models.EventWeeklyView +import org.joda.time.DateTime -class WeeklyCalendarImpl(val callback: WeeklyCalendar, val context: Context) { - var mEvents = ArrayList() +class WeeklyCalendarImpl(val callback: WeeklyCalendar, val context: Context, val timeStepMinutes: Int = 1) { - fun updateWeeklyCalendar(weekStartTS: Long) { - val endTS = weekStartTS + 2 * WEEK_SECONDS - context.eventsHelper.getEvents(weekStartTS - DAY_SECONDS, endTS) { - mEvents = it - callback.updateWeeklyCalendar(it) + companion object { + const val MINUTES_PER_HOUR = 60 + const val HOURS_PER_DAY = 24 + const val MIN_SHOWN_HOURS_PER_DAY = 6 + const val EMPTY_START_HOUR = 6 + const val EMPTY_END_HOUR = 18 + } + + fun updateWeeklyCalendar(dateWithinWeek: DateTime) { + val weekStart = context.getFirstDayOfWeekDt(dateWithinWeek); + val end = weekStart.plusDays(context.config.weeklyViewDays) + val toTS = end.seconds() + context.eventsHelper.getEvents(weekStart.seconds(), toTS) { events -> + val replaceDescription = context.config.replaceDescription + val sortedEvents = events.filter { it.startTS < toTS }.sortedWith( + compareBy { it.startTS }.thenBy { it.endTS }.thenBy { it.title } + .thenBy { if (replaceDescription) it.location else it.description } + ).toMutableList() as ArrayList + + val days = generateDaysInitial(weekStart, sortedEvents) + fixEventOverlap(days) + callbackWithHourRange(days) + } + } + + fun getWeek(targetDate: DateTime) { + updateWeeklyCalendar(targetDate) + } + + private fun generateDaysInitial(weekStart: DateTime, sortedEvents: ArrayList): ArrayList { + val days = ArrayList(context.config.weeklyViewDays) + for (i in 0 until context.config.weeklyViewDays) { + val day = DayWeekly(weekStart.plusDays(i), ArrayList(), ArrayList()) + days.add(day) + } + + // add events to days + for (event in sortedEvents) { + val eventStart = Formatter.getDateTimeFromTS(event.startTS) + val eventEnd = Formatter.getDateTimeFromTS(event.endTS) + + if (shouldAddEventOnTopBar(event, eventStart, eventEnd)) { + // an event spanning multiple days still only gets added to one day's top bar + val day = days.lastOrNull { it.start <= eventStart } ?: days[0] + day.topBarEvents.add(event) + } else { + addNormalEventToDays(days, event, eventStart, eventEnd) + } + } + return days + } + + private fun addNormalEventToDays( + days: ArrayList, + event: Event, + eventStart: DateTime, + eventEnd: DateTime, + ) { + // the event gets added to all days it spans + for (day in days) { + val dayEnd = day.start.plusDays(1) + val eventIsDuringThisDay = eventStart < dayEnd && eventEnd > day.start + val eventStartsAndEndsWithDay = eventStart == day.start && eventEnd == day.start + if (eventIsDuringThisDay || eventStartsAndEndsWithDay) { + val startM = eventStart.coerceAtLeast(day.start).minuteOfDay + val endM = eventEnd.coerceAtMost(dayEnd).minuteOfDay + // round to timeStep + val startMinute = divRound(startM, timeStepMinutes) * timeStepMinutes + val endMinute = divRound(endM, timeStepMinutes) * timeStepMinutes + day.dayEvents.add( + EventWeeklyView( + event, + startMinute, + endMinute.coerceAtLeast(startMinute + timeStepMinutes), + ) + ) + } + } + } + + private fun fixEventOverlap(days: ArrayList) { + // make sure that events don't overlap visually even if their timing overlaps + for (day in days) { + // prepare sweep-and-prune algorithm + val sapPoints = ArrayList() + for ((i, ews) in day.dayEvents.withIndex()) { + sapPoints.add(SweepAndPrunePoint(ews.startMinute, i, true)) + sapPoints.add(SweepAndPrunePoint(ews.endMinute, i, false)) + } + sapPoints.sortWith( + compareBy { it.minutes }.thenBy { it.isStart } + ) + fixEventOverlapDay(day, sapPoints) + } + } + + private fun fixEventOverlapDay(day: DayWeekly, sapPoints: ArrayList) { + // make sure that events don't overlap visually even if their timing overlaps + var startOfCurrentBlock = 0 + var neededSlots = 0 + val currentEvents = ArrayList() + for ((i, sap) in sapPoints.withIndex()) { + if (sap.isStart) { + if (neededSlots == 0) { + startOfCurrentBlock = i + } + currentEvents.add(sap.eventIndex) + } else { + currentEvents.remove(sap.eventIndex) + if (currentEvents.isEmpty()) { + // no events remain in the current block + // slots can now be distributed + distributeEventSlots(day, neededSlots, startOfCurrentBlock, i, sapPoints) + // reset needed slots for the next block + neededSlots = 0 + } + } + // at least as many slots as concurrent events are needed + neededSlots = neededSlots.coerceAtLeast(currentEvents.size) + } + } + + private fun distributeEventSlots( + day: DayWeekly, + neededSlots: Int, + startOfCurrentBlock: Int, + endOfCurrentBlock: Int, + sapPoints: ArrayList, + ) { + var slot = 0 + val slotUsage = (0 until neededSlots).map { false }.toMutableList(); + for (i in startOfCurrentBlock until endOfCurrentBlock) { + // reuse sweep-and-prune points to assign slots + val sap = sapPoints[i] + if (sap.isStart) { + // find next free slot + while (slotUsage[slot]) { + slot = (slot + 1) % neededSlots + } + // block slot + slotUsage[slot] = true + day.dayEvents[sap.eventIndex].slot = slot + day.dayEvents[sap.eventIndex].slotMax = neededSlots + slot = (slot + 1) % neededSlots + } else { + // free slot + slotUsage[day.dayEvents[sap.eventIndex].slot] = false + } + } + } + + private fun callbackWithHourRange(days: ArrayList) { + // allows hiding hours in which nothing happens + var earliestEventStartHour = HOURS_PER_DAY + var latestEventEndHour = 0 + for (day in days) { + val startHour = day.dayEvents.minOfOrNull { it.startMinute / MINUTES_PER_HOUR } + earliestEventStartHour = earliestEventStartHour.coerceAtMost(startHour ?: earliestEventStartHour) + val endHour = day.dayEvents.maxOfOrNull { + it.endMinute / MINUTES_PER_HOUR + if (it.endMinute % MINUTES_PER_HOUR > 0) 1 else 0 + } + latestEventEndHour = latestEventEndHour.coerceAtLeast(endHour ?: latestEventEndHour) } + if (earliestEventStartHour > latestEventEndHour) { + // looks like there are no events during this week, show default range + earliestEventStartHour = EMPTY_START_HOUR + latestEventEndHour = EMPTY_END_HOUR + } else if (latestEventEndHour - earliestEventStartHour < MIN_SHOWN_HOURS_PER_DAY ) { + // make sure that more than one hour is shown + val hoursToAdd = MIN_SHOWN_HOURS_PER_DAY - latestEventEndHour + earliestEventStartHour + earliestEventStartHour = (earliestEventStartHour - hoursToAdd / 2).coerceAtLeast(0) + latestEventEndHour = (latestEventEndHour + hoursToAdd - (hoursToAdd / 2)).coerceAtMost(HOURS_PER_DAY) + } + callback.updateWeeklyCalendar(context, days, earliestEventStartHour, latestEventEndHour) + } + + private class SweepAndPrunePoint ( + val minutes: Int, + val eventIndex: Int, + val isStart: Boolean, + ) + + /** + * Events are shown in the top bar if + * - they're marked as all-day + * - they don't end on the day they started and the 'showMidnightSpanningEventsAtTop' config flag is set to true + */ + private fun shouldAddEventOnTopBar( + event: Event, + startDateTime: DateTime, + endDateTime: DateTime, + ): Boolean { + val dayCodeStart = Formatter.getDayCodeFromDateTime(startDateTime) + val dayCodeEnd = Formatter.getDayCodeFromDateTime(endDateTime) + val spansMultipleDays = dayCodeStart != dayCodeEnd + return event.getIsAllDay() || (spansMultipleDays && context.config.showMidnightSpanningEventsAtTop) } } + +private fun divRound(a: Int, b: Int): Int { + return a / b + if ((a % b) * 2 >= b) 1 else 0 +} diff --git a/app/src/main/kotlin/org/fossify/calendar/interfaces/WeeklyCalendar.kt b/app/src/main/kotlin/org/fossify/calendar/interfaces/WeeklyCalendar.kt index 397eea659..090c7c50d 100644 --- a/app/src/main/kotlin/org/fossify/calendar/interfaces/WeeklyCalendar.kt +++ b/app/src/main/kotlin/org/fossify/calendar/interfaces/WeeklyCalendar.kt @@ -1,7 +1,8 @@ package org.fossify.calendar.interfaces -import org.fossify.calendar.models.Event +import android.content.Context +import org.fossify.calendar.models.DayWeekly interface WeeklyCalendar { - fun updateWeeklyCalendar(events: ArrayList) + fun updateWeeklyCalendar(context: Context, days: ArrayList, earliestStartHour: Int, latestEndHour: Int) } diff --git a/app/src/main/kotlin/org/fossify/calendar/models/DayWeekly.kt b/app/src/main/kotlin/org/fossify/calendar/models/DayWeekly.kt new file mode 100644 index 000000000..eb6338007 --- /dev/null +++ b/app/src/main/kotlin/org/fossify/calendar/models/DayWeekly.kt @@ -0,0 +1,9 @@ +package org.fossify.calendar.models + +import org.joda.time.DateTime + +data class DayWeekly( + val start: DateTime, + var topBarEvents: ArrayList, + var dayEvents: ArrayList, +) diff --git a/app/src/main/kotlin/org/fossify/calendar/models/EventWeeklyView.kt b/app/src/main/kotlin/org/fossify/calendar/models/EventWeeklyView.kt index 68163e258..2e9120f35 100644 --- a/app/src/main/kotlin/org/fossify/calendar/models/EventWeeklyView.kt +++ b/app/src/main/kotlin/org/fossify/calendar/models/EventWeeklyView.kt @@ -1,10 +1,9 @@ package org.fossify.calendar.models -import android.util.Range - data class EventWeeklyView( - val range: Range, + val event: Event, + val startMinute: Int, + val endMinute: Int, var slot: Int = 0, - var slotMax: Int = 0, - var collisions: ArrayList = ArrayList() + var slotMax: Int = 1, ) diff --git a/app/src/main/res/drawable-nodpi/img_widget_weekly_preview.png b/app/src/main/res/drawable-nodpi/img_widget_weekly_preview.png new file mode 100644 index 000000000..f93837426 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/img_widget_weekly_preview.png differ diff --git a/app/src/main/res/layout/fragment_week_widget.xml b/app/src/main/res/layout/fragment_week_widget.xml new file mode 100644 index 000000000..ce7880adc --- /dev/null +++ b/app/src/main/res/layout/fragment_week_widget.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/horizontal_1.xml b/app/src/main/res/layout/horizontal_1.xml new file mode 100644 index 000000000..e46b4f0f0 --- /dev/null +++ b/app/src/main/res/layout/horizontal_1.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/horizontal_10.xml b/app/src/main/res/layout/horizontal_10.xml new file mode 100644 index 000000000..bdca00171 --- /dev/null +++ b/app/src/main/res/layout/horizontal_10.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/horizontal_11.xml b/app/src/main/res/layout/horizontal_11.xml new file mode 100644 index 000000000..dac66e45e --- /dev/null +++ b/app/src/main/res/layout/horizontal_11.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/horizontal_12.xml b/app/src/main/res/layout/horizontal_12.xml new file mode 100644 index 000000000..587240ff1 --- /dev/null +++ b/app/src/main/res/layout/horizontal_12.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/horizontal_13.xml b/app/src/main/res/layout/horizontal_13.xml new file mode 100644 index 000000000..4b85ae038 --- /dev/null +++ b/app/src/main/res/layout/horizontal_13.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/horizontal_14.xml b/app/src/main/res/layout/horizontal_14.xml new file mode 100644 index 000000000..da320c52a --- /dev/null +++ b/app/src/main/res/layout/horizontal_14.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/horizontal_2.xml b/app/src/main/res/layout/horizontal_2.xml new file mode 100644 index 000000000..75a35c8f7 --- /dev/null +++ b/app/src/main/res/layout/horizontal_2.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/horizontal_3.xml b/app/src/main/res/layout/horizontal_3.xml new file mode 100644 index 000000000..5ce4b4d8f --- /dev/null +++ b/app/src/main/res/layout/horizontal_3.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/horizontal_4.xml b/app/src/main/res/layout/horizontal_4.xml new file mode 100644 index 000000000..99b8c5faa --- /dev/null +++ b/app/src/main/res/layout/horizontal_4.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/horizontal_5.xml b/app/src/main/res/layout/horizontal_5.xml new file mode 100644 index 000000000..31aa8b738 --- /dev/null +++ b/app/src/main/res/layout/horizontal_5.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/horizontal_6.xml b/app/src/main/res/layout/horizontal_6.xml new file mode 100644 index 000000000..d37033e0c --- /dev/null +++ b/app/src/main/res/layout/horizontal_6.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/horizontal_7.xml b/app/src/main/res/layout/horizontal_7.xml new file mode 100644 index 000000000..0e3886a58 --- /dev/null +++ b/app/src/main/res/layout/horizontal_7.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/horizontal_8.xml b/app/src/main/res/layout/horizontal_8.xml new file mode 100644 index 000000000..75536db73 --- /dev/null +++ b/app/src/main/res/layout/horizontal_8.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/horizontal_9.xml b/app/src/main/res/layout/horizontal_9.xml new file mode 100644 index 000000000..e07f0022d --- /dev/null +++ b/app/src/main/res/layout/horizontal_9.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/horizontal_line.xml b/app/src/main/res/layout/horizontal_line.xml new file mode 100644 index 000000000..9fa590f7b --- /dev/null +++ b/app/src/main/res/layout/horizontal_line.xml @@ -0,0 +1,5 @@ + + diff --git a/app/src/main/res/layout/vertical_1.xml b/app/src/main/res/layout/vertical_1.xml new file mode 100644 index 000000000..39fbadd8f --- /dev/null +++ b/app/src/main/res/layout/vertical_1.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_10.xml b/app/src/main/res/layout/vertical_10.xml new file mode 100644 index 000000000..140d05810 --- /dev/null +++ b/app/src/main/res/layout/vertical_10.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_11.xml b/app/src/main/res/layout/vertical_11.xml new file mode 100644 index 000000000..e2776c178 --- /dev/null +++ b/app/src/main/res/layout/vertical_11.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_12.xml b/app/src/main/res/layout/vertical_12.xml new file mode 100644 index 000000000..04ad459aa --- /dev/null +++ b/app/src/main/res/layout/vertical_12.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_13.xml b/app/src/main/res/layout/vertical_13.xml new file mode 100644 index 000000000..929a8e7f4 --- /dev/null +++ b/app/src/main/res/layout/vertical_13.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_14.xml b/app/src/main/res/layout/vertical_14.xml new file mode 100644 index 000000000..78c6d2396 --- /dev/null +++ b/app/src/main/res/layout/vertical_14.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_15.xml b/app/src/main/res/layout/vertical_15.xml new file mode 100644 index 000000000..57875111f --- /dev/null +++ b/app/src/main/res/layout/vertical_15.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_16.xml b/app/src/main/res/layout/vertical_16.xml new file mode 100644 index 000000000..1a217aad9 --- /dev/null +++ b/app/src/main/res/layout/vertical_16.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_17.xml b/app/src/main/res/layout/vertical_17.xml new file mode 100644 index 000000000..7ccbaf9e1 --- /dev/null +++ b/app/src/main/res/layout/vertical_17.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_18.xml b/app/src/main/res/layout/vertical_18.xml new file mode 100644 index 000000000..663284ce1 --- /dev/null +++ b/app/src/main/res/layout/vertical_18.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_19.xml b/app/src/main/res/layout/vertical_19.xml new file mode 100644 index 000000000..2f939c5c3 --- /dev/null +++ b/app/src/main/res/layout/vertical_19.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_2.xml b/app/src/main/res/layout/vertical_2.xml new file mode 100644 index 000000000..656bc9855 --- /dev/null +++ b/app/src/main/res/layout/vertical_2.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_20.xml b/app/src/main/res/layout/vertical_20.xml new file mode 100644 index 000000000..611f319e6 --- /dev/null +++ b/app/src/main/res/layout/vertical_20.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_21.xml b/app/src/main/res/layout/vertical_21.xml new file mode 100644 index 000000000..85d998a6c --- /dev/null +++ b/app/src/main/res/layout/vertical_21.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_22.xml b/app/src/main/res/layout/vertical_22.xml new file mode 100644 index 000000000..bf739805d --- /dev/null +++ b/app/src/main/res/layout/vertical_22.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_23.xml b/app/src/main/res/layout/vertical_23.xml new file mode 100644 index 000000000..645376073 --- /dev/null +++ b/app/src/main/res/layout/vertical_23.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_24.xml b/app/src/main/res/layout/vertical_24.xml new file mode 100644 index 000000000..311287d2b --- /dev/null +++ b/app/src/main/res/layout/vertical_24.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_25.xml b/app/src/main/res/layout/vertical_25.xml new file mode 100644 index 000000000..453972b16 --- /dev/null +++ b/app/src/main/res/layout/vertical_25.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_26.xml b/app/src/main/res/layout/vertical_26.xml new file mode 100644 index 000000000..a8783f463 --- /dev/null +++ b/app/src/main/res/layout/vertical_26.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_27.xml b/app/src/main/res/layout/vertical_27.xml new file mode 100644 index 000000000..726c5e363 --- /dev/null +++ b/app/src/main/res/layout/vertical_27.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_28.xml b/app/src/main/res/layout/vertical_28.xml new file mode 100644 index 000000000..3d7a3981d --- /dev/null +++ b/app/src/main/res/layout/vertical_28.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_29.xml b/app/src/main/res/layout/vertical_29.xml new file mode 100644 index 000000000..8ba4c59ad --- /dev/null +++ b/app/src/main/res/layout/vertical_29.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_3.xml b/app/src/main/res/layout/vertical_3.xml new file mode 100644 index 000000000..2ba9bd489 --- /dev/null +++ b/app/src/main/res/layout/vertical_3.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_30.xml b/app/src/main/res/layout/vertical_30.xml new file mode 100644 index 000000000..ff8de134c --- /dev/null +++ b/app/src/main/res/layout/vertical_30.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_31.xml b/app/src/main/res/layout/vertical_31.xml new file mode 100644 index 000000000..601d5e383 --- /dev/null +++ b/app/src/main/res/layout/vertical_31.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_32.xml b/app/src/main/res/layout/vertical_32.xml new file mode 100644 index 000000000..e25b8a686 --- /dev/null +++ b/app/src/main/res/layout/vertical_32.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_33.xml b/app/src/main/res/layout/vertical_33.xml new file mode 100644 index 000000000..9ff755a40 --- /dev/null +++ b/app/src/main/res/layout/vertical_33.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_34.xml b/app/src/main/res/layout/vertical_34.xml new file mode 100644 index 000000000..cb0b9f1f1 --- /dev/null +++ b/app/src/main/res/layout/vertical_34.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_35.xml b/app/src/main/res/layout/vertical_35.xml new file mode 100644 index 000000000..07b107b6f --- /dev/null +++ b/app/src/main/res/layout/vertical_35.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_36.xml b/app/src/main/res/layout/vertical_36.xml new file mode 100644 index 000000000..90f0b95eb --- /dev/null +++ b/app/src/main/res/layout/vertical_36.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_37.xml b/app/src/main/res/layout/vertical_37.xml new file mode 100644 index 000000000..c4a566e89 --- /dev/null +++ b/app/src/main/res/layout/vertical_37.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_38.xml b/app/src/main/res/layout/vertical_38.xml new file mode 100644 index 000000000..8ae17a6c0 --- /dev/null +++ b/app/src/main/res/layout/vertical_38.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_39.xml b/app/src/main/res/layout/vertical_39.xml new file mode 100644 index 000000000..d91590bb4 --- /dev/null +++ b/app/src/main/res/layout/vertical_39.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_4.xml b/app/src/main/res/layout/vertical_4.xml new file mode 100644 index 000000000..a62a6d541 --- /dev/null +++ b/app/src/main/res/layout/vertical_4.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_40.xml b/app/src/main/res/layout/vertical_40.xml new file mode 100644 index 000000000..f025908d0 --- /dev/null +++ b/app/src/main/res/layout/vertical_40.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_41.xml b/app/src/main/res/layout/vertical_41.xml new file mode 100644 index 000000000..da10e316c --- /dev/null +++ b/app/src/main/res/layout/vertical_41.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_42.xml b/app/src/main/res/layout/vertical_42.xml new file mode 100644 index 000000000..cfbf8c5f0 --- /dev/null +++ b/app/src/main/res/layout/vertical_42.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_43.xml b/app/src/main/res/layout/vertical_43.xml new file mode 100644 index 000000000..0cce68287 --- /dev/null +++ b/app/src/main/res/layout/vertical_43.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_44.xml b/app/src/main/res/layout/vertical_44.xml new file mode 100644 index 000000000..916da7eec --- /dev/null +++ b/app/src/main/res/layout/vertical_44.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_45.xml b/app/src/main/res/layout/vertical_45.xml new file mode 100644 index 000000000..0c6bbe880 --- /dev/null +++ b/app/src/main/res/layout/vertical_45.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_46.xml b/app/src/main/res/layout/vertical_46.xml new file mode 100644 index 000000000..866f8d288 --- /dev/null +++ b/app/src/main/res/layout/vertical_46.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_47.xml b/app/src/main/res/layout/vertical_47.xml new file mode 100644 index 000000000..a7589995f --- /dev/null +++ b/app/src/main/res/layout/vertical_47.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_48.xml b/app/src/main/res/layout/vertical_48.xml new file mode 100644 index 000000000..84c2dddb5 --- /dev/null +++ b/app/src/main/res/layout/vertical_48.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_49.xml b/app/src/main/res/layout/vertical_49.xml new file mode 100644 index 000000000..fe680a3a7 --- /dev/null +++ b/app/src/main/res/layout/vertical_49.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_5.xml b/app/src/main/res/layout/vertical_5.xml new file mode 100644 index 000000000..a4363d96e --- /dev/null +++ b/app/src/main/res/layout/vertical_5.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_50.xml b/app/src/main/res/layout/vertical_50.xml new file mode 100644 index 000000000..b883773c8 --- /dev/null +++ b/app/src/main/res/layout/vertical_50.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_51.xml b/app/src/main/res/layout/vertical_51.xml new file mode 100644 index 000000000..f8b78c454 --- /dev/null +++ b/app/src/main/res/layout/vertical_51.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_52.xml b/app/src/main/res/layout/vertical_52.xml new file mode 100644 index 000000000..9fdcab405 --- /dev/null +++ b/app/src/main/res/layout/vertical_52.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_53.xml b/app/src/main/res/layout/vertical_53.xml new file mode 100644 index 000000000..51555209a --- /dev/null +++ b/app/src/main/res/layout/vertical_53.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_54.xml b/app/src/main/res/layout/vertical_54.xml new file mode 100644 index 000000000..7bb40d2dc --- /dev/null +++ b/app/src/main/res/layout/vertical_54.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_55.xml b/app/src/main/res/layout/vertical_55.xml new file mode 100644 index 000000000..549246956 --- /dev/null +++ b/app/src/main/res/layout/vertical_55.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_56.xml b/app/src/main/res/layout/vertical_56.xml new file mode 100644 index 000000000..e40f2a828 --- /dev/null +++ b/app/src/main/res/layout/vertical_56.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_57.xml b/app/src/main/res/layout/vertical_57.xml new file mode 100644 index 000000000..4743e3558 --- /dev/null +++ b/app/src/main/res/layout/vertical_57.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_58.xml b/app/src/main/res/layout/vertical_58.xml new file mode 100644 index 000000000..d08accfab --- /dev/null +++ b/app/src/main/res/layout/vertical_58.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_59.xml b/app/src/main/res/layout/vertical_59.xml new file mode 100644 index 000000000..2e49dc33f --- /dev/null +++ b/app/src/main/res/layout/vertical_59.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_6.xml b/app/src/main/res/layout/vertical_6.xml new file mode 100644 index 000000000..a36adebde --- /dev/null +++ b/app/src/main/res/layout/vertical_6.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_60.xml b/app/src/main/res/layout/vertical_60.xml new file mode 100644 index 000000000..cfa9a6b1c --- /dev/null +++ b/app/src/main/res/layout/vertical_60.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_61.xml b/app/src/main/res/layout/vertical_61.xml new file mode 100644 index 000000000..09b4f3533 --- /dev/null +++ b/app/src/main/res/layout/vertical_61.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_62.xml b/app/src/main/res/layout/vertical_62.xml new file mode 100644 index 000000000..f0270e547 --- /dev/null +++ b/app/src/main/res/layout/vertical_62.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_63.xml b/app/src/main/res/layout/vertical_63.xml new file mode 100644 index 000000000..5fd374810 --- /dev/null +++ b/app/src/main/res/layout/vertical_63.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_64.xml b/app/src/main/res/layout/vertical_64.xml new file mode 100644 index 000000000..ffb825e74 --- /dev/null +++ b/app/src/main/res/layout/vertical_64.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_65.xml b/app/src/main/res/layout/vertical_65.xml new file mode 100644 index 000000000..4b5e2b31d --- /dev/null +++ b/app/src/main/res/layout/vertical_65.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_66.xml b/app/src/main/res/layout/vertical_66.xml new file mode 100644 index 000000000..d8cb15492 --- /dev/null +++ b/app/src/main/res/layout/vertical_66.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_67.xml b/app/src/main/res/layout/vertical_67.xml new file mode 100644 index 000000000..34bd25762 --- /dev/null +++ b/app/src/main/res/layout/vertical_67.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_68.xml b/app/src/main/res/layout/vertical_68.xml new file mode 100644 index 000000000..e618f8ae1 --- /dev/null +++ b/app/src/main/res/layout/vertical_68.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_69.xml b/app/src/main/res/layout/vertical_69.xml new file mode 100644 index 000000000..ef5a38f45 --- /dev/null +++ b/app/src/main/res/layout/vertical_69.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_7.xml b/app/src/main/res/layout/vertical_7.xml new file mode 100644 index 000000000..ccf8675fa --- /dev/null +++ b/app/src/main/res/layout/vertical_7.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_70.xml b/app/src/main/res/layout/vertical_70.xml new file mode 100644 index 000000000..6902954ce --- /dev/null +++ b/app/src/main/res/layout/vertical_70.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_71.xml b/app/src/main/res/layout/vertical_71.xml new file mode 100644 index 000000000..00489aab4 --- /dev/null +++ b/app/src/main/res/layout/vertical_71.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_72.xml b/app/src/main/res/layout/vertical_72.xml new file mode 100644 index 000000000..c81a96ae5 --- /dev/null +++ b/app/src/main/res/layout/vertical_72.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_73.xml b/app/src/main/res/layout/vertical_73.xml new file mode 100644 index 000000000..5abf02f24 --- /dev/null +++ b/app/src/main/res/layout/vertical_73.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_74.xml b/app/src/main/res/layout/vertical_74.xml new file mode 100644 index 000000000..46b436057 --- /dev/null +++ b/app/src/main/res/layout/vertical_74.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_75.xml b/app/src/main/res/layout/vertical_75.xml new file mode 100644 index 000000000..776fb0ce7 --- /dev/null +++ b/app/src/main/res/layout/vertical_75.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_76.xml b/app/src/main/res/layout/vertical_76.xml new file mode 100644 index 000000000..d7444cd6e --- /dev/null +++ b/app/src/main/res/layout/vertical_76.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_77.xml b/app/src/main/res/layout/vertical_77.xml new file mode 100644 index 000000000..eb51403b2 --- /dev/null +++ b/app/src/main/res/layout/vertical_77.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_78.xml b/app/src/main/res/layout/vertical_78.xml new file mode 100644 index 000000000..7cc84d33d --- /dev/null +++ b/app/src/main/res/layout/vertical_78.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_79.xml b/app/src/main/res/layout/vertical_79.xml new file mode 100644 index 000000000..7001ae681 --- /dev/null +++ b/app/src/main/res/layout/vertical_79.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_8.xml b/app/src/main/res/layout/vertical_8.xml new file mode 100644 index 000000000..7fef4f158 --- /dev/null +++ b/app/src/main/res/layout/vertical_8.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_80.xml b/app/src/main/res/layout/vertical_80.xml new file mode 100644 index 000000000..6600dea39 --- /dev/null +++ b/app/src/main/res/layout/vertical_80.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_81.xml b/app/src/main/res/layout/vertical_81.xml new file mode 100644 index 000000000..2cde4eb41 --- /dev/null +++ b/app/src/main/res/layout/vertical_81.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_82.xml b/app/src/main/res/layout/vertical_82.xml new file mode 100644 index 000000000..75bbda7ff --- /dev/null +++ b/app/src/main/res/layout/vertical_82.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_83.xml b/app/src/main/res/layout/vertical_83.xml new file mode 100644 index 000000000..9329f2b97 --- /dev/null +++ b/app/src/main/res/layout/vertical_83.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_84.xml b/app/src/main/res/layout/vertical_84.xml new file mode 100644 index 000000000..569d5a794 --- /dev/null +++ b/app/src/main/res/layout/vertical_84.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_85.xml b/app/src/main/res/layout/vertical_85.xml new file mode 100644 index 000000000..2aaec2278 --- /dev/null +++ b/app/src/main/res/layout/vertical_85.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_86.xml b/app/src/main/res/layout/vertical_86.xml new file mode 100644 index 000000000..e71a173c4 --- /dev/null +++ b/app/src/main/res/layout/vertical_86.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_87.xml b/app/src/main/res/layout/vertical_87.xml new file mode 100644 index 000000000..5a1089195 --- /dev/null +++ b/app/src/main/res/layout/vertical_87.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_88.xml b/app/src/main/res/layout/vertical_88.xml new file mode 100644 index 000000000..7cdde28d4 --- /dev/null +++ b/app/src/main/res/layout/vertical_88.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_89.xml b/app/src/main/res/layout/vertical_89.xml new file mode 100644 index 000000000..6ec66969f --- /dev/null +++ b/app/src/main/res/layout/vertical_89.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_9.xml b/app/src/main/res/layout/vertical_9.xml new file mode 100644 index 000000000..4fc1156cc --- /dev/null +++ b/app/src/main/res/layout/vertical_9.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_90.xml b/app/src/main/res/layout/vertical_90.xml new file mode 100644 index 000000000..4572a4b7e --- /dev/null +++ b/app/src/main/res/layout/vertical_90.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_91.xml b/app/src/main/res/layout/vertical_91.xml new file mode 100644 index 000000000..00b1a1a82 --- /dev/null +++ b/app/src/main/res/layout/vertical_91.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_92.xml b/app/src/main/res/layout/vertical_92.xml new file mode 100644 index 000000000..3e0bbb55b --- /dev/null +++ b/app/src/main/res/layout/vertical_92.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_93.xml b/app/src/main/res/layout/vertical_93.xml new file mode 100644 index 000000000..972f61edb --- /dev/null +++ b/app/src/main/res/layout/vertical_93.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_94.xml b/app/src/main/res/layout/vertical_94.xml new file mode 100644 index 000000000..fc1c3d8c0 --- /dev/null +++ b/app/src/main/res/layout/vertical_94.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_95.xml b/app/src/main/res/layout/vertical_95.xml new file mode 100644 index 000000000..70652e772 --- /dev/null +++ b/app/src/main/res/layout/vertical_95.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_96.xml b/app/src/main/res/layout/vertical_96.xml new file mode 100644 index 000000000..76bcc5cfc --- /dev/null +++ b/app/src/main/res/layout/vertical_96.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/vertical_line.xml b/app/src/main/res/layout/vertical_line.xml new file mode 100644 index 000000000..e4c0bce0c --- /dev/null +++ b/app/src/main/res/layout/vertical_line.xml @@ -0,0 +1,5 @@ + + diff --git a/app/src/main/res/layout/widget_config_weekly.xml b/app/src/main/res/layout/widget_config_weekly.xml new file mode 100644 index 000000000..f77b23fb0 --- /dev/null +++ b/app/src/main/res/layout/widget_config_weekly.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + +