New style UI
This commit is contained in:
@@ -26,7 +26,6 @@ public final class FileHelper {
|
||||
|
||||
public static String loadStringFromUserFile(String filePath) {
|
||||
File file = new File(filePath);
|
||||
|
||||
try (FileInputStream fis = new FileInputStream(file)) {
|
||||
int size = fis.available();
|
||||
byte[] buffer = new byte[size];
|
||||
@@ -38,6 +37,39 @@ public final class FileHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeUserFile(String path, String fileName, String content, AppController app) throws IOException {
|
||||
try {
|
||||
File userDirectory = new File(app.getActivity().getExternalFilesDir(null), path);
|
||||
|
||||
if (!userDirectory.exists() && !userDirectory.mkdirs()) {
|
||||
app.logcat("Failed to create directory: " + userDirectory.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
|
||||
File file = new File(userDirectory, fileName);
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(file);
|
||||
OutputStreamWriter writer = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) {
|
||||
|
||||
writer.write(content);
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean deleteFile(String filePath) {
|
||||
File file = new File(filePath);
|
||||
|
||||
if (!file.exists() || !file.isFile()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return file.delete();
|
||||
}
|
||||
|
||||
public static String[] getAssetFiles(String path, String fileExt, AppController app) {
|
||||
AssetManager assetManager = app.getActivity().getAssets();
|
||||
try {
|
||||
@@ -77,9 +109,20 @@ public final class FileHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean userFileExists(String path, String fileName, AppController app) {
|
||||
File userDirectory = new File(app.getActivity().getExternalFilesDir(null), path);
|
||||
|
||||
if (!userDirectory.exists() || !userDirectory.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File file = new File(userDirectory, fileName);
|
||||
|
||||
return file.exists() && file.isFile();
|
||||
}
|
||||
|
||||
public static String[] getUserFiles(String path, String fileExt, AppController app) {
|
||||
String packageName = app.getActivity().getPackageName();
|
||||
File userDirectory = new File(Environment.getExternalStorageDirectory(), "Android/data/" + packageName + "/" + path);
|
||||
File userDirectory = new File(app.getActivity().getExternalFilesDir(null), path);
|
||||
|
||||
if (!userDirectory.exists() || !userDirectory.isDirectory())
|
||||
return new String[0];
|
||||
|
||||
+4
@@ -1,9 +1,13 @@
|
||||
package eu.konggdev.strikemaps.map.overlay.implementation;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.map.overlay.MapOverlay;
|
||||
|
||||
public class PointSelectionOverlay implements MapOverlay {
|
||||
AppController app;
|
||||
MapComponent map;
|
||||
@Override
|
||||
public JsonNode makePatch() {
|
||||
return null;
|
||||
|
||||
+2
@@ -72,10 +72,12 @@ public class MapLibreGLJSRenderer implements MapRenderer {
|
||||
|
||||
//Sources
|
||||
ObjectNode sources = mapper.createObjectNode();
|
||||
if (style.sources != null)
|
||||
style.sources.forEach((k, v) -> sources.set(k, mapper.valueToTree(v)));
|
||||
|
||||
//Layers
|
||||
ArrayNode layers = mapper.createArrayNode();
|
||||
if (style.layerDefinitions != null)
|
||||
layers.addAll((ArrayNode) style.layerDefinitions);
|
||||
|
||||
//Set all to root
|
||||
|
||||
+3
-1
@@ -56,10 +56,12 @@ public class MapLibreNativeRenderer implements MapRenderer, OnMapReadyCallback {
|
||||
|
||||
//Sources
|
||||
ObjectNode sources = mapper.createObjectNode();
|
||||
if (style.sources != null)
|
||||
style.sources.forEach((k, v) -> sources.set(k, mapper.valueToTree(v)));
|
||||
|
||||
//Layers
|
||||
ArrayNode layers = mapper.createArrayNode();
|
||||
if (style.layerDefinitions != null)
|
||||
layers.addAll((ArrayNode) style.layerDefinitions);
|
||||
|
||||
//Set all to root
|
||||
@@ -126,7 +128,7 @@ public class MapLibreNativeRenderer implements MapRenderer, OnMapReadyCallback {
|
||||
public void onMapReady(@NonNull MapLibreMap maplibreMap) {
|
||||
this.map = maplibreMap;
|
||||
|
||||
controller.setStyle(MapStyle.fromJsonFile(UserPrefsHelper.startupMapStyle(app.getPrefs()), app));
|
||||
controller.setStyle(MapStyle.fromFile(UserPrefsHelper.startupMapStyle(app.getPrefs()), app));
|
||||
|
||||
//I have my own implementation of attribution that credits MapLibre among others, it's not as bad as it looks :)
|
||||
map.getUiSettings().setLogoEnabled(false);
|
||||
|
||||
@@ -23,7 +23,7 @@ public class MapStyle {
|
||||
public ArrayNode layerDefinitions; // "layers" array
|
||||
|
||||
//FIXME
|
||||
public static MapStyle fromJsonFile(String filename, AppController app) {
|
||||
public static MapStyle fromFile(String filename, AppController app) {
|
||||
String styleContents;
|
||||
if (filename.startsWith("/storage")) styleContents = FileHelper.loadStringFromUserFile(filename);
|
||||
else styleContents = FileHelper.loadStringFromAssetFile(filename, app);
|
||||
|
||||
@@ -15,6 +15,7 @@ public class GenericItem implements UIItem {
|
||||
@NonNull public String name;
|
||||
public Bitmap image;
|
||||
public Runnable onClick;
|
||||
public Runnable onLongClick;
|
||||
boolean hasImage;
|
||||
|
||||
public GenericItem(String refName) {
|
||||
@@ -26,6 +27,12 @@ public class GenericItem implements UIItem {
|
||||
this.onClick = onClick;
|
||||
hasImage = false;
|
||||
}
|
||||
public GenericItem(String refName, Runnable onClick, Runnable onLongClick) {
|
||||
this.name = refName;
|
||||
this.onClick = onClick;
|
||||
this.onLongClick = onLongClick;
|
||||
hasImage = false;
|
||||
}
|
||||
public GenericItem(String refName, Bitmap refImage) {
|
||||
this.name = refName;
|
||||
this.image = refImage;
|
||||
@@ -38,18 +45,34 @@ public class GenericItem implements UIItem {
|
||||
hasImage = true;
|
||||
}
|
||||
|
||||
public final static GenericItem fromStyle(MapStyle style, MapComponent map) {
|
||||
public GenericItem(String refName, Bitmap refImage, Runnable onClick, Runnable onLongClick) {
|
||||
this.name = refName;
|
||||
this.image = refImage;
|
||||
this.onClick = onClick;
|
||||
this.onLongClick = onLongClick;
|
||||
hasImage = true;
|
||||
}
|
||||
|
||||
public final static GenericItem fromStyle(MapStyle style, MapComponent map, Runnable onClick) {
|
||||
if(style == null) return new GenericItem("Unknown");
|
||||
if(style.icon != null)
|
||||
return new GenericItem(style.name, style.icon, () -> map.setStyle(style));
|
||||
return new GenericItem(style.name, () -> map.setStyle(style));
|
||||
return new GenericItem(style.name, style.icon, onClick);
|
||||
return new GenericItem(style.name, onClick);
|
||||
}
|
||||
public final static GenericItem fromStyle(MapStyle style, MapComponent map, Runnable onClick, Runnable onLongClick) {
|
||||
if(style == null) return new GenericItem("Unknown");
|
||||
if(style.icon != null)
|
||||
return new GenericItem(style.name, style.icon, onClick, onLongClick);
|
||||
return new GenericItem(style.name, onClick, onLongClick);
|
||||
}
|
||||
|
||||
public View makeView(UIComponent spawner) {
|
||||
View v = spawner.inflateUi(R.layout.item_generic);
|
||||
//FIXME: These shouldn't be casted like that!
|
||||
((TextView) v.findViewById(R.id.name)).setText(name);
|
||||
if(image != null) ((ImageButton) v.findViewById(R.id.image)).setImageBitmap(image);
|
||||
if(onClick != null) v.findViewById(R.id.image).setOnClickListener(click(onClick));
|
||||
if(onLongClick != null) v.findViewById(R.id.image).setOnLongClickListener(longClick(onLongClick));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,256 @@
|
||||
package eu.konggdev.strikemaps.ui.factory;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.Toast;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.*;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.app.util.JsonPatcher;
|
||||
import eu.konggdev.strikemaps.data.helper.FileHelper;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.map.style.MapStyle;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
import eu.konggdev.strikemaps.ui.element.item.GenericItem;
|
||||
import eu.konggdev.strikemaps.ui.element.item.PreviewItem;
|
||||
import eu.konggdev.strikemaps.ui.fragment.popup.FragmentMapChangePopup;
|
||||
import org.maplibre.geojson.Feature;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static androidx.core.content.ContextCompat.getSystemService;
|
||||
|
||||
//FIXME: Move Item functions into specific classes for specific types - e.g. StyleItem
|
||||
public final class AlertDialogFactory {
|
||||
public static AlertDialog copyBuiltInStyle(AppController app, MapComponent map, UIComponent ui, FragmentMapChangePopup mapChangePopup) {
|
||||
//TODO: Use an UI element thats supposed to be vertical, instead of GenericItem
|
||||
List<String> styles = Arrays.asList(FileHelper.getAssetFiles("bundled/style", ".style.json", app));
|
||||
|
||||
LinearLayout container = new LinearLayout(app.getActivity());
|
||||
container.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
for (String style : styles) {
|
||||
View itemView = GenericItem
|
||||
.fromStyle(
|
||||
MapStyle.fromFile(style, app),
|
||||
map,
|
||||
() -> ui.alert(AlertDialogFactory.createStyle(app, FileHelper.loadStringFromAssetFile(style, app), mapChangePopup))
|
||||
)
|
||||
.makeView(ui);
|
||||
|
||||
container.addView(itemView);
|
||||
}
|
||||
|
||||
ScrollView scrollView = new ScrollView(app.getActivity());
|
||||
scrollView.addView(container);
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(app.getActivity())
|
||||
.setTitle("Copy from")
|
||||
.setView(scrollView)
|
||||
.setNegativeButton("Cancel", null)
|
||||
.create();
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public static AlertDialog createStyle(AppController app, String baseStyleContents, FragmentMapChangePopup mapChangePopup) {
|
||||
final EditText nameInput = new EditText(app.getActivity());
|
||||
nameInput.setHint("Name");
|
||||
|
||||
final CheckBox inferFileName = new CheckBox(app.getActivity());
|
||||
inferFileName.setText("Infer filename automatically");
|
||||
inferFileName.setChecked(true);
|
||||
|
||||
final EditText fileInput = new EditText(app.getActivity());
|
||||
fileInput.setHint("Filename");
|
||||
|
||||
final TextView inferedFileName = new TextView(app.getActivity());
|
||||
inferedFileName.setPadding(0, 2, 0, 0);
|
||||
LinearLayout container = new LinearLayout(app.getActivity());
|
||||
container.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
int padding = (int) (20 * app.getActivity().getResources().getDisplayMetrics().density);
|
||||
container.setPadding(padding, padding, padding, 0);
|
||||
|
||||
container.addView(nameInput);
|
||||
container.addView(inferFileName);
|
||||
container.addView(fileInput);
|
||||
container.addView(inferedFileName);
|
||||
|
||||
inferFileName.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
fileInput.setVisibility(isChecked ? View.GONE : View.VISIBLE);
|
||||
inferedFileName.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
||||
});
|
||||
|
||||
fileInput.setVisibility(inferFileName.isChecked() ? View.GONE : View.VISIBLE);
|
||||
inferedFileName.setVisibility(inferFileName.isChecked() ? View.VISIBLE : View.GONE);
|
||||
|
||||
nameInput.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
String nameText = "";
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
|
||||
if (!s.isEmpty() && s != null) {
|
||||
nameText = "File name will be: " + s.toString().toLowerCase(Locale.ROOT) + ".style.json";
|
||||
}
|
||||
} else if (s != null) {
|
||||
nameText = "File name will be: " + s.toString().toLowerCase(Locale.ROOT) + ".style.json";
|
||||
}
|
||||
|
||||
inferedFileName.setText(nameText);
|
||||
}
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {}
|
||||
});
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(app.getActivity())
|
||||
.setTitle("Create")
|
||||
.setView(container)
|
||||
.setPositiveButton("Create", null)
|
||||
.setNegativeButton("Cancel", (d, w) -> d.dismiss())
|
||||
.create();
|
||||
|
||||
dialog.setOnShowListener(d -> {
|
||||
Button createButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
|
||||
createButton.setOnClickListener(v -> {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
boolean nameEntryRequired = true;
|
||||
String styleContentName = "";
|
||||
if (baseStyleContents != null) {
|
||||
try {
|
||||
JsonNode root = mapper.readTree(baseStyleContents);
|
||||
if (!root.path("name").asText().isEmpty()) {
|
||||
nameEntryRequired = false; //We can take the name from the style
|
||||
styleContentName = root.path("name").asText();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
String name = nameInput.getText().toString().trim();
|
||||
|
||||
if (name.isEmpty() && nameEntryRequired) {
|
||||
nameInput.setError("Name required");
|
||||
return;
|
||||
} else if (name.isEmpty() && !nameEntryRequired) {
|
||||
name = styleContentName;
|
||||
}
|
||||
|
||||
assert !name.isEmpty();
|
||||
|
||||
String fileName;
|
||||
if (inferFileName.isChecked()) {
|
||||
fileName = name.toLowerCase(Locale.ROOT) + ".style.json";
|
||||
} else {
|
||||
fileName = fileInput.getText().toString();
|
||||
if (fileName.isEmpty()) {
|
||||
fileInput.setError("File name required");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fileName.endsWith(".style.json")) {
|
||||
fileInput.setError("File must end with .style.json");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
JsonNode root;
|
||||
if(baseStyleContents != null) {
|
||||
if(!baseStyleContents.isEmpty()) {
|
||||
root = mapper.readTree(baseStyleContents);
|
||||
} else {
|
||||
root = mapper.createObjectNode();
|
||||
}
|
||||
} else {
|
||||
root = mapper.createObjectNode();
|
||||
}
|
||||
|
||||
if (!root.path("name").asText().isEmpty()) {
|
||||
ObjectNode node = mapper.createObjectNode();
|
||||
node.put("name", name);
|
||||
root = JsonPatcher.patch(root, node);
|
||||
}
|
||||
|
||||
if (FileHelper.userFileExists("style", fileName, app)) {
|
||||
app.getUi().alert(askUserOverwriteFile(app, fileName, "style", mapper.writeValueAsString(root), dialog));
|
||||
} else {
|
||||
FileHelper.writeUserFile("style", fileName, mapper.writeValueAsString(root), app);
|
||||
}
|
||||
dialog.dismiss();
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(app.getActivity(), "Failed to create", Toast.LENGTH_SHORT).show();
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
mapChangePopup.reloadStyles();
|
||||
});
|
||||
});
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public static AlertDialog askUserOverwriteFile(AppController app, String fileName, String path, String content) {
|
||||
return new AlertDialog.Builder(app.getActivity())
|
||||
.setMessage("Style of filename " + fileName + " already exists, do you wish to overwrite it?")
|
||||
.setPositiveButton("Yes", (dialog, which) -> {
|
||||
try {
|
||||
FileHelper.writeUserFile(path, fileName, content, app);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
})
|
||||
.setNegativeButton("No", null)
|
||||
.create();
|
||||
}
|
||||
|
||||
public static AlertDialog askUserOverwriteFile(AppController app, String fileName, String path, String content, AlertDialog originDialog) {
|
||||
|
||||
return new AlertDialog.Builder(app.getActivity())
|
||||
.setMessage("Style of filename: " + fileName + " already exists, do you wish to overwrite it?")
|
||||
.setPositiveButton("Yes", (dialog, which) -> {
|
||||
try {
|
||||
FileHelper.writeUserFile(path, fileName, content, app);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (originDialog != null) {
|
||||
originDialog.dismiss();
|
||||
}
|
||||
dialog.dismiss();
|
||||
})
|
||||
.setNegativeButton("No", (dialog, which) -> {
|
||||
if (originDialog != null) {
|
||||
originDialog.dismiss();
|
||||
}
|
||||
dialog.dismiss();
|
||||
})
|
||||
.create();
|
||||
}
|
||||
|
||||
public static AlertDialog pointSelector(AppController app, List<Feature> features, Consumer<Feature> callback) {
|
||||
LinearLayout layout = new LinearLayout(app.getActivity());
|
||||
layout.setOrientation(LinearLayout.VERTICAL);
|
||||
@@ -32,7 +266,7 @@ public final class AlertDialogFactory {
|
||||
for (Feature feature : features) {
|
||||
View itemView = PreviewItem.fromFeature(feature).makeView(app.getUi(), v -> {
|
||||
dialog.dismiss();
|
||||
new android.os.Handler(android.os.Looper.getMainLooper())
|
||||
new Handler(Looper.getMainLooper())
|
||||
.post(() -> callback.accept(feature));
|
||||
});
|
||||
layout.addView(itemView);
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
package eu.konggdev.strikemaps.ui.fragment.dialog;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import androidx.annotation.UiContext;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||
import eu.konggdev.strikemaps.R;
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.data.helper.FileHelper;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
import eu.konggdev.strikemaps.ui.factory.AlertDialogFactory;
|
||||
import eu.konggdev.strikemaps.ui.fragment.popup.FragmentMapChangePopup;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class NewStyleBottomSheet extends BottomSheetDialogFragment {
|
||||
private final String styleBase = "{\"name\":\"None\"}";
|
||||
|
||||
@NonNull AppController app;
|
||||
@NonNull MapComponent map;
|
||||
@NonNull UIComponent ui;
|
||||
@NonNull
|
||||
FragmentMapChangePopup mapChangePopup;
|
||||
|
||||
|
||||
private final ActivityResultLauncher<Intent> importLauncher =
|
||||
registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
if (result.getResultCode() == android.app.Activity.RESULT_OK
|
||||
&& result.getData() != null) {
|
||||
|
||||
Uri uri = result.getData().getData();
|
||||
|
||||
try (InputStream in = requireContext()
|
||||
.getContentResolver()
|
||||
.openInputStream(uri)) {
|
||||
|
||||
try (Cursor cursor = requireContext()
|
||||
.getContentResolver()
|
||||
.query(uri, null, null, null, null)) {
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
||||
if (nameIndex >= 0) {
|
||||
String fileName = cursor.getString(nameIndex);
|
||||
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(in)
|
||||
);
|
||||
|
||||
StringBuilder contentBuilder = new StringBuilder();
|
||||
String line;
|
||||
|
||||
while ((line = reader.readLine()) != null) {
|
||||
contentBuilder.append(line).append(System.lineSeparator());
|
||||
}
|
||||
reader.close();
|
||||
String content = contentBuilder.toString();
|
||||
|
||||
if (fileName != null && !fileName.endsWith(".style.json")) {
|
||||
app.getUi().alert(
|
||||
AlertDialogFactory.createStyle(
|
||||
app,
|
||||
content,
|
||||
mapChangePopup
|
||||
)
|
||||
);
|
||||
|
||||
return;
|
||||
} else {
|
||||
if (!FileHelper.userFileExists("style", fileName, app)) {
|
||||
FileHelper.writeUserFile("style", fileName, content, app);
|
||||
} else {
|
||||
app.getUi().alert(AlertDialogFactory.askUserOverwriteFile(app, fileName, "style", content));
|
||||
}
|
||||
|
||||
mapChangePopup.reloadStyles();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
private void showImportDialog() {
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
intent.setType("application/json");
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
|
||||
importLauncher.launch(intent);
|
||||
}
|
||||
|
||||
public NewStyleBottomSheet(AppController app, MapComponent map, UIComponent ui, FragmentMapChangePopup mapChangePopup) {
|
||||
this.app = app;
|
||||
this.map = map;
|
||||
this.ui = ui;
|
||||
this.mapChangePopup = mapChangePopup;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
|
||||
View view = inflater.inflate(R.layout.dialog_new_style, container, false);
|
||||
|
||||
Button builtInBtn = view.findViewById(R.id.buttonFromBuiltInStyle);
|
||||
Button fileBtn = view.findViewById(R.id.buttonFromFile);
|
||||
Button emptyBtn = view.findViewById(R.id.buttonCreateEmpty);
|
||||
|
||||
builtInBtn.setOnClickListener(v -> {
|
||||
app.getUi().alert(AlertDialogFactory.copyBuiltInStyle(app, map, ui, mapChangePopup));
|
||||
});
|
||||
|
||||
fileBtn.setOnClickListener(v -> {
|
||||
showImportDialog();
|
||||
});
|
||||
|
||||
emptyBtn.setOnClickListener(v -> {
|
||||
app.getUi().alert(AlertDialogFactory.createStyle(app, styleBase, mapChangePopup));
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
package eu.konggdev.strikemaps.ui.fragment.dialog;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||
import eu.konggdev.strikemaps.R;
|
||||
import eu.konggdev.strikemaps.app.AppController;
|
||||
import eu.konggdev.strikemaps.data.helper.FileHelper;
|
||||
import eu.konggdev.strikemaps.map.MapComponent;
|
||||
import eu.konggdev.strikemaps.map.style.MapStyle;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
import eu.konggdev.strikemaps.ui.factory.AlertDialogFactory;
|
||||
import eu.konggdev.strikemaps.ui.fragment.popup.FragmentMapChangePopup;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Objects;
|
||||
|
||||
import static android.media.MediaExtractor.MetricsConstants.MIME_TYPE;
|
||||
|
||||
public class StyleDetailsBottomSheet extends BottomSheetDialogFragment {
|
||||
@NonNull
|
||||
AppController app;
|
||||
@NonNull
|
||||
MapComponent map;
|
||||
@NonNull
|
||||
UIComponent ui;
|
||||
@NonNull
|
||||
FragmentMapChangePopup mapChangePopup;
|
||||
|
||||
private final MapStyle style;
|
||||
private final String stylePath;
|
||||
|
||||
private final ActivityResultLauncher<Intent> exportLauncher =
|
||||
registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
|
||||
if (result.getResultCode() == android.app.Activity.RESULT_OK
|
||||
&& result.getData() != null) {
|
||||
|
||||
Uri uri = result.getData().getData();
|
||||
|
||||
try (OutputStream out =
|
||||
requireContext()
|
||||
.getContentResolver()
|
||||
.openOutputStream(uri)) {
|
||||
|
||||
out.write(getContents().getBytes());
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
//Action definitions
|
||||
//*//
|
||||
void deleteStyle() {
|
||||
boolean deleted = FileHelper.deleteFile(stylePath);
|
||||
if (!deleted) {
|
||||
Toast.makeText(requireContext(), "Failed deleting style", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
mapChangePopup.reloadStyles();
|
||||
dismiss();
|
||||
}
|
||||
|
||||
|
||||
private void showExportDialog(String fileName) {
|
||||
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
||||
intent.setType("application/json");
|
||||
intent.putExtra(Intent.EXTRA_TITLE, fileName);
|
||||
|
||||
exportLauncher.launch(intent);
|
||||
}
|
||||
//*//
|
||||
|
||||
String getContents() {
|
||||
if (stylePath.startsWith("/storage")) return FileHelper.loadStringFromUserFile(stylePath);
|
||||
else return FileHelper.loadStringFromAssetFile(stylePath, app);
|
||||
}
|
||||
|
||||
public StyleDetailsBottomSheet(AppController app, MapComponent map, UIComponent ui, FragmentMapChangePopup mapChangePopup, MapStyle style, String stylePath) {
|
||||
this.app = app;
|
||||
this.map = map;
|
||||
this.ui = ui;
|
||||
this.mapChangePopup = mapChangePopup;
|
||||
this.style = style;
|
||||
this.stylePath = stylePath;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
|
||||
View view = inflater.inflate(R.layout.dialog_style_details, container, false);
|
||||
|
||||
TextView styleNameView = view.findViewById(R.id.styleName);
|
||||
TextView fileNameView = view.findViewById(R.id.fileName);
|
||||
TextView styleTypeView = view.findViewById(R.id.styleType);
|
||||
|
||||
ConstraintLayout editButtonLayout = view.findViewById(R.id.editButton);
|
||||
ConstraintLayout copyButtonLayout = view.findViewById(R.id.copyButton);
|
||||
ConstraintLayout exportButtonLayout = view.findViewById(R.id.exportButton);
|
||||
ConstraintLayout deleteButtonLayout = view.findViewById(R.id.deleteButton);
|
||||
ConstraintLayout closeButtonLayout = view.findViewById(R.id.closeButton);
|
||||
|
||||
|
||||
styleNameView.setText(style.name);
|
||||
|
||||
String[] pathSplit = stylePath.split("/");
|
||||
String fileName = pathSplit[pathSplit.length - 1];
|
||||
|
||||
fileNameView.setText(fileName);
|
||||
|
||||
if (Objects.equals(pathSplit[0], "bundled") && pathSplit.length > 1) {
|
||||
styleTypeView.setText("Built-In Style");
|
||||
deleteButtonLayout.setVisibility(View.GONE);
|
||||
} else {
|
||||
styleTypeView.setText("User Style");
|
||||
}
|
||||
|
||||
|
||||
editButtonLayout.setOnClickListener(v -> Toast.makeText(requireContext(), "Editor not implemented yet\nWait for release", Toast.LENGTH_SHORT).show());
|
||||
copyButtonLayout.setOnClickListener(v -> ui.alert(AlertDialogFactory.createStyle(app, getContents(), mapChangePopup)));
|
||||
exportButtonLayout.setOnClickListener(v -> showExportDialog(fileName));
|
||||
deleteButtonLayout.setOnClickListener(v -> deleteStyle());
|
||||
closeButtonLayout.setOnClickListener(v -> dismiss());
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
+37
-6
@@ -1,5 +1,7 @@
|
||||
package eu.konggdev.strikemaps.ui.fragment.popup;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
@@ -14,6 +16,8 @@ import eu.konggdev.strikemaps.map.MapComponent;
|
||||
|
||||
import eu.konggdev.strikemaps.map.style.MapStyle;
|
||||
import eu.konggdev.strikemaps.ui.UIComponent;
|
||||
import eu.konggdev.strikemaps.ui.fragment.dialog.NewStyleBottomSheet;
|
||||
import eu.konggdev.strikemaps.ui.fragment.dialog.StyleDetailsBottomSheet;
|
||||
import eu.konggdev.strikemaps.ui.element.item.GenericItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -28,6 +32,19 @@ public class FragmentMapChangePopup extends Fragment implements Popup {
|
||||
|
||||
private final Integer region;
|
||||
|
||||
private View view;
|
||||
|
||||
// Action definitions
|
||||
//*//
|
||||
void newStyleFlow() {
|
||||
new NewStyleBottomSheet(app, map, ui, this).show(app.getActivity().getSupportFragmentManager(), "NewStyleBottomSheet");
|
||||
}
|
||||
|
||||
void styleDetails(MapStyle style, String stylePath) {
|
||||
new StyleDetailsBottomSheet(app, map, ui, this, style, stylePath).show(app.getActivity().getSupportFragmentManager(), "StyleDetailsBottomSheet");
|
||||
}
|
||||
//*//
|
||||
|
||||
public FragmentMapChangePopup(AppController app, Integer region) {
|
||||
super(R.layout.popup_map_change);
|
||||
this.app = app;
|
||||
@@ -46,16 +63,30 @@ public class FragmentMapChangePopup extends Fragment implements Popup {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void reloadStyles() {
|
||||
List<String> stylePaths = new ArrayList<>();
|
||||
stylePaths.addAll(Arrays.asList(FileHelper.getAssetFiles("bundled/style", ".style.json", app)));
|
||||
stylePaths.addAll(Arrays.asList(FileHelper.getUserFiles("style", ".style.json", app)));
|
||||
LinearLayout stylesLayout = view.findViewById(R.id.stylesLayout);
|
||||
stylesLayout.removeAllViews();
|
||||
for (String stylePath : stylePaths) {
|
||||
MapStyle parsedStyle = MapStyle.fromFile(stylePath, app);
|
||||
stylesLayout.addView(GenericItem.fromStyle(parsedStyle, map,
|
||||
() -> map.setStyle(parsedStyle),
|
||||
() -> this.styleDetails(parsedStyle, stylePath)).makeView(ui));
|
||||
}
|
||||
Bitmap addNewIcon = BitmapFactory.decodeResource(app.getActivity().getResources(), android.R.drawable.ic_menu_add);
|
||||
stylesLayout.addView(new GenericItem("",
|
||||
addNewIcon,
|
||||
this::newStyleFlow).makeView(ui));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
||||
//FIXME
|
||||
setupButton(view, R.id.closeButton, click(() -> ui.getCurrentScreen().closePopup()));
|
||||
setupDragHandle(view, view, () -> ui.getCurrentScreen().closePopup());
|
||||
List<String> stylePaths = new ArrayList<>();
|
||||
stylePaths.addAll(Arrays.asList(FileHelper.getAssetFiles("bundled/style", ".style.json", app)));
|
||||
stylePaths.addAll(Arrays.asList(FileHelper.getUserFiles("style", ".style.json", app)));
|
||||
LinearLayout stylesLayout = view.findViewById(R.id.stylesLayout);
|
||||
for (String style : stylePaths)
|
||||
stylesLayout.addView(GenericItem.fromStyle(MapStyle.fromJsonFile(style, app), map).makeView(ui));
|
||||
this.view = view;
|
||||
reloadStyles();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:background="#000000"
|
||||
android:padding="24dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:text="New style"
|
||||
android:textSize="20sp"
|
||||
android:textColor="#FFFFFF" />
|
||||
|
||||
<View
|
||||
android:id="@+id/headerDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="#FFFFFF" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonFromBuiltInStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="From built-in style"
|
||||
android:textColor="#FFFFFF"
|
||||
android:backgroundTint="#333333" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonFromFile"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="From file"
|
||||
android:textColor="#FFFFFF"
|
||||
android:backgroundTint="#333333" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonCreateEmpty"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="Create empty"
|
||||
android:textColor="#FFFFFF"
|
||||
android:backgroundTint="#333333" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,239 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:background="#000000"
|
||||
android:padding="12dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/styleName"
|
||||
android:layout_width="164dp"
|
||||
android:layout_height="34dp"
|
||||
android:gravity="center"
|
||||
android:text="Style Name"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fileName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="27dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:gravity="center"
|
||||
android:text="\?.style.json"
|
||||
android:textColor="#BDBDBD"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/styleName" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/styleType"
|
||||
android:layout_width="112dp"
|
||||
android:layout_height="27dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="Style Type?"
|
||||
android:textColor="#FDFDFD"
|
||||
android:textSize="18sp"
|
||||
android:gravity="center"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/fileName" />
|
||||
|
||||
<View
|
||||
android:id="@+id/headerDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:background="#FFFFFF"
|
||||
app:layout_constraintTop_toBottomOf="@id/styleType"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/editButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:background="#1B1A1A"
|
||||
app:layout_constraintTop_toBottomOf="@id/headerDivider"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/hideIcon"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:src="@android:drawable/ic_menu_edit"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/hideBtnText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="Edit style"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/copyButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:background="#1B1A1A"
|
||||
app:layout_constraintTop_toBottomOf="@id/editButton"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/copyIcon"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:src="@drawable/ic_copy"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/copyBtnText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="Copy style"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/exportButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:background="#1B1A1A"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/copyButton">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/exportIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:src="@android:drawable/ic_menu_save"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/exportBtnText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="Export style"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/deleteButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:background="#1B1A1A"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/exportButton"
|
||||
app:layout_constraintVertical_bias="0.081">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/deleteIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:src="@android:drawable/ic_menu_delete"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/deleteText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="Delete style"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/closeButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:background="#1B1A1A"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/deleteButton"
|
||||
tools:layout_editor_absoluteY="251dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/closeIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:src="@android:drawable/ic_menu_more"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/closeText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="Close"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
Reference in New Issue
Block a user