For #631 - Adds session item layout
parent
8379c3d2cb
commit
3ecf9d338e
|
@ -4,6 +4,7 @@
|
|||
|
||||
package org.mozilla.fenix.home.sessions
|
||||
|
||||
import android.graphics.PorterDuff
|
||||
import android.text.SpannableString
|
||||
import android.text.style.ClickableSpan
|
||||
import android.text.style.ForegroundColorSpan
|
||||
|
@ -11,11 +12,12 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.android.synthetic.main.session_item.view.*
|
||||
import org.mozilla.fenix.R
|
||||
|
||||
class SessionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
private var isPrivate = false
|
||||
private var items = listOf<ArchivedSession>()
|
||||
|
||||
|
||||
|
@ -30,6 +32,7 @@ class SessionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|||
return when (viewType) {
|
||||
HeaderViewHolder.LAYOUT_ID -> HeaderViewHolder(view)
|
||||
EmptyListViewHolder.LAYOUT_ID -> EmptyListViewHolder(view)
|
||||
SessionItemViewHolder.LAYOUT_ID -> SessionItemViewHolder(view)
|
||||
PrivateEmptyListViewHolder.LAYOUT_ID -> PrivateEmptyListViewHolder(view)
|
||||
else -> EmptyListViewHolder(view)
|
||||
}
|
||||
|
@ -37,7 +40,7 @@ class SessionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|||
|
||||
override fun getItemViewType(position: Int) = when (position) {
|
||||
0 -> HeaderViewHolder.LAYOUT_ID
|
||||
else -> EmptyListViewHolder.LAYOUT_ID
|
||||
else -> SessionItemViewHolder.LAYOUT_ID
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = items.size + 1
|
||||
|
@ -45,6 +48,7 @@ class SessionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is HeaderViewHolder -> holder.headerText.text = "Today"
|
||||
is SessionItemViewHolder -> holder.bind(items[position - 1])
|
||||
is PrivateEmptyListViewHolder -> {
|
||||
// Format the description text to include a hyperlink
|
||||
val descriptionText = String
|
||||
|
@ -80,6 +84,35 @@ class SessionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|||
}
|
||||
}
|
||||
|
||||
private class SessionItemViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
private val thumbnail = view.session_card_thumbnail
|
||||
private val timestampLabel = view.session_card_timestamp
|
||||
private val titlesLabel = view.session_card_titles
|
||||
private val extrasLabel = view.session_card_extras
|
||||
|
||||
private var session: ArchivedSession? = null
|
||||
|
||||
fun bind(session: ArchivedSession) {
|
||||
this.session = session
|
||||
|
||||
thumbnail.setColorFilter(
|
||||
ContextCompat.getColor(itemView.context, AVAILABLE_COLOR_IDS.random()),
|
||||
PorterDuff.Mode.MULTIPLY)
|
||||
timestampLabel.text = session.formattedSavedAt
|
||||
titlesLabel.text = session.titles
|
||||
extrasLabel.text = if (session.extrasLabel > 0) {
|
||||
"+${session.extrasLabel} sites..."
|
||||
} else { "" }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val AVAILABLE_COLOR_IDS = listOf(
|
||||
R.color.photonBlue40, R.color.photonGreen50, R.color.photonYellow50, R.color.photonOrange50,
|
||||
R.color.photonPurple50, R.color.photonInk70)
|
||||
const val LAYOUT_ID = R.layout.session_item
|
||||
}
|
||||
}
|
||||
|
||||
private class EmptyListViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
companion object {
|
||||
const val LAYOUT_ID = R.layout.session_list_empty
|
||||
|
|
|
@ -6,14 +6,70 @@ package org.mozilla.fenix.home.sessions
|
|||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import mozilla.components.browser.session.Session
|
||||
import org.mozilla.fenix.mvi.Action
|
||||
import org.mozilla.fenix.mvi.ActionBusFactory
|
||||
import org.mozilla.fenix.mvi.Change
|
||||
import org.mozilla.fenix.mvi.UIComponent
|
||||
import org.mozilla.fenix.mvi.ViewState
|
||||
import java.net.URL
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
data class ArchivedSession(val id: Long, private val savedAt: Long, val urls: List<String>)
|
||||
data class ArchivedSession(val id: Long, private val savedAt: Long, private val _urls: List<String>) {
|
||||
val formattedSavedAt by lazy {
|
||||
val isSameDay: (Calendar, Calendar) -> Boolean = { a, b ->
|
||||
a.get(Calendar.ERA) == b.get(Calendar.ERA) &&
|
||||
a.get(Calendar.YEAR) == b.get(Calendar.YEAR) &&
|
||||
a.get(Calendar.DAY_OF_YEAR) == b.get(Calendar.DAY_OF_YEAR)
|
||||
|
||||
}
|
||||
|
||||
val parse: (Date) -> String = { date ->
|
||||
val dateCal = Calendar.getInstance().apply { time = date }
|
||||
val today = Calendar.getInstance()
|
||||
val yesterday = Calendar.getInstance().apply { add(Calendar.DAY_OF_YEAR, -1) }
|
||||
|
||||
val time = TIME_FORMATTER.format(date)
|
||||
val month = MONTH_FORMATTER.format(date)
|
||||
val day = DAY_FORMATTER.format(date)
|
||||
val dayOfWeek = DAY_OF_WEEK_FORMATTER.format(date)
|
||||
|
||||
|
||||
when {
|
||||
isSameDay(dateCal, today) -> "Today @ $time"
|
||||
isSameDay(dateCal, yesterday) -> "Yesterday @ $time"
|
||||
else -> "$dayOfWeek $month/$day @ $time"
|
||||
}
|
||||
}
|
||||
|
||||
parse(Date(savedAt))
|
||||
}
|
||||
|
||||
val titles by lazy {
|
||||
val urlFormatter: (String) -> String = { url ->
|
||||
try {
|
||||
URL(url).host
|
||||
} catch (e: Exception) {
|
||||
url
|
||||
}
|
||||
}
|
||||
|
||||
_urls
|
||||
.take(NUMBER_OF_URLS_TO_DISPLAY)
|
||||
.joinToString(", ", transform = urlFormatter)
|
||||
}
|
||||
|
||||
val extrasLabel = maxOf(_urls.size - NUMBER_OF_URLS_TO_DISPLAY, 0)
|
||||
|
||||
private companion object {
|
||||
private const val NUMBER_OF_URLS_TO_DISPLAY = 5
|
||||
|
||||
private val TIME_FORMATTER = SimpleDateFormat("h:mm a", Locale.US)
|
||||
private val MONTH_FORMATTER = SimpleDateFormat("M", Locale.US)
|
||||
private val DAY_FORMATTER = SimpleDateFormat("d", Locale.US)
|
||||
private val DAY_OF_WEEK_FORMATTER = SimpleDateFormat("EEEE", Locale.US)
|
||||
}
|
||||
}
|
||||
|
||||
class SessionsComponent(
|
||||
private val container: ViewGroup,
|
||||
|
|
|
@ -0,0 +1,302 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated by PaintCode - http://www.paintcodeapp.com -->
|
||||
<!-- Canvas 1 -->
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:name="canvas1"
|
||||
android:width="64dp"
|
||||
android:height="64dp"
|
||||
android:viewportWidth="64"
|
||||
android:viewportHeight="64">
|
||||
<!-- Group 2 -->
|
||||
<group
|
||||
android:name="group2">
|
||||
|
||||
<!-- Group 3 -->
|
||||
<group
|
||||
android:name="group3">
|
||||
<!-- Clip 3 Clip -->
|
||||
<clip-path
|
||||
android:name="clip3"
|
||||
android:pathData="M 12,8 L 60,8 C 62.21,8 64,9.79 64,12 L 64,60 C 64,62.21 62.21,64 60,64 L 12,64 C 9.79,64 8,62.21 8,60 L 8,12 C 8,9.79 9.79,8 12,8 Z" />
|
||||
|
||||
<!-- Group 4 -->
|
||||
<group
|
||||
android:name="group4">
|
||||
<!-- Clip Clip -->
|
||||
<clip-path
|
||||
android:name="clip"
|
||||
android:pathData="M 8,64 L 64,64 L 64,8 L 8,8 L 8,64 Z" />
|
||||
|
||||
<!-- Picture -->
|
||||
<group
|
||||
android:name="picture-transform"
|
||||
android:translateX="-1.33"
|
||||
android:translateY="8"
|
||||
android:scaleX="0.53"
|
||||
android:scaleY="0.53">
|
||||
<path
|
||||
android:name="picture"
|
||||
android:pathData="M 0,105 L 140,105 L 140,0 L 0,0 L 0,105 Z" />
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- Rectangle 3 -->
|
||||
<path
|
||||
android:name="rectangle3"
|
||||
android:pathData="M 8,64 L 64,64 L 64,8 L 8,8 L 8,64 Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:type="linear"
|
||||
android:tileMode="clamp"
|
||||
android:startX="3"
|
||||
android:startY="3"
|
||||
android:endX="69"
|
||||
android:endY="69">
|
||||
<item android:color="#FF9952FF" android:offset="0" />
|
||||
<item android:color="#FF9952FF" android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<!-- Group 5 -->
|
||||
<group
|
||||
android:name="group5">
|
||||
|
||||
<!-- Rectangle 4 -->
|
||||
<path
|
||||
android:name="rectangle4"
|
||||
android:pathData="M 8,64 L 64,64 L 64,8 L 8,8 L 8,64 Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:type="linear"
|
||||
android:tileMode="clamp"
|
||||
android:startX="3"
|
||||
android:startY="3"
|
||||
android:endX="69"
|
||||
android:endY="69">
|
||||
<item android:color="#FF9952FF" android:offset="0" />
|
||||
<item android:color="#FF9952FF" android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
</group>
|
||||
|
||||
<!-- Group 6 -->
|
||||
<group
|
||||
android:name="group6">
|
||||
<!-- Clip 2 Clip -->
|
||||
<clip-path
|
||||
android:name="clip2"
|
||||
android:pathData="M 8,64 L 64,64 L 64,8 L 8,8 L 8,64 Z" />
|
||||
|
||||
<!-- Picture 2 -->
|
||||
<group
|
||||
android:name="picture2-transform"
|
||||
android:translateX="-1.2"
|
||||
android:translateY="8"
|
||||
android:scaleX="0.63"
|
||||
android:scaleY="0.63">
|
||||
<path
|
||||
android:name="picture2"
|
||||
android:pathData="M 0,89 L 118,89 L 118,0 L 0,0 L 0,89 Z" />
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- Rectangle 7 -->
|
||||
<path
|
||||
android:name="rectangle7"
|
||||
android:pathData="M 8,64 L 64,64 L 64,8 L 8,8 L 8,64 Z"
|
||||
android:fillColor="#660C0C0D" />
|
||||
</group>
|
||||
|
||||
<!-- Group 7 -->
|
||||
<group
|
||||
android:name="group7">
|
||||
<!-- Clip 6 Clip -->
|
||||
<clip-path
|
||||
android:name="clip6"
|
||||
android:pathData="M 4,56 C 4,58.21 5.79,60 8,60 L 56,60 C 58.21,60 60,58.21 60,56 L 60,8 C 60,5.79 58.21,4 56,4 L 8,4 C 5.79,4 4,5.79 4,8 L 4,56 Z" />
|
||||
|
||||
<!-- Group 8 -->
|
||||
<group
|
||||
android:name="group8">
|
||||
<!-- Clip 4 Clip -->
|
||||
<clip-path
|
||||
android:name="clip4"
|
||||
android:pathData="M 4,60 L 60,60 L 60,4 L 4,4 L 4,60 Z" />
|
||||
|
||||
<!-- Picture 3 -->
|
||||
<group
|
||||
android:name="picture3-transform"
|
||||
android:translateX="-5.33"
|
||||
android:translateY="4"
|
||||
android:scaleX="0.53"
|
||||
android:scaleY="0.53">
|
||||
<path
|
||||
android:name="picture3"
|
||||
android:pathData="M 0,105 L 140,105 L 140,0 L 0,0 L 0,105 Z" />
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- Rectangle 10 -->
|
||||
<path
|
||||
android:name="rectangle10"
|
||||
android:pathData="M 4,60 L 60,60 L 60,4 L 4,4 L 4,60 Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:type="linear"
|
||||
android:tileMode="clamp"
|
||||
android:startX="-1"
|
||||
android:startY="-1"
|
||||
android:endX="65"
|
||||
android:endY="65">
|
||||
<item android:color="#FF9952FF" android:offset="0" />
|
||||
<item android:color="#FF9952FF" android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<!-- Group 9 -->
|
||||
<group
|
||||
android:name="group9">
|
||||
|
||||
<!-- Rectangle 11 -->
|
||||
<path
|
||||
android:name="rectangle11"
|
||||
android:pathData="M 4,60 L 60,60 L 60,4 L 4,4 L 4,60 Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:type="linear"
|
||||
android:tileMode="clamp"
|
||||
android:startX="-1"
|
||||
android:startY="-1"
|
||||
android:endX="65"
|
||||
android:endY="65">
|
||||
<item android:color="#FF9952FF" android:offset="0" />
|
||||
<item android:color="#FF9952FF" android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
</group>
|
||||
|
||||
<!-- Group 10 -->
|
||||
<group
|
||||
android:name="group10">
|
||||
<!-- Clip 5 Clip -->
|
||||
<clip-path
|
||||
android:name="clip5"
|
||||
android:pathData="M 4,60 L 60,60 L 60,4 L 4,4 L 4,60 Z" />
|
||||
|
||||
<!-- Picture 4 -->
|
||||
<group
|
||||
android:name="picture4-transform"
|
||||
android:translateX="-5.2"
|
||||
android:translateY="4"
|
||||
android:scaleX="0.63"
|
||||
android:scaleY="0.63">
|
||||
<path
|
||||
android:name="picture4"
|
||||
android:pathData="M 0,89 L 118,89 L 118,0 L 0,0 L 0,89 Z" />
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- Rectangle 14 -->
|
||||
<path
|
||||
android:name="rectangle14"
|
||||
android:pathData="M 4,60 L 60,60 L 60,4 L 4,4 L 4,60 Z"
|
||||
android:fillColor="#330C0C0D" />
|
||||
</group>
|
||||
|
||||
<!-- Group 11 -->
|
||||
<group
|
||||
android:name="group11">
|
||||
<!-- Clip 9 Clip -->
|
||||
<clip-path
|
||||
android:name="clip9"
|
||||
android:pathData="M 4,0 L 52,0 C 54.21,0 56,1.79 56,4 L 56,52 C 56,54.21 54.21,56 52,56 L 4,56 C 1.79,56 0,54.21 0,52 L 0,4 C 0,1.79 1.79,0 4,0 Z" />
|
||||
|
||||
<!-- Group 12 -->
|
||||
<group
|
||||
android:name="group12">
|
||||
<!-- Clip 7 Clip -->
|
||||
<clip-path
|
||||
android:name="clip7"
|
||||
android:pathData="M 0,56 L 56,56 L 56,0 L 0,0 L 0,56 Z" />
|
||||
|
||||
<!-- Picture 5 -->
|
||||
<group
|
||||
android:name="picture5-transform"
|
||||
android:translateX="-9.33"
|
||||
android:scaleX="0.53"
|
||||
android:scaleY="0.53">
|
||||
<path
|
||||
android:name="picture5"
|
||||
android:pathData="M 0,105 L 140,105 L 140,0 L 0,0 L 0,105 Z" />
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- Rectangle 18 -->
|
||||
<path
|
||||
android:name="rectangle18"
|
||||
android:pathData="M 0,56 L 56,56 L 56,0 L 0,0 L 0,56 Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:type="linear"
|
||||
android:tileMode="clamp"
|
||||
android:startX="-5"
|
||||
android:startY="-5"
|
||||
android:endX="61"
|
||||
android:endY="61">
|
||||
<item android:color="#FF9952FF" android:offset="0" />
|
||||
<item android:color="#FF9952FF" android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<!-- Group 13 -->
|
||||
<group
|
||||
android:name="group13">
|
||||
|
||||
<!-- Rectangle 19 -->
|
||||
<path
|
||||
android:name="rectangle19"
|
||||
android:pathData="M 0,56 L 56,56 L 56,0 L 0,0 L 0,56 Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:type="linear"
|
||||
android:tileMode="clamp"
|
||||
android:startX="-5"
|
||||
android:startY="-5"
|
||||
android:endX="61"
|
||||
android:endY="61">
|
||||
<item android:color="#FF9952FF" android:offset="0" />
|
||||
<item android:color="#FF9952FF" android:offset="1" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
</group>
|
||||
|
||||
<!-- Group 14 -->
|
||||
<group
|
||||
android:name="group14">
|
||||
<!-- Clip 8 Clip -->
|
||||
<clip-path
|
||||
android:name="clip8"
|
||||
android:pathData="M 0,56 L 56,56 L 56,0 L 0,0 L 0,56 Z" />
|
||||
|
||||
<!-- Picture 6 -->
|
||||
<group
|
||||
android:name="picture6-transform"
|
||||
android:translateX="-9.2"
|
||||
android:scaleX="0.63"
|
||||
android:scaleY="0.63">
|
||||
<path
|
||||
android:name="picture6"
|
||||
android:pathData="M 0,89 L 118,89 L 118,0 L 0,0 L 0,89 Z" />
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
|
@ -0,0 +1,80 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="@android:color/white"
|
||||
app:cardElevation="1dp"
|
||||
app:cardCornerRadius="10dp"
|
||||
android:clipChildren="true">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/session_card_thumbnail"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_session_thumbnail"
|
||||
android:layout_margin="16dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/session_card_timestamp"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/photonInk80"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
app:layout_constraintStart_toEndOf="@+id/session_card_thumbnail"
|
||||
app:layout_constraintTop_toTopOf="@id/session_card_thumbnail"
|
||||
app:layout_constraintEnd_toStartOf="@id/session_card_overflow_button"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/session_card_titles"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/photonGrey50"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/session_card_timestamp"
|
||||
app:layout_constraintStart_toStartOf="@id/session_card_timestamp"
|
||||
app:layout_constraintEnd_toEndOf="@id/session_card_timestamp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/session_card_extras"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/photonGrey50"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/session_card_titles"
|
||||
app:layout_constraintStart_toStartOf="@id/session_card_titles" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/bottomBarrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="session_card_thumbnail,session_card_extras" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/session_card_overflow_button"
|
||||
android:layout_width="@dimen/glyph_button_width"
|
||||
android:layout_height="@dimen/glyph_button_height"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_menu"
|
||||
android:tint="?attr/toolbarTextColor"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.cardview.widget.CardView>
|
Loading…
Reference in New Issue