package couchbase.kitchensync;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import com.couchbase.lite.CouchbaseLiteException;
import com.couchbase.lite.Database;
import com.couchbase.lite.Document;
import com.couchbase.lite.Emitter;
import com.couchbase.lite.LiveQuery;
import com.couchbase.lite.Manager;
import com.couchbase.lite.Mapper;
import com.couchbase.lite.QueryRow;
import com.couchbase.lite.android.AndroidContext;
import com.couchbase.lite.replicator.Replication;
import com.couchbase.lite.util.Log;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
public class MainActivity extends Activity implements Replication.ChangeListener,
OnItemClickListener, OnItemLongClickListener, OnKeyListener {
private static final String TAG = "MainActivity";
private Manager manager;
private Database database;
private com.couchbase.lite.View viewItemsByDate;
private LiveQuery liveQuery;
private KitchenSyncListAdapter kitchenSyncArrayAdapter;
private ListView itemListView;
private EditText addItemEditText;
//Step 13 - Deploy on device or Deploy on emulator
private static final String SYNC_URL = "http://localhost:4984/kitchen-sync";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
itemListView = (ListView)findViewById(R.id.itemListView);
itemListView.setOnItemClickListener(this);
itemListView.setOnItemLongClickListener(this);
addItemEditText = (EditText)findViewById(R.id.newItemText);
addItemEditText.setOnKeyListener(this);
addItemEditText.requestFocus();
//Couchbase initialization code goes here - See steps 4, 6, 9, and 16.
//Step 4 - Start Couchbase Lite
try {
startCBLite();
} catch (Exception e) {
e.printStackTrace();
}
//Step 6 - Call the 'initItemListAdapter' method
initItemListAdapter();
//Step 9 - Call the 'startLiveQuery' method within the 'onCreate' method
startLiveQuery();
//Step 15 - Call the 'startSync' method within the 'onCreate' method
startSync();
}
//Step 1 - created 'startCBLite' method
protected void startCBLite() throws Exception {
//Step 2 - Get reference to database object
try {
manager = new Manager(new AndroidContext(this), Manager.DEFAULT_OPTIONS);
database = manager.getDatabase("kitchen-sync");
} catch (CouchbaseLiteException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//Step 3 - Create Index to allow for Fast Queries
viewItemsByDate = database.getView("viewItemsByDate");
viewItemsByDate.setMap(new Mapper() {
@Override
public void map(Map<String, Object> document, Emitter emitter) {
Object createdAt = document.get("created_at");
if (createdAt != null) {
emitter.emit(createdAt.toString(), null);
}
}
}, "1.0");
}
@Override
public void changed(Replication.ChangeEvent event) {
Replication replication = event.getSource();
Log.d(TAG, "Replication : " + replication + " changed.");
if (!replication.isRunning()) {
String msg = String.format("Replicator %s not running", replication);
Log.d(TAG, msg);
}
else {
int processed = replication.getCompletedChangesCount();
int total = replication.getChangesCount();
String msg = String.format("Replicator processed %d / %d", processed, total);
Log.d(TAG, msg);
}
}
public boolean onKey(View v, int keyCode, KeyEvent event) {
if ((event.getAction() == KeyEvent.ACTION_DOWN)
&& (keyCode == KeyEvent.KEYCODE_ENTER)) {
String inputText = addItemEditText.getText().toString();
// Don't do anything until our liveQuery is initialized.
if(!inputText.equals("") && liveQuery != null) {
try {
createListItem(inputText);
Toast.makeText(getApplicationContext(), "Created new list item!", Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Error creating document, see logs for details", Toast.LENGTH_LONG).show();
Log.e(TAG, "Error creating document.", e);
}
}
addItemEditText.setText("");
return true;
}
return false;
}
private Document createListItem(String text) throws Exception {
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
UUID uuid = UUID.randomUUID();
Calendar calendar = GregorianCalendar.getInstance();
long currentTime = calendar.getTimeInMillis();
String currentTimeString = dateFormatter.format(calendar.getTime());
String id = currentTime + "-" + uuid.toString();
// Step 7 - Create document from text box's field entry. code replaces this
Document document = database.getDocument(id); // creates a document with the given id
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("_id", id);
properties.put("text", text);
properties.put("check", Boolean.FALSE);
properties.put("created_at", currentTimeString);
document.putProperties(properties);
return document;
}
//Step 5 - Initialize 'DataAdapter' for our list view
private void initItemListAdapter() {
kitchenSyncArrayAdapter = new KitchenSyncListAdapter(
getApplicationContext(),
R.layout.list_item,
R.id.label,
new ArrayList<QueryRow>()
);
itemListView.setAdapter(kitchenSyncArrayAdapter);
itemListView.setOnItemClickListener(this);
itemListView.setOnItemLongClickListener(this);
}
//Step 8 - Create 'startLiveQuery' method to do 'LiveQuery'
private void startLiveQuery() {
if (liveQuery == null) {
liveQuery = viewItemsByDate.createQuery().toLiveQuery();
liveQuery.addChangeListener(new LiveQuery.ChangeListener() {
public void changed(final LiveQuery.ChangeEvent event) {
runOnUiThread(new Runnable() {
public void run() {
kitchenSyncArrayAdapter.clear();
for (Iterator<QueryRow> it = event.getRows(); it.hasNext();) {
kitchenSyncArrayAdapter.add(it.next());
}
kitchenSyncArrayAdapter.notifyDataSetChanged();
}
});
}
});
liveQuery.start();
}
}
//Step 14 - Create startSync() method
private void startSync() {
URL syncUrl;
try {
syncUrl = new URL(SYNC_URL);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
Replication pullReplication = database.createPullReplication(syncUrl);
pullReplication.setContinuous(true);
Replication pushReplication = database.createPushReplication(syncUrl);
pushReplication.setContinuous(true);
pullReplication.start();
pushReplication.start();
pullReplication.addChangeListener(this);
pushReplication.addChangeListener(this);
}
/**
* Handle click on item in list
*/
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
// Step 10 code goes here
// This code handles checkbox touches. Couchbase Lite documents are like versioned-maps.
// To change a Document, add a new Revision.
QueryRow row = (QueryRow) adapterView.getItemAtPosition(position);
Document document = row.getDocument();
Map<String, Object> newProperties = new HashMap<String, Object>(document.getProperties());
boolean checked = ((Boolean) newProperties.get("check")).booleanValue();
newProperties.put("check", !checked);
try {
document.putProperties(newProperties);
kitchenSyncArrayAdapter.notifyDataSetChanged();
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Error updating database, see logs for details", Toast.LENGTH_LONG).show();
Log.e(TAG, "Error updating database", e);
}
}
/**
* Handle long-click on item in list
*/
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int position, long id) {
// Step 11 code goes here - Deleting Items
QueryRow row = (QueryRow) adapterView.getItemAtPosition(position);
final Document clickedDocument = row.getDocument();
String itemText = (String) clickedDocument.getCurrentRevision().getProperty("text");
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
AlertDialog alert = builder.setTitle("Delete Item?")
.setMessage("Are you sure you want to delete \"" + itemText + "\"?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
try {
clickedDocument.delete();
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Error deleting document, see logs for details", Toast.LENGTH_LONG).show();
Log.e(TAG, "Error deleting document", e);
}
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Handle Cancel
}
})
.create();
alert.show();
return true;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.list, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
// if (id == R.id.action_settings) {
// return true;
// }
return super.onOptionsItemSelected(item);
}
}