forked from mozilla-mobile/fenix
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
For mozilla-mobile#349: View Downloads
- Loading branch information
Kate Glazko
authored and
Kate Glazko
committed
Aug 12, 2020
1 parent
c52e4fd
commit 3d7b3b4
Showing
27 changed files
with
1,194 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
app/src/main/java/org/mozilla/fenix/components/downloads/PagedDownloadProvider.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
package org.mozilla.fenix.components.downloads | ||
|
||
import kotlinx.coroutines.runBlocking | ||
import mozilla.components.browser.state.state.content.DownloadState | ||
import mozilla.components.concept.storage.HistoryStorage | ||
import org.mozilla.fenix.ext.requireComponents | ||
|
||
/** | ||
* An Interface for providing a paginated list of [VisitInfo] | ||
* | ||
*/ | ||
interface PagedDownloadProvider { | ||
/** | ||
* Gets a list of [VisitInfo] | ||
* @param offset How much to offset the list by | ||
* @param numberOfItems How many items to fetch | ||
* @param onComplete A callback that returns the list of [VisitInfo] | ||
*/ | ||
fun getDownload(offset: Long, numberOfItems: Long, onComplete: (List<DownloadState>) -> Unit) | ||
} | ||
|
||
// A PagedList DataSource runs on a background thread automatically. | ||
// If we run this in our own coroutineScope it breaks the PagedList | ||
fun HistoryStorage.createSynchronousPagedDownloadProvider(downloadsMap: (Map<Long, DownloadState>)): PagedDownloadProvider { | ||
return object : PagedDownloadProvider { | ||
override fun getDownload( | ||
offset: Long, | ||
numberOfItems: Long, | ||
onComplete: (List<DownloadState>) -> Unit | ||
) { | ||
runBlocking { | ||
val downloads: List<DownloadState> = downloadsMap.values.toList() | ||
onComplete(downloads) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
123 changes: 123 additions & 0 deletions
123
app/src/main/java/org/mozilla/fenix/library/downloads/DownloadAdaptor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
|
||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
package org.mozilla.fenix.library.downloads | ||
|
||
import android.content.Context | ||
import android.text.format.DateUtils | ||
import android.view.LayoutInflater | ||
import android.view.ViewGroup | ||
import androidx.paging.PagedListAdapter | ||
import androidx.recyclerview.widget.DiffUtil | ||
import org.mozilla.fenix.R | ||
import org.mozilla.fenix.library.SelectionHolder | ||
import org.mozilla.fenix.library.downloads.viewholders.DownloadsListItemViewHolder | ||
import java.util.Calendar | ||
import java.util.Date | ||
|
||
enum class DownloadItemTimeGroup { | ||
Today, ThisWeek, ThisMonth, Older; | ||
|
||
fun humanReadable(context: Context): String = when (this) { | ||
Today -> context.getString(R.string.history_24_hours) | ||
ThisWeek -> context.getString(R.string.history_7_days) | ||
ThisMonth -> context.getString(R.string.history_30_days) | ||
Older -> context.getString(R.string.history_older) | ||
} | ||
} | ||
|
||
class DownloadAdapter( | ||
private val downloadInteractor: DownloadInteractor | ||
) : PagedListAdapter<DownloadItem, DownloadsListItemViewHolder>(downloadDiffCallback), SelectionHolder<DownloadItem> { | ||
|
||
private var mode: DownloadFragmentState.Mode = DownloadFragmentState.Mode.Normal | ||
override val selectedItems get() = mode.selectedItems | ||
var pendingDeletionIds = emptySet<Long>() | ||
private val itemsWithHeaders: MutableMap<DownloadItemTimeGroup, Int> = mutableMapOf() | ||
|
||
override fun getItemViewType(position: Int): Int = DownloadsListItemViewHolder.LAYOUT_ID | ||
|
||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DownloadsListItemViewHolder { | ||
val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false) | ||
return DownloadsListItemViewHolder(view, downloadInteractor, this) | ||
} | ||
|
||
fun updateMode(mode: DownloadFragmentState.Mode) { | ||
this.mode = mode | ||
// Update the delete button alpha that the first item holds | ||
if (itemCount > 0) notifyItemChanged(0) | ||
} | ||
|
||
override fun onBindViewHolder(holder: DownloadsListItemViewHolder, position: Int) { | ||
val current = getItem(position) ?: return | ||
val headerForCurrentItem = timeGroupForDownloadItem(current) | ||
val isPendingDeletion = pendingDeletionIds.contains(current.visitedAt) | ||
var timeGroup: DownloadItemTimeGroup? = null | ||
|
||
// Add or remove the header and position to the map depending on it's deletion status | ||
if (itemsWithHeaders.containsKey(headerForCurrentItem)) { | ||
if (isPendingDeletion && itemsWithHeaders[headerForCurrentItem] == position) { | ||
itemsWithHeaders.remove(headerForCurrentItem) | ||
} else if (isPendingDeletion && itemsWithHeaders[headerForCurrentItem] != position) { | ||
// do nothing | ||
} else { | ||
if (position <= itemsWithHeaders[headerForCurrentItem] as Int) { | ||
itemsWithHeaders[headerForCurrentItem] = position | ||
timeGroup = headerForCurrentItem | ||
} | ||
} | ||
} else if (!isPendingDeletion) { | ||
itemsWithHeaders[headerForCurrentItem] = position | ||
timeGroup = headerForCurrentItem | ||
} | ||
|
||
holder.bind(current, timeGroup, position == 0) | ||
} | ||
|
||
fun updatePendingDeletionIds(pendingDeletionIds: Set<Long>) { | ||
this.pendingDeletionIds = pendingDeletionIds | ||
} | ||
|
||
companion object { | ||
private const val zeroDays = 0 | ||
private const val sevenDays = 7 | ||
private const val thirtyDays = 30 | ||
private val oneDayAgo = getDaysAgo(zeroDays).time | ||
private val sevenDaysAgo = getDaysAgo(sevenDays).time | ||
private val thirtyDaysAgo = getDaysAgo(thirtyDays).time | ||
private val lastWeekRange = LongRange(sevenDaysAgo, oneDayAgo) | ||
private val lastMonthRange = LongRange(thirtyDaysAgo, sevenDaysAgo) | ||
|
||
private fun getDaysAgo(daysAgo: Int): Date { | ||
val calendar = Calendar.getInstance() | ||
calendar.add(Calendar.DAY_OF_YEAR, -daysAgo) | ||
|
||
return calendar.time | ||
} | ||
|
||
private fun timeGroupForDownloadItem(item: DownloadItem): DownloadItemTimeGroup { | ||
return when { | ||
DateUtils.isToday(item.visitedAt) -> DownloadItemTimeGroup.Today | ||
lastWeekRange.contains(item.visitedAt) -> DownloadItemTimeGroup.ThisWeek | ||
lastMonthRange.contains(item.visitedAt) -> DownloadItemTimeGroup.ThisMonth | ||
else -> DownloadItemTimeGroup.Older | ||
} | ||
} | ||
|
||
private val downloadDiffCallback = object : DiffUtil.ItemCallback<DownloadItem>() { | ||
override fun areItemsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean { | ||
return oldItem == newItem | ||
} | ||
|
||
override fun areContentsTheSame(oldItem: DownloadItem, newItem: DownloadItem): Boolean { | ||
return oldItem == newItem | ||
} | ||
|
||
override fun getChangePayload(oldItem: DownloadItem, newItem: DownloadItem): Any? { | ||
return newItem | ||
} | ||
} | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
app/src/main/java/org/mozilla/fenix/library/downloads/DownloadController.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
|
||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
package org.mozilla.fenix.library.downloads | ||
|
||
import org.mozilla.fenix.browser.browsingmode.BrowsingMode | ||
|
||
interface DownloadController { | ||
fun handleOpen(item: DownloadItem, mode: BrowsingMode? = null) | ||
fun handleSelect(item: DownloadItem) | ||
fun handleDeselect(item: DownloadItem) | ||
fun handleBackPressed(): Boolean | ||
fun handleModeSwitched() | ||
fun handleDeleteSome(items: Set<DownloadItem>) | ||
} | ||
|
||
class DefaultDownloadController( | ||
private val store: DownloadFragmentStore, | ||
private val openToBrowser: (item: DownloadItem, mode: BrowsingMode?) -> Unit, | ||
private val invalidateOptionsMenu: () -> Unit, | ||
private val deleteDownloadItems: (Set<DownloadItem>) -> Unit | ||
) : DownloadController { | ||
override fun handleOpen(item: DownloadItem, mode: BrowsingMode?) { | ||
openToBrowser(item, mode) | ||
} | ||
|
||
override fun handleSelect(item: DownloadItem) { | ||
store.dispatch(DownloadFragmentAction.AddItemForRemoval(item)) | ||
} | ||
|
||
override fun handleDeselect(item: DownloadItem) { | ||
store.dispatch(DownloadFragmentAction.RemoveItemForRemoval(item)) | ||
} | ||
|
||
override fun handleBackPressed(): Boolean { | ||
return if (store.state.mode is DownloadFragmentState.Mode.Editing) { | ||
store.dispatch(DownloadFragmentAction.ExitEditMode) | ||
true | ||
} else { | ||
false | ||
} | ||
} | ||
|
||
override fun handleModeSwitched() { | ||
invalidateOptionsMenu.invoke() | ||
} | ||
|
||
override fun handleDeleteSome(items: Set<DownloadItem>) { | ||
deleteDownloadItems.invoke(items) | ||
} | ||
} |
Oops, something went wrong.