summaryrefslogtreecommitdiffstats
path: root/mobile/android/base/java/org/mozilla/gecko/EditBookmarkDialog.java
blob: 38c38a9eba9cbababb1943359a8415160fe5011d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/* -*- 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 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.app.AlertDialog;
import android.content.DialogInterface;
import android.database.Cursor;
import android.support.design.widget.Snackbar;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;

/**
 * A dialog that allows editing a bookmarks url, title, or keywords
 * <p>
 * Invoked by calling one of the {@link org.mozilla.gecko.EditBookmarkDialog#show(String)}
 * methods.
 */
public class EditBookmarkDialog {
    private final Context mContext;

    public EditBookmarkDialog(Context context) {
        mContext = context;
    }

    /**
     * A private struct to make it easier to pass bookmark data across threads
     */
    private class Bookmark {
        final int id;
        final String title;
        final String url;
        final String keyword;

        public Bookmark(int aId, String aTitle, String aUrl, String aKeyword) {
            id = aId;
            title = aTitle;
            url = aUrl;
            keyword = aKeyword;
        }
    }

    /**
     * This text watcher to enable or disable the OK button if the dialog contains
     * valid information. This class is overridden to do data checking on different fields.
     * By itself, it always enables the button.
     *
     * Callers can also assign a paired partner to the TextWatcher, and callers will check
     * that both are enabled before enabling the ok button.
     */
    private class EditBookmarkTextWatcher implements TextWatcher {
        // A stored reference to the dialog containing the text field being watched
        protected AlertDialog mDialog;

        // A stored text watcher to do the real verification of a field
        protected EditBookmarkTextWatcher mPairedTextWatcher;

        // Whether or not the ok button should be enabled.
        protected boolean mEnabled = true;

        public EditBookmarkTextWatcher(AlertDialog aDialog) {
            mDialog = aDialog;
        }

        public void setPairedTextWatcher(EditBookmarkTextWatcher aTextWatcher) {
            mPairedTextWatcher = aTextWatcher;
        }

        public boolean isEnabled() {
            return mEnabled;
        }

        // Textwatcher interface
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // Disable if the we're disabled or the paired partner is disabled
            boolean enabled = mEnabled && (mPairedTextWatcher == null || mPairedTextWatcher.isEnabled());
            mDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(enabled);
        }

        @Override
        public void afterTextChanged(Editable s) {}
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
    }

    /**
     * A version of the EditBookmarkTextWatcher for the url field of the dialog.
     * Only checks if the field is empty or not.
     */
    private class LocationTextWatcher extends EditBookmarkTextWatcher {
        public LocationTextWatcher(AlertDialog aDialog) {
            super(aDialog);
        }

        // Disables the ok button if the location field is empty.
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            mEnabled = (s.toString().trim().length() > 0);
            super.onTextChanged(s, start, before, count);
        }
    }

    /**
     * A version of the EditBookmarkTextWatcher for the keyword field of the dialog.
     * Checks if the field has any (non leading or trailing) spaces.
     */
    private class KeywordTextWatcher extends EditBookmarkTextWatcher {
        public KeywordTextWatcher(AlertDialog aDialog) {
            super(aDialog);
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // Disable if the keyword contains spaces
            mEnabled = (s.toString().trim().indexOf(' ') == -1);
            super.onTextChanged(s, start, before, count);
       }
    }

    /**
     * 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.
     */
    public void show(final String url) {
        final ContentResolver cr = mContext.getContentResolver();
        final BrowserDB db = BrowserDB.from(mContext);
        (new UIAsyncTask.WithoutParams<Bookmark>(ThreadUtils.getBackgroundHandler()) {
            @Override
            public Bookmark doInBackground() {
                final Cursor cursor = db.getBookmarkForUrl(cr, url);
                if (cursor == null) {
                    return null;
                }

                Bookmark bookmark = null;
                try {
                    cursor.moveToFirst();
                    bookmark = new Bookmark(cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks._ID)),
                                                          cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.TITLE)),
                                                          cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.URL)),
                                                          cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.KEYWORD)));
                } finally {
                    cursor.close();
                }
                return bookmark;
            }

            @Override
            public void onPostExecute(Bookmark bookmark) {
                if (bookmark == null) {
                    return;
                }

                show(bookmark.id, bookmark.title, bookmark.url, bookmark.keyword);
            }
        }).execute();
    }

    /**
     * Show the Edit bookmark dialog for a set of data. This will show the dialog whether
     * a bookmark with this url exists or not, but the results will NOT be saved if the id
     * is not a valid bookmark id.
     *
     * @param id The id of the bookmark to change. If there is no bookmark with this ID, the dialog
     *           will fail silently.
     * @param title The initial title to show in the dialog
     * @param url The initial url to show in the dialog
     * @param keyword The initial keyword to show in the dialog
     */
    public void show(final int id, final String title, final String url, final String keyword) {
        final Context context = mContext;

        AlertDialog.Builder editPrompt = new AlertDialog.Builder(context);
        final View editView = LayoutInflater.from(context).inflate(R.layout.bookmark_edit, null);
        editPrompt.setTitle(R.string.bookmark_edit_title);
        editPrompt.setView(editView);

        final EditText nameText = ((EditText) editView.findViewById(R.id.edit_bookmark_name));
        final EditText locationText = ((EditText) editView.findViewById(R.id.edit_bookmark_location));
        final EditText keywordText = ((EditText) editView.findViewById(R.id.edit_bookmark_keyword));
        nameText.setText(title);
        locationText.setText(url);
        keywordText.setText(keyword);

        final BrowserDB db = BrowserDB.from(mContext);
        editPrompt.setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int whichButton) {
                (new UIAsyncTask.WithoutParams<Void>(ThreadUtils.getBackgroundHandler()) {
                    @Override
                    public Void doInBackground() {
                        String newUrl = locationText.getText().toString().trim();
                        String newKeyword = keywordText.getText().toString().trim();

                        db.updateBookmark(context.getContentResolver(), id, newUrl, nameText.getText().toString(), newKeyword);
                        return null;
                    }

                    @Override
                    public void onPostExecute(Void result) {
                        SnackbarBuilder.builder((Activity) context)
                                .message(R.string.bookmark_updated)
                                .duration(Snackbar.LENGTH_LONG)
                                .buildAndShow();
                    }
                }).execute();
            }
        });

        editPrompt.setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int whichButton) {
                  // do nothing
              }
        });

        final AlertDialog dialog = editPrompt.create();

        // Create our TextWatchers
        LocationTextWatcher locationTextWatcher = new LocationTextWatcher(dialog);
        KeywordTextWatcher keywordTextWatcher = new KeywordTextWatcher(dialog);

        // Cross reference the TextWatchers
        locationTextWatcher.setPairedTextWatcher(keywordTextWatcher);
        keywordTextWatcher.setPairedTextWatcher(locationTextWatcher);

        // Add the TextWatcher Listeners
        locationText.addTextChangedListener(locationTextWatcher);
        keywordText.addTextChangedListener(keywordTextWatcher);

        dialog.show();
    }
}