From 3ecf9d338ec73088f5c7fe6baae0994cab57bffc Mon Sep 17 00:00:00 2001 From: Jeff Boek Date: Mon, 25 Feb 2019 13:45:26 -0800 Subject: [PATCH] For #631 - Adds session item layout --- .../fenix/home/sessions/SessionsAdapter.kt | 37 ++- .../fenix/home/sessions/SessionsComponent.kt | 60 +++- .../res/drawable/ic_session_thumbnail.xml | 302 ++++++++++++++++++ app/src/main/res/layout/session_item.xml | 80 +++++ 4 files changed, 475 insertions(+), 4 deletions(-) create mode 100644 app/src/main/res/drawable/ic_session_thumbnail.xml create mode 100644 app/src/main/res/layout/session_item.xml diff --git a/app/src/main/java/org/mozilla/fenix/home/sessions/SessionsAdapter.kt b/app/src/main/java/org/mozilla/fenix/home/sessions/SessionsAdapter.kt index bcd9dd477..6ed586124 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessions/SessionsAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessions/SessionsAdapter.kt @@ -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() { - private var isPrivate = false private var items = listOf() @@ -30,6 +32,7 @@ class SessionsAdapter : RecyclerView.Adapter() { 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() { 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() { 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() { } } + 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 diff --git a/app/src/main/java/org/mozilla/fenix/home/sessions/SessionsComponent.kt b/app/src/main/java/org/mozilla/fenix/home/sessions/SessionsComponent.kt index 2505c82f6..f0ebad78e 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessions/SessionsComponent.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessions/SessionsComponent.kt @@ -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) +data class ArchivedSession(val id: Long, private val savedAt: Long, private val _urls: List) { + 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, diff --git a/app/src/main/res/drawable/ic_session_thumbnail.xml b/app/src/main/res/drawable/ic_session_thumbnail.xml new file mode 100644 index 000000000..c1c805f0e --- /dev/null +++ b/app/src/main/res/drawable/ic_session_thumbnail.xml @@ -0,0 +1,302 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/session_item.xml b/app/src/main/res/layout/session_item.xml new file mode 100644 index 000000000..a90f628db --- /dev/null +++ b/app/src/main/res/layout/session_item.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file