forked from github/wulkanowy-mirror
Add drag and drop to dashboard tiles (#1415)
This commit is contained in:
parent
72ef5f428e
commit
626169de11
@ -2,9 +2,12 @@ package io.github.wulkanowy.data.repositories
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import com.squareup.moshi.Moshi
|
import androidx.core.content.edit
|
||||||
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
|
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
|
||||||
import com.fredporciuncula.flow.preferences.Preference
|
import com.fredporciuncula.flow.preferences.Preference
|
||||||
|
import com.squareup.moshi.JsonAdapter
|
||||||
|
import com.squareup.moshi.Moshi
|
||||||
|
import com.squareup.moshi.adapter
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
||||||
@ -21,8 +24,13 @@ import javax.inject.Singleton
|
|||||||
class PreferencesRepository @Inject constructor(
|
class PreferencesRepository @Inject constructor(
|
||||||
private val sharedPref: SharedPreferences,
|
private val sharedPref: SharedPreferences,
|
||||||
private val flowSharedPref: FlowSharedPreferences,
|
private val flowSharedPref: FlowSharedPreferences,
|
||||||
@ApplicationContext val context: Context
|
@ApplicationContext val context: Context,
|
||||||
|
moshi: Moshi
|
||||||
) {
|
) {
|
||||||
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
|
private val dashboardItemsPositionAdapter: JsonAdapter<Map<DashboardItem.Type, Int>> =
|
||||||
|
moshi.adapter()
|
||||||
|
|
||||||
val startMenuIndex: Int
|
val startMenuIndex: Int
|
||||||
get() = getString(R.string.pref_key_start_menu, R.string.pref_default_startup).toInt()
|
get() = getString(R.string.pref_key_start_menu, R.string.pref_default_startup).toInt()
|
||||||
|
|
||||||
@ -160,6 +168,19 @@ class PreferencesRepository @Inject constructor(
|
|||||||
R.bool.pref_default_optional_arithmetic_average
|
R.bool.pref_default_optional_arithmetic_average
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var dashboardItemsPosition: Map<DashboardItem.Type, Int>?
|
||||||
|
get() {
|
||||||
|
val json = sharedPref.getString(PREF_KEY_DASHBOARD_ITEMS_POSITION, null) ?: return null
|
||||||
|
|
||||||
|
return dashboardItemsPositionAdapter.fromJson(json)
|
||||||
|
}
|
||||||
|
set(value) = sharedPref.edit {
|
||||||
|
putString(
|
||||||
|
PREF_KEY_DASHBOARD_ITEMS_POSITION,
|
||||||
|
dashboardItemsPositionAdapter.toJson(value)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
val selectedDashboardTilesFlow: Flow<Set<DashboardItem.Tile>>
|
val selectedDashboardTilesFlow: Flow<Set<DashboardItem.Tile>>
|
||||||
get() = selectedDashboardTilesPreference.asFlow()
|
get() = selectedDashboardTilesPreference.asFlow()
|
||||||
.map { set ->
|
.map { set ->
|
||||||
@ -199,4 +220,9 @@ class PreferencesRepository @Inject constructor(
|
|||||||
|
|
||||||
private fun getBoolean(id: String, default: Int) =
|
private fun getBoolean(id: String, default: Int) =
|
||||||
sharedPref.getBoolean(id, context.resources.getBoolean(default))
|
sharedPref.getBoolean(id, context.resources.getBoolean(default))
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
|
||||||
|
private const val PREF_KEY_DASHBOARD_ITEMS_POSITION = "dashboard_items_position"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import androidx.core.view.updateLayoutParams
|
|||||||
import androidx.core.view.updateMarginsRelative
|
import androidx.core.view.updateMarginsRelative
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.Timetable
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
@ -38,10 +37,9 @@ import java.util.Timer
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.concurrent.timer
|
import kotlin.concurrent.timer
|
||||||
|
|
||||||
class DashboardAdapter @Inject constructor() :
|
class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
ListAdapter<DashboardItem, RecyclerView.ViewHolder>(DashboardAdapterDiffCallback()) {
|
|
||||||
|
|
||||||
var lessonsTimer: Timer? = null
|
private var lessonsTimer: Timer? = null
|
||||||
|
|
||||||
var onAccountTileClickListener: () -> Unit = {}
|
var onAccountTileClickListener: () -> Unit = {}
|
||||||
|
|
||||||
@ -63,7 +61,23 @@ class DashboardAdapter @Inject constructor() :
|
|||||||
|
|
||||||
var onConferencesTileClickListener: () -> Unit = {}
|
var onConferencesTileClickListener: () -> Unit = {}
|
||||||
|
|
||||||
override fun getItemViewType(position: Int) = getItem(position).type.ordinal
|
val items = mutableListOf<DashboardItem>()
|
||||||
|
|
||||||
|
fun submitList(newItems: List<DashboardItem>) {
|
||||||
|
val diffResult =
|
||||||
|
DiffUtil.calculateDiff(DiffCallback(newItems, items.toMutableList()))
|
||||||
|
|
||||||
|
with(items) {
|
||||||
|
clear()
|
||||||
|
addAll(newItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
diffResult.dispatchUpdatesTo(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
|
override fun getItemViewType(position: Int) = items[position].type.ordinal
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
val inflater = LayoutInflater.from(parent.context)
|
val inflater = LayoutInflater.from(parent.context)
|
||||||
@ -119,7 +133,7 @@ class DashboardAdapter @Inject constructor() :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun bindAccountViewHolder(accountViewHolder: AccountViewHolder, position: Int) {
|
private fun bindAccountViewHolder(accountViewHolder: AccountViewHolder, position: Int) {
|
||||||
val item = getItem(position) as DashboardItem.Account
|
val item = items[position] as DashboardItem.Account
|
||||||
val student = item.student
|
val student = item.student
|
||||||
val isLoading = item.isLoading
|
val isLoading = item.isLoading
|
||||||
|
|
||||||
@ -147,7 +161,7 @@ class DashboardAdapter @Inject constructor() :
|
|||||||
horizontalGroupViewHolder: HorizontalGroupViewHolder,
|
horizontalGroupViewHolder: HorizontalGroupViewHolder,
|
||||||
position: Int
|
position: Int
|
||||||
) {
|
) {
|
||||||
val item = getItem(position) as DashboardItem.HorizontalGroup
|
val item = items[position] as DashboardItem.HorizontalGroup
|
||||||
val unreadMessagesCount = item.unreadMessagesCount
|
val unreadMessagesCount = item.unreadMessagesCount
|
||||||
val attendancePercentage = item.attendancePercentage
|
val attendancePercentage = item.attendancePercentage
|
||||||
val luckyNumber = item.luckyNumber
|
val luckyNumber = item.luckyNumber
|
||||||
@ -221,7 +235,7 @@ class DashboardAdapter @Inject constructor() :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun bindGradesViewHolder(gradesViewHolder: GradesViewHolder, position: Int) {
|
private fun bindGradesViewHolder(gradesViewHolder: GradesViewHolder, position: Int) {
|
||||||
val item = getItem(position) as DashboardItem.Grades
|
val item = items[position] as DashboardItem.Grades
|
||||||
val subjectWithGrades = item.subjectWithGrades.orEmpty()
|
val subjectWithGrades = item.subjectWithGrades.orEmpty()
|
||||||
val gradeTheme = item.gradeTheme
|
val gradeTheme = item.gradeTheme
|
||||||
val error = item.error
|
val error = item.error
|
||||||
@ -250,7 +264,7 @@ class DashboardAdapter @Inject constructor() :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun bindLessonsViewHolder(lessonsViewHolder: LessonsViewHolder, position: Int) {
|
private fun bindLessonsViewHolder(lessonsViewHolder: LessonsViewHolder, position: Int) {
|
||||||
val item = getItem(position) as DashboardItem.Lessons
|
val item = items[position] as DashboardItem.Lessons
|
||||||
val timetableFull = item.lessons
|
val timetableFull = item.lessons
|
||||||
val binding = lessonsViewHolder.binding
|
val binding = lessonsViewHolder.binding
|
||||||
|
|
||||||
@ -519,7 +533,7 @@ class DashboardAdapter @Inject constructor() :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun bindHomeworkViewHolder(homeworkViewHolder: HomeworkViewHolder, position: Int) {
|
private fun bindHomeworkViewHolder(homeworkViewHolder: HomeworkViewHolder, position: Int) {
|
||||||
val item = getItem(position) as DashboardItem.Homework
|
val item = items[position] as DashboardItem.Homework
|
||||||
val homeworkList = item.homework.orEmpty()
|
val homeworkList = item.homework.orEmpty()
|
||||||
val error = item.error
|
val error = item.error
|
||||||
val isLoading = item.isLoading
|
val isLoading = item.isLoading
|
||||||
@ -557,7 +571,7 @@ class DashboardAdapter @Inject constructor() :
|
|||||||
announcementsViewHolder: AnnouncementsViewHolder,
|
announcementsViewHolder: AnnouncementsViewHolder,
|
||||||
position: Int
|
position: Int
|
||||||
) {
|
) {
|
||||||
val item = getItem(position) as DashboardItem.Announcements
|
val item = items[position] as DashboardItem.Announcements
|
||||||
val schoolAnnouncementList = item.announcement.orEmpty()
|
val schoolAnnouncementList = item.announcement.orEmpty()
|
||||||
val error = item.error
|
val error = item.error
|
||||||
val isLoading = item.isLoading
|
val isLoading = item.isLoading
|
||||||
@ -594,7 +608,7 @@ class DashboardAdapter @Inject constructor() :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun bindExamsViewHolder(examsViewHolder: ExamsViewHolder, position: Int) {
|
private fun bindExamsViewHolder(examsViewHolder: ExamsViewHolder, position: Int) {
|
||||||
val item = getItem(position) as DashboardItem.Exams
|
val item = items[position] as DashboardItem.Exams
|
||||||
val exams = item.exams.orEmpty()
|
val exams = item.exams.orEmpty()
|
||||||
val error = item.error
|
val error = item.error
|
||||||
val isLoading = item.isLoading
|
val isLoading = item.isLoading
|
||||||
@ -630,7 +644,7 @@ class DashboardAdapter @Inject constructor() :
|
|||||||
conferencesViewHolder: ConferencesViewHolder,
|
conferencesViewHolder: ConferencesViewHolder,
|
||||||
position: Int
|
position: Int
|
||||||
) {
|
) {
|
||||||
val item = getItem(position) as DashboardItem.Conferences
|
val item = items[position] as DashboardItem.Conferences
|
||||||
val conferences = item.conferences.orEmpty()
|
val conferences = item.conferences.orEmpty()
|
||||||
val error = item.error
|
val error = item.error
|
||||||
val isLoading = item.isLoading
|
val isLoading = item.isLoading
|
||||||
@ -703,13 +717,20 @@ class DashboardAdapter @Inject constructor() :
|
|||||||
val adapter by lazy { DashboardConferencesAdapter() }
|
val adapter by lazy { DashboardConferencesAdapter() }
|
||||||
}
|
}
|
||||||
|
|
||||||
class DashboardAdapterDiffCallback : DiffUtil.ItemCallback<DashboardItem>() {
|
private class DiffCallback(
|
||||||
|
private val newList: List<DashboardItem>,
|
||||||
|
private val oldList: List<DashboardItem>
|
||||||
|
) : DiffUtil.Callback() {
|
||||||
|
|
||||||
override fun areItemsTheSame(oldItem: DashboardItem, newItem: DashboardItem) =
|
override fun getNewListSize() = newList.size
|
||||||
oldItem.type == newItem.type
|
|
||||||
|
|
||||||
override fun areContentsTheSame(oldItem: DashboardItem, newItem: DashboardItem) =
|
override fun getOldListSize() = oldList.size
|
||||||
oldItem == newItem
|
|
||||||
|
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
|
||||||
|
newList[newItemPosition] == oldList[oldItemPosition]
|
||||||
|
|
||||||
|
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
|
||||||
|
newList[newItemPosition].type == oldList[oldItemPosition].type
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
@ -8,6 +8,7 @@ import android.view.View
|
|||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
@ -68,6 +69,12 @@ class DashboardFragment : BaseFragment<FragmentDashboardBinding>(R.layout.fragme
|
|||||||
|
|
||||||
override fun initView() {
|
override fun initView() {
|
||||||
val mainActivity = requireActivity() as MainActivity
|
val mainActivity = requireActivity() as MainActivity
|
||||||
|
val itemTouchHelper = ItemTouchHelper(
|
||||||
|
DashboardItemMoveCallback(
|
||||||
|
dashboardAdapter,
|
||||||
|
presenter::onDragAndDropEnd
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
dashboardAdapter.apply {
|
dashboardAdapter.apply {
|
||||||
onAccountTileClickListener = { mainActivity.pushView(AccountFragment.newInstance()) }
|
onAccountTileClickListener = { mainActivity.pushView(AccountFragment.newInstance()) }
|
||||||
@ -104,6 +111,8 @@ class DashboardFragment : BaseFragment<FragmentDashboardBinding>(R.layout.fragme
|
|||||||
adapter = dashboardAdapter
|
adapter = dashboardAdapter
|
||||||
(itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
(itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
itemTouchHelper.attachToRecyclerView(dashboardRecycler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.dashboard
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import java.util.Collections
|
||||||
|
|
||||||
|
class DashboardItemMoveCallback(
|
||||||
|
private val dashboardAdapter: DashboardAdapter,
|
||||||
|
private var onUserInteractionEndListener: (List<DashboardItem>) -> Unit = {}
|
||||||
|
) : ItemTouchHelper.Callback() {
|
||||||
|
|
||||||
|
override fun isLongPressDragEnabled() = true
|
||||||
|
|
||||||
|
override fun isItemViewSwipeEnabled() = false
|
||||||
|
|
||||||
|
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||||
|
//Not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMovementFlags(
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder
|
||||||
|
): Int {
|
||||||
|
val dragFlags = if (viewHolder.bindingAdapterPosition != 0) {
|
||||||
|
ItemTouchHelper.UP or ItemTouchHelper.DOWN
|
||||||
|
} else 0
|
||||||
|
|
||||||
|
return makeMovementFlags(dragFlags, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canDropOver(
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
current: RecyclerView.ViewHolder,
|
||||||
|
target: RecyclerView.ViewHolder
|
||||||
|
) = target.bindingAdapterPosition != 0
|
||||||
|
|
||||||
|
override fun onMove(
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
|
target: RecyclerView.ViewHolder
|
||||||
|
): Boolean {
|
||||||
|
val list = dashboardAdapter.items.toMutableList()
|
||||||
|
|
||||||
|
Collections.swap(list, viewHolder.bindingAdapterPosition, target.bindingAdapterPosition)
|
||||||
|
|
||||||
|
dashboardAdapter.submitList(list)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||||
|
super.clearView(recyclerView, viewHolder)
|
||||||
|
|
||||||
|
onUserInteractionEndListener(dashboardAdapter.items.toList())
|
||||||
|
}
|
||||||
|
}
|
@ -68,6 +68,16 @@ class DashboardPresenter @Inject constructor(
|
|||||||
.launch("dashboard_pref")
|
.launch("dashboard_pref")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onDragAndDropEnd(list: List<DashboardItem>) {
|
||||||
|
dashboardItemLoadedList.clear()
|
||||||
|
dashboardItemLoadedList.addAll(list)
|
||||||
|
|
||||||
|
val positionList =
|
||||||
|
list.mapIndexed { index, dashboardItem -> Pair(dashboardItem.type, index) }.toMap()
|
||||||
|
|
||||||
|
preferencesRepository.dashboardItemsPosition = positionList
|
||||||
|
}
|
||||||
|
|
||||||
fun loadData(forceRefresh: Boolean = false, tilesToLoad: Set<DashboardItem.Tile>) {
|
fun loadData(forceRefresh: Boolean = false, tilesToLoad: Set<DashboardItem.Tile>) {
|
||||||
val oldDashboardDataToLoad = dashboardTilesToLoad
|
val oldDashboardDataToLoad = dashboardTilesToLoad
|
||||||
|
|
||||||
@ -622,6 +632,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
|
|
||||||
private fun updateData(dashboardItem: DashboardItem, forceRefresh: Boolean) {
|
private fun updateData(dashboardItem: DashboardItem, forceRefresh: Boolean) {
|
||||||
val isForceRefreshError = forceRefresh && dashboardItem.error != null
|
val isForceRefreshError = forceRefresh && dashboardItem.error != null
|
||||||
|
val dashboardItemsPosition = preferencesRepository.dashboardItemsPosition
|
||||||
|
|
||||||
with(dashboardItemLoadedList) {
|
with(dashboardItemLoadedList) {
|
||||||
removeAll { it.type == dashboardItem.type && !isForceRefreshError }
|
removeAll { it.type == dashboardItem.type && !isForceRefreshError }
|
||||||
@ -636,7 +647,12 @@ class DashboardPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dashboardItemLoadedList.sortBy { tile -> dashboardItemsToLoad.single { it == tile.type }.ordinal }
|
dashboardItemLoadedList.sortBy { tile ->
|
||||||
|
dashboardItemsPosition?.getOrDefault(
|
||||||
|
tile.type,
|
||||||
|
tile.type.ordinal + 100
|
||||||
|
) ?: tile.type.ordinal
|
||||||
|
}
|
||||||
|
|
||||||
val isItemsLoaded =
|
val isItemsLoaded =
|
||||||
dashboardItemsToLoad.all { type -> dashboardItemLoadedList.any { it.type == type } }
|
dashboardItemsToLoad.all { type -> dashboardItemLoadedList.any { it.type == type } }
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="12dp"
|
android:paddingHorizontal="12dp"
|
||||||
android:layout_marginVertical="2dp">
|
android:layout_marginVertical="2dp"
|
||||||
|
android:clipToPadding="false">
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/dashboard_horizontal_group_item_lucky_container"
|
android:id="@+id/dashboard_horizontal_group_item_lucky_container"
|
||||||
|
@ -10,10 +10,12 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
|
android:includeFontPadding="false"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:textSize="13sp"
|
android:textSize="13sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/dashboard_grades_subitem_grade_container"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="@id/dashboard_grades_subitem_grade_container"
|
||||||
tools:text="Urządzenia techniki kompu..." />
|
tools:text="Urządzenia techniki kompu..." />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@ -25,6 +27,11 @@
|
|||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/dashboard_grades_subitem_title"
|
app:layout_constraintStart_toEndOf="@id/dashboard_grades_subitem_title"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
tools:ignore="UselessLeaf" />
|
|
||||||
|
<include
|
||||||
|
layout="@layout/subitem_dashboard_small_grade"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</LinearLayout>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -501,7 +501,7 @@
|
|||||||
</plurals>
|
</plurals>
|
||||||
<string name="dashboard_timetable_third_time">until %1$s</string>
|
<string name="dashboard_timetable_third_time">until %1$s</string>
|
||||||
<string name="dashboard_timetable_no_lessons">No upcoming lessons</string>
|
<string name="dashboard_timetable_no_lessons">No upcoming lessons</string>
|
||||||
<string name="dashboard_timetable_error">An error occurred while loading the lesson</string>
|
<string name="dashboard_timetable_error">An error occurred while loading the lessons</string>
|
||||||
|
|
||||||
<string name="dashboard_homework_title">Homework</string>
|
<string name="dashboard_homework_title">Homework</string>
|
||||||
<string name="dashboard_homework_no_homework">No homework to do</string>
|
<string name="dashboard_homework_no_homework">No homework to do</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user