package yuku.alkitab.base.ac; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Point; import android.os.Bundle; import android.support.v7.app.ActionBar; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import com.afollestad.materialdialogs.MaterialDialog; import com.mobeta.android.dslv.DragSortController; import com.mobeta.android.dslv.DragSortListView; import yuku.afw.D; import yuku.afw.V; import yuku.afw.storage.Preferences; import yuku.alkitab.base.App; import yuku.alkitab.base.S; import yuku.alkitab.base.U; import yuku.alkitab.base.ac.base.BaseActivity; import yuku.alkitab.base.dialog.LabelEditorDialog; import yuku.alkitab.base.sync.SyncSettingsActivity; import yuku.alkitab.base.util.BookmarkImporter; import yuku.alkitab.debug.R; import yuku.alkitab.model.Label; import yuku.alkitab.model.Marker; import yuku.ambilwarna.AmbilWarnaDialog; import yuku.ambilwarna.AmbilWarnaDialog.OnAmbilWarnaListener; import yuku.filechooser.FileChooserActivity; import yuku.filechooser.FileChooserConfig; import yuku.filechooser.FileChooserResult; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.List; public class MarkersActivity extends BaseActivity { public static final String TAG = MarkersActivity.class.getSimpleName(); private static final int REQCODE_markerList = 1; private static final int REQCODE_share = 2; private static final int REQCODE_migrateFromV3 = 3; /** Action to broadcast when label list needs to be reloaded due to some background changes */ public static final String ACTION_RELOAD = MarkersActivity.class.getName() + ".action.RELOAD"; DragSortListView lv; View bGotoSync; MarkerFilterAdapter adapter; public static Intent createIntent() { return new Intent(App.context, MarkersActivity.class); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_markers); final Toolbar toolbar = V.get(this, R.id.toolbar); setSupportActionBar(toolbar); final ActionBar ab = getSupportActionBar(); assert ab != null; ab.setDisplayHomeAsUpEnabled(true); adapter = new MarkerFilterAdapter(); adapter.reload(); lv = V.get(this, android.R.id.list); lv.setDropListener(adapter); lv.setOnItemClickListener(lv_click); lv.setAdapter(adapter); MarkerFilterController c = new MarkerFilterController(lv, adapter); lv.setFloatViewManager(c); lv.setOnTouchListener(c); registerForContextMenu(lv); bGotoSync = V.get(this, R.id.bGotoSync); bGotoSync.setOnClickListener(v -> startActivity(SyncSettingsActivity.createIntent())); App.getLbm().registerReceiver(br, new IntentFilter(ACTION_RELOAD)); } @Override protected void onStart() { super.onStart(); // hide sync button if we are already syncing final String syncAccountName = Preferences.getString(R.string.pref_syncAccountName_key); V.get(this, R.id.panelGotoSync).setVisibility(syncAccountName != null ? View.GONE : View.VISIBLE); } @Override public boolean onCreateOptionsMenu(final Menu menu) { getMenuInflater().inflate(R.menu.activity_markers, menu); return true; } @Override public boolean onPrepareOptionsMenu(final Menu menu) { final MenuItem menuLabelSort = menu.findItem(R.id.menuLabelSort); final int labelCount = adapter.getLabelCount(); menuLabelSort.setVisible(labelCount > 1); return true; } @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case R.id.menuMigrateFromV3: { final FileChooserConfig config = new FileChooserConfig(); config.mode = FileChooserConfig.Mode.Open; config.pattern = "(yuku\\.alkitab|yuku\\.alkitab\\.kjv|org\\.sabda\\.alkitab|org\\.sabda\\.online)-(backup|autobackup-[0-9-]+)\\.xml"; config.title = getString(R.string.marker_migrate_file_chooser_title); final Intent intent = FileChooserActivity.createIntent(this, config); startActivityForResult(intent, REQCODE_migrateFromV3); } return true; case R.id.menuLabelSort: S.getDb().sortLabelsAlphabetically(); adapter.reload(); return true; } return super.onOptionsItemSelected(item); } @Override protected void onDestroy() { super.onDestroy(); App.getLbm().unregisterReceiver(br); } BroadcastReceiver br = new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { if (ACTION_RELOAD.equals(intent.getAction())) { adapter.reload(); } } }; private OnItemClickListener lv_click = new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View v, int position, long id) { Intent intent; if (position == 0) { intent = MarkerListActivity.createIntent(App.context, Marker.Kind.bookmark, 0); } else if (position == 1) { intent = MarkerListActivity.createIntent(App.context, Marker.Kind.note, 0); } else if (position == 2) { intent = MarkerListActivity.createIntent(App.context, Marker.Kind.highlight, 0); } else if (position == 3) { intent = MarkerListActivity.createIntent(App.context, Marker.Kind.bookmark, MarkerListActivity.LABELID_noLabel); } else { Label label = adapter.getItem(position); if (label != null) { intent = MarkerListActivity.createIntent(getApplicationContext(), Marker.Kind.bookmark, label._id); } else { return; } } startActivityForResult(intent, REQCODE_markerList); } }; @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; if (info.position >= 4) { getMenuInflater().inflate(R.menu.context_markers, menu); } } @Override public boolean onContextItemSelected(android.view.MenuItem item) { final AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); int itemId = item.getItemId(); if (itemId == R.id.menuRenameLabel) { final Label label = adapter.getItem(info.position); if (label == null) { return true; } LabelEditorDialog.show(this, label.title, getString(R.string.rename_label_title), title -> { label.title = title; S.getDb().insertOrUpdateLabel(label); adapter.notifyDataSetChanged(); }); return true; } else if (itemId == R.id.menuDeleteLabel) { final Label label = adapter.getItem(info.position); if (label == null) { return true; } final int marker_count = S.getDb().countMarkersWithLabel(label); if (marker_count == 0) { // no markers, just delete straight away S.getDb().deleteLabelAndMarker_LabelsByLabelId(label._id); adapter.reload(); } else { new MaterialDialog.Builder(this) .content(getString(R.string.are_you_sure_you_want_to_delete_the_label_label, label.title, marker_count)) .negativeText(R.string.cancel) .positiveText(R.string.delete) .onPositive((dialog, which) -> { S.getDb().deleteLabelAndMarker_LabelsByLabelId(label._id); adapter.reload(); }) .show(); } return true; } else if (itemId == R.id.menuChangeLabelColor) { final Label label = adapter.getItem(info.position); if (label == null) { return true; } int warnaLatarRgb = U.decodeLabelBackgroundColor(label.backgroundColor); new AmbilWarnaDialog(MarkersActivity.this, 0xff000000 | warnaLatarRgb, new OnAmbilWarnaListener() { @Override public void onOk(AmbilWarnaDialog dialog, int color) { label.backgroundColor = U.encodeLabelBackgroundColor(0x00ffffff & color); S.getDb().insertOrUpdateLabel(label); adapter.notifyDataSetChanged(); } @Override public void onCancel(AmbilWarnaDialog dialog) { // nop } }).show(); return true; } return false; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQCODE_markerList) { adapter.reload(); return; } else if (requestCode == REQCODE_share && resultCode == RESULT_OK) { final ShareActivity.Result result = ShareActivity.obtainResult(data); startActivity(result.chosenIntent); return; } else if (requestCode == REQCODE_migrateFromV3 && resultCode == RESULT_OK) { final FileChooserResult result = FileChooserActivity.obtainResult(data); if (result != null) { final File file = new File(result.firstFilename); try { final FileInputStream fis = new FileInputStream(file); BookmarkImporter.importBookmarks(this, fis, false, () -> adapter.reload()); } catch (IOException e) { new MaterialDialog.Builder(this) .content(R.string.marker_migrate_error_opening_backup_file) .positiveText(R.string.ok) .show(); } } return; } super.onActivityResult(requestCode, resultCode, data); } private class MarkerFilterController extends DragSortController { int mDivPos; int mDraggedPos; final DragSortListView lv; public MarkerFilterController(DragSortListView lv, MarkerFilterAdapter adapter) { super(lv, R.id.drag_handle, DragSortController.ON_DOWN, 0); this.lv = lv; mDivPos = adapter.getDivPosition(); setRemoveEnabled(false); } @Override public int startDragPosition(MotionEvent ev) { int res = super.dragHandleHitPosition(ev); if (res < mDivPos) { return DragSortController.MISS; } return res; } @Override public View onCreateFloatView(int position) { mDraggedPos = position; final View res = adapter.getView(position, null, lv); res.setBackgroundColor(0x22ffffff); return res; } @Override public void onDestroyFloatView(View floatView) { // Do not call super and do not remove this override. floatView.setBackgroundColor(0); } @Override public void onDragFloatView(View floatView, Point floatPoint, Point touchPoint) { super.onDragFloatView(floatView, floatPoint, touchPoint); final int first = lv.getFirstVisiblePosition(); final int lvDivHeight = lv.getDividerHeight(); View div = lv.getChildAt(mDivPos - first - 1); if (div != null) { if (mDraggedPos >= mDivPos) { // don't allow floating View to go above section divider final int limit = div.getBottom() + lvDivHeight; if (floatPoint.y < limit) { floatPoint.y = limit; } } } } } private class MarkerFilterAdapter extends BaseAdapter implements DragSortListView.DropListener { // 0. [icon] All bookmarks // 1. [icon] Notes // 2. [icon] Highlights // 3. Unlabeled bookmarks // 4 and so on. labels List<Label> labels; private String[] presetCaptions = { getString(R.string.bmcat_all_bookmarks), getString(R.string.bmcat_notes), getString(R.string.bmcat_highlights), getString(R.string.bmcat_unlabeled_bookmarks), }; @Override public Label getItem(int position) { if (position < 4) return null; return labels.get(position - 4); } @Override public long getItemId(int position) { return position; } @Override public void drop(int from, int to) { if (from != to) { Label fromLabel = getItem(from); Label toLabel = getItem(to); if (fromLabel != null && toLabel != null) { S.getDb().reorderLabels(fromLabel, toLabel); adapter.reload(); } } } private boolean hasLabels() { return labels != null && labels.size() > 0; } @Override public int getCount() { return 3 + (hasLabels() ? 1 + labels.size() : 0); } public int getDivPosition() { return 4; } @Override public View getView(int position, View convertView, ViewGroup parent) { final View res = convertView != null? convertView: getLayoutInflater().inflate(R.layout.item_marker_filter, parent, false); ImageView imgFilterIcon = V.get(res, R.id.imgFilterIcon); if (position < 3) { imgFilterIcon.setVisibility(View.VISIBLE); imgFilterIcon.setImageResource(position == 0? R.drawable.ic_attr_bookmark: position == 1? R.drawable.ic_attr_note: position == 2? R.drawable.ic_attr_highlight: 0); } else { imgFilterIcon.setVisibility(View.GONE); } TextView lFilterCaption = V.get(res, R.id.lFilterCaption); if (position < 4) { lFilterCaption.setVisibility(View.VISIBLE); lFilterCaption.setText(presetCaptions[position]); } else { lFilterCaption.setVisibility(View.GONE); } TextView lFilterLabel = V.get(res, R.id.lFilterLabel); if (position < 4) { lFilterLabel.setVisibility(View.GONE); } else { Label label = getItem(position); lFilterLabel.setVisibility(View.VISIBLE); lFilterLabel.setText(label.title); U.applyLabelColor(label, lFilterLabel); } View drag_handle = V.get(res, R.id.drag_handle); if (position < 4) { drag_handle.setVisibility(View.GONE); } else { drag_handle.setVisibility(View.VISIBLE); } return res; } void reload() { labels = S.getDb().listAllLabels(); if (D.EBUG) { Log.d(TAG, "_id title ordering backgroundColor"); for (Label label: labels) { Log.d(TAG, String.format("%4d %20s %8d %s", label._id, label.title, label.ordering, label.backgroundColor)); } } notifyDataSetChanged(); supportInvalidateOptionsMenu(); } public int getLabelCount() { return labels.size(); } } }