Bug 1232439 - Part 3: Implement full-page bookmark edit dialog. r=ahunt,Grisha

MozReview-Commit-ID: 8wB9CEptVeu

--HG--
extra : rebase_source : 05e9007f52c0a5428b5c316e64b6ead09c11c931
This commit is contained in:
Jing-wei Wu 2017-04-20 09:04:28 +08:00
Родитель 54d4446fc0
Коммит d6a7a9c21f
19 изменённых файлов: 814 добавлений и 47 удалений

Просмотреть файл

@ -22,6 +22,9 @@ import org.mozilla.gecko.DynamicToolbar.VisibilityTransition;
import org.mozilla.gecko.Tabs.TabEvents;
import org.mozilla.gecko.animation.PropertyAnimator;
import org.mozilla.gecko.animation.ViewHelper;
import org.mozilla.gecko.bookmarks.BookmarkEditFragment;
import org.mozilla.gecko.bookmarks.BookmarkUtils;
import org.mozilla.gecko.bookmarks.EditBookmarkTask;
import org.mozilla.gecko.cleanup.FileCleanupController;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.db.BrowserDB;
@ -163,8 +166,6 @@ import android.widget.RelativeLayout;
import android.widget.ViewFlipper;
import org.mozilla.gecko.switchboard.AsyncConfigLoader;
import org.mozilla.gecko.switchboard.SwitchBoard;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import java.io.File;
import java.io.FileNotFoundException;
@ -191,7 +192,8 @@ public class BrowserApp extends GeckoApp
OnUrlOpenInBackgroundListener,
AnchoredPopup.OnVisibilityChangeListener,
ActionModePresenter,
LayoutInflater.Factory {
LayoutInflater.Factory,
BookmarkEditFragment.Callbacks {
private static final String LOGTAG = "GeckoBrowserApp";
private static final int TABS_ANIMATION_DURATION = 450;
@ -4177,4 +4179,22 @@ public class BrowserApp extends GeckoApp
Telemetry.sendUIEvent(TelemetryContract.Event.LAUNCH, method, "restricted");
}
}
/**
* Launch edit bookmark dialog. The {@link BookmarkEditFragment} needs to be started by an activity
* that implements the interface({@link BookmarkEditFragment.Callbacks}) for handling callback method.
*/
public void showEditBookmarkDialog(String pageUrl) {
if (BookmarkUtils.isEnabled(this)) {
BookmarkEditFragment dialog = BookmarkEditFragment.newInstance(pageUrl);
dialog.show(getSupportFragmentManager(), "edit-bookmark");
} else {
new EditBookmarkDialog(this).show(pageUrl);
}
}
@Override
public void onEditBookmark(@NonNull Bundle bundle) {
new EditBookmarkTask(this, bundle).execute();
}
}

Просмотреть файл

@ -0,0 +1,498 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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.gecko.bookmarks;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.support.design.widget.TextInputLayout;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import org.mozilla.gecko.R;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.db.BrowserContract.Bookmarks;
import org.mozilla.gecko.db.BrowserDB;
import java.lang.ref.WeakReference;
/**
* A dialog fragment that allows editing bookmark's url, title and changing the parent."
*/
public class BookmarkEditFragment extends DialogFragment {
private static final String ARG_ID = "id";
private static final String ARG_URL = "url";
private static final String ARG_BOOKMARK = "bookmark";
private long bookmarkId;
private String url;
private Bookmark bookmark;
private Toolbar toolbar;
private EditText nameText;
private TextInputLayout locationLayout;
private EditText locationText;
private EditText folderText;
public interface Callbacks {
/**
* A callback method to tell caller that bookmark has been modified.
* Caller takes charge for the change(e.g. update database).
*/
void onEditBookmark(Bundle bundle);
}
private Callbacks callbacks;
public static BookmarkEditFragment newInstance(long id) {
final Bundle args = new Bundle();
args.putLong(ARG_ID, id);
return newInstance(args);
}
public static BookmarkEditFragment newInstance(String url) {
final Bundle args = new Bundle();
args.putString(ARG_URL, url);
return newInstance(args);
}
private static BookmarkEditFragment newInstance(Bundle args) {
final BookmarkEditFragment fragment = new BookmarkEditFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
Fragment fragment = getTargetFragment();
if (fragment != null && fragment instanceof Callbacks) {
callbacks = (Callbacks) fragment;
} else if (context instanceof Callbacks) {
callbacks = (Callbacks) context;
}
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Apply DialogWhenLarge theme
setStyle(DialogFragment.STYLE_NO_TITLE, R.style.Bookmark_Gecko);
Bundle args = getArguments();
bookmarkId = args.getLong(ARG_ID);
url = args.getString(ARG_URL);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.bookmark_edit_with_full_page, container);
toolbar = (Toolbar) view.findViewById(R.id.toolbar);
nameText = (EditText) view.findViewById(R.id.edit_bookmark_name);
locationLayout = (TextInputLayout) view.findViewById(R.id.edit_bookmark_location_layout);
locationText = (EditText) view.findViewById(R.id.edit_bookmark_location);
folderText = (EditText) view.findViewById(R.id.edit_parent_folder);
toolbar.inflateMenu(R.menu.bookmark_edit_menu);
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.done:
final String newUrl = locationText.getText().toString().trim();
final String newTitle = nameText.getText().toString();
if (callbacks != null) {
if (TextUtils.equals(newTitle, bookmark.originalTitle) &&
TextUtils.equals(newUrl, bookmark.originalUrl) &&
bookmark.parentId == bookmark.originalParentId) {
// Nothing changed, skip callback.
break;
}
final Bundle bundle = new Bundle();
bundle.putLong(Bookmarks._ID, bookmark.id);
bundle.putString(Bookmarks.TITLE, newTitle);
bundle.putString(Bookmarks.URL, newUrl);
bundle.putString(Bookmarks.KEYWORD, bookmark.keyword);
if (bookmark.parentId != bookmark.originalParentId) {
bundle.putLong(Bookmarks.PARENT, bookmark.parentId);
bundle.putLong(BrowserContract.PARAM_OLD_BOOKMARK_PARENT, bookmark.originalParentId);
}
callbacks.onEditBookmark(bundle);
}
break;
}
dismiss();
return true;
}
});
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
if (savedInstanceState != null) {
final Bookmark bookmark = savedInstanceState.getParcelable(ARG_BOOKMARK);
if (bookmark != null) {
invalidateView(bookmark);
return;
}
}
getLoaderManager().initLoader(0, null, new BookmarkLoaderCallbacks());
}
@Override
public void onDestroyView() {
super.onDestroyView();
getLoaderManager().destroyLoader(0);
}
@Override
public void onSaveInstanceState(Bundle outState) {
if (bookmark != null) {
bookmark.url = locationText.getText().toString().trim();
bookmark.title = nameText.getText().toString();
bookmark.folder = folderText.getText().toString();
outState.putParcelable(ARG_BOOKMARK, bookmark);
}
super.onSaveInstanceState(outState);
}
private void invalidateView(Bookmark bookmark) {
this.bookmark = bookmark;
nameText.setText(bookmark.title);
if (bookmark.type == Bookmarks.TYPE_FOLDER) {
locationLayout.setVisibility(View.GONE);
} else {
locationLayout.setVisibility(View.VISIBLE);
}
locationText.setText(bookmark.url);
if (Bookmarks.MOBILE_FOLDER_GUID.equals(bookmark.guid)) {
folderText.setText(R.string.bookmarks_folder_mobile);
} else {
folderText.setText(bookmark.folder);
}
// Enable menu item after bookmark is set to view
final MenuItem doneItem = toolbar.getMenu().findItem(R.id.done);
doneItem.setEnabled(true);
// Add a TextWatcher to prevent invalid input(e.g. empty string).
if (bookmark.type == Bookmarks.TYPE_FOLDER) {
BookmarkTextWatcher nameTextWatcher = new BookmarkTextWatcher(doneItem);
nameText.addTextChangedListener(nameTextWatcher);
} else {
BookmarkTextWatcher locationTextWatcher = new BookmarkTextWatcher(doneItem);
locationText.addTextChangedListener(locationTextWatcher);
}
}
/**
* A private struct to make it easier to pass bookmark data across threads
*/
private static class Bookmark implements Parcelable {
// Cannot be modified in this fragment.
final long id;
final String keyword;
final int type; // folder or bookmark
final String guid;
final String originalTitle;
final String originalUrl;
final long originalParentId;
final String originalFolder;
// Can be modified in this fragment.
String title;
String url;
long parentId;
String folder;
public Bookmark(long id, String url, String title, String keyword, long parentId,
String folder, int type, String guid) {
this(id, url, title, keyword, parentId, folder, type, guid, url, title, parentId, folder);
}
private Bookmark(long id, String originalUrl, String originalTitle, String keyword,
long originalParentId, String originalFolder, int type, String guid,
String modifiedUrl, String modifiedTitle, long modifiedParentId, String modifiedFolder) {
this.id = id;
this.originalUrl = originalUrl;
this.originalTitle = originalTitle;
this.keyword = keyword;
this.originalParentId = originalParentId;
this.originalFolder = originalFolder;
this.type = type;
this.guid = guid;
this.url = modifiedUrl;
this.title = modifiedTitle;
this.parentId = modifiedParentId;
this.folder = modifiedFolder;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeLong(id);
parcel.writeString(url);
parcel.writeString(title);
parcel.writeString(keyword);
parcel.writeLong(parentId);
parcel.writeString(folder);
parcel.writeInt(type);
parcel.writeString(guid);
parcel.writeString(originalUrl);
parcel.writeString(originalTitle);
parcel.writeLong(originalParentId);
parcel.writeString(originalFolder);
}
public static final Creator<Bookmark> CREATOR = new Creator<Bookmark>() {
@Override
public Bookmark createFromParcel(final Parcel source) {
final long id = source.readLong();
final String modifiedUrl = source.readString();
final String modifiedTitle = source.readString();
final String keyword = source.readString();
final long modifiedParentId = source.readLong();
final String modifiedFolder = source.readString();
final int type = source.readInt();
final String guid = source.readString();
final String originalUrl = source.readString();
final String originalTitle = source.readString();
final long originalParentId = source.readLong();
final String originalFolder = source.readString();
return new Bookmark(id, originalUrl, originalTitle, keyword, originalParentId, originalFolder,
type, guid, modifiedUrl, modifiedTitle, modifiedParentId, modifiedFolder);
}
@Override
public Bookmark[] newArray(final int size) {
return new Bookmark[size];
}
};
}
private class BookmarkLoaderCallbacks implements LoaderManager.LoaderCallbacks<Bookmark> {
@Override
public Loader<Bookmark> onCreateLoader(int id, Bundle args) {
return new BookmarkLoader(getContext(), bookmarkId, url);
}
@Override
public void onLoadFinished(Loader<Bookmark> loader, final Bookmark bookmark) {
if (bookmark == null) {
return;
}
invalidateView(bookmark);
}
@Override
public void onLoaderReset(Loader<Bookmark> loader) {
}
}
/**
* An AsyncTaskLoader to load {@link Bookmark} from a cursor.
*/
private static class BookmarkLoader extends AsyncTaskLoader<Bookmark> {
private final long bookmarkId;
private final String url;
private final ContentResolver contentResolver;
private final BrowserDB db;
private Bookmark bookmark;
private BookmarkLoader(Context context, long id, String url) {
super(context);
this.bookmarkId = id;
this.url = url;
this.contentResolver = context.getContentResolver();
this.db = BrowserDB.from(context);
}
@Override
public Bookmark loadInBackground() {
final Cursor cursor;
if (url != null) {
cursor = db.getBookmarkForUrl(contentResolver, url);
} else {
cursor = db.getBookmarkById(contentResolver, bookmarkId);
}
if (cursor == null) {
return null;
}
Bookmark bookmark = null;
try {
if (cursor.moveToFirst()) {
final long id = cursor.getLong(cursor.getColumnIndexOrThrow(Bookmarks._ID));
final String url = cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.URL));
final String title = cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.TITLE));
final String keyword = cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.KEYWORD));
final long parentId = cursor.getLong(cursor.getColumnIndexOrThrow(Bookmarks.PARENT));
final String parentName = queryParentName(parentId);
final int type = cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks.TYPE));
final String guid = cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.GUID));
bookmark = new Bookmark(id, url, title, keyword, parentId, parentName, type, guid);
}
} finally {
cursor.close();
}
return bookmark;
}
private String queryParentName(long folderId) {
Cursor cursor = db.getBookmarkById(contentResolver, folderId);
if (cursor == null) {
return "";
}
String folderName = "";
try {
if (cursor.moveToFirst()) {
final String guid = cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.GUID));
if (Bookmarks.MOBILE_FOLDER_GUID.equals(guid)) {
folderName = getContext().getString(R.string.bookmarks_folder_mobile);
} else {
folderName = cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.TITLE));
}
}
} finally {
cursor.close();
}
return folderName;
}
@Override
public void deliverResult(Bookmark bookmark) {
if (isReset()) {
this.bookmark = null;
return;
}
this.bookmark = bookmark;
if (isStarted()) {
super.deliverResult(bookmark);
}
}
@Override
protected void onStartLoading() {
if (bookmark != null) {
deliverResult(bookmark);
}
if (takeContentChanged() || bookmark == null) {
forceLoad();
}
}
@Override
protected void onStopLoading() {
cancelLoad();
}
@Override
public void onCanceled(Bookmark bookmark) {
this.bookmark = null;
}
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped.
onStopLoading();
bookmark = null;
}
}
/**
* This text watcher enables the menu item if the dialog contains valid information, or disables otherwise.
*/
private class BookmarkTextWatcher implements TextWatcher {
// A stored reference to the dialog containing the text field being watched.
private final WeakReference<MenuItem> doneItemWeakReference;
// Whether or not the menu item should be enabled.
private boolean enabled = true;
private BookmarkTextWatcher(MenuItem doneItem) {
doneItemWeakReference = new WeakReference<>(doneItem);
}
public boolean isEnabled() {
return enabled;
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Disables the menu item if the input field is empty.
final boolean enabled = (s.toString().trim().length() > 0);
final MenuItem doneItem = doneItemWeakReference.get();
if (doneItem != null) {
doneItem.setEnabled(enabled);
}
}
@Override
public void afterTextChanged(Editable s) {}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
}
}

Просмотреть файл

@ -0,0 +1,68 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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.gecko.bookmarks;
import android.app.Activity;
import android.content.ContentResolver;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import org.mozilla.gecko.R;
import org.mozilla.gecko.SnackbarBuilder;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UIAsyncTask;
import java.lang.ref.WeakReference;
public class EditBookmarkTask extends UIAsyncTask.WithoutParams<Void> {
private final WeakReference<Activity> activityWeakReference;
private final BrowserDB db;
private final ContentResolver contentResolver;
private final Bundle bundle;
public EditBookmarkTask(Activity activity, @NonNull Bundle bundle) {
super(ThreadUtils.getBackgroundHandler());
this.activityWeakReference = new WeakReference<>(activity);
this.db = BrowserDB.from(activity);
this.contentResolver = activity.getContentResolver();
this.bundle = bundle;
}
@Override
public Void doInBackground() {
final long bookmarkId = bundle.getLong(BrowserContract.Bookmarks._ID);
final String url = bundle.getString(BrowserContract.Bookmarks.URL);
final String title = bundle.getString(BrowserContract.Bookmarks.TITLE);
final String keyword = bundle.getString(BrowserContract.Bookmarks.KEYWORD);
if (bundle.containsKey(BrowserContract.Bookmarks.PARENT) &&
bundle.containsKey(BrowserContract.PARAM_OLD_BOOKMARK_PARENT)) {
final long newParentId = bundle.getLong(BrowserContract.Bookmarks.PARENT);
final long oldParentId = bundle.getLong(BrowserContract.PARAM_OLD_BOOKMARK_PARENT);
db.updateBookmark(contentResolver, bookmarkId, url, title, keyword, newParentId, oldParentId);
} else {
db.updateBookmark(contentResolver, bookmarkId, url, title, keyword);
}
return null;
}
@Override
public void onPostExecute(Void result) {
final Activity activity = activityWeakReference.get();
if (activity == null || activity.isFinishing()) {
return;
}
SnackbarBuilder.builder(activity)
.message(R.string.bookmark_updated)
.duration(Snackbar.LENGTH_LONG)
.buildAndShow();
}
}

Просмотреть файл

@ -17,7 +17,6 @@ import android.widget.ListView;
import org.mozilla.gecko.AboutPages;
import org.mozilla.gecko.BrowserApp;
import org.mozilla.gecko.EditBookmarkDialog;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.R;
@ -171,7 +170,7 @@ public class BookmarkStateChangeDelegate extends BrowserAppDelegateWithReference
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION,
TelemetryContract.Method.DIALOG, extrasId);
new EditBookmarkDialog(browserApp).show(tab.getURL());
browserApp.showEditBookmarkDialog(tab.getURL());
} else if (itemId == 1) {
final String extrasId = res.getResourceEntryName(R.string.contextmenu_add_to_launcher);

Просмотреть файл

@ -9,8 +9,12 @@ import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.mozilla.gecko.EditBookmarkDialog;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.R;
import org.mozilla.gecko.bookmarks.BookmarkEditFragment;
import org.mozilla.gecko.bookmarks.BookmarkUtils;
import org.mozilla.gecko.bookmarks.EditBookmarkTask;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.db.BrowserContract.Bookmarks;
import org.mozilla.gecko.db.BrowserDB;
@ -32,7 +36,9 @@ import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
@ -42,7 +48,7 @@ import android.widget.TextView;
/**
* A page in about:home that displays a ListView of bookmarks.
*/
public class BookmarksPanel extends HomeFragment {
public class BookmarksPanel extends HomeFragment implements BookmarkEditFragment.Callbacks {
public static final String LOGTAG = "GeckoBookmarksPanel";
// Cursor loader ID for list of bookmarks.
@ -161,6 +167,38 @@ public class BookmarksPanel extends HomeFragment {
loadIfVisible();
}
@Override
public boolean onContextItemSelected(MenuItem item) {
if (super.onContextItemSelected(item)) {
// HomeFragment was able to handle to selected item.
return true;
}
final ContextMenuInfo menuInfo = item.getMenuInfo();
if (!(menuInfo instanceof HomeContextMenuInfo)) {
return false;
}
final HomeContextMenuInfo info = (HomeContextMenuInfo) menuInfo;
final int itemId = item.getItemId();
final Context context = getContext();
if (itemId == R.id.home_edit_bookmark) {
if (BookmarkUtils.isEnabled(getContext())) {
final BookmarkEditFragment dialog = BookmarkEditFragment.newInstance(info.bookmarkId);
dialog.setTargetFragment(this, 0);
dialog.show(getFragmentManager(), "edit-bookmark");
} else {
// UI Dialog associates to the activity context, not the applications'.
new EditBookmarkDialog(context).show(info.url);
}
return true;
}
return false;
}
@Override
public void onDestroyView() {
mList = null;
@ -194,6 +232,11 @@ public class BookmarksPanel extends HomeFragment {
getLoaderManager().initLoader(LOADER_ID_BOOKMARKS_LIST, bundle, mLoaderCallbacks);
}
@Override
public void onEditBookmark(@NonNull Bundle bundle) {
new EditBookmarkTask(getActivity(), bundle).execute();
}
private void updateUiFromCursor(Cursor c) {
if ((c == null || c.getCount() == 0) && mEmptyView == null) {
// Set empty page view. We delay this so that the empty view won't flash.
@ -305,7 +348,7 @@ public class BookmarksPanel extends HomeFragment {
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
BookmarksLoader bl = (BookmarksLoader) loader;
final BookmarksLoader bl = (BookmarksLoader) loader;
mListAdapter.swapCursor(c, bl.getFolderInfo(), bl.getRefreshType());
if (mPanelStateChangeListener != null) {
@ -324,7 +367,7 @@ public class BookmarksPanel extends HomeFragment {
// BrowserDB updates (e.g. through sync, or when opening a new tab) will trigger
// a refresh which reuses the same loader - in that case we don't want to reset
// the scroll position again.
int currentLoaderHash = bl.hashCode();
final int currentLoaderHash = bl.hashCode();
if (mList != null && currentLoaderHash != mLastLoaderHash) {
mList.setSelection(bl.getTargetPosition());
mLastLoaderHash = currentLoaderHash;

Просмотреть файл

@ -442,7 +442,7 @@ public class BrowserSearch extends HomeFragment
// Position for Top Sites grid items, but will always be -1 since this is only for BrowserSearch result
final int position = -1;
new RemoveItemByUrlTask(context, info.url, info.itemType, position).execute();
new RemoveItemTask(getActivity(), info, position).execute();
return true;
}

Просмотреть файл

@ -5,9 +5,9 @@
package org.mozilla.gecko.home;
import java.lang.ref.WeakReference;
import java.util.EnumSet;
import org.mozilla.gecko.EditBookmarkDialog;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.GeckoProfile;
@ -17,7 +17,6 @@ import org.mozilla.gecko.R;
import org.mozilla.gecko.SnackbarBuilder;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.db.BrowserContract.SuggestedSites;
import org.mozilla.gecko.distribution.PartnerBookmarksProviderProxy;
@ -296,20 +295,14 @@ public abstract class HomeFragment extends Fragment {
return true;
}
if (itemId == R.id.home_edit_bookmark) {
// UI Dialog associates to the activity context, not the applications'.
new EditBookmarkDialog(context).show(info.url);
return true;
}
if (itemId == R.id.home_remove) {
// For Top Sites grid items, position is required in case item is Pinned.
final int position = info instanceof TopSitesGridContextMenuInfo ? info.position : -1;
if (info.hasPartnerBookmarkId()) {
new RemovePartnerBookmarkTask(context, info.bookmarkId).execute();
new RemovePartnerBookmarkTask(getActivity(), info.bookmarkId).execute();
} else {
new RemoveItemByUrlTask(context, info.url, info.itemType, position).execute();
new RemoveItemTask(getActivity(), info, position).execute();
}
return true;
}
@ -395,39 +388,40 @@ public abstract class HomeFragment extends Fragment {
mIsLoaded = true;
}
protected static class RemoveItemByUrlTask extends UIAsyncTask.WithoutParams<Void> {
private final Context mContext;
private final String mUrl;
private final RemoveItemType mType;
private final int mPosition;
private final BrowserDB mDB;
static class RemoveItemTask extends UIAsyncTask.WithoutParams<Void> {
private final WeakReference<Activity> activityWeakReference;
private final Context context;
private final HomeContextMenuInfo info;
private final int position;
private final BrowserDB db;
/**
* Remove bookmark/history/reading list type item by url, and also unpin the
* Remove bookmark/history/reading list type item, and also unpin the
* Top Sites grid item at index <code>position</code>.
*/
public RemoveItemByUrlTask(Context context, String url, RemoveItemType type, int position) {
RemoveItemTask(Activity activity, HomeContextMenuInfo info, int position) {
super(ThreadUtils.getBackgroundHandler());
mContext = context;
mUrl = url;
mType = type;
mPosition = position;
mDB = BrowserDB.from(context);
this.activityWeakReference = new WeakReference<>(activity);
this.context = activity.getApplicationContext();
this.info = info;
this.position = position;
this.db = BrowserDB.from(context);
}
@Override
public Void doInBackground() {
ContentResolver cr = mContext.getContentResolver();
ContentResolver cr = context.getContentResolver();
if (mPosition > -1) {
mDB.unpinSite(cr, mPosition);
if (mDB.hideSuggestedSite(mUrl)) {
if (position > -1) {
db.unpinSite(cr, position);
if (db.hideSuggestedSite(info.url)) {
cr.notifyChange(SuggestedSites.CONTENT_URI, null);
}
}
switch (mType) {
final RemoveItemType type = info.itemType;
switch (type) {
case BOOKMARKS:
removeBookmark(cr);
break;
@ -442,7 +436,7 @@ public abstract class HomeFragment extends Fragment {
break;
default:
Log.e(LOGTAG, "Can't remove item type " + mType.toString());
Log.e(LOGTAG, "Can't remove item type " + type.toString());
break;
}
return null;
@ -450,15 +444,20 @@ public abstract class HomeFragment extends Fragment {
@Override
public void onPostExecute(Void result) {
SnackbarBuilder.builder((Activity) mContext)
final Activity activity = activityWeakReference.get();
if (activity == null || activity.isFinishing()) {
return;
}
SnackbarBuilder.builder(activity)
.message(R.string.page_removed)
.duration(Snackbar.LENGTH_LONG)
.buildAndShow();
}
private void removeBookmark(ContentResolver cr) {
SavedReaderViewHelper rch = SavedReaderViewHelper.getSavedReaderViewHelper(mContext);
final boolean isReaderViewPage = rch.isURLCached(mUrl);
SavedReaderViewHelper rch = SavedReaderViewHelper.getSavedReaderViewHelper(context);
final boolean isReaderViewPage = rch.isURLCached(info.url);
final String extra;
if (isReaderViewPage) {
@ -468,26 +467,28 @@ public abstract class HomeFragment extends Fragment {
}
Telemetry.sendUIEvent(TelemetryContract.Event.UNSAVE, TelemetryContract.Method.CONTEXT_MENU, extra);
mDB.removeBookmarksWithURL(cr, mUrl);
db.removeBookmarkWithId(cr, info.bookmarkId);
if (isReaderViewPage) {
ReadingListHelper.removeCachedReaderItem(mUrl, mContext);
ReadingListHelper.removeCachedReaderItem(info.url, context);
}
}
private void removeHistory(ContentResolver cr) {
mDB.removeHistoryEntry(cr, mUrl);
db.removeHistoryEntry(cr, info.url);
}
}
private static class RemovePartnerBookmarkTask extends UIAsyncTask.WithoutParams<Void> {
private final WeakReference<Activity> activityWeakReference;
private Context context;
private long bookmarkId;
public RemovePartnerBookmarkTask(Context context, long bookmarkId) {
private RemovePartnerBookmarkTask(Activity activity, long bookmarkId) {
super(ThreadUtils.getBackgroundHandler());
this.context = context;
this.activityWeakReference = new WeakReference<>(activity);
this.context = activity.getApplicationContext();
this.bookmarkId = bookmarkId;
}
@ -504,7 +505,12 @@ public abstract class HomeFragment extends Fragment {
@Override
protected void onPostExecute(Void aVoid) {
SnackbarBuilder.builder((Activity) context)
final Activity activity = activityWeakReference.get();
if (activity == null || activity.isFinishing()) {
return;
}
SnackbarBuilder.builder(activity)
.message(R.string.page_removed)
.duration(Snackbar.LENGTH_LONG)
.buildAndShow();

Просмотреть файл

@ -75,6 +75,7 @@
<!ENTITY bookmark_removed "Bookmark removed">
<!ENTITY bookmark_updated "Bookmark updated">
<!ENTITY bookmark_options "Options">
<!ENTITY bookmark_save "Save">
<!ENTITY screenshot_added_to_bookmarks "Screenshot added to bookmarks">
<!-- Localization note (screenshot_folder_label_in_bookmarks): We save links to screenshots
the user takes. The folder we store these links in is located in the bookmarks list
@ -86,6 +87,7 @@
in the folder. -->
<!ENTITY bookmark_folder_items "&formatD; items">
<!ENTITY bookmark_folder_one_item "1 item">
<!ENTITY bookmark_parent_folder "Parent Folder">
<!ENTITY reader_saved_offline "Saved offline">
<!-- Localization note (reader_switch_to_bookmarks) : This

Просмотреть файл

@ -482,7 +482,9 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
'animation/Rotate3DAnimation.java',
'animation/ViewHelper.java',
'ANRReporter.java',
'bookmarks/BookmarkEditFragment.java',
'bookmarks/BookmarkUtils.java',
'bookmarks/EditBookmarkTask.java',
'BootReceiver.java',
'BrowserApp.java',
'BrowserLocaleManager.java',

Двоичные данные
mobile/android/base/resources/drawable-hdpi/arrow.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 20 KiB

Двоичные данные
mobile/android/base/resources/drawable-ldrtl-hdpi/arrow.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 20 KiB

Двоичные данные
mobile/android/base/resources/drawable-ldrtl-xhdpi/arrow.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 20 KiB

Двоичные данные
mobile/android/base/resources/drawable-ldrtl-xxhdpi/arrow.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 20 KiB

Двоичные данные
mobile/android/base/resources/drawable-xhdpi/arrow.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 20 KiB

Двоичные данные
mobile/android/base/resources/drawable-xxhdpi/arrow.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 20 KiB

Просмотреть файл

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="@color/text_and_tabs_tray_grey"
android:minHeight="?actionBarSize"
app:navigationIcon="@drawable/abc_ic_clear_mtrl_alpha"
app:subtitleTextColor="@android:color/white"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:title="@string/bookmark_edit_title"
app:titleTextColor="@android:color/white" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
android:paddingEnd="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingStart="16dp">
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="16dp">
<EditText
android:id="@+id/edit_bookmark_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="start"
android:hint="@string/bookmark_edit_name"
android:maxLines="1"
android:singleLine="true"
android:textColor="@color/text_and_tabs_tray_grey"
android:textSize="18sp"
android:focusable="true"
tools:text="Firefox: About your browser" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/edit_bookmark_location_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="16dp">
<EditText
android:id="@+id/edit_bookmark_location"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="start"
android:hint="@string/bookmark_edit_location"
android:inputType="textNoSuggestions"
android:maxLines="1"
android:singleLine="true"
android:textColor="@color/text_and_tabs_tray_grey"
android:textSize="18sp" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="16dp">
<EditText
android:id="@+id/edit_parent_folder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:cursorVisible="false"
android:drawableEnd="@drawable/arrow"
android:drawableRight="@drawable/arrow"
android:drawablePadding="8dp"
android:ellipsize="end"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="start"
android:hint="@string/bookmark_parent_folder"
android:inputType="none"
android:maxLines="1"
android:singleLine="true"
android:textColor="@color/text_and_tabs_tray_grey"
android:textSize="18sp" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
</LinearLayout>

Просмотреть файл

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/done"
android:title="@string/bookmark_save"
android:enabled="false"
app:showAsAction="always"/>
</menu>

Просмотреть файл

@ -137,4 +137,18 @@
<item name="windowActionModeOverlay">true</item>
</style>
<!-- Bookmark full-page dialog theme -->
<style name="Bookmark" parent="Theme.AppCompat.Light.DialogWhenLarge"/>
<style name="Bookmark.Gecko" parent="Gecko">
<item name="toolbarStyle">@style/BookmarkToolbarStyle</item>
<item name="colorAccent">@color/fennec_ui_orange</item>
<item name="colorControlNormal">@color/disabled_grey</item>
<item name="android:textColorHint">@color/tabs_tray_icon_grey</item>
</style>
<style name="BookmarkToolbarStyle" parent="@style/Widget.AppCompat.Toolbar">
<item name="android:paddingRight">5dp</item>
<item name="android:paddingEnd">5dp</item>
</style>
</resources>

Просмотреть файл

@ -97,11 +97,13 @@
<string name="bookmark_removed">&bookmark_removed;</string>
<string name="bookmark_updated">&bookmark_updated;</string>
<string name="bookmark_options">&bookmark_options;</string>
<string name="bookmark_save">&bookmark_save;</string>
<string name="screenshot_added_to_bookmarks">&screenshot_added_to_bookmarks;</string>
<string name="screenshot_folder_label_in_bookmarks">&screenshot_folder_label_in_bookmarks;</string>
<string name="readinglist_smartfolder_label_in_bookmarks">&readinglist_smartfolder_label_in_bookmarks;</string>
<string name="bookmark_folder_items">&bookmark_folder_items;</string>
<string name="bookmark_folder_one_item">&bookmark_folder_one_item;</string>
<string name="bookmark_parent_folder">&bookmark_parent_folder;</string>
<string name="reader_saved_offline">&reader_saved_offline;</string>
<string name="reader_switch_to_bookmarks">&reader_switch_to_bookmarks;</string>