[WIP] Bug 1232439 (972193) - Add "Choose Folder" bookmark edit dialog option. draft
authorTom Klein <twointofive@gmail.com>
Thu, 08 Dec 2016 09:52:19 -0600
changeset 453960 3fecda8a0f25d06e05d4d74032259d815867a6fb
parent 453959 7f4641fd4743840368d56320e99739d5dd066591
child 453961 44fb5136dd8b306c7d083006ca722a0964a2005c
push id39777
push userbmo:twointofive@gmail.com
push dateMon, 26 Dec 2016 21:30:36 +0000
bugs1232439, 972193
milestone53.0a1
[WIP] Bug 1232439 (972193) - Add "Choose Folder" bookmark edit dialog option. MozReview-Commit-ID: L152bg4QH4Q
mobile/android/base/java/org/mozilla/gecko/BookmarkToolbarDialog.java
mobile/android/base/java/org/mozilla/gecko/ChooseBookmarkFolderDialog.java
mobile/android/base/java/org/mozilla/gecko/EditBookmarkDialog.java
mobile/android/base/locales/en-US/android_strings.dtd
mobile/android/base/moz.build
mobile/android/base/resources/layout/choose_bookmark_folder.xml
mobile/android/base/strings.xml.in
--- a/mobile/android/base/java/org/mozilla/gecko/BookmarkToolbarDialog.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BookmarkToolbarDialog.java
@@ -7,29 +7,34 @@ package org.mozilla.gecko;
 
 import org.mozilla.gecko.db.BrowserContract;
 
 import android.app.Activity;
 import android.content.Intent;
 import android.support.annotation.MenuRes;
 import android.support.annotation.StringRes;
 import android.support.design.widget.TextInputLayout;
+import android.os.Bundle;
 import android.support.v4.app.DialogFragment;
 import android.support.v4.app.Fragment;
 import android.support.v7.widget.Toolbar;
 import android.text.Editable;
 import android.text.TextWatcher;
 import android.view.MenuItem;
 import android.view.View;
 
 public abstract class BookmarkToolbarDialog extends DialogFragment
                                             implements FolderTreeView.FolderSelectedListener  {
     protected static final String ARG_FOLDER_ID = "folder_id";
     protected static final String ARG_FOLDER_NAME = "folder_name";
 
+    // setTargetFragment requires an int code, which we don't actually need since a given dialog is
+    // only ever the target of at most one other dialog.
+    protected static final int TARGET_FRAGMENT_CODE_UNUSED = -1;
+
     // The fake Dekstop folder isn't selectable, so use its ID as our invalid folder ID value (the
     // desktop folder doesn't actually exist in the database, so attempting to use it in the
     // database as a parent folder ID will crash on a failed foreign key constraint rather than
     // leading to invalid parent data).
     protected static int INVALID_FOLDER_ID = BrowserContract.Bookmarks.FAKE_DESKTOP_FOLDER_ID;
 
     protected abstract @StringRes int toolbarTitle();
 
@@ -85,16 +90,23 @@ public abstract class BookmarkToolbarDia
         // Send on the selected folder data to this fragment's target fragment.
         final Intent intent = new Intent();
         intent.putExtra(ARG_FOLDER_NAME, folderName);
         intent.putExtra(ARG_FOLDER_ID, folderId);
         targetFragment.onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, intent);
         getFragmentManager().popBackStack();
     }
 
+    protected void setDialogFolderArguments(int folderId, String folderName) {
+        final Bundle args = new Bundle();
+        args.putInt(ARG_FOLDER_ID, folderId);
+        args.putString(ARG_FOLDER_NAME, folderName);
+        setArguments(args);
+    }
+
     protected static class EmptyTextWatcher implements TextWatcher {
         private final TextInputLayout textInputLayout;
         private final String errorText;
 
         EmptyTextWatcher(TextInputLayout textInputLayout, String errorText) {
             this.textInputLayout = textInputLayout;
             this.errorText = errorText;
         }
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/ChooseBookmarkFolderDialog.java
@@ -0,0 +1,61 @@
+/* -*- 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;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.annotation.StringRes;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class ChooseBookmarkFolderDialog extends BookmarkFolderTreeDialog {
+    private int currentFolderId;
+    private String currentFolderName;
+
+    public static ChooseBookmarkFolderDialog newInstance(int currentFolderId, String currentFolderName) {
+        final ChooseBookmarkFolderDialog dialog = new ChooseBookmarkFolderDialog();
+        dialog.setDialogFolderArguments(currentFolderId, currentFolderName);
+        return dialog;
+    }
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final Bundle args = getArguments();
+        currentFolderId = args.getInt(ARG_FOLDER_ID);
+        currentFolderName = args.getString(ARG_FOLDER_NAME);
+    }
+
+    @Override
+    protected @StringRes int toolbarTitle() {
+        return R.string.bookmark_dialog_choose_folder;
+    }
+
+    @Override
+    protected int currentFolderId() {
+        return currentFolderId;
+    }
+
+    @Nullable
+    @Override
+    public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
+        final View editView = inflater.inflate(R.layout.choose_bookmark_folder, container, false);
+
+        setupToolbar(editView, null);
+        setupFolderTree(editView, true);
+
+        editView.findViewById(R.id.add_new_folder).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+            // TODO: Create new fragment to add a new folder.
+            }
+        });
+
+        return editView;
+    }
+}
--- a/mobile/android/base/java/org/mozilla/gecko/EditBookmarkDialog.java
+++ b/mobile/android/base/java/org/mozilla/gecko/EditBookmarkDialog.java
@@ -5,18 +5,20 @@
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.db.BrowserContract.Bookmarks;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.util.UIAsyncTask;
 
+import android.app.Activity;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
 import android.database.Cursor;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.annotation.StringRes;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentTransaction;
 import android.support.design.widget.Snackbar;
 import android.support.design.widget.TextInputLayout;
@@ -33,16 +35,18 @@ import android.widget.EditText;
  */
 public class EditBookmarkDialog extends BookmarkToolbarDialog {
     private Bookmark mBookmark;
 
     private ViewGroup rootView;
     private EditText nameText;
     private EditText locationText;
     private EditText keywordText;
+    private EditText folderText;
+
     @Override
     public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
 
         mBookmark.saveToBundle(outState);
     }
 
     @Override
@@ -165,41 +169,73 @@ public class EditBookmarkDialog extends 
     @Override
     public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
         final View editView = inflater.inflate(R.layout.bookmark_edit, container, false);
 
         rootView = container;
         nameText = ((EditText) editView.findViewById(R.id.edit_bookmark_name));
         locationText = ((EditText) editView.findViewById(R.id.edit_bookmark_location));
         keywordText = ((EditText) editView.findViewById(R.id.edit_bookmark_keyword));
-        final EditText folderText = ((EditText) editView.findViewById(R.id.edit_bookmark_folder));
+        folderText = ((EditText) editView.findViewById(R.id.edit_bookmark_folder));
 
         setupToolbar(editView, R.menu.bookmarks_dialog_menu_save_and_remove);
 
         // Insert text BEFORE the cursor - when the user opens the dialog we want the cursor to be at the end of the name
         // field. We've already requested focus in the layout file using <requestFocus/>, however using setText
         // results in the cursor staying at the start of the text, whereas insert(0,...) results in the text being
         // inserted in front of the cursor.
         nameText.getText().insert(0, mBookmark.title);
         locationText.setText(mBookmark.url);
         keywordText.setText(mBookmark.keyword);
+        // The folder text is updated in onResume (see the note there).
 
         folderText.setOnClickListener(new View.OnClickListener() {
             public void onClick(View v) {
-                // TODO: launch new folder chooser dialog.
+                final ChooseBookmarkFolderDialog chooseFolderDialog =
+                        ChooseBookmarkFolderDialog.newInstance(mBookmark.folderId, mBookmark.folderName);
+                chooseFolderDialog.setTargetFragment(EditBookmarkDialog.this, TARGET_FRAGMENT_CODE_UNUSED);
+                FragmentTransaction transaction = getFragmentManager().beginTransaction();
+                transaction.replace(android.R.id.content, chooseFolderDialog)
+                        .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
+                        .addToBackStack(null)
+                        .commit();
             }
         });
 
         final TextInputLayout locationTextLayout = (TextInputLayout) editView.findViewById(R.id.edit_bookmark_location_layout);
         final String emptyURLErrorText = getString(R.string.bookmark_edit_location_empty_error);
         locationText.addTextChangedListener(new EmptyTextWatcher(locationTextLayout, emptyURLErrorText));
 
         return editView;
     }
 
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        // Updating the folder text after a new folder has been chosen doesn't work in
+        // onActivityResult or onCreateView, so we just always set it here.
+        folderText.setText(mBookmark.folderName);
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (resultCode != Activity.RESULT_OK || data == null) {
+            return;
+        }
+
+        final String folderName = data.getStringExtra(ARG_FOLDER_NAME);
+        final int folderId = data.getIntExtra(ARG_FOLDER_ID, INVALID_FOLDER_ID);
+        if (folderName != null && folderId != INVALID_FOLDER_ID) {
+            mBookmark.folderId = folderId;
+            mBookmark.folderName = folderName;
+            // Updating the EditText folder name doesn't work here; we do it in onResume instead.
+        }
+    }
+
     /**
      * Show the Edit bookmark dialog for a particular url. If the url is bookmarked multiple times
      * this will just edit the first instance it finds.
      *
      * @param url The url of the bookmark to edit. The dialog will look up other information like the id,
      *            current title, or keywords associated with this url. If the url isn't bookmarked, the
      *            dialog will fail silently. If the url is bookmarked multiple times, this will only show
      *            information about the first it finds.
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -85,16 +85,18 @@
      and is labeled by this String. -->
 <!ENTITY screenshot_folder_label_in_bookmarks "Screenshots">
 <!ENTITY readinglist_smartfolder_label_in_bookmarks "Reading List">
 
 <!-- Localization note (bookmark_dialog_save_and_return): Alternate text for accessibility; not UI
      visible.  Save the data input in the current dialog and return to the previous dialog. -->
 <!ENTITY bookmark_dialog_save_and_return "Save and return">
 <!ENTITY bookmark_dialog_folder "Folder">
+<!ENTITY bookmark_dialog_choose_folder "Choose folder">
+<!ENTITY bookmark_dialog_new_folder "New folder...">
 
 <!ENTITY bookmark_edit_title "Edit Bookmark">
 <!ENTITY bookmark_edit_name "Name">
 <!ENTITY bookmark_edit_location "Location">
 <!ENTITY bookmark_edit_keyword "Keyword">
 <!ENTITY bookmark_edit_location_empty_error "Bookmark location must contain a URL">
 
 <!-- Localization note (bookmark_folder_items): The variable is replaced by the number of items
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -342,16 +342,17 @@ gbjar.sources += ['java/org/mozilla/geck
     'animation/Rotate3DAnimation.java',
     'animation/ViewHelper.java',
     'ANRReporter.java',
     'BookmarkFolderTreeDialog.java',
     'BookmarkToolbarDialog.java',
     'BootReceiver.java',
     'BrowserApp.java',
     'BrowserLocaleManager.java',
+    'ChooseBookmarkFolderDialog.java',
     'cleanup/FileCleanupController.java',
     'cleanup/FileCleanupService.java',
     'CustomEditText.java',
     'customtabs/CustomTabsActivity.java',
     'customtabs/GeckoCustomTabsService.java',
     'DataReportingNotification.java',
     'db/AbstractPerProfileDatabaseProvider.java',
     'db/AbstractTransactionalProvider.java',
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/layout/choose_bookmark_folder.xml
@@ -0,0 +1,45 @@
+<?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"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:background="@android:color/white"
+              android:theme="@style/GeckoAlertDialog">
+
+    <include layout="@layout/bookmark_dialog_toolbar"/>
+
+    <android.support.v4.widget.NestedScrollView android:layout_width="match_parent"
+                                                android:layout_height="match_parent">
+
+        <LinearLayout android:layout_width="match_parent"
+                      android:layout_height="match_parent"
+                      android:orientation="vertical">
+
+            <Button android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:paddingLeft="24dp"
+                    android:paddingTop="24dp"
+                    android:paddingRight="24dp"
+                    android:paddingBottom="12dp"
+                    android:id="@+id/add_new_folder"
+                    android:drawableLeft="@drawable/tab_new"
+                    android:drawableStart="@drawable/tab_new"
+                    android:drawablePadding="8dp"
+                    android:textAllCaps="false"
+                    android:text="@string/bookmark_dialog_new_folder"
+                    android:gravity="start|center_vertical"
+                    style="?android:attr/borderlessButtonStyle"/>
+
+            <include layout="@layout/folder_tree_view"
+                     android:layout_height="wrap_content"
+                     android:layout_width="match_parent"/>
+
+        </LinearLayout>
+
+    </android.support.v4.widget.NestedScrollView>
+
+</LinearLayout>
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -99,16 +99,18 @@
   <string name="bookmark_options">&bookmark_options;</string>
   <string name="bookmarks_selected_folder">&bookmarks_selected_folder;</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_dialog_save_and_return">&bookmark_dialog_save_and_return;</string>
   <string name="bookmark_dialog_folder">&bookmark_dialog_folder;</string>
+  <string name="bookmark_dialog_choose_folder">&bookmark_dialog_choose_folder;</string>
+  <string name="bookmark_dialog_new_folder">&bookmark_dialog_new_folder;</string>
 
   <string name="bookmark_edit_title">&bookmark_edit_title;</string>
   <string name="bookmark_edit_name">&bookmark_edit_name;</string>
   <string name="bookmark_edit_location">&bookmark_edit_location;</string>
   <string name="bookmark_edit_keyword">&bookmark_edit_keyword;</string>
   <string name="bookmark_edit_location_empty_error">&bookmark_edit_location_empty_error;</string>
 
   <string name="bookmark_folder_items">&bookmark_folder_items;</string>