implemented a basic share sheet (see #36)
This commit is contained in:
parent
3c5be28ded
commit
9f8e932b5a
6 changed files with 120 additions and 29 deletions
|
@ -51,6 +51,17 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<!-- EXPORT HELPER (FILE PROVIDER) -->
|
||||||
|
<provider
|
||||||
|
android:name=".helpers.ExportHelper"
|
||||||
|
android:authorities="org.y20k.trackbook.exporthelper.provider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/provider_paths"/>
|
||||||
|
</provider>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
|
@ -205,8 +205,10 @@ public class MainActivityTrackFragment extends Fragment implements AdapterView.O
|
||||||
mDropdown = (Spinner) mRootView.findViewById(R.id.track_selector);
|
mDropdown = (Spinner) mRootView.findViewById(R.id.track_selector);
|
||||||
|
|
||||||
// attach listeners to export and delete buttons
|
// attach listeners to export and delete buttons
|
||||||
|
ImageButton shareButton = (ImageButton) mRootView.findViewById(R.id.share_button);
|
||||||
ImageButton exportButton = (ImageButton) mRootView.findViewById(R.id.export_button);
|
ImageButton exportButton = (ImageButton) mRootView.findViewById(R.id.export_button);
|
||||||
ImageButton deleteButton = (ImageButton) mRootView.findViewById(R.id.delete_button);
|
ImageButton deleteButton = (ImageButton) mRootView.findViewById(R.id.delete_button);
|
||||||
|
shareButton.setOnClickListener(getShareButtonListener());
|
||||||
exportButton.setOnClickListener(getExportButtonListener());
|
exportButton.setOnClickListener(getExportButtonListener());
|
||||||
deleteButton.setOnClickListener(getDeleteButtonListener());
|
deleteButton.setOnClickListener(getDeleteButtonListener());
|
||||||
|
|
||||||
|
@ -343,7 +345,7 @@ public class MainActivityTrackFragment extends Fragment implements AdapterView.O
|
||||||
break;
|
break;
|
||||||
case RESULT_EXPORT_DIALOG:
|
case RESULT_EXPORT_DIALOG:
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
// User chose EXPORT
|
// user chose EXPORT
|
||||||
ExportHelper.exportToGpx(mActivity, mTrack);
|
ExportHelper.exportToGpx(mActivity, mTrack);
|
||||||
} else if (resultCode == Activity.RESULT_CANCELED){
|
} else if (resultCode == Activity.RESULT_CANCELED){
|
||||||
// User chose CANCEL
|
// User chose CANCEL
|
||||||
|
@ -525,23 +527,21 @@ public class MainActivityTrackFragment extends Fragment implements AdapterView.O
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Creates OnClickListener for the delete button - needed in onCreateView */
|
/* Creates OnClickListener for the export button - needed in onCreateView */
|
||||||
private View.OnClickListener getDeleteButtonListener() {
|
private View.OnClickListener getShareButtonListener() {
|
||||||
return new View.OnClickListener() {
|
return new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
// get text elements for delete dialog
|
Intent intent = ExportHelper.getGpxFileIntent(mActivity, mTrack);
|
||||||
int dialogTitle = R.string.dialog_delete_title;
|
// create intent to show chooser
|
||||||
int dialogPositiveButton = R.string.dialog_delete_action_delete;
|
String title = "Share GPX file with"; // todo replace with Resource
|
||||||
int dialogNegativeButton = R.string.dialog_default_action_cancel;
|
// String title = getResources().getString(R.string.chooser_title);
|
||||||
DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
|
Intent chooser = Intent.createChooser(intent, title);
|
||||||
String recordingStartDate = df.format(mTrack.getRecordingStart());
|
if (intent.resolveActivity(mActivity.getPackageManager()) != null) {
|
||||||
String dialogMessage = getString(R.string.dialog_delete_content) + " " + recordingStartDate + " | " + LengthUnitHelper.convertDistanceToString(mTrack.getTrackDistance());
|
startActivity(chooser);
|
||||||
|
} else {
|
||||||
// show delete dialog - results are handles by onActivityResult
|
// todo TOAST
|
||||||
DialogFragment dialogFragment = DialogHelper.newInstance(dialogTitle, dialogMessage, dialogPositiveButton, dialogNegativeButton);
|
}
|
||||||
dialogFragment.setTargetFragment(MainActivityTrackFragment.this, RESULT_DELETE_DIALOG);
|
|
||||||
dialogFragment.show(mActivity.getSupportFragmentManager(), "DeleteDialog");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -584,6 +584,28 @@ public class MainActivityTrackFragment extends Fragment implements AdapterView.O
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Creates OnClickListener for the delete button - needed in onCreateView */
|
||||||
|
private View.OnClickListener getDeleteButtonListener() {
|
||||||
|
return new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
// get text elements for delete dialog
|
||||||
|
int dialogTitle = R.string.dialog_delete_title;
|
||||||
|
int dialogPositiveButton = R.string.dialog_delete_action_delete;
|
||||||
|
int dialogNegativeButton = R.string.dialog_default_action_cancel;
|
||||||
|
DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
|
||||||
|
String recordingStartDate = df.format(mTrack.getRecordingStart());
|
||||||
|
String dialogMessage = getString(R.string.dialog_delete_content) + " " + recordingStartDate + " | " + LengthUnitHelper.convertDistanceToString(mTrack.getTrackDistance());
|
||||||
|
|
||||||
|
// show delete dialog - results are handles by onActivityResult
|
||||||
|
DialogFragment dialogFragment = DialogHelper.newInstance(dialogTitle, dialogMessage, dialogPositiveButton, dialogNegativeButton);
|
||||||
|
dialogFragment.setTargetFragment(MainActivityTrackFragment.this, RESULT_DELETE_DIALOG);
|
||||||
|
dialogFragment.show(mActivity.getSupportFragmentManager(), "DeleteDialog");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Add tap listener to elevation data views */
|
/* Add tap listener to elevation data views */
|
||||||
private void attachTapListenerToElevationViews() {
|
private void attachTapListenerToElevationViews() {
|
||||||
int referencedIds[] = mElevationDataViews.getReferencedIds();
|
int referencedIds[] = mElevationDataViews.getReferencedIds();
|
||||||
|
|
|
@ -17,8 +17,10 @@
|
||||||
package org.y20k.trackbook.helpers;
|
package org.y20k.trackbook.helpers;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
import android.support.v4.content.FileProvider;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.y20k.trackbook.R;
|
import org.y20k.trackbook.R;
|
||||||
|
@ -38,7 +40,7 @@ import java.util.TimeZone;
|
||||||
/**
|
/**
|
||||||
* ExportHelper class
|
* ExportHelper class
|
||||||
*/
|
*/
|
||||||
public final class ExportHelper implements TrackbookKeys {
|
public final class ExportHelper extends FileProvider implements TrackbookKeys {
|
||||||
|
|
||||||
/* Define log tag */
|
/* Define log tag */
|
||||||
private static final String LOG_TAG = ExportHelper.class.getSimpleName();
|
private static final String LOG_TAG = ExportHelper.class.getSimpleName();
|
||||||
|
@ -53,17 +55,8 @@ public final class ExportHelper implements TrackbookKeys {
|
||||||
|
|
||||||
/* Exports given track to GPX */
|
/* Exports given track to GPX */
|
||||||
public static boolean exportToGpx(Context context, Track track) {
|
public static boolean exportToGpx(Context context, Track track) {
|
||||||
// get "Download" folder
|
|
||||||
File folder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
|
|
||||||
|
|
||||||
// create "Download" folder if necessary
|
|
||||||
if (folder != null && !folder.exists()) {
|
|
||||||
LogHelper.v(LOG_TAG, "Creating new folder: " + folder.toString());
|
|
||||||
folder.mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
// get file for given track
|
// get file for given track
|
||||||
File gpxFile = createFile(track, folder);
|
File gpxFile = createFile(track, getDownloadFolder());
|
||||||
|
|
||||||
// get GPX string representation for given track
|
// get GPX string representation for given track
|
||||||
String gpxString = createGpxString(track);
|
String gpxString = createGpxString(track);
|
||||||
|
@ -81,6 +74,46 @@ public final class ExportHelper implements TrackbookKeys {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Creates Intent used to bring up an Android share sheet */
|
||||||
|
public static Intent getGpxFileIntent(Context context, Track track) {
|
||||||
|
|
||||||
|
// get file for given track
|
||||||
|
File gpxFile = createFile(track, getDownloadFolder()); // todo use cache folder
|
||||||
|
|
||||||
|
// get GPX string representation for given track
|
||||||
|
String gpxString = createGpxString(track);
|
||||||
|
|
||||||
|
// write GPX file
|
||||||
|
if (writeGpxToFile(gpxString, gpxFile)) {
|
||||||
|
String toastMessage = context.getResources().getString(R.string.toast_message_export_success) + " " + gpxFile.toString();
|
||||||
|
Toast.makeText(context, toastMessage, Toast.LENGTH_LONG).show();
|
||||||
|
} else {
|
||||||
|
String toastMessage = context.getResources().getString(R.string.toast_message_export_fail) + " " + gpxFile.toString();
|
||||||
|
Toast.makeText(context, toastMessage, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// create intent
|
||||||
|
String authority = "org.y20k.trackbook.exporthelper.provider";
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.setAction(Intent.ACTION_SEND);
|
||||||
|
intent.setType("application/gpx+xml");
|
||||||
|
intent.setData(FileProvider.getUriForFile(context, authority, gpxFile));
|
||||||
|
|
||||||
|
return intent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Get "Download" folder */
|
||||||
|
private static File getDownloadFolder() {
|
||||||
|
File folder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
|
||||||
|
if (folder != null && !folder.exists()) {
|
||||||
|
LogHelper.v(LOG_TAG, "Creating new folder: " + folder.toString());
|
||||||
|
folder.mkdirs();
|
||||||
|
}
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return a GPX filepath for a given track */
|
/* Return a GPX filepath for a given track */
|
||||||
private static File createFile(Track track, File folder) {
|
private static File createFile(Track track, File folder) {
|
||||||
Date recordingStart = track.getRecordingStart();
|
Date recordingStart = track.getRecordingStart();
|
||||||
|
|
9
app/src/main/res/drawable/ic_share_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_share_24dp.xml
Normal 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="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"
|
||||||
|
android:fillColor="@color/track_management_icons" />
|
||||||
|
</vector>
|
|
@ -17,10 +17,21 @@
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:contentDescription="@string/descr_track_selector"
|
android:contentDescription="@string/descr_track_selector"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/export_button"
|
app:layout_constraintEnd_toStartOf="@+id/share_button"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/share_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:backgroundTint="@color/trackbook_transparent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/track_selector"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/export_button"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/track_selector"
|
||||||
|
app:srcCompat="@drawable/ic_share_24dp" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/export_button"
|
android:id="@+id/export_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -28,9 +39,9 @@
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:backgroundTint="@color/trackbook_transparent"
|
android:backgroundTint="@color/trackbook_transparent"
|
||||||
android:contentDescription="@string/descr_export_button"
|
android:contentDescription="@string/descr_export_button"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/track_selector"
|
app:layout_constraintBottom_toBottomOf="@+id/share_button"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/delete_button"
|
app:layout_constraintEnd_toStartOf="@+id/delete_button"
|
||||||
app:layout_constraintTop_toTopOf="@+id/track_selector"
|
app:layout_constraintTop_toTopOf="@+id/share_button"
|
||||||
app:srcCompat="@drawable/ic_file_download_24dp" />
|
app:srcCompat="@drawable/ic_file_download_24dp" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
|
@ -45,4 +56,5 @@
|
||||||
app:layout_constraintTop_toTopOf="@+id/export_button"
|
app:layout_constraintTop_toTopOf="@+id/export_button"
|
||||||
app:srcCompat="@drawable/ic_delete_forever_24dp" />
|
app:srcCompat="@drawable/ic_delete_forever_24dp" />
|
||||||
|
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
</android.support.constraint.ConstraintLayout>
|
4
app/src/main/res/xml/provider_paths.xml
Normal file
4
app/src/main/res/xml/provider_paths.xml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<paths>
|
||||||
|
<external-path name="external_files" path="Download/"/>
|
||||||
|
</paths>
|
Loading…
Reference in a new issue