Merge pull request #15 from leanote/feature/edit-notebook-title

Feature/edit notebook title
This commit is contained in:
xxx
2017-03-01 08:57:10 -06:00
committed by GitHub
10 changed files with 357 additions and 16 deletions

View File

@@ -104,4 +104,6 @@ dependencies {
compile 'com.elvishew:xlog:1.3.0'
compile 'com.github.piasy:BigImageViewer:1.2.5'
compile 'com.github.piasy:GlideImageLoader:1.2.5'
compile 'com.weiwangcn.betterspinner:library-material:1.1.0'
}

View File

@@ -14,6 +14,7 @@ import org.houxg.leamonax.database.AppDataBase;
import org.houxg.leamonax.model.Notebook;
import org.houxg.leamonax.service.AccountService;
import org.houxg.leamonax.utils.CollectionUtils;
import org.houxg.leamonax.utils.ToastUtils;
import java.util.ArrayList;
import java.util.List;
@@ -100,7 +101,7 @@ public class NotebookAdapter extends RecyclerView.Adapter<NotebookAdapter.Notebo
@Override
public void onClick(View v) {
if (mListener != null) {
mListener.onClickedAddNotebook(getCurrentParentId());
mListener.onClickedAddNotebook(getCurrentParentId(), mData);
}
}
});
@@ -113,14 +114,16 @@ public class NotebookAdapter extends RecyclerView.Adapter<NotebookAdapter.Notebo
String notebookId = notebook.getNotebookId();
boolean isSuper = isSuper(notebookId);
boolean isSuperOrRoot = isSuper | mStack.isEmpty();
boolean hasChild = hasChild(notebookId);
final boolean hasChild = hasChild(notebookId);
holder.placeholder.setVisibility(isSuperOrRoot ? View.GONE : View.VISIBLE);
holder.navigator.setVisibility(mCanOpenEmpty | hasChild ? View.VISIBLE : View.INVISIBLE);
holder.navigator.setImageResource(isSuper ? R.drawable.ic_expanding : R.drawable.ic_expandable);
holder.navigator.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//TODO: arrow animation
if (!hasChild) {
return;
}
if (isSuper(notebook.getNotebookId())) {
listUpper();
} else {
@@ -132,11 +135,19 @@ public class NotebookAdapter extends RecyclerView.Adapter<NotebookAdapter.Notebo
@Override
public void onClick(View v) {
if (mListener != null) {
listChild(notebook);
mListener.onClickedNotebook(notebook);
}
}
});
holder.titleTv.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mListener != null) {
mListener.onEditNotebook(notebook);
}
return true;
}
});
}
private boolean isSuper(String notebookId) {
@@ -196,7 +207,9 @@ public class NotebookAdapter extends RecyclerView.Adapter<NotebookAdapter.Notebo
public interface NotebookAdapterListener {
void onClickedNotebook(Notebook notebook);
void onClickedAddNotebook(String parentNotebookId);
void onClickedAddNotebook(String parentNotebookId, List<Notebook> notebooks);
void onEditNotebook(Notebook notebook);
}
static class NotebookHolder extends RecyclerView.ViewHolder {

View File

@@ -19,4 +19,9 @@ public interface NotebookApi {
@POST("notebook/addNotebook")
Call<Notebook> addNotebook(@Query("title") String title, @Query("parentNotebookId") String parentId);
@POST("notebook/updateNotebook")
Call<Notebook> updateNotebook(@Query("notebookId") String notebookId, @Query("title") String title,
@Query("parentNotebookId") String parentId, @Query("seq") int seq, @Query("usn") int usn);
}

View File

@@ -36,4 +36,24 @@ public class NotebookService {
Notebook notebook = AppDataBase.getNotebookByLocalId(notebookLocalId);
return notebook != null ? notebook.getTitle() : "";
}
public static Notebook updateNotebook(String title, Notebook notebook) {
Notebook newNotebook = RetrofitUtils.excute(ApiProvider.getInstance().getNotebookApi().
updateNotebook(notebook.getNotebookId(), title, notebook.getParentNotebookId(), notebook.getSeq(), notebook.getUsn()));
if (newNotebook == null) {
throw new IllegalStateException("Network error");
}
if (newNotebook.isOk()) {
Account account = AccountService.getCurrent();
if (notebook.getUsn() - account.getNotebookUsn() == 1) {
account.setNotebookUsn(notebook.getUsn());
account.save();
}
newNotebook.setId(notebook.getId());
newNotebook.update();
return notebook;
} else {
throw new IllegalStateException(notebook.getMsg());
}
}
}

View File

@@ -6,18 +6,13 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.os.Build;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewGroupCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.graphics.drawable.DrawableWrapper;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -27,9 +22,8 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.elvishew.xlog.XLog;
import com.tencent.bugly.Bugly;
import com.tencent.bugly.crashreport.CrashReport;
import com.weiwangcn.betterspinner.library.material.MaterialBetterSpinner;
import org.houxg.leamonax.R;
import org.houxg.leamonax.adapter.AccountAdapter;
@@ -41,10 +35,17 @@ import org.houxg.leamonax.model.Tag;
import org.houxg.leamonax.model.User;
import org.houxg.leamonax.service.AccountService;
import org.houxg.leamonax.service.NotebookService;
import org.houxg.leamonax.utils.CollectionUtils;
import org.houxg.leamonax.utils.DisplayUtils;
import org.houxg.leamonax.utils.OpenUtils;
import org.houxg.leamonax.utils.ToastUtils;
import org.houxg.leamonax.widget.AlphabetDrawable;
import org.houxg.leamonax.widget.TriangleView;
import org.houxg.leamonax.widget.spinner.SpinnerArrayAdapter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
@@ -297,9 +298,24 @@ public class Navigation {
}
@Override
public void onClickedAddNotebook(final String parentNotebookId) {
View view = LayoutInflater.from(mActivity).inflate(R.layout.dialog_sigle_edittext, null);
public void onClickedAddNotebook(final String parentNotebookId, List<Notebook> notebooks) {
View view = LayoutInflater.from(mActivity).inflate(R.layout.dialog_add_notebook, null);
final EditText mEdit = (EditText) view.findViewById(R.id.edit);
final MaterialBetterSpinner spinner = (MaterialBetterSpinner) view.findViewById(R.id.spinner);
final List<Notebook> tempNotebooks = new ArrayList<>();
tempNotebooks.clear();
tempNotebooks.addAll(notebooks);
Notebook rootNoteBook = new Notebook();
rootNoteBook.setTitle(mActivity.getString(R.string.notebook_default_root_notebook_title));
tempNotebooks.add(0, rootNoteBook);
SpinnerArrayAdapter<Notebook> adapter = new SpinnerArrayAdapter<Notebook>(view.getContext(), tempNotebooks) {
@Override
public String itemToString(Notebook item) {
return item.getTitle();
}
};
spinner.setAdapter(adapter);
spinner.setText(rootNoteBook.getTitle());
new AlertDialog.Builder(mActivity)
.setTitle(R.string.add_notebook)
.setView(view)
@@ -307,7 +323,35 @@ public class Navigation {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
addNotebook(mEdit.getText().toString(), parentNotebookId);
addNotebook(mEdit.getText().toString(), getNotebookId(tempNotebooks, spinner.getText().toString()));
}
})
.show();
}
private String getNotebookId(List<Notebook> notebooks, String title) {
for (Notebook notebook : notebooks) {
if (TextUtils.equals(notebook.getTitle(), title)) {
return notebook.getNotebookId();
}
}
return "";
}
@Override
public void onEditNotebook(final Notebook notebook) {
View view = LayoutInflater.from(mActivity).inflate(R.layout.dialog_sigle_edittext, null);
final EditText mEdit = (EditText) view.findViewById(R.id.edit);
mEdit.setText(notebook.getTitle());
mEdit.setSelection(notebook.getTitle().length());
new AlertDialog.Builder(mActivity)
.setTitle(R.string.update_notebook_title)
.setView(view)
.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
updateNotebook(mEdit.getText().toString(), notebook);
}
})
.show();
@@ -323,7 +367,47 @@ public class Navigation {
});
}
private void updateNotebook(final String title, final Notebook notebook) {
if (TextUtils.isEmpty(title)) {
ToastUtils.show(mActivity, R.string.toast_notebook_title_not_empty);
return;
}
Observable.create(
new Observable.OnSubscribe<Notebook>() {
@Override
public void call(Subscriber<? super Notebook> subscriber) {
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(NotebookService.updateNotebook(title, notebook));
subscriber.onCompleted();
}
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Notebook>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@Override
public void onNext(Notebook isSucceed) {
mNotebookAdapter.refresh();
}
});
}
private void addNotebook(final String title, final String parentNotebookId) {
if (TextUtils.isEmpty(title)) {
ToastUtils.show(mActivity, R.string.toast_notebook_title_not_empty);
return;
}
Observable.create(
new Observable.OnSubscribe<Notebook>() {
@Override

View File

@@ -15,6 +15,8 @@ import org.houxg.leamonax.R;
import org.houxg.leamonax.adapter.NotebookAdapter;
import org.houxg.leamonax.model.Notebook;
import java.util.List;
public class DialogUtils {
public static void editLink(Context context, String title, String link, @NonNull final ChangedListener listener) {
@@ -72,7 +74,12 @@ public class DialogUtils {
}
@Override
public void onClickedAddNotebook(String parentNotebookId) {
public void onClickedAddNotebook(String parentNotebookId, List<Notebook> notebooks) {
}
@Override
public void onEditNotebook(Notebook notebook) {
}
});

View File

@@ -0,0 +1,181 @@
package org.houxg.leamonax.widget.spinner;
import android.content.Context;
import android.os.Build;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class SpinnerArrayAdapter<T> extends ArrayAdapter<SpinnerArrayAdapter<T>.ItemProxy> {
private NoFilter noFilter;
public SpinnerArrayAdapter(Context context) {
this(context, new ArrayList<T>());
}
public SpinnerArrayAdapter(Context context, List<T> objects) {
super(context, android.R.layout.simple_spinner_dropdown_item);
setNotifyOnChange(false);
addAll(objects);
notifyDataSetChanged();
}
public SpinnerArrayAdapter(Context context, T[] objects) {
this(context, Arrays.asList(objects));
}
/**
* <p>For default, the ArrayAdapter uses <code>toString()</code> for item view, in somes cases when uses a framework like Realm Database, is not possible to overrides the <code>toString()</code> in model classes.
* Then, the proxy solutions has implemented.
* <p>This method encapsulates the original object into a proxy.</p>
*
* @param objects
* @return
*/
private List<ItemProxy> wrapItems(List<T> objects) {
List<ItemProxy> proxies = new ArrayList<>(objects.size());
for (T item : objects) {
ItemProxy proxy = new ItemProxy(item);
proxies.add(proxy);
}
return proxies;
}
/**
* <p>Converts the item to <code>String</code>.</p>
* <p>Overrides this method for cutomize the text view.</p>
*
* @param item
* @return
*/
public String itemToString(T item) {
return item.toString();
}
/**
* <p>Converts a <code>String</code> in object.</p>
* <p>This method can be used to get selected item.</p>
* <p>Example:</p>
* <code>
* <pre>
*
* MaterialBetterSpinner spPeople;
* SpinnerArrayAdapter<People> adapterPeople;
* ....
* People pSelected = adapterPeople.stringToItem(spPeople.getText())
*
* </pre>
* </code>
*
* @param toString Selected text.
* @return Object converted from selected text.
*/
public T stringToItem(String toString) {
for (int i = 0; i < getCount(); i++) {
T item = getItem(i).object;
if (itemToString(item).equals(toString)) {
return item;
}
}
return null;
}
/**
* <p>Converts a <code>String</code> in object.</p>
* <p>This method can be used to get selected item.</p>
* <p>Example:</p>
* <code>
* <pre>
*
* MaterialBetterSpinner spPeople;
* SpinnerArrayAdapter<People> adapterPeople;
* ....
* People pSelected = adapterPeople.stringToItem(spPeople.getText())
*
* </pre>
* </code>
*
* @param toString Selected text.
* @return Object converted from selected text.
*/
public T stringToItem(CharSequence toString) {
return stringToItem(toString.toString());
}
public void addAll(List<T> objects) {
clear();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
addAll(wrapItems(objects));
} else {
for (ItemProxy p : wrapItems(objects)) {
add(p);
}
}
}
/**
* Proxy for generic SpinnerArrayAdapter.
*/
public class ItemProxy {
public final T object;
protected ItemProxy(T object) {
this.object = object;
}
@Override
public String toString() {
return itemToString(object);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof SpinnerArrayAdapter.ItemProxy)) return false;
ItemProxy itemProxy = (ItemProxy) o;
return !(object != null ? !object.equals(itemProxy.object) : itemProxy.object != null);
}
@Override
public int hashCode() {
return object != null ? object.hashCode() : 0;
}
}
/**
* Override ArrayAdapter.getFilter() to return our own filtering.
*/
@Override
public Filter getFilter() {
if (noFilter == null) {
noFilter = new NoFilter();
}
return noFilter;
}
/**
* Class which does not perform any filtering.
* Filtering is already done by the web service when asking for the list,
* so there is no need to do any more as well.
* This way, ArrayAdapter.mOriginalValues is not used when calling e.g.
* ArrayAdapter.add(), but instead ArrayAdapter.mObjects is updated directly
* and methods like getCount() return the expected result.
*/
private class NoFilter extends Filter {
protected FilterResults performFiltering(CharSequence prefix) {
return new FilterResults();
}
protected void publishResults(CharSequence constraint,
FilterResults results) {
// Do nothing
}
}
}

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<com.weiwangcn.betterspinner.library.material.MaterialBetterSpinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/activity_vertical_margin"
android:hint="@string/notebook_choose_notebook_hint" />
<EditText
android:id="@+id/edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp" />
</LinearLayout>

View File

@@ -108,4 +108,8 @@
<string name="host_example">登录接口地址将会是:\n%s/api/login</string>
<string name="my_blog">我的博客</string>
<string name="explore">蚂蚁笔记探索</string>
<string name="toast_notebook_title_not_empty">笔记本的名称不能为空</string>
<string name="update_notebook_title">修改笔记本的名称</string>
<string name="notebook_choose_notebook_hint">选择该笔记本所在的上一级笔记本目录</string>
<string name="notebook_default_root_notebook_title">空目录(最顶层目录)</string>
</resources>

View File

@@ -110,4 +110,8 @@
<string name="host_example">For example, login api will be:\n%s/api/login</string>
<string name="my_blog">My Blog</string>
<string name="explore">Leanote Explore</string>
<string name="toast_notebook_title_not_empty">the notebook title can\'t empty</string>
<string name="update_notebook_title">Update notebook title</string>
<string name="notebook_choose_notebook_hint">选择该笔记本所在的上一级笔记本目录 Choose current Notebook \'s parentNotebook directory</string>
<string name="notebook_default_root_notebook_title">Empty directory</string>
</resources>