diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index eb22512fe1..156ab3832c 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -25,8 +25,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/src/io/anuke/mindustry/AndroidLauncher.java b/android/src/io/anuke/mindustry/AndroidLauncher.java
index 436c734b4f..eb54d83eff 100644
--- a/android/src/io/anuke/mindustry/AndroidLauncher.java
+++ b/android/src/io/anuke/mindustry/AndroidLauncher.java
@@ -11,6 +11,7 @@ import android.telephony.TelephonyManager;
import android.util.Log;
import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
+import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Base64Coder;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
@@ -19,23 +20,28 @@ import com.google.android.gms.security.ProviderInstaller;
import io.anuke.kryonet.DefaultThreadImpl;
import io.anuke.kryonet.KryoClient;
import io.anuke.kryonet.KryoServer;
-import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
import io.anuke.mindustry.core.Platform;
+import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
import io.anuke.mindustry.net.Net;
+import io.anuke.mindustry.ui.dialogs.FileChooser;
import io.anuke.ucore.core.Settings;
+import io.anuke.ucore.function.Consumer;
import io.anuke.ucore.scene.ui.TextField;
import io.anuke.ucore.scene.ui.layout.Unit;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
import java.util.Random;
public class AndroidLauncher extends AndroidApplication{
+ public static final int PERMISSION_REQUEST_CODE = 1;
+
boolean doubleScaleTablets = true;
- int WRITE_REQUEST_CODE = 1;
+ FileChooser chooser;
@Override
protected void onCreate(Bundle savedInstanceState){
@@ -79,22 +85,7 @@ public class AndroidLauncher extends AndroidApplication{
@Override
public void requestWritePerms() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED &&
- checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
- requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Manifest.permission.READ_EXTERNAL_STORAGE}, WRITE_REQUEST_CODE);
- }else{
- if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
- requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_REQUEST_CODE);
- }
-
- if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
- requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, WRITE_REQUEST_CODE);
- }
- }
- }
}
@Override
@@ -137,6 +128,34 @@ public class AndroidLauncher extends AndroidApplication{
return Base64Coder.decode(uuid);
}
}
+
+ @Override
+ public void shareFile(FileHandle file){
+
+ }
+
+ @Override
+ public void showFileChooser(String text, String content, Consumer cons, boolean open, String filetype) {
+ chooser = new FileChooser(text, file -> file.extension().equalsIgnoreCase(filetype), open, cons);
+
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M || (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
+ checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)){
+ chooser.show();
+ chooser = null;
+ }else {
+ ArrayList perms = new ArrayList<>();
+
+ if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
+ perms.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
+ }
+
+ if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
+ perms.add(Manifest.permission.READ_EXTERNAL_STORAGE);
+ }
+
+ requestPermissions(perms.toArray(new String[perms.size()]), PERMISSION_REQUEST_CODE);
+ }
+ }
};
try {
@@ -159,6 +178,19 @@ public class AndroidLauncher extends AndroidApplication{
initialize(new Mindustry(), config);
}
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
+ if(requestCode == PERMISSION_REQUEST_CODE){
+ for(int i : grantResults){
+ if(i != PackageManager.PERMISSION_GRANTED) return;
+ }
+
+ if(chooser != null){
+ chooser.show();
+ }
+ }
+ }
private boolean isPackageInstalled(String packagename) {
try {
diff --git a/core/src/io/anuke/mindustry/core/Platform.java b/core/src/io/anuke/mindustry/core/Platform.java
index 6e7556f78d..ed5a7fef7b 100644
--- a/core/src/io/anuke/mindustry/core/Platform.java
+++ b/core/src/io/anuke/mindustry/core/Platform.java
@@ -9,7 +9,6 @@ import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.function.Consumer;
import io.anuke.ucore.scene.ui.TextField;
-import java.io.InputStream;
import java.util.Date;
import java.util.Locale;
import java.util.Random;
@@ -67,16 +66,14 @@ public abstract class Platform {
public void shareFile(FileHandle file){}
/**Download a file. Only used on GWT backend.*/
public void downloadFile(String name, byte[] bytes){}
- /**Open a file chooser. Only used on GWT backend.*/
- public void openFile(Consumer cons){}
/**Show a file chooser. Desktop only.
*
* @param text File chooser title text
- * @param content Type of files to be loaded
+ * @param content Description of the type of files to be loaded
* @param cons Selection listener
- * @param open Whether to open or save files.
- * @param filetype File extensions to filter.
+ * @param open Whether to open or save files
+ * @param filetype File extension to filter
*/
public void showFileChooser(String text, String content, Consumer cons, boolean open, String filetype){}
/**Use the default thread provider from the kryonet module for this.*/
diff --git a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java
index 90c9decd4e..1feaad8772 100644
--- a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java
+++ b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java
@@ -15,7 +15,6 @@ import io.anuke.mindustry.io.Map;
import io.anuke.mindustry.io.MapIO;
import io.anuke.mindustry.io.MapMeta;
import io.anuke.mindustry.io.MapTileData;
-import io.anuke.mindustry.ui.dialogs.FileChooser;
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.ColorMapper;
@@ -54,7 +53,6 @@ public class MapEditorDialog extends Dialog implements Disposable{
private MapResizeDialog resizeDialog;
private ScrollPane pane;
private FloatingDialog menu;
- private FileChooser openFile, saveFile, openImage, saveImage;
private boolean saved = false;
private boolean shownWithMap = false;
@@ -68,67 +66,6 @@ public class MapEditorDialog extends Dialog implements Disposable{
infoDialog = new MapInfoDialog(editor);
- saveFile = new FileChooser("$text.saveimage", false, file -> {
- file = file.parent().child(file.nameWithoutExtension() + "." + mapExtension);
- FileHandle result = file;
- ui.loadAnd(() -> {
-
- try{
- if(!editor.getTags().containsKey("name")){
- editor.getTags().put("name", result.nameWithoutExtension());
- }
- MapIO.writeMap(result.write(false), editor.getTags(), editor.getMap());
- }catch (Exception e){
- ui.showError(Bundles.format("text.editor.errorimagesave", Strings.parseException(e, false)));
- Log.err(e);
- }
- });
- });
-
- openFile = new FileChooser("$text.loadimage", FileChooser.mapFilter, true, file -> {
- ui.loadAnd(() -> {
- try{
- DataInputStream stream = new DataInputStream(file.read());
-
- MapMeta meta = MapIO.readMapMeta(stream);
- MapTileData data = MapIO.readTileData(stream, meta, false);
-
- editor.beginEdit(data, meta.tags);
- view.clearStack();
- }catch (Exception e){
- ui.showError(Bundles.format("text.editor.errorimageload", Strings.parseException(e, false)));
- Log.err(e);
- }
- });
- });
-
- saveImage = new FileChooser("$text.saveimage", false, file -> {
- file = file.parent().child(file.nameWithoutExtension() + ".png");
- FileHandle result = file;
- ui.loadAnd(() -> {
- try{
- Pixmaps.write(MapIO.generatePixmap(editor.getMap()), result);
- }catch (Exception e){
- ui.showError(Bundles.format("text.editor.errorimagesave", Strings.parseException(e, false)));
- Log.err(e);
- }
- });
- });
-
- openImage = new FileChooser("$text.loadimage", FileChooser.pngFilter, true, file -> {
- ui.loadAnd(() -> {
- try{
- MapTileData data = MapIO.readPixmap(new Pixmap(file));
-
- editor.beginEdit(data, editor.getTags());
- view.clearStack();
- }catch (Exception e){
- ui.showError(Bundles.format("text.editor.errorimageload", Strings.parseException(e, false)));
- Log.err(e);
- }
- });
- });
-
menu = new FloatingDialog("$text.menu");
menu.addCloseButton();
@@ -157,22 +94,79 @@ public class MapEditorDialog extends Dialog implements Disposable{
t.addImageTextButton("$text.editor.import", "icon-load-map", isize, () ->
createDialog("$text.editor.import",
"$text.editor.importmap", "$text.editor.importmap.description", "icon-load-map", (Listenable)loadDialog::show,
- "$text.editor.importfile", "$text.editor.importfile.description", "icon-file", (Listenable)openFile::show,
+ "$text.editor.importfile", "$text.editor.importfile.description", "icon-file", (Listenable)() -> {
+ Platform.instance.showFileChooser("$text.loadimage", "Map Files", file -> {
+ ui.loadAnd(() -> {
+ try{
+ DataInputStream stream = new DataInputStream(file.read());
+
+ MapMeta meta = MapIO.readMapMeta(stream);
+ MapTileData data = MapIO.readTileData(stream, meta, false);
+
+ editor.beginEdit(data, meta.tags);
+ view.clearStack();
+ }catch (Exception e){
+ ui.showError(Bundles.format("text.editor.errorimageload", Strings.parseException(e, false)));
+ Log.err(e);
+ }
+ });
+ }, true, mapExtension);
+ },
"$text.editor.importimage", "$text.editor.importimage.description", "icon-file-image", (Listenable)() -> {
if(gwt){
ui.showError("text.web.unsupported");
}else {
- openImage.show();
+ Platform.instance.showFileChooser("$text.loadimage", "Image Files", file -> {
+ ui.loadAnd(() -> {
+ try{
+ MapTileData data = MapIO.readPixmap(new Pixmap(file));
+
+ editor.beginEdit(data, editor.getTags());
+ view.clearStack();
+ }catch (Exception e){
+ ui.showError(Bundles.format("text.editor.errorimageload", Strings.parseException(e, false)));
+ Log.err(e);
+ }
+ });
+ }, true, "png");
}
}));
t.addImageTextButton("$text.editor.export", "icon-save-map", isize, () -> createDialog("$text.editor.export",
- "$text.editor.exportfile", "$text.editor.exportfile.description", "icon-file", (Listenable)saveFile::show,
+ "$text.editor.exportfile", "$text.editor.exportfile.description", "icon-file", (Listenable)() -> {
+ Platform.instance.showFileChooser("$text.saveimage", "Map Files", file -> {
+ file = file.parent().child(file.nameWithoutExtension() + "." + mapExtension);
+ FileHandle result = file;
+ ui.loadAnd(() -> {
+
+ try{
+ if(!editor.getTags().containsKey("name")){
+ editor.getTags().put("name", result.nameWithoutExtension());
+ }
+ MapIO.writeMap(result.write(false), editor.getTags(), editor.getMap());
+ }catch (Exception e){
+ ui.showError(Bundles.format("text.editor.errorimagesave", Strings.parseException(e, false)));
+ Log.err(e);
+ }
+ });
+ }, false, mapExtension);
+ },
"$text.editor.exportimage", "$text.editor.exportimage.description", "icon-file-image", (Listenable)() -> {
if(gwt){
ui.showError("text.web.unsupported");
}else {
- saveImage.show();
+ Platform.instance.showFileChooser("$text.saveimage", "Image Files", file -> {
+ file = file.parent().child(file.nameWithoutExtension() + ".png");
+ FileHandle result = file;
+ ui.loadAnd(() -> {
+ try{
+ Pixmaps.write(MapIO.generatePixmap(editor.getMap()), result);
+ }catch (Exception e){
+ ui.showError(Bundles.format("text.editor.errorimagesave", Strings.parseException(e, false)));
+ Log.err(e);
+ }
+ });
+ }, false, "png");
}
}));
@@ -374,6 +368,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
}
public void build(){
+ float size = 60;
new table(){{
aleft();
@@ -387,7 +382,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
ButtonGroup group = new ButtonGroup<>();
int i = 1;
- tools.defaults().size(60f, 64f).padBottom(-5.1f);
+ tools.defaults().size(size, size + 4f).padBottom(-5.1f);
//tools.addImageButton("icon-back", 16*2, () -> hide());
@@ -432,7 +427,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
tools.table("button", t -> {
t.add("$text.editor.teams");
- }).colspan(2).height(40).width(120f);
+ }).colspan(2).height(40).width(size*2f);
tools.row();
@@ -456,13 +451,14 @@ public class MapEditorDialog extends Dialog implements Disposable{
row();
new table("button"){{
+ atop();
Slider slider = new Slider(0, MapEditor.brushSizes.length-1, 1, false);
slider.moved(f -> editor.setBrushSize(MapEditor.brushSizes[(int)(float)f]));
new label("brush");
//new label(() -> Bundles.format("text.editor.brushsize", MapEditor.brushSizes[(int)slider.getValue()])).left();
row();
- add(slider).width(100f).padTop(4f);
- }}.padBottom(10).padTop(5).top().end();
+ add(slider).width(size*2f-20).padTop(4f);
+ }}.padTop(5).growY().top().end();
}}.left().growY().end();
diff --git a/core/src/io/anuke/mindustry/input/AndroidInput.java b/core/src/io/anuke/mindustry/input/AndroidInput.java
index 570f759926..0cda261ec7 100644
--- a/core/src/io/anuke/mindustry/input/AndroidInput.java
+++ b/core/src/io/anuke/mindustry/input/AndroidInput.java
@@ -518,6 +518,8 @@ public class AndroidInput extends InputHandler implements GestureListener{
@Override
public boolean pan(float x, float y, float deltaX, float deltaY){
+ if(ui.hasMouse()) return false;
+
//can't pan in line mode with one finger!
if(lineMode && !Gdx.input.isTouched(1)){
return false;
diff --git a/core/src/io/anuke/mindustry/ui/fragments/BlocksFragment.java b/core/src/io/anuke/mindustry/ui/fragments/BlocksFragment.java
index f8c2fb2ca0..a50a555e19 100644
--- a/core/src/io/anuke/mindustry/ui/fragments/BlocksFragment.java
+++ b/core/src/io/anuke/mindustry/ui/fragments/BlocksFragment.java
@@ -245,7 +245,9 @@ public class BlocksFragment implements Fragment{
cati ++;
}
- group.getButtons().get(checkedi).setChecked(true);
+ if(group.getButtons().size > 0){
+ group.getButtons().get(checkedi).setChecked(true);
+ }
selectTable.row();
selectTable.add(stack).colspan(Category.values().length).padBottom(-5).height((size + 12)*maxrow);
diff --git a/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java b/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java
index 4c007bd4ad..72f8cd46bb 100644
--- a/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java
+++ b/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java
@@ -8,7 +8,6 @@ import io.anuke.kryonet.KryoServer;
import io.anuke.mindustry.Mindustry;
import io.anuke.mindustry.core.Platform;
import io.anuke.mindustry.net.Net;
-import io.anuke.ucore.UCore;
import io.anuke.ucore.util.OS;
public class DesktopLauncher {
@@ -22,7 +21,7 @@ public class DesktopLauncher {
config.setWindowIcon("sprites/icon.png");
if(OS.isMac) {
- config.setPreferencesConfig(UCore.getProperty("user.home") + "/Library/Application Support/Mindustry", FileType.Absolute);
+ config.setPreferencesConfig(OS.getAppDataDirectoryString("Mindustry"), FileType.Absolute);
}
Platform.instance = new DesktopPlatform(arg);
diff --git a/desktop/src/io/anuke/mindustry/desktop/DesktopPlatform.java b/desktop/src/io/anuke/mindustry/desktop/DesktopPlatform.java
index 3dfb230c18..9af1a1c0d8 100644
--- a/desktop/src/io/anuke/mindustry/desktop/DesktopPlatform.java
+++ b/desktop/src/io/anuke/mindustry/desktop/DesktopPlatform.java
@@ -12,6 +12,7 @@ import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.ui.dialogs.FileChooser;
import io.anuke.ucore.core.Settings;
+import io.anuke.ucore.function.Consumer;
import io.anuke.ucore.util.OS;
import io.anuke.ucore.util.Strings;
@@ -35,8 +36,6 @@ public class DesktopPlatform extends Platform {
public DesktopPlatform(String[] args){
this.args = args;
-
-
if(useDiscord) {
DiscordEventHandlers handlers = new DiscordEventHandlers();
DiscordRPC.INSTANCE.Discord_Initialize(applicationId, handlers, true, "");
@@ -60,7 +59,7 @@ public class DesktopPlatform extends Platform {
@Override
public void showError(String text){
- //JOptionPane.showMessageDialog(null, text);
+
}
@Override