Repository: daimajia/Notes Branch: master Commit: 0b743136b208 Files: 157 Total size: 501.5 KB Directory structure: gitextract_lccwb36e/ ├── .gitignore ├── .idea/ │ ├── .name │ ├── compiler.xml │ ├── copyright/ │ │ └── profiles_settings.xml │ ├── encodings.xml │ ├── gradle.xml │ ├── misc.xml │ ├── modules.xml │ └── vcs.xml ├── MaterialPreference/ │ ├── MaterialPreference.iml │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── java/ │ │ └── com/ │ │ └── jenzz/ │ │ └── materialpreference/ │ │ ├── CheckBoxPreference.java │ │ ├── Preference.java │ │ ├── PreferenceCategory.java │ │ ├── PreferenceImageView.java │ │ ├── SwitchPreference.java │ │ ├── ThemeUtils.java │ │ ├── TwoStatePreference.java │ │ └── Typefaces.java │ └── res/ │ ├── layout/ │ │ ├── mp_checkbox_preference.xml │ │ ├── mp_preference.xml │ │ ├── mp_preference_category.xml │ │ └── mp_switch_preference.xml │ └── values/ │ └── mp_attrs.xml ├── Notes.iml ├── README.md ├── app/ │ ├── .gitignore │ ├── app.iml │ ├── build.gradle │ ├── libs/ │ │ ├── BmobSDK_V3.3.8_0521.jar │ │ ├── fastjson.jar │ │ └── libammsdk.jar │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── lguipeng/ │ │ └── notes/ │ │ └── ApplicationTest.java │ └── main/ │ ├── AndroidManifest.xml │ ├── java/ │ │ └── com/ │ │ └── lguipeng/ │ │ └── notes/ │ │ ├── App.java │ │ ├── adpater/ │ │ │ ├── BaseListAdapter.java │ │ │ ├── BaseRecyclerViewAdapter.java │ │ │ ├── ColorsListAdapter.java │ │ │ ├── DrawerListAdapter.java │ │ │ ├── MaterialSimpleListAdapter.java │ │ │ ├── NotesAdapter.java │ │ │ ├── NotesItemViewHolder.java │ │ │ └── SimpleListAdapter.java │ │ ├── listener/ │ │ │ ├── bmob/ │ │ │ │ ├── FindListenerImpl.java │ │ │ │ ├── SaveListenerImpl.java │ │ │ │ └── UpdateListenerImpl.java │ │ │ └── view/ │ │ │ └── RecyclerViewClickListener.java │ │ ├── model/ │ │ │ ├── CloudNote.java │ │ │ ├── MaterialSimpleListItem.java │ │ │ ├── Note.java │ │ │ ├── NoteOperateLog.java │ │ │ └── NoteType.java │ │ ├── module/ │ │ │ ├── AppModule.java │ │ │ └── DataModule.java │ │ ├── ui/ │ │ │ ├── AboutActivity.java │ │ │ ├── BaseActivity.java │ │ │ ├── EditNoteTypeActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── NoteActivity.java │ │ │ ├── PayActivity.java │ │ │ ├── SettingActivity.java │ │ │ └── fragments/ │ │ │ ├── BaseFragment.java │ │ │ └── SettingFragment.java │ │ ├── utils/ │ │ │ ├── AccountUtils.java │ │ │ ├── JsonUtils.java │ │ │ ├── NoteConfig.java │ │ │ ├── NotesLog.java │ │ │ ├── PreferenceUtils.java │ │ │ ├── SnackbarUtils.java │ │ │ ├── ThemeUtils.java │ │ │ ├── TimeUtils.java │ │ │ ├── ViewHelper.java │ │ │ └── WXUtils.java │ │ └── view/ │ │ └── FixedRecyclerView.java │ └── res/ │ ├── drawable/ │ │ ├── activated_background.xml │ │ ├── blue_grey_round.xml │ │ ├── blue_round.xml │ │ ├── brown_round.xml │ │ ├── deep_purple_round.xml │ │ ├── green_round.xml │ │ ├── pink_round.xml │ │ ├── red_round.xml │ │ ├── selectable_background.xml │ │ ├── toolbar_shadow.xml │ │ ├── white_button_background.xml │ │ └── yellow_round.xml │ ├── layout/ │ │ ├── activity_about.xml │ │ ├── activity_edit_note_type.xml │ │ ├── activity_main.xml │ │ ├── activity_note.xml │ │ ├── activity_pay.xml │ │ ├── activity_setting.xml │ │ ├── colors_image_layout.xml │ │ ├── colors_panel_layout.xml │ │ ├── drawer_list_item_layout.xml │ │ ├── edit_layout.xml │ │ ├── md_simplelist_item.xml │ │ ├── notes_item_layout.xml │ │ ├── toolbar_layout.xml │ │ └── toolbar_shadow_layout.xml │ ├── menu/ │ │ ├── menu_about.xml │ │ ├── menu_main.xml │ │ ├── menu_note.xml │ │ └── menu_notes_more.xml │ ├── values/ │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── xml/ │ ├── prefs.xml │ └── searchable.xml ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── orm-library/ │ ├── .gitignore │ ├── build.gradle │ ├── orm-library.iml │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── lguipeng/ │ │ └── library/ │ │ └── ApplicationTest.java │ └── main/ │ ├── AndroidManifest.xml │ ├── java/ │ │ └── net/ │ │ └── tsz/ │ │ └── afinal/ │ │ ├── FinalDb.java │ │ ├── annotation/ │ │ │ └── sqlite/ │ │ │ ├── Id.java │ │ │ ├── ManyToOne.java │ │ │ ├── OneToMany.java │ │ │ ├── Property.java │ │ │ ├── Table.java │ │ │ └── Transient.java │ │ ├── core/ │ │ │ ├── AbstractCollection.java │ │ │ ├── ArrayDeque.java │ │ │ ├── Arrays.java │ │ │ ├── AsyncTask.java │ │ │ ├── Deque.java │ │ │ ├── FileNameGenerator.java │ │ │ └── Queue.java │ │ ├── db/ │ │ │ ├── sqlite/ │ │ │ │ ├── CursorUtils.java │ │ │ │ ├── DbModel.java │ │ │ │ ├── ManyToOneLazyLoader.java │ │ │ │ ├── OneToManyLazyLoader.java │ │ │ │ ├── SqlBuilder.java │ │ │ │ └── SqlInfo.java │ │ │ └── table/ │ │ │ ├── Id.java │ │ │ ├── KeyValue.java │ │ │ ├── ManyToOne.java │ │ │ ├── OneToMany.java │ │ │ ├── Property.java │ │ │ └── TableInfo.java │ │ ├── exception/ │ │ │ ├── AfinalException.java │ │ │ └── DbException.java │ │ └── utils/ │ │ ├── ClassUtils.java │ │ ├── FieldUtils.java │ │ └── Utils.java │ └── res/ │ └── values/ │ └── strings.xml └── settings.gradle ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .gradle /local.properties /.idea/workspace.xml /.idea/libraries .DS_Store /build /captures ================================================ FILE: .idea/.name ================================================ Notes ================================================ FILE: .idea/compiler.xml ================================================ ================================================ FILE: .idea/copyright/profiles_settings.xml ================================================ ================================================ FILE: .idea/encodings.xml ================================================ ================================================ FILE: .idea/gradle.xml ================================================ ================================================ FILE: .idea/misc.xml ================================================ 1.7 ================================================ FILE: .idea/modules.xml ================================================ ================================================ FILE: .idea/vcs.xml ================================================ ================================================ FILE: MaterialPreference/MaterialPreference.iml ================================================ ================================================ FILE: MaterialPreference/build.gradle ================================================ apply plugin: 'com.android.library' android { compileSdkVersion Integer.parseInt(ANDROID_BUILD_COMPILE_SDK_VERSION) buildToolsVersion ANDROID_BUILD_TOOLS_VERSION defaultConfig { minSdkVersion Integer.parseInt(MIN_SDK_VERSION) targetSdkVersion Integer.parseInt(ANDROID_BUILD_TARGET_SDK_VERSION) versionCode Integer.parseInt(VERSION_CODE) versionName VERSION_NAME } lintOptions { abortOnError false } } dependencies { compile 'com.android.support:appcompat-v7:22.2.0' compile 'com.balysv:material-ripple:1.0.2' } ================================================ FILE: MaterialPreference/src/main/AndroidManifest.xml ================================================ ================================================ FILE: MaterialPreference/src/main/java/com/jenzz/materialpreference/CheckBoxPreference.java ================================================ package com.jenzz.materialpreference; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.View; import android.widget.CheckBox; import static com.jenzz.materialpreference.ThemeUtils.isAtLeastL; public class CheckBoxPreference extends TwoStatePreference { public CheckBoxPreference(Context context) { super(context); init(context, null, 0, 0); } public CheckBoxPreference(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs, 0, 0); } public CheckBoxPreference(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs, defStyleAttr, 0); } public CheckBoxPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(context, attrs, defStyleAttr, defStyleRes); } private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { TypedArray typedArray = context.obtainStyledAttributes(attrs, new int[] { android.R.attr.summaryOn, android.R.attr.summaryOff, android.R.attr.disableDependentsState }, defStyleAttr, defStyleRes); setSummaryOn(typedArray.getString(0)); setSummaryOff(typedArray.getString(1)); setDisableDependentsState(typedArray.getBoolean(2, false)); typedArray.recycle(); setWidgetLayoutResource(R.layout.mp_checkbox_preference); } @Override @SuppressWarnings("deprecation") protected void onBindView(View view) { super.onBindView(view); CheckBox checkboxView = (CheckBox) view.findViewById(R.id.checkbox); checkboxView.setChecked(isChecked()); if (isAtLeastL()) { // remove circular background when pressed checkboxView.setBackgroundDrawable(null); } syncSummaryView(view); } } ================================================ FILE: MaterialPreference/src/main/java/com/jenzz/materialpreference/Preference.java ================================================ package com.jenzz.materialpreference; import android.annotation.TargetApi; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import static android.content.Context.LAYOUT_INFLATER_SERVICE; import static android.os.Build.VERSION_CODES.LOLLIPOP; import static android.text.TextUtils.isEmpty; import static android.view.View.GONE; import static android.view.View.VISIBLE; import static com.jenzz.materialpreference.Typefaces.getRobotoRegular; public class Preference extends android.preference.Preference { TextView titleView; TextView summaryView; ImageView imageView; View imageFrame; private int iconResId; private Drawable icon; public Preference(Context context) { super(context); init(context, null, 0, 0); } public Preference(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs, 0, 0); } public Preference(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs, defStyleAttr, 0); } @TargetApi(LOLLIPOP) public Preference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(context, attrs, defStyleAttr, defStyleRes); } private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { TypedArray typedArray = context.obtainStyledAttributes(attrs, new int[] { android.R.attr.icon }, defStyleAttr, defStyleRes); iconResId = typedArray.getResourceId(0, 0); typedArray.recycle(); } @Override protected View onCreateView(ViewGroup parent) { LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService(LAYOUT_INFLATER_SERVICE); View layout = layoutInflater.inflate(R.layout.mp_preference, parent, false); ViewGroup widgetFrame = (ViewGroup) layout.findViewById(R.id.widget_frame); int widgetLayoutResId = getWidgetLayoutResource(); if (widgetLayoutResId != 0) { layoutInflater.inflate(widgetLayoutResId, widgetFrame); } widgetFrame.setVisibility(widgetLayoutResId != 0 ? VISIBLE : GONE); return layout; } @Override protected void onBindView(View view) { super.onBindView(view); CharSequence title = getTitle(); titleView = (TextView) view.findViewById(R.id.title); titleView.setText(title); titleView.setVisibility(!isEmpty(title) ? VISIBLE : GONE); titleView.setTypeface(getRobotoRegular(getContext())); CharSequence summary = getSummary(); summaryView = (TextView) view.findViewById(R.id.summary); summaryView.setText(summary); summaryView.setVisibility(!isEmpty(summary) ? VISIBLE : GONE); summaryView.setTypeface(getRobotoRegular(getContext())); if (icon == null && iconResId > 0) { icon = getContext().getResources().getDrawable(iconResId); } imageView = (ImageView) view.findViewById(R.id.icon); imageView.setImageDrawable(icon); imageView.setVisibility(icon != null ? VISIBLE : GONE); imageFrame = view.findViewById(R.id.icon_frame); imageFrame.setVisibility(icon != null ? VISIBLE : GONE); } @Override public void setIcon(int iconResId) { super.setIcon(iconResId); this.iconResId = iconResId; } @Override public void setIcon(Drawable icon) { super.setIcon(icon); this.icon = icon; } } ================================================ FILE: MaterialPreference/src/main/java/com/jenzz/materialpreference/PreferenceCategory.java ================================================ package com.jenzz.materialpreference; import android.annotation.TargetApi; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import static android.content.Context.LAYOUT_INFLATER_SERVICE; import static android.os.Build.VERSION_CODES.LOLLIPOP; import static android.text.TextUtils.isEmpty; import static android.view.View.GONE; import static android.view.View.VISIBLE; import static com.jenzz.materialpreference.ThemeUtils.resolveAccentColor; import static com.jenzz.materialpreference.Typefaces.getRobotoMedium; public class PreferenceCategory extends android.preference.PreferenceCategory { private int accentColor; public PreferenceCategory(Context context) { super(context); init(); } public PreferenceCategory(Context context, AttributeSet attrs) { super(context, attrs); init(); } public PreferenceCategory(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } @TargetApi(LOLLIPOP) public PreferenceCategory(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(); } private void init() { accentColor = resolveAccentColor(getContext()); } @Override protected View onCreateView(ViewGroup parent) { LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService(LAYOUT_INFLATER_SERVICE); return layoutInflater.inflate(R.layout.mp_preference_category, parent, false); } @Override protected void onBindView(View view) { super.onBindView(view); CharSequence title = getTitle(); TextView titleView = (TextView) view.findViewById(R.id.title); titleView.setText(title); titleView.setTextColor(accentColor); titleView.setVisibility(!isEmpty(title) ? VISIBLE : GONE); titleView.setTypeface(getRobotoMedium(getContext())); } } ================================================ FILE: MaterialPreference/src/main/java/com/jenzz/materialpreference/PreferenceImageView.java ================================================ package com.jenzz.materialpreference; import android.annotation.TargetApi; import android.content.Context; import android.util.AttributeSet; import android.widget.ImageView; import static android.os.Build.VERSION_CODES.LOLLIPOP; import static android.view.View.MeasureSpec.AT_MOST; import static android.view.View.MeasureSpec.UNSPECIFIED; import static android.view.View.MeasureSpec.getMode; import static android.view.View.MeasureSpec.getSize; import static android.view.View.MeasureSpec.makeMeasureSpec; import static java.lang.Integer.MAX_VALUE; /** * Extension of ImageView that correctly applies maxWidth and maxHeight. */ public class PreferenceImageView extends ImageView { private int maxWidth = MAX_VALUE; private int maxHeight = MAX_VALUE; public PreferenceImageView(Context context) { super(context); } public PreferenceImageView(Context context, AttributeSet attrs) { super(context, attrs); } public PreferenceImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(LOLLIPOP) public PreferenceImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public void setMaxWidth(int maxWidth) { super.setMaxWidth(maxWidth); this.maxWidth = maxWidth; } @Override public void setMaxHeight(int maxHeight) { super.setMaxHeight(maxHeight); this.maxHeight = maxHeight; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = getMode(widthMeasureSpec); if (widthMode == AT_MOST || widthMode == UNSPECIFIED) { int widthSize = getSize(widthMeasureSpec); if (maxWidth != MAX_VALUE && (maxWidth < widthSize || widthMode == UNSPECIFIED)) { widthMeasureSpec = makeMeasureSpec(maxWidth, AT_MOST); } } int heightMode = getMode(heightMeasureSpec); if (heightMode == AT_MOST || heightMode == UNSPECIFIED) { int heightSize = getSize(heightMeasureSpec); if (maxHeight != MAX_VALUE && (maxHeight < heightSize || heightMode == UNSPECIFIED)) { heightMeasureSpec = makeMeasureSpec(maxHeight, AT_MOST); } } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } ================================================ FILE: MaterialPreference/src/main/java/com/jenzz/materialpreference/SwitchPreference.java ================================================ package com.jenzz.materialpreference; import android.content.Context; import android.content.res.TypedArray; import android.support.v7.widget.SwitchCompat; import android.util.AttributeSet; import android.view.View; public class SwitchPreference extends TwoStatePreference { public SwitchPreference(Context context) { super(context); init(context, null, 0, 0); } public SwitchPreference(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs, 0, 0); } public SwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs, defStyleAttr, 0); } public SwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(context, attrs, defStyleAttr, defStyleRes); } private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { TypedArray typedArray = context.obtainStyledAttributes(attrs, new int[] { android.R.attr.summaryOn, android.R.attr.summaryOff, android.R.attr.disableDependentsState }, defStyleAttr, defStyleRes); setSummaryOn(typedArray.getString(0)); setSummaryOff(typedArray.getString(1)); setDisableDependentsState(typedArray.getBoolean(2, false)); typedArray.recycle(); setWidgetLayoutResource(R.layout.mp_switch_preference); } @Override protected void onBindView(View view) { super.onBindView(view); SwitchCompat switchCompat = (SwitchCompat) view.findViewById(R.id.switch_compat); switchCompat.setChecked(isChecked()); syncSummaryView(view); } } ================================================ FILE: MaterialPreference/src/main/java/com/jenzz/materialpreference/ThemeUtils.java ================================================ package com.jenzz.materialpreference; import android.annotation.TargetApi; import android.content.Context; import android.content.res.Resources.Theme; import android.content.res.TypedArray; import static android.graphics.Color.parseColor; import static android.os.Build.VERSION.SDK_INT; import static android.os.Build.VERSION_CODES.LOLLIPOP; final class ThemeUtils { // material_deep_teal_500 static final int FALLBACK_COLOR = parseColor("#009688"); private ThemeUtils() { // no instances } static boolean isAtLeastL() { return SDK_INT >= LOLLIPOP; } @TargetApi(LOLLIPOP) static int resolveAccentColor(Context context) { Theme theme = context.getTheme(); // on Lollipop, grab system colorAccent attribute // pre-Lollipop, grab AppCompat colorAccent attribute // finally, check for custom mp_colorAccent attribute int attr = isAtLeastL() ? android.R.attr.colorAccent : R.attr.colorAccent; TypedArray typedArray = theme.obtainStyledAttributes(new int[] { attr, R.attr.mp_colorAccent }); int accentColor = typedArray.getColor(0, FALLBACK_COLOR); accentColor = typedArray.getColor(1, accentColor); typedArray.recycle(); return accentColor; } } ================================================ FILE: MaterialPreference/src/main/java/com/jenzz/materialpreference/TwoStatePreference.java ================================================ package com.jenzz.materialpreference; import android.content.Context; import android.content.SharedPreferences; import android.content.res.TypedArray; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; import android.view.View; import static android.text.TextUtils.isEmpty; public abstract class TwoStatePreference extends Preference { private CharSequence summaryOn; private CharSequence summaryOff; private boolean isChecked; private boolean isCheckedSet; private boolean disableDependentsState; public TwoStatePreference(Context context) { super(context); } public TwoStatePreference(Context context, AttributeSet attrs) { super(context, attrs); } public TwoStatePreference(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public TwoStatePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override protected void onClick() { super.onClick(); boolean newValue = !isChecked(); if (callChangeListener(newValue)) { setChecked(newValue); } } /** * Sets the checked state and saves it to the {@link SharedPreferences}. * * @param checked * The checked state. */ public void setChecked(boolean checked) { // Always persist/notify the first time; don't assume the field's default of false. boolean changed = isChecked != checked; if (changed || !isCheckedSet) { isChecked = checked; isCheckedSet = true; persistBoolean(checked); if (changed) { notifyDependencyChange(shouldDisableDependents()); notifyChanged(); } } } /** * Returns the checked state. * * @return The checked state. */ public boolean isChecked() { return isChecked; } @Override public boolean shouldDisableDependents() { boolean shouldDisable = disableDependentsState ? isChecked : !isChecked; return shouldDisable || super.shouldDisableDependents(); } /** * Sets the summary to be shown when checked. * * @param summary * The summary to be shown when checked. */ public void setSummaryOn(CharSequence summary) { summaryOn = summary; if (isChecked()) { notifyChanged(); } } /** * @param summaryResId * The summary as a resource. * * @see #setSummaryOn(CharSequence) */ public void setSummaryOn(int summaryResId) { setSummaryOn(getContext().getString(summaryResId)); } /** * Returns the summary to be shown when checked. * * @return The summary. */ public CharSequence getSummaryOn() { return summaryOn; } /** * Sets the summary to be shown when unchecked. * * @param summary * The summary to be shown when unchecked. */ public void setSummaryOff(CharSequence summary) { summaryOff = summary; if (!isChecked()) { notifyChanged(); } } /** * @param summaryResId * The summary as a resource. * * @see #setSummaryOff(CharSequence) */ public void setSummaryOff(int summaryResId) { setSummaryOff(getContext().getString(summaryResId)); } /** * Returns the summary to be shown when unchecked. * * @return The summary. */ public CharSequence getSummaryOff() { return summaryOff; } /** * Returns whether dependents are disabled when this preference is on ({@code true}) * or when this preference is off ({@code false}). * * @return Whether dependents are disabled when this preference is on ({@code true}) * or when this preference is off ({@code false}). */ public boolean getDisableDependentsState() { return disableDependentsState; } /** * Sets whether dependents are disabled when this preference is on ({@code true}) * or when this preference is off ({@code false}). * * @param disableDependentsState * The preference state that should disable dependents. */ public void setDisableDependentsState(boolean disableDependentsState) { this.disableDependentsState = disableDependentsState; } @Override protected Object onGetDefaultValue(TypedArray a, int index) { return a.getBoolean(index, false); } @Override protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { setChecked(restoreValue ? getPersistedBoolean(isChecked) : (Boolean) defaultValue); } /** * Sync a summary view contained within view's subhierarchy with the correct summary text. * * @param view * View where a summary should be located */ void syncSummaryView(View view) { // Sync the summary view boolean useDefaultSummary = true; if (isChecked && !isEmpty(summaryOn)) { summaryView.setText(summaryOn); useDefaultSummary = false; } else if (!isChecked && !isEmpty(summaryOff)) { summaryView.setText(summaryOff); useDefaultSummary = false; } if (useDefaultSummary) { CharSequence summary = getSummary(); if (!isEmpty(summary)) { summaryView.setText(summary); useDefaultSummary = false; } } int newVisibility = View.GONE; if (!useDefaultSummary) { // Someone has written to it newVisibility = View.VISIBLE; } if (newVisibility != summaryView.getVisibility()) { summaryView.setVisibility(newVisibility); } } @Override protected Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); if (isPersistent()) { // No need to save instance state since it's persistent return superState; } SavedState myState = new SavedState(superState); myState.checked = isChecked(); return myState; } @Override protected void onRestoreInstanceState(Parcelable state) { if (state == null || !state.getClass().equals(SavedState.class)) { // Didn't save state for us in onSaveInstanceState super.onRestoreInstanceState(state); return; } SavedState myState = (SavedState) state; super.onRestoreInstanceState(myState.getSuperState()); setChecked(myState.checked); } static class SavedState extends BaseSavedState { boolean checked; public SavedState(Parcel source) { super(source); checked = source.readInt() == 1; } @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); dest.writeInt(checked ? 1 : 0); } public SavedState(Parcelable superState) { super(superState); } public static final Creator CREATOR = new Creator() { public SavedState createFromParcel(Parcel in) { return new SavedState(in); } public SavedState[] newArray(int size) { return new SavedState[size]; } }; } } ================================================ FILE: MaterialPreference/src/main/java/com/jenzz/materialpreference/Typefaces.java ================================================ package com.jenzz.materialpreference; import android.content.Context; import android.graphics.Typeface; import android.util.Log; import java.util.Hashtable; final class Typefaces { private static final String TAG = Typefaces.class.getSimpleName(); private static final Hashtable cache = new Hashtable<>(); private Typefaces() { // no instances } static Typeface get(Context context, String assetPath) { synchronized (cache) { if (!cache.containsKey(assetPath)) { try { Typeface t = Typeface.createFromAsset(context.getAssets(), assetPath); cache.put(assetPath, t); } catch (Exception e) { Log.e(TAG, "Could not get typeface '" + assetPath + "' Error: " + e.getMessage()); return null; } } return cache.get(assetPath); } } static Typeface getRobotoRegular(Context context) { return get(context, "fonts/Roboto-Regular.ttf"); } static Typeface getRobotoMedium(Context context) { return get(context, "fonts/Roboto-Medium.ttf"); } } ================================================ FILE: MaterialPreference/src/main/res/layout/mp_checkbox_preference.xml ================================================ ================================================ FILE: MaterialPreference/src/main/res/layout/mp_preference.xml ================================================ ================================================ FILE: MaterialPreference/src/main/res/layout/mp_preference_category.xml ================================================ ================================================ FILE: MaterialPreference/src/main/res/layout/mp_switch_preference.xml ================================================ ================================================ FILE: MaterialPreference/src/main/res/values/mp_attrs.xml ================================================ ================================================ FILE: Notes.iml ================================================ ================================================ FILE: README.md ================================================ #ScreenShot #1.1.2 - 增加了多款彩色主题的选择 - 增加了关于界面的分享功能 - 修复了笔记过长的显示问题 - 修复了SwipeRefreshLayout和RecyclerView的组合问题 - 优化界面的一些细节,修复已知的小bug #1.1.0 - 增加了笔记列表的卡片式的布局,可在设置里面切换 - 增加了下拉同步笔记的组件 - 增加编辑笔记时点击返回询问是否保存 - 使用了Snackbar代替了Toast的提示 - 去除了编辑笔记内容的下划线 - 修改了笔记列表的显示时间方式 - 修复了小米2s 5.0上CardView的显示问题 #1.0.2 - Material Design风格,采用抽屉式菜单,悬浮滑动按钮,点击控件时的水波纹效果,状态栏透明使得与应用融为一体,用户即使在Android L系统以下的手机也能感受到良好的用户体验 - 用文字记录身边随时发生的事情,或者你的待办事项 - 同步,同步需要你在手机设置里面添加一个邮箱,并作为你的同步账号,提交到服务器 #License ``` Copyright 2015 Liaoguipeng Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ``` ================================================ FILE: app/.gitignore ================================================ /build ================================================ FILE: app/app.iml ================================================ ================================================ FILE: app/build.gradle ================================================ apply plugin: 'com.android.application' def packTime() { return new Date().format("yyyyMMddHHmm", TimeZone.getTimeZone("UTC")) } def projectUrl = "https://github.com/lguipeng/Notes" def blogUrl = "http://www.jianshu.com/users/f612d54d668e/latest_articles" def appDownloadUrl = "http://notes.55058a091d225.d01.nanoyun.com/release/notes.apk" def aboutAppUrl = "http://www.jianshu.com/p/640a7f2fe0c5" //remember to add your bmob app key in local.properties Properties properties = new Properties() properties.load(project.rootProject.file('local.properties').newDataInputStream()) def bmobAppKey = properties.getProperty('BMOB_KEY') def weChatId = properties.getProperty('WECHAT_ID') android { signingConfigs { debug { } release { //setting your signing.properties //first, add signing.properties to ./app/ //second, add property STORE_FILE, STORE_PASSWORD, KEY_ALIAS, KEY_PASSWORD } } compileSdkVersion Integer.parseInt(ANDROID_BUILD_COMPILE_SDK_VERSION) buildToolsVersion ANDROID_BUILD_TOOLS_VERSION defaultConfig { applicationId "com.lguipeng.notes" minSdkVersion Integer.parseInt(MIN_SDK_VERSION) targetSdkVersion Integer.parseInt(ANDROID_BUILD_TARGET_SDK_VERSION) versionCode Integer.parseInt(VERSION_CODE) versionName VERSION_NAME buildConfigField "String", "BMOB_KEY", "\"${bmobAppKey}\"" buildConfigField "String", "WECHAT_ID", "\"${weChatId}\"" buildConfigField "String", "APP_DOWNLOAD_URL", "\"${appDownloadUrl}\"" buildConfigField "String", "PROJECT_URL", "\"${projectUrl}\"" buildConfigField "String", "BLOG_URL", "\"${blogUrl}\"" buildConfigField "String", "ABOUT_APP_URL", "\"${aboutAppUrl}\"" } buildTypes { debug { versionNameSuffix " Beta" minifyEnabled false zipAlignEnabled false shrinkResources false signingConfig signingConfigs.debug } release { minifyEnabled false zipAlignEnabled false shrinkResources true signingConfig signingConfigs.release proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } packagingOptions { exclude 'META-INF/LICENSE.txt' exclude 'META-INF/NOTICE.txt' } lintOptions { abortOnError false } applicationVariants.all { variant -> variant.outputs.each { output -> def outputFile = output.outputFile if (outputFile != null && outputFile.name.endsWith('.apk')) { File outputDirectory = new File(outputFile.parent); def fileName if (variant.buildType.name == "release") { fileName = "notes_v${defaultConfig.versionName}_${packTime()}.apk" }else{ fileName = "notes_beta.apk" } output.outputFile = new File(outputDirectory, fileName) } } } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile 'com.android.support:support-v4:22.2.0' compile 'com.android.support:appcompat-v7:22.2.0' compile 'com.android.support:recyclerview-v7:22.2.0' compile 'com.android.support:cardview-v7:22.2.0' compile 'com.jakewharton:butterknife:6.1.0' compile 'com.readystatesoftware.systembartint:systembartint:1.0.3' compile 'com.melnykov:floatingactionbutton:1.3.0' compile 'com.rengwuxian.materialedittext:library:2.1.3' compile 'com.squareup.dagger:dagger:1.2.2' provided 'com.squareup.dagger:dagger-compiler:1.2.2' compile 'de.greenrobot:eventbus:2.4.0' compile 'com.pnikosis:materialish-progress:1.5' compile 'com.nispok:snackbar:2.10.10' compile project(':orm-library') compile project(':MaterialPreference') } File propFile = file('signing.properties'); if (propFile.exists()) { def Properties props = new Properties() props.load(new FileInputStream(propFile)) if (props.containsKey('STORE_FILE') && props.containsKey('STORE_PASSWORD') && props.containsKey('KEY_ALIAS') && props.containsKey('KEY_PASSWORD')) { android.signingConfigs.release.storeFile = file(props['STORE_FILE']) android.signingConfigs.release.storePassword = props['STORE_PASSWORD'] android.signingConfigs.release.keyAlias = props['KEY_ALIAS'] android.signingConfigs.release.keyPassword = props['KEY_PASSWORD'] } else { android.buildTypes.release.signingConfig = null } } else { android.buildTypes.release.signingConfig = null } ================================================ FILE: app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in E:\adt-bundle-windows-x86_64-20131030/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: app/src/androidTest/java/com/lguipeng/notes/ApplicationTest.java ================================================ package com.lguipeng.notes; import android.app.Application; import android.test.ApplicationTestCase; /** * Testing Fundamentals */ public class ApplicationTest extends ApplicationTestCase { public ApplicationTest() { super(Application.class); } } ================================================ FILE: app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: app/src/main/java/com/lguipeng/notes/App.java ================================================ package com.lguipeng.notes; import android.app.Application; import com.lguipeng.notes.module.AppModule; import java.util.Arrays; import java.util.List; import cn.bmob.v3.Bmob; import dagger.ObjectGraph; /** * Created by lgp on 2015/5/24. */ public class App extends Application{ private ObjectGraph objectGraph; @Override public void onCreate() { super.onCreate(); objectGraph = ObjectGraph.create(getModules().toArray()); objectGraph.inject(this); Bmob.initialize(this, BuildConfig.BMOB_KEY); } @Override public void onTerminate() { super.onTerminate(); } @Override public void onLowMemory() { super.onLowMemory(); } private List getModules() { return Arrays.asList(new AppModule(this)); } public ObjectGraph createScopedGraph(Object... modules) { return objectGraph.plus(modules); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/adpater/BaseListAdapter.java ================================================ package com.lguipeng.notes.adpater; import android.annotation.SuppressLint; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.BaseAdapter; import java.util.HashMap; import java.util.List; import java.util.Map; @SuppressLint("UseSparseArrays") public abstract class BaseListAdapter extends BaseAdapter { public List list; public Context mContext; public LayoutInflater mInflater; public List getList() { return list; } public void setList(List list) { this.list = list; notifyDataSetChanged(); } public void add(E e) { this.list.add(e); notifyDataSetChanged(); } public void addAll(List list) { this.list.addAll(list); notifyDataSetChanged(); } public void remove(int position) { this.list.remove(position); notifyDataSetChanged(); } public BaseListAdapter(Context context, List list) { super(); this.mContext = context; this.list = list; mInflater = LayoutInflater.from(context); } @Override public int getCount() { return list.size(); } @Override public E getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { convertView = bindView(position, convertView, parent); addInternalClickListener(convertView, position, list.get(position)); return convertView; } public abstract View bindView(int position, View convertView, ViewGroup parent); public Map> canClickItem; private void addInternalClickListener(final View itemV, final Integer position, final E valuesMap) { if (canClickItem != null) { for (Integer key : canClickItem.keySet()) { View inView = itemV.findViewById(key); final onInternalClickListener listener = canClickItem.get(key); if (inView != null && listener != null) { inView.setOnClickListener(new OnClickListener() { public void onClick(View v) { listener.OnClickListener(itemV, v, position, valuesMap); } }); inView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { listener.OnLongClickListener(itemV, v, position, valuesMap); return true; } }); } } } } public void setOnInViewClickListener(Integer key, onInternalClickListener onClickListener) { if (canClickItem == null) canClickItem = new HashMap<>(); canClickItem.put(key, onClickListener); } public interface onInternalClickListener { void OnClickListener(View parentV, View v, Integer position, T values); void OnLongClickListener(View parentV, View v, Integer position, T values); } public static class onInternalClickListenerImpl implements onInternalClickListener{ @Override public void OnClickListener(View parentV, View v, Integer position, T values) { } @Override public void OnLongClickListener(View parentV, View v, Integer position, T values) { } } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/adpater/BaseRecyclerViewAdapter.java ================================================ package com.lguipeng.notes.adpater; import android.animation.Animator; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.View; import android.view.ViewGroup; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; import com.lguipeng.notes.utils.ViewHelper; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Created by lgp on 2015/5/24. */ public abstract class BaseRecyclerViewAdapter extends RecyclerView.Adapter{ protected Context mContext; private int mDuration = 300; private Interpolator mInterpolator = new LinearInterpolator(); private int mLastPosition = -1; private boolean isFirstOnly = true; protected List list; private Map> canClickItem; public BaseRecyclerViewAdapter(List list) { this(list, null); } public BaseRecyclerViewAdapter(List list, Context context) { this.list = list; this.mContext = context; } public void add(E e) { this.list.add(0, e); notifyItemInserted(0); } public void remove(E e) { this.list.remove(e); notifyDataSetChanged(); } public void remove(int position) { this.list.remove(position); notifyDataSetChanged(); } public void setList(List list) { this.list.clear(); this.list.addAll(list); notifyDataSetChanged(); } public List getList() { return list; } @Override public int getItemCount() { return list.size(); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return null; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (holder != null){ addInternalClickListener(holder.itemView, position, list.get(position)); } } @Override public int getItemViewType(int position) { return 1; } private void addInternalClickListener(final View itemV, final Integer position, final E valuesMap) { if (canClickItem != null) { for (Integer key : canClickItem.keySet()) { View inView = itemV.findViewById(key); final onInternalClickListener listener = canClickItem.get(key); if (inView != null && listener != null) { inView.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { listener.OnClickListener(itemV, v, position, valuesMap); } }); inView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { listener.OnLongClickListener(itemV, v, position, valuesMap); return true; } }); } } } } public void setOnInViewClickListener(Integer key, onInternalClickListener onClickListener) { if (canClickItem == null) canClickItem = new HashMap<>(); canClickItem.put(key, onClickListener); } public interface onInternalClickListener { void OnClickListener(View parentV, View v, Integer position, T values); void OnLongClickListener(View parentV, View v, Integer position, T values); } public static class onInternalClickListenerImpl implements onInternalClickListener{ @Override public void OnClickListener(View parentV, View v, Integer position, T values) { } @Override public void OnLongClickListener(View parentV, View v, Integer position, T values) { } } public void setDuration(int duration) { mDuration = duration; } public void setInterpolator(Interpolator interpolator) { mInterpolator = interpolator; } public void setStartPosition(int start) { mLastPosition = start; } public void setFirstOnly(boolean firstOnly) { isFirstOnly = firstOnly; } protected void animate(RecyclerView.ViewHolder holder, int position){ if (!isFirstOnly || position > mLastPosition) { for (Animator anim : getAnimators(holder.itemView)) { anim.setDuration(mDuration).start(); anim.setInterpolator(mInterpolator); } mLastPosition = position; } else { ViewHelper.clear(holder.itemView); } } protected abstract Animator[] getAnimators(View view); } ================================================ FILE: app/src/main/java/com/lguipeng/notes/adpater/ColorsListAdapter.java ================================================ package com.lguipeng.notes.adpater; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import com.lguipeng.notes.R; import java.util.List; /** * Created by lgp on 2015/6/7. */ public class ColorsListAdapter extends BaseListAdapter{ private int checkItem; public ColorsListAdapter(Context context, List list) { super(context, list); } @Override public View bindView(int position, View convertView, ViewGroup parent) { Holder holder; if (convertView == null){ convertView = LayoutInflater.from(mContext).inflate(R.layout.colors_image_layout, null); holder = new Holder(); holder.imageView1 = (ImageView)convertView.findViewById(R.id.img_1); holder.imageView2 = (ImageView)convertView.findViewById(R.id.img_2); convertView.setTag(holder); }else{ holder = (Holder)convertView.getTag(); } holder.imageView1.setImageResource(list.get(position)); if (checkItem == position){ holder.imageView2.setImageResource(R.drawable.ic_done_white); } return convertView; } public int getCheckItem() { return checkItem; } public void setCheckItem(int checkItem) { this.checkItem = checkItem; } static class Holder { ImageView imageView1; ImageView imageView2; } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/adpater/DrawerListAdapter.java ================================================ package com.lguipeng.notes.adpater; import android.content.Context; import com.lguipeng.notes.R; import java.util.List; /** * Created by lgp on 2015/5/24. */ public class DrawerListAdapter extends SimpleListAdapter{ public DrawerListAdapter(Context mContext, List list) { super(mContext, list); } @Override protected int getLayout() { return R.layout.drawer_list_item_layout; } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/adpater/MaterialSimpleListAdapter.java ================================================ package com.lguipeng.notes.adpater; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; import com.lguipeng.notes.R; import com.lguipeng.notes.model.MaterialSimpleListItem; /** * Created by lgp on 2015/6/10. */ public class MaterialSimpleListAdapter extends ArrayAdapter { public MaterialSimpleListAdapter(Context context) { super(context, R.layout.md_simplelist_item, android.R.id.title); } @Override public View getView(final int index, View convertView, ViewGroup parent) { final View view = super.getView(index, convertView, parent); final MaterialSimpleListItem item = getItem(index); ImageView ic = (ImageView) view.findViewById(android.R.id.icon); if (item.getIcon() != null) ic.setImageDrawable(item.getIcon()); else ic.setVisibility(View.GONE); TextView tv = (TextView) view.findViewById(android.R.id.title); tv.setText(item.getContent()); return view; } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/adpater/NotesAdapter.java ================================================ package com.lguipeng.notes.adpater; import android.animation.Animator; import android.animation.ObjectAnimator; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Filter; import android.widget.Filterable; import com.lguipeng.notes.R; import com.lguipeng.notes.model.Note; import com.lguipeng.notes.utils.TimeUtils; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; /** * Created by lgp on 2015/4/6. */ public class NotesAdapter extends BaseRecyclerViewAdapter implements Filterable{ private final List originalList; private int upDownFactor = 1; private boolean isShowScaleAnimate = true; public NotesAdapter(List list) { super(list); originalList = new ArrayList<>(list); } public NotesAdapter(List list, Context context) { super(list, context); originalList = new ArrayList<>(list); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { Context context = parent.getContext(); final View view = LayoutInflater.from(context).inflate(R.layout.notes_item_layout, parent, false); return new NotesItemViewHolder(view); } @Override public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { super.onBindViewHolder(viewHolder, position); NotesItemViewHolder holder = (NotesItemViewHolder) viewHolder; Note note = list.get(position); if (note == null) return; holder.setLabelText(note.getLabel()); holder.setContentText(note.getContent()); holder.setTimeText(TimeUtils.getConciseTime(note.getLastOprTime(), mContext)); animate(viewHolder, position); } @Override public Filter getFilter() { return new NoteFilter(this, originalList); } @Override protected Animator[] getAnimators(View view) { if (view.getMeasuredHeight() <=0 || isShowScaleAnimate){ ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1.1f, 1f); ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1.1f, 1f); return new ObjectAnimator[]{scaleX, scaleY}; } return new Animator[]{ ObjectAnimator.ofFloat(view, "scaleX", 1.1f, 1f), ObjectAnimator.ofFloat(view, "scaleY", 1.1f, 1f), ObjectAnimator.ofFloat(view, "translationY", upDownFactor * 1.5f * view.getMeasuredHeight(), 0) }; } @Override public void setList(List list) { super.setList(list); this.originalList.clear(); originalList.addAll(list); setUpFactor(); isShowScaleAnimate = true; } public void setDownFactor(){ upDownFactor = -1; isShowScaleAnimate = false; } public void setUpFactor(){ upDownFactor = 1; isShowScaleAnimate = false; } private static class NoteFilter extends Filter{ private final NotesAdapter adapter; private final List originalList; private final List filteredList; private NoteFilter(NotesAdapter adapter, List originalList) { super(); this.adapter = adapter; this.originalList = new LinkedList<>(originalList); this.filteredList = new ArrayList<>(); } @Override protected FilterResults performFiltering(CharSequence constraint) { filteredList.clear(); final FilterResults results = new FilterResults(); if (constraint.length() == 0) { filteredList.addAll(originalList); } else { for ( Note note : originalList) { if (note.getContent().contains(constraint) || note.getLabel().contains(constraint)) { filteredList.add(note); } } } results.values = filteredList; results.count = filteredList.size(); return results; } @Override protected void publishResults(CharSequence constraint, FilterResults results) { adapter.list.clear(); adapter.list.addAll((ArrayList) results.values); adapter.notifyDataSetChanged(); } } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/adpater/NotesItemViewHolder.java ================================================ package com.lguipeng.notes.adpater; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.View; import android.widget.TextView; import com.lguipeng.notes.R; /** * Created by lgp on 2015/4/6. */ public class NotesItemViewHolder extends RecyclerView.ViewHolder{ private final TextView mNoteLabelTextView; private final TextView mNoteContentTextView; private final TextView mNoteTimeTextView; public NotesItemViewHolder(View parent) { super(parent); mNoteLabelTextView = (TextView) parent.findViewById(R.id.note_label_text); mNoteContentTextView = (TextView) parent.findViewById(R.id.note_content_text); mNoteTimeTextView = (TextView) parent.findViewById(R.id.note_last_edit_text); } public void setLabelText(CharSequence text){ setTextView(mNoteLabelTextView, text); } public void setLabelText(int text){ setTextView(mNoteLabelTextView, text); } public void setContentText(CharSequence text){ setTextView(mNoteContentTextView, text); } public void setContentText(int text){ setTextView(mNoteContentTextView, text); } public void setTimeText(CharSequence text){ setTextView(mNoteTimeTextView, text); } public void setTimeText(int text){ setTextView(mNoteTimeTextView, text); } private void setTextView(TextView view, CharSequence text){ if (view == null || TextUtils.isEmpty(text)) return; view.setText(text); } private void setTextView(TextView view, int text){ if (view == null || text <= 0) return; view.setText(text); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/adpater/SimpleListAdapter.java ================================================ package com.lguipeng.notes.adpater; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.lguipeng.notes.R; import java.util.List; /** * Created by lgp on 2014/8/27. */ public abstract class SimpleListAdapter extends BaseListAdapter { public SimpleListAdapter(Context mContext, List list) { super(mContext, list); } @Override public View bindView(int position, View convertView, ViewGroup parent) { Holder holder; if (convertView == null){ convertView = LayoutInflater.from(mContext).inflate(getLayout(), null); holder = new Holder(); holder.textView = (TextView)convertView.findViewById(R.id.textView); convertView.setTag(holder); }else{ holder = (Holder)convertView.getTag(); } holder.textView.setText(list.get(position)); return convertView; } protected abstract int getLayout(); static class Holder { TextView textView; } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/listener/bmob/FindListenerImpl.java ================================================ package com.lguipeng.notes.listener.bmob; import com.lguipeng.notes.utils.NotesLog; import java.util.List; import cn.bmob.v3.listener.FindListener; /** * Created by lgp on 2015/5/30. */ public class FindListenerImpl extends FindListener { @Override public void onSuccess(List list) { } @Override public void onError(int i, String s) { NotesLog.e(s); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/listener/bmob/SaveListenerImpl.java ================================================ package com.lguipeng.notes.listener.bmob; import com.lguipeng.notes.utils.NotesLog; import cn.bmob.v3.listener.SaveListener; /** * Created by lgp on 2015/5/30. */ public class SaveListenerImpl extends SaveListener { @Override public void onSuccess() { } @Override public void onFailure(int i, String s) { NotesLog.e(s); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/listener/bmob/UpdateListenerImpl.java ================================================ package com.lguipeng.notes.listener.bmob; import com.lguipeng.notes.utils.NotesLog; import cn.bmob.v3.listener.UpdateListener; /** * Created by lgp on 2015/5/30. */ public class UpdateListenerImpl extends UpdateListener { @Override public void onSuccess() { } @Override public void onFailure(int i, String s) { NotesLog.e(s); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/listener/view/RecyclerViewClickListener.java ================================================ package com.lguipeng.notes.listener.view; import android.view.View; /** * Interface definition for a callback to be invoked when an item in a * RecyclerView has been clicked. */ public interface RecyclerViewClickListener { /** * Callback method to be invoked when a item in a * RecyclerView is clicked * @param v The view within the RecyclerView.Adapter * @param position The position of the view in the adapter * @param x * @param y */ void onClick(View v, int position, float x, float y); } ================================================ FILE: app/src/main/java/com/lguipeng/notes/model/CloudNote.java ================================================ package com.lguipeng.notes.model; import com.lguipeng.notes.utils.JsonUtils; import java.util.ArrayList; import java.util.List; import cn.bmob.v3.BmobObject; /** * Created by lgp on 2015/5/28. */ public class CloudNote extends BmobObject { public CloudNote() { this("CloudNote"); } public CloudNote(String theClassName) { super(theClassName); } private String email; private List noteList = new ArrayList<>(); private String noteType; private long version; public long getVersion() { return version; } public void setVersion(long version) { this.version = version; } public String getNoteType() { return noteType; } public void setNoteType(String noteType) { this.noteType = noteType; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public List getNoteList() { return noteList; } public void setNoteList(List noteList) { this.noteList = noteList; } public void addNote(Note note) { noteList.add(JsonUtils.jsonNote(note)); } public void clearNotes() { noteList.clear(); } @Override public String toString() { StringBuilder sb = new StringBuilder(); //sb.append(super.toString()); //sb.append("\n"); for (String note : noteList){ sb.append(note); sb.append("\n"); } return sb.toString(); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/model/MaterialSimpleListItem.java ================================================ package com.lguipeng.notes.model; import android.content.Context; import android.graphics.drawable.Drawable; import android.support.annotation.DrawableRes; import android.support.annotation.StringRes; import android.support.v4.content.ContextCompat; /** * Created by lgp on 2015/6/10. */ public class MaterialSimpleListItem { private Builder mBuilder; private MaterialSimpleListItem(Builder builder) { mBuilder = builder; } public Drawable getIcon() { return mBuilder.mIcon; } public CharSequence getContent() { return mBuilder.mContent; } public static class Builder { private Context mContext; protected Drawable mIcon; protected CharSequence mContent; public Builder(Context context) { mContext = context; } public Builder icon(Drawable icon) { this.mIcon = icon; return this; } public Builder icon(@DrawableRes int iconRes) { if (iconRes == 0) return this; return icon(ContextCompat.getDrawable(mContext, iconRes)); } public Builder content(CharSequence content) { this.mContent = content; return this; } public Builder content(@StringRes int contentRes) { return content(mContext.getString(contentRes)); } public MaterialSimpleListItem build() { return new MaterialSimpleListItem(this); } } @Override public String toString() { if (getContent() != null) return getContent().toString(); else return "(no content)"; } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/model/Note.java ================================================ package com.lguipeng.notes.model; import com.alibaba.fastjson.annotation.JSONField; import com.lguipeng.notes.utils.JsonUtils; import net.tsz.afinal.annotation.sqlite.OneToMany; import net.tsz.afinal.annotation.sqlite.Table; import net.tsz.afinal.db.sqlite.OneToManyLazyLoader; import java.io.Serializable; /** * Created by lgp on 2015/5/25. */ @Table(name = "notes") public class Note implements Serializable{ @JSONField(serialize=false, deserialize=false) private int id; private int type; private String label; private String content; private long lastOprTime; @JSONField(serialize=false, deserialize=false) @OneToMany(manyColumn = "noteId") private OneToManyLazyLoader logs; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getLabel() { return label; } public void setLabel(String label) { this.label = label; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public long getLastOprTime() { return lastOprTime; } public void setLastOprTime(long lastOprTime) { this.lastOprTime = lastOprTime; } public int getType() { return type; } public void setType(int type) { this.type = type; } public OneToManyLazyLoader getLogs() { return logs; } public void setLogs(OneToManyLazyLoader logs) { this.logs = logs; } @Override public String toString() { return JsonUtils.jsonNote(this); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/model/NoteOperateLog.java ================================================ package com.lguipeng.notes.model; import net.tsz.afinal.annotation.sqlite.ManyToOne; import net.tsz.afinal.annotation.sqlite.Table; import java.io.Serializable; /** * Created by lgp on 2015/5/25. */ @Table(name = "note_opr_log") public class NoteOperateLog implements Serializable { private int id; private int type; private long time; @ManyToOne(column = "noteId") private Note note; public int getId() { return id; } public void setId(int id) { this.id = id; } public int getType() { return type; } public void setType(int type) { this.type = type; } public long getTime() { return time; } public void setTime(long time) { this.time = time; } public Note getNote() { return note; } public void setNote(Note note) { this.note = note; } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/model/NoteType.java ================================================ package com.lguipeng.notes.model; import android.text.TextUtils; import com.alibaba.fastjson.annotation.JSONField; import java.util.ArrayList; import java.util.List; /** * Created by lgp on 2015/6/2. */ public class NoteType{ @JSONField(serialize=false, deserialize=false) public final static int ALL_COUNT = 4; private List types = new ArrayList<>(); public void addType(String type){ if (types != null && types.size() < ALL_COUNT && !TextUtils.isEmpty(type)){ types.add(type); } } public String getType(int location){ if (types != null && types.size() > location){ return types.get(location); } return ""; } public List getTypes() { return types; } public void setTypes(List types) { this.types = types; } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/module/AppModule.java ================================================ package com.lguipeng.notes.module; import android.app.Application; import android.content.Context; import com.lguipeng.notes.App; import dagger.Module; import dagger.Provides; /** * Created by lgp on 2015/5/26. */ @Module( injects = { App.class }, library = true ) public class AppModule { private App app; public AppModule(App app) { this.app = app; } @Provides Application provideApplication() { return app; } @Provides Context provideContext() { return app.getApplicationContext(); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/module/DataModule.java ================================================ package com.lguipeng.notes.module; import android.content.Context; import com.lguipeng.notes.ui.AboutActivity; import com.lguipeng.notes.ui.EditNoteTypeActivity; import com.lguipeng.notes.ui.MainActivity; import com.lguipeng.notes.ui.NoteActivity; import com.lguipeng.notes.ui.PayActivity; import com.lguipeng.notes.ui.SettingActivity; import com.lguipeng.notes.ui.fragments.SettingFragment; import net.tsz.afinal.FinalDb; import javax.inject.Singleton; import dagger.Module; import dagger.Provides; /** * Created by lgp on 2015/5/26. */ @Module( injects = { AboutActivity.class, MainActivity.class, NoteActivity.class, SettingActivity.class, SettingFragment.class, PayActivity.class, EditNoteTypeActivity.class }, addsTo = AppModule.class, library = true ) public class DataModule { @Provides @Singleton FinalDb.DaoConfig provideDaoConfig(Context context) { FinalDb.DaoConfig config = new FinalDb.DaoConfig(); config.setDbName("notes.db"); config.setDbVersion(1); config.setDebug(true); config.setContext(context); return config; } @Provides @Singleton FinalDb provideFinalDb(FinalDb.DaoConfig config) { return FinalDb.create(config); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/ui/AboutActivity.java ================================================ package com.lguipeng.notes.ui; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Bundle; import android.support.v7.app.AlertDialog; import android.support.v7.widget.Toolbar; import android.text.TextUtils; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.TextView; import com.lguipeng.notes.BuildConfig; import com.lguipeng.notes.R; import com.lguipeng.notes.adpater.MaterialSimpleListAdapter; import com.lguipeng.notes.model.MaterialSimpleListItem; import com.lguipeng.notes.module.DataModule; import com.lguipeng.notes.utils.SnackbarUtils; import com.lguipeng.notes.utils.TimeUtils; import com.lguipeng.notes.utils.WXUtils; import com.tencent.mm.sdk.modelmsg.SendMessageToWX; import com.tencent.mm.sdk.modelmsg.WXMediaMessage; import com.tencent.mm.sdk.modelmsg.WXWebpageObject; import com.tencent.mm.sdk.openapi.IWXAPI; import com.tencent.mm.sdk.openapi.WXAPIFactory; import java.util.Arrays; import java.util.List; import butterknife.InjectView; import butterknife.OnClick; /** * Created by lgp on 2015/5/25. */ public class AboutActivity extends BaseActivity implements View.OnClickListener{ @InjectView(R.id.toolbar) Toolbar toolbar; @InjectView(R.id.version_text) TextView versionTextView; @InjectView(R.id.blog_btn) Button blogButton; @InjectView(R.id.project_home_btn) Button projectHomeButton; private int clickCount = 0; private long lastClickTime = 0; private final static String WEIBO_PACKAGENAME = "com.sina.weibo"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initVersionText(); blogButton.setOnClickListener(this); projectHomeButton.setOnClickListener(this); } @Override protected int getLayoutView() { return R.layout.activity_about; } @Override protected List getModules() { return Arrays.asList(new DataModule()); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.blog_btn: startViewAction(BuildConfig.BLOG_URL); break; case R.id.project_home_btn: startViewAction(BuildConfig.PROJECT_URL); break; default: break; } } @Override protected void initToolbar(){ super.initToolbar(toolbar); toolbar.setTitle(R.string.about); } @OnClick(R.id.version_text) void versionClick(View view){ if (clickCount < 3){ if (TimeUtils.getCurrentTimeInLong() - lastClickTime < 500 || lastClickTime <= 0){ clickCount ++; if (clickCount >= 3){ startViewAction(BuildConfig.ABOUT_APP_URL); clickCount = 0; lastClickTime = 0; return; } }else { clickCount = 0; lastClickTime = 0; return; } lastClickTime = TimeUtils.getCurrentTimeInLong(); } } private void initVersionText(){ versionTextView.setText("v" + getVersion(this)); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_about, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.share: showShareDialog(); break; default: return super.onOptionsItemSelected(item); } return true; } private String getVersion(Context ctx){ try { PackageManager pm = ctx.getPackageManager(); PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES); return pi.versionName; }catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return "1.0.0"; } private void startViewAction(String uriStr){ try { Uri uri = Uri.parse(uriStr); Intent intent = new Intent(Intent.ACTION_VIEW, uri); startActivity(intent); } catch (ActivityNotFoundException e) { e.printStackTrace(); } } private void share(String packages, Uri uri){ Intent intent=new Intent(Intent.ACTION_SEND); if (uri != null){ intent.setType("image/*"); intent.putExtra(Intent.EXTRA_STREAM, uri); }else { intent.setType("text/plain"); } intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share)); intent.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_text, getString(R.string.download_url), BuildConfig.APP_DOWNLOAD_URL)); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (!TextUtils.isEmpty(packages)) intent.setPackage(packages); startActivity(Intent.createChooser(intent, getString(R.string.share))); } private byte[] getLogoBitmapArray(){ Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher); return WXUtils.bmpToByteArray(bitmap, false); } private void shareToWeChat(int scene){ IWXAPI api = WXAPIFactory.createWXAPI(this, BuildConfig.WECHAT_ID, true); if (!api.isWXAppInstalled()){ SnackbarUtils.show(this, R.string.not_install_app); } api.registerApp(BuildConfig.WECHAT_ID); WXWebpageObject object = new WXWebpageObject(); object.webpageUrl = "http://www.wandoujia.com/apps/com.lguipeng.notes"; WXMediaMessage msg = new WXMediaMessage(object); msg.mediaObject = object; msg.thumbData = getLogoBitmapArray(); msg.title = getString(R.string.app_desc); msg.description = getString(R.string.share_text, "", ""); SendMessageToWX.Req request = new SendMessageToWX.Req(); request.message = msg; request.scene = scene; api.sendReq(request); api.unregisterApp(); } private void shareToWeChatTimeline(){ shareToWeChat(SendMessageToWX.Req.WXSceneTimeline); } private void shareToWeChatSession(){ shareToWeChat(SendMessageToWX.Req.WXSceneSession); } private void shareToWeChatFavorite(){ shareToWeChat(SendMessageToWX.Req.WXSceneFavorite); } private void shareToWeibo(){ if (isInstallApplication(WEIBO_PACKAGENAME)){ share(WEIBO_PACKAGENAME, null); }else { SnackbarUtils.show(this, R.string.not_install_app); } } private boolean isInstallApplication(String packageName){ try { PackageManager pm = this.getPackageManager(); pm.getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES); return true; } catch (PackageManager.NameNotFoundException e) { return false; } } private void showShareDialog(){ AlertDialog.Builder builder = generateDialogBuilder(); builder.setTitle(getString(R.string.share)); final MaterialSimpleListAdapter adapter = new MaterialSimpleListAdapter(this); String[] array = getResources().getStringArray(R.array.share_dialog_text); adapter.add(new MaterialSimpleListItem.Builder(this) .content(array[0]) .icon(R.drawable.ic_wx_logo) .build()); adapter.add(new MaterialSimpleListItem.Builder(this) .content(array[1]) .icon(R.drawable.ic_wx_moments) .build()); adapter.add(new MaterialSimpleListItem.Builder(this) .content(array[2]) .icon(R.drawable.ic_wx_collect) .build()); adapter.add(new MaterialSimpleListItem.Builder(this) .content(array[3]) .icon(R.drawable.ic_sina_logo) .build()); adapter.add(new MaterialSimpleListItem.Builder(this) .content(array[4]) .icon(R.drawable.ic_share_more) .build()); builder.setAdapter(adapter, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which){ case 0: shareToWeChatSession(); break; case 1: shareToWeChatTimeline(); break; case 2: shareToWeChatFavorite(); break; case 3: shareToWeibo(); break; default: share("", null); } } }); builder.show(); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/ui/BaseActivity.java ================================================ package com.lguipeng.notes.ui; import android.annotation.TargetApi; import android.os.Build; import android.os.Bundle; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.TypedValue; import android.view.MenuItem; import android.view.WindowManager; import com.lguipeng.notes.App; import com.lguipeng.notes.R; import com.lguipeng.notes.utils.PreferenceUtils; import com.lguipeng.notes.utils.ThemeUtils; import com.readystatesoftware.systembartint.SystemBarTintManager; import java.util.List; import butterknife.ButterKnife; import dagger.ObjectGraph; /** * Created by lgp on 2015/5/24. */ public abstract class BaseActivity extends AppCompatActivity { private ObjectGraph activityGraph; protected PreferenceUtils preferenceUtils; @Override protected void onCreate(Bundle savedInstanceState) { preferenceUtils = PreferenceUtils.getInstance(this); initTheme(); super.onCreate(savedInstanceState); initWindow(); activityGraph = ((App) getApplication()).createScopedGraph(getModules().toArray()); activityGraph.inject(this); setContentView(getLayoutView()); ButterKnife.inject(this); initToolbar(); } private void initTheme(){ ThemeUtils.Theme theme = getCurrentTheme(); ThemeUtils.changTheme(this, theme); } protected int getColor(int res){ if (res <= 0) throw new IllegalArgumentException("resource id can not be less 0"); return getResources().getColor(res); } @TargetApi(19) private void initWindow(){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){ getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); SystemBarTintManager tintManager = new SystemBarTintManager(this); tintManager.setStatusBarTintColor(getStatusBarColor()); tintManager.setStatusBarTintEnabled(true); } } protected void initToolbar(Toolbar toolbar){ if (toolbar == null) return; toolbar.setBackgroundColor(getColorPrimary()); toolbar.setTitle(R.string.app_name); toolbar.setTitleTextColor(getColor(R.color.action_bar_title_color)); toolbar.collapseActionView(); setSupportActionBar(toolbar); if (getSupportActionBar() != null){ getSupportActionBar().setHomeAsUpIndicator(R.drawable.abc_ic_ab_back_mtrl_am_alpha); getSupportActionBar().setDisplayHomeAsUpEnabled(true); } } public int getStatusBarColor(){ return getColorPrimary(); } public int getColorPrimary(){ TypedValue typedValue = new TypedValue(); getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true); return typedValue.data; } public int getDarkColorPrimary(){ TypedValue typedValue = new TypedValue(); getTheme().resolveAttribute(R.attr.colorPrimaryDark, typedValue, true); return typedValue.data; } protected AlertDialog.Builder generateDialogBuilder(){ ThemeUtils.Theme theme = getCurrentTheme(); AlertDialog.Builder builder; int style = R.style.RedDialogTheme; switch (theme){ case BROWN: style = R.style.BrownDialogTheme; break; case BLUE: style = R.style.BlueDialogTheme; break; case BLUE_GREY: style = R.style.BlueGreyDialogTheme; break; case YELLOW: style = R.style.YellowDialogTheme; break; case DEEP_PURPLE: style = R.style.DeepPurpleDialogTheme; break; case PINK: style = R.style.PinkDialogTheme; break; case GREEN: style = R.style.GreenDialogTheme; break; default: break; } builder = new AlertDialog.Builder(this, style); return builder; } protected ThemeUtils.Theme getCurrentTheme(){ int value = preferenceUtils.getIntParam(getString(R.string.change_theme_key), 0); return ThemeUtils.Theme.mapValueToTheme(value); } @Override public void onDestroy() { super.onDestroy(); activityGraph = null; } /** * 增加了默认的返回finish事件 */ @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id) { case android.R.id.home: finish(); return true; default: return super.onOptionsItemSelected(item); } } protected abstract int getLayoutView(); protected abstract List getModules(); protected abstract void initToolbar(); } ================================================ FILE: app/src/main/java/com/lguipeng/notes/ui/EditNoteTypeActivity.java ================================================ package com.lguipeng.notes.ui; import android.content.Context; import android.os.Bundle; import android.support.v7.widget.Toolbar; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.view.Menu; import android.view.MenuItem; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.LinearLayout; import com.lguipeng.notes.R; import com.lguipeng.notes.model.NoteType; import com.lguipeng.notes.module.DataModule; import com.lguipeng.notes.utils.JsonUtils; import com.lguipeng.notes.utils.NoteConfig; import com.lguipeng.notes.utils.PreferenceUtils; import com.rengwuxian.materialedittext.MaterialEditText; import java.util.Arrays; import java.util.List; import butterknife.InjectView; import de.greenrobot.event.EventBus; /** * Created by lgp on 2015/6/2. */ public class EditNoteTypeActivity extends BaseActivity{ @InjectView(R.id.toolbar) Toolbar toolbar; @InjectView(R.id.edit_root_view) LinearLayout editRootView; private MaterialEditText[] editTexts = new MaterialEditText[NoteType.ALL_COUNT - 1]; private MenuItem doneMenuItem; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initEditTextView(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_note, menu); return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { doneMenuItem = menu.getItem(0); doneMenuItem.setVisible(false); return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.done: hideKeyBoard(editTexts[0]); NoteType type = new NoteType(); for (MaterialEditText view : editTexts){ type.addType(view.getText().toString()); } type.addType(getString(R.string.recycle_bin)); String json = JsonUtils.jsonNoteType(type); preferenceUtils.saveParam(PreferenceUtils.NOTE_TYPE_KEY, json); EventBus.getDefault().post(NoteConfig.NOTE_TYPE_UPDATE_EVENT); finish(); return true; default: return super.onOptionsItemSelected(item); } } @Override protected int getLayoutView() { return R.layout.activity_edit_note_type; } @Override protected List getModules() { return Arrays.asList(new DataModule()); } @Override protected void initToolbar(){ super.initToolbar(toolbar); toolbar.setTitle(R.string.edit); } private void initEditTextView(){ String json = preferenceUtils.getStringParam(PreferenceUtils.NOTE_TYPE_KEY); List lists = JsonUtils.parseNoteType(json); if (lists == null) return; for (int i=0; i< editTexts.length; i++){ MaterialEditText view = (MaterialEditText)getLayoutInflater().inflate(R.layout.edit_layout, null); view.addTextChangedListener(new SimpleTextWatcher()); if (i < lists.size()){ view.setText(lists.get(i)); view.setSelection(lists.get(i).length()); } editRootView.addView(view); editTexts[i] = view; } } class SimpleTextWatcher implements TextWatcher { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (doneMenuItem == null) return; boolean allFill = true; for (MaterialEditText view : editTexts){ if (TextUtils.isEmpty(view.getText().toString())) allFill = false; } if (allFill){ doneMenuItem.setVisible(true); }else { doneMenuItem.setVisible(false); } } @Override public void afterTextChanged(Editable s) { } } private void hideKeyBoard(EditText editText){ InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(editText.getWindowToken(), 0); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/ui/MainActivity.java ================================================ package com.lguipeng.notes.ui; import android.app.SearchManager; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; import android.os.Parcelable; import android.support.v4.view.MenuItemCompat; import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.AlertDialog; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.PopupMenu; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.SearchView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.support.v7.widget.Toolbar; import android.text.TextUtils; import android.view.Gravity; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.Button; import android.widget.ListView; import com.lguipeng.notes.R; import com.lguipeng.notes.adpater.BaseRecyclerViewAdapter; import com.lguipeng.notes.adpater.DrawerListAdapter; import com.lguipeng.notes.adpater.NotesAdapter; import com.lguipeng.notes.adpater.SimpleListAdapter; import com.lguipeng.notes.listener.bmob.FindListenerImpl; import com.lguipeng.notes.listener.bmob.SaveListenerImpl; import com.lguipeng.notes.listener.bmob.UpdateListenerImpl; import com.lguipeng.notes.model.CloudNote; import com.lguipeng.notes.model.Note; import com.lguipeng.notes.model.NoteOperateLog; import com.lguipeng.notes.model.NoteType; import com.lguipeng.notes.module.DataModule; import com.lguipeng.notes.utils.AccountUtils; import com.lguipeng.notes.utils.JsonUtils; import com.lguipeng.notes.utils.NoteConfig; import com.lguipeng.notes.utils.PreferenceUtils; import com.lguipeng.notes.utils.SnackbarUtils; import com.melnykov.fab.FloatingActionButton; import com.melnykov.fab.ScrollDirectionListener; import com.pnikosis.materialishprogress.ProgressWheel; import net.tsz.afinal.FinalDb; import java.util.Arrays; import java.util.List; import javax.inject.Inject; import butterknife.InjectView; import butterknife.OnClick; import cn.bmob.v3.BmobQuery; import de.greenrobot.event.EventBus; /** * Created by lgp on 2015/5/24. */ public class MainActivity extends BaseActivity implements SwipeRefreshLayout.OnRefreshListener{ @InjectView(R.id.toolbar) Toolbar toolbar; @InjectView(R.id.refresher) SwipeRefreshLayout refreshLayout; @InjectView(R.id.recyclerView) RecyclerView recyclerView; @InjectView(R.id.drawer_layout) DrawerLayout mDrawerLayout; @InjectView(R.id.edit_note_type) Button editNoteTypeButton; @InjectView(R.id.left_drawer_listview) ListView mDrawerMenuListView; @InjectView(R.id.left_drawer) View drawerRootView; @InjectView(R.id.fab) FloatingActionButton fab; @InjectView(R.id.progress_wheel) ProgressWheel progressWheel; @Inject FinalDb finalDb; private ActionBarDrawerToggle mDrawerToggle; private SearchView searchView; private NotesAdapter recyclerAdapter; private int mCurrentNoteType; private boolean rightHandOn = false; private boolean cardLayout = true; private boolean hasUpdateNote = false; private boolean hasEditClick = false; private List noteTypelist; private boolean hasSyncing = false; private final String CURRENT_NOTE_TYPE_KEY = "CURRENT_NOTE_TYPE_KEY"; private final String PROGRESS_WHEEL_KEY = "PROGRESS_WHEEL_KEY"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null){ mCurrentNoteType = savedInstanceState.getInt(CURRENT_NOTE_TYPE_KEY); progressWheel.onRestoreInstanceState(savedInstanceState.getParcelable(PROGRESS_WHEEL_KEY)); } initToolbar(); initDrawerView(); initRecyclerView(); EventBus.getDefault().register(this); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt(CURRENT_NOTE_TYPE_KEY, mCurrentNoteType); Parcelable parcelable = progressWheel.onSaveInstanceState(); outState.putParcelable(PROGRESS_WHEEL_KEY, parcelable); } @Override public void onStart() { super.onStart(); if (rightHandOn != preferenceUtils.getBooleanParam(getString(R.string.right_hand_mode_key))){ rightHandOn = !rightHandOn; if (rightHandOn){ setMenuListViewGravity(Gravity.END); }else{ setMenuListViewGravity(Gravity.START); } } } @Override protected void onResume() { super.onResume(); if (hasUpdateNote){ changeToSelectNoteType(mCurrentNoteType); hasUpdateNote = false; } if (cardLayout != preferenceUtils.getBooleanParam(getString(R.string.card_note_item_layout_key), true)){ changeItemLayout(!cardLayout); } } @Override public void onStop() { super.onStop(); } @Override public void onDestroy() { EventBus.getDefault().unregister(this); super.onDestroy(); } public void onEvent(Integer event){ switch (event){ case NoteConfig.NOTE_UPDATE_EVENT: hasUpdateNote = true; break; case NoteConfig.NOTE_TYPE_UPDATE_EVENT: initDrawerListView(); break; case NoteConfig.CHANGE_THEME_EVENT: this.recreate(); break; } } @Override protected int getLayoutView() { return R.layout.activity_main; } @Override protected List getModules() { return Arrays.asList(new DataModule()); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mDrawerToggle.onConfigurationChanged(newConfig); } @Override public void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); mDrawerToggle.syncState(); if (toolbar != null){ toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { openOrCloseDrawer(); } }); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); MenuItem searchItem = menu.findItem(R.id.action_search); //searchItem.expandActionView(); searchView = (SearchView) MenuItemCompat.getActionView(searchItem); ComponentName componentName = getComponentName(); searchView.setSearchableInfo( searchManager.getSearchableInfo(componentName)); searchView.setQueryHint(getString(R.string.search_note)); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String s) { return true; } @Override public boolean onQueryTextChange(String s) { recyclerAdapter.getFilter().filter(s); return true; } }); MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() { @Override public boolean onMenuItemActionExpand(MenuItem item) { recyclerAdapter.setUpFactor(); refreshLayout.setEnabled(false); return true; } @Override public boolean onMenuItemActionCollapse(MenuItem item) { refreshLayout.setEnabled(true); return true; } }); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { if(mDrawerToggle.onOptionsItemSelected(item)) { return true; } Intent intent; switch (item.getItemId()){ case R.id.setting: intent = new Intent(MainActivity.this, SettingActivity.class); startActivity(intent); return true; case R.id.sync: sync(); return true; case R.id.about: intent = new Intent(MainActivity.this, AboutActivity.class); startActivity(intent); return true; default: return super.onOptionsItemSelected(item); } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && mDrawerLayout.isDrawerOpen(drawerRootView)){ mDrawerLayout.closeDrawer(drawerRootView); return true; } moveTaskToBack(true); return super.onKeyDown(keyCode, event); } @Override protected void initToolbar(){ super.initToolbar(toolbar); } private void initDrawerListView(){ String json = preferenceUtils.getStringParam(PreferenceUtils.NOTE_TYPE_KEY); if (!TextUtils.isEmpty(json)){ noteTypelist = JsonUtils.parseNoteType(json); }else{ noteTypelist = Arrays.asList(getResources().getStringArray(R.array.drawer_content)); NoteType type = new NoteType(); type.setTypes(noteTypelist); String text = JsonUtils.jsonNoteType(type); preferenceUtils.saveParam(PreferenceUtils.NOTE_TYPE_KEY, text); } SimpleListAdapter adapter = new DrawerListAdapter(this, noteTypelist); mDrawerMenuListView.setAdapter(adapter); mDrawerMenuListView.setItemChecked(mCurrentNoteType, true); toolbar.setTitle(noteTypelist.get(mCurrentNoteType)); } private void initDrawerView() { initDrawerListView(); mDrawerMenuListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { mDrawerMenuListView.setItemChecked(position, true); openOrCloseDrawer(); mCurrentNoteType = position; changeToSelectNoteType(mCurrentNoteType); if (mCurrentNoteType == NoteConfig.NOTE_TRASH_TYPE) { fab.hide(); fab.setVisibility(View.INVISIBLE); } else { fab.setVisibility(View.VISIBLE); fab.show(); } } }); mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, 0, 0){ @Override public void onDrawerOpened(View drawerView) { super.onDrawerOpened(drawerView); invalidateOptionsMenu(); toolbar.setTitle(R.string.app_name); } @Override public void onDrawerClosed(View drawerView) { super.onDrawerClosed(drawerView); invalidateOptionsMenu(); toolbar.setTitle(noteTypelist.get(mCurrentNoteType)); if (hasEditClick){ Intent intent = new Intent(MainActivity.this, EditNoteTypeActivity.class); startActivity(intent); hasEditClick = false; } } }; mDrawerToggle.setDrawerIndicatorEnabled(true); mDrawerLayout.setDrawerListener(mDrawerToggle); mDrawerLayout.setScrimColor(getColor(R.color.drawer_scrim_color)); rightHandOn = preferenceUtils.getBooleanParam(getString(R.string.right_hand_mode_key)); if (rightHandOn){ setMenuListViewGravity(Gravity.END); } } private void initRecyclerView(){ showProgressWheel(true); initItemLayout(); recyclerView.setHasFixedSize(true); recyclerAdapter = new NotesAdapter(initItemData(mCurrentNoteType), this); recyclerAdapter.setOnInViewClickListener(R.id.notes_item_root, new BaseRecyclerViewAdapter.onInternalClickListenerImpl() { @Override public void OnClickListener(View parentV, View v, Integer position, Note values) { super.OnClickListener(parentV, v, position, values); if (mCurrentNoteType == NoteConfig.NOTE_TRASH_TYPE) return; startNoteActivity(NoteActivity.VIEW_NOTE_TYPE, values); } }); recyclerAdapter.setOnInViewClickListener(R.id.note_more, new BaseRecyclerViewAdapter.onInternalClickListenerImpl() { @Override public void OnClickListener(View parentV, View v, Integer position, Note values) { super.OnClickListener(parentV, v, position, values); showPopupMenu(v, values); } }); recyclerAdapter.setFirstOnly(false); recyclerAdapter.setDuration(300); recyclerView.setAdapter(recyclerAdapter); fab.attachToRecyclerView(recyclerView, new ScrollDirectionListener() { @Override public void onScrollDown() { recyclerAdapter.setDownFactor(); } @Override public void onScrollUp() { recyclerAdapter.setUpFactor(); } }); showProgressWheel(false); refreshLayout.setColorSchemeColors(getColorPrimary()); refreshLayout.setOnRefreshListener(this); } @OnClick(R.id.fab) public void newNote(View view){ Note note = new Note(); note.setType(mCurrentNoteType); startNoteActivity(NoteActivity.CREATE_NOTE_TYPE, note); } @OnClick(R.id.edit_note_type) public void editNoteType(View view){ hasEditClick = true; openOrCloseDrawer(); } @Override public void onRefresh() { sync(); } private void changeToSelectNoteType(int type){ showProgressWheel(true); recyclerAdapter.setList(initItemData(type)); showProgressWheel(false); } private void openDrawer() { if (!mDrawerLayout.isDrawerOpen(drawerRootView)) { mDrawerLayout.openDrawer(drawerRootView); } } private void closeDrawer() { if (mDrawerLayout.isDrawerOpen(drawerRootView)) { mDrawerLayout.closeDrawer(drawerRootView); } } private void openOrCloseDrawer() { if (mDrawerLayout.isDrawerOpen(drawerRootView)) { mDrawerLayout.closeDrawer(drawerRootView); } else { mDrawerLayout.openDrawer(drawerRootView); } } private void showPopupMenu(View view, final Note note) { PopupMenu popup = new PopupMenu(this, view); //Inflating the Popup using xml file String move = getString(R.string.move_to); if (mCurrentNoteType == NoteConfig.NOTE_TRASH_TYPE){ for (int i=0; i< noteTypelist.size()-1; i++){ popup.getMenu().add(Menu.NONE, i, Menu.NONE, move + noteTypelist.get(i)); } popup.getMenu().add(Menu.NONE, noteTypelist.size()-1, Menu.NONE, getString(R.string.delete_forever)); popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { int id = item.getItemId(); if (id < noteTypelist.size() - 1) { note.setType(id); finalDb.update(note); changeToSelectNoteType(mCurrentNoteType); } else { showDeleteForeverDialog(note); } return true; } }); } else { popup.getMenuInflater() .inflate(R.menu.menu_notes_more, popup.getMenu()); popup.setOnMenuItemClickListener( new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case R.id.delete_forever: showDeleteForeverDialog(note); break; case R.id.edit: startNoteActivity(NoteActivity.EDIT_NOTE_TYPE, note); break; case R.id.move_to_trash: note.setType(NoteConfig.NOTE_TRASH_TYPE); finalDb.update(note); changeToSelectNoteType(mCurrentNoteType); break; default: break; } return true; } }); } popup.show(); //showing popup menu } private void showDeleteForeverDialog(final Note note){ AlertDialog.Builder builder = generateDialogBuilder(); builder.setTitle(R.string.delete_forever_message); DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which){ case DialogInterface.BUTTON_POSITIVE: for (NoteOperateLog log : note.getLogs().getList()){ finalDb.delete(log); } finalDb.delete(note); changeToSelectNoteType(mCurrentNoteType); break; case DialogInterface.BUTTON_NEGATIVE: break; default: break; } } }; builder.setPositiveButton(R.string.sure, listener); builder.setNegativeButton(R.string.cancel, listener); builder.show(); } private void startNoteActivity(int oprType, Note value){ Intent intent = new Intent(this, NoteActivity.class); Bundle bundle = new Bundle(); bundle.putInt(NoteActivity.OPERATE_NOTE_TYPE_KEY, oprType); EventBus.getDefault().postSticky(value); intent.putExtras(bundle); startActivity(intent); } private void setMenuListViewGravity(int gravity){ DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) drawerRootView.getLayoutParams(); params.gravity = gravity; drawerRootView.setLayoutParams(params); } private List initItemData(int noteType) { List itemList = null; switch (noteType){ case NoteConfig.NOTE_STUDY_TYPE: case NoteConfig.NOTE_WORK_TYPE: case NoteConfig.NOTE_OTHER_TYPE: case NoteConfig.NOTE_TRASH_TYPE: itemList = finalDb.findAllByWhere(Note.class, "type = " + noteType, "lastOprTime", true); break; default: break; } return itemList; } private void showProgressWheel(boolean visible){ progressWheel.setBarColor(getColorPrimary()); if (visible){ if (!progressWheel.isSpinning()) progressWheel.spin(); }else{ progressWheel.postDelayed(new Runnable() { @Override public void run() { if (progressWheel.isSpinning()) { progressWheel.stopSpinning(); } } }, 500); } } private void syncNotes(final String account){ new Thread(){ @Override public void run() { BmobQuery query = new BmobQuery<>(); query.addWhereEqualTo("email", account); query.findObjects(MainActivity.this, new FindListenerImpl(){ CloudNote cloudNote; @Override public void onSuccess(List notes) { List list = finalDb.findAll(Note.class); if (notes != null && notes.size() >= 1){ cloudNote = notes.get(0); long localVersion = preferenceUtils.getLongParam(account); if (cloudNote.getVersion() > localVersion){ //pull notes preferenceUtils.saveParam(PreferenceUtils.NOTE_TYPE_KEY, cloudNote.getNoteType()); for (String string : cloudNote.getNoteList()) { Note note = JsonUtils.parseNote(string); if (note == null) continue; finalDb.saveBindId(note); NoteOperateLog log = new NoteOperateLog(); log.setTime(note.getLastOprTime()); log.setType(NoteConfig.NOTE_CREATE_OPR); log.setNote(note); finalDb.save(log); } preferenceUtils.saveParam(account, cloudNote.getVersion()); runOnUiThread(new Runnable() { @Override public void run() { initDrawerListView(); changeToSelectNoteType(mCurrentNoteType); onSyncSuccess(); } }); return; }else { //upload notes cloudNote.setVersion(++localVersion); } }else { cloudNote = new CloudNote(); cloudNote.setEmail(account); cloudNote.setVersion(1); } cloudNote.clearNotes(); for (Note note : list){ cloudNote.addNote(note); } String json = preferenceUtils.getStringParam(PreferenceUtils.NOTE_TYPE_KEY); cloudNote.setNoteType(json); if (TextUtils.isEmpty(cloudNote.getObjectId())){ cloudNote.save(MainActivity.this, new SaveListenerImpl() { @Override public void onSuccess() { preferenceUtils.saveParam(account, cloudNote.getVersion()); onSyncSuccess(); } @Override public void onFailure(int i, String s) { super.onFailure(i, s); onSyncFail(); } }); }else{ cloudNote.update(MainActivity.this, new UpdateListenerImpl() { @Override public void onSuccess() { preferenceUtils.saveParam(account, cloudNote.getVersion()); onSyncSuccess(); } @Override public void onFailure(int i, String s) { super.onFailure(i, s); onSyncFail(); } }); } } @Override public void onError(int i, String s) { super.onError(i, s); onSyncFail(); } }); } }.start(); } private void sync(){ if (hasSyncing) return; String account = preferenceUtils.getStringParam(getString(R.string.sync_account_key)); if (TextUtils.isEmpty(account)){ AccountUtils.findValidAccount(getApplicationContext(), new AccountUtils.AccountFinderListener() { @Override protected void onNone() { if (refreshLayout.isRefreshing()){ refreshLayout.setRefreshing(false); } SnackbarUtils.show(MainActivity.this, R.string.no_account_tip); } @Override protected void onOne(String account) { preferenceUtils.saveParam(getString(R.string.sync_account_key), account); hasSyncing = true; syncNotes(account); } @Override protected void onMore(List accountItems) { if (refreshLayout.isRefreshing()){ refreshLayout.setRefreshing(false); } SnackbarUtils.show(MainActivity.this, R.string.no_account_tip); } }); }else { if (!refreshLayout.isRefreshing()){ refreshLayout.setRefreshing(true); } hasSyncing = true; syncNotes(account); } } private void onSyncSuccess(){ runOnUiThread(new Runnable() { @Override public void run() { hasSyncing = false; refreshLayout.setRefreshing(false); SnackbarUtils.show(MainActivity.this, R.string.sync_success); } }); } private void onSyncFail(){ runOnUiThread(new Runnable() { @Override public void run() { hasSyncing = false; refreshLayout.setRefreshing(false); SnackbarUtils.show(MainActivity.this, R.string.sync_fail); } }); } private void changeItemLayout(boolean flow){ cardLayout = flow; if (!flow){ recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); }else { recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, LinearLayoutManager.VERTICAL)); } } private void initItemLayout(){ if (preferenceUtils.getBooleanParam(getString(R.string.card_note_item_layout_key), true)){ cardLayout = true; recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, LinearLayoutManager.VERTICAL)); }else { cardLayout = false; recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); } } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/ui/NoteActivity.java ================================================ package com.lguipeng.notes.ui; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AlertDialog; import android.support.v7.widget.Toolbar; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.TextView; import com.lguipeng.notes.R; import com.lguipeng.notes.model.Note; import com.lguipeng.notes.model.NoteOperateLog; import com.lguipeng.notes.module.DataModule; import com.lguipeng.notes.utils.NoteConfig; import com.lguipeng.notes.utils.TimeUtils; import com.rengwuxian.materialedittext.MaterialEditText; import net.tsz.afinal.FinalDb; import java.util.Arrays; import java.util.List; import javax.inject.Inject; import butterknife.InjectView; import de.greenrobot.event.EventBus; /** * Created by lgp on 2015/5/25. */ public class NoteActivity extends BaseActivity{ @InjectView(R.id.toolbar) Toolbar toolbar; @InjectView(R.id.label_edit_text) MaterialEditText labelEditText; @InjectView(R.id.content_edit_text) MaterialEditText contentEditText; @InjectView(R.id.opr_time_line_text) TextView oprTimeLineTextView; @Inject FinalDb finalDb; private MenuItem doneMenuItem; private int operateNoteType = 0; private Note note; public final static String OPERATE_NOTE_TYPE_KEY = "OPERATE_NOTE_TYPE_KEY"; public final static int VIEW_NOTE_TYPE = 0x00; public final static int EDIT_NOTE_TYPE = 0x01; public final static int CREATE_NOTE_TYPE = 0x02; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); parseIntent(getIntent()); EventBus.getDefault().registerSticky(this); } @Override public void onDestroy() { EventBus.getDefault().unregister(this); super.onDestroy(); } @Override protected int getLayoutView() { return R.layout.activity_note; } @Override protected List getModules() { return Arrays.asList(new DataModule()); } public void onEventMainThread(Note note) { this.note = note; initToolbar(); initEditText(); initTextView(); } private void parseIntent(Intent intent){ if (intent != null && intent.getExtras() != null){ operateNoteType = intent.getExtras().getInt(OPERATE_NOTE_TYPE_KEY, 0); } } @Override protected void initToolbar(){ super.initToolbar(toolbar); toolbar.setTitle(R.string.view_note); switch (operateNoteType){ case CREATE_NOTE_TYPE: toolbar.setTitle(R.string.new_note); break; case EDIT_NOTE_TYPE: toolbar.setTitle(R.string.edit_note); break; case VIEW_NOTE_TYPE: toolbar.setTitle(R.string.view_note); break; default: break; } } private void initEditText(){ switch (operateNoteType){ case EDIT_NOTE_TYPE: labelEditText.requestFocus(); labelEditText.setText(note.getLabel()); contentEditText.setText(note.getContent()); labelEditText.setSelection(note.getLabel().length()); contentEditText.setSelection(note.getContent().length()); break; case VIEW_NOTE_TYPE: labelEditText.setText(note.getLabel()); contentEditText.setText(note.getContent()); labelEditText.setOnFocusChangeListener(new SimpleOnFocusChangeListener()); contentEditText.setOnFocusChangeListener(new SimpleOnFocusChangeListener()); break; default: labelEditText.requestFocus(); break; } labelEditText.addTextChangedListener(new SimpleTextWatcher()); contentEditText.addTextChangedListener(new SimpleTextWatcher()); } private void initTextView(){ boolean all = preferenceUtils.getBooleanParam(getString(R.string.show_note_history_log_key)); oprTimeLineTextView.setText(getOprTimeLineText(note, all)); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_note, menu); return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { doneMenuItem = menu.getItem(0); doneMenuItem.setVisible(false); return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.done: saveNote(); return true; case android.R.id.home: if (doneMenuItem.isVisible()){ showNotSaveNoteDialog(); return true; } finish(); default: return super.onOptionsItemSelected(item); } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK){ if (doneMenuItem != null && doneMenuItem.isVisible()){ showNotSaveNoteDialog(); return true; } } return super.onKeyDown(keyCode, event); } private void showNotSaveNoteDialog(){ hideKeyBoard(labelEditText); AlertDialog.Builder builder = generateDialogBuilder(); builder.setTitle(R.string.not_save_note_leave_tip); DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which){ case DialogInterface.BUTTON_POSITIVE: saveNote(); break; case DialogInterface.BUTTON_NEGATIVE: NoteActivity.this.finish(); break; default: break; } } }; builder.setPositiveButton(R.string.sure, listener); builder.setNegativeButton(R.string.cancel, listener); builder.show(); } private void saveNote(){ hideKeyBoard(labelEditText); note.setLabel(labelEditText.getText().toString()); note.setContent(contentEditText.getText().toString()); note.setLastOprTime(TimeUtils.getCurrentTimeInLong()); NoteOperateLog log = new NoteOperateLog(); log.setTime(TimeUtils.getCurrentTimeInLong()); switch (operateNoteType){ case CREATE_NOTE_TYPE: finalDb.saveBindId(note); log.setType(NoteConfig.NOTE_CREATE_OPR); log.setNote(note); finalDb.save(log); break; default: finalDb.update(note); log.setType(NoteConfig.NOTE_EDIT_OPR); log.setNote(note); finalDb.save(log); break; } EventBus.getDefault().post(NoteConfig.NOTE_UPDATE_EVENT); finish(); } class SimpleTextWatcher implements TextWatcher { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (doneMenuItem == null) return; String labelSrc = labelEditText.getText().toString(); String contentSrc = contentEditText.getText().toString(); String label = labelSrc.replaceAll("\\s*|\t|\r|\n", ""); String content = contentSrc.replaceAll("\\s*|\t|\r|\n", ""); if (!TextUtils.isEmpty(label) && !TextUtils.isEmpty(content)){ if (TextUtils.equals(labelSrc, note.getLabel()) && TextUtils.equals(contentSrc, note.getContent())){ doneMenuItem.setVisible(false); return; } doneMenuItem.setVisible(true); }else{ doneMenuItem.setVisible(false); } } @Override public void afterTextChanged(Editable s) { } } class SimpleOnFocusChangeListener implements View.OnFocusChangeListener { @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus && toolbar != null){ toolbar.setTitle(R.string.edit_note); } } } private String getOprTimeLineText(Note note, boolean all){ if (note == null || note.getLogs() == null) return ""; String create = getString(R.string.create); String edit = getString(R.string.edit); StringBuilder sb = new StringBuilder(); if (note.getLogs().getList().size() <= 0){ return ""; } NoteOperateLog log; List logs = note.getLogs().getList(); int size = logs.size(); if (!all){ log = logs.get(size - 1); if (log.getType() == NoteConfig.NOTE_CREATE_OPR){ sb.append(getString(R.string.note_log_text, create, TimeUtils.getTime(log.getTime()))); }else{ sb.append(getString(R.string.note_log_text, edit, TimeUtils.getTime(log.getTime()))); } return sb.toString(); } for (int i=size-1; i>=0; i--){ log = logs.get(i); if (log.getType() == NoteConfig.NOTE_CREATE_OPR){ sb.append(getString(R.string.note_log_text, create, TimeUtils.getTime(log.getTime()))); }else{ sb.append(getString(R.string.note_log_text, edit, TimeUtils.getTime(log.getTime()))); } sb.append("\n"); } return sb.toString(); } private void hideKeyBoard(EditText editText){ InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(editText.getWindowToken(), 0); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/ui/PayActivity.java ================================================ package com.lguipeng.notes.ui; import android.os.Bundle; import android.support.v7.widget.Toolbar; import com.lguipeng.notes.R; import com.lguipeng.notes.module.DataModule; import java.util.Arrays; import java.util.List; import butterknife.InjectView; /** * Created by lgp on 2015/6/1. */ public class PayActivity extends BaseActivity{ @InjectView(R.id.toolbar) Toolbar toolbar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override protected int getLayoutView() { return R.layout.activity_pay; } @Override protected List getModules() { return Arrays.asList(new DataModule()); } @Override protected void initToolbar(){ super.initToolbar(toolbar); toolbar.setTitle(R.string.pay_for_me); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/ui/SettingActivity.java ================================================ package com.lguipeng.notes.ui; import android.os.Bundle; import android.support.v7.widget.Toolbar; import com.lguipeng.notes.R; import com.lguipeng.notes.module.DataModule; import com.lguipeng.notes.ui.fragments.SettingFragment; import java.util.Arrays; import java.util.List; import butterknife.InjectView; /** * Created by lgp on 2015/5/24. */ public class SettingActivity extends BaseActivity{ @InjectView(R.id.toolbar) Toolbar toolbar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); init(); } @Override protected int getLayoutView() { return R.layout.activity_setting; } @Override protected List getModules() { return Arrays.asList(new DataModule()); } @Override protected void initToolbar(){ super.initToolbar(toolbar); toolbar.setTitle(R.string.setting); } private void init(){ SettingFragment settingFragment = SettingFragment.newInstance(); getFragmentManager().beginTransaction().replace(R.id.fragment_content, settingFragment).commit(); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/ui/fragments/BaseFragment.java ================================================ package com.lguipeng.notes.ui.fragments; import android.os.Bundle; import android.preference.PreferenceFragment; import android.support.v7.app.AlertDialog; import com.lguipeng.notes.App; import com.lguipeng.notes.R; import com.lguipeng.notes.ui.BaseActivity; import com.lguipeng.notes.utils.PreferenceUtils; import com.lguipeng.notes.utils.ThemeUtils; import java.util.List; import dagger.ObjectGraph; /** * Created by lgp on 2015/5/26. */ public abstract class BaseFragment extends PreferenceFragment { private ObjectGraph activityGraph; protected BaseActivity activity; protected PreferenceUtils preferenceUtils; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); activityGraph = ((App) getActivity().getApplication()).createScopedGraph(getModules().toArray()); activityGraph.inject(this); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (getActivity() != null && getActivity() instanceof BaseActivity){ activity = (BaseActivity)getActivity(); } preferenceUtils = PreferenceUtils.getInstance(getActivity()); } @Override public void onDestroy() { super.onDestroy(); activityGraph = null; } protected AlertDialog.Builder generateDialogBuilder(){ ThemeUtils.Theme theme = getCurrentTheme(); AlertDialog.Builder builder; switch (theme){ case BROWN: builder = new AlertDialog.Builder(getActivity(), R.style.BrownDialogTheme); break; case BLUE: builder = new AlertDialog.Builder(getActivity(), R.style.BlueDialogTheme); break; case BLUE_GREY: builder = new AlertDialog.Builder(getActivity(), R.style.BlueGreyDialogTheme); break; default: builder = new AlertDialog.Builder(getActivity(), R.style.RedDialogTheme); break; } return builder; } protected ThemeUtils.Theme getCurrentTheme(){ int value = preferenceUtils.getIntParam(getString(R.string.change_theme_key), 0); return ThemeUtils.Theme.mapValueToTheme(value); } protected abstract List getModules(); } ================================================ FILE: app/src/main/java/com/lguipeng/notes/ui/fragments/SettingFragment.java ================================================ package com.lguipeng.notes.ui.fragments; import android.content.ActivityNotFoundException; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Bundle; import android.preference.PreferenceScreen; import android.support.v7.app.AlertDialog; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.widget.AdapterView; import android.widget.GridView; import com.jenzz.materialpreference.CheckBoxPreference; import com.jenzz.materialpreference.Preference; import com.jenzz.materialpreference.SwitchPreference; import com.lguipeng.notes.R; import com.lguipeng.notes.adpater.ColorsListAdapter; import com.lguipeng.notes.module.DataModule; import com.lguipeng.notes.ui.PayActivity; import com.lguipeng.notes.utils.AccountUtils; import com.lguipeng.notes.utils.NoteConfig; import com.lguipeng.notes.utils.PreferenceUtils; import com.lguipeng.notes.utils.ThemeUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import de.greenrobot.event.EventBus; /** * Created by lgp on 2015/5/26. */ public class SettingFragment extends BaseFragment{ public static final String PREFERENCE_FILE_NAME = "note.settings"; private CheckBoxPreference showNoteHistoryLogCheckBox; private SwitchPreference rightHandModeSwitch; private Preference feedbackPreference; private Preference payMePreference; private Preference giveFavorPreference; private Preference accountPreference; private boolean showNoteHistoryLog; private boolean rightHandMode; private boolean cardLayout; private List accountItems = new ArrayList<>(); private PreferenceUtils preferenceUtils; public static SettingFragment newInstance(){ SettingFragment fragment = new SettingFragment(); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); preferenceUtils = PreferenceUtils.getInstance(getActivity()); addPreferencesFromResource(R.xml.prefs); getPreferenceManager().setSharedPreferencesName(PREFERENCE_FILE_NAME); showNoteHistoryLog = preferenceUtils.getBooleanParam(getString(R.string.show_note_history_log_key)); rightHandMode = preferenceUtils.getBooleanParam(getString(R.string.right_hand_mode_key)); showNoteHistoryLogCheckBox = (CheckBoxPreference)findPreference(getString(R.string.show_note_history_log_key)); showNoteHistoryLogCheckBox.setChecked(showNoteHistoryLog); rightHandModeSwitch = (SwitchPreference)findPreference(getString(R.string.right_hand_mode_key)); rightHandModeSwitch.setChecked(rightHandMode); cardLayout = preferenceUtils.getBooleanParam(getString(R.string.card_note_item_layout_key), true); CheckBoxPreference cardLayoutPreference = (CheckBoxPreference)findPreference(getString(R.string.card_note_item_layout_key)); cardLayoutPreference.setChecked(cardLayout); feedbackPreference = (Preference)findPreference(getString(R.string.advice_feedback_key)); accountPreference = (Preference)findPreference(getString(R.string.sync_account_key)); payMePreference = (Preference)findPreference(getString(R.string.pay_for_me_key)); giveFavorPreference = (Preference)findPreference(getString(R.string.give_favor_key)); initFeedbackPreference(); initAccountPreference(); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); View listView = view.findViewById(android.R.id.list); listView.setHorizontalScrollBarEnabled(false); listView.setVerticalScrollBarEnabled(false); } public SettingFragment() { super(); } @Override public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, android.preference.Preference preference) { if (preference == null) return super.onPreferenceTreeClick(preferenceScreen, preference); String key = preference.getKey(); if (TextUtils.equals(key, getString(R.string.right_hand_mode_key))){ rightHandMode = !rightHandMode; preferenceUtils.saveParam(getString(R.string.right_hand_mode_key), rightHandMode); } if (TextUtils.equals(key, getString(R.string.card_note_item_layout_key))){ cardLayout = !cardLayout; preferenceUtils.saveParam(getString(R.string.card_note_item_layout_key), cardLayout); } if (TextUtils.equals(key, getString(R.string.show_note_history_log_key))){ showNoteHistoryLog = !showNoteHistoryLog; preferenceUtils.saveParam(getString(R.string.show_note_history_log_key), showNoteHistoryLog); } if (TextUtils.equals(key, getString(R.string.change_theme_key))){ showThemeChooseDialog(); } if (TextUtils.equals(key, getString(R.string.pay_for_me_key))){ Intent intent = new Intent(getActivity(), PayActivity.class); startActivity(intent); } if (TextUtils.equals(key, getString(R.string.give_favor_key))){ giveFavor(); } return super.onPreferenceTreeClick(preferenceScreen, preference); } @Override protected List getModules() { return Arrays.asList(new DataModule()); } private void initFeedbackPreference(){ Uri uri = Uri.parse("mailto:lgpszu@163.com"); final Intent intent = new Intent(Intent.ACTION_SENDTO, uri); PackageManager pm = getActivity().getPackageManager(); List infos = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); if (infos == null || infos.size() <= 0){ feedbackPreference.setSummary(getString(R.string.no_email_app_tip)); return; } feedbackPreference.setOnPreferenceClickListener(new android.preference.Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(android.preference.Preference preference) { startActivity(intent); return true; } }); } private void initAccountPreference(){ AccountUtils.findValidAccount(getActivity(), new AccountUtils.AccountFinderListener() { @Override protected void onNone() { accountPreference.setSummary(getString(R.string.no_account_tip)); } @Override protected void onOne(String account) { accountPreference.setSummary(account); preferenceUtils.saveParam(getString(R.string.sync_account_key), account); } @Override protected void onMore(List items) { SettingFragment.this.accountItems = items; String account = preferenceUtils.getStringParam(getString(R.string.sync_account_key)); if (!isHasAccountSave()) { accountPreference.setSummary(getString(R.string.multi_account_choose_tip)); } else { accountPreference.setSummary(account); } accountPreference.setOnPreferenceClickListener(new android.preference.Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(android.preference.Preference preference) { showAccountChooseDialog(accountItems.toArray(new String[accountItems.size()])); return true; } }); } }); } private void showThemeChooseDialog(){ AlertDialog.Builder builder = generateDialogBuilder(); builder.setTitle(R.string.change_theme); Integer[] res = new Integer[]{R.drawable.red_round, R.drawable.brown_round, R.drawable.blue_round, R.drawable.blue_grey_round, R.drawable.yellow_round, R.drawable.deep_purple_round, R.drawable.pink_round, R.drawable.green_round}; List list = Arrays.asList(res); ColorsListAdapter adapter = new ColorsListAdapter(getActivity(), list); adapter.setCheckItem(getCurrentTheme().getIntValue()); GridView gridView = (GridView)LayoutInflater.from(getActivity()).inflate(R.layout.colors_panel_layout, null); gridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH); gridView.setCacheColorHint(0); gridView.setAdapter(adapter); builder.setView(gridView); final AlertDialog dialog = builder.show(); gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { dialog.dismiss(); int value = getCurrentTheme().getIntValue(); if (value != position){ preferenceUtils.saveParam(getString(R.string.change_theme_key), position); changeTheme(ThemeUtils.Theme.mapValueToTheme(position)); } } }); } private void showAccountChooseDialog(final CharSequence[] text){ AlertDialog.Builder builder = generateDialogBuilder(); builder.setTitle(R.string.choose_account); builder.setItems(text, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { accountPreference.setSummary(text[which]); String account = preferenceUtils.getStringParam(getString(R.string.sync_account_key)); if (TextUtils.equals(account, text[which])) return; preferenceUtils.saveParam(getString(R.string.sync_account_key), text[which].toString()); } }); builder.show(); } private void giveFavor(){ try{ Uri uri = Uri.parse("market://details?id="+ getActivity().getPackageName()); Intent intent = new Intent(Intent.ACTION_VIEW, uri); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); }catch(ActivityNotFoundException e){ e.printStackTrace(); } } private void changeTheme(ThemeUtils.Theme theme){ if (activity == null) return; //ThemeUtils.changTheme(activity, theme); //activity.recreate(); EventBus.getDefault().post(NoteConfig.CHANGE_THEME_EVENT); activity.finish(); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/utils/AccountUtils.java ================================================ package com.lguipeng.notes.utils; import android.accounts.Account; import android.accounts.AccountManager; import android.content.Context; import android.text.TextUtils; import android.util.Patterns; import com.lguipeng.notes.R; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; /** * Created by lgp on 2015/5/29. */ public class AccountUtils { private static final String EMAIL_TYPE = "com.android.email"; public static void findValidAccount(Context context, AccountFinderListener listener){ if (listener == null) return; String accountString = PreferenceUtils.getInstance(context).getStringParam(context.getString(R.string.sync_account_key)); if (!TextUtils.isEmpty(accountString)){ listener.setHasAccountSave(true); } Pattern emailPattern = Patterns.EMAIL_ADDRESS; Account[] accounts = AccountManager.get(context.getApplicationContext()).getAccounts(); List accountItems = new ArrayList<>(); for (Account account : accounts) { if (emailPattern.matcher(account.name).matches() && TextUtils.equals(EMAIL_TYPE, account.type)) { accountItems.add(account.name); } } if (accountItems.size() <= 0){ if (listener.isHasAccountSave()){ listener.onOne(accountString); return; } listener.onNone(); } if (accountItems.size() == 1){ if (listener.isHasAccountSave()){ listener.onOne(accountString); return; } listener.onOne(accountItems.get(0)); } if (accountItems.size() > 1){ listener.onMore(accountItems); } } public static abstract class AccountFinderListener{ private boolean hasAccountSave = false; protected abstract void onNone(); protected abstract void onOne(String account); protected abstract void onMore(List accountItems); public boolean isHasAccountSave() { return hasAccountSave; } public void setHasAccountSave(boolean hasAccountSave) { this.hasAccountSave = hasAccountSave; } } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/utils/JsonUtils.java ================================================ package com.lguipeng.notes.utils; import android.text.TextUtils; import com.alibaba.fastjson.JSON; import com.lguipeng.notes.model.Note; import com.lguipeng.notes.model.NoteType; import java.util.List; /** * Created by lgp on 2015/5/28. */ public class JsonUtils { public static String json(T note){ if (note == null) return ""; try { return JSON.toJSONString(note); }catch (Exception e){ e.printStackTrace(); return ""; } } public static T parse(String json, Class clazz){ if (TextUtils.isEmpty(json)) return null; try { return JSON.parseObject(json, clazz); }catch (Exception e){ e.printStackTrace(); return null; } } public static Note parseNote(String json){ return parse(json, Note.class); } public static String jsonNote(Note note){ return json(note); } public static List parseNoteType(String json){ NoteType type = parse(json, NoteType.class); if (type == null) return null; return type.getTypes(); } public static String jsonNoteType(NoteType type){ return json(type); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/utils/NoteConfig.java ================================================ package com.lguipeng.notes.utils; /** * Created by lgp on 2015/5/25. */ public class NoteConfig { public final static int NOTE_CREATE_OPR = 0x00; public final static int NOTE_EDIT_OPR = 0x01; public final static int NOTE_STUDY_TYPE = 0x00; public final static int NOTE_WORK_TYPE = 0x01; public final static int NOTE_OTHER_TYPE = 0x02; public final static int NOTE_TRASH_TYPE = 0x03; public final static int NOTE_UPDATE_EVENT = 0x00; public final static int NOTE_TYPE_UPDATE_EVENT = 0x01; public final static int CHANGE_THEME_EVENT = 0x02; } ================================================ FILE: app/src/main/java/com/lguipeng/notes/utils/NotesLog.java ================================================ /*** This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. For more information, please refer to */ package com.lguipeng.notes.utils; import android.util.Log; import com.lguipeng.notes.BuildConfig; /** * @date 21.06.2012 * @author Mustafa Ferhan Akman * * Create a simple and more understandable Android logs. * */ public class NotesLog{ static String className; static String methodName; static int lineNumber; private NotesLog(){ /* Protect from instantiations */ } public static boolean isDebuggable() { return BuildConfig.DEBUG; } private static String createLog( String log ) { StringBuffer buffer = new StringBuffer(); buffer.append("["); buffer.append(methodName); buffer.append(":"); buffer.append(lineNumber); buffer.append("]"); buffer.append(log); return buffer.toString(); } private static void getMethodNames(StackTraceElement[] sElements){ className = sElements[1].getFileName(); methodName = sElements[1].getMethodName(); lineNumber = sElements[1].getLineNumber(); } public static void e(String message){ if (!isDebuggable()) return; // Throwable instance must be created before any methods getMethodNames(new Throwable().getStackTrace()); Log.e(className, createLog(message)); } public static void i(String message){ if (!isDebuggable()) return; getMethodNames(new Throwable().getStackTrace()); Log.i(className, createLog(message)); } public static void d(String message){ if (!isDebuggable()) return; getMethodNames(new Throwable().getStackTrace()); Log.d(className, createLog(message)); } public static void d(){ d(""); } public static void v(String message){ if (!isDebuggable()) return; getMethodNames(new Throwable().getStackTrace()); Log.v(className, createLog(message)); } public static void w(String message){ if (!isDebuggable()) return; getMethodNames(new Throwable().getStackTrace()); Log.w(className, createLog(message)); } public static void wtf(String message){ if (!isDebuggable()) return; getMethodNames(new Throwable().getStackTrace()); Log.wtf(className, createLog(message)); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/utils/PreferenceUtils.java ================================================ package com.lguipeng.notes.utils; import android.content.Context; import android.content.SharedPreferences; import com.lguipeng.notes.ui.fragments.SettingFragment; /** * Created by lgp on 2014/10/30. */ public class PreferenceUtils{ private SharedPreferences sharedPreferences; private SharedPreferences.Editor shareEditor; private static PreferenceUtils preferenceUtils = null; public static final String NOTE_TYPE_KEY = "NOTE_TYPE_KEY"; private PreferenceUtils(Context context){ sharedPreferences = context.getSharedPreferences(SettingFragment.PREFERENCE_FILE_NAME, Context.MODE_PRIVATE); shareEditor = sharedPreferences.edit(); } public static PreferenceUtils getInstance(Context context){ if (preferenceUtils == null) { synchronized (PreferenceUtils.class) { if (preferenceUtils == null) { preferenceUtils = new PreferenceUtils(context.getApplicationContext()); } } } return preferenceUtils; } public String getStringParam(String key){ return getStringParam(key, ""); } public String getStringParam(String key, String defaultString){ return sharedPreferences.getString(key, defaultString); } public void saveParam(String key, String value) { shareEditor.putString(key,value).commit(); } public boolean getBooleanParam(String key){ return getBooleanParam(key, false); } public boolean getBooleanParam(String key, boolean defaultBool){ return sharedPreferences.getBoolean(key, defaultBool); } public void saveParam(String key, boolean value){ shareEditor.putBoolean(key, value).commit(); } public int getIntParam(String key){ return getIntParam(key, 0); } public int getIntParam(String key, int defaultInt){ return sharedPreferences.getInt(key, defaultInt); } public void saveParam(String key, int value){ shareEditor.putInt(key, value).commit(); } public long getLongParam(String key){ return getLongParam(key, 0); } public long getLongParam(String key, long defaultInt){ return sharedPreferences.getLong(key, defaultInt); } public void saveParam(String key, long value){ shareEditor.putLong(key, value).commit(); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/utils/SnackbarUtils.java ================================================ package com.lguipeng.notes.utils; import android.app.Activity; import android.graphics.Color; import com.lguipeng.notes.ui.BaseActivity; import com.nispok.snackbar.Snackbar; import com.nispok.snackbar.SnackbarManager; /** * Author: lgp * Date: 2014/12/31. */ public class SnackbarUtils { public static void show(Activity activity, int message) { // Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show(); // Toast toast = new Toast(mContext); // View view = LayoutInflater.from(mContext).inflate(R.layout.toast_layout, null, false); // TextView textView = (TextView)view.findViewById(R.id.toast_text); // textView.setText(message); // toast.setView(view); // toast.setDuration(Toast.LENGTH_SHORT); // toast.show(); int color = Color.BLACK; if (activity instanceof BaseActivity){ color = (((BaseActivity) activity)).getColorPrimary(); } color = color & 0xddffffff; SnackbarManager.show( Snackbar.with(activity.getApplicationContext()) .color(color) .duration((Snackbar.SnackbarDuration.LENGTH_SHORT.getDuration() / 2)) .text(message), activity); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/utils/ThemeUtils.java ================================================ package com.lguipeng.notes.utils; import android.app.Activity; import com.lguipeng.notes.R; /** * Created by lgp on 2015/6/7. */ public class ThemeUtils { public static void changTheme(Activity activity, Theme theme){ if (activity == null) return; int style = R.style.RedTheme; switch (theme){ case BROWN: style = R.style.BrownTheme; break; case BLUE: style = R.style.BlueTheme; break; case BLUE_GREY: style = R.style.BlueGreyTheme; break; case YELLOW: style = R.style.YellowTheme; break; case DEEP_PURPLE: style = R.style.DeepPurpleTheme; break; case PINK: style = R.style.PinkTheme; break; case GREEN: style = R.style.GreenTheme; break; default: break; } activity.setTheme(style); } public enum Theme{ RED(0x00), BROWN(0x01), BLUE(0x02), BLUE_GREY(0x03), YELLOW(0x04), DEEP_PURPLE(0x05), PINK(0x06), GREEN(0x07); private int mValue; Theme(int value){ this.mValue = value; } public static Theme mapValueToTheme(final int value) { for (Theme theme : Theme.values()) { if (value == theme.getIntValue()) { return theme; } } // If run here, return default return RED; } static Theme getDefault() { return RED; } public int getIntValue() { return mValue; } } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/utils/TimeUtils.java ================================================ package com.lguipeng.notes.utils; import android.content.Context; import com.lguipeng.notes.R; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by lgp on 2015/5/25. */ public class TimeUtils { public static final long DAY_Millis = 24 * 60 * 60 * 1000; public static final long MONTH_Millis = 30 * DAY_Millis; public static final long YEAR_Millis = 365 * DAY_Millis; public static final SimpleDateFormat DEFAULT_DATE_FORMAT = new SimpleDateFormat("yyyy.MM.dd HH : mm"); public static final SimpleDateFormat DATE_FORMAT_DATE_1 = new SimpleDateFormat(" HH : mm "); private TimeUtils() { throw new AssertionError(); } /** * long time to string * * @param timeInMillis * @param dateFormat * @return */ public static String getTime(long timeInMillis, SimpleDateFormat dateFormat) { return dateFormat.format(new Date(timeInMillis)); } /** * long time to string, format is {@link #DEFAULT_DATE_FORMAT} * * @param timeInMillis * @return */ public static String getTime(long timeInMillis) { return getTime(timeInMillis, DEFAULT_DATE_FORMAT); } @SuppressWarnings("Deprecated") public static String getConciseTime(long timeInMillis, long nowInMillis, Context context) { if (context == null) return ""; Date date = new Date(timeInMillis); Date now = new Date(nowInMillis); if (now.getYear() == date.getYear()) { if (now.getMonth() == date.getMonth()) { if (now.getDate() == date.getDate()) return context.getString(R.string.today, getTime(timeInMillis, DATE_FORMAT_DATE_1)); else{ return context.getString(R.string.before_day, now.getDate() - date.getDate()); } }else { return context.getString(R.string.before_month, now.getMonth() - date.getMonth()); } } return context.getString(R.string.before_year, now.getYear() - date.getYear()); } public static String getConciseTime(long timeInMillis, Context context) { return getConciseTime(timeInMillis, getCurrentTimeInLong(), context); } /** * get current time in milliseconds * * @return */ public static long getCurrentTimeInLong() { return System.currentTimeMillis(); } /** * get current time in milliseconds, format is {@link #DEFAULT_DATE_FORMAT} * * @return */ public static String getCurrentTimeInString() { return getTime(getCurrentTimeInLong()); } /** * get current time in milliseconds * * @return */ public static String getCurrentTimeInString(SimpleDateFormat dateFormat) { return getTime(getCurrentTimeInLong(), dateFormat); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/utils/ViewHelper.java ================================================ package com.lguipeng.notes.utils; import android.support.v4.view.ViewCompat; import android.view.View; /** * Created by lgp on 2015/5/27. */ public class ViewHelper { public static void clear(View v) { ViewCompat.setAlpha(v, 1); ViewCompat.setScaleY(v, 1); ViewCompat.setScaleX(v, 1); ViewCompat.setTranslationY(v, 0); ViewCompat.setTranslationX(v, 0); ViewCompat.setRotation(v, 0); ViewCompat.setRotationY(v, 0); ViewCompat.setRotationX(v, 0); // @TODO https://code.google.com/p/android/issues/detail?id=80863 // ViewCompat.setPivotY(v, v.getMeasuredHeight() / 2); v.setPivotY(v.getMeasuredHeight() / 2); ViewCompat.setPivotX(v, v.getMeasuredWidth() / 2); ViewCompat.animate(v).setInterpolator(null); } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/utils/WXUtils.java ================================================ package com.lguipeng.notes.utils; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import junit.framework.Assert; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; public class WXUtils { public static byte[] bmpToByteArray(final Bitmap bmp, final boolean needRecycle) { ByteArrayOutputStream output = new ByteArrayOutputStream(); bmp.compress(CompressFormat.PNG, 100, output); if (needRecycle) { bmp.recycle(); } byte[] result = output.toByteArray(); try { output.close(); } catch (Exception e) { e.printStackTrace(); } return result; } public static byte[] getHtmlByteArray(final String url) { URL htmlUrl = null; InputStream inStream = null; try { htmlUrl = new URL(url); URLConnection connection = htmlUrl.openConnection(); HttpURLConnection httpConnection = (HttpURLConnection)connection; int responseCode = httpConnection.getResponseCode(); if(responseCode == HttpURLConnection.HTTP_OK){ inStream = httpConnection.getInputStream(); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } byte[] data = inputStreamToByte(inStream); return data; } public static byte[] inputStreamToByte(InputStream is) { try{ ByteArrayOutputStream bytestream = new ByteArrayOutputStream(); int ch; while ((ch = is.read()) != -1) { bytestream.write(ch); } byte imgdata[] = bytestream.toByteArray(); bytestream.close(); return imgdata; }catch(Exception e){ e.printStackTrace(); } return null; } public static byte[] readFromFile(String fileName, int offset, int len) { if (fileName == null) { return null; } File file = new File(fileName); if (!file.exists()) { NotesLog.i("readFromFile: file not found"); return null; } if (len == -1) { len = (int) file.length(); } NotesLog.d("readFromFile : offset = " + offset + " len = " + len + " offset + len = " + (offset + len)); if(offset <0){ NotesLog.e("readFromFile invalid offset:" + offset); return null; } if(len <=0 ){ NotesLog.e("readFromFile invalid len:" + len); return null; } if(offset + len > (int) file.length()){ NotesLog.e("readFromFile invalid file len:" + file.length()); return null; } byte[] b = null; try { RandomAccessFile in = new RandomAccessFile(fileName, "r"); b = new byte[len]; in.seek(offset); in.readFully(b); in.close(); } catch (Exception e) { NotesLog.e("readFromFile : errMsg = " + e.getMessage()); e.printStackTrace(); } return b; } private static final int MAX_DECODE_PICTURE_SIZE = 1920 * 1440; public static Bitmap extractThumbNail(final String path, final int height, final int width, final boolean crop) { Assert.assertTrue(path != null && !path.equals("") && height > 0 && width > 0); BitmapFactory.Options options = new BitmapFactory.Options(); try { options.inJustDecodeBounds = true; Bitmap tmp = BitmapFactory.decodeFile(path, options); if (tmp != null) { tmp.recycle(); tmp = null; } NotesLog.d("extractThumbNail: round=" + width + "x" + height + ", crop=" + crop); final double beY = options.outHeight * 1.0 / height; final double beX = options.outWidth * 1.0 / width; NotesLog.d("extractThumbNail: extract beX = " + beX + ", beY = " + beY); options.inSampleSize = (int) (crop ? (beY > beX ? beX : beY) : (beY < beX ? beX : beY)); if (options.inSampleSize <= 1) { options.inSampleSize = 1; } // NOTE: out of memory error while (options.outHeight * options.outWidth / options.inSampleSize > MAX_DECODE_PICTURE_SIZE) { options.inSampleSize++; } int newHeight = height; int newWidth = width; if (crop) { if (beY > beX) { newHeight = (int) (newWidth * 1.0 * options.outHeight / options.outWidth); } else { newWidth = (int) (newHeight * 1.0 * options.outWidth / options.outHeight); } } else { if (beY < beX) { newHeight = (int) (newWidth * 1.0 * options.outHeight / options.outWidth); } else { newWidth = (int) (newHeight * 1.0 * options.outWidth / options.outHeight); } } options.inJustDecodeBounds = false; NotesLog.i("bitmap required size=" + newWidth + "x" + newHeight + ", orig=" + options.outWidth + "x" + options.outHeight + ", sample=" + options.inSampleSize); Bitmap bm = BitmapFactory.decodeFile(path, options); if (bm == null) { NotesLog.e("bitmap decode failed"); return null; } NotesLog.i("bitmap decoded size=" + bm.getWidth() + "x" + bm.getHeight()); final Bitmap scale = Bitmap.createScaledBitmap(bm, newWidth, newHeight, true); if (scale != null) { bm.recycle(); bm = scale; } if (crop) { final Bitmap cropped = Bitmap.createBitmap(bm, (bm.getWidth() - width) >> 1, (bm.getHeight() - height) >> 1, width, height); if (cropped == null) { return bm; } bm.recycle(); bm = cropped; NotesLog.i("bitmap croped size=" + bm.getWidth() + "x" + bm.getHeight()); } return bm; } catch (final OutOfMemoryError e) { NotesLog.e("decode bitmap failed: " + e.getMessage()); options = null; } return null; } } ================================================ FILE: app/src/main/java/com/lguipeng/notes/view/FixedRecyclerView.java ================================================ package com.lguipeng.notes.view; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; /** * Created by lgp on 2015/6/11. */ public class FixedRecyclerView extends RecyclerView { public FixedRecyclerView(Context context) { super(context); } public FixedRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } public FixedRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean canScrollVertically(int direction) { // check if scrolling up if (direction < 1) { boolean original = super.canScrollVertically(direction); return !original && getChildAt(0) != null && getChildAt(0).getTop() < 0 || original; } return super.canScrollVertically(direction); } } ================================================ FILE: app/src/main/res/drawable/activated_background.xml ================================================ ================================================ FILE: app/src/main/res/drawable/blue_grey_round.xml ================================================ ================================================ FILE: app/src/main/res/drawable/blue_round.xml ================================================ ================================================ FILE: app/src/main/res/drawable/brown_round.xml ================================================ ================================================ FILE: app/src/main/res/drawable/deep_purple_round.xml ================================================ ================================================ FILE: app/src/main/res/drawable/green_round.xml ================================================ ================================================ FILE: app/src/main/res/drawable/pink_round.xml ================================================ ================================================ FILE: app/src/main/res/drawable/red_round.xml ================================================ ================================================ FILE: app/src/main/res/drawable/selectable_background.xml ================================================ ================================================ FILE: app/src/main/res/drawable/toolbar_shadow.xml ================================================ ================================================ FILE: app/src/main/res/drawable/white_button_background.xml ================================================ ================================================ FILE: app/src/main/res/drawable/yellow_round.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_about.xml ================================================