implemented a basic share sheet (see #36)

This commit is contained in:
y20k 2018-05-28 17:56:38 +02:00
parent 3c5be28ded
commit 9f8e932b5a
6 changed files with 120 additions and 29 deletions

View file

@ -51,6 +51,17 @@
</intent-filter>
</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>
</manifest>

View file

@ -205,8 +205,10 @@ public class MainActivityTrackFragment extends Fragment implements AdapterView.O
mDropdown = (Spinner) mRootView.findViewById(R.id.track_selector);
// 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 deleteButton = (ImageButton) mRootView.findViewById(R.id.delete_button);
shareButton.setOnClickListener(getShareButtonListener());
exportButton.setOnClickListener(getExportButtonListener());
deleteButton.setOnClickListener(getDeleteButtonListener());
@ -343,7 +345,7 @@ public class MainActivityTrackFragment extends Fragment implements AdapterView.O
break;
case RESULT_EXPORT_DIALOG:
if (resultCode == Activity.RESULT_OK) {
// User chose EXPORT
// user chose EXPORT
ExportHelper.exportToGpx(mActivity, mTrack);
} else if (resultCode == Activity.RESULT_CANCELED){
// User chose CANCEL
@ -525,23 +527,21 @@ public class MainActivityTrackFragment extends Fragment implements AdapterView.O
}
/* Creates OnClickListener for the delete button - needed in onCreateView */
private View.OnClickListener getDeleteButtonListener() {
/* Creates OnClickListener for the export button - needed in onCreateView */
private View.OnClickListener getShareButtonListener() {
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");
Intent intent = ExportHelper.getGpxFileIntent(mActivity, mTrack);
// create intent to show chooser
String title = "Share GPX file with"; // todo replace with Resource
// String title = getResources().getString(R.string.chooser_title);
Intent chooser = Intent.createChooser(intent, title);
if (intent.resolveActivity(mActivity.getPackageManager()) != null) {
startActivity(chooser);
} else {
// todo TOAST
}
}
};
}
@ -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 */
private void attachTapListenerToElevationViews() {
int referencedIds[] = mElevationDataViews.getReferencedIds();

View file

@ -17,8 +17,10 @@
package org.y20k.trackbook.helpers;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.os.Environment;
import android.support.v4.content.FileProvider;
import android.widget.Toast;
import org.y20k.trackbook.R;
@ -38,7 +40,7 @@ import java.util.TimeZone;
/**
* ExportHelper class
*/
public final class ExportHelper implements TrackbookKeys {
public final class ExportHelper extends FileProvider implements TrackbookKeys {
/* Define log tag */
private static final String LOG_TAG = ExportHelper.class.getSimpleName();
@ -53,17 +55,8 @@ public final class ExportHelper implements TrackbookKeys {
/* Exports given track to GPX */
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
File gpxFile = createFile(track, folder);
File gpxFile = createFile(track, getDownloadFolder());
// get GPX string representation for given 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 */
private static File createFile(Track track, File folder) {
Date recordingStart = track.getRecordingStart();

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="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>

View file

@ -17,10 +17,21 @@
android:layout_marginTop="4dp"
android:contentDescription="@string/descr_track_selector"
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_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
android:id="@+id/export_button"
android:layout_width="wrap_content"
@ -28,9 +39,9 @@
android:layout_marginEnd="8dp"
android:backgroundTint="@color/trackbook_transparent"
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_constraintTop_toTopOf="@+id/track_selector"
app:layout_constraintTop_toTopOf="@+id/share_button"
app:srcCompat="@drawable/ic_file_download_24dp" />
<ImageButton
@ -45,4 +56,5 @@
app:layout_constraintTop_toTopOf="@+id/export_button"
app:srcCompat="@drawable/ic_delete_forever_24dp" />
</android.support.constraint.ConstraintLayout>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="Download/"/>
</paths>