Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion app/src/main/java/com/kitty/geotracker/MapsActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.google.maps.android.heatmaps.HeatmapTileProvider;
import com.kitty.geotracker.dialogs.JoinSession;
import com.kitty.geotracker.dialogs.StartSession;
import com.kitty.geotracker.dialogs.ViewSession;

import java.util.ArrayList;
import java.util.HashMap;
Expand All @@ -44,11 +45,12 @@ public class MapsActivity extends FragmentActivity implements
View.OnClickListener,
StartSession.StartSessionListener,
JoinSession.JoinSessionListener,
ViewSession.ViewSessionListener,
MeteorController.MeteorControllerListener {

private GoogleMap mMap;
private FloatingActionsMenu floatingMenu;
private FloatingActionButton btnJoinSession, btnStartSession, btnLeaveSession, btnEndSession;
private FloatingActionButton btnJoinSession, btnStartSession, btnLeaveSession, btnEndSession, btnViewSession;
private MeteorController meteorController;
private HashMap<String, Marker> mapMarkers = new HashMap<>();
private Intent serviceIntent;
Expand All @@ -72,13 +74,15 @@ protected void onCreate(Bundle savedInstanceState) {
FloatingActionButton btnSettings = (FloatingActionButton) findViewById(R.id.btn_settings);
btnJoinSession = (FloatingActionButton) findViewById(R.id.btn_join_session);
btnStartSession = (FloatingActionButton) findViewById(R.id.btn_start_session);
btnViewSession = (FloatingActionButton) findViewById(R.id.btn_view_session);
btnLeaveSession = (FloatingActionButton) findViewById(R.id.btn_leave_session);
btnEndSession = (FloatingActionButton) findViewById(R.id.btn_end_session);
btnSettings.setOnClickListener(this);
btnJoinSession.setOnClickListener(this);
btnStartSession.setOnClickListener(this);
btnLeaveSession.setOnClickListener(this);
btnEndSession.setOnClickListener(this);
btnViewSession.setOnClickListener(this);

// Get map fragment and register callback
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
Expand Down Expand Up @@ -124,6 +128,12 @@ public void onClick(View v) {
openJoinSessionDialog();
break;

case R.id.btn_view_session:
// Create the start session dialog
ViewSession viewSession = new ViewSession();
viewSession.show(getSupportFragmentManager(), viewSession.getClass().getSimpleName());
break;

case R.id.btn_leave_session:
leaveSession();
break;
Expand Down Expand Up @@ -284,6 +294,7 @@ public void onSessionManage(String sessionName) {
btnJoinSession.setVisibility(View.GONE);
btnLeaveSession.setVisibility(View.GONE);
btnEndSession.setVisibility(View.VISIBLE);
btnViewSession.setVisibility(View.GONE);

// Keep the screen on
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Expand All @@ -307,6 +318,20 @@ public void onSessionJoined(final String sessionName) {
btnJoinSession.setVisibility(View.GONE);
btnLeaveSession.setVisibility(View.VISIBLE);
btnEndSession.setVisibility(View.GONE);
btnViewSession.setVisibility(View.GONE);
}

@Override
public void onSessionViewed(String sessionName) {
// View the session
meteorController.viewSession(sessionName);

// Hide the start and join session buttons, show the leave session button.
btnStartSession.setVisibility(View.GONE);
btnJoinSession.setVisibility(View.GONE);
btnViewSession.setVisibility(View.GONE);
btnLeaveSession.setVisibility(View.VISIBLE);
btnEndSession.setVisibility(View.GONE);
}

/**
Expand Down Expand Up @@ -359,6 +384,7 @@ public void leaveSession() {
// Hide the leave session button, show the start and join session buttons
btnStartSession.setVisibility(View.VISIBLE);
btnJoinSession.setVisibility(View.VISIBLE);
btnViewSession.setVisibility(View.VISIBLE);
btnLeaveSession.setVisibility(View.GONE);

// Stop location updates
Expand Down Expand Up @@ -413,6 +439,7 @@ public void onSuccess(String result) {
// Hide/show buttons
btnStartSession.setVisibility(View.VISIBLE);
btnJoinSession.setVisibility(View.VISIBLE);
btnViewSession.setVisibility(View.VISIBLE);
btnEndSession.setVisibility(View.GONE);

// Show confirmation
Expand Down
55 changes: 53 additions & 2 deletions app/src/main/java/com/kitty/geotracker/MeteorController.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public class MeteorController implements MeteorCallback, SharedPreferences.OnSha
public static final int STATE_NO_SESSION = 0;
public static final int STATE_CREATED_SESSION = 1;
public static final int STATE_JOINED_SESSION = 2;
public static final int STATE_VIEWING_SESSION = 3;

// Sessions
public static final String COLLECTION_SESSIONS = "Sessions";
Expand Down Expand Up @@ -459,6 +460,46 @@ public void leaveSession() {
clearSession();
}

/**
* View a finished session
*
* @param sessionName Session to view
*/
public void viewSession(final String sessionName) {
Log.d(TAG, "[View Session] Viewing session \"" + sessionName + "\"");
setState(STATE_VIEWING_SESSION);
session = sessionName;
Document document = meteor
.getDatabase()
.getCollection(COLLECTION_SESSIONS)
.whereEqual(COLLECTION_SESSIONS_COLUMN_TITLE, sessionName)
.whereEqual(COLLECTION_SESSIONS_COLUMN_ACTIVE, false)
.findOne();

if (document == null) {
mListener.onSessionMessage("Session cannot be viewed", false);
return;
}

// Subscribe to the session
meteor.subscribe(sessionName, null, new SubscribeListener() {
@Override
public void onSuccess() {
Log.d(TAG, "[View Session] Session viewing successfully.");
}

@Override
public void onError(String error, String reason, String details) {
Log.e(TAG, "[View Session] Failed to view session \"" + sessionName + "\"");
Log.e(TAG, "[View Session] Error: " + error);
Log.e(TAG, "[View Session] Reason: " + reason);
Log.e(TAG, "[View Session] Details: " + details);
clearSession();
mListener.onSessionMessage("Failed to view session", false);
}
});
}

/**
* Clear the current session
*/
Expand All @@ -474,7 +515,17 @@ public void clearSession() {
* @return List of sessions
*/
public Document[] getSessions() {
return database.getCollection(COLLECTION_SESSIONS).whereEqual(COLLECTION_SESSIONS_COLUMN_ACTIVE, true).find();
return getSessions(true);
}

/**
* Get all sessions
*
* @param active Whether the session is active
* @return Session list
*/
public Document[] getSessions(boolean active) {
return database.getCollection(COLLECTION_SESSIONS).whereEqual(COLLECTION_SESSIONS_COLUMN_ACTIVE, active).find();
}

/**
Expand Down Expand Up @@ -565,7 +616,7 @@ public void onDataAdded(String collectionName, String documentID, String newValu

// Only trigger GPS data listener if the user created the session
if (collectionName.equals(COLLECTION_GPS_DATA)) {
if (getState() == STATE_CREATED_SESSION && getSession() != null) {
if ((getState() == STATE_CREATED_SESSION || getState() == STATE_VIEWING_SESSION) && getSession() != null) {
mListener.onReceivedGPSData(documentID);
}
}
Expand Down
170 changes: 170 additions & 0 deletions app/src/main/java/com/kitty/geotracker/dialogs/ViewSession.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package com.kitty.geotracker.dialogs;

import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.widget.ArrayAdapter;

import com.kitty.geotracker.MeteorController;
import com.kitty.geotracker.R;

import java.util.ArrayList;
import java.util.HashMap;

import im.delight.android.ddp.Meteor;
import im.delight.android.ddp.MeteorCallback;
import im.delight.android.ddp.db.Collection;
import im.delight.android.ddp.db.Database;
import im.delight.android.ddp.db.Document;


public class ViewSession extends DialogFragment implements MeteorCallback, DialogInterface.OnClickListener {

private ViewSessionListener mListener;
private Meteor mMeteor;
private MeteorController meteorController;
private Database database;
private ArrayList<String> items = new ArrayList<>();
private HashMap<String, String> documentMap = new HashMap<>();
private ArrayAdapter<String> adapter;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, items);
meteorController = MeteorController.getInstance();
mMeteor = meteorController.getMeteor();
mMeteor.addCallback(this);
database = mMeteor.getDatabase();
refreshData();
}

@Override
public void onDestroy() {
mMeteor.removeCallback(this);
super.onDestroy();
}

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.view_session)
.setAdapter(adapter, this);
return builder.create();
}

@Override
public void onClick(DialogInterface dialog, int which) {
Log.d(getClass().getSimpleName(), "Selected item " + String.valueOf(which));
mListener.onSessionViewed(items.get(which));
}

// Override the Fragment.onAttach() method to instantiate the ViewSessionListener
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Verify that the host activity implements the callback interface
try {
// Instantiate the ViewSessionListener so we can send events to the host
mListener = (ViewSessionListener) activity;
} catch (ClassCastException e) {
// The activity doesn't implement the interface, throw exception
throw new ClassCastException(activity.toString() + " must implement ViewSessionListener");
}
}

/* The activity that creates an instance of this dialog fragment must
* implement this interface in order to receive event callbacks.
* Each method passes the DialogFragment in case the host needs to query it. */
public interface ViewSessionListener {
public void onSessionViewed(final String sessionName);
}

private void refreshData() {
items.clear();
documentMap.clear();
for (Document document : meteorController.getSessions(false)) {
String title = document.getField(MeteorController.COLLECTION_SESSIONS_COLUMN_TITLE).toString();
items.add(title);
documentMap.put(document.getId(), title);
}
}

@Override
public void onConnect(boolean signedInAutomatically) {}

@Override
public void onDisconnect() {}

@Override
public void onException(Exception e) {}

@Override
public void onDataAdded(String collectionName, String documentID, String newValuesJson) {
Log.d(getClass().getSimpleName(), "New data added to " + collectionName + ": " + documentID);
if (collectionName.equals(MeteorController.COLLECTION_SESSIONS)) {
Collection collection = database.getCollection(collectionName);
if (!documentMap.containsKey(documentID)) {
Document document = collection.getDocument(documentID);
boolean active = (boolean) document.getField(MeteorController.COLLECTION_SESSIONS_COLUMN_ACTIVE);

// If this session is active, don't add it to the list
if (active) {
return;
}

String title = document.getField(MeteorController.COLLECTION_SESSIONS_COLUMN_TITLE).toString();
items.add(title);
documentMap.put(documentID, title);
adapter.notifyDataSetChanged();
}
}
}

@Override
public void onDataRemoved(String collectionName, String documentID) {
Log.d(getClass().getSimpleName(), "Data removed from " + collectionName + ": " + documentID);
if (collectionName.equals(MeteorController.COLLECTION_SESSIONS)) {
String title = documentMap.get(documentID);
if (title != null) {
items.remove(title);
documentMap.remove(documentID);
adapter.notifyDataSetChanged();
}
}
}

@Override
public void onDataChanged(String collectionName, String documentID, String updatedValuesJson,
String removedValuesJson) {
Log.d(getClass().getSimpleName(), "Data changed in " + collectionName + ": " + documentID);
if (collectionName.equals(MeteorController.COLLECTION_SESSIONS)) {

Collection collection = database.getCollection(collectionName);
Document document = collection.getDocument(documentID);

boolean active = (boolean) document.getField(MeteorController.COLLECTION_SESSIONS_COLUMN_ACTIVE);
String title = (String) document.getField(MeteorController.COLLECTION_SESSIONS_COLUMN_TITLE);

if (active && !items.contains(title)) {
// Session becomes active
items.remove(title);
documentMap.remove(documentID);
adapter.notifyDataSetChanged();
} else if (!active && items.contains(title)) {
// Session becomes inactive
items.add(title);
documentMap.put(documentID, title);
adapter.notifyDataSetChanged();
}
}
}
}
Loading