ref: c66d69c69f5f0ed6426d6abc6638701e75f16064
app/src/main/java/xyz/apiote/bimba/czwek/dashboard/ui/home/Favourites.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
// SPDX-FileCopyrightText: Adam Evyčędo // // SPDX-License-Identifier: GPL-3.0-or-later package xyz.apiote.bimba.czwek.dashboard.ui.home import android.content.Context import android.content.Intent import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import xyz.apiote.bimba.czwek.R import xyz.apiote.bimba.czwek.departures.DeparturesActivity import xyz.apiote.bimba.czwek.repo.Departure import xyz.apiote.bimba.czwek.repo.Favourite import java.time.ZoneId import java.time.ZonedDateTime import java.util.Collections import java.util.Optional class BimbaFavouritesAdapter( private var favourites: List<Favourite>, private var departures: Map<String, Optional<Departure>>, private val inflater: LayoutInflater, private val context: Context ) : RecyclerView.Adapter<FavouriteViewHolder>() { var lastUpdate: ZonedDateTime = ZonedDateTime.of(0, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()) private set inner class DiffUtilCallback( private val oldFavourites: List<Favourite>, private val oldDepartures: Map<String, Optional<Departure>?>, private val newFavourites: List<Favourite>, private val newDepartures: Map<String, Optional<Departure>?> ) : DiffUtil.Callback() { override fun getOldListSize() = oldFavourites.size override fun getNewListSize() = newFavourites.size override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) = oldFavourites[oldItemPosition].feedID + oldFavourites[oldItemPosition].stopCode == newFavourites[newItemPosition].feedID + newFavourites[newItemPosition].stopCode @Suppress("KotlinConstantConditions", "UNNECESSARY_NOT_NULL_ASSERTION") override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { val oldFav = oldFavourites[oldItemPosition] val newFav = newFavourites[newItemPosition] val oldDeparture = oldDepartures[oldFav.feedID + oldFav.stopCode] val newDeparture = newDepartures[oldFav.feedID + oldFav.stopCode] if ((oldDeparture == null && newDeparture != null) || (oldDeparture != null && newDeparture == null)) { return false } val favouritesSame = oldFav.feedName == newFav.feedName && oldFav.stopName == newFav.stopName && oldFav.sequence == newFav.sequence && oldFav.lines == newFav.lines if (!favouritesSame) { return false } if ((oldDeparture == null && newDeparture == null) || (oldDeparture!!.isEmpty && newDeparture!!.isEmpty)) { return true } if ((oldDeparture!!.isEmpty && !newDeparture!!.isEmpty) || (!oldDeparture!!.isEmpty && newDeparture!!.isEmpty)) { return false } return oldDeparture!!.get().ID == newDeparture!!.get().ID && oldDeparture!!.get().vehicle.Line == newDeparture!!.get().vehicle.Line && oldDeparture!!.get().vehicle.Headsign == newDeparture!!.get().vehicle.Headsign && oldDeparture!!.get().statusText( context, false, lastUpdate ) == newDeparture!!.get().statusText(context, false) } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FavouriteViewHolder { val rowView = inflater.inflate(R.layout.favourite, parent, false) return FavouriteViewHolder(rowView) } override fun getItemCount() = favourites.size override fun onBindViewHolder(holder: FavouriteViewHolder, position: Int) { FavouriteViewHolder.bind( favourites[position], holder, context, departures[favourites[position].feedID + favourites[position].stopCode] ) } fun updateFavourites(favourites: List<Favourite>) { val diff = DiffUtil.calculateDiff( DiffUtilCallback( this.favourites, this.departures, favourites, this.departures ) ) this.favourites = favourites diff.dispatchUpdatesTo(this) } fun updateDepartures(departures: Map<String, Optional<Departure>>) { this.departures = departures notifyDataSetChanged() lastUpdate = ZonedDateTime.now() } fun swap(from: Int, to: Int): List<Favourite> { Collections.swap(favourites, from, to) favourites = favourites.mapIndexed { i, it -> it.copy(sequence = i) } notifyItemMoved(from, to) return favourites } fun delete(position: Int): Pair<List<Favourite>, Favourite> { val removedFavourite = favourites[position] favourites = favourites.filterIndexed { i, _ -> i != position }.mapIndexed { i, it -> it.copy(sequence = i) } notifyItemRemoved(position) return Pair(favourites, removedFavourite) } fun insert(removedFavourite: Favourite): List<Favourite> { favourites = favourites.toMutableList().apply { add(removedFavourite.sequence!!, removedFavourite) }.mapIndexed { i, it -> it.copy(sequence = i) } return favourites } } class FavouriteViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val root: View = itemView.findViewById(R.id.favourite) val feedName: TextView = itemView.findViewById(R.id.feed_name) val lineIcon: ImageView = itemView.findViewById(R.id.line_icon) val departureTime: TextView = itemView.findViewById(R.id.departure_time) val departureTimeFull: TextView = itemView.findViewById(R.id.departure_full_time) val lineName: TextView = itemView.findViewById(R.id.departure_line) val headsign: TextView = itemView.findViewById(R.id.departure_headsign) val stopHeadline: TextView = itemView.findViewById(R.id.stop_name) companion object { fun bind( favourite: Favourite, holder: FavouriteViewHolder, context: Context, departure: Optional<Departure>? ) { if (departure == null) { holder.feedName.text = favourite.feedName holder.stopHeadline.text = favourite.stopName holder.lineIcon.setImageDrawable(null) holder.lineName.text = context.getString(R.string.loading) holder.departureTime.text = "" holder.departureTimeFull.text = "" holder.headsign.text = "" } else if (departure.isEmpty) { holder.feedName.text = favourite.feedName holder.stopHeadline.text = favourite.stopName holder.lineIcon.setImageDrawable(null) holder.lineName.text = context.getString(R.string.no_next_departures) holder.departureTime.text = "" holder.departureTimeFull.text = "" holder.headsign.text = "" } else { val vehicle = departure.get().vehicle holder.feedName.text = favourite.feedName holder.stopHeadline.text = favourite.stopName holder.lineIcon.setImageDrawable(vehicle.Line.icon(context)) holder.lineIcon.contentDescription = vehicle.Line.kind.name holder.lineName.text = vehicle.Line.name holder.departureTime.text = departure.get().statusText(context, false) holder.departureTimeFull.text = departure.get().timeString(context) holder.headsign.text = context.getString(R.string.departure_headsign, vehicle.Headsign) holder.headsign.contentDescription = context.getString( R.string.departure_headsign_content_description, vehicle.Headsign ) } holder.root.setOnClickListener { val intent = Intent(context, DeparturesActivity::class.java).apply { putExtra("code", favourite.stopCode) putExtra("name", favourite.stopName) putExtra("feedID", favourite.feedID) putExtra("linesFilter", favourite.lines.toTypedArray()) } context.startActivity(intent) } } } } |