1
0
mirror of https://github.com/wulkanowy/wulkanowy.git synced 2025-01-31 12:38:21 +01:00

Timetable widget improvements (#2219)

This commit is contained in:
Bartosz Bieniek 2023-07-25 23:05:14 +02:00 committed by GitHub
parent 398bc513fb
commit b296926423
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 524 additions and 206 deletions

View File

@ -124,14 +124,12 @@ class TimetableWidgetFactory(
val lessonStartTime = lesson.start.toFormattedString(TIME_FORMAT_STYLE)
val lessonEndTime = lesson.end.toFormattedString(TIME_FORMAT_STYLE)
val roomText = "${context.getString(R.string.timetable_room)} ${lesson.room}"
val remoteViews = RemoteViews(context.packageName, R.layout.item_widget_timetable).apply {
setTextViewText(R.id.timetableWidgetItemNumber, lesson.number.toString())
setTextViewText(R.id.timetableWidgetItemTimeStart, lessonStartTime)
setTextViewText(R.id.timetableWidgetItemTimeFinish, lessonEndTime)
setTextViewText(R.id.timetableWidgetItemSubject, lesson.subject)
setTextViewText(R.id.timetableWidgetItemRoom, roomText)
setTextViewText(R.id.timetableWidgetItemTeacher, lesson.teacher)
setTextViewText(R.id.timetableWidgetItemDescription, lesson.info)
setOnClickFillInIntent(R.id.timetableWidgetItemContainer, Intent())
@ -140,6 +138,12 @@ class TimetableWidgetFactory(
updateTheme()
clearLessonStyles(remoteViews)
if (lesson.room.isBlank()) {
remoteViews.setViewVisibility(R.id.timetableWidgetItemRoom, GONE)
} else {
remoteViews.setTextViewText(R.id.timetableWidgetItemRoom, lesson.room)
}
when {
lesson.canceled -> applyCancelledLessonStyles(remoteViews)
lesson.changes or lesson.info.isNotBlank() -> applyChangedLessonStyles(

View File

@ -8,6 +8,7 @@ import android.content.Context
import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.graphics.Bitmap
import android.widget.RemoteViews
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.graphics.drawable.DrawableCompat
@ -76,110 +77,151 @@ class TimetableWidgetProvider : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
GlobalScope.launch {
when (intent.action) {
ACTION_APPWIDGET_UPDATE -> onUpdate(context, intent)
ACTION_APPWIDGET_DELETED -> onDelete(intent)
ACTION_APPWIDGET_UPDATE -> onWidgetUpdate(context, intent)
ACTION_APPWIDGET_DELETED -> onWidgetDeleted(intent)
}
}
}
private suspend fun onUpdate(context: Context, intent: Intent) {
if (intent.getStringExtra(EXTRA_BUTTON_TYPE) == null) {
val isFromConfigure = intent.getBooleanExtra(EXTRA_FROM_CONFIGURE, false)
val appWidgetIds = intent.getIntArrayExtra(EXTRA_APPWIDGET_IDS) ?: return
private suspend fun onWidgetUpdate(context: Context, intent: Intent) {
val pressedButton = intent.getPressedButton()
appWidgetIds.forEach { appWidgetId ->
val student =
getStudent(sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0), appWidgetId)
val savedDataEpochDay = sharedPref.getLong(getDateWidgetKey(appWidgetId), 0)
val dateToLoad = if (isFromConfigure && savedDataEpochDay != 0L) {
LocalDate.ofEpochDay(savedDataEpochDay)
} else {
getWidgetDefaultDateToLoad(appWidgetId)
}
updateWidget(context, appWidgetId, dateToLoad, student)
}
if (pressedButton == null) {
val updatedWidgetIds = intent.getWidgetIds() ?: return
updatedWidgetIds.forEach { updateWidgetLayout(context, it) }
} else {
val buttonType = intent.getStringExtra(EXTRA_BUTTON_TYPE)
val toggledWidgetId = intent.getIntExtra(EXTRA_TOGGLED_WIDGET_ID, 0)
val student = getStudent(
sharedPref.getLong(getStudentWidgetKey(toggledWidgetId), 0), toggledWidgetId
)
val savedDate =
LocalDate.ofEpochDay(sharedPref.getLong(getDateWidgetKey(toggledWidgetId), 0))
val date = when (buttonType) {
BUTTON_RESET -> getWidgetDefaultDateToLoad(toggledWidgetId)
BUTTON_NEXT -> savedDate.nextSchoolDay
BUTTON_PREV -> savedDate.previousSchoolDay
else -> getWidgetDefaultDateToLoad(toggledWidgetId)
}
if (!buttonType.isNullOrBlank()) {
analytics.logEvent(
"changed_timetable_widget_day", "button" to buttonType
)
}
updateWidget(context, toggledWidgetId, date, student)
val widgetId = intent.getToggledWidgetId() ?: return
reportChangedDay(pressedButton)
updateSavedWidgetDate(widgetId, pressedButton)
updateWidgetLayout(context, widgetId)
}
}
private fun onDelete(intent: Intent) {
val appWidgetId = intent.getIntExtra(EXTRA_APPWIDGET_ID, 0)
private fun Intent.getPressedButton(): String? {
return getStringExtra(EXTRA_BUTTON_TYPE)
}
if (appWidgetId != 0) {
with(sharedPref) {
delete(getStudentWidgetKey(appWidgetId))
delete(getDateWidgetKey(appWidgetId))
}
private fun Intent.getWidgetIds(): IntArray? {
return getIntArrayExtra(EXTRA_APPWIDGET_IDS)
}
private fun Intent.getToggledWidgetId(): Int? {
val toggledWidgetId = getIntExtra(EXTRA_TOGGLED_WIDGET_ID, INVALID_APPWIDGET_ID)
return toggledWidgetId.takeIf { it != INVALID_APPWIDGET_ID }
}
private fun reportChangedDay(buttonType: String) {
if (buttonType.isNotBlank()) {
analytics.logEvent("changed_timetable_widget_day", "button" to buttonType)
}
}
private fun updateWidget(
context: Context, appWidgetId: Int, date: LocalDate, student: Student?
private fun updateSavedWidgetDate(widgetId: Int, buttonType: String) {
val savedDate = getSavedWidgetDate(widgetId)
val newDate = savedDate?.let { getNewDate(it, widgetId, buttonType) }
?: getWidgetDefaultDateToLoad(widgetId)
setWidgetDate(widgetId, newDate)
}
private fun getSavedWidgetDate(widgetId: Int): LocalDate? {
val epochDay = sharedPref.getLong(getDateWidgetKey(widgetId), 0)
return if (epochDay == 0L) null else LocalDate.ofEpochDay(epochDay)
}
private fun getNewDate(
currentDate: LocalDate,
widgetId: Int,
selectedButton: String
): LocalDate {
return when (selectedButton) {
BUTTON_NEXT -> currentDate.nextSchoolDay
BUTTON_PREV -> currentDate.previousSchoolDay
else -> getWidgetDefaultDateToLoad(widgetId)
}
}
private fun setWidgetDate(widgetId: Int, dateToSet: LocalDate) {
val widgetDateKey = getDateWidgetKey(widgetId)
sharedPref.putLong(widgetDateKey, dateToSet.toEpochDay(), true)
}
private fun getWidgetDefaultDateToLoad(widgetId: Int): LocalDate {
val lastLessonEndDateTime = getLastLessonDateTime(widgetId)
val todayDate = LocalDate.now()
val isLastLessonToday = lastLessonEndDateTime.toLocalDate() == todayDate
val isEndOfLessons = LocalDateTime.now() > lastLessonEndDateTime
return if (isLastLessonToday && isEndOfLessons) {
todayDate.nextSchoolDay
} else {
todayDate.nextOrSameSchoolDay
}
}
private fun getLastLessonDateTime(widgetId: Int): LocalDateTime {
val lastLessonTimestamp = sharedPref
.getLong(getTodayLastLessonEndDateTimeWidgetKey(widgetId), 0)
return LocalDateTime.ofEpochSecond(lastLessonTimestamp, 0, ZoneOffset.UTC)
}
private suspend fun updateWidgetLayout(
context: Context, widgetId: Int
) {
val nextNavIntent = createNavIntent(context, appWidgetId, appWidgetId, BUTTON_NEXT)
val prevNavIntent = createNavIntent(context, -appWidgetId, appWidgetId, BUTTON_PREV)
val resetNavIntent =
createNavIntent(context, Int.MAX_VALUE - appWidgetId, appWidgetId, BUTTON_RESET)
val adapterIntent = Intent(context, TimetableWidgetService::class.java).apply {
putExtra(EXTRA_APPWIDGET_ID, appWidgetId)
action = appWidgetId.toString() //make Intent unique
}
val appIntent = PendingIntent.getActivity(
context,
TIMETABLE_PENDING_INTENT_ID,
SplashActivity.getStartIntent(context, Destination.Timetable()),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
)
val widgetRemoteViews = RemoteViews(context.packageName, R.layout.widget_timetable)
// Apply the click action intent
val appIntent = createPendingAppIntent(context)
widgetRemoteViews.setPendingIntentTemplate(R.id.timetableWidgetList, appIntent)
// Display saved date
val date = getSavedWidgetDate(widgetId) ?: getWidgetDefaultDateToLoad(widgetId)
val formattedDate = date.toFormattedString("EEE, dd.MM").capitalise()
val remoteView = RemoteViews(context.packageName, R.layout.widget_timetable).apply {
setEmptyView(R.id.timetableWidgetList, R.id.timetableWidgetEmpty)
setTextViewText(R.id.timetableWidgetDate, formattedDate)
setRemoteAdapter(R.id.timetableWidgetList, adapterIntent)
widgetRemoteViews.setTextViewText(R.id.timetableWidgetDate, formattedDate)
// Apply intents to the date switcher buttons
val nextNavIntent = createNavButtonIntent(context, widgetId, widgetId, BUTTON_NEXT)
val prevNavIntent = createNavButtonIntent(context, -widgetId, widgetId, BUTTON_PREV)
val resetNavIntent =
createNavButtonIntent(context, Int.MAX_VALUE - widgetId, widgetId, BUTTON_RESET)
widgetRemoteViews.run {
setOnClickPendingIntent(R.id.timetableWidgetNext, nextNavIntent)
setOnClickPendingIntent(R.id.timetableWidgetPrev, prevNavIntent)
setOnClickPendingIntent(R.id.timetableWidgetDate, resetNavIntent)
setPendingIntentTemplate(R.id.timetableWidgetList, appIntent)
}
student?.let {
setupAccountView(context, student, remoteView, appWidgetId)
// Setup the lesson list adapter
val lessonListAdapterIntent = createLessonListAdapterIntent(context, widgetId)
// --- Ensure the selected date is stored in the shared preferences,
// --- on which the TimetableWidgetFactory relies
setWidgetDate(widgetId, date)
// ---
widgetRemoteViews.apply {
setEmptyView(R.id.timetableWidgetList, R.id.timetableWidgetEmpty)
setRemoteAdapter(R.id.timetableWidgetList, lessonListAdapterIntent)
}
with(sharedPref) {
putLong(getDateWidgetKey(appWidgetId), date.toEpochDay(), true)
// Setup profile picture
getWidgetStudent(widgetId)?.let { student ->
setupAccountView(context, student, widgetRemoteViews, widgetId)
}
// Apply updates
with(appWidgetManager) {
partiallyUpdateAppWidget(appWidgetId, remoteView)
notifyAppWidgetViewDataChanged(appWidgetId, R.id.timetableWidgetList)
partiallyUpdateAppWidget(widgetId, widgetRemoteViews)
notifyAppWidgetViewDataChanged(widgetId, R.id.timetableWidgetList)
}
Timber.d("TimetableWidgetProvider updated")
}
private fun createNavIntent(
private fun createPendingAppIntent(context: Context) = PendingIntent.getActivity(
context, TIMETABLE_PENDING_INTENT_ID,
SplashActivity.getStartIntent(context, Destination.Timetable()),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
)
private fun createNavButtonIntent(
context: Context, code: Int, appWidgetId: Int, buttonType: String
) = PendingIntent.getBroadcast(
context, code, Intent(context, TimetableWidgetProvider::class.java).apply {
@ -189,6 +231,17 @@ class TimetableWidgetProvider : BroadcastReceiver() {
}, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
)
private fun createLessonListAdapterIntent(context: Context, widgetId: Int) =
Intent(context, TimetableWidgetService::class.java).apply {
putExtra(EXTRA_APPWIDGET_ID, widgetId)
action = widgetId.toString() //make Intent unique
}
private suspend fun getWidgetStudent(widgetId: Int): Student? {
val studentId = sharedPref.getLong(getStudentWidgetKey(widgetId), 0)
return getStudent(studentId, widgetId)
}
private suspend fun getStudent(studentId: Long, appWidgetId: Int) = try {
val students = studentRepository.getSavedStudents(false)
val student = students.singleOrNull { it.student.id == studentId }?.student
@ -199,6 +252,7 @@ class TimetableWidgetProvider : BroadcastReceiver() {
sharedPref.putLong(getStudentWidgetKey(appWidgetId), it.id)
}
}
else -> null
}
} catch (e: Exception) {
@ -208,60 +262,64 @@ class TimetableWidgetProvider : BroadcastReceiver() {
null
}
private fun getWidgetDefaultDateToLoad(appWidgetId: Int): LocalDate {
val lastLessonEndTimestamp =
sharedPref.getLong(getTodayLastLessonEndDateTimeWidgetKey(appWidgetId), 0)
val lastLessonEndDateTime =
LocalDateTime.ofEpochSecond(lastLessonEndTimestamp, 0, ZoneOffset.UTC)
private fun setupAccountView(
context: Context, student: Student, remoteViews: RemoteViews, widgetId: Int
) {
val accountInitials = getAccountInitials(student.nickOrName)
val accountPickerPendingIntent = createAccountPickerPendingIntent(context, widgetId)
val todayDate = LocalDate.now()
val isLastLessonEndDateNow = lastLessonEndDateTime.toLocalDate() == todayDate
val isLastLessonEndDateAfterNowTime = LocalDateTime.now() > lastLessonEndDateTime
getAvatarBackgroundBitmap(context, student.avatarColor)?.let {
remoteViews.setImageViewBitmap(R.id.timetableWidgetAccountBackground, it)
}
return if (isLastLessonEndDateNow && isLastLessonEndDateAfterNowTime) {
todayDate.nextSchoolDay
} else {
todayDate.nextOrSameSchoolDay
remoteViews.apply {
setTextViewText(R.id.timetableWidgetAccountInitials, accountInitials)
setOnClickPendingIntent(R.id.timetableWidgetAccount, accountPickerPendingIntent)
}
}
private fun setupAccountView(
context: Context,
student: Student,
remoteViews: RemoteViews,
appWidgetId: Int
) {
val accountInitials = student.nickOrName
.split(" ")
.mapNotNull { it.firstOrNull() }.take(2)
.joinToString(separator = "").uppercase()
private fun getAccountInitials(name: String): String {
val firstLetters = name.split(" ").mapNotNull { it.firstOrNull() }
return firstLetters.joinToString(separator = "").uppercase()
}
val accountPickerIntent = PendingIntent.getActivity(
private fun createAccountPickerPendingIntent(context: Context, widgetId: Int) =
PendingIntent.getActivity(
context,
-Int.MAX_VALUE + appWidgetId,
-Int.MAX_VALUE + widgetId,
Intent(context, TimetableWidgetConfigureActivity::class.java).apply {
addFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK)
putExtra(EXTRA_APPWIDGET_ID, appWidgetId)
putExtra(EXTRA_APPWIDGET_ID, widgetId)
putExtra(EXTRA_FROM_PROVIDER, true)
},
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
)
// Create background bitmap
private fun getAvatarBackgroundBitmap(context: Context, avatarColor: Long): Bitmap? {
val avatarDrawableResource = R.drawable.background_timetable_widget_avatar
AppCompatResources.getDrawable(context, avatarDrawableResource)?.let { drawable ->
return AppCompatResources.getDrawable(context, avatarDrawableResource)?.let { drawable ->
val screenDensity = context.resources.displayMetrics.density
val avatarSize = (48 * screenDensity).toInt()
val backgroundBitmap = DrawableCompat.wrap(drawable).run {
DrawableCompat.setTint(this, student.avatarColor.toInt())
DrawableCompat.wrap(drawable).run {
DrawableCompat.setTint(this, avatarColor.toInt())
toBitmap(avatarSize, avatarSize)
}
remoteViews.setImageViewBitmap(R.id.timetableWidgetAccountBackground, backgroundBitmap)
}
}
remoteViews.apply {
setTextViewText(R.id.timetableWidgetAccountInitials, accountInitials)
setOnClickPendingIntent(R.id.timetableWidgetAccount, accountPickerIntent)
private fun onWidgetDeleted(intent: Intent) {
val deletedWidgetId = intent.getWidgetId()
deleteWidgetPreferences(deletedWidgetId)
}
private fun Intent.getWidgetId(): Int {
return getIntExtra(EXTRA_APPWIDGET_ID, INVALID_APPWIDGET_ID)
}
private fun deleteWidgetPreferences(widgetId: Int) {
with(sharedPref) {
delete(getStudentWidgetKey(widgetId))
delete(getDateWidgetKey(widgetId))
}
}
}

View File

@ -2,5 +2,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FF000000" />
<corners android:radius="12dp" />
<corners android:radius="14dp" />
</shape>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFBFF" />
<corners android:radius="12dp" />
<corners android:radius="14dp" />
</shape>

View File

@ -1,6 +1,6 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:width="20dp"
android:height="20dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path

View File

@ -1,6 +1,6 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:width="20dp"
android:height="20dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 75 KiB

View File

@ -5,10 +5,10 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background_widget_timetable"
android:backgroundTint="?attr/colorSurface"
android:backgroundTint="?attr/colorSecondaryContainer"
android:clipToOutline="true"
android:orientation="vertical"
android:paddingHorizontal="16dp"
android:paddingHorizontal="12dp"
android:theme="@style/Wulkanowy.Widget.Theme"
tools:context=".ui.modules.timetablewidget.TimetableWidgetProvider">
@ -16,23 +16,47 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingVertical="16dp">
android:paddingTop="12dp"
android:paddingBottom="8dp">
<FrameLayout
android:layout_width="48dp"
android:layout_height="48dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:importantForAccessibility="no"
android:src="@drawable/background_timetable_widget_avatar"
android:tint="?attr/colorPrimary"
app:tint="?attr/colorPrimary"
tools:ignore="UseAppTint" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="JK"
android:textAppearance="?attr/textAppearanceTitleLarge"
android:textColor="?attr/colorOnPrimary"
android:textSize="18sp"
tools:ignore="HardcodedText" />
</FrameLayout>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginHorizontal="12dp"
android:layout_weight="1"
android:lines="1"
android:text="Pon, 03.10"
android:textAppearance="?attr/textAppearanceHeadline5"
android:text="Pon, 19.05"
android:textSize="18sp"
tools:ignore="HardcodedText" />
<ImageButton
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="12dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/all_prev"
android:rotation="180"
@ -51,46 +75,273 @@
app:tint="?attr/colorPrimary"
tools:ignore="UseAppTint" />
<TextView
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="12dp"
android:background="@drawable/background_timetable_widget_avatar"
android:backgroundTint="?attr/colorPrimary"
android:contentDescription="@string/account_quick_manager"
android:gravity="center"
android:text="AW"
android:textAppearance="?attr/textAppearanceTitleLarge"
android:textColor="?attr/colorOnPrimary" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:showDividers="middle">
android:paddingBottom="12dp">
<ImageView
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:importantForAccessibility="no"
android:src="@drawable/background_widget_item_timetable"
app:tint="?attr/backgroundColor" />
android:background="@drawable/background_widget_item_timetable"
android:backgroundTint="?attr/colorSurface"
android:gravity="center_vertical"
android:minHeight="48dp"
android:orientation="horizontal"
android:paddingHorizontal="12dp"
android:paddingVertical="8dp">
<ImageView
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
android:textSize="22sp"
tools:ignore="HardcodedText" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="08:00"
android:textAppearance="?attr/textAppearanceBodySmall"
tools:ignore="HardcodedText" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="09:45"
android:textAppearance="?attr/textAppearanceBodySmall"
tools:ignore="HardcodedText" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:text="Wychowanie fizyczne"
android:textSize="14sp"
tools:ignore="HardcodedText" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:text="213"
android:textSize="12sp"
tools:ignore="HardcodedText" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:text="Dorota Nowak"
android:textAppearance="?attr/textAppearanceBodySmall"
tools:ignore="HardcodedText" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:importantForAccessibility="no"
android:src="@drawable/background_widget_item_timetable"
app:tint="?attr/backgroundColor" />
android:background="@drawable/background_widget_item_timetable"
android:backgroundTint="?attr/colorSurface"
android:gravity="center_vertical"
android:minHeight="48dp"
android:orientation="horizontal"
android:paddingHorizontal="12dp"
android:paddingVertical="8dp">
<ImageView
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2"
android:textSize="22sp"
tools:ignore="HardcodedText"
tools:textColor="?attr/colorTimetableChange" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="08:50"
android:textAppearance="?attr/textAppearanceBodySmall"
tools:ignore="HardcodedText" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="09:35"
android:textAppearance="?attr/textAppearanceBodySmall"
tools:ignore="HardcodedText" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:text="Język polski"
android:textColor="?attr/colorTimetableChange"
android:textSize="14sp"
tools:ignore="HardcodedText" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:text="125"
android:textSize="12sp"
tools:ignore="HardcodedText" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:text="Karolina Kowalska"
android:textAppearance="?attr/textAppearanceBodySmall"
android:textColor="?attr/colorTimetableChange"
tools:ignore="HardcodedText" />
</LinearLayout>
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:contentDescription="@string/timetable_changes"
android:tint="?attr/colorTimetableChange"
app:tint="?attr/colorTimetableChange"
tools:ignore="UseAppTint"
tools:src="@drawable/ic_timetable_widget_swap" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:importantForAccessibility="no"
android:src="@drawable/background_widget_item_timetable"
app:tint="?attr/backgroundColor" />
android:layout_height="wrap_content"
android:background="@drawable/background_widget_item_timetable"
android:backgroundTint="?attr/colorSurface"
android:gravity="center_vertical"
android:minHeight="48dp"
android:orientation="horizontal"
android:paddingHorizontal="12dp"
android:paddingVertical="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3"
android:textSize="22sp"
tools:ignore="HardcodedText"
tools:textColor="?attr/colorTimetableCanceled" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="09:45"
android:textAppearance="?attr/textAppearanceBodySmall"
tools:ignore="HardcodedText" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="10:30"
android:textAppearance="?attr/textAppearanceBodySmall"
tools:ignore="HardcodedText" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:text="Wiedza o społeczeństwie"
android:textColor="?attr/colorTimetableCanceled"
android:textSize="14sp"
tools:ignore="HardcodedText" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Lekcja odwołana: uczniowie zwolnieni do domu"
android:textAppearance="?attr/textAppearanceBodySmall"
android:textColor="?attr/colorTimetableCanceled"
tools:ignore="HardcodedText" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -6,11 +6,12 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/background_widget_item_timetable"
android:backgroundTint="?attr/backgroundColor"
android:backgroundTint="?attr/colorSurface"
android:gravity="center_vertical"
android:minHeight="48dp"
android:orientation="horizontal"
android:paddingHorizontal="16dp"
android:paddingVertical="12dp"
android:paddingHorizontal="12dp"
android:paddingVertical="8dp"
android:theme="@style/Wulkanowy.Widget.Theme"
tools:context=".ui.modules.timetablewidget.TimetableWidgetFactory">
@ -18,15 +19,14 @@
android:id="@+id/timetableWidgetItemNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceHeadline6"
android:textSize="24sp"
android:textSize="22sp"
tools:text="1"
tools:textColor="?attr/colorTimetableChange" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginStart="10dp"
android:gravity="center_vertical"
android:orientation="vertical">
@ -41,7 +41,7 @@
android:id="@+id/timetableWidgetItemTimeFinish"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginTop="2dp"
android:textAppearance="?attr/textAppearanceBodySmall"
tools:text="09:45" />
@ -60,7 +60,7 @@
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:textAppearance="?attr/textAppearanceTitleMedium"
android:textSize="14sp"
tools:text="Programowanie aplikacji mobilnych i desktopowych" />
<LinearLayout
@ -72,15 +72,15 @@
android:id="@+id/timetableWidgetItemRoom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:textAppearance="?attr/textAppearanceBodySmall"
tools:text="Sala 213"
tools:text="213"
tools:textColor="?attr/colorTimetableChange" />
<TextView
android:id="@+id/timetableWidgetItemTeacher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:ellipsize="end"
android:lines="1"
android:textAppearance="?attr/textAppearanceBodySmall"

View File

@ -5,35 +5,70 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background_widget_timetable"
android:backgroundTint="?attr/colorSurface"
android:backgroundTint="?attr/colorSecondaryContainer"
android:clipToOutline="true"
android:orientation="vertical"
android:paddingHorizontal="16dp"
android:paddingHorizontal="12dp"
android:theme="@style/Wulkanowy.Widget.Theme"
tools:context=".ui.modules.timetablewidget.TimetableWidgetProvider">
tools:context=".ui.modules.timetablewidget.TimetableWidgetProvider"
tools:targetApi="s">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingVertical="16dp">
android:paddingTop="12dp"
android:paddingBottom="8dp">
<FrameLayout
android:id="@+id/timetableWidgetAccount"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="@drawable/background_timetable_widget_avatar"
android:backgroundTint="@android:color/transparent"
android:clickable="true"
android:clipToOutline="true"
android:contentDescription="@string/account_quick_manager"
android:focusable="true"
android:foreground="?attr/selectableItemBackgroundBorderless"
android:importantForAccessibility="yes"
android:outlineProvider="background"
tools:targetApi="s">
<ImageView
android:id="@+id/timetableWidgetAccountBackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:importantForAccessibility="no"
tools:src="@drawable/background_timetable_widget_avatar"
tools:tint="?attr/colorPrimary" />
<TextView
android:id="@+id/timetableWidgetAccountInitials"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAppearance="?attr/textAppearanceTitleLarge"
android:textColor="@android:color/white"
android:textSize="18sp"
tools:text="JK" />
</FrameLayout>
<TextView
android:id="@+id/timetableWidgetDate"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginHorizontal="12dp"
android:layout_weight="1"
android:lines="1"
android:textAppearance="?attr/textAppearanceHeadline5"
tools:text="Pon, 12.05" />
android:textSize="18sp"
tools:text="Friday, 19.05" />
<ImageButton
android:id="@+id/timetableWidgetPrev"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="12dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/all_prev"
android:rotation="180"
@ -53,39 +88,6 @@
app:tint="?attr/colorPrimary"
tools:ignore="UseAppTint" />
<FrameLayout
android:id="@+id/timetableWidgetAccount"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="12dp"
android:background="@drawable/background_timetable_widget_avatar"
android:backgroundTint="@android:color/transparent"
android:clickable="true"
android:clipToOutline="true"
android:contentDescription="@string/account_quick_manager"
android:focusable="true"
android:foreground="?attr/selectableItemBackgroundBorderless"
android:importantForAccessibility="yes"
android:outlineProvider="background">
<ImageView
android:id="@+id/timetableWidgetAccountBackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:importantForAccessibility="no"
tools:src="@drawable/background_timetable_widget_avatar"
tools:tint="?attr/colorPrimary" />
<TextView
android:id="@+id/timetableWidgetAccountInitials"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAppearance="?attr/textAppearanceTitleLarge"
android:textColor="@android:color/white"
android:textSize="20sp"
tools:text="AW" />
</FrameLayout>
</LinearLayout>
<FrameLayout
@ -99,6 +101,7 @@
android:clipToPadding="false"
android:divider="@android:color/transparent"
android:dividerHeight="4dp"
android:listSelector="@android:color/transparent"
android:paddingBottom="16dp"
tools:listfooter="@layout/item_widget_timetable_footer"
tools:listitem="@layout/item_widget_timetable" />
@ -111,5 +114,7 @@
android:text="@string/widget_timetable_no_items"
android:textAppearance="?attr/textAppearanceBody1"
android:visibility="gone" />
</FrameLayout>
</LinearLayout>

View File

@ -3,15 +3,15 @@
xmlns:tools="http://schemas.android.com/tools"
android:configure="io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetConfigureActivity"
android:initialLayout="@layout/widget_timetable"
android:minWidth="250dp"
android:minHeight="110dp"
android:minResizeWidth="250dp"
android:minResizeHeight="110dp"
android:minWidth="245dp"
android:minHeight="102dp"
android:minResizeWidth="245dp"
android:minResizeHeight="102dp"
android:previewImage="@drawable/img_timetable_widget_preview"
android:previewLayout="@layout/widget_timetable_preview"
android:resizeMode="horizontal|vertical"
android:targetCellWidth="3"
android:targetCellHeight="2"
android:targetCellHeight="3"
android:updatePeriodMillis="3600000"
android:widgetCategory="home_screen"
tools:targetApi="s" />