Skip to content

Commit

Permalink
Add support for local PMTiles
Browse files Browse the repository at this point in the history
This required a larger re-factoring of nearly all the imagery
configuration modals to DialogFragments and numerous other changes.
  • Loading branch information
simonpoole committed Sep 8, 2023
1 parent 5662be6 commit 304699f
Show file tree
Hide file tree
Showing 19 changed files with 1,186 additions and 679 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ dependencies {
implementation 'ch.poole.android:sprites:0.0.4'
implementation 'ch.poole.android:indeterminate-checkbox:1.1.0@aar'
implementation 'ch.poole.misc:bentley-ottmann:0.1.1'
implementation 'ch.poole.geo.pmtiles-reader:Reader:0.3.0'
implementation 'ch.poole.geo.pmtiles-reader:Reader:0.3.4'

// for temp stuff during dev
// implementation(name:'alibrary', ext:'jar')
Expand Down
1 change: 1 addition & 0 deletions src/main/java/de/blau/android/contract/FileExtensions.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public final class FileExtensions {
public static final String RES = "res";
public static final String SVG = "svg";
public static final String TEMP = "temp";
public static final String PMTILES = "pmtiles";

/**
* Private default constructor
Expand Down
30 changes: 21 additions & 9 deletions src/main/java/de/blau/android/dialogs/Layers.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
import de.blau.android.resources.OAMCatalogView;
import de.blau.android.resources.TileLayerDatabase;
import de.blau.android.resources.TileLayerDialog;
import de.blau.android.resources.TileLayerDialog.OnUpdateListener;
import de.blau.android.resources.TileLayerSource;
import de.blau.android.resources.TileLayerSource.Category;
import de.blau.android.resources.TileLayerSource.TileType;
Expand All @@ -112,7 +113,7 @@
* @author Simon Poole
*
*/
public class Layers extends AbstractConfigurationDialog {
public class Layers extends AbstractConfigurationDialog implements OnUpdateListener {
private static final String DEBUG_TAG = Layers.class.getName();

private static final int VERTICAL_OFFSET = 64;
Expand All @@ -127,6 +128,8 @@ public class Layers extends AbstractConfigurationDialog {

private TableLayout tl;

private OnUpdateListener updateListener;

/**
* Show dialog that allows to configure the layers
*
Expand Down Expand Up @@ -258,7 +261,7 @@ public AppCompatDialog onCreateDialog(Bundle savedInstanceState) {

item = popup.getMenu().add(R.string.layer_add_custom_imagery);
item.setOnMenuItemClickListener(unused -> {
TileLayerDialog.showLayerDialog(activity, null, () -> updateDialogAndPrefs(activity, prefs, map));
TileLayerDialog.showDialog(this, null);
return true;
});

Expand All @@ -270,15 +273,13 @@ public AppCompatDialog onCreateDialog(Bundle savedInstanceState) {

item = popup.getMenu().add(R.string.menu_tools_add_imagery_from_oam);
item.setOnMenuItemClickListener(unused -> {
OAMCatalogView.queryAndSelectLayers(getActivity(), activity instanceof Main ? ((Main) activity).getMap().getViewBox() : null,
() -> updateDialogAndPrefs(activity, prefs, map));
OAMCatalogView.showDialog(this, activity instanceof Main ? ((Main) activity).getMap().getViewBox() : null);
return true;
});

item = popup.getMenu().add(R.string.add_imagery_from_wms_endpoint);
item.setOnMenuItemClickListener(unused -> {
WmsEndpointDatabaseView ui = new WmsEndpointDatabaseView();
ui.manageEndpoints(getActivity(), () -> updateDialogAndPrefs(activity, prefs, map));
WmsEndpointDatabaseView.showDialog(this);
return true;
});

Expand Down Expand Up @@ -748,11 +749,12 @@ public void onClick(View arg0) {
editItem.setOnMenuItemClickListener(unused -> {
try (TileLayerDatabase tlDb = new TileLayerDatabase(activity); SQLiteDatabase db = tlDb.getReadableDatabase()) {
long rowid = TileLayerDatabase.getLayerRowId(db, currentServerId);
TileLayerDialog.showLayerDialog(activity, rowid, null, () -> {
updateListener = () -> {
populateImageryLists(activity);
map.setUpLayers(activity);
updateDialogAndPrefs(activity, App.getLogic().getPrefs(), map);
});

};
TileLayerDialog.showDialog(Layers.this, rowid, null);
} catch (IllegalArgumentException iaex) {
Snack.toastTopError(activity, iaex.getMessage());
}
Expand Down Expand Up @@ -1286,4 +1288,14 @@ private void setPrefs(@Nullable FragmentActivity activity, @NonNull Preferences
App.getLogic().getMap().setPrefs(activity, prefs);
}
}

@Override
public void update() {
if (updateListener != null) {
updateListener.update();
updateListener = null;
}
final Logic logic = App.getLogic();
updateDialogAndPrefs(getActivity(), logic.getPrefs(), logic.getMap());
}
}
3 changes: 1 addition & 2 deletions src/main/java/de/blau/android/prefs/PrefEditorFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ private void setPreferenceListeners(@NonNull final Resources r) {
if (customLayersPref != null) {
customLayersPref.setOnPreferenceClickListener(preference -> {
Log.d(DEBUG_TAG, "onPreferenceClick custom layers");
TileLayerDatabaseView ui = new TileLayerDatabaseView();
ui.manageLayers(getActivity());
TileLayerDatabaseView.showDialog(getActivity());
return true;
});
}
Expand Down
8 changes: 7 additions & 1 deletion src/main/java/de/blau/android/resources/LayerEntry.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package de.blau.android.resources;

import java.io.Serializable;

import de.blau.android.osm.BoundingBox;

/**
* Small container class for layer configuration information
*
* @author simon
*
*/
public class LayerEntry {
public class LayerEntry implements Serializable {

private static final long serialVersionUID = 1L;

String id;
String title;
String tileUrl;
Expand Down
119 changes: 86 additions & 33 deletions src/main/java/de/blau/android/resources/OAMCatalogView.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.List;

import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
Expand All @@ -12,25 +13,76 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDialog;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import de.blau.android.App;
import de.blau.android.Logic;
import de.blau.android.Main;
import de.blau.android.R;
import de.blau.android.contract.Urls;
import de.blau.android.dialogs.Progress;
import de.blau.android.osm.BoundingBox;
import de.blau.android.resources.TileLayerDialog.OnUpdateListener;
import de.blau.android.util.ExecutorTask;
import de.blau.android.util.ImmersiveDialogFragment;
import de.blau.android.util.Snack;
import de.blau.android.util.Util;

public final class OAMCatalogView {
public final class OAMCatalogView extends ImmersiveDialogFragment implements OnUpdateListener {
private static final String DEBUG_TAG = OAMCatalogView.class.getSimpleName();

private static final String BOUNDING_BOX_KEY = "boundingbox";

private static final String TAG = "fragment_oam_catalog";

/**
* Private constructor to stop instantiation
* Query the OAM catalog and display the results for selection
*
* @param activity the calling Activity
* @param box a BoundingBox to search in or null for the whole world
*
*/
private OAMCatalogView() {
// private
public static void showDialog(@NonNull Fragment parent, @Nullable final BoundingBox box) {
dismissDialog(parent);
try {
FragmentManager fm = parent.getChildFragmentManager();
FragmentActivity activity = parent.getActivity();
if (activity instanceof Main) {
((Main) activity).descheduleAutoLock();
}
OAMCatalogView fragment = newInstance(box);
fragment.show(fm, TAG);
} catch (IllegalStateException isex) {
Log.e(DEBUG_TAG, "showDialog", isex);
}
}

/**
* Dismiss the Dialog
*
* @param parent the calling FragmentActivity
*/
private static void dismissDialog(@NonNull Fragment parent) {
de.blau.android.dialogs.Util.dismissDialog(parent, TAG);
}

/**
* Create new instance of this object
*
* @param result the List of Result elements
* @return a TileLayerDialog instance
*/
private static OAMCatalogView newInstance(@Nullable final BoundingBox box) {
OAMCatalogView f = new OAMCatalogView();
Bundle args = new Bundle();
args.putSerializable(BOUNDING_BOX_KEY, box);

f.setArguments(args);
f.setShowsDialog(true);

return f;
}

/**
Expand All @@ -41,8 +93,24 @@ private OAMCatalogView() {
* @param box a BoundingBox to search in or null for the whole world
* @param updateListener a TileLayerDialog.OnUpdateListener to execute or null
*/
public static void displayLayers(@NonNull final FragmentActivity activity, @NonNull final List<LayerEntry> catalog, @Nullable final BoundingBox box,
@Nullable final TileLayerDialog.OnUpdateListener updateListener) {
private void displayLayers(@NonNull final ListView layerList, @NonNull final List<LayerEntry> catalog) {
ArrayAdapter<LayerEntry> layerAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, catalog);
layerList.setAdapter(layerAdapter);
layerList.setOnItemClickListener((parent, view, position, id) -> {
LayerEntry entry = catalog.get(position);
TileLayerDialog.showDialog(OAMCatalogView.this, entry);
});
}

@NonNull
@Override
public AppCompatDialog onCreateDialog(Bundle savedInstanceState) {

Bundle bundle = savedInstanceState == null ? getArguments() : savedInstanceState;

BoundingBox box = Util.getSerializeable(bundle, BOUNDING_BOX_KEY, BoundingBox.class);

FragmentActivity activity = getActivity();
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(activity);
View layerListView = LayoutInflater.from(activity).inflate(R.layout.oam_layer_list, null);
dialogBuilder.setTitle(R.string.oam_layer_title);
Expand All @@ -56,33 +124,7 @@ public static void displayLayers(@NonNull final FragmentActivity activity, @NonN
TileLayerDatabaseView.resetLayer(activity, db);
}
});
final AlertDialog dialog = dialogBuilder.create();
ArrayAdapter<LayerEntry> layerAdapter = new ArrayAdapter<>(activity, android.R.layout.simple_list_item_1, catalog);
layerList.setAdapter(layerAdapter);
layerList.setOnItemClickListener((parent, view, position, id) -> {
LayerEntry entry = catalog.get(position);
TileLayerDialog.showLayerDialog(activity, entry, () -> {
dialog.dismiss();
try (final TileLayerDatabase tlDb = new TileLayerDatabase(activity); SQLiteDatabase db = tlDb.getReadableDatabase()) {
TileLayerDatabaseView.resetLayer(activity, db);
}
if (updateListener != null) {
updateListener.update();
}
});
});
dialog.show();
}

/**
* Query the OAM catalog and display the results for selection
*
* @param activity the calling Activity
* @param box a BoundingBox to search in or null for the whole world
* @param updateListener a TileLayerDialog.OnUpdateListener to execute or null
*/
public static void queryAndSelectLayers(@NonNull FragmentActivity activity, @Nullable final BoundingBox box,
@Nullable final TileLayerDialog.OnUpdateListener updateListener) {
Logic logic = App.getLogic();
new ExecutorTask<Void, Void, List<LayerEntry>>(logic.getExecutorService(), logic.getHandler()) {
@Override
Expand Down Expand Up @@ -113,11 +155,22 @@ protected List<LayerEntry> doInBackground(Void param) {
protected void onPostExecute(List<LayerEntry> catalog) {
Progress.dismissDialog(activity, Progress.PROGRESS_QUERY_OAM);
if (catalog != null && !catalog.isEmpty()) {
OAMCatalogView.displayLayers(activity, catalog, box, updateListener);
displayLayers(layerList, catalog);
} else {
Snack.toastTopInfo(activity, R.string.toast_nothing_found);
}
}
}.execute();

return dialogBuilder.create();
}

@Override
public void update() {
getDialog().dismiss();
try (final TileLayerDatabase tlDb = new TileLayerDatabase(getActivity()); SQLiteDatabase db = tlDb.getReadableDatabase()) {
TileLayerDatabaseView.resetLayer(getActivity(), db);
}
TileLayerDialog.update(this);
}
}
Loading

0 comments on commit 304699f

Please sign in to comment.