Commit 34193994 authored by Hesen Zhang's avatar Hesen Zhang Committed by Commit Bot

Rework on Rename UI

Implemented Rename Downloads feature in Download Home
> UI in download home

Bug: 924751
Change-Id: Ib9288e5c6428e4c42f7c5e5d0e2b222eb6c16997
Reviewed-on: https://chromium-review.googlesource.com/c/1468584
Commit-Queue: Hesen Zhang <hesen@google.com>
Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Reviewed-by: default avatarShakti Sahu <shaktisahu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#635288}
parent 40508cc3
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2019 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<org.chromium.chrome.browser.download.home.rename.RenameDialogCustomView
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" >
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/AlertDialogContent">
<TextView
android:id="@+id/subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:visibility="gone"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<org.chromium.ui.widget.ChromeImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_drive_file_24dp"
app:tint="@color/default_icon_color"
style="@style/ListItemStartIcon" />
<org.chromium.chrome.browser.widget.AlertDialogEditText
android:id="@+id/file_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true" />
</LinearLayout>
</LinearLayout>
</org.chromium.chrome.browser.download.home.rename.RenameDialogCustomView>
......@@ -17,9 +17,11 @@ import org.chromium.chrome.browser.download.home.DownloadManagerCoordinatorFacto
import org.chromium.chrome.browser.download.home.DownloadManagerUiConfig;
import org.chromium.chrome.browser.download.items.OfflineContentAggregatorNotificationBridgeUiFactory;
import org.chromium.chrome.browser.download.ui.DownloadManagerUi;
import org.chromium.chrome.browser.modaldialog.AppModalPresenter;
import org.chromium.chrome.browser.util.IntentUtils;
import org.chromium.ui.base.ActivityAndroidPermissionDelegate;
import org.chromium.ui.base.AndroidPermissionDelegate;
import org.chromium.ui.modaldialog.ModalDialogManager;
import java.lang.ref.WeakReference;
......@@ -32,6 +34,7 @@ public class DownloadActivity extends SnackbarActivity {
private DownloadManagerCoordinator mDownloadCoordinator;
private boolean mIsOffTheRecord;
private AndroidPermissionDelegate mPermissionDelegate;
private ModalDialogManager mModalDialogManager;
/** Caches the current URL for the filter being applied. */
private String mCurrentUrl;
......@@ -59,8 +62,11 @@ public class DownloadActivity extends SnackbarActivity {
.setIsOffTheRecord(isOffTheRecord)
.setIsSeparateActivity(true)
.build();
mModalDialogManager = new ModalDialogManager(
new AppModalPresenter(this), ModalDialogManager.ModalDialogType.APP);
mDownloadCoordinator = DownloadManagerCoordinatorFactory.create(
this, config, getSnackbarManager(), parentComponent);
this, config, getSnackbarManager(), parentComponent, mModalDialogManager);
setContentView(mDownloadCoordinator.getView());
mIsOffTheRecord = isOffTheRecord;
mDownloadCoordinator.addObserver(mUiObserver);
......@@ -95,6 +101,7 @@ public class DownloadActivity extends SnackbarActivity {
protected void onDestroy() {
mDownloadCoordinator.removeObserver(mUiObserver);
mDownloadCoordinator.destroy();
mModalDialogManager.destroy();
super.onDestroy();
}
......
......@@ -47,7 +47,8 @@ public class DownloadPage extends BasicNativePage implements DownloadManagerCoor
.setIsSeparateActivity(false)
.build();
mDownloadCoordinator = DownloadManagerCoordinatorFactory.create(activity, config,
((SnackbarManageable) activity).getSnackbarManager(), activity.getComponentName());
((SnackbarManageable) activity).getSnackbarManager(), activity.getComponentName(),
activity.getModalDialogManager());
mDownloadCoordinator.addObserver(this);
mTitle = activity.getString(R.string.menu_downloads);
......
......@@ -11,6 +11,7 @@ import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.download.ui.DownloadManagerUi;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.snackbar.SnackbarManager;
import org.chromium.ui.modaldialog.ModalDialogManager;
/** A helper class to build and return an {@link DownloadManagerCoordinator}. */
public class DownloadManagerCoordinatorFactory {
......@@ -20,14 +21,15 @@ public class DownloadManagerCoordinatorFactory {
* @param config A {@link DownloadManagerUiConfig} to provide configuration params.
* @param parentComponent The parent component.
* @param snackbarManager The {@link SnackbarManager} that should be used to show snackbars.
* @param modalDialogManager The {@link ModalDialogManager} that should be used to show dialog.
* @return A new {@link DownloadManagerCoordinator} instance.
*/
public static DownloadManagerCoordinator create(Activity activity,
DownloadManagerUiConfig config, SnackbarManager snackbarManager,
ComponentName parentComponent) {
ComponentName parentComponent, ModalDialogManager modalDialogManager) {
if (ChromeFeatureList.isEnabled(ChromeFeatureList.DOWNLOAD_HOME_V2)) {
return new DownloadManagerCoordinatorImpl(
Profile.getLastUsedProfile(), activity, config, snackbarManager);
return new DownloadManagerCoordinatorImpl(Profile.getLastUsedProfile(), activity,
config, snackbarManager, modalDialogManager);
} else {
return new DownloadManagerUi(activity, config.isOffTheRecord, parentComponent,
config.isSeparateActivity, snackbarManager);
......
......@@ -27,6 +27,7 @@ import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.snackbar.SnackbarManager;
import org.chromium.chrome.browser.widget.selection.SelectionDelegate;
import org.chromium.chrome.download.R;
import org.chromium.ui.modaldialog.ModalDialogManager;
import java.io.Closeable;
......@@ -52,14 +53,15 @@ class DownloadManagerCoordinatorImpl
/** Builds a {@link DownloadManagerCoordinatorImpl} instance. */
public DownloadManagerCoordinatorImpl(Profile profile, Activity activity,
DownloadManagerUiConfig config, SnackbarManager snackbarManager) {
DownloadManagerUiConfig config, SnackbarManager snackbarManager,
ModalDialogManager modalDialogManager) {
mActivity = activity;
mDeleteCoordinator = new DeleteUndoCoordinator(snackbarManager);
mSelectionDelegate = new SelectionDelegate<ListItem>();
mListCoordinator = new DateOrderedListCoordinator(mActivity, config,
OfflineContentAggregatorFactory.forProfile(profile),
mDeleteCoordinator::showSnackbar, mSelectionDelegate, this ::notifyFilterChanged,
createDateOrderedListObserver());
mDeleteCoordinator::showSnackbar, mSelectionDelegate, this::notifyFilterChanged,
createDateOrderedListObserver(), modalDialogManager);
mToolbarCoordinator = new ToolbarCoordinator(mActivity, this, mListCoordinator,
mSelectionDelegate, config.isSeparateActivity, profile);
......
......@@ -4,6 +4,9 @@
package org.chromium.chrome.browser.download.home.glue;
import android.os.Handler;
import android.os.Looper;
import org.chromium.base.Callback;
import org.chromium.base.ObserverList;
import org.chromium.chrome.browser.download.home.DownloadManagerUiConfig;
......@@ -13,6 +16,7 @@ import org.chromium.components.offline_items_collection.LaunchLocation;
import org.chromium.components.offline_items_collection.LegacyHelpers;
import org.chromium.components.offline_items_collection.OfflineContentProvider;
import org.chromium.components.offline_items_collection.OfflineItem;
import org.chromium.components.offline_items_collection.RenameResult;
import org.chromium.components.offline_items_collection.ShareCallback;
import org.chromium.components.offline_items_collection.VisualsCallback;
......@@ -77,6 +81,13 @@ public class OfflineContentProviderGlue implements OfflineContentProvider.Observ
}
}
/** @see OfflineContentProvider#renameItem(ContentId, String, Callback) */
public void renameItem(
OfflineItem item, String targetName, Callback</*RenameResult*/ Integer> callback) {
// TODO(hesen):Implement glue.
new Handler(Looper.getMainLooper()).post(() -> callback.onResult(RenameResult.SUCCESS));
}
/** @see OfflineContentProvider#cancelDownload(ContentId) */
public void cancelDownload(OfflineItem item) {
if (mDownloadProvider != null && LegacyHelpers.isLegacyDownload(item.id)) {
......
......@@ -21,11 +21,13 @@ import org.chromium.chrome.browser.download.home.filter.FilterCoordinator;
import org.chromium.chrome.browser.download.home.filter.Filters.FilterType;
import org.chromium.chrome.browser.download.home.list.ListItem.ViewListItem;
import org.chromium.chrome.browser.download.home.metrics.FilterChangeLogger;
import org.chromium.chrome.browser.download.home.rename.RenameDialogCoordinator;
import org.chromium.chrome.browser.download.home.storage.StorageCoordinator;
import org.chromium.chrome.browser.download.home.toolbar.ToolbarCoordinator;
import org.chromium.chrome.browser.widget.selection.SelectionDelegate;
import org.chromium.components.offline_items_collection.OfflineContentProvider;
import org.chromium.components.offline_items_collection.OfflineItem;
import org.chromium.ui.modaldialog.ModalDialogManager;
import java.util.List;
......@@ -78,6 +80,7 @@ public class DateOrderedListCoordinator implements ToolbarCoordinator.ToolbarLis
private final EmptyCoordinator mEmptyCoordinator;
private final DateOrderedListMediator mMediator;
private final DateOrderedListView mListView;
private final RenameDialogCoordinator mRenameDialogCoordinator;
private ViewGroup mMainView;
/**
......@@ -96,15 +99,18 @@ public class DateOrderedListCoordinator implements ToolbarCoordinator.ToolbarLis
OfflineContentProvider provider, DeleteController deleteController,
SelectionDelegate<ListItem> selectionDelegate,
FilterCoordinator.Observer filterObserver,
DateOrderedListObserver dateOrderedListObserver) {
DateOrderedListObserver dateOrderedListObserver,
ModalDialogManager modalDialogManager) {
mContext = context;
ListItemModel model = new ListItemModel();
DecoratedListItemModel decoratedModel = new DecoratedListItemModel(model);
mListView =
new DateOrderedListView(context, config, decoratedModel, dateOrderedListObserver);
mMediator = new DateOrderedListMediator(provider, this ::startShareIntent, deleteController,
selectionDelegate, config, dateOrderedListObserver, model);
mRenameDialogCoordinator = new RenameDialogCoordinator(context, modalDialogManager);
mMediator = new DateOrderedListMediator(provider, this::startShareIntent, deleteController,
this::startRename, selectionDelegate, config, dateOrderedListObserver, model);
mEmptyCoordinator = new EmptyCoordinator(context, mMediator.getEmptySource());
......@@ -144,6 +150,7 @@ public class DateOrderedListCoordinator implements ToolbarCoordinator.ToolbarLis
/** Tears down this coordinator. */
public void destroy() {
mMediator.destroy();
mRenameDialogCoordinator.destroy();
}
/** @return The {@link View} representing downloads home. */
......@@ -182,4 +189,8 @@ public class DateOrderedListCoordinator implements ToolbarCoordinator.ToolbarLis
mContext.startActivity(Intent.createChooser(
intent, mContext.getString(R.string.share_link_chooser_title)));
}
private void startRename(String name, DateOrderedListMediator.RenameCallback callback) {
mRenameDialogCoordinator.startRename(name, callback::tryToRename);
}
}
......@@ -9,6 +9,7 @@ import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import org.chromium.base.Callback;
import org.chromium.base.CollectionUtil;
import org.chromium.base.ContextUtils;
import org.chromium.chrome.browser.ChromeApplication;
......@@ -62,12 +63,38 @@ class DateOrderedListMediator {
void share(Intent intent);
}
/**
* Helper interface for handling rename requests by the UI, allows implementers of the
* RenameController to finish the asynchronous rename operation.
*/
@FunctionalInterface
public interface RenameCallback {
/**
* Calling this will asynchronously attempt to commit a new name.
* @param newName String representing the new name user designated to rename the item.
* @param callback A callback that will pass to the backend to determine the validation
* result.
*/
void tryToRename(String newName, Callback</*RenameResult*/ Integer> callback);
}
/** Helper interface for handling rename requests by the UI. */
@FunctionalInterface
public interface RenameController {
/**
* Will be called whenever {@link OfflineItem}s are being requested to be renamed by the UI.
* @param name representing new name user designated to rename the item.
*/
void rename(String name, RenameCallback result);
}
private final Handler mHandler = new Handler();
private final OfflineContentProviderGlue mProvider;
private final ShareController mShareController;
private final ListItemModel mModel;
private final DeleteController mDeleteController;
private final RenameController mRenameController;
private final OfflineItemSource mSource;
private final DateOrderedListMutator mListMutator;
......@@ -122,9 +149,9 @@ class DateOrderedListMediator {
* @param model The {@link ListItemModel} to push {@code provider} into.
*/
public DateOrderedListMediator(OfflineContentProvider provider, ShareController shareController,
DeleteController deleteController, SelectionDelegate<ListItem> selectionDelegate,
DownloadManagerUiConfig config, DateOrderedListObserver dateOrderedListObserver,
ListItemModel model) {
DeleteController deleteController, RenameController renameController,
SelectionDelegate<ListItem> selectionDelegate, DownloadManagerUiConfig config,
DateOrderedListObserver dateOrderedListObserver, ListItemModel model) {
// Build a chain from the data source to the model. The chain will look like:
// [OfflineContentProvider] ->
// [OfflineItemSource] ->
......@@ -140,6 +167,7 @@ class DateOrderedListMediator {
mShareController = shareController;
mModel = model;
mDeleteController = deleteController;
mRenameController = renameController;
mSelectionDelegate = selectionDelegate;
mUiConfig = config;
......@@ -171,6 +199,7 @@ class DateOrderedListMediator {
mModel.getProperties().set(ListProperties.CALLBACK_REMOVE_ALL, this ::onDeleteItems);
mModel.getProperties().set(ListProperties.PROVIDER_VISUALS, this ::getVisuals);
mModel.getProperties().set(ListProperties.CALLBACK_SELECTION, this ::onSelection);
mModel.getProperties().set(ListProperties.CALLBACK_RENAME, this::onRenameItem);
mModel.getProperties().set(
ListProperties.CALLBACK_START_SELECTION, this ::onStartSelection);
}
......@@ -308,6 +337,13 @@ class DateOrderedListMediator {
deleteItemsInternal(items);
}
private void onRenameItem(OfflineItem item) {
// TODO(hesen): Add sanity check canRename for item, and add uma stats.
mRenameController.rename(item.title, (newName, renameCallback) -> {
mProvider.renameItem(item, newName, renameCallback);
});
}
/**
* Deletes a given list of items. If the items are not completed yet, they would be cancelled.
* @param items The list of items to delete.
......
......@@ -69,6 +69,10 @@ public interface ListProperties {
WritableObjectPropertyKey < Callback < List<OfflineItem>>> CALLBACK_REMOVE_ALL =
new WritableObjectPropertyKey<>();
/** The callback for when a UI action should rename a {@link OfflineItem}. */
WritableObjectPropertyKey<Callback<OfflineItem>> CALLBACK_RENAME =
new WritableObjectPropertyKey<>();
/** The provider to retrieve expensive assets for a {@link OfflineItem}. */
WritableObjectPropertyKey<VisualsProvider> PROVIDER_VISUALS = new WritableObjectPropertyKey<>();
......@@ -89,6 +93,6 @@ public interface ListProperties {
PropertyKey[] ALL_KEYS = new PropertyKey[] {ENABLE_ITEM_ANIMATIONS, CALLBACK_OPEN,
CALLBACK_PAUSE, CALLBACK_RESUME, CALLBACK_CANCEL, CALLBACK_SHARE, CALLBACK_SHARE_ALL,
CALLBACK_REMOVE, CALLBACK_REMOVE_ALL, PROVIDER_VISUALS, CALLBACK_SELECTION,
SELECTION_MODE_ACTIVE, CALLBACK_START_SELECTION};
CALLBACK_REMOVE, CALLBACK_REMOVE_ALL, CALLBACK_RENAME, PROVIDER_VISUALS,
CALLBACK_SELECTION, SELECTION_MODE_ACTIVE, CALLBACK_START_SELECTION};
}
......@@ -35,6 +35,7 @@ class ListPropertyViewBinder implements ViewBinder<PropertyModel, RecyclerView,
|| propertyKey == ListProperties.CALLBACK_REMOVE
|| propertyKey == ListProperties.PROVIDER_VISUALS
|| propertyKey == ListProperties.CALLBACK_SELECTION
|| propertyKey == ListProperties.CALLBACK_RENAME
|| propertyKey == ListProperties.SELECTION_MODE_ACTIVE) {
view.getAdapter().notifyItemRangeChanged(0, view.getAdapter().getItemCount());
}
......
......@@ -37,6 +37,10 @@ class OfflineItemViewHolder extends ListItemViewHolder implements ListMenuButton
// Persisted 'More' button properties.
private Runnable mShareCallback;
private Runnable mDeleteCallback;
private Runnable mRenameCallback;
// flag to hide rename list menu option for offline pages
private boolean mCanRename;
/**
* Creates a new instance of a {@link MoreButtonViewHolder}.
......@@ -76,7 +80,8 @@ class OfflineItemViewHolder extends ListItemViewHolder implements ListMenuButton
() -> properties.get(ListProperties.CALLBACK_SHARE).onResult(offlineItem);
mDeleteCallback =
() -> properties.get(ListProperties.CALLBACK_REMOVE).onResult(offlineItem);
mRenameCallback =
() -> properties.get(ListProperties.CALLBACK_RENAME).onResult(offlineItem);
mMore.setClickable(!properties.get(ListProperties.SELECTION_MODE_ACTIVE));
}
......@@ -97,6 +102,7 @@ class OfflineItemViewHolder extends ListItemViewHolder implements ListMenuButton
});
}, offlineItem.id);
}
// TODO(hesen): Add a new property in OfflineItem, set false for now.
}
@Override
......@@ -123,9 +129,16 @@ class OfflineItemViewHolder extends ListItemViewHolder implements ListMenuButton
// ListMenuButton.Delegate implementation.
@Override
public ListMenuButton.Item[] getItems() {
return new ListMenuButton.Item[] {
new ListMenuButton.Item(itemView.getContext(), R.string.share, true),
new ListMenuButton.Item(itemView.getContext(), R.string.delete, true)};
if (mCanRename) {
return new ListMenuButton.Item[] {
new ListMenuButton.Item(itemView.getContext(), R.string.share, true),
new ListMenuButton.Item(itemView.getContext(), R.string.rename, true),
new ListMenuButton.Item(itemView.getContext(), R.string.delete, true)};
} else {
return new ListMenuButton.Item[] {
new ListMenuButton.Item(itemView.getContext(), R.string.share, true),
new ListMenuButton.Item(itemView.getContext(), R.string.delete, true)};
}
}
@Override
......@@ -134,6 +147,8 @@ class OfflineItemViewHolder extends ListItemViewHolder implements ListMenuButton
if (mShareCallback != null) mShareCallback.run();
} else if (item.getTextId() == R.string.delete) {
if (mDeleteCallback != null) mDeleteCallback.run();
} else if (item.getTextId() == R.string.rename) {
if (mRenameCallback != null) mRenameCallback.run();
}
}
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.download.home.rename;
import android.content.Context;
import android.view.LayoutInflater;
import org.chromium.base.Callback;
import org.chromium.components.offline_items_collection.RenameResult;
import org.chromium.ui.modaldialog.DialogDismissalCause;
import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.modaldialog.ModalDialogProperties;
import org.chromium.ui.modelutil.PropertyModel;
/**
* A class to manage Rename Dialog UI.
*/
public class RenameDialogCoordinator {
/**
* Helper interface for handling rename attempts by the UI, must be called when user click
* submit and make the attempt to rename the download item, allows the UI to
* response to result of a rename attempt from the backend.
*/
@FunctionalInterface
public interface RenameCallback {
void attemptRename(String name, Callback</*@RenameResult*/ Integer> callback);
}
private final ModalDialogManager mModalDialogManager;
private final PropertyModel mRenameDialogModel;
private final RenameDialogCustomView mRenameDialogCustomView;
private String mOriginalName;
private RenameCallback mRenameCallback;
public RenameDialogCoordinator(Context context, ModalDialogManager modalDialogManager) {
mModalDialogManager = modalDialogManager;
mRenameDialogCustomView = (RenameDialogCustomView) LayoutInflater.from(context).inflate(
org.chromium.chrome.download.R.layout.download_rename_custom_dialog, null);
mRenameDialogModel =
new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS)
.with(ModalDialogProperties.CONTROLLER, new RenameDialogController())
.with(ModalDialogProperties.TITLE,
context.getString(org.chromium.chrome.download.R.string.rename))
.with(ModalDialogProperties.CUSTOM_VIEW, mRenameDialogCustomView)
.with(ModalDialogProperties.POSITIVE_BUTTON_TEXT, context.getResources(),
org.chromium.chrome.download.R.string.ok)
.with(ModalDialogProperties.NEGATIVE_BUTTON_TEXT, context.getResources(),
org.chromium.chrome.download.R.string.cancel)
.build();
}
/**
* Function that will be triggered by UI to show a rename dialog showing {@code originalName}.
* @param originalName the Original Name for the download item.
* @param callback the callback that talks to the backend.
*/
public void startRename(String originalName, RenameCallback callback) {
mRenameCallback = callback;
mOriginalName = originalName;
mRenameDialogCustomView.initializeView(originalName);
mModalDialogManager.showDialog(mRenameDialogModel, ModalDialogManager.ModalDialogType.APP);
}
public void destroy() {
if (mModalDialogManager != null) {
mModalDialogManager.dismissDialog(
mRenameDialogModel, DialogDismissalCause.ACTIVITY_DESTROYED);
}
}
private class RenameDialogController implements ModalDialogProperties.Controller {
@Override
public void onDismiss(PropertyModel model, int dismissalCause) {}
@Override
public void onClick(PropertyModel model, int buttonType) {
switch (buttonType) {
case ModalDialogProperties.ButtonType.POSITIVE:
String targetName = mRenameDialogCustomView.getTargetName();
if (targetName.equals(mOriginalName)) {
mModalDialogManager.dismissDialog(
model, DialogDismissalCause.ACTION_ON_CONTENT);
return;
}
mRenameCallback.attemptRename(targetName, result -> {
if (result == RenameResult.SUCCESS) {
mModalDialogManager.dismissDialog(
model, DialogDismissalCause.POSITIVE_BUTTON_CLICKED);
} else {
mRenameDialogCustomView.updateSubtitleView(result);
}
});
break;
case ModalDialogProperties.ButtonType.NEGATIVE:
mModalDialogManager.dismissDialog(
model, DialogDismissalCause.NEGATIVE_BUTTON_CLICKED);
break;
default:
}
}
}
}
\ No newline at end of file
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.download.home.rename;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ScrollView;
import android.widget.TextView;
import org.chromium.chrome.browser.widget.AlertDialogEditText;
import org.chromium.chrome.download.R;
import org.chromium.components.offline_items_collection.RenameResult;
/**
* Content View of dialog in Download Home that allows users to rename a downloaded file
*/
public class RenameDialogCustomView extends ScrollView {
private TextView mSubtitleView;
private AlertDialogEditText mFileName;
public RenameDialogCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
// ScrollView Implementation
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mSubtitleView = findViewById(R.id.subtitle);
mFileName = findViewById(R.id.file_name);
}
/**
* @param suggestedName The suggested file name to fill the initialized edit text.
*/
public void initializeView(String suggestedName) {
if (TextUtils.isEmpty(suggestedName)) return;
mFileName.setText(suggestedName);
mSubtitleView.setVisibility(View.GONE);
}
/**
* @param renameResult RenameResult to distinguish dialog type, used for updating the subtitle
* view.
*/
public void updateSubtitleView(@RenameResult int renameResult) {
if (renameResult == RenameResult.SUCCESS) return;
mSubtitleView.setVisibility(View.VISIBLE);
switch (renameResult) {
case RenameResult.FAILURE_NAME_CONFLICT:
mSubtitleView.setText(R.string.rename_failure_name_conflict);
break;
case RenameResult.FAILURE_NAME_TOO_LONG:
mSubtitleView.setText(R.string.rename_failure_name_too_long);
break;
case RenameResult.FAILURE_UNKNOWN:
mSubtitleView.setText(R.string.rename_failure_name_unavailable);
break;
default:
break;
}
}
/**
* @return a string from user input for the target name.
*/
public String getTargetName() {
return mFileName.getText().toString();
}
}
......@@ -1459,6 +1459,18 @@ Your Google account may have other forms of browsing history like searches and a
<message name="IDS_DOWNLOAD_SETTINGS_ENABLE_PREFETCH_DESCRIPTION" desc="Description for preference that describes that prefetching of articles only happens when connected to Wi-Fi.">
Download occurs only on Wi-Fi
</message>
<message name="IDS_RENAME" desc="Label for the option to rename items.">
Rename
</message>
<message name="IDS_RENAME_FAILURE_NAME_CONFLICT" desc="Subtitle for rename dialog in the case that rename attempt failed because the target name already exists.">
Name already exists
</message>
<message name="IDS_RENAME_FAILURE_NAME_TOO_LONG" desc="Subtitle for rename dialog in the case that rename attempt failed because the target name is too long.">
Name is too long
</message>
<message name="IDS_RENAME_FAILURE_NAME_UNAVAILABLE" desc="Subtitle for rename dialog in the case that rename attempt failed because the target name is unavailable.">
Name is unavailable
</message>
<!-- About Chrome preferences -->
<message name="IDS_PREFS_ABOUT_CHROME" desc="Title for the About Chrome page. [CHAR-LIMIT=32]">
......
......@@ -642,6 +642,8 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/download/home/metrics/FilterChangeLogger.java",
"java/src/org/chromium/chrome/browser/download/home/metrics/OfflineItemStartupLogger.java",
"java/src/org/chromium/chrome/browser/download/home/metrics/UmaUtils.java",
"java/src/org/chromium/chrome/browser/download/home/rename/RenameDialogCoordinator.java",
"java/src/org/chromium/chrome/browser/download/home/rename/RenameDialogCustomView.java",
"java/src/org/chromium/chrome/browser/download/home/snackbars/DeleteUndoCoordinator.java",
"java/src/org/chromium/chrome/browser/download/home/snackbars/UndoUiUtils.java",
"java/src/org/chromium/chrome/browser/download/home/storage/StorageCoordinator.java",
......
......@@ -35,6 +35,7 @@ import org.chromium.chrome.test.ui.DummyUiActivity;
import org.chromium.chrome.test.ui.DummyUiActivityTestCase;
import org.chromium.components.feature_engagement.Tracker;
import org.chromium.components.offline_items_collection.OfflineItem;
import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.test.util.UiRestriction;
import java.util.HashMap;
......@@ -50,6 +51,10 @@ public class DownloadActivityV2Test extends DummyUiActivityTestCase {
private Tracker mTracker;
@Mock
private SnackbarManager mSnackbarManager;
@Mock
private ModalDialogManager.Presenter mAppModalPresenter;
private ModalDialogManager mModalDialogManager;
private DownloadManagerCoordinator mDownloadCoordinator;
......@@ -98,8 +103,12 @@ public class DownloadActivityV2Test extends DummyUiActivityTestCase {
.setUseNewDownloadPath(true)
.setUseNewDownloadPathThumbnails(true)
.build();
mModalDialogManager =
new ModalDialogManager(mAppModalPresenter, ModalDialogManager.ModalDialogType.APP);
mDownloadCoordinator = new DownloadManagerCoordinatorImpl(
mProfile, getActivity(), config, mSnackbarManager);
mProfile, getActivity(), config, mSnackbarManager, mModalDialogManager);
getActivity().setContentView(mDownloadCoordinator.getView());
mDownloadCoordinator.updateForUrl(UrlConstants.DOWNLOADS_URL);
......
......@@ -21,6 +21,7 @@ static_library("core") {
"offline_item_filter.h",
"offline_item_state.h",
"pending_state.h",
"rename_result.h",
"throttled_offline_content_provider.cc",
"throttled_offline_content_provider.h",
]
......@@ -118,6 +119,7 @@ if (is_android) {
"offline_item_filter.h",
"offline_item_state.h",
"pending_state.h",
"rename_result.h",
]
}
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_RENAME_RESULT_H_
#define COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_RENAME_RESULT_H_
// The type of download rename dialog that should by shown by Android.
// A Java counterpart will be generated for this enum.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.offline_items_collection
enum class RenameResult {
SUCCESS = 0, // Rename filename successfully
FAILURE_NAME_CONFLICT = 1, // Filename already exists
FAILURE_NAME_TOO_LONG = 2, // Illegal file name: too long
FAILURE_UNKNOWN = 3, // Unknown
kMaxValue = FAILURE_UNKNOWN
};
#endif // COMPONENTS_OFFLINE_ITEMS_COLLECTION_CORE_RENAME_RESULT_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment