saving the last track: implemented a floating action button sub menu instead of a user dialog (#2)

master
y20k 2016-12-12 18:52:01 +01:00
parent c19cf469d3
commit f3909ec3a5
19 changed files with 451 additions and 208 deletions

View File

@ -25,6 +25,7 @@ dependencies {
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:25.0.1' compile 'com.android.support:appcompat-v7:25.0.1'
compile 'com.android.support:design:25.0.1' compile 'com.android.support:design:25.0.1'
compile 'com.android.support:cardview-v7:25.0.1'
compile 'org.osmdroid:osmdroid-android:5.5:release@aar' compile 'org.osmdroid:osmdroid-android:5.5:release@aar'
compile 'com.google.code.gson:gson:2.8.0' compile 'com.google.code.gson:gson:2.8.0'
} }

View File

@ -23,10 +23,12 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.location.Location; import android.location.Location;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton; import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
@ -44,9 +46,9 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast; import android.widget.Toast;
import org.y20k.trackbook.helpers.DialogClearFragment;
import org.y20k.trackbook.helpers.LogHelper; import org.y20k.trackbook.helpers.LogHelper;
import org.y20k.trackbook.helpers.NotificationHelper; import org.y20k.trackbook.helpers.NotificationHelper;
import org.y20k.trackbook.helpers.TrackbookKeys; import org.y20k.trackbook.helpers.TrackbookKeys;
@ -60,7 +62,7 @@ import java.util.Map;
/** /**
* MainActivity class * MainActivity class
*/ */
public class MainActivity extends AppCompatActivity implements TrackbookKeys, DialogClearFragment.DialogClearListener { public class MainActivity extends AppCompatActivity implements TrackbookKeys {
/* Define log tag */ /* Define log tag */
private static final String LOG_TAG = MainActivity.class.getSimpleName(); private static final String LOG_TAG = MainActivity.class.getSimpleName();
@ -68,9 +70,14 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys, Di
/* Main class variables */ /* Main class variables */
private boolean mTrackerServiceRunning; private boolean mTrackerServiceRunning;
private boolean mCurrentTrackVisible;
private boolean mPermissionsGranted; private boolean mPermissionsGranted;
private boolean mFloatingActionButtonSubMenuVisible;
private List<String> mMissingPermissions; private List<String> mMissingPermissions;
private LinearLayout mFloatingActionButtonLayout;
private FloatingActionButton mFloatingActionButton; private FloatingActionButton mFloatingActionButton;
private LinearLayout mFloatingActionButtonSubMenu1;
private LinearLayout mFloatingActionButtonSubMenu2;
private MainActivityMapFragment mMainActivityMapFragment; private MainActivityMapFragment mMainActivityMapFragment;
private MainActivityTrackFragment mMainActivityTrackFragment; private MainActivityTrackFragment mMainActivityTrackFragment;
private BroadcastReceiver mTrackingStoppedReceiver; private BroadcastReceiver mTrackingStoppedReceiver;
@ -81,12 +88,8 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys, Di
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// get state of tracking and get selected tab // load saved state of app
mTrackerServiceRunning = false; loadAppState(this);
if (savedInstanceState != null) {
mTrackerServiceRunning = savedInstanceState.getBoolean(INSTANCE_TRACKING_STATE, false);
mSelectedTab = savedInstanceState.getInt(INSTANCE_SELECTED_TAB, 0);
}
// check permissions on Android 6 and higher // check permissions on Android 6 and higher
mPermissionsGranted = false; mPermissionsGranted = false;
@ -104,7 +107,6 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys, Di
// set up main layout // set up main layout
setupLayout(); setupLayout();
} }
@ -112,27 +114,28 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys, Di
protected void onStart() { protected void onStart() {
super.onStart(); super.onStart();
// add listeners to button // add listeners to button and submenu
if (mFloatingActionButton != null) { if (mFloatingActionButton != null) {
mFloatingActionButton.setOnClickListener(new View.OnClickListener() { mFloatingActionButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
// onClick: start / stop tracking
handleFloatingActionButtonClick(view); handleFloatingActionButtonClick(view);
} }
}); });
mFloatingActionButton.setOnLongClickListener(new View.OnLongClickListener() { }
if (mFloatingActionButtonSubMenu1 != null) {
mFloatingActionButtonSubMenu1.setOnClickListener(new View.OnClickListener() {
@Override @Override
public boolean onLongClick(View view) { public void onClick(View view) {
// onLongClick: clear map handleButtonSaveAndClearClick();
if (mTrackerServiceRunning || mMainActivityMapFragment == null) { }
return false; });
} else { }
// show clear dialog if (mFloatingActionButtonSubMenu2 != null) {
DialogFragment dialog = new DialogClearFragment(); mFloatingActionButtonSubMenu2.setOnClickListener(new View.OnClickListener() {
dialog.show(getFragmentManager(), "DialogClearFragment"); @Override
return true; public void onClick(View view) {
} handleButtonClearClick();
} }
}); });
} }
@ -177,14 +180,6 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys, Di
} }
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean(INSTANCE_TRACKING_STATE, mTrackerServiceRunning);
outState.putInt(INSTANCE_SELECTED_TAB, mSelectedTab);
super.onSaveInstanceState(outState);
}
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
@ -243,25 +238,48 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys, Di
@Override @Override
public void onDialogClearPositiveClick(DialogFragment dialog) { protected void onSaveInstanceState(Bundle outState) {
// DialogClear: User chose CLEAR. LogHelper.v(LOG_TAG, "onSaveInstanceState called.");
LogHelper.v(LOG_TAG, "User chose CLEAR"); outState.putBoolean(INSTANCE_TRACKING_STATE, mTrackerServiceRunning);
outState.putBoolean(INSTANCE_TRACK_VISIBLE, mCurrentTrackVisible);
// clear the map outState.putBoolean(INSTANCE_FAB_SUB_MENU_VISIBLE, mFloatingActionButtonSubMenuVisible);
mMainActivityMapFragment.clearMap(); outState.putInt(INSTANCE_SELECTED_TAB, mSelectedTab);
super.onSaveInstanceState(outState);
// reset current track
mMainActivityTrackFragment.refreshTrackView();
// dismiss notification
NotificationHelper.stop();
} }
@Override @Override
public void onDialogClearNegativeClick(DialogFragment dialog) { public void onRestoreInstanceState(Bundle savedInstanceState) {
// DialogClear: User chose CANCEL. super.onRestoreInstanceState(savedInstanceState);
LogHelper.v(LOG_TAG, "User chose CANCEL."); LogHelper.v(LOG_TAG, "onRestoreInstanceState called.");
mTrackerServiceRunning = savedInstanceState.getBoolean(INSTANCE_TRACKING_STATE, false);
mCurrentTrackVisible = savedInstanceState.getBoolean(INSTANCE_TRACK_VISIBLE, false);
mFloatingActionButtonSubMenuVisible = savedInstanceState.getBoolean(INSTANCE_FAB_SUB_MENU_VISIBLE, false);
mSelectedTab = savedInstanceState.getInt(INSTANCE_SELECTED_TAB, 0);
}
/* Saves app state to SharedPreferences */
private void saveAppState(Context context) {
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean(INSTANCE_TRACKING_STATE, mTrackerServiceRunning);
editor.putBoolean(INSTANCE_TRACK_VISIBLE, mCurrentTrackVisible);
editor.putBoolean(INSTANCE_FAB_SUB_MENU_VISIBLE, mFloatingActionButtonSubMenuVisible);
editor.putInt(INSTANCE_SELECTED_TAB, mSelectedTab);
editor.apply();
LogHelper.v(LOG_TAG, "Saving state.");
}
/* Loads app state from preferences */
private void loadAppState(Context context) {
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
mTrackerServiceRunning = settings.getBoolean(INSTANCE_TRACKING_STATE, false);
mCurrentTrackVisible = settings.getBoolean(INSTANCE_TRACK_VISIBLE, false);
mFloatingActionButtonSubMenuVisible = settings.getBoolean(INSTANCE_FAB_SUB_MENU_VISIBLE, false);
mSelectedTab = settings.getInt(INSTANCE_SELECTED_TAB, 0);
LogHelper.v(LOG_TAG, "Loading state.");
} }
@ -269,7 +287,7 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys, Di
private void setupLayout() { private void setupLayout() {
if (mPermissionsGranted) { if (mPermissionsGranted) {
// point to the main map layout // point to the main map layout
setContentView(R.layout.activity_main_test); setContentView(R.layout.activity_main);
// show action bar // show action bar
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
@ -312,8 +330,16 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys, Di
} }
}); });
// show the record button and attach listener // get references to the record button and show/hide its sub menu
mFloatingActionButton = (FloatingActionButton) findViewById(R.id.fab); mFloatingActionButtonLayout = (LinearLayout) findViewById(R.id.fabFrameLayout);
mFloatingActionButton = (FloatingActionButton) findViewById(R.id.fabMainButton);
mFloatingActionButtonSubMenu1 = (LinearLayout) findViewById(R.id.fabSubMenu1);
mFloatingActionButtonSubMenu2 = (LinearLayout) findViewById(R.id.fabSubMenu2);
if (mFloatingActionButtonSubMenuVisible) {
showFloatingActionButtonMenu(true);
} else {
showFloatingActionButtonMenu(false);
}
} else { } else {
// point to the on main onboarding layout // point to the on main onboarding layout
@ -338,6 +364,15 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys, Di
} }
@Override
protected void onPause() {
super.onPause();
// save current state
saveAppState(this);
}
/* Handles tap on the record button */ /* Handles tap on the record button */
private void handleFloatingActionButtonClick(View view) { private void handleFloatingActionButtonClick(View view) {
if (mTrackerServiceRunning) { if (mTrackerServiceRunning) {
@ -352,14 +387,21 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys, Di
intent.setAction(ACTION_STOP); intent.setAction(ACTION_STOP);
startService(intent); startService(intent);
} else if (mCurrentTrackVisible) {
// toggle floating action button sub menu
if (!mFloatingActionButtonSubMenuVisible) {
showFloatingActionButtonMenu(true);
} else {
showFloatingActionButtonMenu(false);
}
} else { } else {
// TODO ask if user wants to save the last track before starting a new recording
// TODO alternatively only ask if last track was very short
// show snackbar // show snackbar
Snackbar.make(view, R.string.snackbar_message_tracking_started, Snackbar.LENGTH_SHORT).setAction("Action", null).show(); Snackbar.make(view, R.string.snackbar_message_tracking_started, Snackbar.LENGTH_SHORT).setAction("Action", null).show();
// change state // change state
mTrackerServiceRunning = true; mTrackerServiceRunning = true;
mCurrentTrackVisible = true;
setFloatingActionButtonState(); setFloatingActionButtonState();
// get last location from MainActivity Fragment // get last location from MainActivity Fragment
@ -385,16 +427,76 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys, Di
} }
/* Handles tap on the save and clear button */
public void handleButtonSaveAndClearClick() {
LogHelper.v(LOG_TAG, "User chose SAVE and CLEAR");
// clear map and save track
mMainActivityMapFragment.clearMap(true); // TODO change to true
mCurrentTrackVisible = false;
// // reset current track // TODO ist this still necessary
// mMainActivityTrackFragment.refreshTrackView();
// TODO change to track tab
// dismiss notification
NotificationHelper.stop();
// hide Floating Action Button sub menu
showFloatingActionButtonMenu(false);
// update Floating Action Button icon
setFloatingActionButtonState();
}
/* Handles tap on the clear button */
public void handleButtonClearClick() {
LogHelper.v(LOG_TAG, "User chose CLEAR");
// clear map, do not save track
mMainActivityMapFragment.clearMap(false);
mCurrentTrackVisible = false;
// dismiss notification
NotificationHelper.stop();
// hide Floating Action Button sub menu
showFloatingActionButtonMenu(false);
// update Floating Action Button icon
setFloatingActionButtonState();
}
/* Set state of FloatingActionButton */ /* Set state of FloatingActionButton */
private void setFloatingActionButtonState() { private void setFloatingActionButtonState() {
if (mTrackerServiceRunning) { if (mTrackerServiceRunning) {
mFloatingActionButton.setImageResource(R.drawable.ic_fiber_manual_record_red_24dp); mFloatingActionButton.setImageResource(R.drawable.ic_fiber_manual_record_red_24dp);
} else if (mCurrentTrackVisible) {
mFloatingActionButton.setImageResource(R.drawable.ic_save_white_24dp);
} else { } else {
mFloatingActionButton.setImageResource(R.drawable.ic_fiber_manual_record_white_24dp); mFloatingActionButton.setImageResource(R.drawable.ic_fiber_manual_record_white_24dp);
} }
} }
/* Shows (and hides) the sub menu of the floating action button */
private void showFloatingActionButtonMenu(boolean visible) {
if (visible) {
mFloatingActionButtonSubMenu1.setVisibility(View.VISIBLE);
mFloatingActionButtonSubMenu2.setVisibility(View.VISIBLE);
mFloatingActionButtonSubMenuVisible = true;
} else {
mFloatingActionButtonSubMenu1.setVisibility(View.INVISIBLE);
mFloatingActionButtonSubMenu2.setVisibility(View.INVISIBLE);
mFloatingActionButtonSubMenuVisible = false;
}
}
/* Handles new incoming intents */ /* Handles new incoming intents */
private void handleIncomingIntent() { private void handleIncomingIntent() {
Intent intent = getIntent(); Intent intent = getIntent();
@ -407,12 +509,6 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys, Di
mMainActivityMapFragment.setTrackingState(mTrackerServiceRunning); mMainActivityMapFragment.setTrackingState(mTrackerServiceRunning);
// prevent multiple reactions to intent // prevent multiple reactions to intent
intent.setAction(ACTION_DEFAULT); intent.setAction(ACTION_DEFAULT);
} else if (intent.hasExtra(EXTRA_CLEAR_MAP) && mMainActivityMapFragment != null) {
// show clear dialog
DialogFragment dialog = new DialogClearFragment();
dialog.show(getFragmentManager(), "DialogClearFragment");
// prevent multiple reactions to intent
intent.setAction(ACTION_DEFAULT);
} }
break; break;

View File

@ -108,7 +108,7 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
mFirstStart = savedInstanceState.getBoolean(INSTANCE_FIRST_START, true); mFirstStart = savedInstanceState.getBoolean(INSTANCE_FIRST_START, true);
} }
// restore tracking state // restore tracking and map state
mTrackerServiceRunning = false; mTrackerServiceRunning = false;
if (savedInstanceState != null) { if (savedInstanceState != null) {
mTrackerServiceRunning = savedInstanceState.getBoolean(INSTANCE_TRACKING_STATE, false); mTrackerServiceRunning = savedInstanceState.getBoolean(INSTANCE_TRACKING_STATE, false);
@ -235,7 +235,7 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
// show/hide the location off notification bar // show/hide the location off notification bar
toggleLocationOffBar(); toggleLocationOffBar();
// start preliminary tracking - if no TrackerService is running // start preliminary tracking - if no TrackerService is running // TODO check if this still works in tabbed ui
if (!mTrackerServiceRunning && mFragmentVisible) { if (!mTrackerServiceRunning && mFragmentVisible) {
startPreliminaryTracking(); startPreliminaryTracking();
} }
@ -388,20 +388,26 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
/* Removes track crumbs from map */ /* Removes track crumbs from map */
public void clearMap() { public void clearMap(boolean saveTrack) {
LogHelper.v(LOG_TAG, "!!! Ding clear.");
// clear map // clear map
if (mTrackOverlay != null) { if (mTrackOverlay != null) {
Toast.makeText(mActivity, mActivity.getString(R.string.toast_message_clear_map), Toast.LENGTH_LONG).show();
mMapView.getOverlays().remove(mTrackOverlay); mMapView.getOverlays().remove(mTrackOverlay);
} }
// save track object // save track object if requested
SaveTrackAsyncHelper saveTrackAsyncHelper = new SaveTrackAsyncHelper(); if (saveTrack) {
saveTrackAsyncHelper.execute(); SaveTrackAsyncHelper saveTrackAsyncHelper = new SaveTrackAsyncHelper();
// TODO add toast indicating track save saveTrackAsyncHelper.execute();
Toast.makeText(mActivity, mActivity.getString(R.string.toast_message_save_track), Toast.LENGTH_LONG).show();
}
}
/* Getter for length of current track */
public String getCurrentTrackLength() {
return mTrack.getTrackDistance();
} }

View File

@ -1,83 +0,0 @@
/**
* DialogClearFragment.java
* Implements the DialogClearFragment class
* A DialogClearFragment appears when the user wants to clear the map
*
* This file is part of
* TRACKBOOK - Movement Recorder for Android
*
* Copyright (c) 2016 - Y20K.org
* Licensed under the MIT-License
* http://opensource.org/licenses/MIT
*
* Trackbook uses osmdroid - OpenStreetMap-Tools for Android
* https://github.com/osmdroid/osmdroid
*/
package org.y20k.trackbook.helpers;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import org.y20k.trackbook.R;
/**
* DialogClearFragment class
*/
public class DialogClearFragment extends DialogFragment {
/* Define log tag */
private static final String LOG_TAG = DialogClearFragment.class.getSimpleName();
/* Interface that the context that creates an instance of this fragment must implement */
public interface DialogClearListener {
public void onDialogClearPositiveClick(DialogFragment dialog);
public void onDialogClearNegativeClick(DialogFragment dialog);
}
/* Main class variables */
private DialogClearListener mListener;
@Override
public void onAttach(Context context) {
super.onAttach(context);
// verify that the host context implements the callback interface
try {
// instantiate the NoticeDialogListener so we can send events to the host
mListener = (DialogClearListener) context;
} catch (ClassCastException e) {
LogHelper.e(LOG_TAG, "Context does not implement the DialogClearListener interface.");
}
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// construct dialog
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.dialog_clear_map_title)
.setMessage(R.string.dialog_clear_map_message)
.setPositiveButton(R.string.dialog_clear_map_okay, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// user clicked CLEAR - inform initiating fragment / context
mListener.onDialogClearPositiveClick(DialogClearFragment.this);
}
})
.setNegativeButton(R.string.dialog_clear_map_cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// user clicked CANCEL - inform initiating fragment / context
mListener.onDialogClearNegativeClick(DialogClearFragment.this);
}
});
// create the AlertDialog object and return it
return builder.create();
}
}

View File

@ -114,8 +114,6 @@ public class NotificationHelper implements TrackbookKeys {
TaskStackBuilder swipeActionIntentBuilder = TaskStackBuilder.create(mService); TaskStackBuilder swipeActionIntentBuilder = TaskStackBuilder.create(mService);
swipeActionIntentBuilder.addParentStack(MainActivity.class); swipeActionIntentBuilder.addParentStack(MainActivity.class);
swipeActionIntentBuilder.addNextIntent(swipeActionIntent); swipeActionIntentBuilder.addNextIntent(swipeActionIntent);
// pending intent wrapper for notification tap
PendingIntent swipeActionPendingIntent = swipeActionIntentBuilder.getPendingIntent(11, PendingIntent.FLAG_UPDATE_CURRENT);
// ACTION: NOTIFICATION BUTTON STOP // ACTION: NOTIFICATION BUTTON STOP
Intent stopActionIntent = new Intent(mService, TrackerService.class); Intent stopActionIntent = new Intent(mService, TrackerService.class);
@ -136,10 +134,8 @@ public class NotificationHelper implements TrackbookKeys {
builder.setContentTitle(mService.getString(R.string.notification_title_trackbook_running)); builder.setContentTitle(mService.getString(R.string.notification_title_trackbook_running));
builder.setContentText(contentText); builder.setContentText(contentText);
} else { } else {
builder.setDeleteIntent(swipeActionPendingIntent);
builder.setContentTitle(mService.getString(R.string.notification_title_trackbook_not_running)); builder.setContentTitle(mService.getString(R.string.notification_title_trackbook_not_running));
builder.setContentText(contentText); builder.setContentText(contentText);
builder.setSubText(mService.getString(R.string.notification_swipe_to_clear_map));
} }
return builder; return builder;

View File

@ -42,6 +42,8 @@ public interface TrackbookKeys {
String ARG_PERMISSIONS_GRANTED = "ArgPermissionsGranted"; String ARG_PERMISSIONS_GRANTED = "ArgPermissionsGranted";
String ARG_TRACKING_STATE = "ArgTrackingState"; String ARG_TRACKING_STATE = "ArgTrackingState";
String ARG_TRACK = "ArgTrack"; String ARG_TRACK = "ArgTrack";
String ARG_TRACK_VISIBLE = "ArgTrackVisible";
String ARG_TRACK_DISTANCE = "ArgTrackDistance";
/* TAGS */ /* TAGS */
String TAG_MAIN_ACTIVITY_FRAGMENT = "TagMainActivityFragment"; String TAG_MAIN_ACTIVITY_FRAGMENT = "TagMainActivityFragment";
@ -58,7 +60,9 @@ public interface TrackbookKeys {
/* INSTANCE STATE */ /* INSTANCE STATE */
String INSTANCE_FIRST_START = "firstStart"; String INSTANCE_FIRST_START = "firstStart";
String INSTANCE_TRACKING_STATE = "trackingState"; String INSTANCE_TRACKING_STATE = "trackingState";
String INSTANCE_TRACK_VISIBLE = "trackVisible";
String INSTANCE_SELECTED_TAB = "selectedTab"; String INSTANCE_SELECTED_TAB = "selectedTab";
String INSTANCE_FAB_SUB_MENU_VISIBLE = "fabSubMenuVisible";
String INSTANCE_TRACK_MAIN_MAP = "trackMainMap"; String INSTANCE_TRACK_MAIN_MAP = "trackMainMap";
String INSTANCE_LATITUDE_MAIN_MAP = "latitudeMainMap"; String INSTANCE_LATITUDE_MAIN_MAP = "latitudeMainMap";
String INSTANCE_LONGITUDE_MAIN_MAP = "longitudeMainMap"; String INSTANCE_LONGITUDE_MAIN_MAP = "longitudeMainMap";

View File

@ -0,0 +1,68 @@
/**
* DodgeAbleLayoutBehavior.java
* Implements the DodgeAbleLayoutBehavior class
* A DodgeAbleLayoutBehavior enables any element to be dodged up by a snackbar
*
* This file is part of
* TRACKBOOK - Movement Recorder for Android
*
* Copyright (c) 2016 - Y20K.org
* Licensed under the MIT-License
* http://opensource.org/licenses/MIT
*
* Trackbook uses osmdroid - OpenStreetMap-Tools for Android
* https://github.com/osmdroid/osmdroid
*/
package org.y20k.trackbook.layout;
import android.content.Context;
import android.os.Build;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.util.AttributeSet;
import android.view.View;
/**
* DodgeAbleLayoutBehavior class
* adapted from: http://stackoverflow.com/a/35904421
*/
public class DodgeAbleLayoutBehavior extends CoordinatorLayout.Behavior<View> {
/* Main class variables */
private static final boolean SNACKBAR_BEHAVIOR_ENABLED;
/* Constructor (default) */
public DodgeAbleLayoutBehavior() {
super();
}
/* Constructor for context and attributes */
public DodgeAbleLayoutBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return SNACKBAR_BEHAVIOR_ENABLED && dependency instanceof Snackbar.SnackbarLayout;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
float translationY = Math.min(0, dependency.getTranslationY() - dependency.getHeight());
child.setTranslationY(translationY);
return true;
}
static {
SNACKBAR_BEHAVIOR_ENABLED = Build.VERSION.SDK_INT >= 11;
}
}

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"
android:fillColor="@color/trackbook_white" />
</vector>

View File

@ -5,5 +5,5 @@
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:pathData="M12,12m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0" android:pathData="M12,12m-8,0a8,8 0,1 1,16 0a8,8 0,1 1,-16 0"
android:fillColor="#FFFFFF"/> android:fillColor="@color/trackbook_white" />
</vector> </vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="@color/trackbook_white"
android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="@color/trackbook_white"
android:pathData="M9,11L7,11v2h2v-2zM13,11h-2v2h2v-2zM17,11h-2v2h2v-2zM19,4h-1L18,2h-2v2L8,4L8,2L6,2v2L5,4c-1.11,0 -1.99,0.9 -1.99,2L3,20c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,6c0,-1.1 -0.9,-2 -2,-2zM19,20L5,20L5,9h14v11z"/>
</vector>

View File

@ -1,15 +1,19 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" <android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
tools:context="org.y20k.trackbook.MainActivity"> tools:context="org.y20k.trackbook.MainActivity">
<android.support.design.widget.AppBarLayout <android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="@dimen/appbar_padding_top"
android:theme="@style/TrackbookAppTheme.AppBarOverlay"> android:theme="@style/TrackbookAppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar <android.support.v7.widget.Toolbar
@ -17,31 +21,39 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary" android:background="?attr/colorPrimary"
app:popupTheme="@style/TrackbookAppTheme.PopupOverlay" /> app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/TrackbookAppTheme.PopupOverlay">
</android.support.v7.widget.Toolbar>
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMaxWidth="0dp"
app:tabGravity="fill"
app:tabMode="fixed" />
</android.support.design.widget.AppBarLayout> </android.support.design.widget.AppBarLayout>
<!-- include MainActivityMapFragment --> <android.support.v4.view.ViewPager
<fragment android:id="@+id/container"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/content_main"
android:name="org.y20k.trackbook.MainActivityMapFragment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" app:layout_behavior="@string/appbar_scrolling_view_behavior" />
tools:layout="@layout/fragment_main_map" /> <!-- MainActivityMapFragment and MainActivityTrackFragment are included at runtime -->
<android.support.design.widget.FloatingActionButton <include layout="@layout/floating_action_button" />
<!-- <android.support.design.widget.FloatingActionButton
android:id="@+id/fab" android:id="@+id/fab"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom|end" android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin" android:layout_margin="@dimen/fab_margin"
app:srcCompat="@drawable/ic_fiber_manual_record_white_24dp" app:srcCompat="@drawable/ic_fiber_manual_record_white_24dp"
app:fabSize="auto"/> app:fabSize="auto"/> -->
</android.support.design.widget.CoordinatorLayout> </android.support.design.widget.CoordinatorLayout>

View File

@ -1,19 +1,15 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
tools:context="org.y20k.trackbook.MainActivity"> tools:context="org.y20k.trackbook.MainActivity">
<android.support.design.widget.AppBarLayout <android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="@dimen/appbar_padding_top"
android:theme="@style/TrackbookAppTheme.AppBarOverlay"> android:theme="@style/TrackbookAppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar <android.support.v7.widget.Toolbar
@ -21,37 +17,33 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary" android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways" app:popupTheme="@style/TrackbookAppTheme.PopupOverlay" />
app:popupTheme="@style/TrackbookAppTheme.PopupOverlay">
</android.support.v7.widget.Toolbar>
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMaxWidth="0dp"
app:tabGravity="fill"
app:tabMode="fixed" />
</android.support.design.widget.AppBarLayout> </android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager <!-- include MainActivityMapFragment -->
android:id="@+id/container" <fragment
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/content_main"
android:name="org.y20k.trackbook.MainActivityMapFragment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" /> app:layout_behavior="@string/appbar_scrolling_view_behavior"
<!-- MainActivityMapFragment and MainActivityTrackFragment are included at runtime --> tools:layout="@layout/fragment_main_map" />
<android.support.design.widget.FloatingActionButton <include layout="@layout/floating_action_button" />
<!-- <android.support.design.widget.FloatingActionButton
android:id="@+id/fab" android:id="@+id/fab"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom|end" android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin" android:layout_margin="@dimen/fab_margin"
app:srcCompat="@drawable/ic_fiber_manual_record_white_24dp" app:srcCompat="@drawable/ic_fiber_manual_record_white_24dp"
app:fabSize="auto"/> app:fabSize="auto"/> -->
</android.support.design.widget.CoordinatorLayout> </android.support.design.widget.CoordinatorLayout>

View File

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- TODO add missing descriptions and color definitions -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/fabFrameLayout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:layout_behavior="org.y20k.trackbook.layout.DodgeAbleLayoutBehavior">
<LinearLayout
android:id="@+id/fabSubMenu1"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:gravity="center_vertical"
android:layout_weight="1"
android:layout_gravity="bottom|end"
android:layout_marginEnd="8dp"
android:layout_marginBottom="@dimen/fab_margin"
android:orientation="horizontal"
android:visibility="visible">
<android.support.v7.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
app:cardBackgroundColor="@color/trackbook_white"
app:cardCornerRadius="4dp"
app:cardElevation="4dp"
app:cardUseCompatPadding="true" >
<TextView
android:id="@+id/fabSubMenuLabel1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="@string/fab_sub_menu_save_and_clear"
android:textStyle="bold"
android:paddingRight="6dp"
android:paddingLeft="6dp"
android:paddingBottom="2dp"
android:paddingTop="2dp" />
</android.support.v7.widget.CardView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fabSubMenuButton1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
app:srcCompat="@drawable/ic_save_white_24dp"
app:backgroundTint="#4CAF50"
app:fabSize="mini" />
</LinearLayout>
<LinearLayout
android:id="@+id/fabSubMenu2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_gravity="bottom|end"
android:layout_marginEnd="8dp"
android:layout_marginBottom="@dimen/fab_margin"
android:orientation="horizontal"
android:visibility="visible">
<android.support.v7.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardBackgroundColor="@color/trackbook_white"
app:cardCornerRadius="4dp"
app:cardElevation="4dp"
app:cardUseCompatPadding="true">
<TextView
android:id="@+id/fabSubMenuLabel2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="@string/fab_sub_menu_clear"
android:textStyle="bold"
android:paddingRight="6dp"
android:paddingLeft="6dp"
android:paddingBottom="2dp"
android:paddingTop="2dp" />
</android.support.v7.widget.CardView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fabSubMenuButton2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_clear_white_24dp"
app:backgroundTint="#2196F3"
app:fabSize="mini" />
</LinearLayout>
<LinearLayout
android:id="@+id/fabMain"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:orientation="horizontal">
<android.support.design.widget.FloatingActionButton
android:id="@+id/fabMainButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_fiber_manual_record_white_24dp"
app:fabSize="normal" />
</LinearLayout>
<!-- <android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@drawable/ic_fiber_manual_record_white_24dp"
app:fabSize="auto"/> -->
</LinearLayout>

View File

@ -7,7 +7,7 @@
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
tools:context=".MainActivityMapFragment" tools:context=".MainActivityMapFragment"
tools:showIn="@layout/activity_main"> tools:showIn="@layout/activity_main_old">
<org.osmdroid.views.MapView android:id="@+id/map" <org.osmdroid.views.MapView android:id="@+id/map"
android:layout_width="fill_parent" android:layout_width="fill_parent"

View File

@ -15,8 +15,6 @@
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:contentDescription="@string/descr_map_last_track" /> android:contentDescription="@string/descr_map_last_track" />
<!-- TODO ADD android:contentDescription="@string/descr_xyz" -->
<!-- BOTTOM SHEET --> <!-- BOTTOM SHEET -->
<android.support.v4.widget.NestedScrollView <android.support.v4.widget.NestedScrollView
android:id="@+id/statistics_sheet" android:id="@+id/statistics_sheet"

View File

@ -28,11 +28,9 @@
<string name="snackbar_message_tracking_started">Tracking aktiviert</string> <string name="snackbar_message_tracking_started">Tracking aktiviert</string>
<string name="snackbar_message_location_offline">Standortdienste sind deaktiviert. Trackbook kann nicht aufzeichnen.</string> <string name="snackbar_message_location_offline">Standortdienste sind deaktiviert. Trackbook kann nicht aufzeichnen.</string>
<!-- dialogs --> <!-- fab sub menu -->
<string name="dialog_clear_map_title">Zurücksetzen</string> <string name="fab_sub_menu_clear">Zurücksetzen</string>
<string name="dialog_clear_map_message">Möchten Sie die Karte zurücksetzen?</string> <string name="fab_sub_menu_save_and_clear">Speichern und Zurücksetzen</string>
<string name="dialog_clear_map_okay">Zurücksetzen</string>
<string name="dialog_clear_map_cancel">Abbrechen</string>
<!-- toast messages --> <!-- toast messages -->
<string name="toast_message_permissions_granted">Berechtigungen erteilt.</string> <string name="toast_message_permissions_granted">Berechtigungen erteilt.</string>
@ -42,7 +40,7 @@
<string name="toast_message_acquiring_location">Suche aktuellen Standort.</string> <string name="toast_message_acquiring_location">Suche aktuellen Standort.</string>
<string name="toast_message_location_services_not_ready">Standortdienste noch nicht bereit. Bitte erneut versuchen.</string> <string name="toast_message_location_services_not_ready">Standortdienste noch nicht bereit. Bitte erneut versuchen.</string>
<string name="toast_message_last_location">Letzte Position:</string> <string name="toast_message_last_location">Letzte Position:</string>
<string name="toast_message_clear_map">Kartenansicht wird zurückgesetzt</string> <string name="toast_message_save_track">Aufzeichnung wird gespeichert.</string>
<string name="toast_message_last_location_age_one_hour">über eine Stunde</string> <string name="toast_message_last_location_age_one_hour">über eine Stunde</string>
<!-- map markers --> <!-- map markers -->

View File

@ -28,11 +28,10 @@
<string name="snackbar_message_tracking_started">Tracking started</string> <string name="snackbar_message_tracking_started">Tracking started</string>
<string name="snackbar_message_location_offline">Location is turned off. Trackbook will not work.</string> <string name="snackbar_message_location_offline">Location is turned off. Trackbook will not work.</string>
<!-- dialogs --> <!-- fab sub menu -->
<string name="dialog_clear_map_title">Clear</string> <string name="fab_sub_menu_clear">Clear</string>
<string name="dialog_clear_map_message">Do you want to clear the map?</string> <string name="fab_sub_menu_save_and_clear">Save and Clear</string>
<string name="dialog_clear_map_okay">Clear</string>
<string name="dialog_clear_map_cancel">Cancel</string>
<!-- toast messages --> <!-- toast messages -->
<string name="toast_message_permissions_granted">Permissions granted.</string> <string name="toast_message_permissions_granted">Permissions granted.</string>
@ -42,7 +41,7 @@
<string name="toast_message_acquiring_location">Acquiring current location.</string> <string name="toast_message_acquiring_location">Acquiring current location.</string>
<string name="toast_message_location_services_not_ready">Location services not ready. Please retry.</string> <string name="toast_message_location_services_not_ready">Location services not ready. Please retry.</string>
<string name="toast_message_last_location">Last location:</string> <string name="toast_message_last_location">Last location:</string>
<string name="toast_message_clear_map">Clearing map.</string> <string name="toast_message_save_track">Saving current track.</string>
<string name="toast_message_last_location_age_one_hour">over one hour</string> <string name="toast_message_last_location_age_one_hour">over one hour</string>
<!-- map markers --> <!-- map markers -->

View File

@ -5,7 +5,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:2.2.2' classpath 'com.android.tools.build:gradle:2.2.3'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files