diff --git a/.gitignore b/.gitignore index 8083acaa32..da580b91ea 100644 --- a/.gitignore +++ b/.gitignore @@ -26,7 +26,7 @@ bin gen # JSettlers folders and files -release +/release save logs /replayForSavegame.log diff --git a/.travis.yml b/.travis.yml index ae1a3dd2ce..bf1cb132ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -63,4 +63,4 @@ before_cache: cache: directories: - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ \ No newline at end of file + - $HOME/.gradle/wrapper/ diff --git a/build.gradle b/build.gradle index acbd7b865f..1bb4446442 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ ext { androidBuildToolsVersion = '27.0.3' androidCompileSdkVersion = 27 androidMinSdkVersion = 19 - androidTargetSdkVersion = 25 + androidTargetSdkVersion = 26 } buildscript { @@ -22,7 +22,7 @@ buildscript { dependencies { classpath 'org.eclipse.jgit:org.eclipse.jgit:3.1.0.201310021548-r' if (findProject(':jsettlers.main.android')) { - classpath 'com.android.tools.build:gradle:3.1.0' + classpath 'com.android.tools.build:gradle:3.1.2' } } } @@ -33,6 +33,8 @@ allprojects { jcenter() google() maven { url "https://raw.github.com/laenger/maven-releases/master/releases" } + maven { url "https://maven.google.com" } + maven { url "https://oss.sonatype.org/content/repositories/snapshots" } } } diff --git a/go.graphics.android/src/main/java/go/graphics/android/AndroidDrawContext.java b/go.graphics.android/src/main/java/go/graphics/android/AndroidDrawContext.java index 263b5f3c63..1337ca3684 100644 --- a/go.graphics.android/src/main/java/go/graphics/android/AndroidDrawContext.java +++ b/go.graphics.android/src/main/java/go/graphics/android/AndroidDrawContext.java @@ -14,14 +14,15 @@ *******************************************************************************/ package go.graphics.android; +import android.content.Context; +import android.opengl.GLES10; +import android.opengl.GLES11; + import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.ShortBuffer; -import android.content.Context; -import android.opengl.GLES10; -import android.opengl.GLES11; import go.graphics.GLDrawContext; import go.graphics.GeometryHandle; import go.graphics.TextureHandle; @@ -264,8 +265,7 @@ public TextureHandle generateTexture(int width, int height, ShortBuffer data) { glBindTexture(texture); GLES10.glTexImage2D(GLES10.GL_TEXTURE_2D, 0, GLES10.GL_RGBA, width, - height, 0, GLES10.GL_RGBA, GLES10.GL_UNSIGNED_SHORT_5_5_5_1, - data); + height, 0, GLES10.GL_RGBA, GLES10.GL_UNSIGNED_SHORT_4_4_4_4, data); setTextureParameters(); return texture; @@ -289,6 +289,8 @@ private static void setTextureParameters() { GLES10.GL_REPEAT); GLES10.glTexParameterf(GLES10.GL_TEXTURE_2D, GLES10.GL_TEXTURE_WRAP_T, GLES10.GL_REPEAT); + + GLES10.glAlphaFunc(GLES10.GL_GREATER, 0.5f) ; // prevent writing of transparent pixels to z buffer } @Override @@ -296,7 +298,7 @@ public void updateTexture(TextureHandle textureIndex, int left, int bottom, int width, int height, ShortBuffer data) { glBindTexture(textureIndex); GLES10.glTexSubImage2D(GLES10.GL_TEXTURE_2D, 0, left, bottom, width, - height, GLES10.GL_RGBA, GLES10.GL_UNSIGNED_SHORT_5_5_5_1, data); + height, GLES10.GL_RGBA, GLES10.GL_UNSIGNED_SHORT_4_4_4_4, data); } public TextureHandle generateTextureAlpha(int width, int height) { @@ -330,8 +332,8 @@ public void updateTextureAlpha(TextureHandle textureIndex, int left, int bottom, } @Override - public void glMultMatrixf(float[] matrix, int offset) { - GLES10.glMultMatrixf(matrix, offset); + public void glMultMatrixf(float[] matrix) { + GLES10.glMultMatrixf(matrix, 0); } @Override diff --git a/go.graphics.android/src/main/java/go/graphics/android/GOSurfaceView.java b/go.graphics.android/src/main/java/go/graphics/android/GOSurfaceView.java index 4a2fc58e22..37c2c182f8 100644 --- a/go.graphics.android/src/main/java/go/graphics/android/GOSurfaceView.java +++ b/go.graphics.android/src/main/java/go/graphics/android/GOSurfaceView.java @@ -14,6 +14,15 @@ *******************************************************************************/ package go.graphics.android; +import android.content.Context; +import android.opengl.GLES10; +import android.opengl.GLSurfaceView; +import android.os.Vibrator; +import android.util.Log; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; + import java.lang.reflect.Method; import javax.microedition.khronos.egl.EGL10; @@ -30,15 +39,6 @@ import go.graphics.event.GOEventHandlerProvider; import go.graphics.event.interpreter.AbstractEventConverter; -import android.content.Context; -import android.opengl.GLES10; -import android.opengl.GLSurfaceView; -import android.os.Vibrator; -import android.util.Log; -import android.view.GestureDetector; -import android.view.MotionEvent; -import android.view.ScaleGestureDetector; - public class GOSurfaceView extends GLSurfaceView implements RedrawListener, GOEventHandlerProvider { private final Area area; @@ -218,6 +218,9 @@ private class Renderer implements GLSurfaceView.Renderer { private Renderer(Context aContext) { drawcontext = new AndroidDrawContext(aContext); + + GLES10.glBlendFunc(GLES10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); + GLES10.glEnable(GLES10.GL_BLEND); } @Override diff --git a/go.graphics.swing/build.gradle b/go.graphics.swing/build.gradle index 1046e852f6..990ed20524 100644 --- a/go.graphics.swing/build.gradle +++ b/go.graphics.swing/build.gradle @@ -1,32 +1,32 @@ apply plugin: 'java' +def lwjgl_version="3.1.6" + dependencies { implementation project(':go.graphics') - implementation "org.jogamp.gluegen:gluegen-rt:2.3.2" - implementation "org.jogamp.jogl:jogl-all:2.3.2" + compile "org.lwjgl:lwjgl:"+lwjgl_version + compile "org.lwjgl:lwjgl-opengl:"+lwjgl_version + compile "org.lwjgl:lwjgl-glfw:"+lwjgl_version + compile "org.lwjgl:lwjgl-egl:"+lwjgl_version + compile "org.lwjgl:lwjgl-jawt:"+lwjgl_version + + compile "org.lwjgl:lwjgl:"+lwjgl_version+":natives-linux" + compile "org.lwjgl:lwjgl:"+lwjgl_version+":natives-macos" + compile "org.lwjgl:lwjgl:"+lwjgl_version+":natives-windows" + + compile "org.lwjgl:lwjgl-opengl:"+lwjgl_version+":natives-linux" + compile "org.lwjgl:lwjgl-opengl:"+lwjgl_version+":natives-macos" + compile "org.lwjgl:lwjgl-opengl:"+lwjgl_version+":natives-windows" + + compile "org.lwjgl:lwjgl-glfw:"+lwjgl_version+":natives-linux" + compile "org.lwjgl:lwjgl-glfw:"+lwjgl_version+":natives-macos" + compile "org.lwjgl:lwjgl-glfw:"+lwjgl_version+":natives-windows" + - runtime "org.jogamp.gluegen:gluegen-rt:2.3.2:natives-android-aarch64" - runtime "org.jogamp.gluegen:gluegen-rt:2.3.2:natives-android-armv6" - runtime "org.jogamp.gluegen:gluegen-rt:2.3.2:natives-linux-amd64" - runtime "org.jogamp.gluegen:gluegen-rt:2.3.2:natives-linux-armv6" - runtime "org.jogamp.gluegen:gluegen-rt:2.3.2:natives-linux-armv6hf" - runtime "org.jogamp.gluegen:gluegen-rt:2.3.2:natives-linux-i586" + // macos support + compile "org.jogamp.gluegen:gluegen-rt:2.3.2" + compile "org.jogamp.jogl:jogl-all:2.3.2" runtime "org.jogamp.gluegen:gluegen-rt:2.3.2:natives-macosx-universal" - runtime "org.jogamp.gluegen:gluegen-rt:2.3.2:natives-solaris-amd64" - runtime "org.jogamp.gluegen:gluegen-rt:2.3.2:natives-solaris-i586" - runtime "org.jogamp.gluegen:gluegen-rt:2.3.2:natives-windows-amd64" - runtime "org.jogamp.gluegen:gluegen-rt:2.3.2:natives-windows-i586" - - runtime "org.jogamp.jogl:jogl-all:2.3.2:natives-android-aarch64" - runtime "org.jogamp.jogl:jogl-all:2.3.2:natives-android-armv6" - runtime "org.jogamp.jogl:jogl-all:2.3.2:natives-linux-amd64" - runtime "org.jogamp.jogl:jogl-all:2.3.2:natives-linux-armv6" - runtime "org.jogamp.jogl:jogl-all:2.3.2:natives-linux-armv6hf" - runtime "org.jogamp.jogl:jogl-all:2.3.2:natives-linux-i586" runtime "org.jogamp.jogl:jogl-all:2.3.2:natives-macosx-universal" - runtime "org.jogamp.jogl:jogl-all:2.3.2:natives-solaris-amd64" - runtime "org.jogamp.jogl:jogl-all:2.3.2:natives-solaris-i586" - runtime "org.jogamp.jogl:jogl-all:2.3.2:natives-windows-amd64" - runtime "org.jogamp.jogl:jogl-all:2.3.2:natives-windows-i586" } diff --git a/go.graphics.swing/src/main/java/go/graphics/swing/AreaContainer.java b/go.graphics.swing/src/main/java/go/graphics/swing/AreaContainer.java index ed9ec68030..be9f0b0a71 100644 --- a/go.graphics.swing/src/main/java/go/graphics/swing/AreaContainer.java +++ b/go.graphics.swing/src/main/java/go/graphics/swing/AreaContainer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015 + * Copyright (c) 2015-2018 * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, @@ -15,177 +15,59 @@ package go.graphics.swing; import java.awt.BorderLayout; -import java.awt.Component; - -import javax.swing.JPanel; - -import com.jogamp.opengl.GL2; -import com.jogamp.opengl.GLAutoDrawable; -import com.jogamp.opengl.GLCapabilities; -import com.jogamp.opengl.GLEventListener; -import com.jogamp.opengl.GLProfile; -import com.jogamp.opengl.awt.GLCanvas; -import com.jogamp.opengl.awt.GLJPanel; -import com.jogamp.opengl.glu.GLU; - +import go.graphics.DrawmodeListener; import go.graphics.RedrawListener; import go.graphics.area.Area; import go.graphics.event.GOEvent; -import go.graphics.event.GOEventHandlerProvider; -import go.graphics.swing.event.swingInterpreter.GOSwingEventConverter; -import go.graphics.swing.opengl.JOGLDrawContext; +import go.graphics.swing.contextcreator.EBackendType; /** * This class lets you embed areas into swing components. * * @author michael + * @author paul */ -public class AreaContainer extends JPanel implements RedrawListener, GOEventHandlerProvider { +public class AreaContainer extends GLContainer implements RedrawListener { /** * */ private static final long serialVersionUID = 8204496712425576430L; - private final Area area; - - private Component canvas; - private JOGLDrawContext context; + protected final Area area; /** - * creates a new area conaainer + * creates a new area container * * @param area * The area to display */ public AreaContainer(Area area) { - this(area, false); + this(area, EBackendType.DEFAULT); } - /** - * creates a new area conaainer - * - * @param area - * The area to display - */ - public AreaContainer(Area area, boolean forceLightweight) { + public AreaContainer(Area area, EBackendType backend) { + super(backend, new BorderLayout()); this.area = area; - this.setLayout(new BorderLayout()); - - GLProfile profile = GLProfile.getDefault(); - GLCapabilities cap = new GLCapabilities(profile); - cap.setStencilBits(1); - - GLEventListener glEventListener = new GLEventListener() { - @Override - public void reshape(GLAutoDrawable gl, int x, int y, int width, int height) { - resizeArea(gl.getGL().getGL2(), x, y, width, height); - } - - @Override - public void init(GLAutoDrawable arg0) { - arg0.getGL().setSwapInterval(0); - } - - @Override - public void dispose(GLAutoDrawable arg0) { - disposeAll(); - } - - @Override - public void display(GLAutoDrawable glDrawable) { - draw(glDrawable.getGL().getGL2()); - } - }; - - if (forceLightweight) { - GLJPanel panel = new GLJPanel(cap); - panel.addGLEventListener(glEventListener); - canvas = panel; - } else { - GLCanvas glCanvas = new GLCanvas(cap); - glCanvas.addGLEventListener(glEventListener); - canvas = glCanvas; + if(cc instanceof DrawmodeListener) { + area.setDrawmodeListener((DrawmodeListener) cc); } - // Listener for Key-, Mouse- etc. events - new GOSwingEventConverter(canvas, this); area.addRedrawListener(this); - this.add(canvas); - } - - /** - * Resizes the area. - * - * @param gl2 - * The GL object - * @param x - * unused - * @param y - * unused - * @param width - * The width - * @param height - * The hieght - */ - protected void resizeArea(GL2 gl2, int x, int y, int width, int height) { - gl2.glMatrixMode(GL2.GL_PROJECTION); - gl2.glLoadIdentity(); - - // coordinate system origin at lower left with width and height same as - // the window - GLU glu = new GLU(); - glu.gluOrtho2D(0.0f, width, 0.0f, height); - - gl2.glMatrixMode(GL2.GL_MODELVIEW); - gl2.glLoadIdentity(); - gl2.glViewport(0, 0, width, height); + } + public void resize_gl(int width, int height) { + super.resize_gl(width, height); area.setWidth(width); area.setHeight(height); - } - - /** - * Draws the content area on the OpenGl object. - * - * @param gl2 - * Where to draw on. - */ - protected void draw(GL2 gl2) { - gl2.glClear(GL2.GL_COLOR_BUFFER_BIT); - gl2.glLoadIdentity(); - - if (context == null || context.getGl2() != gl2) { - context = new JOGLDrawContext(gl2); - } - context.startFrame(); - area.drawArea(context); } - /** - * Disposes all textures / buffers that were allocated by this context. - */ - protected void disposeAll() { - if (context != null) { - context.disposeAll(); - } - context = null; - } - - @Override - public void requestRedraw() { - canvas.repaint(); - } - - /** - * Forward the focus call to the Input canvas - */ - @Override - public void requestFocus() { - canvas.requestFocus(); + public void draw() { + super.draw(); + area.drawArea(context); } @Override diff --git a/go.graphics.swing/src/main/java/go/graphics/swing/GLContainer.java b/go.graphics.swing/src/main/java/go/graphics/swing/GLContainer.java new file mode 100644 index 0000000000..49e8b08c7f --- /dev/null +++ b/go.graphics.swing/src/main/java/go/graphics/swing/GLContainer.java @@ -0,0 +1,87 @@ +package go.graphics.swing; + +import org.lwjgl.opengl.GL; +import org.lwjgl.opengl.GL11; + +import java.awt.Component; +import java.awt.LayoutManager; + +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import go.graphics.event.GOEventHandlerProvider; +import go.graphics.swing.contextcreator.BackendSelector; +import go.graphics.swing.contextcreator.ContextCreator; +import go.graphics.swing.contextcreator.EBackendType; +import go.graphics.swing.opengl.LWJGLDrawContext; + +public abstract class GLContainer extends JPanel implements GOEventHandlerProvider { + + + protected ContextCreator cc; + protected LWJGLDrawContext context; + + public GLContainer(EBackendType backend, LayoutManager layout) { + setLayout(layout); + + try { + cc = BackendSelector.createBackend(this, backend); + cc.init(); + } catch (Exception ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(null, "Could not create opengl context through " + backend.cc_name + "\nPress ok to exit"); + System.exit(1); + } + } + + public void resize_gl(int width, int height) { + GL11.glMatrixMode(GL11.GL_PROJECTION); + GL11.glLoadIdentity(); + // coordinate system origin at lower left with width and height same as + // the window + GL11.glOrtho(0, width, 0, height, -1, 1); + + GL11.glMatrixMode(GL11.GL_MODELVIEW); + GL11.glLoadIdentity(); + GL11.glViewport(0, 0, width, height); + } + + + public void init() { + context = new LWJGLDrawContext(GL.createCapabilities()); + } + + /** + * Disposes all textures / buffers that were allocated by this context. + */ + public void disposeAll() { + cc.stop(); + if (context != null) { + context.disposeAll(); + } + context = null; + } + + public void draw() { + GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); + GL11.glLoadIdentity(); + + context.startFrame(); + } + + public void requestRedraw() { + cc.repaint(); + } + + /** + * Forward the focus call to the Input canvas + */ + @Override + public void requestFocus() { + cc.requestFocus(); + } + + public void addCanvas(Component canvas) { + add(canvas); + } +} diff --git a/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/AsyncContextCreator.java b/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/AsyncContextCreator.java new file mode 100644 index 0000000000..12c195af6c --- /dev/null +++ b/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/AsyncContextCreator.java @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright (c) 2018 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *******************************************************************************/ +package go.graphics.swing.contextcreator; + +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.nio.IntBuffer; + +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +import go.graphics.DrawmodeListener; +import go.graphics.swing.GLContainer; +import go.graphics.swing.event.swingInterpreter.GOSwingEventConverter; + +public abstract class AsyncContextCreator extends ContextCreator implements Runnable,DrawmodeListener { + + private boolean offscreen = true; + private boolean clear_offscreen = true; + private boolean continue_run = true; + + protected boolean ignore_resize = false; + protected BufferedImage bi = null; + protected IntBuffer pixels; + + private Thread render_thread; + + public AsyncContextCreator(GLContainer container) { + super(container); + } + + @Override + public void stop() { + continue_run = false; + } + + @Override + public void initSpecific() { + JPanel panel = new JPanel() { + public void paintComponent(Graphics graphics) { + super.paintComponent(graphics); + + if(first_draw) { + SwingUtilities.windowForComponent(this).addKeyListener(new GOSwingEventConverter(parent, parent)); + first_draw = false; + } + + if(offscreen) { + synchronized (wnd_lock) { + graphics.drawImage(bi, 0, 0, null); + graphics.dispose(); + } + } else { + graphics.drawString("Press m to enable offscreen transfer", width/3, height/2); + } + } + }; + + canvas = panel; + render_thread = new Thread(this); + render_thread.start(); + + + } + + @Override + public void repaint() { + canvas.repaint(); + } + + @Override + public void requestFocus() { + canvas.requestFocus(); + } + + public abstract void async_init(); + + public abstract void async_set_size(int width, int height); + + public abstract void async_refresh(); + + public abstract void async_swapbuffers(); + + public abstract void async_stop(); + + @Override + public void run() { + async_init(); + + parent.init(); + + while(continue_run) { + if (change_res) { + if(!ignore_resize) { + width = new_width; + height = new_height; + async_set_size(width, height); + + parent.resize_gl(width, height); + + bi = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR); + pixels = BufferUtils.createIntBuffer(width * height); + } + ignore_resize = false; + change_res = false; + } + + async_refresh(); + + parent.draw(); + + if (offscreen) { + synchronized (wnd_lock) { + GL11.glReadPixels(0, 0, width, height, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, pixels); + for (int x = 0; x != width; x++) { + for (int y = 0; y != height; y++) { + bi.setRGB(x, height - y - 1, pixels.get(y * width + x)); + } + } + } + } + + if(!offscreen || clear_offscreen ){ + if(clear_offscreen) { + GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); + clear_offscreen = false; + } + async_swapbuffers(); + } + } + + async_stop(); + } + + @Override + public void changeDrawMode() { + offscreen = !offscreen; + clear_offscreen = true; + } +} diff --git a/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/BackendSelector.java b/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/BackendSelector.java new file mode 100644 index 0000000000..3809a25bb1 --- /dev/null +++ b/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/BackendSelector.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2018 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *******************************************************************************/ +package go.graphics.swing.contextcreator; + +import org.lwjgl.system.Platform; + +import java.awt.event.ActionEvent; +import java.util.Arrays; +import java.util.stream.Stream; + +import javax.swing.JComboBox; +import javax.swing.JOptionPane; + +import go.graphics.swing.GLContainer; + +public class BackendSelector extends JComboBox { + + private EBackendType current_item = null; + + public static final EBackendType FALLBACK_BACKEND = EBackendType.GLFW; + + @Override + public void actionPerformed(ActionEvent actionEvent) { + super.actionPerformed(actionEvent); + + if(actionEvent.getActionCommand() == "comboBoxChanged") { + EBackendType bi = (EBackendType) getSelectedItem(); + if (bi.platform != null && bi.platform != Platform.get()) { + setSelectedItem(current_item); + BackendSelector.this.hidePopup(); + JOptionPane.showMessageDialog(BackendSelector.this.getParent(), bi.cc_name + " is only available on " + bi.platform); + } else { + current_item = bi; + } + + } + } + + public BackendSelector() { + setEditable(false); + + addActionListener(this); + + availableBackends().forEach(backend -> addItem(backend)); + } + + private static Stream availableBackends() { + return Arrays.stream(EBackendType.values()).filter(backend -> backend.available(Platform.get())); + } + + public static EBackendType getBackendByName(String name) { + // matching and matching and suitable backends + return availableBackends().filter(backend -> backend.cc_name.equalsIgnoreCase(name)).findFirst().orElse(EBackendType.DEFAULT); + } + + public static ContextCreator createBackend(GLContainer container, EBackendType backend) throws Exception { + EBackendType real_backend = backend; + + if(backend == null || backend.cc_class == null) { + // first of all usable and suitable backends sorted for being default + real_backend = availableBackends().filter(current_backend -> current_backend.cc_class != null).sorted().findFirst().orElse(FALLBACK_BACKEND); + } + + return real_backend.cc_class.getConstructor(GLContainer.class).newInstance(container); + } + +} diff --git a/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/ContextCreator.java b/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/ContextCreator.java new file mode 100644 index 0000000000..767c98d75a --- /dev/null +++ b/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/ContextCreator.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2018 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *******************************************************************************/ +package go.graphics.swing.contextcreator; + +import java.awt.Component; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; + +import go.graphics.swing.GLContainer; + +public abstract class ContextCreator implements ComponentListener{ + + public ContextCreator(GLContainer ac) { + parent = ac; + } + + protected int width = 1, height = 1; + protected int new_width = 1, new_height = 1; + protected boolean change_res = true; + protected Object wnd_lock = new Object(); + protected boolean first_draw = true; + protected Component canvas; + protected GLContainer parent; + + + public abstract void stop(); + public abstract void initSpecific(); + + public abstract void repaint(); + + public abstract void requestFocus(); + + + public void init() { + initSpecific(); + + parent.addCanvas(canvas); + + canvas.addComponentListener(this); + } + + @Override + public void componentResized(ComponentEvent componentEvent) { + Component cmp = componentEvent.getComponent(); + synchronized (wnd_lock) { + new_width = cmp.getWidth(); + new_height = cmp.getHeight(); + change_res = true; + + if(new_width == 0) new_width = 1; + if(new_height == 0) new_height = 1; + } + } + + @Override + public void componentHidden(ComponentEvent componentEvent) {} + + @Override + public void componentMoved(ComponentEvent componentEvent) {} + + @Override + public void componentShown(ComponentEvent componentEvent) {} +} diff --git a/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/EBackendType.java b/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/EBackendType.java new file mode 100644 index 0000000000..5211e2b203 --- /dev/null +++ b/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/EBackendType.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2018 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *******************************************************************************/ +package go.graphics.swing.contextcreator; + +import org.lwjgl.system.Platform; +import org.lwjgl.system.linux.X11; +import org.lwjgl.system.windows.GDI32; + + +public enum EBackendType implements Comparable { + + DEFAULT(null, "default", null, null, null, null), + + GLX(GLXContextCreator.class, "glx", null, Platform.LINUX, X11.class, null), + EGL(EGLContextCreator.class, "egl", null, null, org.lwjgl.egl.EGL.class, "getFunctionProvider"), + WGL(WGLContextCreator.class, "wgl", null, Platform.WINDOWS, GDI32.class, null), + JOGL(JOGLContextCreator.class, "jogl", Platform.MACOSX, Platform.MACOSX, null, null), + + GLFW(GLFWContextCreator.class, "glfw", null, null, org.lwjgl.glfw.GLFW.class, null); + + EBackendType(Class cc_class, String cc_name, Platform platform, Platform default_for, Class probe_class, String probe_method) { + this.cc_class = cc_class; + this.cc_name = cc_name; + this.platform = platform; + this.default_for = default_for; + this.probe_class = probe_class; + this.probe_method = probe_method; + } + + public Class cc_class; + public Platform platform, default_for; + public String cc_name; + private Class probe_class; + private String probe_method; + + @Override + public String toString() { + return cc_name; + } + + public boolean available(Platform platform) { + if(probe_class != null) { + try { + probe_class.getDeclaredMethod(probe_method != null ? probe_method : "getLibrary").invoke(null); + } catch (Throwable thrown) { + return false; + } + } else if(this.platform != null){ + return this.platform == platform; + } + + return true; + } +} diff --git a/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/EGLContextCreator.java b/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/EGLContextCreator.java new file mode 100644 index 0000000000..d2c728e528 --- /dev/null +++ b/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/EGLContextCreator.java @@ -0,0 +1,98 @@ +package go.graphics.swing.contextcreator; + +import org.lwjgl.BufferUtils; +import org.lwjgl.PointerBuffer; +import org.lwjgl.egl.EGL10; +import org.lwjgl.egl.EGL12; +import org.lwjgl.egl.EGL13; +import org.lwjgl.egl.EGL14; +import org.lwjgl.system.Platform; +import org.lwjgl.system.jawt.JAWTWin32DrawingSurfaceInfo; +import org.lwjgl.system.jawt.JAWTX11DrawingSurfaceInfo; + +import java.nio.IntBuffer; + +import go.graphics.swing.GLContainer; + +public class EGLContextCreator extends JAWTContextCreator { + + private static long egl_config; + private static long egl_display = 0; + private long egl_surface; + private static long egl_context; + + private long native_drawable = 0; + + public EGLContextCreator(GLContainer container) { + super(container); + } + + @Override + public void stop() { + EGL10.eglDestroySurface(egl_display, egl_surface); + } + + @Override + protected void swapBuffers() { + EGL10.eglSwapBuffers(egl_display, egl_surface); + } + + @Override + protected void makeCurrent(boolean draw) { + if(draw) { + EGL10.eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context); + } else { + EGL10.eglMakeCurrent(egl_display, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); + } + } + + @Override + protected void initContext() {} + + private void initStatic() { + egl_display = EGL10.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); + + int[] egl_major = new int[1]; + int[] egl_minor = new int[1]; + + EGL10.eglInitialize(egl_display, egl_major, egl_minor); + + if(egl_major[0] == 1 && egl_minor[0] < 4) throw new Error("EGL version is too low (" +egl_major[0]+"."+egl_minor[0] + ")"); + + if(!EGL12.eglBindAPI(EGL14.EGL_OPENGL_API)) throw new Error("could not bind OpenGL"); + + int[] attrs = {EGL13.EGL_CONFORMANT, EGL14.EGL_OPENGL_BIT, + EGL10.EGL_STENCIL_SIZE, 1, + EGL10.EGL_NONE}; + PointerBuffer cfgs = BufferUtils.createPointerBuffer(1); + int[] num_config = new int[1]; + + EGL10.eglChooseConfig(egl_display, attrs, cfgs, num_config); + if(num_config[0] == 0) throw new Error("could not found egl configs!"); + egl_config = cfgs.get(0); + + int[] ctx_attrs = new int[] {EGL10.EGL_NONE}; + + egl_context = EGL10.eglCreateContext(egl_display, egl_config, 0, ctx_attrs); + } + + @Override + protected void createNewSurfaceInfo() { + long new_native_drawable = 0; + + if(Platform.get() == Platform.LINUX) { + JAWTX11DrawingSurfaceInfo x11surfaceInfo = JAWTX11DrawingSurfaceInfo.create(surfaceinfo.platformInfo()); + new_native_drawable = x11surfaceInfo.drawable(); + } else if(Platform.get() == Platform.WINDOWS) { + JAWTWin32DrawingSurfaceInfo win32surfaceInfo = JAWTWin32DrawingSurfaceInfo.create(surfaceinfo.platformInfo()); + new_native_drawable = win32surfaceInfo.hwnd(); + } + + if(native_drawable != new_native_drawable) { + if(egl_display == 0) initStatic(); + + if(native_drawable != 0) stop(); + egl_surface = EGL10.eglCreateWindowSurface(egl_display, egl_config, native_drawable = new_native_drawable, (IntBuffer)null); + } + } +} diff --git a/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/GLFWContextCreator.java b/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/GLFWContextCreator.java new file mode 100644 index 0000000000..09a62d0214 --- /dev/null +++ b/go.graphics.swing/src/main/java/go/graphics/swing/contextcreator/GLFWContextCreator.java @@ -0,0 +1,219 @@ +/******************************************************************************* + * Copyright (c) 2018 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *******************************************************************************/ +package go.graphics.swing.contextcreator; + +import org.lwjgl.glfw.GLFW; +import org.lwjgl.glfw.GLFWCursorEnterCallback; +import org.lwjgl.glfw.GLFWCursorPosCallback; +import org.lwjgl.glfw.GLFWErrorCallback; +import org.lwjgl.glfw.GLFWKeyCallback; +import org.lwjgl.glfw.GLFWMouseButtonCallback; +import org.lwjgl.glfw.GLFWScrollCallback; +import org.lwjgl.glfw.GLFWWindowSizeCallback; + +import java.awt.Dimension; +import java.util.HashMap; + +import javax.swing.SwingUtilities; + +import go.graphics.UIPoint; +import go.graphics.event.interpreter.AbstractEventConverter; +import go.graphics.swing.GLContainer; + +public class GLFWContextCreator extends AsyncContextCreator { + + private final GLFWEventConverter event_converter; + + public GLFWContextCreator(GLContainer container) { + super(container); + event_converter = new GLFWEventConverter(); + } + + private long glfw_wnd; + + public void async_init() { + GLFWErrorCallback ec = GLFWErrorCallback.createPrint(System.err);; + GLFW.glfwSetErrorCallback(ec); + + if(!GLFW.glfwInit()) throw new Error("glfwInit() failed!"); + + GLFW.glfwWindowHint(GLFW.GLFW_STENCIL_BITS, 1); + glfw_wnd = GLFW.glfwCreateWindow(width + 1, width + 1, "lwjgl-offscreen", 0, 0); + GLFW.glfwMakeContextCurrent(glfw_wnd); + GLFW.glfwSwapInterval(0); + + event_converter.registerCallbacks(); + } + + public void async_set_size(int width, int height) { + GLFW.glfwSetWindowSize(glfw_wnd, width, height); + + } + + + public void async_refresh() { + GLFW.glfwPollEvents(); + } + + public void async_swapbuffers() { + GLFW.glfwSwapBuffers(glfw_wnd); + } + + public void async_stop() { + GLFW.glfwTerminate(); + } + + private static final HashMap keys = new HashMap<>(); + + static { + keys.put(GLFW.GLFW_KEY_LEFT, "LEFT"); + keys.put(GLFW.GLFW_KEY_RIGHT, "RIGHT"); + keys.put(GLFW.GLFW_KEY_UP, "UP"); + keys.put(GLFW.GLFW_KEY_DOWN, "DOWN"); + keys.put(GLFW.GLFW_KEY_PAUSE, "PAUSE"); + + keys.put(GLFW.GLFW_KEY_F1, "F1"); + keys.put(GLFW.GLFW_KEY_F2, "F2"); + keys.put(GLFW.GLFW_KEY_F3, "F3"); + keys.put(GLFW.GLFW_KEY_F4, "F4"); + keys.put(GLFW.GLFW_KEY_F5, "F5"); + keys.put(GLFW.GLFW_KEY_F6, "F6"); + keys.put(GLFW.GLFW_KEY_F7, "F7"); + keys.put(GLFW.GLFW_KEY_F8, "F8"); + keys.put(GLFW.GLFW_KEY_F9, "F9"); + keys.put(GLFW.GLFW_KEY_F10, "F10"); + keys.put(GLFW.GLFW_KEY_F11, "F11"); + keys.put(GLFW.GLFW_KEY_F12, "F12"); + + keys.put(GLFW.GLFW_KEY_DELETE, "DELETE"); + keys.put(GLFW.GLFW_KEY_ESCAPE, "ESCAPE"); + keys.put(GLFW.GLFW_KEY_BACKSPACE, "BACK_SPACE"); + keys.put(GLFW.GLFW_KEY_SPACE, " "); + } + + private class GLFWEventConverter extends AbstractEventConverter { + + private UIPoint last_point = new UIPoint(0, 0); + + private GLFWKeyCallback key_callback = new GLFWKeyCallback() { + @Override + public void invoke(long window, int key, int scancode, int action, int mods) { + String name = GLFW.glfwGetKeyName(key, scancode); + if(name == null) { + name = keys.get(key); + } + + if(action == GLFW.GLFW_PRESS) { + startKeyEvent(name); + } else if(action == GLFW.GLFW_RELEASE){ + endKeyEvent(name); + } + } + }; + + private double presstime = -1; + + private GLFWMouseButtonCallback mouse_callback = new GLFWMouseButtonCallback() { + @Override + public void invoke(long window, int button, int action, int mods) { + + UIPoint point = last_point; + + if(action == GLFW.GLFW_PRESS) { + switch(button) { + case GLFW.GLFW_MOUSE_BUTTON_1: + startDraw(point); + break; + case GLFW.GLFW_MOUSE_BUTTON_2: + presstime = GLFW.glfwGetTime(); + case GLFW.GLFW_MOUSE_BUTTON_3: + startPan(point); + break; + } + } else { + switch(button) { + case GLFW.GLFW_MOUSE_BUTTON_1: + endDraw(point); + break; + case GLFW.GLFW_MOUSE_BUTTON_2: + presstime = -1; + case GLFW.GLFW_MOUSE_BUTTON_3: + endPan(point); + break; + } + } + } + }; + + private GLFWCursorEnterCallback cursorenter_callback = new GLFWCursorEnterCallback() { + @Override + public void invoke(long window, boolean entered) { + if(entered) { + startHover(last_point); + } else { + endHover(last_point); + } + } + }; + + private GLFWCursorPosCallback cursorpos_callback = new GLFWCursorPosCallback() { + @Override + public void invoke(long window, double xpos, double ypos) { + last_point = new UIPoint(xpos, height - ypos); + updateHoverPosition(last_point); + + if(presstime+0.1 items); +public interface DrawmodeListener { + public void changeDrawMode(); } diff --git a/go.graphics/src/main/java/go/graphics/GLDrawContext.java b/go.graphics/src/main/java/go/graphics/GLDrawContext.java index a635dbc919..89644db186 100644 --- a/go.graphics/src/main/java/go/graphics/GLDrawContext.java +++ b/go.graphics/src/main/java/go/graphics/GLDrawContext.java @@ -103,7 +103,7 @@ public interface GLDrawContext { int makeHeightValid(int height); - void glMultMatrixf(float[] matrix, int offset); + void glMultMatrixf(float[] matrix); /** * Updates a part of a texture image. diff --git a/go.graphics/src/main/java/go/graphics/area/Area.java b/go.graphics/src/main/java/go/graphics/area/Area.java index dd4464d598..97e42d0662 100644 --- a/go.graphics/src/main/java/go/graphics/area/Area.java +++ b/go.graphics/src/main/java/go/graphics/area/Area.java @@ -18,6 +18,7 @@ import java.util.Iterator; import java.util.LinkedList; +import go.graphics.DrawmodeListener; import go.graphics.GLDrawContext; import go.graphics.RedrawListener; import go.graphics.UIPoint; @@ -60,6 +61,8 @@ public class Area implements RedrawListener, GOEventHandlerProvider { private Region activeRegion = null; + private DrawmodeListener drawmodeListener; + /** * Creates a new area. */ @@ -102,6 +105,10 @@ public void add(Region region) { region.addRedrawListener(this); } + public void setDrawmodeListener(DrawmodeListener drawmodeListener) { + this.drawmodeListener = drawmodeListener; + } + /** * Draws the area at the given gl context. *

@@ -375,6 +382,12 @@ private void setActiveRegion(Region region) { @Override public void handleEvent(GOEvent event) { + if(event instanceof GOKeyEvent) { + if ("m".equalsIgnoreCase(((GOKeyEvent) event).getKeyCode())) { + if(drawmodeListener != null) drawmodeListener.changeDrawMode(); + } + } + if (event instanceof GOCommandEvent) { handleCommandEvent((GOCommandEvent) event); } else if (event instanceof GOPanEvent) { diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000000..03a95d2227 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,16 @@ +# +# Copyright (c) 2018 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +org.gradle.configureondemand=false \ No newline at end of file diff --git a/jsettlers.buildingcreator/src/main/java/jsettlers/buildingcreator/editor/map/BuildingtestMap.java b/jsettlers.buildingcreator/src/main/java/jsettlers/buildingcreator/editor/map/BuildingtestMap.java index 08cea42553..f540c72eb9 100644 --- a/jsettlers.buildingcreator/src/main/java/jsettlers/buildingcreator/editor/map/BuildingtestMap.java +++ b/jsettlers.buildingcreator/src/main/java/jsettlers/buildingcreator/editor/map/BuildingtestMap.java @@ -108,11 +108,6 @@ public byte getVisibleStatus(int x, int y) { public void setBackgroundListener(IGraphicsBackgroundListener backgroundListener) { } - @Override - public int nextDrawableX(int x, int y, int maxX) { - return x + 1; - } - @Override public IPartitionData getPartitionData(int x, int y) { return null; diff --git a/jsettlers.common/src/main/java/jsettlers/common/Color.java b/jsettlers.common/src/main/java/jsettlers/common/Color.java index fed9b863e4..2e7079bd07 100644 --- a/jsettlers.common/src/main/java/jsettlers/common/Color.java +++ b/jsettlers.common/src/main/java/jsettlers/common/Color.java @@ -65,11 +65,11 @@ public final class Color { private static final int SHIFT_ARGB_B = 0; private static final int ARGB_FIELD_MAX = 0xff; private static final float VALUE_CONSIDERED_TRANSPARENT_BELOW = .1f; - private static final int SHORT_SHIFT_RED = 11; - private static final int SHORT_SHIFT_GREEN = 6; - private static final int SHORT_SHIFT_BLUE = 1; - private static final int SHORT_FIELD_MAX = 0x1f; - private static final int SHORT_MASK_ALPHA = 1; + private static final int SHORT_SHIFT_RED = 12; + private static final int SHORT_SHIFT_GREEN = 8; + private static final int SHORT_SHIFT_BLUE = 4; + private static final int SHORT_FIELD_MAX = 0xf; + private static final int SHORT_MASK_ALPHA = 0xf; private final float blue; private final float red; @@ -240,44 +240,19 @@ private static float argbFieldToFloat(int f) { */ public static int convertTo32Bit(int color16bit) { // TODO: Make faster - float red = (float) ((color16bit >> 11) & 0x1f) / 0x1f; - float green = (float) ((color16bit >> 6) & 0x1f) / 0x1f; - float blue = (float) ((color16bit >> 1) & 0x1f) / 0x1f; - float alpha = color16bit & 0x1; + float red = (float) ((color16bit >> SHORT_SHIFT_RED) & SHORT_FIELD_MAX) / SHORT_FIELD_MAX; + float green = (float) ((color16bit >> SHORT_SHIFT_GREEN) & SHORT_FIELD_MAX) / SHORT_FIELD_MAX; + float blue = (float) ((color16bit >> SHORT_SHIFT_BLUE) & SHORT_FIELD_MAX) / SHORT_FIELD_MAX; + float alpha = (float) (color16bit & SHORT_MASK_ALPHA) / SHORT_FIELD_MAX; return Color.getARGB(red, green, blue, alpha); } - private static final int[] table6to5 = new int[64]; - private static final int[] table5to8 = new int[2 << 5]; - - static { - // Generate table6to5 - for (int i = 0; i < 64; i++) { - table6to5[i] = Math.round(i / 63.0f * 31.0f); - } - for (int i = 0; i < table5to8.length; i++) { - table5to8[i] = Math.round(i / (table5to8.length - 1f) * 255.0f); - } - } - - private static int convertColorChannel6to5(int c) { - return table6to5[c]; + public static int convert565to4444(int rgb565) { + return (rgb565 & 0xf000) | ((rgb565 & 0x780) << 1) | ((rgb565 & 0x1e) << 3) | 0xf; } - public static int convert565to555(int rgb565) { - int r5 = (rgb565 & 0xf800) >> 11; - int g6 = (rgb565 & 0x07e0) >> 5; - int b5 = rgb565 & 0x001f; - - int g5 = convertColorChannel6to5(g6); - - int rgb555 = r5; - rgb555 = rgb555 << 5; - rgb555 |= g5; - rgb555 = rgb555 << 5; - rgb555 |= b5; - - return rgb555; + public static int convert555to4444(int argb555) { + return ((argb555 & 0x7800) << 1) | ((argb555 & 0x3c0) << 2) | ((argb555 & 0x1e) << 3) | 0xf; } /** @@ -288,9 +263,9 @@ public static int convert565to555(int rgb565) { * @return The short color. */ public short toShortColor(float multiply) { - if (multiply == 1) { + if (multiply >= 1) { return shortColor; - } else if (multiply < 0) { + } else if (multiply <= 0) { return BLACK.toShortColor(1); } else { return toShortColorForced(multiply); @@ -303,7 +278,8 @@ private short toShortColorForced(float multiply) { } else { return (short) (convertToShortField(red, multiply) << SHORT_SHIFT_RED | convertToShortField(green, multiply) << SHORT_SHIFT_GREEN - | convertToShortField(blue, multiply) << SHORT_SHIFT_BLUE | SHORT_MASK_ALPHA); + | convertToShortField(blue, multiply) << SHORT_SHIFT_BLUE + | (short)(alpha * SHORT_MASK_ALPHA)); } } diff --git a/jsettlers.common/src/main/java/jsettlers/common/map/IGraphicsGrid.java b/jsettlers.common/src/main/java/jsettlers/common/map/IGraphicsGrid.java index f5ba9313d8..bcd3ec68bc 100644 --- a/jsettlers.common/src/main/java/jsettlers/common/map/IGraphicsGrid.java +++ b/jsettlers.common/src/main/java/jsettlers/common/map/IGraphicsGrid.java @@ -126,17 +126,6 @@ public interface IGraphicsGrid { */ void setBackgroundListener(IGraphicsBackgroundListener backgroundListener); - /** - * Gets the next x coordinate that might contain a drawable Object. - * - * @param x - * @param y - * @param maxX - * the maximum x that needs to be searched. - * @return a value bigger than x, might be outside the map. - */ - int nextDrawableX(int x, int y, int maxX); - /** * Gets the current data and settings of the partition at the given position. * diff --git a/jsettlers.common/src/main/resources/jsettlers/common/buildings/baker.xml b/jsettlers.common/src/main/resources/jsettlers/common/buildings/baker.xml index 44d2105325..3648a6d2f0 100644 --- a/jsettlers.common/src/main/resources/jsettlers/common/buildings/baker.xml +++ b/jsettlers.common/src/main/resources/jsettlers/common/buildings/baker.xml @@ -56,6 +56,10 @@ + + + + @@ -63,7 +67,7 @@ - + @@ -87,10 +91,10 @@ - - - - + + + + diff --git a/jsettlers.common/src/main/resources/jsettlers/common/buildings/stock.xml b/jsettlers.common/src/main/resources/jsettlers/common/buildings/stock.xml index 534f9c67b1..f9b144d25c 100644 --- a/jsettlers.common/src/main/resources/jsettlers/common/buildings/stock.xml +++ b/jsettlers.common/src/main/resources/jsettlers/common/buildings/stock.xml @@ -1,91 +1,100 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + - + @@ -95,14 +104,14 @@ - - - + + + - + - + @@ -112,12 +121,12 @@ - - - - - - - + + + + + + + diff --git a/jsettlers.common/src/main/resources/jsettlers/common/buildings/winegrower.xml b/jsettlers.common/src/main/resources/jsettlers/common/buildings/winegrower.xml index 870049c83d..a6bf59a7ae 100644 --- a/jsettlers.common/src/main/resources/jsettlers/common/buildings/winegrower.xml +++ b/jsettlers.common/src/main/resources/jsettlers/common/buildings/winegrower.xml @@ -63,6 +63,7 @@ + diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/Image.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/Image.java index dfa1cf14a8..9cee63412b 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/Image.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/Image.java @@ -104,7 +104,12 @@ public abstract class Image { * The color the image should have (argb) */ public abstract void drawAt(GLDrawContext gl, DrawBuffer buffer, - float viewX, float viewY, int color); + float viewX, float viewY, int color); + + public abstract void drawOnlyImageAt(GLDrawContext gl, DrawBuffer buffer, + float viewX, float viewY, int color); + public abstract void drawOnlyShadowAt(GLDrawContext gl, DrawBuffer buffer, + float viewX, float viewY, int color); /** * Draws the image at a given {@link DrawBuffer}. diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/ImageIndexImage.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/ImageIndexImage.java index 3789477d57..305c36626e 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/ImageIndexImage.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/ImageIndexImage.java @@ -148,6 +148,12 @@ public void drawAt(GLDrawContext gl, DrawBuffer buffer, float viewX, float viewY } } + @Override + public void drawOnlyImageAt(GLDrawContext gl, DrawBuffer buffer, float viewX, float viewY, int iColor) {} + + @Override + public void drawOnlyShadowAt(GLDrawContext gl, DrawBuffer buffer, float viewX, float viewY, int iColor) {} + private static float[] createGeometry(int offsetX, int offsetY, int width, int height, float umin, float vmin, float umax, float vmax) { return new float[] { // top left diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/MultiImageImage.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/MultiImageImage.java index 9076ad2b1e..86cd16778d 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/MultiImageImage.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/MultiImageImage.java @@ -200,6 +200,12 @@ public void drawAt(GLDrawContext gl, DrawBuffer buffer, float viewX, drawAt(gl, buffer, viewX, viewY, iColor, iColor); } + @Override + public void drawOnlyImageAt(GLDrawContext gl, DrawBuffer buffer, float viewX, float viewY, int iColor) {} + + @Override + public void drawOnlyShadowAt(GLDrawContext gl, DrawBuffer buffer, float viewX, float viewY, int iColor) {} + private void drawAt(GLDrawContext gl, DrawBuffer buffer, float viewX, float viewY, int sColor, int tColor) { try { diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/SettlerImage.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/SettlerImage.java index 82f9ec86ad..e4ef9205ff 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/SettlerImage.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/SettlerImage.java @@ -30,6 +30,7 @@ public class SettlerImage extends SingleImage { private SingleImage torso = null; + private SingleImage shadow = null; /** * Creates a new settler image. @@ -71,6 +72,10 @@ public void setTorso(SingleImage torso) { this.torso = torso; } + public void setShadow(SingleImage shadow) { + this.shadow = shadow; + } + /** * Gets the torso for this image. * @@ -94,19 +99,39 @@ protected GeometryHandle getGeometry(GLDrawContext context) { @Override public void drawAt(GLDrawContext gl, DrawBuffer buffer, float viewX, - float viewY, int iColor) { + float viewY, int iColor) { super.drawAt(gl, buffer, viewX, viewY, iColor); if (this.torso != null) { - torso.drawAt(gl, buffer, viewX, viewY, iColor); + this.torso.drawAt(gl, buffer, viewX, viewY, iColor); + } + if (this.shadow != null) { + this.shadow.drawAt(gl, buffer, viewX, viewY, -1); + } + } + + @Override + public void drawOnlyImageAt(GLDrawContext gl, DrawBuffer buffer, float viewX, + float viewY, int iColor) { + super.drawAt(gl, buffer, viewX, viewY, iColor); + } + + @Override + public void drawOnlyShadowAt(GLDrawContext gl, DrawBuffer buffer, float viewX, + float viewY, int iColor) { + if (this.shadow != null) { + this.shadow.drawAt(gl, buffer, viewX, viewY, -1); } } @Override public void drawAt(GLDrawContext gl, DrawBuffer buffer, float viewX, float viewY, Color color, float multiply) { - super.drawAt(gl, buffer, viewX, viewY, Color.WHITE, multiply); + super.drawAt(gl, buffer, viewX, viewY, dimColor(Color.WHITE, multiply)); + if (this.shadow != null) { + this.shadow.drawAt(gl, buffer, viewX, viewY, -1); + } if (this.torso != null) { - torso.drawAt(gl, buffer, viewX, viewY, dimColor(color, multiply)); + this.torso.drawAt(gl, buffer, viewX, viewY, dimColor(color, multiply)); } } } diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/SingleImage.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/SingleImage.java index a17cf93ac4..4b7a12605c 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/SingleImage.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/SingleImage.java @@ -14,19 +14,16 @@ *******************************************************************************/ package jsettlers.graphics.image; +import java.awt.image.BufferedImage; import java.nio.ShortBuffer; import go.graphics.GLDrawContext; import go.graphics.GeometryHandle; import go.graphics.IllegalBufferException; import go.graphics.TextureHandle; - -import java.awt.image.BufferedImage; -import java.nio.ShortBuffer; - import jsettlers.common.Color; -import jsettlers.graphics.map.draw.DrawBuffer; import jsettlers.graphics.image.reader.ImageMetadata; +import jsettlers.graphics.map.draw.DrawBuffer; /** * This is the base for all images that are directly loaded from the image file. @@ -334,6 +331,16 @@ public void drawAt(GLDrawContext gl, DrawBuffer buffer, float viewX, } } + @Override + public void drawOnlyImageAt(GLDrawContext gl, DrawBuffer buffer, float viewX, float viewY, int iColor) { + drawAt(gl, buffer, viewX, viewY, iColor); + } + + @Override + public void drawOnlyShadowAt(GLDrawContext gl, DrawBuffer buffer, float viewX, float viewY, int iColor) { + drawAt(gl, buffer, viewX, viewY, iColor); + } + protected float convertU(float relativeU) { return relativeU * getTextureScaleX(); } diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/AdvancedDatFileReader.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/AdvancedDatFileReader.java index e06f20ca6c..891ff65e66 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/AdvancedDatFileReader.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/AdvancedDatFileReader.java @@ -14,6 +14,10 @@ */ package jsettlers.graphics.image.reader; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; + import java8.util.stream.Collectors; import java8.util.stream.IntStreams; import jsettlers.graphics.image.GuiImage; @@ -37,10 +41,6 @@ import jsettlers.graphics.image.sequence.Sequence; import jsettlers.graphics.image.sequence.SequenceList; -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; - import static jsettlers.graphics.image.reader.versions.GfxFolderMapping.DatFileMapping; /** @@ -117,86 +117,86 @@ public class AdvancedDatFileReader implements DatFileReader { * Every dat file seems to have to start with this sequence. */ private static final byte[] FILE_START1 = { - 0x04, - 0x13, - 0x04, - 0x00, - 0x0c, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x54, - 0x00, - 0x00, - 0x00, - 0x20, - 0x00, - 0x00, - 0x00, - 0x40, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x10, - 0x00, - 0x00, - 0x00, - 0x00, - }; + 0x04, + 0x13, + 0x04, + 0x00, + 0x0c, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x54, + 0x00, + 0x00, + 0x00, + 0x20, + 0x00, + 0x00, + 0x00, + 0x40, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x10, + 0x00, + 0x00, + 0x00, + 0x00, + }; private static final byte[] FILE_START2 = { - 0x00, - 0x00, - 0x1f, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00 + 0x00, + 0x00, + 0x1f, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 }; private static final byte[] FILE_HEADER_END = { - 0x04, - 0x19, - 0x00, - 0x00, - 0x0c, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00 + 0x04, + 0x19, + 0x00, + 0x00, + 0x0c, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 }; private static final int SEQUENCE_TYPE_COUNT = 6; - private static final int ID_SETTLERS = 0x106; - private static final int ID_TORSOS = 0x3112; - private static final int ID_LANDSCAPE = 0x2412; - private static final int ID_SHADOWS = 0x5982; + private static final int ID_SETTLERS = 0x106; + private static final int ID_TORSOS = 0x3112; + private static final int ID_LANDSCAPE = 0x2412; + private static final int ID_SHADOWS = 0x5982; // fullscreen images - private static final int ID_GUIS = 0x11306; + private static final int ID_GUIS = 0x11306; - private final DatBitmapTranslator settlerTranslator; - private final DatBitmapTranslator torsoTranslator; + private final DatBitmapTranslator settlerTranslator; + private final DatBitmapTranslator torsoTranslator; private final DatBitmapTranslator landscapeTranslator; - private final DatBitmapTranslator shadowTranslator; - private final DatBitmapTranslator guiTranslator; + private final DatBitmapTranslator shadowTranslator; + private final DatBitmapTranslator guiTranslator; private final DatFileMapping mapping; - private ByteReader reader = null; - private final File file; + private ByteReader reader = null; + private final File file; /** * This is a list of file positions where the settler sequences start. @@ -210,27 +210,33 @@ public class AdvancedDatFileReader implements DatFileReader { /** * An array with the same length as settlers. */ - private int[] torsoStarts; + private int[] torsoStarts; /** * An array with the same length as settlers. */ - private int[] shadowStarts; + private int[] shadowStarts; /** * A list of loaded landscae images. */ - private LandscapeImage[] landscapeImages = null; + private LandscapeImage[] landscapeImages = null; private final Sequence landscapeSequence = new LandscapeImageSequence(); - private int[] landscapeStarts; + private int[] landscapeStarts; - private GuiImage[] guiImages = null; - private int[] guiStarts; + private GuiImage[] guiImages = null; + private int[] guiStarts; private final Sequence guiSequence = new GuiImageSequence(); private final SequenceList directSettlerList; - private static final byte[] START = new byte[] { - 0x02, 0x14, 0x00, 0x00, 0x08, 0x00, 0x00 + private static final byte[] START = new byte[]{ + 0x02, + 0x14, + 0x00, + 0x00, + 0x08, + 0x00, + 0x00 }; private final DatFileType type; @@ -299,7 +305,7 @@ public void initialize() { settlerSequences = new Sequence[settlerStarts.length]; int torsoDifference = settlerStarts.length - torsoStarts.length; - if (torsoDifference != 0) { + if (torsoDifference > 0) { int[] oldTorsos = torsoStarts; torsoStarts = new int[settlerStarts.length]; System.arraycopy(oldTorsos, 0, torsoStarts, torsoDifference, oldTorsos.length); @@ -309,12 +315,68 @@ public void initialize() { } int shadowDifference = settlerStarts.length - shadowStarts.length; - if (shadowStarts.length < settlerStarts.length) { + int i; + if (shadowDifference > 0) { int[] oldShadows = shadowStarts; shadowStarts = new int[settlerStarts.length]; - System.arraycopy(oldShadows, 0, shadowStarts, shadowDifference, oldShadows.length); - for (int i = 0; i < shadowDifference; i++) { - torsoStarts[i] = -1; + if (shadowDifference == 8 || shadowDifference == 7) { + // push shadows to end of settler images + for (i = 0; i < shadowDifference; i++) { + shadowStarts[i] = -1; + } + for (; i < settlerStarts.length; i++) { + shadowStarts[i] = oldShadows[i - shadowDifference]; + } + } else { + // push shadows to beginning of settler images + for (i = 0; i < oldShadows.length; i++) { + shadowStarts[i] = oldShadows[i]; + } + for (; i < settlerStarts.length; i++) { + shadowStarts[i] = -1; + } + } + if (shadowDifference == 33) { // change shadows in file 1: + shadowStarts[106] = -1; + for (i = 105; i >= 33; i--) { + shadowStarts[i] = shadowStarts[i - 2]; // material... + } + shadowStarts[32] = -1; + for (i = 31; i >= 27; i--) { + shadowStarts[i] = shadowStarts[i - 1]; // decorations + } + shadowStarts[26] = -1; // wave gets no shadow + } else if (shadowDifference == 26) { // change shadows in file 13: + for (i = 0; i < 27; i++) { + shadowStarts[i] = shadowStarts[i + 3]; + } + for (i = 27; i < 36; i++) { + shadowStarts[i] = shadowStarts[i + 2]; + } + shadowStarts[28] = -1; // market place gets no shadow (has it already) + shadowStarts[44] = shadowStarts[38]; // dock + shadowStarts[45] = shadowStarts[39]; // harbour + for (i = 36; i < 44; i++) { + shadowStarts[i] = -1; // rest has no shadow + } + for (i = 46; i < shadowStarts.length; i++) { + shadowStarts[i] = -1; // rest has no shadow + } + } else if (shadowDifference == 7) { // change shadows in file 6: + shadowStarts[18] = shadowStarts[10]; // donkey + shadowStarts[17] = shadowStarts[9]; // donkey + shadowStarts[16] = shadowStarts[8]; // donkey + shadowStarts[15] = shadowStarts[7]; // donkey + } else if (shadowDifference == 28) { // change shadows in file 36: + shadowStarts[4] = shadowStarts[1]; // roman ferry + shadowStarts[6] = -1; // roman ferry front has no extra shadow + shadowStarts[2] = -1; // roman cargo ship front has no extra shadow + } + } else if (shadowDifference == 0) { + if (settlerStarts.length == 239) { // change shadows in file 11: + for (i = 171; i >= 13; i--) { + shadowStarts[i] = shadowStarts[i - 13]; // several specialists + } } } } @@ -340,7 +402,7 @@ private int[] readSequenceIndexStarts(long fileLength, ByteReader reader) throws if (fileSize != fileLength) { throw new IOException( - "The length stored in the dat file is not the file length."); + "The length stored in the dat file is not the file length."); } // ignore unknown bytes. @@ -479,6 +541,17 @@ private synchronized void loadSettlers(int goldIndex) throws IOException { } } + int shadowPosition = shadowStarts[theseGraphicsFilesIndex]; + if (shadowPosition >= 0) { + long[] shadowPositions = readSequenceHeader(shadowPosition); + for (int i = 0; i < shadowPositions.length + && i < framePositions.length; i++) { + reader.skipTo(shadowPositions[i]); + ShadowImage shadow = DatBitmapReader.getImage(shadowTranslator, reader); + images[i].setShadow(shadow); + } + } + settlerSequences[goldIndex] = new ArraySequence<>(images); } diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/DatFileType.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/DatFileType.java index ee553a905b..b60f451e1f 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/DatFileType.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/DatFileType.java @@ -54,11 +54,13 @@ public byte[] getFileStartMagic() { /** * Converts a color in the current format to a rgba 5551 color. */ - public short convertTo5551(int color) { - if (this == RGB565) { - color = (short) Color.convert565to555(color); + public short convertTo4444(int color) { + if (this == RGB555) { + color = (short) Color.convert555to4444(color); + } else if (this == RGB565) { + color = (short) Color.convert565to4444(color); } - return (short) ((color << 1) | 0x01); + return (short) color; } public static DatFileType getForPath(File path) { diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/GuiTranslator.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/GuiTranslator.java index cd1b672969..9037ad0f93 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/GuiTranslator.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/GuiTranslator.java @@ -47,7 +47,7 @@ public short getTransparentColor() { @Override public short readUntransparentColor(ByteReader reader) throws IOException { - return type.convertTo5551(reader.read16()); + return type.convertTo4444(reader.read16()); } @Override diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/LandscapeTranslator.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/LandscapeTranslator.java index c7becfb508..084ab8a88b 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/LandscapeTranslator.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/LandscapeTranslator.java @@ -48,7 +48,7 @@ public short getTransparentColor() { @Override public short readUntransparentColor(ByteReader reader) throws IOException { - return type.convertTo5551(reader.read16()); + return type.convertTo4444(reader.read16()); } @Override diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/SettlerTranslator.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/SettlerTranslator.java index 59138feaac..138040b25c 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/SettlerTranslator.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/SettlerTranslator.java @@ -48,7 +48,7 @@ public SettlerImage createImage(ImageMetadata metadata, short[] array) { @Override public short getTransparentColor() { - return 0x00; + return 0; } @Override @@ -58,7 +58,7 @@ public HeaderType getHeaderType() { @Override public short readUntransparentColor(ByteReader reader) throws IOException { - return type.convertTo5551(reader.read16()); + return type.convertTo4444(reader.read16()); } } diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/ShadowTranslator.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/ShadowTranslator.java index 06df576c58..057a5f17be 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/ShadowTranslator.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/ShadowTranslator.java @@ -29,7 +29,7 @@ public class ShadowTranslator implements DatBitmapTranslator { @Override public short readUntransparentColor(ByteReader reader) throws IOException { - return 0; + return 0x8; // shadow: A = 0.5 in 4444 coding } @Override @@ -39,7 +39,7 @@ public HeaderType getHeaderType() { @Override public short getTransparentColor() { - return 0x0001; + return 0; } @Override diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/TorsoTranslator.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/TorsoTranslator.java index b27b2c4569..cea68be077 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/TorsoTranslator.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/image/reader/translator/TorsoTranslator.java @@ -31,13 +31,13 @@ public class TorsoTranslator implements DatBitmapTranslator { @Override public short getTransparentColor() { - return 0x00; + return 0; } @Override public short readUntransparentColor(ByteReader reader) throws IOException { - int read = reader.read8() & TORSO_BITS; // only 5 bit. - return (short) (read << 11 | read << 6 | read << 1 | 0x01); + int read = (reader.read8() & TORSO_BITS) >> 1; // only 5 bits, 4 used + return (short) (read << 12 | read << 8 | read << 4 | 0xf); // convert to 4444 } @Override diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/FramerateComputer.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/FramerateComputer.java index 964c1a73a5..54be68169e 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/FramerateComputer.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/FramerateComputer.java @@ -20,13 +20,17 @@ * @author Michael Zangl */ public class FramerateComputer { - private static final int FRAMES_TO_AVERAGE = 30; private static final long RECOMPUTE_INTERVALL = 500; - private final long[] lastFrames = new long[FRAMES_TO_AVERAGE]; + private final long[] lastFrames; private long lastRecompute = 0; private int capturedFrames = 0; private double rate; + + public FramerateComputer(int lastFramesLength) { + lastFrames = new long[lastFramesLength]; + } + /** * Called whenever a new frame is displayed. */ diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/MapContent.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/MapContent.java index d4ce405d2a..60e2644d9b 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/MapContent.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/MapContent.java @@ -34,6 +34,7 @@ import jsettlers.common.CommitInfo; import jsettlers.common.CommonConstants; import jsettlers.common.buildings.EBuildingType; +import jsettlers.common.buildings.IBuilding; import jsettlers.common.images.AnimationSequence; import jsettlers.common.images.EImageLinkType; import jsettlers.common.images.ImageLink; @@ -159,7 +160,7 @@ private void eventDataChanged(float zoomFactor, UIPoint p) { */ private final MapInterfaceConnector connector; - private final FramerateComputer framerate = new FramerateComputer(); + private final FramerateComputer framerate; private final Messenger messenger; private final SoundManager soundmanager; @@ -208,7 +209,15 @@ private void eventDataChanged(float zoomFactor, UIPoint p) { * @param soundPlayer */ public MapContent(IStartedGame game, SoundPlayer soundPlayer, ETextDrawPosition textDrawPosition) { - this(game, soundPlayer, textDrawPosition, null); + this(game, soundPlayer, 60, textDrawPosition,null); + } + + public MapContent(IStartedGame game, SoundPlayer soundPlayer, int fpsLimit, ETextDrawPosition textDrawPosition) { + this(game, soundPlayer, fpsLimit, textDrawPosition,null); + } + + public MapContent(IStartedGame game, SoundPlayer soundPlayer, ETextDrawPosition textDrawPosition, IControls controls) { + this(game, soundPlayer, 60, textDrawPosition,controls); } /** @@ -221,7 +230,8 @@ public MapContent(IStartedGame game, SoundPlayer soundPlayer, ETextDrawPosition * The player * @param controls */ - public MapContent(IStartedGame game, SoundPlayer soundPlayer, ETextDrawPosition textDrawPosition, IControls controls) { + public MapContent(IStartedGame game, SoundPlayer soundPlayer, int fpsLimit, ETextDrawPosition textDrawPosition, IControls controls) { + this.framerate = new FramerateComputer(fpsLimit); this.map = game.getMap(); this.gameTimeProvider = game.getGameTimeProvider(); this.textDrawPosition = textDrawPosition; @@ -481,7 +491,7 @@ private void drawMain(FloatRectangle screen) { int endX = Math.min(area.getLineEndX(line), width - 1); int startX = Math.max(area.getLineStartX(line), 0); - for (int x = startX; x <= endX; x = map.nextDrawableX(x, y, endX)) { + for (int x = startX; x <= endX; x++) { drawTile(x, y); if (!linePartiallyVisible) { double drawSpaceY = this.context.getConverter().getViewY(x, y, this.context.getHeight(x, y)); @@ -516,6 +526,24 @@ private void drawTile(int x, int y) { this.objectDrawer.drawMapObject(x, y, object); } + if (y > 3) { + object = map.getMapObjectsAt(x, y - 3); // objects to draw three lines later + if (object != null && object.getObjectType() == EMapObjectType.BUILDING && ((IBuilding) object).getBuildingType() == EBuildingType.STOCK) { + this.objectDrawer.drawStockFront(x, y - 3, (IBuilding) object); + } + } + if (y < map.getHeight() - 3) { + object = map.getMapObjectsAt(x, y + 3); // objects to draw three lines earlier + if (object != null) { + EMapObjectType type = object.getObjectType(); + if (type == EMapObjectType.BUILDING && ((IBuilding) object).getBuildingType() == EBuildingType.STOCK) { + this.objectDrawer.drawStockBack(x, y + 3, (IBuilding) object); + } else if (type == EMapObjectType.DOCK) { + this.objectDrawer.drawDock(x, y + 3, object); + } + } + } + IMovable movable = map.getMovableAt(x, y); if (movable != null) { this.objectDrawer.draw(movable); diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/controls/original/panel/MainPanel.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/controls/original/panel/MainPanel.java index d819cccc19..5b93ce9a94 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/controls/original/panel/MainPanel.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/controls/original/panel/MainPanel.java @@ -37,6 +37,7 @@ import jsettlers.graphics.map.controls.original.panel.content.ESecondaryTabType; import jsettlers.graphics.map.controls.original.panel.content.MessageContent; import jsettlers.graphics.ui.Button; +import jsettlers.graphics.ui.LabeledButton; import jsettlers.graphics.ui.UIPanel; /** @@ -74,32 +75,30 @@ public class MainPanel extends UIPanel { new TabButton(ContentType.PRODUCTION, BUTTONS_FILE, 243, 255, ""), }; - private final MessageContent quitPrompt = new MessageContent( - Labels.getString("game-quit"), - Labels.getString("game-quit-cancel"), - new ExecutableAction() { - @Override - public void execute() { - setContent(ContentType.BUILD_NORMAL); - btnSystem.setActive(false); - } - }, - Labels.getString("game-quit-ok"), - new Action(EActionType.EXIT)) { - @Override - public void contentShowing(ActionFireable actionFireable) { - btnSystem.setActive(true); - } + private final UIPanel gamePanel = new UIPanel(); - @Override - public void contentHiding(ActionFireable actionFireable, AbstractContentProvider nextContent) { + private final LabeledButton exitButton = new LabeledButton(Labels.getString("game-menu-quit"), new Action(EActionType.EXIT)); + private final LabeledButton saveButton = new LabeledButton(Labels.getString("game-menu-save"), new Action(EActionType.SAVE)); + private final LabeledButton cancelButton = new LabeledButton(Labels.getString("game-menu-cancel"), new ExecutableAction() { + public void execute() { + setContent(ContentType.BUILD_NORMAL); btnSystem.setActive(false); } + }); + + { + gamePanel.addChild(saveButton, .1f, .4f, .9f, .5f); + gamePanel.addChild(exitButton, .1f, .25f, .9f, .35f); + gamePanel.addChild(cancelButton, .1f, .1f, .9f, .2f); + } + + private AbstractContentProvider gamePanelACP = new AbstractContentProvider() { + public UIPanel getPanel() { return gamePanel; } }; - private final Button btnSystem = new TabButton(quitPrompt, + private final Button btnSystem = new TabButton(gamePanelACP, new OriginalImageLink(EImageLinkType.GUI, BUTTONS_FILE, 93, 0), - new OriginalImageLink(EImageLinkType.GUI, BUTTONS_FILE, 96, 0), Labels.getString("game-quit-description")); + new OriginalImageLink(EImageLinkType.GUI, BUTTONS_FILE, 96, 0), Labels.getString("game-menu-description")); private final Button btnScroll = new TabButton(ContentType.EMPTY, BUTTONS_FILE, 111, 99, ""); private final Button btnSwords = new TabButton(ContentType.EMPTY, BUTTONS_FILE, 114, 102, ""); @@ -333,8 +332,8 @@ public PointAction getSelectAction(ShortPoint2D position) { goBackContent = activeContent; setContent(new MessageContent( Labels.getString("really_destroy_building"), - Labels.getName(EActionType.DESTROY), new Action( - EActionType.DESTROY), + Labels.getString("action_ASK_DESTROY"), + new Action(EActionType.DESTROY), Labels.getString("abort"), new Action(EActionType.ABORT)) { @Override diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/Background.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/Background.java index 5fb9ec85da..21826297af 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/Background.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/Background.java @@ -1199,7 +1199,7 @@ public void drawMapContent(MapDrawContext context, FloatRectangle screen) { try { gl.glTranslatef(0, 0, -.1f); gl.glScalef(1, 1, 0); - gl.glMultMatrixf(context.getConverter().getMatrixWithHeight(), 0); + gl.glMultMatrixf(context.getConverter().getMatrixWithHeight()); gl.color(1, 1, 1, 1); gl.drawTrianglesWithTextureColored(getTexture(context.getGl()), geometryhandle, geometrytirs); } finally { diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/DrawBuffer.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/DrawBuffer.java index 25f61ed47b..45dde6e540 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/DrawBuffer.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/DrawBuffer.java @@ -14,12 +14,11 @@ *******************************************************************************/ package jsettlers.graphics.map.draw; -import go.graphics.IllegalBufferException; -import go.graphics.TextureHandle; - import java.nio.ByteBuffer; import java.nio.ByteOrder; +import go.graphics.IllegalBufferException; +import go.graphics.TextureHandle; import jsettlers.graphics.map.IGLProvider; /** diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/MapObjectDrawer.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/MapObjectDrawer.java index eb52fe860c..b65612992e 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/MapObjectDrawer.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/MapObjectDrawer.java @@ -46,6 +46,7 @@ import jsettlers.common.position.ShortPoint2D; import jsettlers.common.sound.ISoundable; import jsettlers.graphics.image.Image; +import jsettlers.graphics.image.SettlerImage; import jsettlers.graphics.image.SingleImage; import jsettlers.graphics.image.sequence.Sequence; import jsettlers.graphics.map.MapDrawContext; @@ -168,19 +169,18 @@ public class MapObjectDrawer { private static final int MOVE_TO_MARKER_SEQUENCE = 0; private static final int MARKER_FILE = 3; - private static final float CONSTRUCTION_MARK_Z = 0.92f; - private static final float PLACEMENT_BUILDING_Z = 0.91f; - + private static final float CONSTRUCTION_MARK_Z = 0.92f; + private static final float PLACEMENT_BUILDING_Z = 0.91f; private static final float MOVABLE_SELECTION_MARKER_Z = 0.9f; private static final float BUILDING_SELECTION_MARKER_Z = 0.9f; + private static final float FLAG_ROOF_Z = 0.89f; + private static final float SMOKE_Z = 0.9f; + private static final float WAVES_Z = -0.1f; + private static final float BORDER_STONE_Z = -0.1f; - private static final float FLAG_ROOF_Z = 0.89f; - - private static final int SHIP_IMAGE_FILE = 36; - private static final int FERRY_BASE_SEQUENCE = 4; - private static final int CARGO_SHIP_BASE_SEQUENCE = 0; - private static final float WAVES_Z = -0.1f; - private static final float DOCK_Z = 0.f; + private static final int SHIP_IMAGE_FILE = 36; + private static final int FERRY_BASE_SEQUENCE = 4; + private static final int CARGO_SHIP_BASE_SEQUENCE = 0; private static final int SMOKE_HEIGHT = 30; @@ -237,6 +237,49 @@ public void drawMapObject(int x, int y, IMapObject object) { } } + public void drawDock(int x, int y, IMapObject object) { + forceSetup(); + byte fogStatus = context.getVisibleStatus(x, y); + if (fogStatus == 0) { + return; + } + float color = getColor(fogStatus); + Image image = imageProvider.getImage(new OriginalImageLink(EImageLinkType.SETTLER, 1, 112, 0)); + draw(image, x, y, getColor(object), color); + } + + public void drawStockBack(int x, int y, IBuilding stock) { + forceSetup(); + byte fogStatus = context.getVisibleStatus(x, y); + if (fogStatus == 0) { + return; + } + float color = getColor(fogStatus); + float state = stock.getStateProgress(); + if (state >= 0.99) { + ImageLink[] images = EBuildingType.STOCK.getImages(); + draw(imageProvider.getImage(images[0]), x, y, color); + draw(imageProvider.getImage(images[1]), x, y, color); + draw(imageProvider.getImage(images[5]), x, y, color); + } + } + + public void drawStockFront(int x, int y, IBuilding stock) { + forceSetup(); + byte fogStatus = context.getVisibleStatus(x, y); + if (fogStatus == 0) { + return; + } + float color = getColor(fogStatus); + float state = stock.getStateProgress(); + if (state >= 0.99) { + ImageLink[] images = EBuildingType.STOCK.getImages(); + for (int i = 2; i < 5; i++) { + draw(imageProvider.getImage(images[i]), x, y, color); + } + } + } + private void drawShipInConstruction(int x, int y, IShipInConstruction ship) { byte fogOfWarVisibleStatus = context.getVisibleStatus(x, y); EDirection direction = ship.getDirection(); @@ -525,7 +568,11 @@ private void drawObject(int x, int y, IMapObject object, float color) { break; case BUILDING: - drawBuilding(x, y, (IBuilding) object, color); + IBuilding building = (IBuilding) object; + if (building.getBuildingType() == EBuildingType.STOCK && building.getStateProgress() >= 0.99) { + return; + } + drawBuilding(x, y, building, color); break; case PLACEMENT_BUILDING: @@ -556,13 +603,6 @@ private void drawObject(int x, int y, IMapObject object, float color) { drawDonkey(x, y, object, color); break; - case DOCK: - float z = context.getDrawBuffer().getZ(); - context.getDrawBuffer().setZ(DOCK_Z); - drawDock(x, y, object, color); - context.getDrawBuffer().setZ(z); - break; - case FISH_DECORATION: drawDecorativeFish(x, y, color); break; @@ -597,7 +637,12 @@ private void drawRoofFlag(int x, int y, IMapObject object, float color) { private void drawPlacementBuilding(int x, int y, IMapObject object, float color) { float z = context.getDrawBuffer().getZ(); context.getDrawBuffer().setZ(PLACEMENT_BUILDING_Z); - drawBuilding(x, y, (IBuilding) object, color); + ImageLink[] images = ((IBuilding) object).getBuildingType().getImages(); + Image image; + for (ImageLink image1 : images) { + image = imageProvider.getImage(image1); + drawOnlyImage(image, x, y, color); + } context.getDrawBuffer().setZ(z); } @@ -629,11 +674,6 @@ private void drawDonkey(int x, int y, IMapObject object, float color) { draw(image, x, y, getColor(object), color); } - private void drawDock(int x, int y, IMapObject object, float color) { - Image image = imageProvider.getImage(new OriginalImageLink(EImageLinkType.SETTLER, 1, 112, 0)); - draw(image, x, y, getColor(object), color); - } - private void drawDecorativeFish(int x, int y, float color) { int step = getAnimationStep(x, y); Sequence seq = this.imageProvider.getSettlerSequence(ANIMALS_FILE, FISH_SEQ); @@ -865,7 +905,10 @@ private void drawMovableAt(IMovable movable, int x, int y) { viewY = context.getConverter().getViewY(smokeX, smokeY, height); link = new OriginalImageLink(EImageLinkType.SETTLER, 13, 42, number > 35 ? 35 : number); image = imageProvider.getImage(link); + float z = context.getDrawBuffer().getZ(); + context.getDrawBuffer().setZ(SMOKE_Z); image.drawAt(context.getGl(), context.getDrawBuffer(), viewX, viewY, color, shade); + context.getDrawBuffer().setZ(z); } if (movable.getAction() == EMovableAction.WALKING) { @@ -1100,8 +1143,10 @@ public void drawPlayerBorderObject(int x, int y, byte player) { } float base = getColor(fogStatus); Color color = context.getPlayerColor(player); - + float z = context.getDrawBuffer().getZ(); + context.getDrawBuffer().setZ(BORDER_STONE_Z); draw(imageProvider.getSettlerSequence(FILE_BORDER_POST, 65).getImageSafe(0), x, y, color, base); + context.getDrawBuffer().setZ(z); } private static int getTreeType(int x, int y) { @@ -1198,7 +1243,12 @@ private void drawBuilding(int x, int y, IBuilding building, float color) { if (seq.length() > 0) { int i = getAnimationStep(x, y); int step = i % seq.length(); - draw(seq.getImageSafe(step), x, y, color); + drawOnlyImage(seq.getImageSafe(step), x, y, color); + ImageLink[] images = type.getImages(); + if (images.length > 0) { + Image image = imageProvider.getImage(images[0]); + drawOnlyShadow(image, x, y, color); + } } playSound(building, SOUND_MILL, x, y); @@ -1281,6 +1331,7 @@ private void drawOccupiers(int x, int y, IOccupied building, float baseColor) { case INFANTRY: OriginalImageLink imageLink = place.looksRight() ? INSIDE_BUILDING_RIGHT : INSIDE_BUILDING_LEFT; image = imageProvider.getImage(imageLink); + ((SettlerImage)image).setShadow(null); break; case BOWMAN: default: @@ -1398,6 +1449,16 @@ private void draw(Image image, int x, int y, float color) { draw(image, x, y, iColor); } + private void drawOnlyImage(Image image, int x, int y, float color) { + int iColor = Color.getABGR(color, color, color, 1); + drawOnlyImage(image, x, y, iColor); + } + + private void drawOnlyShadow(Image image, int x, int y, float color) { + int iColor = Color.getABGR(color, color, color, 1); + drawOnlyShadow(image, x, y, iColor); + } + private void drawWithHeight(Image image, int x, int y, int height, float color) { int iColor = Color.getABGR(color, color, color, 1); drawWithHeight(image, x, y, height, iColor); @@ -1407,10 +1468,23 @@ private void draw(Image image, int x, int y, int color) { int height = context.getHeight(x, y); float viewX = context.getConverter().getViewX(x, y, height); float viewY = context.getConverter().getViewY(x, y, height); - image.drawAt(context.getGl(), context.getDrawBuffer(), viewX, viewY, color); } + private void drawOnlyImage(Image image, int x, int y, int color) { + int height = context.getHeight(x, y); + float viewX = context.getConverter().getViewX(x, y, height); + float viewY = context.getConverter().getViewY(x, y, height); + image.drawOnlyImageAt(context.getGl(), context.getDrawBuffer(), viewX, viewY, color); + } + + private void drawOnlyShadow(Image image, int x, int y, int color) { + int height = context.getHeight(x, y); + float viewX = context.getConverter().getViewX(x, y, height); + float viewY = context.getConverter().getViewY(x, y, height); + image.drawOnlyShadowAt(context.getGl(), context.getDrawBuffer(), viewX, viewY, color); + } + private void drawWithHeight(Image image, int x, int y, int height, int color) { int baseHeight = context.getHeight(x, y); float viewX = context.getConverter().getViewX(x, y, baseHeight + height); diff --git a/jsettlers.graphics/src/main/res/layout/MaterialInventoryLayout.xml b/jsettlers.graphics/src/main/res/layout/MaterialInventoryLayout.xml index 369c0c29e7..c48a709d41 100644 --- a/jsettlers.graphics/src/main/res/layout/MaterialInventoryLayout.xml +++ b/jsettlers.graphics/src/main/res/layout/MaterialInventoryLayout.xml @@ -2,7 +2,7 @@ - + diff --git a/jsettlers.graphics/src/main/res/layout/MaterialPriorityLayout.xml b/jsettlers.graphics/src/main/res/layout/MaterialPriorityLayout.xml index 035c72d45b..e4b5088dc4 100644 --- a/jsettlers.graphics/src/main/res/layout/MaterialPriorityLayout.xml +++ b/jsettlers.graphics/src/main/res/layout/MaterialPriorityLayout.xml @@ -3,7 +3,7 @@ - + diff --git a/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_da_DK.properties b/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_da_DK.properties index 5c370dd46a..471ef5a6fd 100644 --- a/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_da_DK.properties +++ b/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_da_DK.properties @@ -286,9 +286,8 @@ settings-server = Netværksserver settings-volume = Lydstyrke settings-back = Tilbage settings-ok = OK -game-quit = Vil du afslutte? -game-quit-cancel = Fortryd -game-quit-ok = Afslut +game-menu-cancel = Fortryd +game-menu-quit = Afslut game-quit-description = Afslut spillet # Swing extras diff --git a/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_de.properties b/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_de.properties index abc7a7daf2..c714d631fe 100644 --- a/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_de.properties +++ b/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_de.properties @@ -126,11 +126,11 @@ resource_GOLDORE = Gold resource_IRONORE = Eisen # actions -action_BUILD = bauen -action_ASK_DESTROY = abreißen -action_MOVE_TO = gehe nach -action_START_WORKING = beginne zu arbeiten -action_STOP_WORKING = höre auf zu arbeiten +action_BUILD = Bauen +action_ASK_DESTROY = Abreißen +action_MOVE_TO = Gehe nach +action_START_WORKING = Beginne zu arbeiten +action_STOP_WORKING = Höre auf zu arbeiten action_NEXT_OF_TYPE = Nächstes Gebäude dieses Typs action_ASK_SET_WORK_AREA = Arbeitsbereich setzen action_ASK_SET_DOCK = Setze Dockposition @@ -161,6 +161,7 @@ controlpanel_title_inventory = Lagerbestand controlpanel_tools_title = Werkzeug controlpanel_weapons_title = Waffen controlpanel_distribution_title = Warenverteilung +controlpanel_transportation_title = Warentransport # Settlers Control Panel Titles settler_stats_title = Siedlerstatistik @@ -321,10 +322,10 @@ settings-server = Mehrspielerserver settings-volume = Lautstärke settings-back = Abbrechen settings-ok = OK -game-quit = Möchten Sie das Spiel beenden? -game-quit-cancel = Abbrechen -game-quit-ok = Beenden -game-quit-description = Spiel beenden +game-menu-cancel = Abbrechen +game-menu-quit = Beenden +game-menu-save = Speichern +game-menu-description = Spielmenü # Swing extras diff --git a/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_en.properties b/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_en.properties index 78a7c0d21d..f3d17078c0 100644 --- a/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_en.properties +++ b/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_en.properties @@ -161,6 +161,7 @@ controlpanel_title_inventory = Inventory controlpanel_tools_title = Tools controlpanel_weapons_title = Weapons controlpanel_distribution_title = Goods Distribution +controlpanel_transportation_title = Goods Transportation # Settlers Control Panel Titles settler_stats_title = Settler Statistic @@ -319,12 +320,14 @@ settings-title = Settings settings-name = Player Name settings-server = server for multiplayer games settings-volume = Volume +settings-fps-limit = fps limit +settings-backend = drawing backend settings-back = Back settings-ok = OK -game-quit = Do you wish to quit? -game-quit-cancel = Cancel -game-quit-ok = Quit game -game-quit-description = Quit the game +game-menu-cancel = Cancel +game-menu-quit = Quit game +game-menu-save = Save game +game-menu-description = Quit or Save the game # Swing extras diff --git a/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_es.properties b/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_es.properties index 9de42feebb..746f0b410d 100644 --- a/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_es.properties +++ b/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_es.properties @@ -310,9 +310,8 @@ settings-server = Nombre de Servidor settings-volume = Volumen settings-back = Volver settings-ok = OK -game-quit = ¿Deseas abandonar la partida? -game-quit-cancel = Cancelar -game-quit-ok = Abandonar +game-menu-cancel = Cancelar +game-menu-quit = Abandonar game-quit-description = Cerrar el Juego # Swing extras diff --git a/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_pl.properties b/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_pl.properties index 51287f9f63..9ee8d452cc 100644 --- a/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_pl.properties +++ b/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_pl.properties @@ -285,9 +285,8 @@ settings-server = Serwer dla gry wieloosobowej settings-volume = Głośność settings-back = Wróć settings-ok = OK -game-quit = Czy na pewno chcesz wyjść z gry? -game-quit-cancel = Anuluj -game-quit-ok = Wyjdź +game-menu-quit = Wyjdź +game-menu-cancel = Anuluj game-quit-description = Wyjdź z gry # Swing extras diff --git a/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_ru.properties b/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_ru.properties index 37f41d64f9..5a1b56521c 100644 --- a/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_ru.properties +++ b/jsettlers.graphics/src/main/resources/jsettlers/graphics/localization/labels_ru.properties @@ -282,9 +282,8 @@ settings-server = Адрес сервера settings-volume = Громкость settings-back = Назад settings-ok = Применить -game-quit = Вы хотите выйти? -game-quit-cancel = Отмена -game-quit-ok = Выйти +game-menu-cancel = Отмена +game-menu-quit = Выйти game-quit-description = Выйти из игры # Swing extras diff --git a/jsettlers.logic/src/main/java/jsettlers/input/GuiTaskExecutor.java b/jsettlers.logic/src/main/java/jsettlers/input/GuiTaskExecutor.java index 116e8294eb..a1113ea780 100644 --- a/jsettlers.logic/src/main/java/jsettlers/input/GuiTaskExecutor.java +++ b/jsettlers.logic/src/main/java/jsettlers/input/GuiTaskExecutor.java @@ -367,7 +367,7 @@ private Optional removeMovableThatCanMoveTo(List m } private boolean canMoveTo(ILogicMovable movable, int x, int y) { - return (movable.isShip() && grid.isWater(x, y)) + return (movable.isShip() && grid.isNavigable(x, y)) || (!grid.isBlocked(x, y) && grid.getBlockedPartition(movable.getPosition().x, movable.getPosition().y) == grid.getBlockedPartition(x, y)); } diff --git a/jsettlers.logic/src/main/java/jsettlers/input/IGuiInputGrid.java b/jsettlers.logic/src/main/java/jsettlers/input/IGuiInputGrid.java index b2c3989e8f..5fabfb11d5 100644 --- a/jsettlers.logic/src/main/java/jsettlers/input/IGuiInputGrid.java +++ b/jsettlers.logic/src/main/java/jsettlers/input/IGuiInputGrid.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015 - 2017 + * Copyright (c) 2015 - 2018 * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, @@ -136,5 +136,5 @@ public interface IGuiInputGrid { FerryEntrance ferryAtPosition(ShortPoint2D position, byte playerId); - boolean isWater(int x, int y); + boolean isNavigable(int x, int y); } diff --git a/jsettlers.logic/src/main/java/jsettlers/logic/buildings/trading/TradingBuilding.java b/jsettlers.logic/src/main/java/jsettlers/logic/buildings/trading/TradingBuilding.java index a49de0193b..0791dccd34 100644 --- a/jsettlers.logic/src/main/java/jsettlers/logic/buildings/trading/TradingBuilding.java +++ b/jsettlers.logic/src/main/java/jsettlers/logic/buildings/trading/TradingBuilding.java @@ -110,12 +110,12 @@ public void setWaypoint(EWaypointType waypointType, ShortPoint2D position) { Arrays.fill(waypoints, null); } - ShortPoint2D closeReachableLocation = findClosestReachablePosition(waypointType, position); - if (closeReachableLocation != null && !isWaypointFulfillingPreconditions(waypointType, closeReachableLocation)) { + ShortPoint2D closestReachableLocation = findClosestReachablePosition(waypointType, position); + if (closestReachableLocation == null || !isWaypointFulfillingPreconditions(waypointType, closestReachableLocation)) { return; } - waypoints[waypointType.ordinal()] = closeReachableLocation; + waypoints[waypointType.ordinal()] = closestReachableLocation; if (isSelected()) { drawWaypointLine(true); diff --git a/jsettlers.logic/src/main/java/jsettlers/logic/map/grid/MainGrid.java b/jsettlers.logic/src/main/java/jsettlers/logic/map/grid/MainGrid.java index 4c8ec5e621..7b2a142ef4 100644 --- a/jsettlers.logic/src/main/java/jsettlers/logic/map/grid/MainGrid.java +++ b/jsettlers.logic/src/main/java/jsettlers/logic/map/grid/MainGrid.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015 - 2017 + * Copyright (c) 2015 - 2018 * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, @@ -494,12 +494,20 @@ final void checkPositionThatChangedPlayer(int x, int y) { final boolean isValidPosition(IPathCalculatable pathCalculatable, int x, int y) { if (pathCalculatable.isShip()) { - return isSurroundedByWater((short) x, (short) y); + return isNavigable(x, y); } return isInBounds(x, y) && !flagsGrid.isBlocked(x, y) && (!pathCalculatable.needsPlayersGround() || pathCalculatable.getPlayer().getPlayerId() == partitionsGrid.getPlayerIdAt(x, y)); } + final boolean isNavigable(int x, int y) { + Optional blockingOptional = HexGridArea.stream(x, y, 0, 2) + .filterBounds(width, height) + .filter((x1, y1) -> !landscapeGrid.getLandscapeTypeAt(x1, y1).isWater || objectsGrid.getMapObjectAt(x1, y1, EMapObjectType.DOCK) != null) + .getFirst(); + return !blockingOptional.isPresent(); + } + public FlagsGrid getFlagsGrid() { return flagsGrid; } @@ -521,7 +529,6 @@ public boolean isBlocked(IPathCalculatable requester, int x, int y) { @Override public final float getCost(int sx, int sy, int tx, int ty) { - // return Constants.TILE_PATHFINDER_COST * (flagsGrid.isProtected(sx, sy) ? 3.5f : 1); return 1; } @@ -843,11 +850,6 @@ public final void setBackgroundListener(IGraphicsBackgroundListener backgroundLi landscapeGrid.setBackgroundListener(backgroundListener); } - @Override - public int nextDrawableX(int x, int y, int maxX) { - return x + 1; - } - @Override public IPartitionData getPartitionData(int x, int y) { return partitionsGrid.getPartitionDataForManagerAt(x, y); @@ -1576,7 +1578,7 @@ public void removeDock(DockPosition dockPosition) { @Override public boolean isCoastReachable(ShortPoint2D position) { - return !HexGridArea.stream(position.x, position.y, 0, 2) + return !HexGridArea.stream(position.x, position.y, 0, 3) .filterBounds(width, height) .filter((x, y) -> !landscapeGrid.getLandscapeTypeAt(x, y).isWater) .isEmpty(); @@ -1924,8 +1926,8 @@ public FerryEntrance ferryAtPosition(ShortPoint2D position, byte playerId) { } @Override - public boolean isWater(int x, int y) { - return landscapeGrid.getLandscapeTypeAt(x, y).isWater; + public boolean isNavigable(int x, int y) { + return MainGrid.this.isNavigable(x, y); } @Override diff --git a/jsettlers.logic/src/main/java/jsettlers/logic/map/loading/original/OriginalMapFileContentReader.java b/jsettlers.logic/src/main/java/jsettlers/logic/map/loading/original/OriginalMapFileContentReader.java index bbba603d61..af670bb731 100644 --- a/jsettlers.logic/src/main/java/jsettlers/logic/map/loading/original/OriginalMapFileContentReader.java +++ b/jsettlers.logic/src/main/java/jsettlers/logic/map/loading/original/OriginalMapFileContentReader.java @@ -14,6 +14,15 @@ *******************************************************************************/ package jsettlers.logic.map.loading.original; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.EnumMap; +import java.util.List; + +import jsettlers.common.Color; import java8.util.Optional; import jsettlers.common.buildings.EBuildingType; import jsettlers.common.position.RelativePoint; @@ -414,8 +423,8 @@ private short[] getPreviewImage(int width, int height) throws MapLoadException { int colorValue = (mapContent[inIndex] & 0xFF) | ((mapContent[inIndex + 1] & 0xFF) << 8); - // - the Settlers Remake uses Short-Colors like argb_1555 (alpha, r, g, b) - outImg[outIndex] = (short) (1 | colorValue << 1); + // - the Settlers Remake uses rgba4444 colors + outImg[outIndex] = (short) Color.convert565to4444(colorValue); outIndex++; } } diff --git a/jsettlers.logic/src/test/java/jsettlers/integration/ai/AiDifficultiesIT.java b/jsettlers.logic/src/test/java/jsettlers/integration/ai/AiDifficultiesIT.java index 8b657dc797..06c510e674 100644 --- a/jsettlers.logic/src/test/java/jsettlers/integration/ai/AiDifficultiesIT.java +++ b/jsettlers.logic/src/test/java/jsettlers/integration/ai/AiDifficultiesIT.java @@ -54,7 +54,7 @@ public class AiDifficultiesIT { @Test public void easyShouldConquerVeryEasy() throws MapLoadException { - holdBattleBetween(EPlayerType.AI_EASY, EPlayerType.AI_VERY_EASY, 75 * MINUTES); + holdBattleBetween(EPlayerType.AI_EASY, EPlayerType.AI_VERY_EASY, 80 * MINUTES); } @Test @@ -78,7 +78,7 @@ public void veryHardShouldProduceCertainAmountOfSoldiersWithin90Minutes() throws MatchConstants.clock().fastForwardTo(90 * MINUTES); - short expectedMinimalProducedSoldiers = 920; + short expectedMinimalProducedSoldiers = 850; short producedSoldiers = startingGame.getMainGrid().getPartitionsGrid().getPlayer(0).getEndgameStatistic().getAmountOfProducedSoldiers(); if (producedSoldiers < expectedMinimalProducedSoldiers) { stopAndFail("AI_VERY_HARD was not able to produce " + expectedMinimalProducedSoldiers + " soldiers within 90 minutes.\nOnly " + producedSoldiers diff --git a/jsettlers.main.android/AndroidManifest.xml b/jsettlers.main.android/AndroidManifest.xml index 432d84cc97..e617c4239f 100644 --- a/jsettlers.main.android/AndroidManifest.xml +++ b/jsettlers.main.android/AndroidManifest.xml @@ -19,7 +19,7 @@ android:largeHeap="true" android:theme="@style/SettlersTheme"> - + @@ -27,7 +27,7 @@ @@ -38,7 +38,7 @@ android:description="@string/service_description"/> diff --git a/jsettlers.main.android/build.gradle b/jsettlers.main.android/build.gradle index f106a5fb9d..a954cd66de 100644 --- a/jsettlers.main.android/build.gradle +++ b/jsettlers.main.android/build.gradle @@ -46,6 +46,10 @@ android { packagingOptions { pickFirst '**' } + + dataBinding { + enabled = true + } } dependencies { @@ -56,6 +60,7 @@ dependencies { implementation project(':jsettlers.common') implementation project(':jsettlers.network') + implementation "android.arch.lifecycle:extensions:1.1.1" implementation 'com.android.support:appcompat-v7:' + rootProject.ext.androidSupportLibraryVersion implementation 'com.android.support:support-v4:' + rootProject.ext.androidSupportLibraryVersion implementation 'com.android.support:cardview-v7:' + rootProject.ext.androidSupportLibraryVersion diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/MainApplication.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/MainApplication.java index a24240868b..a566cc8b8b 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/MainApplication.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/MainApplication.java @@ -15,15 +15,11 @@ package jsettlers.main.android; -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_PAUSE; -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_QUIT; -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_QUIT_CONFIRM; -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_SAVE; -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_UNPAUSE; +import android.app.Application; +import android.arch.lifecycle.Observer; import org.androidannotations.annotations.EApplication; -import jsettlers.common.menu.IGameExitListener; import jsettlers.common.menu.IJoinPhaseMultiplayerGameConnector; import jsettlers.common.menu.IJoiningGame; import jsettlers.common.menu.IMapInterfaceConnector; @@ -39,16 +35,10 @@ import jsettlers.main.android.core.GameStarter; import jsettlers.main.android.core.controls.ControlsAdapter; import jsettlers.main.android.core.controls.GameMenu; - -import android.app.Application; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.support.v4.content.LocalBroadcastManager; +import jsettlers.main.android.core.resources.scanner.AndroidResourcesLoader; @EApplication -public class MainApplication extends Application implements GameStarter, GameManager, IGameExitListener { +public class MainApplication extends Application implements GameStarter, GameManager { static { // configure game to be better usable on Android Constants.BUILDING_PLACEMENT_MAX_SEARCH_RADIUS = 10; } @@ -61,22 +51,11 @@ public class MainApplication extends Application implements GameStarter, GameMan private ControlsAdapter controlsAdapter; - private LocalBroadcastManager localBroadcastManager; - @Override public void onCreate() { super.onCreate(); System.setProperty("org.xml.sax.driver", "org.xmlpull.v1.sax2.Driver"); - localBroadcastManager = LocalBroadcastManager.getInstance(this); - - // TODO register this only when a game starts - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(ACTION_PAUSE); - intentFilter.addAction(ACTION_UNPAUSE); - intentFilter.addAction(ACTION_SAVE); - intentFilter.addAction(ACTION_QUIT); - intentFilter.addAction(ACTION_QUIT_CONFIRM); - registerReceiver(broadcastReceiver, intentFilter); + new AndroidResourcesLoader(this).setup(); } /** @@ -140,9 +119,10 @@ public void setJoinPhaseMultiPlayerConnector(IJoinPhaseMultiplayerGameConnector @Override public IMapInterfaceConnector gameStarted(IStartedGame game) { controlsAdapter = new ControlsAdapter(getApplicationContext(), game); - GameService_.intent(this).start(); + game.setGameExitListener(controlsAdapter.getGameMenu()); + controlsAdapter.getGameMenu().getGameState().observeForever(gameStateObserver); - game.setGameExitListener(this); + GameService_.intent(this).start(); return controlsAdapter.getMapContent().getInterfaceConnector(); } @@ -157,6 +137,10 @@ public ControlsAdapter getControlsAdapter() { @Override public GameMenu getGameMenu() { + if (controlsAdapter == null) { + return null; + } + return controlsAdapter.getGameMenu(); } @@ -165,43 +149,21 @@ public boolean isGameInProgress() { return controlsAdapter != null; } - /** - * IGameExitedListener implementation - */ - @Override - public void gameExited(IStartedGame game) { - controlsAdapter = null; - startingGame = null; - joiningGame = null; - joinPhaseMultiplayerGameConnector = null; - mapList = null; // Nulling this means that any new saved games will be available next time mapList is set - closeMultiPlayerConnector(); - // Send a local broadcast so that any UI can update if necessary and the service can stop itself - localBroadcastManager.sendBroadcast(new Intent(ACTION_QUIT_CONFIRM)); - } - private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - switch (intent.getAction()) { - case ACTION_PAUSE: - controlsAdapter.getGameMenu().pause(); - break; - case ACTION_UNPAUSE: - controlsAdapter.getGameMenu().unPause(); - break; - case ACTION_SAVE: - controlsAdapter.getGameMenu().save(); - break; - case ACTION_QUIT: - controlsAdapter.getGameMenu().quit(); - break; - case ACTION_QUIT_CONFIRM: - controlsAdapter.getGameMenu().quitConfirm(); - break; - } + + private Observer gameStateObserver = gameState -> { + if (gameState == GameMenu.GameState.QUITTED) { + controlsAdapter.getGameMenu().getGameState().removeObserver(this.gameStateObserver); + + controlsAdapter = null; + startingGame = null; + joiningGame = null; + joinPhaseMultiplayerGameConnector = null; + mapList = null; // Nulling this means that any new saved games will be available next time mapList is set + + closeMultiPlayerConnector(); } }; } diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/core/GameService.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/GameService.java index 5aa5217379..4bc243878c 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/core/GameService.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/GameService.java @@ -15,24 +15,63 @@ package jsettlers.main.android.core; -import static jsettlers.main.android.core.controls.GameMenu.NOTIFICATION_ID; -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_QUIT_CONFIRM; - -import org.androidannotations.annotations.EService; -import org.androidannotations.annotations.Receiver; - +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; import android.app.Service; +import android.arch.lifecycle.Observer; +import android.content.BroadcastReceiver; +import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; +import android.os.Build; import android.os.IBinder; +import org.androidannotations.annotations.EService; + +import jsettlers.main.android.R; +import jsettlers.main.android.core.controls.GameMenu; +import jsettlers.main.android.core.controls.NotificationBuilder; +import jsettlers.main.android.core.controls.NotificationBuilder_; + @EService public class GameService extends Service { + public static final String ACTION_PAUSE = "com.jsettlers.pause"; + public static final String ACTION_UNPAUSE = "com.jsettlers.unpause"; + public static final String ACTION_SAVE = "com.jsettlers.save"; + public static final String ACTION_QUIT = "com.jsettlers.quit"; + public static final String ACTION_QUIT_CONFIRM = "com.jsettlers.quitconfirm"; + public static final String ACTION_QUIT_CANCELLED = "com.jsettlers.quitcancelled"; + + public static final int NOTIFICATION_ID = 100; + + private final Observer pauseObserver = paused -> postNotification(); + private final Observer gameStateObserver = gameState -> postNotification(); + + private GameMenu gameMenu; + private NotificationManager notificationManager; @Override public void onCreate() { super.onCreate(); GameManager gameManager = (GameManager) getApplication(); - startForeground(NOTIFICATION_ID, gameManager.getGameMenu().createNotification()); + gameMenu = gameManager.getGameMenu(); + notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE); + + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ACTION_PAUSE); + intentFilter.addAction(ACTION_UNPAUSE); + intentFilter.addAction(ACTION_SAVE); + intentFilter.addAction(ACTION_QUIT); + intentFilter.addAction(ACTION_QUIT_CONFIRM); + registerReceiver(broadcastReceiver, intentFilter); + + createNotificationChannel(); + + startForeground(NOTIFICATION_ID, createNotification()); + + gameMenu.isPausedState().observeForever(pauseObserver); + gameMenu.getGameState().observeForever(gameStateObserver); } @Override @@ -40,14 +79,78 @@ public int onStartCommand(Intent intent, int flags, int startId) { return START_NOT_STICKY; } + @Override + public void onDestroy() { + super.onDestroy(); + unregisterReceiver(broadcastReceiver); + gameMenu.isPausedState().removeObserver(pauseObserver); + gameMenu.getGameState().observeForever(gameStateObserver); + } + @Override public IBinder onBind(Intent intent) { return null; } - @Receiver(actions = ACTION_QUIT_CONFIRM, local = true) - void quitConfirmReceived() { - stopForeground(true); - stopSelf(); + private void postNotification() { + if (gameMenu.getGameState().getValue() == GameMenu.GameState.QUITTED) { + notificationManager.cancel(NOTIFICATION_ID); + stopForeground(true); + stopSelf(); + } else { + notificationManager.notify(NOTIFICATION_ID, createNotification()); + } + } + + private Notification createNotification() { + NotificationBuilder notificationBuilder = NotificationBuilder_.getInstance_(getApplicationContext()); + + if (gameMenu.getGameState().getValue() == GameMenu.GameState.CONFIRM_QUIT) { + notificationBuilder.addQuitConfirmButton(); + } else { + notificationBuilder.addQuitButton(); + } + + notificationBuilder.addSaveButton(); + + if (gameMenu.isPausedState().getValue() == Boolean.TRUE) { + notificationBuilder.addUnPauseButton(); + } else { + notificationBuilder.addPauseButton(); + } + + return notificationBuilder.build(); + } + + private void createNotificationChannel() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + CharSequence name = getString(R.string.app_name); + int importance = NotificationManager.IMPORTANCE_LOW; + NotificationChannel channel = new NotificationChannel(getString(R.string.notification_channel_id), name, importance); + notificationManager.createNotificationChannel(channel); + } } + + private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + switch (intent.getAction()) { + case ACTION_PAUSE: + gameMenu.pause(); + break; + case ACTION_UNPAUSE: + gameMenu.unPause(); + break; + case ACTION_SAVE: + gameMenu.save(); + break; + case ACTION_QUIT: + gameMenu.quit(); + break; + case ACTION_QUIT_CONFIRM: + gameMenu.quitConfirm(); + break; + } + } + }; } diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/core/controls/ControlsResolver.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/controls/ControlsResolver.java index 25435ad5bf..19d88f76a7 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/core/controls/ControlsResolver.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/controls/ControlsResolver.java @@ -15,6 +15,7 @@ package jsettlers.main.android.core.controls; +import jsettlers.common.player.IInGamePlayer; import jsettlers.graphics.map.MapContent; import jsettlers.main.android.core.GameManager; @@ -57,4 +58,8 @@ public GameMenu getGameMenu() { public PositionControls getPositionControls() { return controlsAdapter; } + + public IInGamePlayer getPlayer() { + return controlsAdapter.getInGamePlayer(); + } } diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/core/controls/GameMenu.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/controls/GameMenu.java index c507963f37..aeee72fa46 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/core/controls/GameMenu.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/controls/GameMenu.java @@ -15,52 +15,54 @@ package jsettlers.main.android.core.controls; -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_PAUSE; -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_QUIT; -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_QUIT_CANCELLED; -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_UNPAUSE; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.MutableLiveData; +import android.content.Context; +import android.widget.Toast; import java.util.Timer; import java.util.TimerTask; import go.graphics.android.AndroidSoundPlayer; - -import jsettlers.common.action.EActionType; import jsettlers.common.action.Action; +import jsettlers.common.action.EActionType; +import jsettlers.common.menu.IGameExitListener; +import jsettlers.common.menu.IStartedGame; import jsettlers.main.android.R; -import android.app.Notification; -import android.app.NotificationManager; -import android.content.Context; -import android.content.Intent; -import android.support.v4.content.LocalBroadcastManager; -import android.widget.Toast; - /** * GameMenu is a singleton within the scope of a started game */ -public class GameMenu { - - public static final int NOTIFICATION_ID = 100; +public class GameMenu implements IGameExitListener { + public enum GameState { + PLAYING, + CONFIRM_QUIT, + QUITTED + } private final Context context; private final ActionControls actionControls; private final AndroidSoundPlayer soundPlayer; - private final LocalBroadcastManager localBroadcastManager; - private final NotificationManager notificationManager; - private Timer quitConfirmTimer; - private boolean paused = false; + private final MutableLiveData gameState = new MutableLiveData<>(); + public LiveData getGameState() { + return gameState; + } + + private final MutableLiveData pausedState = new MutableLiveData<>(); + public LiveData isPausedState() { + return pausedState; + } public GameMenu(Context context, AndroidSoundPlayer soundPlayer, ActionControls actionFireable) { this.context = context; this.soundPlayer = soundPlayer; this.actionControls = actionFireable; - localBroadcastManager = LocalBroadcastManager.getInstance(context); - notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + pausedState.postValue(false); + gameState.postValue(GameState.PLAYING); } public void save() { @@ -72,25 +74,15 @@ public void save() { public void pause() { actionControls.fireAction(new Action(EActionType.SPEED_SET_PAUSE)); mute(); - paused = true; - // Send a local broadcast so that any UI can update if necessary - localBroadcastManager.sendBroadcast(new Intent(ACTION_PAUSE)); - notificationManager.notify(NOTIFICATION_ID, createNotification()); + pausedState.postValue(true); } - // don't unmute here, MapFragment will unmute when receiving unpause broadcast if its visible. + // don't unmute here, MapFragment will unmute if its visible. public void unPause() { actionControls.fireAction(new Action(EActionType.SPEED_UNSET_PAUSE)); - paused = false; - - // Send a local broadcast so that any UI can update if necessary - localBroadcastManager.sendBroadcast(new Intent(ACTION_UNPAUSE)); - notificationManager.notify(NOTIFICATION_ID, createNotification()); - } - public boolean isPaused() { - return paused; + pausedState.postValue(false); } public void quit() { @@ -101,15 +93,13 @@ public void quit() { public void run() { if (quitConfirmTimer != null) { quitConfirmTimer = null; - notificationManager.notify(NOTIFICATION_ID, createNotification()); - localBroadcastManager.sendBroadcast(new Intent(ACTION_QUIT_CANCELLED)); + + gameState.postValue(GameState.PLAYING); } } }, 3000); - // Send a local broadcast so that any UI can update if necessary - localBroadcastManager.sendBroadcast(new Intent(ACTION_QUIT)); - notificationManager.notify(NOTIFICATION_ID, createNotification()); + gameState.postValue(GameState.CONFIRM_QUIT); } public void quitConfirm() { @@ -118,10 +108,6 @@ public void quitConfirm() { actionControls.fireAction(new Action(EActionType.EXIT)); } - public boolean canQuitConfirm() { - return quitConfirmTimer != null; - } - public void mute() { soundPlayer.setPaused(true); } @@ -130,23 +116,11 @@ public void unMute() { soundPlayer.setPaused(false); } - public Notification createNotification() { - NotificationBuilder notificationBuilder = NotificationBuilder_.getInstance_(context); - - if (quitConfirmTimer == null) { - notificationBuilder.addQuitButton(); - } else { - notificationBuilder.addQuitConfirmButton(); - } - - notificationBuilder.addSaveButton(); - - if (isPaused()) { - notificationBuilder.addUnPauseButton(); - } else { - notificationBuilder.addPauseButton(); - } - - return notificationBuilder.build(); + /** + * IGameExitedListener implementation + */ + @Override + public void gameExited(IStartedGame game) { + gameState.postValue(GameState.QUITTED); } } diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/core/controls/NotificationBuilder.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/controls/NotificationBuilder.java index 75351e0a33..b02da59025 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/core/controls/NotificationBuilder.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/controls/NotificationBuilder.java @@ -20,7 +20,8 @@ import org.androidannotations.annotations.res.StringRes; import jsettlers.main.android.R; -import jsettlers.main.android.gameplay.ui.activities.GameActivity_; +import jsettlers.main.android.core.GameService; +import jsettlers.main.android.gameplay.GameActivity_; import jsettlers.main.android.mainmenu.navigation.Actions; import android.app.Notification; @@ -33,7 +34,7 @@ * Created by Andreas Eberle on 13.05.2017. */ @EBean -class NotificationBuilder { +public class NotificationBuilder { private final Context context; private NotificationCompat.Builder builder; @@ -59,38 +60,39 @@ void setupBuilder() { Intent gameActivityIntent = GameActivity_.intent(context).action(Actions.ACTION_RESUME_GAME).get(); PendingIntent gameActivityPendingIntent = PendingIntent.getActivity(context, 0, gameActivityIntent, 0); - builder = new NotificationCompat.Builder(context) + builder = new NotificationCompat.Builder(context, context.getString(R.string.notification_channel_id)) .setSmallIcon(R.drawable.icon) .setContentTitle(title) - .setContentIntent(gameActivityPendingIntent); + .setContentIntent(gameActivityPendingIntent) + .setPriority(NotificationCompat.PRIORITY_DEFAULT); } public NotificationBuilder addQuitButton() { - PendingIntent quitPendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(Actions.ACTION_QUIT), 0); + PendingIntent quitPendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(GameService.ACTION_QUIT), 0); builder.addAction(R.drawable.ic_stop, quit, quitPendingIntent); return this; } public NotificationBuilder addQuitConfirmButton() { - PendingIntent quitPendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(Actions.ACTION_QUIT_CONFIRM), 0); + PendingIntent quitPendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(GameService.ACTION_QUIT_CONFIRM), 0); builder.addAction(R.drawable.ic_stop, quitConfirmString, quitPendingIntent); return this; } public NotificationBuilder addSaveButton() { - PendingIntent savePendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(Actions.ACTION_SAVE), 0); + PendingIntent savePendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(GameService.ACTION_SAVE), 0); builder.addAction(R.drawable.ic_save, saveString, savePendingIntent); return this; } public NotificationBuilder addPauseButton() { - PendingIntent pausePendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(Actions.ACTION_PAUSE), 0); + PendingIntent pausePendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(GameService.ACTION_PAUSE), 0); builder.addAction(R.drawable.ic_pause, pauseString, pausePendingIntent); return this; } public NotificationBuilder addUnPauseButton() { - PendingIntent unPausePendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(Actions.ACTION_UNPAUSE), 0); + PendingIntent unPausePendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(GameService.ACTION_UNPAUSE), 0); builder.addAction(R.drawable.ic_play, unpauseString, unPausePendingIntent); return this; } diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/core/events/DrawEvents.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/events/DrawEvents.java new file mode 100644 index 0000000000..33e8d8e7ce --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/events/DrawEvents.java @@ -0,0 +1,38 @@ +package jsettlers.main.android.core.events; + +/** + * Created by Tom Pratt on 30/09/2017. + */ + + +import android.arch.lifecycle.LiveData; + +import jsettlers.main.android.core.controls.DrawControls; +import jsettlers.main.android.core.controls.DrawListener; + + +public class DrawEvents extends LiveData implements DrawListener { + private final DrawControls drawControls; + + public DrawEvents(DrawControls drawControls) { + this.drawControls = drawControls; + setValue(null); + } + + @Override + protected void onActive() { + super.onActive(); + drawControls.addInfrequentDrawListener(this); + } + + @Override + protected void onInactive() { + super.onInactive(); + drawControls.removeInfrequentDrawListener(this); + } + + @Override + public void draw() { + postValue(null); + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/core/events/SingleLiveEvent.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/events/SingleLiveEvent.java new file mode 100644 index 0000000000..2d5dadf188 --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/events/SingleLiveEvent.java @@ -0,0 +1,75 @@ +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jsettlers.main.android.core.events; + +import android.arch.lifecycle.LifecycleOwner; +import android.arch.lifecycle.MutableLiveData; +import android.arch.lifecycle.Observer; +import android.support.annotation.MainThread; +import android.support.annotation.Nullable; +import android.util.Log; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * A lifecycle-aware observable that sends only new updates after subscription, used for events like + * navigation and Snackbar messages. + *

+ * This avoids a common problem with events: on configuration change (like rotation) an update + * can be emitted if the observer is active. This LiveData only calls the observable if there's an + * explicit call to setValue() or call(). + *

+ * Note that only one observer is going to be notified of changes. + */ +public class SingleLiveEvent extends MutableLiveData { + + private static final String TAG = "SingleLiveEvent"; + + private final AtomicBoolean mPending = new AtomicBoolean(false); + + @MainThread + public void observe(LifecycleOwner owner, final Observer observer) { + + if (hasActiveObservers()) { + Log.w(TAG, "Multiple observers registered but only one will be notified of changes."); + } + + // Observe the internal MutableLiveData + super.observe(owner, new Observer() { + @Override + public void onChanged(@Nullable T t) { + if (mPending.compareAndSet(true, false)) { + observer.onChanged(t); + } + } + }); + } + + @MainThread + public void setValue(@Nullable T t) { + mPending.set(true); + super.setValue(t); + } + + /** + * Used for cases where T is Void, to make calls cleaner. + */ + @MainThread + public void call() { + setValue(null); + } +} \ No newline at end of file diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ImageLinkFactory.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/resources/ImageLinkFactory.java similarity index 98% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ImageLinkFactory.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/core/resources/ImageLinkFactory.java index 4fb1798c9c..dabadca59b 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ImageLinkFactory.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/resources/ImageLinkFactory.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay; +package jsettlers.main.android.core.resources; import jsettlers.common.images.EImageLinkType; import jsettlers.common.images.ImageLink; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/utils/OriginalImageProvider.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/resources/OriginalImageProvider.java similarity index 99% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/utils/OriginalImageProvider.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/core/resources/OriginalImageProvider.java index bd94f55ede..6cc3f87537 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/utils/OriginalImageProvider.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/resources/OriginalImageProvider.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.utils; +package jsettlers.main.android.core.resources; import static java8.util.stream.StreamSupport.stream; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/core/ui/PreviewImageConverter.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/resources/PreviewImageConverter.java similarity index 98% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/core/ui/PreviewImageConverter.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/core/resources/PreviewImageConverter.java index 3b7e27f731..3cf2da53cd 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/core/ui/PreviewImageConverter.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/resources/PreviewImageConverter.java @@ -12,7 +12,7 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.core.ui; +package jsettlers.main.android.core.resources; import jsettlers.common.Color; import jsettlers.logic.map.loading.newmap.MapFileHeader; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/core/resources/scanner/AndroidResourcesLoader.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/resources/scanner/AndroidResourcesLoader.java index be9c3e6866..01533d3ddf 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/core/resources/scanner/AndroidResourcesLoader.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/core/resources/scanner/AndroidResourcesLoader.java @@ -15,10 +15,16 @@ package jsettlers.main.android.core.resources.scanner; +import java.io.File; + +import org.androidannotations.annotations.EBean; + import android.content.Context; import android.content.SharedPreferences; import android.os.Environment; import android.preference.PreferenceManager; + +import io.reactivex.Completable; import jsettlers.common.resources.ResourceManager; import jsettlers.common.resources.SettlersFolderChecker; import jsettlers.common.resources.SettlersFolderChecker.SettlersFolderInfo; @@ -28,9 +34,6 @@ import jsettlers.logic.map.loading.list.MapList; import jsettlers.main.android.core.resources.AndroidMapListFactory; import jsettlers.main.android.core.resources.AndroidResourceProvider; -import org.androidannotations.annotations.EBean; - -import java.io.File; @EBean public class AndroidResourcesLoader { @@ -69,6 +72,18 @@ public boolean setup() { return true; } + public Completable setupSingle() { + return Completable.create(emitter -> { + boolean success = setup(); + + if (success) { + emitter.onComplete(); + } else { + emitter.onError(new Exception("Not a valid settlers folder")); + } + }); + } + public void setResourcesDirectory(String path) { PreferenceManager.getDefaultSharedPreferences(context).edit().putString(ORIGINAL_SETTLERS_FILES_PATH_SETTING_KEY, path).apply(); } diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/activities/FullScreenAppCompatActivity.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/FullScreenAppCompatActivity.java similarity index 96% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/activities/FullScreenAppCompatActivity.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/FullScreenAppCompatActivity.java index ef865bad64..19709dd01a 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/activities/FullScreenAppCompatActivity.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/FullScreenAppCompatActivity.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.activities; +package jsettlers.main.android.gameplay; import android.support.v7.app.AppCompatActivity; import android.view.View; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/activities/GameActivity.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/GameActivity.java similarity index 88% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/activities/GameActivity.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/GameActivity.java index bf160718c3..388b5a062d 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/activities/GameActivity.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/GameActivity.java @@ -13,14 +13,14 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.activities; +package jsettlers.main.android.gameplay; -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_QUIT_CONFIRM; - -import java.util.List; +import android.os.Bundle; +import android.support.v4.app.Fragment; import org.androidannotations.annotations.EActivity; -import org.androidannotations.annotations.Receiver; + +import java.util.List; import jsettlers.main.android.R; import jsettlers.main.android.core.GameStarter; @@ -28,13 +28,8 @@ import jsettlers.main.android.gameplay.navigation.GameNavigator; import jsettlers.main.android.gameplay.navigation.MenuNavigator; import jsettlers.main.android.gameplay.navigation.MenuNavigatorProvider; -import jsettlers.main.android.gameplay.ui.fragments.LoadingFragment; -import jsettlers.main.android.gameplay.ui.fragments.MapFragment_; import jsettlers.main.android.mainmenu.navigation.Actions; -import android.os.Bundle; -import android.support.v4.app.Fragment; - @EActivity(R.layout.activity_game) public class GameActivity extends FullScreenAppCompatActivity implements GameNavigator, MenuNavigatorProvider { private static final String TAG_FRAGMENT_MAP = "map_fragment"; @@ -104,9 +99,4 @@ private void showLoading() { .add(R.id.frame_layout, LoadingFragment.newInstance(), TAG_FRAGMENT_LOADING) .commitNow(); } - - @Receiver(actions = ACTION_QUIT_CONFIRM, local = true) - void onActionQuitConfirm() { - finish(); - } } diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/LoadingFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/LoadingFragment.java similarity index 98% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/LoadingFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/LoadingFragment.java index 7b6e3c0d1c..93d30b6b68 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/LoadingFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/LoadingFragment.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments; +package jsettlers.main.android.gameplay; import jsettlers.graphics.map.draw.ImageProvider; import org.androidannotations.annotations.EFragment; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/MapFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/MapFragment.java similarity index 89% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/MapFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/MapFragment.java index f5459edf8b..a3a2d5d1d8 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/MapFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/MapFragment.java @@ -13,8 +13,9 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments; +package jsettlers.main.android.gameplay; +import android.arch.lifecycle.Observer; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.BottomSheetBehavior; @@ -30,7 +31,6 @@ import org.androidannotations.annotations.EFragment; import org.androidannotations.annotations.OptionsItem; import org.androidannotations.annotations.OptionsMenu; -import org.androidannotations.annotations.Receiver; import org.androidannotations.annotations.ViewById; import java.util.LinkedList; @@ -57,19 +57,16 @@ import jsettlers.main.android.core.ui.dialogs.ConfirmDialog; import jsettlers.main.android.core.ui.dialogs.ConfirmDialog_; import jsettlers.main.android.gameplay.navigation.MenuNavigator; -import jsettlers.main.android.gameplay.ui.dialogs.PausedDialog; -import jsettlers.main.android.gameplay.ui.fragments.menus.buildings.BuildingsMenuFragment; -import jsettlers.main.android.gameplay.ui.fragments.menus.goods.GoodsMenuFragment; -import jsettlers.main.android.gameplay.ui.fragments.menus.selection.BuildingSelectionFragment; -import jsettlers.main.android.gameplay.ui.fragments.menus.selection.CarriersSelectionFragment; -import jsettlers.main.android.gameplay.ui.fragments.menus.selection.ShipsSelectionFragment; -import jsettlers.main.android.gameplay.ui.fragments.menus.selection.SoldiersSelectionFragment; -import jsettlers.main.android.gameplay.ui.fragments.menus.selection.SpecialistsSelectionFragment; -import jsettlers.main.android.gameplay.ui.fragments.menus.settlers.SettlersMenuFragment; -import jsettlers.main.android.mainmenu.ui.activities.MainActivity_; - -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_PAUSE; -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_UNPAUSE; +import jsettlers.main.android.gameplay.gamemenu.PausedDialog; +import jsettlers.main.android.gameplay.controlsmenu.buildings.BuildingsMenuFragment; +import jsettlers.main.android.gameplay.controlsmenu.goods.GoodsMenuFragment; +import jsettlers.main.android.gameplay.controlsmenu.selection.BuildingSelectionFragment; +import jsettlers.main.android.gameplay.controlsmenu.selection.CarriersSelectionFragment; +import jsettlers.main.android.gameplay.controlsmenu.selection.ShipsSelectionFragment; +import jsettlers.main.android.gameplay.controlsmenu.selection.SoldiersSelectionFragment; +import jsettlers.main.android.gameplay.controlsmenu.selection.SpecialistsSelectionFragment; +import jsettlers.main.android.gameplay.controlsmenu.settlers.SettlersMenuFragment; +import jsettlers.main.android.mainmenu.MainActivity_; @EFragment(R.layout.fragment_map) @OptionsMenu(R.menu.game) @@ -120,6 +117,12 @@ void setupControls() { addMapViews(controlsResolver.getMapContent()); } + @AfterViews + void registerObservers() { + gameMenu.isPausedState().observe(this, pauseObserver); + gameMenu.getGameState().observeForever(gameStateObserver); + } + private void addMapViews(MapContent mapContent) { Region goRegion = new Region(Region.POSITION_CENTER); goRegion.setContent(mapContent); @@ -144,10 +147,7 @@ public void onActivityCreated(@Nullable Bundle savedInstanceState) { @Override public void onResume() { super.onResume(); - if (gameMenu.isPaused()) { - showPausedMenu(); - } else { - dismissPausedMenu(); + if (gameMenu.isPausedState().getValue() == Boolean.FALSE) { gameMenu.unMute(); } } @@ -170,6 +170,12 @@ public void onStop() { selectionControls.removeSelectionListener(this); } + @Override + public void onDestroy() { + super.onDestroy(); + gameMenu.getGameState().removeObserver(gameStateObserver); + } + @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -416,14 +422,19 @@ void skipOneMinuteClicked() { actionControls.fireAction(new Action(EActionType.FAST_FORWARD)); } - @Receiver(actions = ACTION_PAUSE, local = true, registerAt = Receiver.RegisterAt.OnResumeOnPause) - void pauseGameReceived() { - showPausedMenu(); - } - @Receiver(actions = ACTION_UNPAUSE, local = true, registerAt = Receiver.RegisterAt.OnStartOnStop) - void unPauseGameReceived() { - gameMenu.unMute(); - dismissPausedMenu(); - } + private Observer pauseObserver = paused -> { + if (paused) { + showPausedMenu(); + } else { + dismissPausedMenu(); + gameMenu.unMute(); + } + }; + + private Observer gameStateObserver = gameState -> { + if (gameState == GameMenu.GameState.QUITTED) { + getActivity().finish(); + } + }; } diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/viewstates/BuildingState.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/buildings/BuildingViewState.java similarity index 88% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/viewstates/BuildingState.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/buildings/BuildingViewState.java index dc0c3d2c9a..b72c42f916 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/viewstates/BuildingState.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/buildings/BuildingViewState.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.viewstates; +package jsettlers.main.android.gameplay.controlsmenu.buildings; import jsettlers.common.buildings.EBuildingType; import jsettlers.common.map.partition.IBuildingCounts; @@ -23,14 +23,14 @@ * Created by tompr on 29/05/2017. */ -public class BuildingState { +public class BuildingViewState { private final EBuildingType buildingType; private final String name; private final String count; private final String constructionCount; - public BuildingState(EBuildingType buildingType, IBuildingCounts buildingCounts) { + public BuildingViewState(EBuildingType buildingType, IBuildingCounts buildingCounts) { this.buildingType = buildingType; this.name = Labels.getName(buildingType); @@ -67,6 +67,6 @@ public String getConstructionCount() { @Override public boolean equals(Object obj) { - return obj instanceof BuildingState && ((BuildingState) obj).getBuildingType() == getBuildingType(); + return obj instanceof BuildingViewState && ((BuildingViewState) obj).getBuildingType() == getBuildingType(); } } diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/buildings/BuildingsCategoryFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/buildings/BuildingsCategoryFragment.java similarity index 53% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/buildings/BuildingsCategoryFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/buildings/BuildingsCategoryFragment.java index 4f2668a648..b4f7f92f95 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/buildings/BuildingsCategoryFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/buildings/BuildingsCategoryFragment.java @@ -13,12 +13,13 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.buildings; +package jsettlers.main.android.gameplay.controlsmenu.buildings; +import android.arch.lifecycle.ViewModelProviders; +import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v7.util.DiffUtil; -import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; @@ -26,10 +27,8 @@ import android.widget.ImageView; import android.widget.TextView; -import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.EFragment; import org.androidannotations.annotations.FragmentArg; -import org.androidannotations.annotations.UiThread; import org.androidannotations.annotations.ViewById; import java.util.List; @@ -37,82 +36,59 @@ import jsettlers.common.buildings.EBuildingType; import jsettlers.graphics.map.controls.original.panel.content.buildings.EBuildingsCategory; import jsettlers.main.android.R; -import jsettlers.main.android.gameplay.viewstates.BuildingState; -import jsettlers.main.android.gameplay.presenters.BuildingsCategoryMenu; -import jsettlers.main.android.gameplay.presenters.MenuFactory; -import jsettlers.main.android.gameplay.ui.views.BuildingsCategoryView; -import jsettlers.main.android.utils.OriginalImageProvider; +import jsettlers.main.android.core.resources.OriginalImageProvider; /** - * Created by tompr on 24/11/2016. + * Created by Tom Pratt on 24/11/2016. */ @EFragment(R.layout.menu_buildings_category) -public class BuildingsCategoryFragment extends Fragment implements BuildingsCategoryView { +public class BuildingsCategoryFragment extends Fragment { private static final String ARG_BUILDINGS_CATEGORY = "arg_buildings_category"; public static BuildingsCategoryFragment newInstance(EBuildingsCategory buildingsCategory) { return BuildingsCategoryFragment_.builder().buildingsCategory(buildingsCategory).build(); } + private BuildingsCategoryViewModel viewModel; + @ViewById(R.id.recycler_view) RecyclerView recyclerView; @FragmentArg(ARG_BUILDINGS_CATEGORY) EBuildingsCategory buildingsCategory; - private BuildingsCategoryMenu buildingsMenu; - private BuildingsAdapter adapter; - - @AfterViews - void afterViews() { - buildingsMenu = new MenuFactory(getActivity()).buildingsMenu(this, buildingsCategory); - buildingsMenu.start(); - } - @Override - public void onDestroyView() { - super.onDestroyView(); - buildingsMenu.finish(); - } + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + viewModel = ViewModelProviders.of(this, new BuildingsCategoryViewModel.Factory(getActivity(), buildingsCategory)).get(BuildingsCategoryViewModel.class); - /** - * BuildingsCategoryView implementation - */ - @UiThread - @Override - public void setBuildings(List buildingStates) { - if (adapter == null) { - adapter = new BuildingsCategoryFragment.BuildingsAdapter(buildingStates); - } else { - adapter.setBuildingStates(buildingStates); - } + BuildingsAdapter adapter = new BuildingsAdapter(); + recyclerView.setHasFixedSize(true); + recyclerView.setAdapter(adapter); - if (recyclerView.getAdapter() == null) { - recyclerView.setHasFixedSize(true); - recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 3)); - recyclerView.setAdapter(adapter); - } + viewModel.getBuildingStates().observe(this, adapter::setBuildingViewStates); } + private void buildingSelected(EBuildingType buildingType) { - buildingsMenu.buildingSelected(buildingType); + viewModel.showConstructionMarkers(buildingType); } /** * Adapter */ private class BuildingsAdapter extends RecyclerView.Adapter { - private List buildingStates; + private final LayoutInflater layoutInflater; - private LayoutInflater layoutInflater; + private BuildingViewState[] buildingViewStates; - BuildingsAdapter(List buildingStates) { - this.buildingStates = buildingStates; - layoutInflater = getActivity().getLayoutInflater(); + BuildingsAdapter() { + this.layoutInflater = getActivity().getLayoutInflater(); + this.buildingViewStates = new BuildingViewState[0]; } @Override public int getItemCount() { - return buildingStates.size(); + return buildingViewStates.length; } @Override @@ -122,7 +98,7 @@ public BuildingsCategoryFragment.BuildingViewHolder onCreateViewHolder(ViewGroup itemView.setOnClickListener(view -> { int position = buildingViewHolder.getLayoutPosition(); - buildingSelected(buildingStates.get(position).getBuildingType()); + buildingSelected(buildingViewStates[position].getBuildingType()); }); return buildingViewHolder; @@ -130,7 +106,7 @@ public BuildingsCategoryFragment.BuildingViewHolder onCreateViewHolder(ViewGroup @Override public void onBindViewHolder(BuildingsCategoryFragment.BuildingViewHolder holder, int position) { - holder.setBuilding(buildingStates.get(position)); + holder.setBuilding(buildingViewStates[position]); } @Override @@ -138,15 +114,15 @@ public void onBindViewHolder(BuildingViewHolder holder, int position, List buildingStates) { - DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new BuildingsDiffCallback(this.buildingStates, buildingStates)); + void setBuildingViewStates(BuildingViewState[] buildingViewStates) { + DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new BuildingsDiffCallback(this.buildingViewStates, buildingViewStates)); diffResult.dispatchUpdatesTo(this); - this.buildingStates = buildingStates; + this.buildingViewStates = buildingViewStates; } } @@ -158,22 +134,22 @@ private class BuildingViewHolder extends RecyclerView.ViewHolder { BuildingViewHolder(View itemView) { super(itemView); - imageView = (ImageView) itemView.findViewById(R.id.image_view); - nameTextView = (TextView) itemView.findViewById(R.id.text_view_building_name); - buildingCountTextView = (TextView) itemView.findViewById(R.id.text_view_building_count); - buildingConstructionCountTextView = (TextView) itemView.findViewById(R.id.text_view_building_construction_count); + imageView = itemView.findViewById(R.id.image_view); + nameTextView = itemView.findViewById(R.id.text_view_building_name); + buildingCountTextView = itemView.findViewById(R.id.text_view_building_count); + buildingConstructionCountTextView = itemView.findViewById(R.id.text_view_building_construction_count); } - void setBuilding(BuildingState buildingState) { - OriginalImageProvider.get(buildingState.getBuildingType()).setAsImage(imageView); - nameTextView.setText(buildingState.getName()); - buildingCountTextView.setText(buildingState.getCount()); - buildingConstructionCountTextView.setText(buildingState.getConstructionCount()); + void setBuilding(BuildingViewState buildingViewState) { + OriginalImageProvider.get(buildingViewState.getBuildingType()).setAsImage(imageView); + nameTextView.setText(buildingViewState.getName()); + buildingCountTextView.setText(buildingViewState.getCount()); + buildingConstructionCountTextView.setText(buildingViewState.getConstructionCount()); } - void updateCounts(BuildingState buildingState) { - buildingCountTextView.setText(buildingState.getCount()); - buildingConstructionCountTextView.setText(buildingState.getConstructionCount()); + void updateCounts(BuildingViewState buildingViewState) { + buildingCountTextView.setText(buildingViewState.getCount()); + buildingConstructionCountTextView.setText(buildingViewState.getConstructionCount()); } } @@ -182,33 +158,35 @@ void updateCounts(BuildingState buildingState) { */ private class BuildingsDiffCallback extends DiffUtil.Callback { - private final List oldBuildingStates; - private final List newBuildingStates; + private final BuildingViewState[] oldBuildingViewStates; + private final BuildingViewState[] newBuildingViewStates; - BuildingsDiffCallback(List oldBuildingStates, List newBuildingStates) { - this.oldBuildingStates = oldBuildingStates; - this.newBuildingStates = newBuildingStates; + BuildingsDiffCallback(BuildingViewState[] oldBuildingViewStates, BuildingViewState[] newBuildingViewStates) { + this.oldBuildingViewStates = oldBuildingViewStates; + this.newBuildingViewStates = newBuildingViewStates; } @Override public int getOldListSize() { - return oldBuildingStates.size(); + return oldBuildingViewStates.length; } @Override public int getNewListSize() { - return newBuildingStates.size(); + return newBuildingViewStates.length; } @Override public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { - return oldBuildingStates.get(oldItemPosition).equals(newBuildingStates.get(newItemPosition)); + return oldBuildingViewStates[oldItemPosition].equals(newBuildingViewStates[newItemPosition]); } @Override public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { - boolean constructedCountsEqual = oldBuildingStates.get(oldItemPosition).getCount().equals(newBuildingStates.get(newItemPosition).getCount()); - boolean constructingCountsEqual = oldBuildingStates.get(oldItemPosition).getConstructionCount().equals(newBuildingStates.get(newItemPosition).getConstructionCount()); + BuildingViewState oldState = oldBuildingViewStates[oldItemPosition]; + BuildingViewState newState = newBuildingViewStates[newItemPosition]; + boolean constructedCountsEqual = oldState.getCount().equals(newState.getCount()); + boolean constructingCountsEqual = oldState.getConstructionCount().equals(newState.getConstructionCount()); return constructedCountsEqual && constructingCountsEqual; } diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/buildings/BuildingsCategoryViewModel.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/buildings/BuildingsCategoryViewModel.java new file mode 100644 index 0000000000..c55af528e9 --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/buildings/BuildingsCategoryViewModel.java @@ -0,0 +1,98 @@ +package jsettlers.main.android.gameplay.controlsmenu.buildings; + +import android.app.Activity; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.Transformations; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProvider; + +import jsettlers.common.action.Action; +import jsettlers.common.action.ShowConstructionMarksAction; +import jsettlers.common.buildings.EBuildingType; +import jsettlers.common.map.partition.IBuildingCounts; +import jsettlers.graphics.map.controls.original.panel.content.buildings.EBuildingsCategory; +import jsettlers.main.android.core.controls.ActionControls; +import jsettlers.main.android.core.controls.ControlsResolver; +import jsettlers.main.android.core.controls.DrawControls; +import jsettlers.main.android.core.controls.PositionControls; +import jsettlers.main.android.core.events.DrawEvents; +import jsettlers.main.android.gameplay.navigation.MenuNavigator; +import jsettlers.main.android.gameplay.navigation.MenuNavigatorProvider; + +import static java8.util.stream.StreamSupport.stream; + +/** + * Created by Tom Pratt on 28/09/2017. + */ + +public class BuildingsCategoryViewModel extends ViewModel { + private final ActionControls actionControls; + private final PositionControls positionControls; + private final MenuNavigator menuNavigator; + private final EBuildingsCategory buildingsCategory; + + private final LiveData buildingStates; + + public BuildingsCategoryViewModel(ActionControls actionControls, DrawControls drawControls, PositionControls positionControls, MenuNavigator menuNavigator, EBuildingsCategory buildingsCategory) { + this.actionControls = actionControls; + this.positionControls = positionControls; + this.menuNavigator = menuNavigator; + this.buildingsCategory = buildingsCategory; + + DrawEvents drawEvents = new DrawEvents(drawControls); + buildingStates = Transformations.map(drawEvents, x -> buildingStates()); + } + + public LiveData getBuildingStates() { + return buildingStates; + } + + public void showConstructionMarkers(EBuildingType buildingType) { + Action action = new ShowConstructionMarksAction(buildingType); + actionControls.fireAction(action); + menuNavigator.dismissMenu(); + } + + private BuildingViewState[] buildingStates() { + final IBuildingCounts buildingCounts; + + if (positionControls.isInPlayerPartition()) { + buildingCounts = positionControls.getCurrentPartitionData().getBuildingCounts(); + } else { + buildingCounts = null; + } + + return stream(buildingsCategory.buildingTypes) + .map(buildingType -> new BuildingViewState(buildingType, buildingCounts)) + .toArray(BuildingViewState[]::new); + } + + + /** + * ViewModel factory + */ + public static class Factory implements ViewModelProvider.Factory { + private final ControlsResolver controlsResolver; + private final MenuNavigator menuNavigator; + private final EBuildingsCategory buildingsCategory; + + public Factory(Activity activity, EBuildingsCategory buildingsCategory) { + this.controlsResolver = new ControlsResolver(activity); + this.menuNavigator = ((MenuNavigatorProvider) activity).getMenuNavigator(); + this.buildingsCategory = buildingsCategory; + } + + @Override + public T create(Class modelClass) { + if (modelClass == BuildingsCategoryViewModel.class) { + return (T) new BuildingsCategoryViewModel( + controlsResolver.getActionControls(), + controlsResolver.getDrawControls(), + controlsResolver.getPositionControls(), + menuNavigator, + buildingsCategory); + } + throw new RuntimeException("BuildingsCategoryViewModel.Factory doesn't know how to create a: " + modelClass.toString()); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/buildings/BuildingsMenuFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/buildings/BuildingsMenuFragment.java similarity index 97% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/buildings/BuildingsMenuFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/buildings/BuildingsMenuFragment.java index d4555e778e..a5683b3e1d 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/buildings/BuildingsMenuFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/buildings/BuildingsMenuFragment.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.buildings; +package jsettlers.main.android.gameplay.controlsmenu.buildings; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/DistributionState.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/DistributionState.java new file mode 100644 index 0000000000..a9d4b75c4f --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/DistributionState.java @@ -0,0 +1,26 @@ +package jsettlers.main.android.gameplay.controlsmenu.goods; + +import jsettlers.common.buildings.EBuildingType; +import jsettlers.common.map.partition.IMaterialDistributionSettings; + +/** + * Created by Tom Pratt on 29/09/2017. + */ + +public class DistributionState { + private final EBuildingType buildingType; + private final float ratio; + + public DistributionState(EBuildingType buildingType, IMaterialDistributionSettings materialDistributionSettings) { + this.buildingType = buildingType; + this.ratio = materialDistributionSettings.getDistributionProbability(buildingType); + } + + public EBuildingType getBuildingType() { + return buildingType; + } + + public float getRatio() { + return ratio; + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/DistributionViewModel.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/DistributionViewModel.java new file mode 100644 index 0000000000..810f421076 --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/DistributionViewModel.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2017 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package jsettlers.main.android.gameplay.controlsmenu.goods; + +import android.app.Activity; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProvider; + +import jsettlers.common.action.SetMaterialDistributionSettingsAction; +import jsettlers.common.buildings.EBuildingType; +import jsettlers.common.buildings.MaterialsOfBuildings; +import jsettlers.common.map.partition.IMaterialDistributionSettings; +import jsettlers.common.material.EMaterialType; +import jsettlers.main.android.core.controls.ActionControls; +import jsettlers.main.android.core.controls.ControlsResolver; +import jsettlers.main.android.core.controls.PositionControls; + +import static java8.util.J8Arrays.stream; + +/** + * Created by Tom Pratt on 29/09/2017. + */ + +public class DistributionViewModel extends ViewModel { + private static final EMaterialType[] MATERIAL_TYPES_FOR_DISTRIBUTION = new EMaterialType[] { + EMaterialType.COAL, + EMaterialType.IRON, + EMaterialType.PLANK, + EMaterialType.CROP, + EMaterialType.WATER, + EMaterialType.BREAD, + EMaterialType.MEAT, + EMaterialType.FISH + }; + + private final PositionControls positionControls; + private final ActionControls actionControls; + + public DistributionViewModel(PositionControls positionControls, ActionControls actionControls) { + this.positionControls = positionControls; + this.actionControls = actionControls; + } + + public EMaterialType[] getDistributionMaterials() { + return MATERIAL_TYPES_FOR_DISTRIBUTION; + } + + public DistributionState[] getDistributionStates(EMaterialType materialType) { + IMaterialDistributionSettings materialDistributionSettings = positionControls.getCurrentPartitionData().getPartitionSettings().getDistributionSettings(materialType); + EBuildingType[] buildingsForMaterial = MaterialsOfBuildings.getBuildingTypesRequestingMaterial(materialType); + + return stream(buildingsForMaterial) + .map(buildingType -> new DistributionState(buildingType, materialDistributionSettings)) + .toArray(DistributionState[]::new); + } + + public void setDistributionRatio(EMaterialType materialType, EBuildingType buildingType, float ratio) { + actionControls.fireAction(new SetMaterialDistributionSettingsAction(positionControls.getCurrentPosition(), materialType, buildingType, ratio)); + } + + /** + * ViewModel factory + */ + public static class Factory implements ViewModelProvider.Factory { + private final ControlsResolver controlsResolver; + + public Factory(Activity activity) { + this.controlsResolver = new ControlsResolver(activity); + } + + @Override + public T create(Class modelClass) { + if (modelClass == DistributionViewModel.class) { + return (T) new DistributionViewModel( + controlsResolver.getPositionControls(), + controlsResolver.getActionControls()); + } + throw new RuntimeException("DistributionViewModel.Factory doesn't know how to create a: " + modelClass.toString()); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsDistributionFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsDistributionFragment.java new file mode 100644 index 0000000000..6bdb5907f2 --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsDistributionFragment.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2017 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package jsettlers.main.android.gameplay.controlsmenu.goods; + +import android.app.Activity; +import android.arch.lifecycle.ViewModelProviders; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.PopupWindow; +import android.widget.SeekBar; + +import org.androidannotations.annotations.EFragment; +import org.androidannotations.annotations.ViewById; + +import jsettlers.common.material.EMaterialType; +import jsettlers.main.android.R; +import jsettlers.main.android.core.navigation.BackPressedListener; +import jsettlers.main.android.gameplay.navigation.MenuNavigator; +import jsettlers.main.android.gameplay.navigation.MenuNavigatorProvider; +import jsettlers.main.android.core.resources.OriginalImageProvider; + +/** + * Created by tompr on 24/11/2016. + */ + +@EFragment(R.layout.menu_goods_distribution) +public class GoodsDistributionFragment extends Fragment implements BackPressedListener { + public static GoodsDistributionFragment newInstance() { + return new GoodsDistributionFragment_(); + } + + private DistributionViewModel viewModel; + private MenuNavigator menuNavigator; + + private PopupWindow popupWindow; + + @ViewById(R.id.recyclerView) + RecyclerView recyclerView; + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + viewModel = ViewModelProviders.of(this, new DistributionViewModel.Factory(getActivity())).get(DistributionViewModel.class); + menuNavigator = ((MenuNavigatorProvider) getActivity()).getMenuNavigator(); + + MaterialsAdapter materialsAdapter = new MaterialsAdapter(getActivity(), viewModel.getDistributionMaterials()); + recyclerView.setHasFixedSize(true); + recyclerView.setAdapter(materialsAdapter); + } + + @Override + public void onStart() { + super.onStart(); + menuNavigator.addBackPressedListener(this); + } + + @Override + public void onStop() { + super.onStop(); + menuNavigator.removeBackPressedListener(this); + } + + @Override + public boolean onBackPressed() { + if (popupWindow != null && popupWindow.isShowing()) { + popupWindow.dismiss(); + return true; + } + return false; + } + + void showDistributionPopup(View anchor, EMaterialType materialType) { + DistributionState[] distributionStates = viewModel.getDistributionStates(materialType); + LayoutInflater layoutInflater = getLayoutInflater(); + + View popupView = layoutInflater.inflate(R.layout.popup_empty, null); + LinearLayout container = popupView.findViewById(R.id.container); + + for (DistributionState distributionState : distributionStates) { + View view = layoutInflater.inflate(R.layout.vh_distribution_building, container, false); + ImageView imageView = view.findViewById(R.id.imageView_building); + SeekBar seekBar = view.findViewById(R.id.seekBar); + + OriginalImageProvider.get(distributionState.getBuildingType()).setAsImage(imageView); + seekBar.setProgress(Math.round(distributionState.getRatio() * seekBar.getMax())); + + seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int i, boolean b) {} + + @Override + public void onStartTrackingTouch(SeekBar seekBar) {} + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + viewModel.setDistributionRatio(materialType, distributionState.getBuildingType (), (float)seekBar.getProgress() / seekBar.getMax()); + } + }); + + container.addView(view); + } + + popupView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); + int xOffset = -((popupView.getMeasuredWidth() - anchor.getWidth()) / 2); + int yOffset = -(popupView.getMeasuredHeight() + anchor.getHeight()); + + popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, false); + popupWindow.setOutsideTouchable(true); + popupWindow.showAsDropDown(anchor, xOffset, yOffset); + } + + /** + * Adapter + */ + private class MaterialsAdapter extends RecyclerView.Adapter { + + private final LayoutInflater inflater; + + private EMaterialType[] materialTypes; + + public MaterialsAdapter(Activity activity, EMaterialType[] materialTypes) { + inflater = LayoutInflater.from(activity); + this.materialTypes = materialTypes; + } + + @Override + public int getItemCount() { + return materialTypes.length; + } + + @Override + public MaterialViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = inflater.inflate(R.layout.vh_distribution_material, parent, false); + MaterialViewHolder viewHolder = new MaterialViewHolder(view); + + view.setOnClickListener(view1 -> showDistributionPopup(view1, materialTypes[viewHolder.getAdapterPosition()])); + + return viewHolder; + } + + @Override + public void onBindViewHolder(MaterialViewHolder holder, int position) { + EMaterialType materialType = materialTypes[position]; + holder.bind(materialType); + } + } + + /** + * ViewHolder + */ + private class MaterialViewHolder extends RecyclerView.ViewHolder { + private final ImageView imageView; + + MaterialViewHolder(View itemView) { + super(itemView); + imageView = itemView.findViewById(R.id.imageView_material); + } + + void bind(EMaterialType materialType) { + OriginalImageProvider.get(materialType).setAsImage(imageView); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsInventoryFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsInventoryFragment.java new file mode 100644 index 0000000000..b0cbfc8e4c --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsInventoryFragment.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2017 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package jsettlers.main.android.gameplay.controlsmenu.goods; + +import android.app.Activity; +import android.arch.lifecycle.ViewModelProviders; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v7.util.DiffUtil; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import org.androidannotations.annotations.EFragment; +import org.androidannotations.annotations.ViewById; + +import java.util.List; + +import jsettlers.main.android.R; +import jsettlers.main.android.core.resources.OriginalImageProvider; + +/** + * Created by Tom Pratt on 24/11/2016. + */ +@EFragment(R.layout.menu_goods_inventory) +public class GoodsInventoryFragment extends Fragment { + public static GoodsInventoryFragment newInstance() { + return new GoodsInventoryFragment_(); + } + + private InventoryViewModel viewModel; + + @ViewById(R.id.recyclerView) + RecyclerView recyclerView; + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + viewModel = ViewModelProviders.of(this, new InventoryViewModel.Factory(getActivity())).get(InventoryViewModel.class); + + InventoryMaterialsAdapter inventoryMaterialsAdapter = new InventoryMaterialsAdapter(getActivity()); + recyclerView.setHasFixedSize(true); + recyclerView.setAdapter(inventoryMaterialsAdapter); + + viewModel.getMaterialStates().observe(this, inventoryMaterialsAdapter::setInventoryMaterialStates); + } + + /** + * Adapter + */ + private class InventoryMaterialsAdapter extends RecyclerView.Adapter { + + private final LayoutInflater inflater; + + private InventoryMaterialState[] inventoryMaterialStates; + + public InventoryMaterialsAdapter(Activity activity) { + inflater = LayoutInflater.from(activity); + inventoryMaterialStates = new InventoryMaterialState[0]; + } + + @Override + public int getItemCount() { + return inventoryMaterialStates.length; + } + + @Override + public InventoryMaterialViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = inflater.inflate(R.layout.vh_inventory_material, parent, false); + return new InventoryMaterialViewHolder(view); + } + + @Override + public void onBindViewHolder(InventoryMaterialViewHolder holder, int position) { + InventoryMaterialState inventoryMaterialState = inventoryMaterialStates[position]; + holder.bind(inventoryMaterialState); + } + + @Override + public void onBindViewHolder(InventoryMaterialViewHolder holder, int position, List payloads) { + if (payloads == null || payloads.size() == 0) { + onBindViewHolder(holder, position); + } else { + holder.updateState(inventoryMaterialStates[position]); + } + } + + public void setInventoryMaterialStates(InventoryMaterialState[] inventoryMaterialStates) { + DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new InventoryMaterialsDiffCallback(this.inventoryMaterialStates, inventoryMaterialStates)); + diffResult.dispatchUpdatesTo(this); + this.inventoryMaterialStates = inventoryMaterialStates; + } + + + /** + * Diff callback + */ + private class InventoryMaterialsDiffCallback extends DiffUtil.Callback { + + private final InventoryMaterialState[] oldStates; + private final InventoryMaterialState[] newStates; + + InventoryMaterialsDiffCallback(InventoryMaterialState[] oldStates, InventoryMaterialState[] newStates) { + this.oldStates = oldStates; + this.newStates = newStates; + } + + @Override + public int getOldListSize() { + return oldStates.length; + } + + @Override + public int getNewListSize() { + return newStates.length; + } + + @Override + public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { + return oldStates[oldItemPosition].getMaterialType() == newStates[newItemPosition].getMaterialType(); + } + + @Override + public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { + return oldStates[oldItemPosition].getCount() == newStates[newItemPosition].getCount(); + } + + @Nullable + @Override + public Object getChangePayload(int oldItemPosition, int newItemPosition) { + return Boolean.TRUE; + } + } + } + + /** + * ViewHolder + */ + private class InventoryMaterialViewHolder extends RecyclerView.ViewHolder { + private final ImageView imageView; + private final TextView textView; + + InventoryMaterialViewHolder(View itemView) { + super(itemView); + imageView = itemView.findViewById(R.id.imageView_material); + textView = itemView.findViewById(R.id.textView_count); + } + + void bind(InventoryMaterialState inventoryMaterialState) { + OriginalImageProvider.get(inventoryMaterialState.getMaterialType()).setAsImage(imageView); + updateState(inventoryMaterialState); + } + + void updateState(InventoryMaterialState inventoryMaterialState) { + textView.setText(inventoryMaterialState.getCount() + ""); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsMenuFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsMenuFragment.java similarity index 96% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsMenuFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsMenuFragment.java index 9a92840f01..ac72e9d3c4 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsMenuFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsMenuFragment.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.goods; +package jsettlers.main.android.gameplay.controlsmenu.goods; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; @@ -67,7 +67,7 @@ public int getCount() { public Fragment getItem(int position) { switch (position) { case 0: - return GoodsQuantitiesFragment.newInstance(); + return GoodsInventoryFragment.newInstance(); case 1: return GoodsProductionFragment.newInstance(); case 2: diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsPrioritiesFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsPrioritiesFragment.java similarity index 95% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsPrioritiesFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsPrioritiesFragment.java index 47eebc49fe..92a3c3accc 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsPrioritiesFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsPrioritiesFragment.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.goods; +package jsettlers.main.android.gameplay.controlsmenu.goods; import jsettlers.main.android.R; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsProductionFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsProductionFragment.java new file mode 100644 index 0000000000..34a96fe318 --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsProductionFragment.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2017 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package jsettlers.main.android.gameplay.controlsmenu.goods; + +import android.app.Activity; +import android.arch.lifecycle.ViewModelProviders; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v7.util.DiffUtil; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.SeekBar; +import android.widget.TextView; + +import org.androidannotations.annotations.EFragment; +import org.androidannotations.annotations.ViewById; + +import java.util.List; + +import jsettlers.common.material.EMaterialType; +import jsettlers.main.android.R; +import jsettlers.main.android.core.resources.OriginalImageProvider; + +/** + * Created by tompr on 24/11/2016. + */ +@EFragment(R.layout.menu_goods_production) +public class GoodsProductionFragment extends Fragment { + public static GoodsProductionFragment newInstance() { + return new GoodsProductionFragment_(); + } + + private ProductionViewModel viewModel; + + @ViewById(R.id.recyclerView) + RecyclerView recyclerView; + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + viewModel = ViewModelProviders.of(this, new ProductionViewModel.Factory(getActivity())).get(ProductionViewModel.class); + + ProductionAdapter productionAdapter = new ProductionAdapter(getActivity()); + recyclerView.setHasFixedSize(true); + recyclerView.setAdapter(productionAdapter); + + viewModel.getProductionStates().observe(this, productionAdapter::updateProductionStates); + } + + + /** + * RecyclerView adapter + */ + private class ProductionAdapter extends RecyclerView.Adapter { + + private final LayoutInflater layoutInflater; + + private ProductionState[] productionStates; + + ProductionAdapter(Activity activity) { + this.layoutInflater = LayoutInflater.from(activity); + this.productionStates = new ProductionState[0]; + } + + @Override + public int getItemCount() { + return productionStates.length; + } + + @Override + public ProductionItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = layoutInflater.inflate(R.layout.vh_production_material, parent, false); + return new ProductionItemViewHolder(view); + } + + @Override + public void onBindViewHolder(ProductionItemViewHolder holder, int position) { + ProductionState productionState = productionStates[position]; + holder.bind(productionState); + } + + @Override + public void onBindViewHolder(ProductionItemViewHolder holder, int position, List payloads) { + if (payloads == null || payloads.size() == 0) { + onBindViewHolder(holder, position); + } else { + holder.update(productionStates[position]); + } + } + + void updateProductionStates(ProductionState[] productionStates) { + DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffCallback(this.productionStates, productionStates)); + diffResult.dispatchUpdatesTo(this); + this.productionStates = productionStates; + } + + /** + * Diff callback + */ + private class DiffCallback extends DiffUtil.Callback { + + private final ProductionState[] oldStates; + private final ProductionState[] newStates; + + DiffCallback(ProductionState[] oldStates, ProductionState[] newStates) { + this.oldStates = oldStates; + this.newStates = newStates; + } + + @Override + public int getOldListSize() { + return oldStates.length; + } + + @Override + public int getNewListSize() { + return newStates.length; + } + + @Override + public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { + return oldStates[oldItemPosition].getMaterialType() == newStates[newItemPosition].getMaterialType(); + } + + @Override + public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { + return oldStates[oldItemPosition].getQuantity() == newStates[newItemPosition].getQuantity() + && oldStates[oldItemPosition].getRatio() == newStates[newItemPosition].getRatio(); + } + + @Nullable + @Override + public Object getChangePayload(int oldItemPosition, int newItemPosition) { + return Boolean.TRUE; + } + } + } + + + /** + * RecyclerView ViewHolder + */ + private class ProductionItemViewHolder extends RecyclerView.ViewHolder implements SeekBar.OnSeekBarChangeListener { + + private final ImageView imageView; + private final SeekBar seekBar; + private final TextView quantityTextView; + private final TextView incrementTextView; + private final TextView decrementTextView; + + private EMaterialType materialType; + + ProductionItemViewHolder(View itemView) { + super(itemView); + imageView = itemView.findViewById(R.id.imageView_material); + seekBar = itemView.findViewById(R.id.seekBar); + quantityTextView = itemView.findViewById(R.id.textView_quantity); + incrementTextView = itemView.findViewById(R.id.textView_increment); + decrementTextView = itemView.findViewById(R.id.textView_decrement); + + incrementTextView.setOnClickListener(view -> viewModel.increment(materialType)); + decrementTextView.setOnClickListener(view -> viewModel.decrement(materialType)); + seekBar.setOnSeekBarChangeListener(this); + } + + @Override + public void onProgressChanged(SeekBar seekBar, int i, boolean b) {} + + @Override + public void onStartTrackingTouch(SeekBar seekBar) {} + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + viewModel.setProductionRatio(materialType, (float)seekBar.getProgress() / seekBar.getMax()); + } + + void bind(ProductionState productionState) { + materialType = productionState.getMaterialType(); + OriginalImageProvider.get(productionState.getMaterialType()).setAsImage(imageView); + update(productionState); + } + + void update(ProductionState productionState) { + quantityTextView.setText(productionState.getQuantity() + ""); + seekBar.setProgress(Math.round(productionState.getRatio() * seekBar.getMax())); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsStockFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsStockFragment.java similarity index 95% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsStockFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsStockFragment.java index 1193500b83..1579e6fc93 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsStockFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/GoodsStockFragment.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.goods; +package jsettlers.main.android.gameplay.controlsmenu.goods; import android.os.Bundle; import android.support.annotation.Nullable; @@ -37,8 +37,6 @@ import jsettlers.main.android.core.controls.DrawControls; import jsettlers.main.android.core.controls.DrawListener; import jsettlers.main.android.core.controls.PositionControls; -import jsettlers.main.android.gameplay.ui.adapters.MaterialsAdapter; -import jsettlers.main.android.gameplay.viewstates.StockMaterialState; import static java8.util.J8Arrays.stream; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/views/SettlersSoldiersView.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/InventoryMaterialState.java similarity index 65% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/views/SettlersSoldiersView.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/InventoryMaterialState.java index 67517a47ad..b88ad306c1 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/views/SettlersSoldiersView.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/InventoryMaterialState.java @@ -13,27 +13,29 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.views; +package jsettlers.main.android.gameplay.controlsmenu.goods; -import jsettlers.common.images.ImageLink; +import jsettlers.common.map.partition.IPartitionData; +import jsettlers.common.material.EMaterialType; /** - * Created by tompr on 10/03/2017. + * Created by tompr on 28/09/2017. */ -public interface SettlersSoldiersView { - void setStrengthText(String strengthText); - void setPromotionText(String promotionText); +public class InventoryMaterialState { + private final EMaterialType materialType; + private int count; - void setSwordsmenPromotionEnabled(boolean enabled); + public InventoryMaterialState(EMaterialType materialType, IPartitionData partitionData) { + this.materialType = materialType; + this.count = partitionData.getAmountOf(materialType); + } - void setBowmenPromotionEnabled(boolean enabled); + public EMaterialType getMaterialType() { + return materialType; + } - void setPikemenPromotionEnabled(boolean enabled); - - void setSwordsmenImage(ImageLink imageLink); - - void setBowmenImage(ImageLink imageLink); - - void setPikemenImage(ImageLink imageLink); -} + public int getCount() { + return count; + } +} \ No newline at end of file diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/InventoryViewModel.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/InventoryViewModel.java new file mode 100644 index 0000000000..27cd264b3a --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/InventoryViewModel.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package jsettlers.main.android.gameplay.controlsmenu.goods; + +import android.app.Activity; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.Transformations; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProvider; + +import jsettlers.common.map.partition.IPartitionData; +import jsettlers.common.material.EMaterialType; +import jsettlers.main.android.core.controls.ControlsResolver; +import jsettlers.main.android.core.controls.DrawControls; +import jsettlers.main.android.core.controls.PositionControls; +import jsettlers.main.android.core.events.DrawEvents; + +import static java8.util.J8Arrays.stream; + +/** + * Created by Tom Pratt on 27/09/2017. + */ + +public class InventoryViewModel extends ViewModel { + private final EMaterialType[] inventoryMaterials = EMaterialType.STOCK_MATERIALS; + + private final PositionControls positionControls; + + private final LiveData inventoryMaterialStatesData; + + public InventoryViewModel(DrawControls drawControls, PositionControls positionControls) { + this.positionControls = positionControls; + + DrawEvents drawEvents = new DrawEvents(drawControls); + inventoryMaterialStatesData = Transformations.map(drawEvents, x -> productionStates()); + } + + public LiveData getMaterialStates() { + return inventoryMaterialStatesData; + } + + private InventoryMaterialState[] productionStates() { + IPartitionData partitionData = positionControls.getCurrentPartitionData(); + + return stream(inventoryMaterials) + .map(materialType -> new InventoryMaterialState(materialType, partitionData)) + .toArray(InventoryMaterialState[]::new); + } + + /** + * ViewModel factory + */ + public static class Factory implements ViewModelProvider.Factory { + private final ControlsResolver controlsResolver; + + public Factory(Activity activity) { + this.controlsResolver = new ControlsResolver(activity); + } + + @Override + public T create(Class modelClass) { + if (modelClass == InventoryViewModel.class) { + return (T) new InventoryViewModel( + controlsResolver.getDrawControls(), + controlsResolver.getPositionControls()); + } + throw new RuntimeException("InventoryViewModel.Factory doesn't know how to create a: " + modelClass.toString()); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/viewholders/MaterialViewHolder.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/MaterialViewHolder.java similarity index 91% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/viewholders/MaterialViewHolder.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/MaterialViewHolder.java index 65ed951c1d..cd286d340e 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/viewholders/MaterialViewHolder.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/MaterialViewHolder.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.viewholders; +package jsettlers.main.android.gameplay.controlsmenu.goods; /** * Created by Tom Pratt on 12/07/2017. @@ -25,8 +25,7 @@ import android.widget.ImageView; import jsettlers.main.android.R; -import jsettlers.main.android.gameplay.viewstates.StockMaterialState; -import jsettlers.main.android.utils.OriginalImageProvider; +import jsettlers.main.android.core.resources.OriginalImageProvider; public class MaterialViewHolder extends RecyclerView.ViewHolder { diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/adapters/MaterialsAdapter.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/MaterialsAdapter.java similarity index 95% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/adapters/MaterialsAdapter.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/MaterialsAdapter.java index 024c091a0d..8e55fbcdcd 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/adapters/MaterialsAdapter.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/MaterialsAdapter.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.adapters; +package jsettlers.main.android.gameplay.controlsmenu.goods; /** * Created by Tom Pratt on 12/07/2017. @@ -30,8 +30,6 @@ import java.util.List; import jsettlers.main.android.R; -import jsettlers.main.android.gameplay.ui.viewholders.MaterialViewHolder; -import jsettlers.main.android.gameplay.viewstates.StockMaterialState; public class MaterialsAdapter extends RecyclerView.Adapter { diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/ProductionState.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/ProductionState.java new file mode 100644 index 0000000000..12e39fec33 --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/ProductionState.java @@ -0,0 +1,32 @@ +package jsettlers.main.android.gameplay.controlsmenu.goods; + +import jsettlers.common.buildings.IMaterialProductionSettings; +import jsettlers.common.material.EMaterialType; + +/** + * Created by Tom Pratt on 25/09/2017. + */ + +public class ProductionState { + private final EMaterialType materialType; + private final int quantity; + private final float ratio; + + public ProductionState(EMaterialType materialType, IMaterialProductionSettings materialProductionSettings) { + this.materialType = materialType; + this.quantity = materialProductionSettings.getAbsoluteProductionRequest(materialType); + this.ratio = materialProductionSettings.getUserConfiguredRelativeRequestValue(materialType); + } + + public EMaterialType getMaterialType() { + return materialType; + } + + public int getQuantity() { + return quantity; + } + + public float getRatio() { + return ratio; + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/ProductionViewModel.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/ProductionViewModel.java new file mode 100644 index 0000000000..b2c9564688 --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/ProductionViewModel.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2017 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package jsettlers.main.android.gameplay.controlsmenu.goods; + +import android.app.Activity; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.Transformations; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProvider; + +import jsettlers.common.action.SetMaterialProductionAction; +import jsettlers.common.buildings.IMaterialProductionSettings; +import jsettlers.common.material.EMaterialType; +import jsettlers.main.android.core.controls.ActionControls; +import jsettlers.main.android.core.controls.ControlsResolver; +import jsettlers.main.android.core.controls.DrawControls; +import jsettlers.main.android.core.controls.PositionControls; +import jsettlers.main.android.core.events.DrawEvents; + +import static java8.util.J8Arrays.stream; + +/** + * Created by Tom Pratt on 25/09/2017. + */ + +public class ProductionViewModel extends ViewModel { + private final EMaterialType[] productionMaterials = { + EMaterialType.SWORD, + EMaterialType.BOW, + EMaterialType.SPEAR, + EMaterialType.HAMMER, + EMaterialType.BLADE, + EMaterialType.PICK, + EMaterialType.AXE, + EMaterialType.SAW, + EMaterialType.SCYTHE, + EMaterialType.FISHINGROD + }; + + private final ActionControls actionControls; + private final PositionControls positionControls; + + private final LiveData productionStates; + + public ProductionViewModel(ActionControls actionControls, PositionControls positionControls, DrawControls drawControls) { + this.actionControls = actionControls; + this.positionControls = positionControls; + + DrawEvents drawEvents = new DrawEvents(drawControls); + productionStates = Transformations.map(drawEvents, x -> productionStates()); + } + + public LiveData getProductionStates() { + return productionStates; + } + + public void increment(EMaterialType materialType) { + actionControls.fireAction(new SetMaterialProductionAction(positionControls.getCurrentPosition(), materialType, SetMaterialProductionAction.EMaterialProductionType.INCREASE, 0)); + } + + public void decrement(EMaterialType materialType) { + actionControls.fireAction(new SetMaterialProductionAction(positionControls.getCurrentPosition(), materialType, SetMaterialProductionAction.EMaterialProductionType.DECREASE, 0)); + } + + public void setProductionRatio(EMaterialType materialType, float ratio) { + actionControls.fireAction(new SetMaterialProductionAction(positionControls.getCurrentPosition(), materialType, SetMaterialProductionAction.EMaterialProductionType.SET_RATIO, ratio)); + } + + private ProductionState[] productionStates() { + IMaterialProductionSettings materialProductionSettings = positionControls.getCurrentPartitionData().getPartitionSettings().getMaterialProductionSettings(); + + return stream(productionMaterials) + .map(materialType -> new ProductionState(materialType, materialProductionSettings)) + .toArray(ProductionState[]::new); + } + + /** + * ViewModel factory + */ + public static class Factory implements ViewModelProvider.Factory { + private final ControlsResolver controlsResolver; + + public Factory(Activity activity) { + this.controlsResolver = new ControlsResolver(activity); + } + + @Override + public T create(Class modelClass) { + if (modelClass == ProductionViewModel.class) { + return (T) new ProductionViewModel( + controlsResolver.getActionControls(), + controlsResolver.getPositionControls(), + controlsResolver.getDrawControls()); + } + throw new RuntimeException("ProductionViewModel.Factory doesn't know how to create a: " + modelClass.toString()); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/viewstates/StockMaterialState.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/StockMaterialState.java similarity index 96% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/viewstates/StockMaterialState.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/StockMaterialState.java index 8b1d096275..935d6c7ab2 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/viewstates/StockMaterialState.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/StockMaterialState.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.viewstates; +package jsettlers.main.android.gameplay.controlsmenu.goods; /** * Created by Tom Pratt on 12/07/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/viewstates/TradeMaterialState.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/TradeMaterialState.java similarity index 96% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/viewstates/TradeMaterialState.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/TradeMaterialState.java index ff2adc75d0..4417c5d023 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/viewstates/TradeMaterialState.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/TradeMaterialState.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.viewstates; +package jsettlers.main.android.gameplay.controlsmenu.goods; import jsettlers.common.material.EMaterialType; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/viewholders/TradeMaterialViewHolder.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/TradeMaterialViewHolder.java similarity index 92% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/viewholders/TradeMaterialViewHolder.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/TradeMaterialViewHolder.java index 1d19fd1f24..1c0fabd4ce 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/viewholders/TradeMaterialViewHolder.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/TradeMaterialViewHolder.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.viewholders; +package jsettlers.main.android.gameplay.controlsmenu.goods; import android.support.v7.widget.RecyclerView; import android.view.View; @@ -21,8 +21,7 @@ import android.widget.TextView; import jsettlers.main.android.R; -import jsettlers.main.android.gameplay.viewstates.TradeMaterialState; -import jsettlers.main.android.utils.OriginalImageProvider; +import jsettlers.main.android.core.resources.OriginalImageProvider; /** * Created by Tom Pratt on 05/08/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/adapters/TradeMaterialsAdapter.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/TradeMaterialsAdapter.java similarity index 95% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/adapters/TradeMaterialsAdapter.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/TradeMaterialsAdapter.java index 047e49ff88..bfd6be9105 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/adapters/TradeMaterialsAdapter.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/goods/TradeMaterialsAdapter.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.adapters; +package jsettlers.main.android.gameplay.controlsmenu.goods; import android.app.Activity; import android.support.annotation.Nullable; @@ -26,8 +26,6 @@ import java.util.List; import jsettlers.main.android.R; -import jsettlers.main.android.gameplay.ui.viewholders.TradeMaterialViewHolder; -import jsettlers.main.android.gameplay.viewstates.TradeMaterialState; /** * Created by Tom Pratt on 05/08/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/BuildingSelectionFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/BuildingSelectionFragment.java similarity index 84% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/BuildingSelectionFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/BuildingSelectionFragment.java index 93356e95c1..2f771f83d4 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/BuildingSelectionFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/BuildingSelectionFragment.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.selection; +package jsettlers.main.android.gameplay.controlsmenu.selection; import android.os.Bundle; import android.support.annotation.Nullable; @@ -35,16 +35,16 @@ import jsettlers.main.android.core.controls.DrawControls; import jsettlers.main.android.core.controls.TaskControls; import jsettlers.main.android.gameplay.navigation.MenuNavigator; -import jsettlers.main.android.gameplay.ui.fragments.menus.selection.features.DestroyFeature; -import jsettlers.main.android.gameplay.ui.fragments.menus.selection.features.DockFeature; -import jsettlers.main.android.gameplay.ui.fragments.menus.selection.features.MaterialsFeature; -import jsettlers.main.android.gameplay.ui.fragments.menus.selection.features.OccupiedFeature; -import jsettlers.main.android.gameplay.ui.fragments.menus.selection.features.PriorityFeature; -import jsettlers.main.android.gameplay.ui.fragments.menus.selection.features.SelectionFeature; -import jsettlers.main.android.gameplay.ui.fragments.menus.selection.features.StockFeature; -import jsettlers.main.android.gameplay.ui.fragments.menus.selection.features.TitleFeature; -import jsettlers.main.android.gameplay.ui.fragments.menus.selection.features.TradingFeature; -import jsettlers.main.android.gameplay.ui.fragments.menus.selection.features.WorkAreaFeature; +import jsettlers.main.android.gameplay.controlsmenu.selection.features.DestroyFeature; +import jsettlers.main.android.gameplay.controlsmenu.selection.features.DockFeature; +import jsettlers.main.android.gameplay.controlsmenu.selection.features.MaterialsFeature; +import jsettlers.main.android.gameplay.controlsmenu.selection.features.OccupiedFeature; +import jsettlers.main.android.gameplay.controlsmenu.selection.features.PriorityFeature; +import jsettlers.main.android.gameplay.controlsmenu.selection.features.SelectionFeature; +import jsettlers.main.android.gameplay.controlsmenu.selection.features.StockFeature; +import jsettlers.main.android.gameplay.controlsmenu.selection.features.TitleFeature; +import jsettlers.main.android.gameplay.controlsmenu.selection.features.TradingFeature; +import jsettlers.main.android.gameplay.controlsmenu.selection.features.WorkAreaFeature; import static java8.util.stream.StreamSupport.stream; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/CarriersSelectionFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/CarriersSelectionFragment.java similarity index 94% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/CarriersSelectionFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/CarriersSelectionFragment.java index 95ff800ca7..1a45661ea7 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/CarriersSelectionFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/CarriersSelectionFragment.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.selection; +package jsettlers.main.android.gameplay.controlsmenu.selection; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.Click; @@ -25,8 +25,8 @@ import jsettlers.main.android.R; import jsettlers.main.android.core.controls.ActionControls; import jsettlers.main.android.core.controls.ControlsResolver; -import jsettlers.main.android.gameplay.ImageLinkFactory; -import jsettlers.main.android.utils.OriginalImageProvider; +import jsettlers.main.android.core.resources.ImageLinkFactory; +import jsettlers.main.android.core.resources.OriginalImageProvider; import android.widget.ImageView; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/SelectionFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/SelectionFragment.java similarity index 97% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/SelectionFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/SelectionFragment.java index 4b0f20a5ec..bf461b5cd3 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/SelectionFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/SelectionFragment.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.selection; +package jsettlers.main.android.gameplay.controlsmenu.selection; import jsettlers.common.selectable.ISelectionSet; import jsettlers.input.SelectionSet; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/ShipsSelectionFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/ShipsSelectionFragment.java similarity index 96% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/ShipsSelectionFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/ShipsSelectionFragment.java index 249076bf55..917a019f8c 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/ShipsSelectionFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/ShipsSelectionFragment.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.selection; +package jsettlers.main.android.gameplay.controlsmenu.selection; import android.os.Bundle; import android.support.annotation.Nullable; @@ -29,7 +29,7 @@ import jsettlers.main.android.R; import jsettlers.main.android.core.controls.ActionControls; import jsettlers.main.android.core.controls.ControlsResolver; -import jsettlers.main.android.utils.OriginalImageProvider; +import jsettlers.main.android.core.resources.OriginalImageProvider; import org.androidannotations.annotations.Click; import org.androidannotations.annotations.EFragment; import org.androidannotations.annotations.ViewsById; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/SoldiersSelectionFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/SoldiersSelectionFragment.java similarity index 95% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/SoldiersSelectionFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/SoldiersSelectionFragment.java index 56c755f6da..f8f33bce95 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/SoldiersSelectionFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/SoldiersSelectionFragment.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.selection; +package jsettlers.main.android.gameplay.controlsmenu.selection; import org.androidannotations.annotations.Click; import org.androidannotations.annotations.EFragment; @@ -24,8 +24,8 @@ import jsettlers.main.android.R; import jsettlers.main.android.core.controls.ActionControls; import jsettlers.main.android.core.controls.ControlsResolver; -import jsettlers.main.android.gameplay.ImageLinkFactory; -import jsettlers.main.android.utils.OriginalImageProvider; +import jsettlers.main.android.core.resources.ImageLinkFactory; +import jsettlers.main.android.core.resources.OriginalImageProvider; import android.os.Bundle; import android.support.annotation.Nullable; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/SpecialistsSelectionFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/SpecialistsSelectionFragment.java similarity index 94% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/SpecialistsSelectionFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/SpecialistsSelectionFragment.java index d8bc703c40..fe925609b5 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/SpecialistsSelectionFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/SpecialistsSelectionFragment.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.selection; +package jsettlers.main.android.gameplay.controlsmenu.selection; import org.androidannotations.annotations.Click; import org.androidannotations.annotations.EFragment; @@ -25,8 +25,8 @@ import jsettlers.main.android.R; import jsettlers.main.android.core.controls.ActionControls; import jsettlers.main.android.core.controls.ControlsResolver; -import jsettlers.main.android.gameplay.ImageLinkFactory; -import jsettlers.main.android.utils.OriginalImageProvider; +import jsettlers.main.android.core.resources.ImageLinkFactory; +import jsettlers.main.android.core.resources.OriginalImageProvider; import android.os.Bundle; import android.support.annotation.Nullable; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/DestroyFeature.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/DestroyFeature.java similarity index 93% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/DestroyFeature.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/DestroyFeature.java index f17fe1ca91..65c6547fb7 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/DestroyFeature.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/DestroyFeature.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.selection.features; +package jsettlers.main.android.gameplay.controlsmenu.selection.features; import android.support.design.widget.Snackbar; import android.view.View; @@ -28,8 +28,8 @@ import jsettlers.main.android.core.controls.ActionControls; import jsettlers.main.android.core.controls.ActionListener; import jsettlers.main.android.gameplay.navigation.MenuNavigator; -import jsettlers.main.android.gameplay.ui.customviews.InGameButton; -import jsettlers.main.android.utils.OriginalImageProvider; +import jsettlers.main.android.gameplay.customviews.InGameButton; +import jsettlers.main.android.core.resources.OriginalImageProvider; /** * Created by tompr on 10/01/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/DockFeature.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/DockFeature.java similarity index 96% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/DockFeature.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/DockFeature.java index c8485b1c1d..3a65cced9e 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/DockFeature.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/DockFeature.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.selection.features; +package jsettlers.main.android.gameplay.controlsmenu.selection.features; import android.support.design.widget.Snackbar; import android.view.View; @@ -33,8 +33,8 @@ import jsettlers.main.android.core.controls.DrawListener; import jsettlers.main.android.core.controls.TaskControls; import jsettlers.main.android.gameplay.navigation.MenuNavigator; -import jsettlers.main.android.gameplay.ui.customviews.InGameButton; -import jsettlers.main.android.utils.OriginalImageProvider; +import jsettlers.main.android.gameplay.customviews.InGameButton; +import jsettlers.main.android.core.resources.OriginalImageProvider; /** * Created by Tom Pratt on 10/01/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/MaterialsFeature.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/MaterialsFeature.java similarity index 96% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/MaterialsFeature.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/MaterialsFeature.java index 8bfe048aa8..7c94e641fd 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/MaterialsFeature.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/MaterialsFeature.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.selection.features; +package jsettlers.main.android.gameplay.controlsmenu.selection.features; import jsettlers.common.buildings.IBuilding; import jsettlers.graphics.map.controls.original.panel.selection.BuildingState; @@ -21,7 +21,7 @@ import jsettlers.main.android.core.controls.DrawControls; import jsettlers.main.android.core.controls.DrawListener; import jsettlers.main.android.gameplay.navigation.MenuNavigator; -import jsettlers.main.android.utils.OriginalImageProvider; +import jsettlers.main.android.core.resources.OriginalImageProvider; import android.view.LayoutInflater; import android.view.View; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/OccupiedFeature.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/OccupiedFeature.java similarity index 97% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/OccupiedFeature.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/OccupiedFeature.java index 640dfcb923..40ffc0e190 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/OccupiedFeature.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/OccupiedFeature.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.selection.features; +package jsettlers.main.android.gameplay.controlsmenu.selection.features; import java.util.List; @@ -31,10 +31,10 @@ import jsettlers.main.android.core.controls.ActionControls; import jsettlers.main.android.core.controls.DrawControls; import jsettlers.main.android.core.controls.DrawListener; -import jsettlers.main.android.gameplay.ImageLinkFactory; +import jsettlers.main.android.core.resources.ImageLinkFactory; import jsettlers.main.android.gameplay.navigation.MenuNavigator; -import jsettlers.main.android.gameplay.ui.customviews.InGameButton; -import jsettlers.main.android.utils.OriginalImageProvider; +import jsettlers.main.android.gameplay.customviews.InGameButton; +import jsettlers.main.android.core.resources.OriginalImageProvider; import android.view.View; import android.widget.ImageView; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/PriorityFeature.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/PriorityFeature.java similarity index 95% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/PriorityFeature.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/PriorityFeature.java index 6bd3f6b621..bb2c0ade05 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/PriorityFeature.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/PriorityFeature.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.selection.features; +package jsettlers.main.android.gameplay.controlsmenu.selection.features; import jsettlers.common.buildings.IBuilding; import jsettlers.common.images.ImageLink; @@ -28,8 +28,8 @@ import jsettlers.main.android.core.controls.DrawControls; import jsettlers.main.android.core.controls.DrawListener; import jsettlers.main.android.gameplay.navigation.MenuNavigator; -import jsettlers.main.android.gameplay.ui.customviews.InGameButton; -import jsettlers.main.android.utils.OriginalImageProvider; +import jsettlers.main.android.gameplay.customviews.InGameButton; +import jsettlers.main.android.core.resources.OriginalImageProvider; import android.view.View; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/SelectionFeature.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/SelectionFeature.java similarity index 96% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/SelectionFeature.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/SelectionFeature.java index 37e29cba11..2af7455663 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/SelectionFeature.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/SelectionFeature.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.selection.features; +package jsettlers.main.android.gameplay.controlsmenu.selection.features; import jsettlers.common.buildings.IBuilding; import jsettlers.graphics.map.controls.original.panel.selection.BuildingState; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/StockFeature.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/StockFeature.java similarity index 94% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/StockFeature.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/StockFeature.java index ba0af04c4e..9b4bbad748 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/StockFeature.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/StockFeature.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.selection.features; +package jsettlers.main.android.gameplay.controlsmenu.selection.features; import static java8.util.J8Arrays.stream; @@ -29,8 +29,8 @@ import jsettlers.main.android.core.controls.DrawControls; import jsettlers.main.android.core.controls.DrawListener; import jsettlers.main.android.gameplay.navigation.MenuNavigator; -import jsettlers.main.android.gameplay.ui.adapters.MaterialsAdapter; -import jsettlers.main.android.gameplay.viewstates.StockMaterialState; +import jsettlers.main.android.gameplay.controlsmenu.goods.MaterialsAdapter; +import jsettlers.main.android.gameplay.controlsmenu.goods.StockMaterialState; import android.app.Activity; import android.support.v7.widget.RecyclerView; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/TitleFeature.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/TitleFeature.java similarity index 95% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/TitleFeature.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/TitleFeature.java index b23bdab01b..0c5fa17e09 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/TitleFeature.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/TitleFeature.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.selection.features; +package jsettlers.main.android.gameplay.controlsmenu.selection.features; import jsettlers.common.buildings.IBuilding; import jsettlers.graphics.localization.Labels; @@ -26,7 +26,7 @@ import android.view.View; import android.widget.ImageView; import android.widget.TextView; -import jsettlers.main.android.utils.OriginalImageProvider; +import jsettlers.main.android.core.resources.OriginalImageProvider; /** * Created by tompr on 10/01/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/TradingFeature.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/TradingFeature.java similarity index 96% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/TradingFeature.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/TradingFeature.java index 60b528ada5..bf40bf8a73 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/TradingFeature.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/TradingFeature.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.selection.features; +package jsettlers.main.android.gameplay.controlsmenu.selection.features; import android.app.Activity; import android.support.v7.widget.RecyclerView; @@ -37,9 +37,9 @@ import jsettlers.main.android.core.controls.DrawListener; import jsettlers.main.android.core.navigation.BackPressedListener; import jsettlers.main.android.gameplay.navigation.MenuNavigator; -import jsettlers.main.android.gameplay.ui.adapters.TradeMaterialsAdapter; -import jsettlers.main.android.gameplay.viewstates.TradeMaterialState; -import jsettlers.main.android.utils.OriginalImageProvider; +import jsettlers.main.android.gameplay.controlsmenu.goods.TradeMaterialsAdapter; +import jsettlers.main.android.gameplay.controlsmenu.goods.TradeMaterialState; +import jsettlers.main.android.core.resources.OriginalImageProvider; import java.util.List; @@ -138,7 +138,7 @@ public void draw() { @Override public boolean onBackPressed() { - if (popupWindow.isShowing()) { + if (popupWindow != null && popupWindow.isShowing()) { popupWindow.dismiss(); return true; } diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/WorkAreaFeature.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/WorkAreaFeature.java similarity index 94% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/WorkAreaFeature.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/WorkAreaFeature.java index e06de562a9..5a9f3d0ddf 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/selection/features/WorkAreaFeature.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/selection/features/WorkAreaFeature.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.selection.features; +package jsettlers.main.android.gameplay.controlsmenu.selection.features; import jsettlers.common.buildings.IBuilding; import jsettlers.common.images.ImageLink; @@ -26,11 +26,11 @@ import jsettlers.main.android.core.controls.ActionListener; import jsettlers.main.android.core.controls.TaskControls; import jsettlers.main.android.gameplay.navigation.MenuNavigator; -import jsettlers.main.android.gameplay.ui.customviews.InGameButton; +import jsettlers.main.android.gameplay.customviews.InGameButton; import android.support.design.widget.Snackbar; import android.view.View; -import jsettlers.main.android.utils.OriginalImageProvider; +import jsettlers.main.android.core.resources.OriginalImageProvider; /** * Created by tompr on 11/01/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/settlers/SettlersMenuFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/settlers/SettlersMenuFragment.java similarity index 97% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/settlers/SettlersMenuFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/settlers/SettlersMenuFragment.java index 5d9a84c777..5ea710135e 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/settlers/SettlersMenuFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/settlers/SettlersMenuFragment.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.settlers; +package jsettlers.main.android.gameplay.controlsmenu.settlers; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.EFragment; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/settlers/SettlersSoldiersFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/settlers/SettlersSoldiersFragment.java similarity index 55% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/settlers/SettlersSoldiersFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/settlers/SettlersSoldiersFragment.java index 65a50b365d..f0197f1e73 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/settlers/SettlersSoldiersFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/settlers/SettlersSoldiersFragment.java @@ -13,7 +13,14 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.settlers; +package jsettlers.main.android.gameplay.controlsmenu.settlers; + +import android.arch.lifecycle.ViewModelProviders; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.widget.ImageView; +import android.widget.TextView; import org.androidannotations.annotations.Click; import org.androidannotations.annotations.EFragment; @@ -21,27 +28,18 @@ import jsettlers.common.images.ImageLink; import jsettlers.main.android.R; -import jsettlers.main.android.gameplay.presenters.MenuFactory; -import jsettlers.main.android.gameplay.presenters.SettlersSoldiersMenu; -import jsettlers.main.android.gameplay.ui.views.SettlersSoldiersView; -import jsettlers.main.android.utils.OriginalImageProvider; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.widget.ImageView; -import android.widget.TextView; +import jsettlers.main.android.core.resources.OriginalImageProvider; /** * Created by tompr on 13/01/2017. */ @EFragment(R.layout.menu_settlers_soldiers) -public class SettlersSoldiersFragment extends Fragment implements SettlersSoldiersView { +public class SettlersSoldiersFragment extends Fragment { public static SettlersSoldiersFragment newInstance() { return new SettlersSoldiersFragment_(); } - SettlersSoldiersMenu settlersSoldiersMenu; + private SoldiersViewModel viewModel; @ViewById(R.id.text_view_soldier_strength) TextView soldierStrengthTextView; @@ -57,89 +55,34 @@ public static SettlersSoldiersFragment newInstance() { @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - settlersSoldiersMenu = new MenuFactory(getActivity()).settlersSoldiersMenu(this); - settlersSoldiersMenu.start(); - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - settlersSoldiersMenu.finish(); + viewModel = ViewModelProviders.of(this, new SoldiersViewModel.Factory(getActivity())).get(SoldiersViewModel.class); + + viewModel.getStrengthText().observe(this, s -> soldierStrengthTextView.setText(s)); + viewModel.getPromotionText().observe(this, s -> soldierPromotionTextView.setText(s)); + viewModel.getSwordsmenPromotionEnabled().observe(this, enabled -> bowmenPromotionImageView.setEnabled(enabled)); + viewModel.getBowmenPromotionEnabled().observe(this, enabled -> bowmenPromotionImageView.setEnabled(enabled)); + viewModel.getPikemenPromotionEnabled().observe(this, enabled -> pikemenPromotionImageView.setEnabled(enabled)); + viewModel.getSwordsmenImageLink().observe(this, imageLink -> setPromotionButtonImage(swordsmenPromotionImageView, imageLink)); + viewModel.getBowmenImageLink().observe(this, imageLink -> setPromotionButtonImage(bowmenPromotionImageView, imageLink)); + viewModel.getPikemenImageLink().observe(this, imageLink -> setPromotionButtonImage(pikemenPromotionImageView, imageLink)); } @Click(R.id.image_view_promotion_swordsmen) void promoteSwordsmenClicked() { - settlersSoldiersMenu.swordsmenPromotionClicked(); + viewModel.swordsmenPromotionClicked(); } @Click(R.id.image_view_promotion_pikemen) void promotePikemenClicked() { - settlersSoldiersMenu.pikemenPromotionClicked(); + viewModel.pikemenPromotionClicked(); } @Click(R.id.image_view_promotion_bowmen) void promoteBowmenClicked() { - settlersSoldiersMenu.bowmenPromotionClicked(); - } - - /** - * SettlersSoldiersView implementation - */ - @Override - public void setStrengthText(String strengthText) { - if (soldierStrengthTextView != null) { - soldierStrengthTextView.setText(strengthText); - } - } - - @Override - public void setPromotionText(String promotionText) { - if (soldierPromotionTextView != null) { - soldierPromotionTextView.setText(promotionText); - } - } - - @Override - public void setSwordsmenPromotionEnabled(boolean enabled) { - if (swordsmenPromotionImageView != null) { - swordsmenPromotionImageView.setEnabled(enabled); - } - } - - @Override - public void setBowmenPromotionEnabled(boolean enabled) { - if (bowmenPromotionImageView != null) { - bowmenPromotionImageView.setEnabled(enabled); - } - } - - @Override - public void setPikemenPromotionEnabled(boolean enabled) { - if (pikemenPromotionImageView != null) { - pikemenPromotionImageView.setEnabled(enabled); - } - } - - @Override - public void setSwordsmenImage(ImageLink imageLink) { - setPromotionButtonImage(swordsmenPromotionImageView, imageLink); - } - - @Override - public void setBowmenImage(ImageLink imageLink) { - setPromotionButtonImage(bowmenPromotionImageView, imageLink); - } - - @Override - public void setPikemenImage(ImageLink imageLink) { - setPromotionButtonImage(pikemenPromotionImageView, imageLink); + viewModel.bowmenPromotionClicked(); } private void setPromotionButtonImage(ImageView imageView, ImageLink imageLink) { - if (imageView == null) { - return; - } - if (imageLink == null) { imageView.setImageDrawable(null); } else { diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/settlers/SoldiersViewModel.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/settlers/SoldiersViewModel.java new file mode 100644 index 0000000000..ac2013453a --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/controlsmenu/settlers/SoldiersViewModel.java @@ -0,0 +1,157 @@ +package jsettlers.main.android.gameplay.controlsmenu.settlers; + +import android.app.Activity; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.Transformations; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProvider; + +import jsettlers.common.action.EActionType; +import jsettlers.common.action.SoldierAction; +import jsettlers.common.images.EImageLinkType; +import jsettlers.common.images.ImageLink; +import jsettlers.common.images.OriginalImageLink; +import jsettlers.common.movable.ESoldierType; +import jsettlers.common.player.IInGamePlayer; +import jsettlers.graphics.localization.Labels; +import jsettlers.main.android.core.controls.ActionControls; +import jsettlers.main.android.core.controls.ControlsResolver; +import jsettlers.main.android.core.controls.DrawControls; +import jsettlers.main.android.core.events.DrawEvents; + +/** + * Created by Tom Pratt on 30/09/2017. + */ + +public class SoldiersViewModel extends ViewModel { + private final ImageLink[] swordsmenPromotionPossibleImages = new OriginalImageLink[] { new OriginalImageLink(EImageLinkType.GUI, 3, 396, 0), + new OriginalImageLink(EImageLinkType.GUI, 3, 402, 0), null }; + private final ImageLink[] swordsmenPromotionNotPossibleImages = new OriginalImageLink[] { new OriginalImageLink(EImageLinkType.GUI, 3, 399, 0), + new OriginalImageLink(EImageLinkType.GUI, 3, 405, 0), null }; + private final ImageLink[] bowmenPromotionPossibleImages = new OriginalImageLink[] { new OriginalImageLink(EImageLinkType.GUI, 3, 408, 0), + new OriginalImageLink(EImageLinkType.GUI, 3, 414, 0), null }; + private final ImageLink[] bowmenPromotionNotPossibleImages = new OriginalImageLink[] { new OriginalImageLink(EImageLinkType.GUI, 3, 411, 0), + new OriginalImageLink(EImageLinkType.GUI, 3, 417, 0), null }; + private final ImageLink[] pikemenPromotionPossibleImages = new OriginalImageLink[] { new OriginalImageLink(EImageLinkType.GUI, 3, 420, 0), + new OriginalImageLink(EImageLinkType.GUI, 3, 426, 0), null }; + private final ImageLink[] pikemenPromotionNotPossibleImages = new OriginalImageLink[] { new OriginalImageLink(EImageLinkType.GUI, 3, 423, 0), + new OriginalImageLink(EImageLinkType.GUI, 3, 429, 0), null }; + + private final ActionControls actionControls; + private final IInGamePlayer player; + + private final LiveData strengthText; + private final LiveData promotionText; + private final LiveData swordsmenPromotionEnabled; + private final LiveData bowmenPromotionEnabled; + private final LiveData pikemenPromotionEnabled; + private final LiveData swordsmenImageLink; + private final LiveData bowmenImageLink; + private final LiveData pikemenImageLink; + + public SoldiersViewModel(ActionControls actionControls, DrawControls drawControls, IInGamePlayer player) { + this.actionControls = actionControls; + this.player = player; + + DrawEvents drawEvents = new DrawEvents(drawControls); + + strengthText = Transformations.map(drawEvents, x -> strengthText()); + promotionText = Transformations.map(drawEvents, x -> promotionText()); + swordsmenPromotionEnabled = Transformations.map(drawEvents, x -> isPromotionPossible(ESoldierType.SWORDSMAN)); + bowmenPromotionEnabled = Transformations.map(drawEvents, x -> isPromotionPossible(ESoldierType.BOWMAN)); + pikemenPromotionEnabled = Transformations.map(drawEvents, x -> isPromotionPossible(ESoldierType.PIKEMAN)); + swordsmenImageLink = Transformations.map(swordsmenPromotionEnabled, isPromotionPossible -> getPromotionImageLink(isPromotionPossible, swordsmenPromotionPossibleImages, swordsmenPromotionNotPossibleImages, ESoldierType.SWORDSMAN)); + bowmenImageLink = Transformations.map(bowmenPromotionEnabled, isPromotionPossible -> getPromotionImageLink(isPromotionPossible, bowmenPromotionPossibleImages, bowmenPromotionNotPossibleImages, ESoldierType.BOWMAN)); + pikemenImageLink = Transformations.map(pikemenPromotionEnabled, isPromotionPossible -> getPromotionImageLink(isPromotionPossible, pikemenPromotionPossibleImages, pikemenPromotionNotPossibleImages, ESoldierType.PIKEMAN)); + } + + public LiveData getStrengthText() { + return strengthText; + } + + public LiveData getPromotionText() { + return promotionText; + } + + public LiveData getSwordsmenPromotionEnabled() { + return swordsmenPromotionEnabled; + } + + public LiveData getBowmenPromotionEnabled() { + return bowmenPromotionEnabled; + } + + public LiveData getPikemenPromotionEnabled() { + return pikemenPromotionEnabled; + } + + public LiveData getSwordsmenImageLink() { + return swordsmenImageLink; + } + + public LiveData getBowmenImageLink() { + return bowmenImageLink; + } + + public LiveData getPikemenImageLink() { + return pikemenImageLink; + } + + public void swordsmenPromotionClicked() { + promote(ESoldierType.SWORDSMAN); + } + + public void bowmenPromotionClicked() { + promote(ESoldierType.BOWMAN); + } + + public void pikemenPromotionClicked() { + promote(ESoldierType.PIKEMAN); + } + + + private String strengthText() { + return Labels.getString("combat_strength", (int) (player.getCombatStrengthInformation().getCombatStrength(false) * 100)); + } + + private String promotionText() { + return Labels.getString("upgrade_warriors_progress", player.getMannaInformation().getNextUpdateProgressPercent()); + } + + private boolean isPromotionPossible(ESoldierType soldierType) { + return player.getMannaInformation().isUpgradePossible(soldierType); + } + + private void promote(ESoldierType soldierType) { + if (isPromotionPossible(soldierType)) { + actionControls.fireAction(new SoldierAction(EActionType.UPGRADE_SOLDIERS, soldierType)); + } + } + + private ImageLink getPromotionImageLink(boolean isPromotionPossible, ImageLink[] possibleImages, ImageLink[] notPossibleImages, ESoldierType soldierType) { + if (isPromotionPossible) { + return possibleImages[player.getMannaInformation().getLevel(soldierType)]; + } else { + return notPossibleImages[player.getMannaInformation().getLevel(soldierType)]; + } + } + + /** + * ViewModel factory + */ + public static class Factory implements ViewModelProvider.Factory { + private final ControlsResolver controlsResolver; + + public Factory(Activity activity) { + this.controlsResolver = new ControlsResolver(activity); + } + + @Override + public T create(Class modelClass) { + if (modelClass == SoldiersViewModel.class) { + return (T) new SoldiersViewModel(controlsResolver.getActionControls(), controlsResolver.getDrawControls(), controlsResolver.getPlayer()); + } + throw new RuntimeException("SoldiersViewModel.Factory doesn't know how to create a: " + modelClass.toString()); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/customviews/InGameButton.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/customviews/InGameButton.java similarity index 97% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/customviews/InGameButton.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/customviews/InGameButton.java index 411a9c8510..6586a3b0c3 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/customviews/InGameButton.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/customviews/InGameButton.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.customviews; +package jsettlers.main.android.gameplay.customviews; import jsettlers.main.android.R; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/dialogs/PausedDialog.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/gamemenu/PausedDialog.java similarity index 97% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/dialogs/PausedDialog.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/gamemenu/PausedDialog.java index 115ecd8025..1caabff776 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/dialogs/PausedDialog.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/gamemenu/PausedDialog.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.dialogs; +package jsettlers.main.android.gameplay.gamemenu; import jsettlers.main.android.R; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/navigation/MenuNavigator.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/navigation/MenuNavigator.java index e30522237a..49713c1fb1 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/navigation/MenuNavigator.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/navigation/MenuNavigator.java @@ -16,7 +16,6 @@ package jsettlers.main.android.gameplay.navigation; import jsettlers.main.android.core.navigation.BackPressedListener; -import jsettlers.main.android.gameplay.ui.fragments.menus.selection.features.TradingFeature; /** * Created by tompr on 11/01/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/presenters/BuildingsCategoryMenu.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/presenters/BuildingsCategoryMenu.java deleted file mode 100644 index 0eacfb7c4b..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/presenters/BuildingsCategoryMenu.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.gameplay.presenters; - -import java8.util.stream.Collectors; -import jsettlers.common.buildings.EBuildingType; -import jsettlers.common.map.partition.IBuildingCounts; -import jsettlers.common.action.Action; -import jsettlers.common.action.ShowConstructionMarksAction; -import jsettlers.graphics.map.controls.original.panel.content.buildings.EBuildingsCategory; -import jsettlers.main.android.core.controls.ActionControls; -import jsettlers.main.android.core.controls.DrawControls; -import jsettlers.main.android.core.controls.DrawListener; -import jsettlers.main.android.core.controls.PositionControls; -import jsettlers.main.android.gameplay.navigation.MenuNavigator; -import jsettlers.main.android.gameplay.ui.views.BuildingsCategoryView; -import jsettlers.main.android.gameplay.viewstates.BuildingState; - -import java.util.List; - -import static java8.util.stream.StreamSupport.stream; - -/** - * Created by tompr on 22/11/2016. - */ -public class BuildingsCategoryMenu implements DrawListener { - private final BuildingsCategoryView view; - private final ActionControls actionControls; - private final DrawControls drawControls; - private final PositionControls positionControls; - private final MenuNavigator menuNavigator; - private final EBuildingsCategory buildingsCategory; - - public BuildingsCategoryMenu(BuildingsCategoryView view, ActionControls actionControls, DrawControls drawControls, PositionControls positionControls, MenuNavigator menuNavigator, - EBuildingsCategory buildingsCategory) { - this.view = view; - this.actionControls = actionControls; - this.drawControls = drawControls; - this.positionControls = positionControls; - this.menuNavigator = menuNavigator; - this.buildingsCategory = buildingsCategory; - } - - public void start() { - drawControls.addInfrequentDrawListener(this); - } - - public void finish() { - drawControls.removeInfrequentDrawListener(this); - } - - public void buildingSelected(EBuildingType buildingType) { - Action action = new ShowConstructionMarksAction(buildingType); - actionControls.fireAction(action); - menuNavigator.dismissMenu(); - } - - /** - * DrawListener implementation - */ - @Override - public void draw() { - IBuildingCounts buildingCounts = null; - - if (positionControls.isInPlayerPartition()) { - buildingCounts = positionControls.getCurrentPartitionData().getBuildingCounts(); - } - - view.setBuildings(buildingTiles(buildingCounts)); - } - - private List buildingTiles(IBuildingCounts buildingCounts) { - - return stream(buildingsCategory.buildingTypes) - .map(buildingType -> new BuildingState(buildingType, buildingCounts)) - .collect(Collectors.toList()); - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/presenters/MenuFactory.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/presenters/MenuFactory.java deleted file mode 100644 index cd8301cdf7..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/presenters/MenuFactory.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.gameplay.presenters; - -import jsettlers.main.android.core.GameManager; -import jsettlers.main.android.core.controls.ControlsAdapter; -import jsettlers.main.android.core.utils.Dispatcher; -import jsettlers.main.android.gameplay.navigation.MenuNavigator; -import jsettlers.main.android.gameplay.navigation.MenuNavigatorProvider; -import jsettlers.graphics.map.controls.original.panel.content.buildings.EBuildingsCategory; -import jsettlers.main.android.gameplay.ui.views.BuildingsCategoryView; -import jsettlers.main.android.gameplay.ui.views.SettlersSoldiersView; - -import android.app.Activity; - -/** - * Created by tompr on 10/03/2017. - */ -public class MenuFactory { - private final ControlsAdapter controlsAdapter; - private final MenuNavigator menuNavigator; - - public MenuFactory(Activity activity) { - this.controlsAdapter = ((GameManager) activity.getApplication()).getControlsAdapter(); - this.menuNavigator = ((MenuNavigatorProvider) activity).getMenuNavigator(); - } - - public BuildingsCategoryMenu buildingsMenu(BuildingsCategoryView view, EBuildingsCategory buildingsCategory) { - return new BuildingsCategoryMenu(view, controlsAdapter, controlsAdapter, controlsAdapter, menuNavigator, buildingsCategory); - } - - public SettlersSoldiersMenu settlersSoldiersMenu(SettlersSoldiersView view) { - return new SettlersSoldiersMenu(view, controlsAdapter, controlsAdapter, controlsAdapter.getInGamePlayer(), new Dispatcher()); - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/presenters/SettlersSoldiersMenu.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/presenters/SettlersSoldiersMenu.java deleted file mode 100644 index f1eab2bed0..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/presenters/SettlersSoldiersMenu.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.gameplay.presenters; - -import jsettlers.common.images.EImageLinkType; -import jsettlers.common.images.ImageLink; -import jsettlers.common.images.OriginalImageLink; -import jsettlers.common.action.EActionType; -import jsettlers.common.movable.ESoldierType; -import jsettlers.common.player.IInGamePlayer; -import jsettlers.graphics.action.ActionFireable; -import jsettlers.common.action.SoldierAction; -import jsettlers.graphics.localization.Labels; -import jsettlers.main.android.core.controls.DrawControls; -import jsettlers.main.android.core.controls.DrawListener; -import jsettlers.main.android.core.utils.Dispatcher; -import jsettlers.main.android.gameplay.ui.views.SettlersSoldiersView; - -/** - * Created by tompr on 13/01/2017. - */ -public class SettlersSoldiersMenu implements DrawListener { - private final ImageLink[] swordsmenPromotionPossibleImages = new OriginalImageLink[] { new OriginalImageLink(EImageLinkType.GUI, 3, 396, 0), - new OriginalImageLink(EImageLinkType.GUI, 3, 402, 0), null }; - private final ImageLink[] swordsmenPromotionNotPossibleImages = new OriginalImageLink[] { new OriginalImageLink(EImageLinkType.GUI, 3, 399, 0), - new OriginalImageLink(EImageLinkType.GUI, 3, 405, 0), null }; - private final ImageLink[] bowPromotionPossibleImages = new OriginalImageLink[] { new OriginalImageLink(EImageLinkType.GUI, 3, 408, 0), - new OriginalImageLink(EImageLinkType.GUI, 3, 414, 0), null }; - private final ImageLink[] bowmenPromotionNotPossibleImages = new OriginalImageLink[] { new OriginalImageLink(EImageLinkType.GUI, 3, 411, 0), - new OriginalImageLink(EImageLinkType.GUI, 3, 417, 0), null }; - private final ImageLink[] pikemenPromotionPossibleImages = new OriginalImageLink[] { new OriginalImageLink(EImageLinkType.GUI, 3, 420, 0), - new OriginalImageLink(EImageLinkType.GUI, 3, 426, 0), null }; - private final ImageLink[] pikemenPromotionNotPossibleImages = new OriginalImageLink[] { new OriginalImageLink(EImageLinkType.GUI, 3, 423, 0), - new OriginalImageLink(EImageLinkType.GUI, 3, 429, 0), null }; - - private final SettlersSoldiersView view; - private final ActionFireable actionFireable; - private final DrawControls drawControls; - private final IInGamePlayer player; - private final Dispatcher dispatcher; - - public SettlersSoldiersMenu(SettlersSoldiersView view, ActionFireable actionFireable, DrawControls drawControls, IInGamePlayer player, Dispatcher dispatcher) { - this.view = view; - this.actionFireable = actionFireable; - this.drawControls = drawControls; - this.player = player; - this.dispatcher = dispatcher; - } - - public void start() { - drawControls.addInfrequentDrawListener(this); - updateView(); - } - - public void finish() { - drawControls.removeInfrequentDrawListener(this); - } - - public void swordsmenPromotionClicked() { - promote(ESoldierType.SWORDSMAN); - } - - public void bowmenPromotionClicked() { - promote(ESoldierType.BOWMAN); - } - - public void pikemenPromotionClicked() { - promote(ESoldierType.PIKEMAN); - } - - /** - * DrawListener implementation - */ - @Override - public void draw() { - dispatcher.runOnMainThread(this::updateView); - } - - private void updateView() { - view.setStrengthText(strengthText()); - view.setPromotionText(promotionText()); - view.setSwordsmenPromotionEnabled(isPromotionPossible(ESoldierType.SWORDSMAN)); - view.setBowmenPromotionEnabled(isPromotionPossible(ESoldierType.BOWMAN)); - view.setPikemenPromotionEnabled(isPromotionPossible(ESoldierType.PIKEMAN)); - view.setSwordsmenImage(getPromotionImageLink(swordsmenPromotionPossibleImages, swordsmenPromotionNotPossibleImages, ESoldierType.SWORDSMAN)); - view.setBowmenImage(getPromotionImageLink(bowPromotionPossibleImages, bowmenPromotionNotPossibleImages, ESoldierType.BOWMAN)); - view.setPikemenImage(getPromotionImageLink(pikemenPromotionPossibleImages, pikemenPromotionNotPossibleImages, ESoldierType.PIKEMAN)); - } - - private String strengthText() { - return Labels.getString("combat_strength", (int) (player.getCombatStrengthInformation().getCombatStrength(false) * 100)); - } - - private String promotionText() { - return Labels.getString("upgrade_warriors_progress", player.getMannaInformation().getNextUpdateProgressPercent()); - } - - private boolean isPromotionPossible(ESoldierType soldierType) { - return player.getMannaInformation().isUpgradePossible(soldierType); - } - - private void promote(ESoldierType soldierType) { - if (isPromotionPossible(soldierType)) { - actionFireable.fireAction(new SoldierAction(EActionType.UPGRADE_SOLDIERS, soldierType)); - } - } - - private ImageLink getPromotionImageLink(ImageLink[] possibleImages, ImageLink[] notPossibleImages, ESoldierType soldierType) { - if (isPromotionPossible(soldierType)) { - return possibleImages[player.getMannaInformation().getLevel(soldierType)]; - } else { - return notPossibleImages[player.getMannaInformation().getLevel(soldierType)]; - } - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsProductionFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsProductionFragment.java deleted file mode 100644 index fd8f3e4ee2..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsProductionFragment.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.gameplay.ui.fragments.menus.goods; - -import org.androidannotations.annotations.EFragment; - -import jsettlers.main.android.R; - -import android.support.v4.app.Fragment; - -/** - * Created by tompr on 24/11/2016. - */ -@EFragment(R.layout.menu_goods_production) -public class GoodsProductionFragment extends Fragment { - public static GoodsProductionFragment newInstance() { - return new GoodsProductionFragment_(); - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsQuantitiesFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsQuantitiesFragment.java deleted file mode 100644 index e4b354d139..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsQuantitiesFragment.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.gameplay.ui.fragments.menus.goods; - -import org.androidannotations.annotations.EFragment; - -import jsettlers.main.android.R; - -import android.support.v4.app.Fragment; - -/** - * Created by tompr on 24/11/2016. - */ -@EFragment(R.layout.menu_goods_quantities) -public class GoodsQuantitiesFragment extends Fragment { - public static GoodsQuantitiesFragment newInstance() { - return new GoodsQuantitiesFragment_(); - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/views/BuildingsCategoryView.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/views/BuildingsCategoryView.java deleted file mode 100644 index 26f0ef7bb2..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/views/BuildingsCategoryView.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.gameplay.ui.views; - -import java.util.List; - -import jsettlers.main.android.gameplay.viewstates.BuildingState; - -/** - * Created by tompr on 10/03/2017. - */ -public interface BuildingsCategoryView { - void setBuildings(List buildingStates); -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/activities/MainActivity.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/MainActivity.java similarity index 78% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/activities/MainActivity.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/MainActivity.java index 3f7ea15b72..6c4bdd9157 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/activities/MainActivity.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/MainActivity.java @@ -13,24 +13,23 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.ui.activities; +package jsettlers.main.android.mainmenu; import org.androidannotations.annotations.EActivity; import org.androidannotations.annotations.OptionsItem; -import jsettlers.common.menu.IMapDefinition; import jsettlers.main.android.R; -import jsettlers.main.android.gameplay.ui.activities.GameActivity_; +import jsettlers.main.android.gameplay.GameActivity_; import jsettlers.main.android.mainmenu.navigation.Actions; import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; -import jsettlers.main.android.mainmenu.ui.fragments.MainMenuFragment; -import jsettlers.main.android.mainmenu.ui.fragments.picker.JoinMultiPlayerPickerFragment; -import jsettlers.main.android.mainmenu.ui.fragments.picker.LoadSinglePlayerPickerFragment; -import jsettlers.main.android.mainmenu.ui.fragments.picker.NewMultiPlayerPickerFragment; -import jsettlers.main.android.mainmenu.ui.fragments.picker.NewSinglePlayerPickerFragment; -import jsettlers.main.android.mainmenu.ui.fragments.setup.JoinMultiPlayerSetupFragment; -import jsettlers.main.android.mainmenu.ui.fragments.setup.NewMultiPlayerSetupFragment; -import jsettlers.main.android.mainmenu.ui.fragments.setup.NewSinglePlayerSetupFragment; +import jsettlers.main.android.mainmenu.home.MainMenuFragment; +import jsettlers.main.android.mainmenu.mappicker.JoinMultiPlayerPickerFragment; +import jsettlers.main.android.mainmenu.mappicker.LoadSinglePlayerPickerFragment; +import jsettlers.main.android.mainmenu.mappicker.NewMultiPlayerPickerFragment; +import jsettlers.main.android.mainmenu.mappicker.NewSinglePlayerPickerFragment; +import jsettlers.main.android.mainmenu.gamesetup.JoinMultiPlayerSetupFragment; +import jsettlers.main.android.mainmenu.gamesetup.NewMultiPlayerSetupFragment; +import jsettlers.main.android.mainmenu.gamesetup.NewSinglePlayerSetupFragment; import android.os.Bundle; import android.support.annotation.Nullable; @@ -84,9 +83,9 @@ public void showLoadSinglePlayerPicker() { } @Override - public void showNewSinglePlayerSetup(IMapDefinition mapDefinition) { + public void showNewSinglePlayerSetup(String mapId) { getSupportFragmentManager().beginTransaction() - .replace(R.id.frame_layout, NewSinglePlayerSetupFragment.create(mapDefinition)) + .replace(R.id.frame_layout, NewSinglePlayerSetupFragment.create(mapId)) .addToBackStack(null) .commit(); } @@ -108,17 +107,17 @@ public void showJoinMultiPlayerPicker() { } @Override - public void showJoinMultiPlayerSetup(IMapDefinition mapDefinition) { + public void showJoinMultiPlayerSetup(String mapId) { getSupportFragmentManager().beginTransaction() - .replace(R.id.frame_layout, JoinMultiPlayerSetupFragment.create(mapDefinition)) + .replace(R.id.frame_layout, JoinMultiPlayerSetupFragment.create(mapId)) .addToBackStack(null) .commit(); } @Override - public void showNewMultiPlayerSetup(IMapDefinition mapDefinition) { + public void showNewMultiPlayerSetup(String mapId) { getSupportFragmentManager().beginTransaction() - .replace(R.id.frame_layout, NewMultiPlayerSetupFragment.create(mapDefinition)) + .replace(R.id.frame_layout, NewMultiPlayerSetupFragment.create(mapId)) .addToBackStack(null) .commit(); } diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/factories/PresenterFactory.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/factories/PresenterFactory.java deleted file mode 100644 index 6053bf1771..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/factories/PresenterFactory.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.factories; - -import static java8.util.stream.StreamSupport.stream; - -import java.util.List; - -import jsettlers.common.menu.IJoinPhaseMultiplayerGameConnector; -import jsettlers.common.utils.collections.ChangingList; -import jsettlers.logic.map.loading.MapLoader; -import jsettlers.main.android.core.AndroidPreferences; -import jsettlers.main.android.core.GameManager; -import jsettlers.main.android.core.GameStarter; -import jsettlers.main.android.core.resources.scanner.AndroidResourcesLoader; -import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; -import jsettlers.main.android.mainmenu.presenters.MainMenuPresenter; -import jsettlers.main.android.mainmenu.presenters.SettingsPresenter; -import jsettlers.main.android.mainmenu.presenters.picker.JoinMultiPlayerPickerPresenter; -import jsettlers.main.android.mainmenu.presenters.picker.LoadSinglePlayerPickerPresenter; -import jsettlers.main.android.mainmenu.presenters.picker.NewMultiPlayerPickerPresenter; -import jsettlers.main.android.mainmenu.presenters.picker.NewSinglePlayerPickerPresenter; -import jsettlers.main.android.mainmenu.presenters.setup.JoinMultiPlayerSetupPresenter; -import jsettlers.main.android.mainmenu.presenters.setup.JoinMultiPlayerSetupPresenterImpl; -import jsettlers.main.android.mainmenu.presenters.setup.JoinMultiPlayerSetupPresenterPop; -import jsettlers.main.android.mainmenu.presenters.setup.NewMultiPlayerSetupPresenter; -import jsettlers.main.android.mainmenu.presenters.setup.NewMultiPlayerSetupPresenterImpl; -import jsettlers.main.android.mainmenu.presenters.setup.NewMultiPlayerSetupPresenterPop; -import jsettlers.main.android.mainmenu.presenters.setup.NewSinglePlayerSetupPresenter; -import jsettlers.main.android.mainmenu.views.JoinMultiPlayerPickerView; -import jsettlers.main.android.mainmenu.views.JoinMultiPlayerSetupView; -import jsettlers.main.android.mainmenu.views.LoadSinglePlayerPickerView; -import jsettlers.main.android.mainmenu.views.MainMenuView; -import jsettlers.main.android.mainmenu.views.MapPickerView; -import jsettlers.main.android.mainmenu.views.NewMultiPlayerPickerView; -import jsettlers.main.android.mainmenu.views.NewMultiPlayerSetupView; -import jsettlers.main.android.mainmenu.views.NewSinglePlayerSetupView; -import jsettlers.main.android.mainmenu.views.SettingsView; - -import android.app.Activity; -import android.content.Context; - -/** - * Created by tompr on 03/02/2017. - */ -public class PresenterFactory { - - public static MainMenuPresenter createMainMenuPresenter(Activity activity, MainMenuView view) { - MainMenuNavigator navigator = (MainMenuNavigator) activity; - GameManager gameManager = (GameManager) activity.getApplication(); - - return new MainMenuPresenter(view, navigator, gameManager, new AndroidResourcesLoader(activity)); - } - - public static SettingsPresenter createSettingsPresenter(Context context, SettingsView view) { - return new SettingsPresenter(view, new AndroidPreferences(context)); - } - - /** - * Picker screen presenters - */ - public static NewSinglePlayerPickerPresenter createNewSinglePlayerPickerPresenter(Activity activity, MapPickerView view) { - MainMenuNavigator navigator = (MainMenuNavigator) activity; - GameStarter gameStarter = (GameStarter) activity.getApplication(); - ChangingList changingMaps = gameStarter.getMapList().getFreshMaps(); - - return new NewSinglePlayerPickerPresenter(view, navigator, gameStarter, changingMaps); - } - - public static LoadSinglePlayerPickerPresenter createLoadSinglePlayerPickerPresenter(Activity activity, LoadSinglePlayerPickerView view) { - MainMenuNavigator navigator = (MainMenuNavigator) activity; - GameStarter gameStarter = (GameStarter) activity.getApplication(); - ChangingList changingMaps = gameStarter.getMapList().getSavedMaps(); - - return new LoadSinglePlayerPickerPresenter(view, navigator, gameStarter, changingMaps); - } - - public static NewMultiPlayerPickerPresenter createNewMultiPlayerPickerPresenter(Activity activity, NewMultiPlayerPickerView view) { - MainMenuNavigator navigator = (MainMenuNavigator) activity; - GameStarter gameStarter = (GameStarter) activity.getApplication(); - ChangingList changingMaps = gameStarter.getMapList().getFreshMaps(); - - return new NewMultiPlayerPickerPresenter(view, navigator, gameStarter, new AndroidPreferences(activity), changingMaps); - } - - public static JoinMultiPlayerPickerPresenter createJoinMultiPlayerPickerPresenter(Activity activity, JoinMultiPlayerPickerView view) { - MainMenuNavigator navigator = (MainMenuNavigator) activity; - GameStarter gameStarter = (GameStarter) activity.getApplication(); - - return new JoinMultiPlayerPickerPresenter(view, navigator, gameStarter); - } - - /** - * Setup screen presenters - */ - public static NewSinglePlayerSetupPresenter createNewSinglePlayerSetupPresenter(Activity activity, NewSinglePlayerSetupView view, String mapId) { - MainMenuNavigator navigator = (MainMenuNavigator) activity; - GameStarter gameStarter = (GameStarter) activity.getApplication(); - - MapLoader mapDefinition = getMapById(mapId, gameStarter); - - return new NewSinglePlayerSetupPresenter(view, navigator, gameStarter, new AndroidPreferences(activity), mapDefinition); - } - - public static NewMultiPlayerSetupPresenter createNewMultiPlayerSetupPresenter(Activity activity, NewMultiPlayerSetupView view, String mapId) { - MainMenuNavigator mainMenuNavigator = (MainMenuNavigator) activity; - GameStarter gameStarter = (GameStarter) activity.getApplication(); - IJoinPhaseMultiplayerGameConnector joinPhaseMultiplayerGameConnector = gameStarter.getJoinPhaseMultiplayerConnector(); - - MapLoader mapDefinition = getMapById(mapId, gameStarter); - - if (joinPhaseMultiplayerGameConnector == null || mapDefinition == null) { - return new NewMultiPlayerSetupPresenterPop(mainMenuNavigator); - } else { - return new NewMultiPlayerSetupPresenterImpl(view, mainMenuNavigator, gameStarter, joinPhaseMultiplayerGameConnector, - new AndroidPreferences(activity), mapDefinition); - } - } - - public static JoinMultiPlayerSetupPresenter createJoinMultiPlayerSetupPresenter(Activity activity, JoinMultiPlayerSetupView view, String mapId) { - MainMenuNavigator navigator = (MainMenuNavigator) activity; - GameStarter gameStarter = (GameStarter) activity.getApplication(); - IJoinPhaseMultiplayerGameConnector connector = gameStarter.getJoinPhaseMultiplayerConnector(); - - MapLoader mapDefinition = getMapById(mapId, gameStarter); - - if (connector == null/* || mapDefinition == null */) { - return new JoinMultiPlayerSetupPresenterPop(navigator); - } else { - return new JoinMultiPlayerSetupPresenterImpl(view, navigator, gameStarter, connector, new AndroidPreferences(activity), mapDefinition); - } - } - - private static MapLoader getMapById(String mapId, GameStarter gameStarter) { - List maps = gameStarter.getMapList().getFreshMaps().getItems(); - return stream(maps) - .filter(x -> mapId.equals(x.getMapId())) - .findFirst() - .get(); - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/setup/NewSinglePlayerSetupFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/JoinMultiPlayerSetupFragment.java similarity index 57% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/setup/NewSinglePlayerSetupFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/JoinMultiPlayerSetupFragment.java index b7fd4216b1..608147fddb 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/setup/NewSinglePlayerSetupFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/JoinMultiPlayerSetupFragment.java @@ -13,26 +13,40 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.ui.fragments.setup; +package jsettlers.main.android.mainmenu.gamesetup; +import android.arch.lifecycle.ViewModelProviders; +import android.support.v4.app.Fragment; + +import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.EFragment; -import jsettlers.common.menu.IMapDefinition; import jsettlers.main.android.R; -import jsettlers.main.android.mainmenu.factories.PresenterFactory; -import jsettlers.main.android.mainmenu.presenters.setup.NewSinglePlayerSetupPresenter; -import jsettlers.main.android.mainmenu.views.NewSinglePlayerSetupView; - -import android.support.v4.app.Fragment; +/** + * Created by tompr on 22/01/2017. + */ @EFragment(R.layout.fragment_new_single_player_setup) -public class NewSinglePlayerSetupFragment extends MapSetupFragment implements NewSinglePlayerSetupView { - public static Fragment create(IMapDefinition mapDefinition) { - return NewSinglePlayerSetupFragment_.builder().mapId(mapDefinition.getMapId()).build(); - } - - @Override - protected NewSinglePlayerSetupPresenter createPresenter() { - return PresenterFactory.createNewSinglePlayerSetupPresenter(getActivity(), this, mapId); - } +public class JoinMultiPlayerSetupFragment extends MapSetupFragment { + + public static Fragment create(String mapId) { + return JoinMultiPlayerSetupFragment_.builder().mapId(mapId).build(); + } + + @Override + protected MapSetupViewModel createViewModel() { + return ViewModelProviders.of(this, new JoinMultiPlayerSetupViewModel.Factory(getActivity(), mapId)).get(JoinMultiPlayerSetupViewModel.class); + } + + @AfterViews + void disableUnavailableSpinners() { + numberOfPlayersSpinner.setEnabled(false); + startResourcesSpinner.setEnabled(false); + peacetimeSpinner.setEnabled(false); + } + + @Override + protected int getListItemLayoutId() { + return R.layout.item_multiplayer_playerslot; + } } diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/JoinMultiPlayerSetupViewModel.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/JoinMultiPlayerSetupViewModel.java new file mode 100644 index 0000000000..abfcc97b81 --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/JoinMultiPlayerSetupViewModel.java @@ -0,0 +1,154 @@ +package jsettlers.main.android.mainmenu.gamesetup; + +import android.app.Activity; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProvider; + +import java.util.List; + +import jsettlers.common.menu.IJoinPhaseMultiplayerGameConnector; +import jsettlers.common.menu.IMultiplayerListener; +import jsettlers.common.menu.IMultiplayerPlayer; +import jsettlers.common.menu.IStartingGame; +import jsettlers.common.utils.collections.ChangingList; +import jsettlers.common.utils.collections.IChangingListListener; +import jsettlers.logic.map.loading.MapLoader; +import jsettlers.main.android.core.AndroidPreferences; +import jsettlers.main.android.core.GameStarter; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.PlayerSlotPresenter; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.ReadyListener; + +/** + * Created by Tom Pratt on 07/10/2017. + */ + +public class JoinMultiPlayerSetupViewModel extends MapSetupViewModel implements IMultiplayerListener, IChangingListListener, ReadyListener { + + private final GameStarter gameStarter; + private final AndroidPreferences androidPreferences; + private final IJoinPhaseMultiplayerGameConnector connector; + private final MapLoader mapLoader; + + public JoinMultiPlayerSetupViewModel(GameStarter gameStarter, AndroidPreferences androidPreferences, IJoinPhaseMultiplayerGameConnector connector, MapLoader mapLoader) { + super(gameStarter, mapLoader); + this.gameStarter = gameStarter; + this.androidPreferences = androidPreferences; + this.connector = connector; + this.mapLoader = mapLoader; + + connector.setMultiplayerListener(this); + connector.getPlayers().setListener(this); + + updateSlots(); + } + + @Override + public void startGame() { + connector.startGame(); + } + + /** + * IMultiplayerListener implementation + */ + @Override + public void gameAborted() { + gameStarter.setJoinPhaseMultiPlayerConnector(null); + + // TODO pop + } + + @Override + public void gameIsStarting(IStartingGame game) { + gameStarter.setJoinPhaseMultiPlayerConnector(null); + gameStarter.setStartingGame(game); + showMapEvent.postValue(null); + } + + /** + * ChangingListListener implementation + */ + @Override + public void listChanged(ChangingList list) { + updateSlots(); + playerSlots.postValue(playerSlots.getValue()); + // updateViewItems(); // trigger a notify data set changed for now. Probably want to update the view more dynamically at some point + } + + /** + * ReadyListener implementation + */ + @Override + public void readyChanged(boolean ready) { + connector.setReady(ready); + } + + + + + + private void updateSlots() { + List players = connector.getPlayers().getItems(); + int numberOfConnectedPlayers = players.size(); + + for (int i = 0; i < playerSlotPresenters.size(); i++) { + PlayerSlotPresenter playerSlotPresenter = playerSlotPresenters.get(i); + + if (i < numberOfConnectedPlayers) { + setHumanSlotPlayerTypes(playerSlotPresenter); + + IMultiplayerPlayer multiplayerPlayer = players.get(i); + playerSlotPresenter.setName(multiplayerPlayer.getName()); + playerSlotPresenter.setReady(multiplayerPlayer.isReady()); + playerSlotPresenter.setShowReadyControl(true); + + boolean isMe = multiplayerPlayer.getId().equals(androidPreferences.getPlayerId()); + + if (isMe) { + playerSlotPresenter.setControlsEnabled(true); + playerSlotPresenter.setReadyListener(this); + } else { + playerSlotPresenter.setControlsEnabled(false); + playerSlotPresenter.setReadyListener(null); + } + } else { + setComputerSlotPlayerTypes(playerSlotPresenter); + playerSlotPresenter.setName("Computer " + i); + playerSlotPresenter.setShowReadyControl(false); + playerSlotPresenter.setControlsEnabled(true); + playerSlotPresenter.setReadyListener(null); + } + } + } + + + + /** + * ViewModel factory + */ + public static class Factory implements ViewModelProvider.Factory { + + private final Activity activity; + private final String mapId; + + public Factory(Activity activity, String mapId) { + this.activity = activity; + this.mapId = mapId; + } + + @Override + public T create(Class modelClass) { + GameStarter gameStarter = (GameStarter) activity.getApplication(); + MapLoader mapLoader = gameStarter.getMapList().getMapById(mapId); + IJoinPhaseMultiplayerGameConnector joinPhaseMultiplayerGameConnector = gameStarter.getJoinPhaseMultiplayerConnector(); + + if (joinPhaseMultiplayerGameConnector == null) { + throw new MultiPlayerConnectorUnavailableException(); + } + + if (modelClass == JoinMultiPlayerSetupViewModel.class) { + return (T) new JoinMultiPlayerSetupViewModel(gameStarter, new AndroidPreferences(activity), joinPhaseMultiplayerGameConnector, mapLoader); + } + throw new RuntimeException("JoinMultiPlayerSetupViewModel.Factory doesn't know how to create a: " + modelClass.toString()); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/setup/MapSetupFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/MapSetupFragment.java similarity index 66% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/setup/MapSetupFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/MapSetupFragment.java index 9afec4640b..5b9c2b22a6 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/setup/MapSetupFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/MapSetupFragment.java @@ -13,35 +13,8 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.ui.fragments.setup; +package jsettlers.main.android.mainmenu.gamesetup; -import java.util.List; - -import org.androidannotations.annotations.AfterViews; -import org.androidannotations.annotations.Background; -import org.androidannotations.annotations.Click; -import org.androidannotations.annotations.EFragment; -import org.androidannotations.annotations.FragmentArg; -import org.androidannotations.annotations.ItemSelect; -import org.androidannotations.annotations.UiThread; -import org.androidannotations.annotations.ViewById; - -import jsettlers.main.android.R; -import jsettlers.main.android.core.ui.FragmentUtil; -import jsettlers.main.android.core.ui.PreviewImageConverter; -import jsettlers.main.android.mainmenu.presenters.setup.MapSetupPresenter; -import jsettlers.main.android.mainmenu.presenters.setup.Peacetime; -import jsettlers.main.android.mainmenu.presenters.setup.PlayerCount; -import jsettlers.main.android.mainmenu.presenters.setup.StartResources; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.Civilisation; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.PlayerSlotPresenter; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.PlayerType; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.StartPosition; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.Team; -import jsettlers.main.android.mainmenu.views.MapSetupView; -import jsettlers.main.android.mainmenu.views.PlayerSlotView; - -import android.graphics.Bitmap; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; @@ -56,13 +29,29 @@ import android.widget.ImageView; import android.widget.Spinner; import android.widget.TextView; -import android.widget.Toast; + +import org.androidannotations.annotations.AfterViews; +import org.androidannotations.annotations.Click; +import org.androidannotations.annotations.EFragment; +import org.androidannotations.annotations.FragmentArg; +import org.androidannotations.annotations.ItemSelect; +import org.androidannotations.annotations.ViewById; + +import jsettlers.main.android.R; +import jsettlers.main.android.core.ui.FragmentUtil; +import jsettlers.main.android.core.resources.PreviewImageConverter; +import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.Civilisation; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.PlayerSlotPresenter; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.PlayerType; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.StartPosition; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.Team; /** * Created by tompr on 21/01/2017. */ @EFragment(R.layout.fragment_new_single_player_setup) -public abstract class MapSetupFragment extends Fragment implements MapSetupView { +public abstract class MapSetupFragment extends Fragment { @ViewById(R.id.recycler_view) RecyclerView recyclerView; @@ -81,19 +70,24 @@ public abstract class MapSetupFragment exte @FragmentArg("mapid") protected String mapId; - protected Presenter presenter; + private MapSetupViewModel viewModel; + PlayersAdapter adapter; ArrayAdapter playerCountsAdapter; ArrayAdapter startResourcesAdapter; + ArrayAdapter peaceTimesAdapter; - boolean isSaving = false; - - protected abstract Presenter createPresenter(); + protected abstract MapSetupViewModel createViewModel(); @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - presenter = createPresenter(); + try { + viewModel = createViewModel(); + } catch (MultiPlayerConnectorUnavailableException e) { + MainMenuNavigator mainMenuNavigator = (MainMenuNavigator) getActivity(); + mainMenuNavigator.popToMenuRoot(); + } } @AfterViews @@ -104,99 +98,74 @@ void setupView() { // Disable these for now, as these features are not implemented yet. startResourcesSpinner.setEnabled(false); peacetimeSpinner.setEnabled(false); - - presenter.initView(); - } - - @Override - public void onResume() { - super.onResume(); - presenter.updateViewTitle(); } @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - isSaving = true; - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - presenter.dispose(); - } - - @Override - public void onDetach() { - super.onDetach(); - if (isRemoving() && !isSaving) { - presenter.viewFinished(); + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + if (viewModel == null) { + return; } + + viewModel.getPlayerCountOptions().observe(this, playerCounts -> { + playerCountsAdapter = getSpinnerAdapter(playerCounts); + numberOfPlayersSpinner.setAdapter(playerCountsAdapter); + }); + viewModel.getPlayerCount().observe(this, playerCount -> numberOfPlayersSpinner.setSelection(playerCountsAdapter.getPosition(playerCount))); + + viewModel.getStartResourcesOptions().observe(this, startResources -> { + startResourcesAdapter = getSpinnerAdapter(startResources); + startResourcesSpinner.setAdapter(startResourcesAdapter); + }); + viewModel.getStartResources().observe(this, startResources -> startResourcesSpinner.setSelection(startResourcesAdapter.getPosition(startResources))); + + viewModel.getPeaceTimeOptions().observe(this, peacetimes -> { + peaceTimesAdapter = getSpinnerAdapter(peacetimes); + peacetimeSpinner.setAdapter(peaceTimesAdapter); + }); + viewModel.getPeaceTime().observe(this, peacetime -> peacetimeSpinner.setSelection(peaceTimesAdapter.getPosition(peacetime))); + + viewModel.getImage().observe(this, image -> mapPreviewImageView.setImageBitmap(PreviewImageConverter.convert(image))); + viewModel.getTitle().observe(this, title -> toolbar.setTitle(title)); + viewModel.getPlayerSlots().observe(this, playerSlotPresenters -> { + if (adapter == null) { + adapter = new PlayersAdapter(); + } + + if (recyclerView.getAdapter() == null) { + recyclerView.setAdapter(adapter); + } + + adapter.setItems(playerSlotPresenters); + }); + + viewModel.getShowMapEvent().observe(this, z -> { + MainMenuNavigator mainMenuNavigator = (MainMenuNavigator) getActivity(); + mainMenuNavigator.showGame(); + }); } @Click(R.id.button_start_game) protected void onStartGameClicked() { - if (!presenter.startGame()) { - Toast.makeText(this.getContext(), R.string.multiplayer_not_all_players_ready, Toast.LENGTH_LONG).show(); - } + viewModel.startGame(); +// if (!presenter.startGame()) { +// Toast.makeText(this.getContext(), R.string.multiplayer_not_all_players_ready, Toast.LENGTH_LONG).show(); +// } } @ItemSelect(R.id.spinner_number_of_players) void playerSelected(boolean selected, int position) { - presenter.playerCountSelected(playerCountsAdapter.getItem(position)); + viewModel.playerCountSelected(playerCountsAdapter.getItem(position)); } @ItemSelect(R.id.spinner_start_resources) void startResourcesSelected(boolean selected, int position) { - presenter.startResourcesSelected(startResourcesAdapter.getItem(position)); + viewModel.startResourcesSelected(startResourcesAdapter.getItem(position)); } - /** - * MapSetupView implementation - */ - @Override - public void setNumberOfPlayersOptions(PlayerCount[] numberOfPlayersOptions) { - playerCountsAdapter = getSpinnerAdapter(numberOfPlayersOptions); - numberOfPlayersSpinner.setAdapter(playerCountsAdapter); - } - - @Override - public void setPlayerCount(PlayerCount playerCount) { - numberOfPlayersSpinner.setSelection(playerCountsAdapter.getPosition(playerCount)); - } - - @Override - public void setStartResourcesOptions(StartResources[] startResources) { - startResourcesAdapter = getSpinnerAdapter(startResources); - startResourcesSpinner.setAdapter(startResourcesAdapter); - } - - @Override - public void setStartResources(StartResources startResources) { - startResourcesSpinner.setSelection(startResourcesAdapter.getPosition(startResources)); - } - - @Override - public void setPeaceTimeOptions(Peacetime[] peaceTimeOptions) { - peacetimeSpinner.setAdapter(getSpinnerAdapter(peaceTimeOptions)); - } - - @Override - public void setMapName(String mapName) { - getActivity().setTitle(mapName); - } - - @Override - @Background - public void setMapImage(short[] image) { - setMapImage(PreviewImageConverter.convert(image)); - } - - @UiThread - public void setMapImage(Bitmap bitmap) { - if (mapPreviewImageView != null) { - mapPreviewImageView.setImageBitmap(bitmap); - } + @ItemSelect(R.id.spinner_peacetime) + void peacetimeSelected(boolean selected, int position) { + viewModel.peaceTimeSelected(peaceTimesAdapter.getItem(position)); } private ArrayAdapter getSpinnerAdapter(T[] items) { @@ -205,38 +174,28 @@ private ArrayAdapter getSpinnerAdapter(T[] items) { return adapter; } - @Override - @UiThread - public void setItems(List items, int playerCount) { - if (adapter == null) { - adapter = new PlayersAdapter(items); - } - - if (recyclerView.getAdapter() == null) { - recyclerView.setAdapter(adapter); - } - - adapter.setItems(items, playerCount); - } - protected int getListItemLayoutId() { return R.layout.item_playerslot; } + + + + /** + * Recyclerview adapter + */ class PlayersAdapter extends RecyclerView.Adapter { private final LayoutInflater layoutInflater; - private List players; - private int playerCount; + private PlayerSlotPresenter[] players = new PlayerSlotPresenter[0]; - PlayersAdapter(List players) { + PlayersAdapter() { this.layoutInflater = LayoutInflater.from(getActivity()); - this.players = players; } @Override public int getItemCount() { - return playerCount; + return players.length; } @Override @@ -247,13 +206,12 @@ public PlayerHolder onCreateViewHolder(ViewGroup parent, int viewType) { @Override public void onBindViewHolder(PlayerHolder holder, int position) { - holder.bind(players.get(position)); + holder.bind(players[position]); } - void setItems(List items, int playerCount) { + void setItems(PlayerSlotPresenter[] items) { // TODO use diffutil this.players = items; - this.playerCount = playerCount; notifyDataSetChanged(); } } @@ -275,12 +233,12 @@ class PlayerHolder extends RecyclerView.ViewHolder implements PlayerSlotView { PlayerHolder(View itemView) { super(itemView); - this.playerNameTextView = (TextView) itemView.findViewById(R.id.text_view_player_name); - this.readySwitch = (SwitchCompat) itemView.findViewById(R.id.switch_ready); - this.civilisationSpinner = (Spinner) itemView.findViewById(R.id.spinner_civilisation); - this.playerTypeSpinner = (Spinner) itemView.findViewById(R.id.spinner_type); - this.startPositionSpinner = (Spinner) itemView.findViewById(R.id.spinner_slot); - this.teamSpinner = (Spinner) itemView.findViewById(R.id.spinner_team); + this.playerNameTextView = itemView.findViewById(R.id.text_view_player_name); + this.readySwitch = itemView.findViewById(R.id.switch_ready); + this.civilisationSpinner = itemView.findViewById(R.id.spinner_civilisation); + this.playerTypeSpinner = itemView.findViewById(R.id.spinner_type); + this.startPositionSpinner = itemView.findViewById(R.id.spinner_slot); + this.teamSpinner = itemView.findViewById(R.id.spinner_team); readySwitch.setOnCheckedChangeListener((compoundButton, checked) -> { presenter.readyChanged(checked); diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/MapSetupViewModel.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/MapSetupViewModel.java new file mode 100644 index 0000000000..4f7145b6af --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/MapSetupViewModel.java @@ -0,0 +1,251 @@ +package jsettlers.main.android.mainmenu.gamesetup; + +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.MediatorLiveData; +import android.arch.lifecycle.MutableLiveData; +import android.arch.lifecycle.ViewModel; + +import java.util.ArrayList; +import java.util.List; + +import java8.util.J8Arrays; +import jsettlers.common.ai.EPlayerType; +import jsettlers.common.player.ECivilisation; +import jsettlers.logic.map.loading.EMapStartResources; +import jsettlers.logic.map.loading.MapLoader; +import jsettlers.logic.player.PlayerSetting; +import jsettlers.main.android.core.GameStarter; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.Civilisation; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.PlayerSlotPresenter; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.PlayerType; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.PositionChangedListener; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.StartPosition; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.Team; +import jsettlers.main.android.core.events.SingleLiveEvent; + +import static java8.util.stream.StreamSupport.stream; + +/** + * Created by Tom Pratt on 07/10/2017. + */ + +public abstract class MapSetupViewModel extends ViewModel implements PositionChangedListener { + + private final GameStarter gameStarter; + private final MapLoader mapLoader; + + protected final List playerSlotPresenters; + + private final MutableLiveData playerCountOptions = new MutableLiveData<>(); + private final MutableLiveData playerCount = new MutableLiveData<>(); + private final MutableLiveData startResourcesOptions = new MutableLiveData<>(); + private final MutableLiveData startResources = new MutableLiveData<>(); + private final MutableLiveData peaceTimeOptions = new MutableLiveData<>(); + private final MutableLiveData peaceTime = new MutableLiveData<>(); + private final MutableLiveData image = new MutableLiveData<>(); + private final MutableLiveData title = new MutableLiveData<>(); + protected final SingleLiveEvent showMapEvent = new SingleLiveEvent<>(); + protected final MediatorLiveData playerSlots = new MediatorLiveData<>(); + + + + public MapSetupViewModel(GameStarter gameStarter, MapLoader mapLoader) { + this.gameStarter = gameStarter; + this.mapLoader = mapLoader; + + playerSlotPresenters = createComputerPlayerSlots(); + + playerCountOptions.setValue(playerCountOptions()); + playerCount.setValue(new PlayerCount(mapLoader.getMaxPlayers())); + startResourcesOptions.setValue(startResourcesOptions()); + startResources.setValue(new StartResources(EMapStartResources.MEDIUM_GOODS)); + peaceTimeOptions.setValue(peaceTimeOptions()); + peaceTime.setValue(peaceTimeOptions.getValue()[0]); + image.setValue(mapLoader.getImage()); + title.setValue(mapLoader.getMapName()); + + playerSlots.addSource(playerCount, playerCount -> { + playerSlots.setValue(stream(playerSlotPresenters) + .limit(playerCount.getNumberOfPlayers()) + .toArray(PlayerSlotPresenter[]::new)); + }); + +// playerSlots = Transformations.map(playerCount, playerCount -> stream(playerSlotPresenters) +// .limit(playerCount.getNumberOfPlayers()) +// .toArray(PlayerSlotPresenter[]::new)); + } + + public LiveData getPlayerCountOptions() { + return playerCountOptions; + } + + public LiveData getPlayerCount() { + return playerCount; + } + + public MutableLiveData getStartResourcesOptions() { + return startResourcesOptions; + } + + public MutableLiveData getStartResources() { + return startResources; + } + + public MutableLiveData getPeaceTimeOptions() { + return peaceTimeOptions; + } + + public MutableLiveData getPeaceTime() { + return peaceTime; + } + + public MutableLiveData getImage() { + return image; + } + + public MutableLiveData getTitle() { + return title; + } + + public LiveData getPlayerSlots() { + return playerSlots; + } + + public LiveData getShowMapEvent() { + return showMapEvent; + } + + public void playerCountSelected(PlayerCount item) { + playerCount.setValue(item); + // updateViewItems(); Also update player slots via Transformation. + } + + public void startResourcesSelected(StartResources item) { + startResources.setValue(item); + } + + public void peaceTimeSelected(Peacetime item) { + peaceTime.setValue(item); + } + + public void startGame() { + // make abstract + } + + + @Override + protected void onCleared() { + super.onCleared(); + + if (gameStarter.getStartingGame() == null) { + abort(); + } + } + + protected void abort() { + + } + + private List createComputerPlayerSlots() { + List playerSlotPresenters = new ArrayList<>(); + PlayerSetting[] playerSettings = mapLoader.getFileHeader().getPlayerSettings(); + int playerCountValue = mapLoader.getMaxPlayers(); + + for (byte i = 0; i < playerCountValue; i++) { + PlayerSlotPresenter playerSlotPresenter = new PlayerSlotPresenter(this); + PlayerSetting playerSetting = playerSettings[i]; + + playerSlotPresenter.setName("Computer " + i); + playerSlotPresenter.setShowReadyControl(false); + + setComputerSlotPlayerTypes(playerSlotPresenter); + setSlotCivilisations(playerSlotPresenter, playerSetting); + setSlotStartPositions(playerSlotPresenter, playerCountValue, i); + setSlotTeams(playerSlotPresenter, playerSetting, playerCountValue, i); + + playerSlotPresenters.add(playerSlotPresenter); + } + + return playerSlotPresenters; + } + + protected static void setComputerSlotPlayerTypes(PlayerSlotPresenter playerSlotPresenter) { + playerSlotPresenter.setPossiblePlayerTypes(new PlayerType[] { + new PlayerType(EPlayerType.AI_VERY_HARD), + new PlayerType(EPlayerType.AI_HARD), + new PlayerType(EPlayerType.AI_EASY), + new PlayerType(EPlayerType.AI_VERY_EASY) + }); + playerSlotPresenter.setPlayerType(new PlayerType(EPlayerType.AI_VERY_HARD)); + } + + protected static void setHumanSlotPlayerTypes(PlayerSlotPresenter playerSlotPresenter) { + playerSlotPresenter.setPossiblePlayerTypes(new PlayerType[] { + new PlayerType(EPlayerType.HUMAN) + }); + playerSlotPresenter.setPlayerType(new PlayerType(EPlayerType.HUMAN)); + } + + private static void setSlotCivilisations(PlayerSlotPresenter playerSlotPresenter, PlayerSetting playerSetting) { + playerSlotPresenter.setPossibleCivilisations(new Civilisation[] { new Civilisation(ECivilisation.ROMAN) }); + + if (playerSetting.getCivilisation() != null) { + playerSlotPresenter.setCivilisation(new Civilisation(playerSetting.getCivilisation())); + } else { + playerSlotPresenter.setCivilisation(new Civilisation(ECivilisation.ROMAN)); + } + } + + private static void setSlotStartPositions(PlayerSlotPresenter playerSlotPresenter, int numberOfPlayers, byte orderNumber) { + playerSlotPresenter.setPossibleStartPositions(numberOfPlayers); + playerSlotPresenter.setStartPosition(new StartPosition(orderNumber)); + } + + private static void setSlotTeams(PlayerSlotPresenter playerSlotPresenter, PlayerSetting playerSetting, int numberOfPlayers, byte orderNumber) { + playerSlotPresenter.setPossibleTeams(numberOfPlayers); + if (playerSetting.getTeamId() != null) { + playerSlotPresenter.setTeam(new Team(playerSetting.getTeamId())); + } else { + playerSlotPresenter.setTeam(new Team(orderNumber)); + } + } + + /** + * PositionChangedListener implementation + */ + @Override + public void positionChanged(PlayerSlotPresenter updatedPlayerSlotPresenter, StartPosition oldPosition, StartPosition newPosition) { + for (PlayerSlotPresenter playerSlotPresenter : playerSlotPresenters) { + if (playerSlotPresenter != updatedPlayerSlotPresenter && playerSlotPresenter.getStartPosition().equals(newPosition)) { + playerSlotPresenter.setStartPosition(oldPosition); + } + } + } + + /** + * Get items for the main map options + */ + private PlayerCount[] playerCountOptions() { + int maxPlayers = mapLoader.getMaxPlayers(); + int minPlayers = mapLoader.getMinPlayers(); + int numberOfOptions = maxPlayers - minPlayers + 1; + + PlayerCount[] allowedPlayerCounts = new PlayerCount[numberOfOptions]; + + for (int i = 0; i < numberOfOptions; i++) { + allowedPlayerCounts[i] = new PlayerCount(minPlayers + i); + } + + return allowedPlayerCounts; + } + + private StartResources[] startResourcesOptions() { + return J8Arrays.stream(EMapStartResources.values()) + .map(StartResources::new) + .toArray(StartResources[]::new); + } + + private Peacetime[] peaceTimeOptions() { + return new Peacetime[] { new Peacetime("Without") }; + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/MultiPlayerConnectorUnavailableException.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/MultiPlayerConnectorUnavailableException.java new file mode 100644 index 0000000000..6159bf5404 --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/MultiPlayerConnectorUnavailableException.java @@ -0,0 +1,8 @@ +package jsettlers.main.android.mainmenu.gamesetup; + +/** + * Created by Tom Pratt on 08/10/2017. + */ + +public class MultiPlayerConnectorUnavailableException extends RuntimeException { +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/setup/NewMultiPlayerSetupFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/NewMultiPlayerSetupFragment.java similarity index 71% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/setup/NewMultiPlayerSetupFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/NewMultiPlayerSetupFragment.java index 6b3544e8e6..b01a4cd0ca 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/setup/NewMultiPlayerSetupFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/NewMultiPlayerSetupFragment.java @@ -13,32 +13,32 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.ui.fragments.setup; +package jsettlers.main.android.mainmenu.gamesetup; + +import android.arch.lifecycle.ViewModelProviders; +import android.support.v4.app.Fragment; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.EFragment; -import jsettlers.common.menu.IMapDefinition; import jsettlers.main.android.R; -import jsettlers.main.android.mainmenu.factories.PresenterFactory; -import jsettlers.main.android.mainmenu.presenters.setup.NewMultiPlayerSetupPresenter; -import jsettlers.main.android.mainmenu.views.NewMultiPlayerSetupView; - -import android.support.v4.app.Fragment; /** * Created by tompr on 21/01/2017. */ @EFragment(R.layout.fragment_new_single_player_setup) -public class NewMultiPlayerSetupFragment extends MapSetupFragment implements NewMultiPlayerSetupView { +public class NewMultiPlayerSetupFragment extends MapSetupFragment { + + private NewMultiPlayerSetupViewModel viewModel; - public static Fragment create(IMapDefinition mapDefinition) { - return NewMultiPlayerSetupFragment_.builder().mapId(mapDefinition.getMapId()).build(); + public static Fragment create(String mapId) { + return NewMultiPlayerSetupFragment_.builder().mapId(mapId).build(); } @Override - protected NewMultiPlayerSetupPresenter createPresenter() { - return PresenterFactory.createNewMultiPlayerSetupPresenter(getActivity(), this, mapId); + protected MapSetupViewModel createViewModel() { + viewModel = ViewModelProviders.of(this, new NewMultiPlayerSetupViewModel.Factory(getActivity(), mapId)).get(NewMultiPlayerSetupViewModel.class); + return viewModel; } @AfterViews diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/NewMultiPlayerSetupViewModel.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/NewMultiPlayerSetupViewModel.java new file mode 100644 index 0000000000..2776110bc0 --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/NewMultiPlayerSetupViewModel.java @@ -0,0 +1,161 @@ +package jsettlers.main.android.mainmenu.gamesetup; + +import android.app.Activity; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProvider; + +import java.util.List; + +import jsettlers.common.menu.IJoinPhaseMultiplayerGameConnector; +import jsettlers.common.menu.IMultiplayerListener; +import jsettlers.common.menu.IMultiplayerPlayer; +import jsettlers.common.menu.IStartingGame; +import jsettlers.common.utils.collections.ChangingList; +import jsettlers.common.utils.collections.IChangingListListener; +import jsettlers.logic.map.loading.MapLoader; +import jsettlers.main.android.core.AndroidPreferences; +import jsettlers.main.android.core.GameStarter; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.PlayerSlotPresenter; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.ReadyListener; + +/** + * Created by Tom Pratt on 07/10/2017. + */ + +public class NewMultiPlayerSetupViewModel extends MapSetupViewModel implements IMultiplayerListener, IChangingListListener, ReadyListener { + + private final GameStarter gameStarter; + private final AndroidPreferences androidPreferences; + private final IJoinPhaseMultiplayerGameConnector connector; + private final MapLoader mapLoader; + + public NewMultiPlayerSetupViewModel(GameStarter gameStarter, AndroidPreferences androidPreferences, IJoinPhaseMultiplayerGameConnector connector, MapLoader mapLoader) { + super(gameStarter, mapLoader); + this.gameStarter = gameStarter; + this.androidPreferences = androidPreferences; + this.connector = connector; + this.mapLoader = mapLoader; + + connector.setMultiplayerListener(this); + connector.getPlayers().setListener(this); + + updateSlots(); + } + + @Override + public void startGame() { + connector.startGame(); + } + + @Override + protected void abort() { + super.abort(); + connector.abort(); + } + + /** + * IMultiplayerListener implementation + */ + @Override + public void gameAborted() { + gameStarter.setJoinPhaseMultiPlayerConnector(null); + // TODO pop + } + + @Override + public void gameIsStarting(IStartingGame game) { + gameStarter.setJoinPhaseMultiPlayerConnector(null); + gameStarter.setStartingGame(game); + showMapEvent.postValue(null); + } + + /** + * ChangingListListener implementation + */ + @Override + public void listChanged(ChangingList list) { + updateSlots(); + if (playerSlots.getValue() != null) { + playerSlots.postValue(playerSlots.getValue()); + } + // updateViewItems(); // trigger a notify data set changed for now. Probably want to update the view more dynamically at some point + } + + /** + * ReadyListener implementation + */ + @Override + public void readyChanged(boolean ready) { + connector.setReady(ready); + } + + + + + + private void updateSlots() { + List players = connector.getPlayers().getItems(); + int numberOfConnectedPlayers = players.size(); + + for (int i = 0; i < playerSlotPresenters.size(); i++) { + PlayerSlotPresenter playerSlotPresenter = playerSlotPresenters.get(i); + + if (i < numberOfConnectedPlayers) { + setHumanSlotPlayerTypes(playerSlotPresenter); + + IMultiplayerPlayer multiplayerPlayer = players.get(i); + playerSlotPresenter.setName(multiplayerPlayer.getName()); + playerSlotPresenter.setReady(multiplayerPlayer.isReady()); + playerSlotPresenter.setShowReadyControl(true); + + boolean isMe = multiplayerPlayer.getId().equals(androidPreferences.getPlayerId()); + + if (isMe) { + playerSlotPresenter.setControlsEnabled(true); + playerSlotPresenter.setReadyListener(this); + } else { + playerSlotPresenter.setControlsEnabled(false); + playerSlotPresenter.setReadyListener(null); + } + } else { + setComputerSlotPlayerTypes(playerSlotPresenter); + playerSlotPresenter.setName("Computer " + i); + playerSlotPresenter.setShowReadyControl(false); + playerSlotPresenter.setControlsEnabled(true); + playerSlotPresenter.setReadyListener(null); + } + } + } + + + + /** + * ViewModel factory + */ + public static class Factory implements ViewModelProvider.Factory { + + private final Activity activity; + private final String mapId; + + public Factory(Activity activity, String mapId) { + this.activity = activity; + this.mapId = mapId; + } + + @Override + public T create(Class modelClass) { + GameStarter gameStarter = (GameStarter) activity.getApplication(); + MapLoader mapLoader = gameStarter.getMapList().getMapById(mapId); + IJoinPhaseMultiplayerGameConnector joinPhaseMultiplayerGameConnector = gameStarter.getJoinPhaseMultiplayerConnector(); + + if (joinPhaseMultiplayerGameConnector == null) { + throw new MultiPlayerConnectorUnavailableException(); + } + + if (modelClass == NewMultiPlayerSetupViewModel.class) { + return (T) new NewMultiPlayerSetupViewModel(gameStarter, new AndroidPreferences(activity), joinPhaseMultiplayerGameConnector, mapLoader); + } + throw new RuntimeException("NewMultiPlayerSetupViewModel.Factory doesn't know how to create a: " + modelClass.toString()); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsDistributionFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/NewSinglePlayerSetupFragment.java similarity index 66% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsDistributionFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/NewSinglePlayerSetupFragment.java index 16c2c0b0f5..1cbedadde2 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/gameplay/ui/fragments/menus/goods/GoodsDistributionFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/NewSinglePlayerSetupFragment.java @@ -13,21 +13,27 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.gameplay.ui.fragments.menus.goods; +package jsettlers.main.android.mainmenu.gamesetup; + +import android.arch.lifecycle.ViewModelProviders; +import android.support.v4.app.Fragment; import org.androidannotations.annotations.EFragment; import jsettlers.main.android.R; -import android.support.v4.app.Fragment; +@EFragment(R.layout.fragment_new_single_player_setup) +public class NewSinglePlayerSetupFragment extends MapSetupFragment { -/** - * Created by tompr on 24/11/2016. - */ + private NewSinglePlayerSetupViewModel viewModel; + + public static Fragment create(String mapId) { + return NewSinglePlayerSetupFragment_.builder().mapId(mapId).build(); + } -@EFragment(R.layout.menu_goods_distribution) -public class GoodsDistributionFragment extends Fragment { - public static GoodsDistributionFragment newInstance() { - return new GoodsDistributionFragment_(); + @Override + protected MapSetupViewModel createViewModel() { + viewModel = ViewModelProviders.of(this, new NewSinglePlayerSetupViewModel.Factory(getActivity(), mapId)).get(NewSinglePlayerSetupViewModel.class); + return viewModel; } -} +} \ No newline at end of file diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/NewSinglePlayerSetupViewModel.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/NewSinglePlayerSetupViewModel.java new file mode 100644 index 0000000000..fe4dafde61 --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/NewSinglePlayerSetupViewModel.java @@ -0,0 +1,109 @@ +package jsettlers.main.android.mainmenu.gamesetup; + +import android.app.Activity; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProvider; + +import java.util.Arrays; +import java.util.List; + +import java8.util.Optional; +import jsettlers.common.ai.EPlayerType; +import jsettlers.logic.map.loading.MapLoader; +import jsettlers.logic.player.PlayerSetting; +import jsettlers.main.JSettlersGame; +import jsettlers.main.android.core.AndroidPreferences; +import jsettlers.main.android.core.GameStarter; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.PlayerSlotPresenter; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.PlayerType; + +import static java8.util.stream.StreamSupport.stream; + +/** + * Created by Tom Pratt on 07/10/2017. + */ + +public class NewSinglePlayerSetupViewModel extends MapSetupViewModel { + + private final GameStarter gameStarter; + private final AndroidPreferences androidPreferences; + private final MapLoader mapLoader; + + + public NewSinglePlayerSetupViewModel(GameStarter gameStarter, AndroidPreferences androidPreferences, MapLoader mapLoader) { + super(gameStarter, mapLoader); + this.gameStarter = gameStarter; + this.androidPreferences = androidPreferences; + this.mapLoader = mapLoader; + + updateHumanPlayerSlot(); + } + + @Override + public void startGame() { + int maxPlayers = mapLoader.getMaxPlayers(); + + List playerSlotPresenters = Arrays.asList(getPlayerSlots().getValue()); + PlayerSetting[] playerSettings = new PlayerSetting[maxPlayers]; + byte humanPlayerId = playerSlotPresenters.get(0).getPlayerId(); + + for (int i = 0; i < maxPlayers; i++) { + final int position = i; + + Optional player = stream(playerSlotPresenters) + .filter(playerSlotPresenter -> playerSlotPresenter.getStartPosition().asByte() == position) + .findFirst(); + + if (player.isPresent()) { + playerSettings[position] = player.get().getPlayerSettings(); + } else { + playerSettings[position] = new PlayerSetting(); + } + } + + JSettlersGame game = new JSettlersGame(mapLoader, 4711L, humanPlayerId, playerSettings); + + gameStarter.setStartingGame(game.start()); + showMapEvent.call(); + } + + private void updateHumanPlayerSlot() { + PlayerSlotPresenter humanPlayerSlot = playerSlotPresenters.get(0); + humanPlayerSlot.setName(androidPreferences.getPlayerName()); + humanPlayerSlot.setPossiblePlayerTypes(new PlayerType[] { + new PlayerType(EPlayerType.HUMAN), + new PlayerType(EPlayerType.AI_VERY_HARD), + new PlayerType(EPlayerType.AI_HARD), + new PlayerType(EPlayerType.AI_EASY), + new PlayerType(EPlayerType.AI_VERY_EASY) + }); + humanPlayerSlot.setPlayerType(new PlayerType(EPlayerType.HUMAN)); + } + + + + /** + * ViewModel factory + */ + public static class Factory implements ViewModelProvider.Factory { + + private final Activity activity; + private final String mapId; + + public Factory(Activity activity, String mapId) { + this.activity = activity; + this.mapId = mapId; + } + + @Override + public T create(Class modelClass) { + GameStarter gameStarter = (GameStarter) activity.getApplication(); + MapLoader mapLoader = gameStarter.getMapList().getMapById(mapId); + + if (modelClass == NewSinglePlayerSetupViewModel.class) { + return (T) new NewSinglePlayerSetupViewModel(gameStarter, new AndroidPreferences(activity), mapLoader); + } + throw new RuntimeException("NewSinglePlayerSetupViewModel.Factory doesn't know how to create a: " + modelClass.toString()); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/Peacetime.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/Peacetime.java similarity index 96% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/Peacetime.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/Peacetime.java index 9a58b0f8da..60cf66e8d7 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/Peacetime.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/Peacetime.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.presenters.setup; +package jsettlers.main.android.mainmenu.gamesetup; /** * Created by tompr on 24/02/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/PlayerCount.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/PlayerCount.java similarity index 96% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/PlayerCount.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/PlayerCount.java index e8156866d4..7abe6016a6 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/PlayerCount.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/PlayerCount.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.presenters.setup; +package jsettlers.main.android.mainmenu.gamesetup; /** * Created by tompr on 24/02/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/PlayerSlotView.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/PlayerSlotView.java similarity index 82% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/PlayerSlotView.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/PlayerSlotView.java index e8899ae530..3127f24618 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/PlayerSlotView.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/PlayerSlotView.java @@ -13,12 +13,12 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.views; +package jsettlers.main.android.mainmenu.gamesetup; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.Civilisation; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.PlayerType; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.StartPosition; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.Team; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.Civilisation; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.PlayerType; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.StartPosition; +import jsettlers.main.android.mainmenu.gamesetup.playeritem.Team; /** * Created by tompr on 18/02/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/StartResources.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/StartResources.java similarity index 96% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/StartResources.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/StartResources.java index db9b24b266..32503bb7e6 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/StartResources.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/StartResources.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.presenters.setup; +package jsettlers.main.android.mainmenu.gamesetup; import jsettlers.graphics.localization.Labels; import jsettlers.logic.map.loading.EMapStartResources; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/Civilisation.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/Civilisation.java similarity index 95% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/Civilisation.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/Civilisation.java index 72dd8aaa1f..3320c00b75 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/Civilisation.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/Civilisation.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.presenters.setup.playeritem; +package jsettlers.main.android.mainmenu.gamesetup.playeritem; import jsettlers.common.player.ECivilisation; import jsettlers.graphics.localization.Labels; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/PlayerSlotPresenter.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/PlayerSlotPresenter.java similarity index 97% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/PlayerSlotPresenter.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/PlayerSlotPresenter.java index 672a2acd47..1f17ff3659 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/PlayerSlotPresenter.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/PlayerSlotPresenter.java @@ -13,10 +13,10 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.presenters.setup.playeritem; +package jsettlers.main.android.mainmenu.gamesetup.playeritem; import jsettlers.logic.player.PlayerSetting; -import jsettlers.main.android.mainmenu.views.PlayerSlotView; +import jsettlers.main.android.mainmenu.gamesetup.PlayerSlotView; /** * Created by tompr on 18/02/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/PlayerType.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/PlayerType.java similarity index 95% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/PlayerType.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/PlayerType.java index 0cce796a2f..abe4be0aea 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/PlayerType.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/PlayerType.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.presenters.setup.playeritem; +package jsettlers.main.android.mainmenu.gamesetup.playeritem; import jsettlers.common.ai.EPlayerType; import jsettlers.graphics.localization.Labels; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/PositionChangedListener.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/PositionChangedListener.java similarity index 94% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/PositionChangedListener.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/PositionChangedListener.java index ee70d8af35..fd594047ac 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/PositionChangedListener.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/PositionChangedListener.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.presenters.setup.playeritem; +package jsettlers.main.android.mainmenu.gamesetup.playeritem; /** * Created by tompr on 24/02/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/ReadyListener.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/ReadyListener.java similarity index 94% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/ReadyListener.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/ReadyListener.java index 2fa74bed28..728aa331b3 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/ReadyListener.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/ReadyListener.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.presenters.setup.playeritem; +package jsettlers.main.android.mainmenu.gamesetup.playeritem; /** * Created by tompr on 01/03/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/StartPosition.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/StartPosition.java similarity index 95% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/StartPosition.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/StartPosition.java index f28f0a22ac..f056d2fe2b 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/StartPosition.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/StartPosition.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.presenters.setup.playeritem; +package jsettlers.main.android.mainmenu.gamesetup.playeritem; /** * Created by tompr on 24/02/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/Team.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/Team.java similarity index 95% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/Team.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/Team.java index 5ffdb27b3e..f73483b590 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/playeritem/Team.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/gamesetup/playeritem/Team.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.presenters.setup.playeritem; +package jsettlers.main.android.mainmenu.gamesetup.playeritem; /** * Created by tompr on 24/02/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/dialogs/DirectoryPickerDialog.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/home/DirectoryPickerDialog.java similarity index 79% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/dialogs/DirectoryPickerDialog.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/home/DirectoryPickerDialog.java index 145ac0daf5..35227d1a4a 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/dialogs/DirectoryPickerDialog.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/home/DirectoryPickerDialog.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.ui.dialogs; +package jsettlers.main.android.mainmenu.home; import java.io.File; import java.io.IOException; @@ -24,31 +24,32 @@ import org.androidannotations.annotations.EFragment; import org.androidannotations.annotations.UiThread; -import jsettlers.common.resources.SettlersFolderChecker; -import jsettlers.main.android.R; -import jsettlers.main.android.core.resources.scanner.AndroidResourcesLoader; - import android.app.Dialog; import android.content.Context; +import android.content.DialogInterface; import android.os.Bundle; import android.os.Environment; import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; import android.support.v7.app.AlertDialog; +import android.view.LayoutInflater; +import android.view.View; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; +import android.widget.ProgressBar; + +import jsettlers.common.resources.SettlersFolderChecker; +import jsettlers.main.android.R; @EFragment public class DirectoryPickerDialog extends DialogFragment { @Bean DirectoryAdapter directoryAdapter; - @Bean - AndroidResourcesLoader androidResourcesLoader; public interface Listener { - void onDirectorySelected(); + void onDirectorySelected(File resourceDirectory); } public static DirectoryPickerDialog newInstance() { @@ -64,21 +65,37 @@ public void onCreate(Bundle savedInstanceState) { @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - ListView listView = new ListView(getActivity()); + LayoutInflater layoutInflater = LayoutInflater.from(getActivity()); + View view = layoutInflater.inflate(R.layout.dialog_directory_picker, null); + + ProgressBar progressBar = view.findViewById(R.id.progressBar); + + ListView listView = view.findViewById(R.id.listView); listView.setAdapter(directoryAdapter); listView.setOnItemClickListener((arg0, arg1, position, arg3) -> { directoryAdapter.positionSelected(position); setButtonState(); }); - return new AlertDialog.Builder(getActivity()) + AlertDialog alertDialog = new AlertDialog.Builder(getActivity()) .setTitle(R.string.resource_selection_dialog_title) - .setView(listView) - .setPositiveButton(R.string.ok, (dialog, which) -> { - androidResourcesLoader.setResourcesDirectory(directoryAdapter.getCurrentDirectory().getAbsolutePath()); - ((Listener) getParentFragment()).onDirectorySelected(); - }) + .setView(view) + .setPositiveButton(R.string.ok, null) .create(); + + alertDialog.setOnShowListener(dialog -> { + Button button = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE); + + button.setOnClickListener(v -> { + setCancelable(false); + listView.setEnabled(false); + button.setEnabled(false); + progressBar.setVisibility(View.VISIBLE); + ((Listener) getParentFragment()).onDirectorySelected(directoryAdapter.getCurrentDirectory()); + }); + }); + + return alertDialog; } @Override diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/home/MainMenuFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/home/MainMenuFragment.java new file mode 100644 index 0000000000..1f61aa666d --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/home/MainMenuFragment.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2017 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package jsettlers.main.android.mainmenu.home; + +import java.io.File; + +import org.androidannotations.annotations.AfterViews; +import org.androidannotations.annotations.BindingObject; +import org.androidannotations.annotations.Click; +import org.androidannotations.annotations.DataBound; +import org.androidannotations.annotations.EFragment; +import org.androidannotations.annotations.OptionsMenu; +import org.androidannotations.annotations.ViewById; + +import android.Manifest; +import android.arch.lifecycle.ViewModelProviders; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.Toolbar; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.LinearLayout; + +import jsettlers.main.android.R; +import jsettlers.main.android.core.ui.FragmentUtil; +import jsettlers.main.android.databinding.FragmentMainMenuBinding; +import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; +import jsettlers.main.android.mainmenu.settings.SettingsActivity_; + +/** + * A simple {@link Fragment} subclass. + */ +@DataBound +@EFragment(R.layout.fragment_main_menu) +@OptionsMenu(R.menu.fragment_mainmenu) +public class MainMenuFragment extends Fragment implements DirectoryPickerDialog.Listener { + private static final int REQUEST_CODE_PERMISSION_STORAGE = 10; + private static final String TAG_RESOURCE_DIALOG = "resourcedialog"; + + private MainMenuViewModel viewModel; + private MainMenuNavigator mainMenuNavigator; + + @ViewById(R.id.linearLayout_main) + LinearLayout mainLinearLayout; + @ViewById(R.id.cardView_resume) + View resumeView; + @ViewById(R.id.cardView_resourcePicker) + View resourcePickerView; + @ViewById(R.id.button_pause) + Button pauseButton; + @ViewById(R.id.button_quit) + Button quitButton; + @ViewById(R.id.button_new_single_player_game) + Button newSinglePlayerButton; + @ViewById(R.id.button_load_single_player_game) + Button loadSinglePlayerButton; + @ViewById(R.id.button_new_multi_player_game) + Button newMultiPlayerButton; + @ViewById(R.id.button_join_multi_player_game) + Button joinMultiPlayerButton; + @ViewById(R.id.toolbar) + Toolbar toolbar; + + @BindingObject + FragmentMainMenuBinding binding; + + public static MainMenuFragment create() { + return new MainMenuFragment_(); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mainMenuNavigator = (MainMenuNavigator)getActivity(); + viewModel = ViewModelProviders.of(this, new MainMenuViewModel.Factory(getActivity().getApplication())).get(MainMenuViewModel.class); + } + + @AfterViews + public void afterViews() { + FragmentUtil.setActionBar(this, toolbar); + toolbar.setTitle(R.string.app_name); + binding.setViewmodel(viewModel); + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + viewModel.getResumeState().observe(this, this::updateResumeView); + viewModel.getAreResourcesLoaded().observe(this, this::updateResourceView); + viewModel.getAreResourcesLoaded().observe(this, newSinglePlayerButton::setEnabled); + viewModel.getAreResourcesLoaded().observe(this, loadSinglePlayerButton::setEnabled); + viewModel.getAreResourcesLoaded().observe(this, newMultiPlayerButton::setEnabled); + viewModel.getAreResourcesLoaded().observe(this, joinMultiPlayerButton::setEnabled); + viewModel.getAreResourcesLoaded().observe(this, this::dismissResourceDialog); + viewModel.getShowSinglePlayer().observe(this, z -> mainMenuNavigator.showNewSinglePlayerPicker()); + viewModel.getShowLoadSinglePlayer().observe(this, z -> mainMenuNavigator.showLoadSinglePlayerPicker()); + viewModel.getShowMultiplayerPlayer().observe(this, z -> mainMenuNavigator.showNewMultiPlayerPicker()); + viewModel.getShowJoinMultiplayerPlayer().observe(this, z -> mainMenuNavigator.showJoinMultiPlayerPicker()); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_item_settings: + SettingsActivity_.intent(this).start(); + break; + default: + return super.onOptionsItemSelected(item); + } + return true; + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + switch (requestCode) { + case REQUEST_CODE_PERMISSION_STORAGE: + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + showDirectoryPicker(); + } + break; + } + } + + + /** + * DirectoryPickerDialog.Listener implementation + */ + @Override + public void onDirectorySelected(File resourceDirectory) { + viewModel.resourceDirectoryChosen(resourceDirectory); + } + + + @Click(R.id.button_resources) + void showDirectoryPicker() { + if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + requestPermissions(new String[] { Manifest.permission.READ_EXTERNAL_STORAGE }, REQUEST_CODE_PERMISSION_STORAGE); + } else { + DirectoryPickerDialog.newInstance().show(getChildFragmentManager(), TAG_RESOURCE_DIALOG); + } + } + + @Click(R.id.cardView_resume) + void resumeView() { + mainMenuNavigator.resumeGame(); + } + + private void dismissResourceDialog(Boolean areResourcesLoaded) { + if (areResourcesLoaded) { + DialogFragment dialog = (DialogFragment) getChildFragmentManager().findFragmentByTag(TAG_RESOURCE_DIALOG); + if (dialog != null) { + dialog.dismiss(); + } + } + } + + private void updateResumeView(MainMenuViewModel.ResumeViewState resumeViewState) { + if (resumeViewState == null){ + resumeView.setVisibility(View.GONE); + } else { + pauseButton.setText(resumeViewState.isPaused() ? R.string.game_menu_unpause : R.string.game_menu_pause); + quitButton.setText(resumeViewState.isConfirmQuit() ? R.string.game_menu_quit_confirm : R.string.game_menu_quit); + resumeView.setVisibility(View.VISIBLE); + } + } + + private void updateResourceView(boolean areResourcesLoaded) { + if (areResourcesLoaded) { + resourcePickerView.setVisibility(View.GONE); + } else { + resourcePickerView.setVisibility(View.VISIBLE); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/home/MainMenuViewModel.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/home/MainMenuViewModel.java new file mode 100644 index 0000000000..600924b189 --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/home/MainMenuViewModel.java @@ -0,0 +1,209 @@ +package jsettlers.main.android.mainmenu.home; + +import android.app.Application; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.MediatorLiveData; +import android.arch.lifecycle.MutableLiveData; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProvider; + +import java.io.File; + +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; +import jsettlers.main.android.core.GameManager; +import jsettlers.main.android.core.controls.GameMenu; +import jsettlers.main.android.core.resources.scanner.AndroidResourcesLoader; +import jsettlers.main.android.core.events.SingleLiveEvent; + +/** + * Created by Tom Pratt on 02/10/2017. + */ + +public class MainMenuViewModel extends ViewModel { + + private final GameManager gameManager; + private final AndroidResourcesLoader androidResourcesLoader; + + private final ResumeStateData resumeStateData = new ResumeStateData(); + private final MutableLiveData areResourcesLoaded = new MutableLiveData<>(); + private final SingleLiveEvent showSinglePlayer = new SingleLiveEvent<>(); + private final SingleLiveEvent showLoadSinglePlayer = new SingleLiveEvent<>(); + private final SingleLiveEvent showMultiplayerPlayer = new SingleLiveEvent<>(); + private final SingleLiveEvent showJoinMultiplayerPlayer = new SingleLiveEvent<>(); + + public MainMenuViewModel(GameManager gameManager, AndroidResourcesLoader androidResourcesLoader) { + this.gameManager = gameManager; + this.androidResourcesLoader = androidResourcesLoader; + + areResourcesLoaded.setValue(androidResourcesLoader.setup()); + } + + public LiveData getResumeState() { + return resumeStateData; + } + + public MutableLiveData getAreResourcesLoaded() { + return areResourcesLoaded; + } + + public LiveData getShowSinglePlayer() { + return showSinglePlayer; + } + + public LiveData getShowLoadSinglePlayer() { + return showLoadSinglePlayer; + } + + public LiveData getShowMultiplayerPlayer() { + return showMultiplayerPlayer; + } + + public LiveData getShowJoinMultiplayerPlayer() { + return showJoinMultiplayerPlayer; + } + + public void resourceDirectoryChosen(File resourceDirectory) { + androidResourcesLoader.setResourcesDirectory(resourceDirectory.getAbsolutePath()); + + Disposable resourceSetupSubscription = androidResourcesLoader.setupSingle() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(() -> { + areResourcesLoaded.postValue(true); + }); + } + public void quitSelected() { + if (gameManager.getGameMenu().getGameState().getValue() == GameMenu.GameState.CONFIRM_QUIT) { + gameManager.getGameMenu().quitConfirm(); + } else { + gameManager.getGameMenu().quit(); + } + } + + public void pauseSelected() { + if (gameManager.getGameMenu().isPausedState().getValue()) { + gameManager.getGameMenu().unPause(); + } else { + gameManager.getGameMenu().pause(); + } + } + + public void newSinglePlayerSelected() { + if (areResourcesLoaded.getValue() == Boolean.TRUE) { + showSinglePlayer.call(); + } + } + + public void loadSinglePlayerSelected() { + if (areResourcesLoaded.getValue() == Boolean.TRUE) { + showLoadSinglePlayer.call(); + } + } + + public void newMultiPlayerSelected() { + if (areResourcesLoaded.getValue() == Boolean.TRUE) { + showMultiplayerPlayer.call(); + } + } + + public void joinMultiPlayerSelected() { + if (areResourcesLoaded.getValue() == Boolean.TRUE) { + showJoinMultiplayerPlayer.call(); + } + } + + + /** + * ViewState for resume state + */ + public static class ResumeViewState { + private final boolean isPaused; + private final boolean confirmQuit; + + public ResumeViewState(boolean isPaused, boolean confirmQuit) { + this.isPaused = isPaused; + this.confirmQuit = confirmQuit; + } + + public boolean isPaused() { + return isPaused; + } + + public boolean isConfirmQuit() { + return confirmQuit; + } + } + + + /** + * LiveData for resume state + * It monitors the current GameManager and relays state changes + */ + private class ResumeStateData extends MediatorLiveData { + private GameMenu gameMenu; + + @Override + protected void onActive() { + super.onActive(); + if (gameManager.isGameInProgress()) { + GameMenu newGameMenu = gameManager.getGameMenu(); + + if (gameMenu == newGameMenu) { + return; + } + + if (gameMenu != null) { + removeSource(gameMenu.isPausedState()); + removeSource(gameMenu.getGameState()); + } + + gameMenu = newGameMenu; + if (gameMenu != null) { + addSource(gameMenu.isPausedState(), paused -> update()); + addSource(gameMenu.getGameState(), state -> update()); + } else { + setValue(null); + } + } else { + setValue(null); + gameMenu = null; + } + } + + private void update() { + if (gameMenu.getGameState().getValue() == GameMenu.GameState.QUITTED) { + setValue(null); + } else { + boolean paused = gameMenu.isPausedState().getValue(); + boolean confirmQuit = gameMenu.getGameState().getValue() == GameMenu.GameState.CONFIRM_QUIT; + setValue(new ResumeViewState(paused, confirmQuit)); + } + } + } + + /** + * ViewModel factory + */ + public static class Factory implements ViewModelProvider.Factory { + + private final Application application; + private final GameManager gameManager; + + public Factory(Application application) { + this.application = application; + gameManager = (GameManager)application; + } + + @Override + public T create(Class modelClass) { + if (modelClass == MainMenuViewModel.class) { + return (T) new MainMenuViewModel( + gameManager, + new AndroidResourcesLoader(application)); + } + throw new RuntimeException("MainMenuViewModel.Factory doesn't know how to create a: " + modelClass.toString()); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/picker/JoinMultiPlayerPickerFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/JoinMultiPlayerPickerFragment.java similarity index 64% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/picker/JoinMultiPlayerPickerFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/JoinMultiPlayerPickerFragment.java index 60fe61074d..7161c6a981 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/picker/JoinMultiPlayerPickerFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/JoinMultiPlayerPickerFragment.java @@ -13,29 +13,9 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.ui.fragments.picker; - -import java.util.List; -import java.util.concurrent.Semaphore; - -import org.androidannotations.annotations.AfterViews; -import org.androidannotations.annotations.EFragment; -import org.androidannotations.annotations.UiThread; -import org.androidannotations.annotations.ViewById; - -import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration; - -import jsettlers.common.menu.IJoinableGame; -import jsettlers.common.menu.IMapDefinition; -import jsettlers.main.android.R; -import jsettlers.main.android.core.ui.FragmentUtil; -import jsettlers.main.android.core.ui.NoChangeItemAnimator; -import jsettlers.main.android.core.ui.PreviewImageConverter; -import jsettlers.main.android.mainmenu.factories.PresenterFactory; -import jsettlers.main.android.mainmenu.presenters.picker.JoinMultiPlayerPickerPresenter; -import jsettlers.main.android.mainmenu.ui.dialogs.JoiningGameProgressDialog; -import jsettlers.main.android.mainmenu.views.JoinMultiPlayerPickerView; +package jsettlers.main.android.mainmenu.mappicker; +import android.arch.lifecycle.ViewModelProviders; import android.graphics.Bitmap; import android.os.Bundle; import android.support.annotation.Nullable; @@ -47,16 +27,32 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; + +import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration; + +import org.androidannotations.annotations.AfterViews; +import org.androidannotations.annotations.EFragment; +import org.androidannotations.annotations.ViewById; + +import java.util.concurrent.Semaphore; + import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.observers.DisposableSingleObserver; import io.reactivex.schedulers.Schedulers; +import jsettlers.common.menu.IJoinableGame; +import jsettlers.common.menu.IMapDefinition; +import jsettlers.main.android.R; +import jsettlers.main.android.core.ui.FragmentUtil; +import jsettlers.main.android.core.ui.NoChangeItemAnimator; +import jsettlers.main.android.core.resources.PreviewImageConverter; +import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; /** * Created by tompr on 21/01/2017. */ @EFragment(R.layout.fragment_map_picker_join_multiplayer) -public class JoinMultiPlayerPickerFragment extends Fragment implements JoinMultiPlayerPickerView { +public class JoinMultiPlayerPickerFragment extends Fragment{ private static final String TAG_JOINING_PROGRESS_DIALOG = "joingingprogress"; public static JoinMultiPlayerPickerFragment create() { @@ -70,74 +66,57 @@ public static JoinMultiPlayerPickerFragment create() { @ViewById(R.id.toolbar) Toolbar toolbar; - JoinMultiPlayerPickerPresenter presenter; + JoinMultiPlayerPickerViewModel viewModel; JoinableGamesAdapter adapter; - boolean isSaving = false; - @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - presenter = PresenterFactory.createJoinMultiPlayerPickerPresenter(getActivity(), this); + viewModel = ViewModelProviders.of(this, new JoinMultiPlayerPickerViewModel.Factory(getActivity())).get(JoinMultiPlayerPickerViewModel.class); } @AfterViews void setupToolbar() { FragmentUtil.setActionBar(this, toolbar); - presenter.initView(); // will need to remove this if this class ends up using the general Picker base class, because its already called there + toolbar.setTitle(R.string.join_multi_player_game); } @Override - public void onResume() { - super.onResume(); - getActivity().setTitle(R.string.join_multi_player_game); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - isSaving = true; - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - presenter.dispose(); - } - - @Override - public void onDetach() { - super.onDetach(); - if (isRemoving() && !isSaving) { - presenter.viewFinished(); - } - } + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + viewModel.getShowNoGamesMessage().observe(this, showMessage -> searchingForGamesView.setVisibility(showMessage ? View.VISIBLE : View.GONE)); + + viewModel.getMapSelectedEvent().observe(this, mapId -> { + MainMenuNavigator mainMenuNavigator = (MainMenuNavigator) getActivity(); + mainMenuNavigator.showJoinMultiPlayerSetup(mapId); + }); + + viewModel.getJoinableGames().observe(this, joinableGames -> { + if (adapter == null) { + adapter = new JoinableGamesAdapter(joinableGames); + } - /** - * JoinMultiPlayerPickerView implementation - * - * @param joinableGames - */ - @Override - @UiThread - public void updateJoinableGames(List joinableGames) { - if (adapter == null) { - adapter = new JoinableGamesAdapter(joinableGames); - } + if (recyclerView.getAdapter() == null) { + recyclerView.setHasFixedSize(true); + recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); + recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build()); + recyclerView.setItemAnimator(new NoChangeItemAnimator()); + recyclerView.setAdapter(adapter); + } - if (recyclerView.getAdapter() == null) { - recyclerView.setHasFixedSize(true); - recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); - recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build()); - recyclerView.setItemAnimator(new NoChangeItemAnimator()); - recyclerView.setAdapter(adapter); - } + adapter.setItems(joinableGames); + }); - adapter.setItems(joinableGames); + viewModel.getJoiningState().observe(this, joiningViewState -> { + if (joiningViewState == null) { + dismissJoiningProgress(); + } else { + setJoiningProgress(joiningViewState.getState(), joiningViewState.getProgress()); + } + }); } - @Override - public void setJoiningProgress(String stateString, int progressPercentage) { + private void setJoiningProgress(String stateString, int progressPercentage) { JoiningGameProgressDialog joiningProgressDialog = (JoiningGameProgressDialog) getChildFragmentManager().findFragmentByTag(TAG_JOINING_PROGRESS_DIALOG); if (joiningProgressDialog == null) { JoiningGameProgressDialog.create(stateString, progressPercentage).show(getChildFragmentManager(), TAG_JOINING_PROGRESS_DIALOG); @@ -146,44 +125,27 @@ public void setJoiningProgress(String stateString, int progressPercentage) { } } - @Override - public void dismissJoiningProgress() { + private void dismissJoiningProgress() { JoiningGameProgressDialog joiningProgressDialog = (JoiningGameProgressDialog) getChildFragmentManager().findFragmentByTag(TAG_JOINING_PROGRESS_DIALOG); if (joiningProgressDialog != null) { joiningProgressDialog.dismiss(); } } - @Override - @UiThread - public void showSearchingForGamesView() { - searchingForGamesView.setVisibility(View.VISIBLE); - } - - @Override - @UiThread - public void hideSearchingForGamesView() { - searchingForGamesView.setVisibility(View.GONE); - } - - private void joinableGameSelected(IJoinableGame joinableGame) { - presenter.joinableGameSelected(joinableGame); - } - /** * RecyclerView Adapter for displaying list of maps */ private class JoinableGamesAdapter extends RecyclerView.Adapter { - private List joinableGames; + private IJoinableGame[] joinableGames; private final Semaphore limitImageLoadingSemaphore = new Semaphore(3, true); - public JoinableGamesAdapter(List joinableGames) { + public JoinableGamesAdapter(IJoinableGame[] joinableGames) { this.joinableGames = joinableGames; } @Override public int getItemCount() { - return joinableGames.size(); + return joinableGames.length; } @Override @@ -193,7 +155,7 @@ public JoinableGameHolder onCreateViewHolder(ViewGroup parent, int viewType) { itemView.setOnClickListener(view -> { int position = mapHolder.getAdapterPosition(); - joinableGameSelected(joinableGames.get(position)); + viewModel.joinableGameSelected(joinableGames[position]); }); return mapHolder; @@ -201,11 +163,11 @@ public JoinableGameHolder onCreateViewHolder(ViewGroup parent, int viewType) { @Override public void onBindViewHolder(JoinableGameHolder holder, int position) { - IJoinableGame joinableGame = joinableGames.get(position); + IJoinableGame joinableGame = joinableGames[position]; holder.bind(joinableGame); } - void setItems(List joinableGames) { + void setItems(IJoinableGame[] joinableGames) { this.joinableGames = joinableGames; notifyDataSetChanged(); } @@ -220,10 +182,10 @@ class JoinableGameHolder extends RecyclerView.ViewHolder { public JoinableGameHolder(View itemView) { super(itemView); - hostNameTextView = (TextView) itemView.findViewById(R.id.text_view_host_name); - mapNameTextView = (TextView) itemView.findViewById(R.id.text_view_map_name); - playerCountTextView = (TextView) itemView.findViewById(R.id.text_view_player_count); - mapPreviewImageView = (ImageView) itemView.findViewById(R.id.image_view_map_preview); + hostNameTextView = itemView.findViewById(R.id.text_view_host_name); + mapNameTextView = itemView.findViewById(R.id.text_view_map_name); + playerCountTextView = itemView.findViewById(R.id.text_view_player_count); + mapPreviewImageView = itemView.findViewById(R.id.image_view_map_preview); } public void bind(IJoinableGame joinableGame) { diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/JoinMultiPlayerPickerViewModel.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/JoinMultiPlayerPickerViewModel.java new file mode 100644 index 0000000000..26cc0b0151 --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/JoinMultiPlayerPickerViewModel.java @@ -0,0 +1,171 @@ +package jsettlers.main.android.mainmenu.mappicker; + +import android.app.Activity; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.MutableLiveData; +import android.arch.lifecycle.Transformations; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProvider; + +import java.util.List; + +import jsettlers.common.menu.EProgressState; +import jsettlers.common.menu.IJoinPhaseMultiplayerGameConnector; +import jsettlers.common.menu.IJoinableGame; +import jsettlers.common.menu.IJoiningGame; +import jsettlers.common.menu.IJoiningGameListener; +import jsettlers.common.menu.IMapDefinition; +import jsettlers.common.utils.collections.ChangingList; +import jsettlers.common.utils.collections.IChangingListListener; +import jsettlers.graphics.localization.Labels; +import jsettlers.main.android.core.GameStarter; +import jsettlers.main.android.core.events.SingleLiveEvent; + +import static java8.util.stream.StreamSupport.stream; + +/** + * Created by Tom Pratt on 06/10/2017. + */ + +public class JoinMultiPlayerPickerViewModel extends ViewModel implements IJoiningGameListener { + + private final GameStarter gameStarter; + private final ChangingList changingJoinableGames; + + private final JoinableGamesData joinableGames = new JoinableGamesData(); + private final SingleLiveEvent mapSelectedEvent = new SingleLiveEvent<>(); + private final MutableLiveData joiningState = new MutableLiveData<>(); + private final LiveData showNoGamesMessage; + + private IJoiningGame joiningGame; + private IMapDefinition mapDefinition; + + public JoinMultiPlayerPickerViewModel(GameStarter gameStarter, ChangingList changingJoinableGames) { + this.gameStarter = gameStarter; + this.changingJoinableGames = changingJoinableGames; + + showNoGamesMessage = Transformations.map(joinableGames, joinableGames -> joinableGames.length == 0); + } + + @Override + protected void onCleared() { + super.onCleared(); + if (joiningGame != null) { + joiningGame.setListener(null); + } + + if (gameStarter.getStartingGame() == null) { + abort(); + } + } + + /** + * IJoiningGameListener imeplementation + */ + @Override + public void joinProgressChanged(EProgressState state, float progress) { + String stateString = Labels.getProgress(state); + int progressPercentage = (int) (progress * 100); + + joiningState.postValue(new JoiningViewState(stateString, progressPercentage)); + } + + @Override + public void gameJoined(IJoinPhaseMultiplayerGameConnector connector) { + joiningGame.setListener(null); + gameStarter.setJoiningGame(null); + joiningState.postValue(null); + + gameStarter.setJoinPhaseMultiPlayerConnector(connector); + mapSelectedEvent.postValue(mapDefinition.getMapId()); + } + + public void joinableGameSelected(IJoinableGame joinableGame) { + abort(); + mapDefinition = joinableGame.getMap(); + + joiningGame = gameStarter.getMultiPlayerConnector().joinMultiplayerGame(joinableGame); + joiningGame.setListener(this); + + gameStarter.setJoiningGame(joiningGame); + } + + public LiveData getJoinableGames() { + return joinableGames; + } + + public LiveData getMapSelectedEvent() { + return mapSelectedEvent; + } + + public LiveData getShowNoGamesMessage() { + return showNoGamesMessage; + } + + public LiveData getJoiningState() { + return joiningState; + } + + private void abort() { + if (joiningGame != null) { + joiningGame.abort(); + } + gameStarter.setJoiningGame(null); + gameStarter.closeMultiPlayerConnector(); + joiningGame = null; + mapDefinition = null; + } + + + + /** + * Maps list live data + */ + class JoinableGamesData extends LiveData implements IChangingListListener { + + @Override + protected void onActive() { + super.onActive(); + changingJoinableGames.setListener(this); + setValue(sortedMaps(changingJoinableGames.getItems())); + } + + @Override + protected void onInactive() { + super.onInactive(); + changingJoinableGames.removeListener(this); + } + + @Override + public void listChanged(ChangingList list) { + postValue(sortedMaps(list.getItems())); + } + + private IJoinableGame[] sortedMaps(List items) { + return stream(items) + .toArray(IJoinableGame[]::new); + } + } + + /** + * ViewModel factory + */ + public static class Factory implements ViewModelProvider.Factory { + + private final Activity activity; + private final GameStarter gameStarter; + + public Factory(Activity activity) { + this.activity = activity; + gameStarter = (GameStarter) activity.getApplication(); + } + + @Override + public T create(Class modelClass) { + if (modelClass == JoinMultiPlayerPickerViewModel.class) { + return (T) new JoinMultiPlayerPickerViewModel(gameStarter, gameStarter.getMultiPlayerConnector().getJoinableMultiplayerGames()); + } + throw new RuntimeException("NewSinglePlayerPickerViewModel.Factory doesn't know how to create a: " + modelClass.toString()); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/dialogs/JoiningGameProgressDialog.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/JoiningGameProgressDialog.java similarity index 97% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/dialogs/JoiningGameProgressDialog.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/JoiningGameProgressDialog.java index 83f052b3c5..2ea7bcb67c 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/dialogs/JoiningGameProgressDialog.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/JoiningGameProgressDialog.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.ui.dialogs; +package jsettlers.main.android.mainmenu.mappicker; import org.androidannotations.annotations.EFragment; import org.androidannotations.annotations.FragmentArg; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/JoiningViewState.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/JoiningViewState.java new file mode 100644 index 0000000000..220dedf3cd --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/JoiningViewState.java @@ -0,0 +1,23 @@ +package jsettlers.main.android.mainmenu.mappicker; + +/** + * Created by Tom Pratt on 06/10/2017. + */ + +public class JoiningViewState { + private final String state; + private final int progress; + + public JoiningViewState(String state, int progress) { + this.state = state; + this.progress = progress; + } + + public String getState() { + return state; + } + + public int getProgress() { + return progress; + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/picker/LoadSinglePlayerPickerFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/LoadSinglePlayerPickerFragment.java similarity index 62% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/picker/LoadSinglePlayerPickerFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/LoadSinglePlayerPickerFragment.java index 2b09486680..02db662ac2 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/picker/LoadSinglePlayerPickerFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/LoadSinglePlayerPickerFragment.java @@ -13,55 +13,60 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.ui.fragments.picker; +package jsettlers.main.android.mainmenu.mappicker; + +import android.arch.lifecycle.ViewModelProviders; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.View; import org.androidannotations.annotations.EFragment; import org.androidannotations.annotations.ViewById; import jsettlers.main.android.R; -import jsettlers.main.android.mainmenu.factories.PresenterFactory; -import jsettlers.main.android.mainmenu.presenters.picker.MapPickerPresenter; -import jsettlers.main.android.mainmenu.views.LoadSinglePlayerPickerView; - -import android.support.v4.app.Fragment; -import android.view.View; +import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; /** * Created by tompr on 19/01/2017. */ @EFragment(R.layout.fragment_map_picker_load_singleplayer) -public class LoadSinglePlayerPickerFragment extends MapPickerFragment implements LoadSinglePlayerPickerView { - - @ViewById(R.id.layout_no_saved_games) - View noSavedGamesView; - +public class LoadSinglePlayerPickerFragment extends MapPickerFragment { public static Fragment newInstance() { return new LoadSinglePlayerPickerFragment_(); } - @Override - protected MapPickerPresenter createPresenter() { - return PresenterFactory.createLoadSinglePlayerPickerPresenter(getActivity(), this); - } + private LoadSinglePlayerPickerViewModel viewModel; + + @ViewById(R.id.layout_no_saved_games) + View noSavedGamesView; @Override - public void onResume() { - super.onResume(); - getActivity().setTitle(R.string.load_single_player_game); + protected MapPickerViewModel createViewModel() { + viewModel = ViewModelProviders.of(this, new LoadSinglePlayerPickerViewModel.Factory(getActivity())).get(LoadSinglePlayerPickerViewModel.class); + return viewModel; } @Override - protected boolean showMapDates() { - return true; + void setupToolbar() { + super.setupToolbar(); + toolbar.setTitle(R.string.new_single_player_game); } @Override - public void hideNoGamesView() { - noSavedGamesView.setVisibility(View.GONE); + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + viewModel.getShowNoMapsMessage().observe(this, showMessage -> noSavedGamesView.setVisibility(showMessage ? View.VISIBLE : View.GONE)); + + viewModel.getMapSelectedEvent().observe(this, mapId -> { + MainMenuNavigator mainMenuNavigator = (MainMenuNavigator)getActivity(); + mainMenuNavigator.showGame(); + }); } @Override - public void showNoGamesView() { - noSavedGamesView.setVisibility(View.VISIBLE); + protected boolean showMapDates() { + return true; } } diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/LoadSinglePlayerPickerViewModel.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/LoadSinglePlayerPickerViewModel.java new file mode 100644 index 0000000000..c698235ee2 --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/LoadSinglePlayerPickerViewModel.java @@ -0,0 +1,73 @@ +package jsettlers.main.android.mainmenu.mappicker; + +import android.app.Activity; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.Transformations; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProvider; + +import jsettlers.common.utils.collections.ChangingList; +import jsettlers.logic.map.loading.MapLoader; +import jsettlers.logic.map.loading.newmap.MapFileHeader; +import jsettlers.logic.player.PlayerSetting; +import jsettlers.main.JSettlersGame; +import jsettlers.main.android.core.GameStarter; +import jsettlers.main.android.core.events.SingleLiveEvent; + +/** + * Created by Tom Pratt on 06/10/2017. + */ + +public class LoadSinglePlayerPickerViewModel extends MapPickerViewModel { + + private final GameStarter gameStarter; + private final SingleLiveEvent mapSelectedEvent = new SingleLiveEvent<>(); + private final LiveData showNoMapsMessage; + + public LoadSinglePlayerPickerViewModel(GameStarter gameStarter, ChangingList changingMaps) { + super(gameStarter, changingMaps); + this.gameStarter = gameStarter; + + showNoMapsMessage = Transformations.map(getMaps(), maps -> maps.length == 0); + } + + @Override + public void selectMap(MapLoader map) { + MapFileHeader mapFileHeader = map.getFileHeader(); + PlayerSetting[] playerSettings = mapFileHeader.getPlayerSettings(); + byte playerId = mapFileHeader.getPlayerId(); + JSettlersGame game = new JSettlersGame(map, 4711L, playerId, playerSettings); + gameStarter.setStartingGame(game.start()); + mapSelectedEvent.call(); + } + + public LiveData getMapSelectedEvent() { + return mapSelectedEvent; + } + + public LiveData getShowNoMapsMessage() { + return showNoMapsMessage; + } + + /** + * ViewModel factory + */ + public static class Factory implements ViewModelProvider.Factory { + + private final Activity activity; + private final GameStarter gameStarter; + + public Factory(Activity activity) { + this.activity = activity; + gameStarter = (GameStarter) activity.getApplication(); + } + + @Override + public T create(Class modelClass) { + if (modelClass == LoadSinglePlayerPickerViewModel.class) { + return (T) new LoadSinglePlayerPickerViewModel(gameStarter, gameStarter.getMapList().getSavedMaps()); + } + throw new RuntimeException("NewSinglePlayerPickerViewModel.Factory doesn't know how to create a: " + modelClass.toString()); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/picker/MapPickerFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/MapPickerFragment.java similarity index 70% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/picker/MapPickerFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/MapPickerFragment.java index 00dd286e55..0f074460fa 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/picker/MapPickerFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/MapPickerFragment.java @@ -13,29 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.ui.fragments.picker; - -import java.text.SimpleDateFormat; -import java.util.List; -import java.util.Locale; -import java.util.concurrent.Semaphore; - -import org.androidannotations.annotations.AfterViews; -import org.androidannotations.annotations.EFragment; -import org.androidannotations.annotations.UiThread; -import org.androidannotations.annotations.ViewById; - -import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration; - -import jsettlers.common.menu.IMapDefinition; -import jsettlers.graphics.localization.Labels; -import jsettlers.logic.map.loading.MapLoader; -import jsettlers.main.android.R; -import jsettlers.main.android.core.ui.FragmentUtil; -import jsettlers.main.android.core.ui.NoChangeItemAnimator; -import jsettlers.main.android.core.ui.PreviewImageConverter; -import jsettlers.main.android.mainmenu.presenters.picker.MapPickerPresenter; -import jsettlers.main.android.mainmenu.views.MapPickerView; +package jsettlers.main.android.mainmenu.mappicker; import android.graphics.Bitmap; import android.os.Bundle; @@ -48,16 +26,34 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; + +import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration; + +import org.androidannotations.annotations.AfterViews; +import org.androidannotations.annotations.EFragment; +import org.androidannotations.annotations.ViewById; + +import java.text.SimpleDateFormat; +import java.util.Locale; +import java.util.concurrent.Semaphore; + import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.observers.DisposableSingleObserver; import io.reactivex.schedulers.Schedulers; +import jsettlers.common.menu.IMapDefinition; +import jsettlers.graphics.localization.Labels; +import jsettlers.logic.map.loading.MapLoader; +import jsettlers.main.android.R; +import jsettlers.main.android.core.ui.FragmentUtil; +import jsettlers.main.android.core.ui.NoChangeItemAnimator; +import jsettlers.main.android.core.resources.PreviewImageConverter; /** * A simple {@link Fragment} subclass. */ @EFragment(R.layout.fragment_map_picker) -public abstract class MapPickerFragment extends Fragment implements MapPickerView { +public abstract class MapPickerFragment extends Fragment { private static final SimpleDateFormat dateFormat = new SimpleDateFormat(Labels.getString("date.date-only"), Locale.getDefault()); @ViewById(R.id.recycler_view) @@ -65,67 +61,42 @@ public abstract class MapPickerFragment extends Fragment implements MapPickerVie @ViewById(R.id.toolbar) Toolbar toolbar; - MapPickerPresenter presenter; - MapAdapter adapter; + private MapPickerViewModel viewModel; + private MapAdapter adapter; - boolean isSaving = false; + + protected abstract MapPickerViewModel createViewModel(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - presenter = createPresenter(); + viewModel = createViewModel(); } @AfterViews void setupToolbar() { FragmentUtil.setActionBar(this, toolbar); - presenter.initView(); - } - - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - isSaving = true; } @Override - public void onDestroyView() { - super.onDestroyView(); - presenter.dispose(); - } + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); - @Override - public void onDetach() { - super.onDetach(); - if (isRemoving() && !isSaving) { - presenter.viewFinished(); - } - } - - /** - * MapPickerView implementation - */ - @Override - @UiThread - public void setItems(List items) { - if (adapter == null) { - adapter = new MapAdapter(items); - } + viewModel.getMaps().observe(this, maps -> { + if (adapter == null) { + adapter = new MapAdapter(maps); + } - if (recyclerView.getAdapter() == null) { - recyclerView.setHasFixedSize(true); - recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); - recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build()); - recyclerView.setItemAnimator(new NoChangeItemAnimator()); - recyclerView.setAdapter(adapter); - } + if (recyclerView.getAdapter() == null) { + recyclerView.setHasFixedSize(true); + recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); + recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build()); + recyclerView.setItemAnimator(new NoChangeItemAnimator()); + recyclerView.setAdapter(adapter); + } - adapter.setItems(items); + adapter.setItems(maps); + }); } /** @@ -135,13 +106,12 @@ protected boolean showMapDates() { return false; } - protected abstract MapPickerPresenter createPresenter(); /** * RecyclerView Adapter for displaying list of maps */ private class MapAdapter extends RecyclerView.Adapter { - private List maps; + private MapLoader[] maps; private final Semaphore limitImageLoadingSemaphore = new Semaphore(3, true); private View.OnClickListener itemClickListener = new View.OnClickListener() { @@ -150,19 +120,19 @@ public void onClick(View v) { RecyclerView.ViewHolder viewHolder = recyclerView.findContainingViewHolder(v); if (viewHolder != null) { int position = viewHolder.getAdapterPosition(); - MapLoader map = maps.get(position); - presenter.itemSelected(map); + MapLoader map = maps[position]; + viewModel.selectMap(map); } } }; - public MapAdapter(List maps) { + public MapAdapter(MapLoader[] maps) { this.maps = maps; } @Override public int getItemCount() { - return maps.size(); + return maps.length; } @Override @@ -175,11 +145,11 @@ public MapHolder onCreateViewHolder(ViewGroup parent, int viewType) { @Override public void onBindViewHolder(MapHolder holder, int position) { - IMapDefinition map = maps.get(position); + IMapDefinition map = maps[position]; holder.bind(map); } - void setItems(List maps) { + void setItems(MapLoader[] maps) { this.maps = maps; notifyDataSetChanged(); } @@ -194,10 +164,10 @@ class MapHolder extends RecyclerView.ViewHolder { public MapHolder(View itemView) { super(itemView); - nameTextView = (TextView) itemView.findViewById(R.id.text_view_name); - dateTextView = (TextView) itemView.findViewById(R.id.text_view_date); - playerCountTextView = (TextView) itemView.findViewById(R.id.text_view_player_count); - mapPreviewImageView = (ImageView) itemView.findViewById(R.id.image_view_map_preview); + nameTextView = itemView.findViewById(R.id.text_view_name); + dateTextView = itemView.findViewById(R.id.text_view_date); + playerCountTextView = itemView.findViewById(R.id.text_view_player_count); + mapPreviewImageView = itemView.findViewById(R.id.image_view_map_preview); if (showMapDates()) { dateTextView.setVisibility(View.VISIBLE); diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/MapPickerViewModel.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/MapPickerViewModel.java new file mode 100644 index 0000000000..94cfa4e31e --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/MapPickerViewModel.java @@ -0,0 +1,78 @@ +package jsettlers.main.android.mainmenu.mappicker; + +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.ViewModel; + +import java.util.List; + +import jsettlers.common.utils.collections.ChangingList; +import jsettlers.common.utils.collections.IChangingListListener; +import jsettlers.logic.map.loading.MapLoader; +import jsettlers.main.android.core.GameStarter; + +import static java8.util.stream.StreamSupport.stream; + +/** + * Created by Tom Pratt on 06/10/2017. + */ + +public abstract class MapPickerViewModel extends ViewModel { + + private final GameStarter gameStarter; + private final ChangingList changingMaps; + + private final MapsData maps = new MapsData(); + + public MapPickerViewModel(GameStarter gameStarter, ChangingList changingMaps) { + this.gameStarter = gameStarter; + this.changingMaps = changingMaps; + } + + @Override + protected void onCleared() { + super.onCleared(); + if (gameStarter.getStartingGame() == null) { + abort(); + } + } + + public LiveData getMaps() { + return maps; + } + + public abstract void selectMap(MapLoader map); + + protected void abort() { + } + + + /** + * Maps list live data + */ + class MapsData extends LiveData implements IChangingListListener { + + @Override + protected void onActive() { + super.onActive(); + changingMaps.setListener(this); + setValue(sortedMaps(changingMaps.getItems())); + } + + @Override + protected void onInactive() { + super.onInactive(); + changingMaps.removeListener(this); + } + + @Override + public void listChanged(ChangingList list) { + postValue(sortedMaps(list.getItems())); + } + + private MapLoader[] sortedMaps(List items) { + return stream(items) + .sorted((o1, o2) -> o1.getMapName().compareToIgnoreCase(o2.getMapName())) + .toArray(MapLoader[]::new); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/picker/NewMultiPlayerPickerFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/NewMultiPlayerPickerFragment.java similarity index 63% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/picker/NewMultiPlayerPickerFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/NewMultiPlayerPickerFragment.java index 981899a3a9..4709a41aba 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/picker/NewMultiPlayerPickerFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/NewMultiPlayerPickerFragment.java @@ -13,45 +13,62 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.ui.fragments.picker; +package jsettlers.main.android.mainmenu.mappicker; + +import android.arch.lifecycle.ViewModelProviders; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import org.androidannotations.annotations.EFragment; import jsettlers.main.android.R; -import jsettlers.main.android.mainmenu.factories.PresenterFactory; -import jsettlers.main.android.mainmenu.presenters.picker.MapPickerPresenter; -import jsettlers.main.android.mainmenu.ui.dialogs.JoiningGameProgressDialog; -import jsettlers.main.android.mainmenu.views.NewMultiPlayerPickerView; - -import android.support.v4.app.Fragment; +import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; /** * Created by tompr on 21/01/2017. */ @EFragment(R.layout.fragment_map_picker) -public class NewMultiPlayerPickerFragment extends MapPickerFragment implements NewMultiPlayerPickerView { +public class NewMultiPlayerPickerFragment extends MapPickerFragment { private static final String TAG_JOINING_PROGRESS_DIALOG = "joingingprogress"; public static Fragment newInstance() { return new NewMultiPlayerPickerFragment_(); } + private NewMultiPlayerPickerViewModel viewModel; + @Override - protected MapPickerPresenter createPresenter() { - return PresenterFactory.createNewMultiPlayerPickerPresenter(getActivity(), this); + protected MapPickerViewModel createViewModel() { + viewModel = ViewModelProviders.of(this, new NewMultiPlayerPickerViewModel.Factory(getActivity())).get(NewMultiPlayerPickerViewModel.class); + return viewModel; } @Override - public void onResume() { - super.onResume(); - getActivity().setTitle(R.string.new_multi_player_game); + void setupToolbar() { + super.setupToolbar(); + toolbar.setTitle(R.string.new_multi_player_game); } - /** - * NewMultiPlayerPickerView implementation - */ @Override - public void setJoiningProgress(String stateString, int progressPercentage) { + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + viewModel.getMapSelectedEvent().observe(this, mapId -> { + MainMenuNavigator mainMenuNavigator = (MainMenuNavigator)getActivity(); + mainMenuNavigator.showNewMultiPlayerSetup(mapId); + }); + + viewModel.getJoiningState().observe(this, joiningViewState -> { + if (joiningViewState == null) { + dismissJoiningProgress(); + } else { + setJoiningProgress(joiningViewState.getState(), joiningViewState.getProgress()); + } + }); + } + + private void setJoiningProgress(String stateString, int progressPercentage) { JoiningGameProgressDialog joiningProgressDialog = (JoiningGameProgressDialog) getChildFragmentManager().findFragmentByTag(TAG_JOINING_PROGRESS_DIALOG); if (joiningProgressDialog == null) { JoiningGameProgressDialog.create(stateString, progressPercentage).show(getChildFragmentManager(), TAG_JOINING_PROGRESS_DIALOG); @@ -60,8 +77,7 @@ public void setJoiningProgress(String stateString, int progressPercentage) { } } - @Override - public void dismissJoiningProgress() { + private void dismissJoiningProgress() { JoiningGameProgressDialog joiningProgressDialog = (JoiningGameProgressDialog) getChildFragmentManager().findFragmentByTag(TAG_JOINING_PROGRESS_DIALOG); if (joiningProgressDialog != null) { joiningProgressDialog.dismiss(); diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/NewMultiPlayerPickerViewModel.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/NewMultiPlayerPickerViewModel.java new file mode 100644 index 0000000000..2ea6d74923 --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/NewMultiPlayerPickerViewModel.java @@ -0,0 +1,139 @@ +package jsettlers.main.android.mainmenu.mappicker; + +import android.app.Activity; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.MutableLiveData; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProvider; + +import jsettlers.common.menu.EProgressState; +import jsettlers.common.menu.IJoinPhaseMultiplayerGameConnector; +import jsettlers.common.menu.IJoiningGame; +import jsettlers.common.menu.IJoiningGameListener; +import jsettlers.common.menu.IMapDefinition; +import jsettlers.common.menu.IOpenMultiplayerGameInfo; +import jsettlers.common.utils.collections.ChangingList; +import jsettlers.graphics.localization.Labels; +import jsettlers.logic.map.loading.MapLoader; +import jsettlers.main.android.core.AndroidPreferences; +import jsettlers.main.android.core.GameStarter; +import jsettlers.main.android.core.events.SingleLiveEvent; + +/** + * Created by Tom Pratt on 06/10/2017. + */ + +public class NewMultiPlayerPickerViewModel extends MapPickerViewModel implements IJoiningGameListener { + + private final GameStarter gameStarter; + private final AndroidPreferences androidPreferences; + + private final SingleLiveEvent mapSelectedEvent = new SingleLiveEvent<>(); + private final MutableLiveData joiningState = new MutableLiveData<>(); + + private IJoiningGame joiningGame; + private IMapDefinition tempMapDefinition; + + public NewMultiPlayerPickerViewModel(GameStarter gameStarter, AndroidPreferences androidPreferences, ChangingList changingMaps) { + super(gameStarter, changingMaps); + this.gameStarter = gameStarter; + this.androidPreferences = androidPreferences; + } + + @Override + public void selectMap(MapLoader map) { + cancelJoining(); + tempMapDefinition = map; + + joiningGame = gameStarter.getMultiPlayerConnector().openNewMultiplayerGame(new IOpenMultiplayerGameInfo() { + @Override + public String getMatchName() { + return androidPreferences.getPlayerName(); + } + + @Override + public IMapDefinition getMapDefinition() { + return map; + } + + @Override + public int getMaxPlayers() { + return map.getMaxPlayers(); + } + }); + + joiningGame.setListener(this); + + gameStarter.setJoiningGame(joiningGame); + } + + @Override + protected void abort() { + super.abort(); + cancelJoining(); + } + + public LiveData getMapSelectedEvent() { + return mapSelectedEvent; + } + + public LiveData getJoiningState() { + return joiningState; + } + + + private void cancelJoining() { + if (joiningGame != null) { + joiningGame.abort(); + } + + gameStarter.setJoiningGame(null); + gameStarter.closeMultiPlayerConnector(); + } + + + + /** + * IJoiningGameListener imeplementation + */ + @Override + public void joinProgressChanged(EProgressState state, float progress) { + String stateString = Labels.getProgress(state); + int progressPercentage = (int) (progress * 100); + + joiningState.postValue(new JoiningViewState(stateString, progressPercentage)); + } + + @Override + public void gameJoined(IJoinPhaseMultiplayerGameConnector connector) { + joiningGame.setListener(null); + gameStarter.setJoiningGame(null); + joiningState.postValue(null); + + gameStarter.setJoinPhaseMultiPlayerConnector(connector); + mapSelectedEvent.postValue(tempMapDefinition.getMapId()); + } + + + /** + * ViewModel factory + */ + public static class Factory implements ViewModelProvider.Factory { + + private final Activity activity; + private final GameStarter gameStarter; + + public Factory(Activity activity) { + this.activity = activity; + gameStarter = (GameStarter) activity.getApplication(); + } + + @Override + public T create(Class modelClass) { + if (modelClass == NewMultiPlayerPickerViewModel.class) { + return (T) new NewMultiPlayerPickerViewModel(gameStarter, new AndroidPreferences(activity), gameStarter.getMapList().getFreshMaps()); + } + throw new RuntimeException("NewSinglePlayerPickerViewModel.Factory doesn't know how to create a: " + modelClass.toString()); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/picker/NewSinglePlayerPickerFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/NewSinglePlayerPickerFragment.java similarity index 61% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/picker/NewSinglePlayerPickerFragment.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/NewSinglePlayerPickerFragment.java index 4493a1da3a..3473ae2499 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/picker/NewSinglePlayerPickerFragment.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/NewSinglePlayerPickerFragment.java @@ -13,32 +13,47 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.ui.fragments.picker; - -import jsettlers.main.android.R; -import jsettlers.main.android.mainmenu.factories.PresenterFactory; -import jsettlers.main.android.mainmenu.presenters.picker.MapPickerPresenter; +package jsettlers.main.android.mainmenu.mappicker; +import android.arch.lifecycle.ViewModelProviders; +import android.os.Bundle; +import android.support.annotation.Nullable; import android.support.v4.app.Fragment; + import org.androidannotations.annotations.EFragment; +import jsettlers.main.android.R; +import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; + /** * Created by tompr on 19/01/2017. */ @EFragment(R.layout.fragment_map_picker) public class NewSinglePlayerPickerFragment extends MapPickerFragment { + private NewSinglePlayerPickerViewModel viewModel; + public static Fragment newInstance() { return new NewSinglePlayerPickerFragment_(); } @Override - protected MapPickerPresenter createPresenter() { - return PresenterFactory.createNewSinglePlayerPickerPresenter(getActivity(), this); + protected MapPickerViewModel createViewModel() { + viewModel = ViewModelProviders.of(this, new NewSinglePlayerPickerViewModel.Factory(getActivity())).get(NewSinglePlayerPickerViewModel.class); + return viewModel; + } + + @Override + void setupToolbar() { + super.setupToolbar(); + toolbar.setTitle(R.string.new_single_player_game); } @Override - public void onResume() { - super.onResume(); - getActivity().setTitle(R.string.new_single_player_game); + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + viewModel.getMapSelectedEvent().observe(this, mapId -> { + MainMenuNavigator mainMenuNavigator = (MainMenuNavigator)getActivity(); + mainMenuNavigator.showNewSinglePlayerSetup(mapId); + }); } } diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/NewSinglePlayerPickerViewModel.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/NewSinglePlayerPickerViewModel.java new file mode 100644 index 0000000000..4cc8ac495a --- /dev/null +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/mappicker/NewSinglePlayerPickerViewModel.java @@ -0,0 +1,55 @@ +package jsettlers.main.android.mainmenu.mappicker; + +import android.app.Activity; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProvider; + +import jsettlers.common.utils.collections.ChangingList; +import jsettlers.logic.map.loading.MapLoader; +import jsettlers.main.android.core.GameStarter; +import jsettlers.main.android.core.events.SingleLiveEvent; + +/** + * Created by Tom Pratt on 06/10/2017. + */ + +public class NewSinglePlayerPickerViewModel extends MapPickerViewModel { + + private final SingleLiveEvent mapSelectedEvent = new SingleLiveEvent<>(); + + public NewSinglePlayerPickerViewModel(GameStarter gameStarter, ChangingList changingMaps) { + super(gameStarter, changingMaps); + } + + @Override + public void selectMap(MapLoader map) { + mapSelectedEvent.setValue(map.getMapId()); + } + + public LiveData getMapSelectedEvent() { + return mapSelectedEvent; + } + + /** + * ViewModel factory + */ + public static class Factory implements ViewModelProvider.Factory { + + private final Activity activity; + private final GameStarter gameStarter; + + public Factory(Activity activity) { + this.activity = activity; + gameStarter = (GameStarter) activity.getApplication(); + } + + @Override + public T create(Class modelClass) { + if (modelClass == NewSinglePlayerPickerViewModel.class) { + return (T) new NewSinglePlayerPickerViewModel(gameStarter, gameStarter.getMapList().getFreshMaps()); + } + throw new RuntimeException("NewSinglePlayerPickerViewModel.Factory doesn't know how to create a: " + modelClass.toString()); + } + } +} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/navigation/Actions.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/navigation/Actions.java index d0e1219d73..601bd2c0bb 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/navigation/Actions.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/navigation/Actions.java @@ -20,10 +20,4 @@ */ public class Actions { public static final String ACTION_RESUME_GAME = "com.jsettlers.RESUME"; - public static final String ACTION_PAUSE = "com.jsettlers.pause"; - public static final String ACTION_UNPAUSE = "com.jsettlers.unpause"; - public static final String ACTION_SAVE = "com.jsettlers.save"; - public static final String ACTION_QUIT = "com.jsettlers.quit"; - public static final String ACTION_QUIT_CONFIRM = "com.jsettlers.quitconfirm"; - public static final String ACTION_QUIT_CANCELLED = "com.jsettlers.quitcancelled"; } diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/navigation/MainMenuNavigator.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/navigation/MainMenuNavigator.java index b45e08f287..4eb894e8f5 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/navigation/MainMenuNavigator.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/navigation/MainMenuNavigator.java @@ -15,8 +15,6 @@ package jsettlers.main.android.mainmenu.navigation; -import jsettlers.common.menu.IMapDefinition; - /** * Created by tingl on 27/05/2016. */ @@ -25,15 +23,15 @@ public interface MainMenuNavigator { void showLoadSinglePlayerPicker(); - void showNewSinglePlayerSetup(IMapDefinition mapDefinition); + void showNewSinglePlayerSetup(String mapId); void showNewMultiPlayerPicker(); void showJoinMultiPlayerPicker(); - void showNewMultiPlayerSetup(IMapDefinition mapDefinition); + void showNewMultiPlayerSetup(String mapId); - void showJoinMultiPlayerSetup(IMapDefinition mapDefinition); + void showJoinMultiPlayerSetup(String mapId); void showGame(); diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/MainMenuPresenter.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/MainMenuPresenter.java deleted file mode 100644 index abdd5d1dea..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/MainMenuPresenter.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.presenters; - -import jsettlers.main.android.core.GameManager; -import jsettlers.main.android.core.resources.scanner.AndroidResourcesLoader; -import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; -import jsettlers.main.android.mainmenu.views.MainMenuView; - -/** - * Created by tompr on 04/03/2017. - */ -public class MainMenuPresenter { - private final MainMenuView view; - private final MainMenuNavigator navigator; - private final GameManager gameManager; - private final AndroidResourcesLoader androidResourcesLoader; - - private boolean resourcesLoaded; - - public MainMenuPresenter(MainMenuView view, MainMenuNavigator navigator, GameManager gameManager, AndroidResourcesLoader androidResourcesLoader) { - this.view = view; - this.navigator = navigator; - this.gameManager = gameManager; - this.androidResourcesLoader = androidResourcesLoader; - this.resourcesLoaded = androidResourcesLoader.setup(); - } - - public void initView() { - if (!resourcesLoaded) { - view.showResourcePicker(); - } - } - - public void newSinglePlayerSelected() { - if (resourcesLoaded) { - navigator.showNewSinglePlayerPicker(); - } - } - - public void loadSinglePlayerSelected() { - if (resourcesLoaded) { - navigator.showLoadSinglePlayerPicker(); - } - } - - public void newMultiPlayerSelected() { - if (resourcesLoaded) { - navigator.showNewMultiPlayerPicker(); - } - } - - public void joinMultiPlayerSelected() { - if (resourcesLoaded) { - navigator.showJoinMultiPlayerPicker(); - } - } - - public void resumeSelected() { - navigator.resumeGame(); - } - - public void quitSelected() { - if (gameManager.getGameMenu().canQuitConfirm()) { - gameManager.getGameMenu().quitConfirm(); - } else { - gameManager.getGameMenu().quit(); - } - } - - public void pauseSelected() { - if (gameManager.getGameMenu().isPaused()) { - gameManager.getGameMenu().unPause(); - } else { - gameManager.getGameMenu().pause(); - } - updateResumeGameView(); - } - - public void updateResumeGameView() { - if (gameManager.isGameInProgress()) { - view.updatePauseButton(gameManager.getGameMenu().isPaused()); - view.updateQuitButton(gameManager.getGameMenu().canQuitConfirm()); - view.showResumeGameView(); - } else { - view.hideResumeGameView(); - } - } - - public void resourceDirectoryChosen() { - resourcesLoaded = androidResourcesLoader.setup(); - if (resourcesLoaded) { - view.hideResourcePicker(); - } else { - throw new RuntimeException("Resources not found or not valid after directory chosen by user"); - } - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/picker/JoinMultiPlayerPickerPresenter.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/picker/JoinMultiPlayerPickerPresenter.java deleted file mode 100644 index 64f42c659c..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/picker/JoinMultiPlayerPickerPresenter.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.presenters.picker; - -import java.util.List; - -import jsettlers.common.menu.EProgressState; -import jsettlers.common.menu.IJoinPhaseMultiplayerGameConnector; -import jsettlers.common.menu.IJoinableGame; -import jsettlers.common.menu.IJoiningGame; -import jsettlers.common.menu.IJoiningGameListener; -import jsettlers.common.menu.IMapDefinition; -import jsettlers.common.utils.collections.ChangingList; -import jsettlers.common.utils.collections.IChangingListListener; -import jsettlers.graphics.localization.Labels; -import jsettlers.main.android.core.GameStarter; -import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; -import jsettlers.main.android.mainmenu.views.JoinMultiPlayerPickerView; - -/** - * Created by tompr on 22/01/2017. - */ -public class JoinMultiPlayerPickerPresenter implements IChangingListListener, IJoiningGameListener { - private final JoinMultiPlayerPickerView view; - private final GameStarter gameStarter; - private final MainMenuNavigator navigator; - private final ChangingList changingJoinableGames; - - private IJoiningGame joiningGame; - private IMapDefinition mapDefinition; - - public JoinMultiPlayerPickerPresenter(JoinMultiPlayerPickerView view, MainMenuNavigator navigator, GameStarter gameStarter) { - this.view = view; - this.gameStarter = gameStarter; - this.navigator = navigator; - - changingJoinableGames = gameStarter.getMultiPlayerConnector().getJoinableMultiplayerGames(); - changingJoinableGames.setListener(this); - - joiningGame = gameStarter.getJoiningGame(); - if (joiningGame == null) { - // pop - } else { - joiningGame.setListener(this); - } - } - - public void initView() { - updateViewJoinableGames(); - } - - public void viewFinished() { - if (gameStarter.getStartingGame() == null) { - abort(); - } - } - - private void abort() { - if (joiningGame != null) { - joiningGame.abort(); - } - gameStarter.setJoiningGame(null); - gameStarter.closeMultiPlayerConnector(); - joiningGame = null; - mapDefinition = null; - } - - public void dispose() { - changingJoinableGames.removeListener(this); - if (joiningGame != null) { - joiningGame.setListener(null); - } - } - - public void joinableGameSelected(IJoinableGame joinableGame) { - abort(); - mapDefinition = joinableGame.getMap(); - - joiningGame = gameStarter.getMultiPlayerConnector().joinMultiplayerGame(joinableGame); - joiningGame.setListener(this); - - gameStarter.setJoiningGame(joiningGame); - } - - /** - * ChangingListListener implementation - */ - @Override - public void listChanged(ChangingList list) { - updateViewJoinableGames(); - } - - /** - * IJoiningGameListener imeplementation - */ - @Override - public void joinProgressChanged(EProgressState state, float progress) { - String stateString = Labels.getProgress(state); - int progressPercentage = (int) (progress * 100); - - view.setJoiningProgress(stateString, progressPercentage); - } - - @Override - public void gameJoined(IJoinPhaseMultiplayerGameConnector connector) { - joiningGame.setListener(null); - gameStarter.setJoiningGame(null); - view.dismissJoiningProgress(); - - gameStarter.setJoinPhaseMultiPlayerConnector(connector); - navigator.showJoinMultiPlayerSetup(mapDefinition); - } - - private void updateViewJoinableGames() { - List joinableGames = changingJoinableGames.getItems(); - view.updateJoinableGames(joinableGames); - - if (joinableGames.size() > 0) { - view.hideSearchingForGamesView(); - } else { - view.showSearchingForGamesView(); - } - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/picker/LoadSinglePlayerPickerPresenter.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/picker/LoadSinglePlayerPickerPresenter.java deleted file mode 100644 index 55fe59a296..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/picker/LoadSinglePlayerPickerPresenter.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.presenters.picker; - -import static java8.util.stream.StreamSupport.stream; - -import java.util.List; - -import jsettlers.common.utils.collections.ChangingList; -import jsettlers.logic.map.loading.MapLoader; -import jsettlers.logic.map.loading.newmap.MapFileHeader; -import jsettlers.logic.player.PlayerSetting; -import jsettlers.main.JSettlersGame; -import jsettlers.main.android.core.GameStarter; -import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; -import jsettlers.main.android.mainmenu.views.LoadSinglePlayerPickerView; - -import java8.util.stream.Collectors; - -/** - * Created by tompr on 22/01/2017. - */ -public class LoadSinglePlayerPickerPresenter extends MapPickerPresenter { - private final LoadSinglePlayerPickerView view; - private final GameStarter gameStarter; - private final MainMenuNavigator navigator; - - public LoadSinglePlayerPickerPresenter(LoadSinglePlayerPickerView view, MainMenuNavigator navigator, GameStarter gameStarter, ChangingList changingMaps) { - super(view, navigator, gameStarter, changingMaps); - this.view = view; - this.navigator = navigator; - this.gameStarter = gameStarter; - } - - @Override - public void itemSelected(MapLoader mapLoader) { - MapFileHeader mapFileHeader = mapLoader.getFileHeader(); - PlayerSetting[] playerSettings = mapFileHeader.getPlayerSettings(); - byte playerId = mapFileHeader.getPlayerId(); - JSettlersGame game = new JSettlersGame(mapLoader, 4711L, playerId, playerSettings); - gameStarter.setStartingGame(game.start()); - navigator.showGame(); - } - - @Override - protected void updateViewItems(List items) { - List sortedList = stream(items) - .sorted((o1, o2) -> o2.getCreationDate().compareTo(o1.getCreationDate())) - .collect(Collectors.toList()); - - view.setItems(sortedList); - - if (sortedList.size() > 0) { - view.hideNoGamesView(); - } else { - view.showNoGamesView(); - } - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/picker/MapPickerPresenter.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/picker/MapPickerPresenter.java deleted file mode 100644 index 5d10525345..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/picker/MapPickerPresenter.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.presenters.picker; - -import java.util.List; - -import java8.util.stream.Collectors; -import jsettlers.common.utils.collections.ChangingList; -import jsettlers.common.utils.collections.IChangingListListener; -import jsettlers.logic.map.loading.MapLoader; -import jsettlers.main.android.core.GameStarter; -import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; -import jsettlers.main.android.mainmenu.views.MapPickerView; - -import static java8.util.stream.StreamSupport.stream; - -/** - * Created by tompr on 22/01/2017. - */ -public abstract class MapPickerPresenter implements IChangingListListener { - private final MapPickerView view; - private final GameStarter gameStarter; - private final MainMenuNavigator navigator; - private final ChangingList changingMaps; - - public MapPickerPresenter(MapPickerView view, MainMenuNavigator navigator, GameStarter gameStarter, ChangingList changingMaps) { - this.view = view; - this.gameStarter = gameStarter; - this.navigator = navigator; - this.changingMaps = changingMaps; - - changingMaps.setListener(this); - } - - public void initView() { - sortAndUpdateItems(changingMaps.getItems()); - } - - public void viewFinished() { - if (gameStarter.getStartingGame() == null) { - abort(); - } - } - - protected void abort() { - } - - public void dispose() { - changingMaps.removeListener(this); - } - - public abstract void itemSelected(MapLoader mapLoader); - - protected void updateViewItems(List items) { - view.setItems(items); - } - - private void sortAndUpdateItems(List items) { - List sortedList = stream(items) - .sorted((o1, o2) -> o1.getMapName().compareToIgnoreCase(o2.getMapName())) - .collect(Collectors.toList()); - - updateViewItems(sortedList); - } - - /** - * ChangingListListener implementation - */ - @Override - public void listChanged(ChangingList list) { - sortAndUpdateItems(list.getItems()); - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/picker/NewMultiPlayerPickerPresenter.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/picker/NewMultiPlayerPickerPresenter.java deleted file mode 100644 index c05d5f078c..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/picker/NewMultiPlayerPickerPresenter.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.presenters.picker; - -import jsettlers.common.menu.EProgressState; -import jsettlers.common.menu.IJoinPhaseMultiplayerGameConnector; -import jsettlers.common.menu.IJoiningGame; -import jsettlers.common.menu.IJoiningGameListener; -import jsettlers.common.menu.IMapDefinition; -import jsettlers.common.menu.IOpenMultiplayerGameInfo; -import jsettlers.common.utils.collections.ChangingList; -import jsettlers.graphics.localization.Labels; -import jsettlers.logic.map.loading.MapLoader; -import jsettlers.main.android.core.AndroidPreferences; -import jsettlers.main.android.core.GameStarter; -import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; -import jsettlers.main.android.mainmenu.views.NewMultiPlayerPickerView; - -/** - * Created by tompr on 22/01/2017. - */ -public class NewMultiPlayerPickerPresenter extends MapPickerPresenter implements IJoiningGameListener { - private final NewMultiPlayerPickerView view; - private final GameStarter gameStarter; - private final AndroidPreferences androidPreferences; - private final MainMenuNavigator navigator; - - private IJoiningGame joiningGame; - private IMapDefinition tempMapDefinition; - - public NewMultiPlayerPickerPresenter(NewMultiPlayerPickerView view, MainMenuNavigator navigator, GameStarter gameStarter, AndroidPreferences androidPreferences, - ChangingList changingMaps) { - - super(view, navigator, gameStarter, changingMaps); - this.view = view; - this.navigator = navigator; - this.gameStarter = gameStarter; - this.androidPreferences = androidPreferences; - } - - @Override - public void itemSelected(MapLoader mapLoader) { - cancelJoining(); - tempMapDefinition = mapLoader; - - joiningGame = gameStarter.getMultiPlayerConnector().openNewMultiplayerGame(new IOpenMultiplayerGameInfo() { - @Override - public String getMatchName() { - return androidPreferences.getPlayerName(); - } - - @Override - public IMapDefinition getMapDefinition() { - return mapLoader; - } - - @Override - public int getMaxPlayers() { - return mapLoader.getMaxPlayers(); - } - }); - - joiningGame.setListener(this); - - gameStarter.setJoiningGame(joiningGame); - } - - @Override - protected void abort() { - super.abort(); - cancelJoining(); - } - - public void dispose() { - super.dispose(); - if (joiningGame != null) { - joiningGame.setListener(null); - } - } - - private void cancelJoining() { - if (joiningGame != null) { - joiningGame.abort(); - } - - gameStarter.setJoiningGame(null); - gameStarter.closeMultiPlayerConnector(); - } - - /** - * IJoiningGameListener imeplementation - */ - @Override - public void joinProgressChanged(EProgressState state, float progress) { - String stateString = Labels.getProgress(state); - int progressPercentage = (int) (progress * 100); - - view.setJoiningProgress(stateString, progressPercentage); - } - - @Override - public void gameJoined(IJoinPhaseMultiplayerGameConnector connector) { - joiningGame.setListener(null); - gameStarter.setJoiningGame(null); - view.dismissJoiningProgress(); - - gameStarter.setJoinPhaseMultiPlayerConnector(connector); - navigator.showNewMultiPlayerSetup(tempMapDefinition); - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/picker/NewSinglePlayerPickerPresenter.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/picker/NewSinglePlayerPickerPresenter.java deleted file mode 100644 index 5a9b7d7c23..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/picker/NewSinglePlayerPickerPresenter.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.presenters.picker; - -import jsettlers.common.utils.collections.ChangingList; -import jsettlers.logic.map.loading.MapLoader; -import jsettlers.main.android.core.GameStarter; -import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; -import jsettlers.main.android.mainmenu.views.MapPickerView; - -/** - * Created by tompr on 22/01/2017. - */ -public class NewSinglePlayerPickerPresenter extends MapPickerPresenter { - private final MainMenuNavigator navigator; - - public NewSinglePlayerPickerPresenter(MapPickerView view, MainMenuNavigator navigator, GameStarter gameStarter, ChangingList changingMaps) { - super(view, navigator, gameStarter, changingMaps); - this.navigator = navigator; - } - - @Override - public void itemSelected(MapLoader mapLoader) { - navigator.showNewSinglePlayerSetup(mapLoader); - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/JoinMultiPlayerSetupPresenter.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/JoinMultiPlayerSetupPresenter.java deleted file mode 100644 index 371dd922a0..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/JoinMultiPlayerSetupPresenter.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.presenters.setup; - -/** - * Created by tompr on 03/02/2017. - */ -public interface JoinMultiPlayerSetupPresenter extends MapSetupPresenter { -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/JoinMultiPlayerSetupPresenterImpl.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/JoinMultiPlayerSetupPresenterImpl.java deleted file mode 100644 index 0afb3d7af6..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/JoinMultiPlayerSetupPresenterImpl.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.presenters.setup; - -import java.util.List; - -import jsettlers.common.ai.EPlayerType; -import jsettlers.common.menu.IJoinPhaseMultiplayerGameConnector; -import jsettlers.common.menu.IMultiplayerListener; -import jsettlers.common.menu.IMultiplayerPlayer; -import jsettlers.common.menu.IStartingGame; -import jsettlers.common.utils.collections.ChangingList; -import jsettlers.common.utils.collections.IChangingListListener; -import jsettlers.logic.map.loading.MapLoader; -import jsettlers.main.android.core.AndroidPreferences; -import jsettlers.main.android.core.GameStarter; -import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.PlayerSlotPresenter; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.PlayerType; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.ReadyListener; -import jsettlers.main.android.mainmenu.views.JoinMultiPlayerSetupView; - -/** - * Created by tompr on 22/01/2017. - */ -public class JoinMultiPlayerSetupPresenterImpl extends MapSetupPresenterImpl implements JoinMultiPlayerSetupPresenter, IMultiplayerListener, IChangingListListener, ReadyListener { - private final JoinMultiPlayerSetupView view; - private final MainMenuNavigator navigator; - private final GameStarter gameStarter; - private final IJoinPhaseMultiplayerGameConnector connector; - private final AndroidPreferences androidPreferences; - - public JoinMultiPlayerSetupPresenterImpl(JoinMultiPlayerSetupView view, MainMenuNavigator navigator, GameStarter gameStarter, IJoinPhaseMultiplayerGameConnector connector, - AndroidPreferences androidPreferences, MapLoader mapLoader) { - - super(view, gameStarter, mapLoader); - this.view = view; - this.navigator = navigator; - this.gameStarter = gameStarter; - this.connector = connector; - this.androidPreferences = androidPreferences; - - connector.setMultiplayerListener(this); - connector.getPlayers().setListener(this); - - updateSlots(); - } - - @Override - public void initView() { - super.initView(); - view.disableHostOnlyControls(); - } - - @Override - protected void abort() { - super.abort(); - connector.abort(); - gameStarter.setJoinPhaseMultiPlayerConnector(null); - } - - @Override - public void dispose() { - connector.setMultiplayerListener(null); - connector.getPlayers().setListener(null); - } - - @Override - public boolean startGame() { - return connector.startGame(); - } - - /** - * IMultiplayerListener implementation - */ - @Override - public void gameAborted() { - // TODO pop - } - - @Override - public void gameIsStarting(IStartingGame game) { - gameStarter.setJoinPhaseMultiPlayerConnector(null); - gameStarter.setStartingGame(game); - navigator.showGame(); - } - - /** - * ChangingListListener implementation - */ - @Override - public void listChanged(ChangingList list) { - updateSlots(); - - // trigger a notify data set changed for now. Probably want to update the view more dynamically at some point - updateViewItems(); - } - - /** - * ReadyListener implementation - */ - @Override - public void readyChanged(boolean ready) { - connector.setReady(ready); - } - - private void updateSlots() { - List playerSlotPresenters = getPlayerSlotPresenters(); - List players = connector.getPlayers().getItems(); - int numberOfConnectedPlayers = players.size(); - - for (int i = 0; i < playerSlotPresenters.size(); i++) { - PlayerSlotPresenter playerSlotPresenter = playerSlotPresenters.get(i); - - if (i < numberOfConnectedPlayers) { - setHumanSlotPlayerTypes(playerSlotPresenter); - - IMultiplayerPlayer multiplayerPlayer = players.get(i); - playerSlotPresenter.setName(multiplayerPlayer.getName()); - playerSlotPresenter.setReady(multiplayerPlayer.isReady()); - playerSlotPresenter.setShowReadyControl(true); - - boolean isMe = multiplayerPlayer.getId().equals(androidPreferences.getPlayerId()); - - if (isMe) { - playerSlotPresenter.setControlsEnabled(true); - playerSlotPresenter.setReadyListener(this); - } else { - playerSlotPresenter.setControlsEnabled(false); - playerSlotPresenter.setReadyListener(null); - } - } else { - setComputerSlotPlayerTypes(playerSlotPresenter); - playerSlotPresenter.setName("Computer " + i); - playerSlotPresenter.setShowReadyControl(false); - playerSlotPresenter.setControlsEnabled(false); - } - } - } - - protected static void setHumanSlotPlayerTypes(PlayerSlotPresenter playerSlotPresenter) { - playerSlotPresenter.setPossiblePlayerTypes(new PlayerType[] { - new PlayerType(EPlayerType.HUMAN) - }); - playerSlotPresenter.setPlayerType(new PlayerType(EPlayerType.HUMAN)); - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/JoinMultiPlayerSetupPresenterPop.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/JoinMultiPlayerSetupPresenterPop.java deleted file mode 100644 index cb3b478c84..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/JoinMultiPlayerSetupPresenterPop.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.presenters.setup; - -import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; - -/** - * Created by tompr on 03/02/2017. - */ -public class JoinMultiPlayerSetupPresenterPop implements JoinMultiPlayerSetupPresenter { - - public JoinMultiPlayerSetupPresenterPop(MainMenuNavigator navigator) { - navigator.popToMenuRoot(); - } - - @Override - public void initView() { - } - - @Override - public void updateViewTitle() { - } - - @Override - public void viewFinished() { - } - - @Override - public void dispose() { - } - - @Override - public boolean startGame() { - return false; - } - - @Override - public void playerCountSelected(PlayerCount item) { - } - - @Override - public void startResourcesSelected(StartResources item) { - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/MapSetupPresenterImpl.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/MapSetupPresenterImpl.java deleted file mode 100644 index 5fa3ede288..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/MapSetupPresenterImpl.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.presenters.setup; - -import java.util.ArrayList; -import java.util.List; - -import jsettlers.common.ai.EPlayerType; -import jsettlers.common.player.ECivilisation; -import jsettlers.logic.map.loading.EMapStartResources; -import jsettlers.logic.map.loading.MapLoader; -import jsettlers.logic.player.PlayerSetting; -import jsettlers.main.android.core.GameStarter; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.Civilisation; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.PlayerSlotPresenter; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.PlayerType; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.PositionChangedListener; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.StartPosition; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.Team; -import jsettlers.main.android.mainmenu.views.MapSetupView; - -import java8.util.J8Arrays; - -/** - * Created by tompr on 21/01/2017. - */ -public abstract class MapSetupPresenterImpl implements MapSetupPresenter, PositionChangedListener { - private final MapSetupView view; - private final GameStarter gameStarter; - private final MapLoader mapLoader; - - private final List playerSlotPresenters = new ArrayList<>(); - - private PlayerCount playerCount; - private StartResources startResources; - - public MapSetupPresenterImpl(MapSetupView view, GameStarter gameStarter, MapLoader mapLoader) { - this.view = view; - this.gameStarter = gameStarter; - this.mapLoader = mapLoader; - - createComputerPlayerSlots(); - } - - @Override - public void initView() { - view.setNumberOfPlayersOptions(allowedPlayerCounts()); - view.setPlayerCount(playerCount); - - view.setStartResourcesOptions(startResourcesOptions()); - view.setStartResources(new StartResources(EMapStartResources.MEDIUM_GOODS)); - - view.setPeaceTimeOptions(peaceTimeOptions()); - view.setMapImage(mapLoader.getImage()); - } - - @Override - public void updateViewTitle() { - view.setMapName(mapLoader.getMapName()); - } - - @Override - public void viewFinished() { - if (gameStarter.getStartingGame() == null) { - abort(); - } - } - - @Override - public void dispose() { - } - - protected void abort() { - } - - @Override - public void playerCountSelected(PlayerCount item) { - playerCount = item; - updateViewItems(); - } - - @Override - public void startResourcesSelected(StartResources item) { - startResources = item; - } - - protected void updateViewItems() { - view.setItems(getPlayerSlotPresenters(), playerCount.getNumberOfPlayers()); - } - - protected List getPlayerSlotPresenters() { - return playerSlotPresenters; - } - - protected PlayerCount getPlayerCount() { - return playerCount; - } - - /** - * Get items for the main map options - */ - private PlayerCount[] allowedPlayerCounts() { - int maxPlayers = mapLoader.getMaxPlayers(); - int minPlayers = mapLoader.getMinPlayers(); - int numberOfOptions = maxPlayers - minPlayers + 1; - - PlayerCount[] allowedPlayerCounts = new PlayerCount[numberOfOptions]; - - for (int i = 0; i < numberOfOptions; i++) { - allowedPlayerCounts[i] = new PlayerCount(minPlayers + i); - } - - return allowedPlayerCounts; - } - - private StartResources[] startResourcesOptions() { - return J8Arrays.stream(EMapStartResources.values()) - .map(StartResources::new) - .toArray(StartResources[]::new); - } - - private Peacetime[] peaceTimeOptions() { - return new Peacetime[] { new Peacetime("Without") }; - } - - /** - * Player slots setup Sets up the player slots as computer players. Subclasses can then modify the slots for any single or multi player human players. - */ - private void createComputerPlayerSlots() { - playerCount = new PlayerCount(mapLoader.getMaxPlayers()); - PlayerSetting[] playerSettings = mapLoader.getFileHeader().getPlayerSettings(); - - for (byte i = 0; i < playerCount.getNumberOfPlayers(); i++) { - PlayerSlotPresenter playerSlotPresenter = new PlayerSlotPresenter(this); - PlayerSetting playerSetting = playerSettings[i]; - - playerSlotPresenter.setName("Computer " + i); - playerSlotPresenter.setShowReadyControl(false); - - setComputerSlotPlayerTypes(playerSlotPresenter); - setSlotCivilisations(playerSlotPresenter, playerSetting); - setSlotStartPositions(playerSlotPresenter, playerCount.getNumberOfPlayers(), i); - setSlotTeams(playerSlotPresenter, playerSetting, playerCount.getNumberOfPlayers(), i); - - playerSlotPresenters.add(playerSlotPresenter); - } - } - - protected static void setComputerSlotPlayerTypes(PlayerSlotPresenter playerSlotPresenter) { - playerSlotPresenter.setPossiblePlayerTypes(new PlayerType[] { - new PlayerType(EPlayerType.AI_VERY_HARD), - new PlayerType(EPlayerType.AI_HARD), - new PlayerType(EPlayerType.AI_EASY), - new PlayerType(EPlayerType.AI_VERY_EASY) - }); - playerSlotPresenter.setPlayerType(new PlayerType(EPlayerType.AI_VERY_HARD)); - } - - private static void setSlotCivilisations(PlayerSlotPresenter playerSlotPresenter, PlayerSetting playerSetting) { - playerSlotPresenter.setPossibleCivilisations(new Civilisation[] { new Civilisation(ECivilisation.ROMAN) }); - - if (playerSetting.getCivilisation() != null) { - playerSlotPresenter.setCivilisation(new Civilisation(playerSetting.getCivilisation())); - } else { - playerSlotPresenter.setCivilisation(new Civilisation(ECivilisation.ROMAN)); - } - } - - private static void setSlotStartPositions(PlayerSlotPresenter playerSlotPresenter, int numberOfPlayers, byte orderNumber) { - playerSlotPresenter.setPossibleStartPositions(numberOfPlayers); - playerSlotPresenter.setStartPosition(new StartPosition(orderNumber)); - } - - private static void setSlotTeams(PlayerSlotPresenter playerSlotPresenter, PlayerSetting playerSetting, int numberOfPlayers, byte orderNumber) { - playerSlotPresenter.setPossibleTeams(numberOfPlayers); - if (playerSetting.getTeamId() != null) { - playerSlotPresenter.setTeam(new Team(playerSetting.getTeamId())); - } else { - playerSlotPresenter.setTeam(new Team(orderNumber)); - } - } - - /** - * PositionChangedListener implementation - */ - @Override - public void positionChanged(PlayerSlotPresenter updatedPlayerSlotPresenter, StartPosition oldPosition, StartPosition newPosition) { - for (PlayerSlotPresenter playerSlotPresenter : playerSlotPresenters) { - if (playerSlotPresenter != updatedPlayerSlotPresenter && playerSlotPresenter.getStartPosition().equals(newPosition)) { - playerSlotPresenter.setStartPosition(oldPosition); - } - } - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/NewMultiPlayerSetupPresenter.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/NewMultiPlayerSetupPresenter.java deleted file mode 100644 index e896fb91fa..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/NewMultiPlayerSetupPresenter.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.presenters.setup; - -/** - * Created by tompr on 03/02/2017. - */ -public interface NewMultiPlayerSetupPresenter extends MapSetupPresenter { -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/NewMultiPlayerSetupPresenterImpl.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/NewMultiPlayerSetupPresenterImpl.java deleted file mode 100644 index 0c0a1747ca..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/NewMultiPlayerSetupPresenterImpl.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.presenters.setup; - -import java.util.List; - -import jsettlers.common.ai.EPlayerType; -import jsettlers.common.menu.IJoinPhaseMultiplayerGameConnector; -import jsettlers.common.menu.IMultiplayerListener; -import jsettlers.common.menu.IMultiplayerPlayer; -import jsettlers.common.menu.IStartingGame; -import jsettlers.common.utils.collections.ChangingList; -import jsettlers.common.utils.collections.IChangingListListener; -import jsettlers.logic.map.loading.MapLoader; -import jsettlers.main.android.core.AndroidPreferences; -import jsettlers.main.android.core.GameStarter; -import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.PlayerSlotPresenter; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.PlayerType; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.ReadyListener; -import jsettlers.main.android.mainmenu.views.NewMultiPlayerSetupView; - -/** - * Created by tompr on 21/01/2017. - */ -public class NewMultiPlayerSetupPresenterImpl extends MapSetupPresenterImpl implements NewMultiPlayerSetupPresenter, IMultiplayerListener, IChangingListListener, ReadyListener { - private final NewMultiPlayerSetupView view; - - private final GameStarter gameStarter; - private final MainMenuNavigator navigator; - private final IJoinPhaseMultiplayerGameConnector connector; - private final AndroidPreferences androidPreferences; - - public NewMultiPlayerSetupPresenterImpl(NewMultiPlayerSetupView view, MainMenuNavigator navigator, GameStarter gameStarter, IJoinPhaseMultiplayerGameConnector connector, - AndroidPreferences settingsManager, MapLoader mapLoader) { - - super(view, gameStarter, mapLoader); - this.view = view; - this.navigator = navigator; - this.gameStarter = gameStarter; - this.connector = connector; - this.androidPreferences = settingsManager; - - connector.setMultiplayerListener(this); - connector.getPlayers().setListener(this); - - updateSlots(); - } - - private void updateSlots() { - List playerSlotPresenters = getPlayerSlotPresenters(); - List players = connector.getPlayers().getItems(); - int numberOfConnectedPlayers = players.size(); - - for (int i = 0; i < playerSlotPresenters.size(); i++) { - PlayerSlotPresenter playerSlotPresenter = playerSlotPresenters.get(i); - - if (i < numberOfConnectedPlayers) { - setHumanSlotPlayerTypes(playerSlotPresenter); - - IMultiplayerPlayer multiplayerPlayer = players.get(i); - playerSlotPresenter.setName(multiplayerPlayer.getName()); - playerSlotPresenter.setReady(multiplayerPlayer.isReady()); - playerSlotPresenter.setShowReadyControl(true); - - boolean isMe = multiplayerPlayer.getId().equals(androidPreferences.getPlayerId()); - - if (isMe) { - playerSlotPresenter.setControlsEnabled(true); - playerSlotPresenter.setReadyListener(this); - } else { - playerSlotPresenter.setControlsEnabled(false); - playerSlotPresenter.setReadyListener(null); - } - } else { - setComputerSlotPlayerTypes(playerSlotPresenter); - playerSlotPresenter.setName("Computer " + i); - playerSlotPresenter.setShowReadyControl(false); - playerSlotPresenter.setControlsEnabled(true); - } - } - } - - @Override - public void initView() { - super.initView(); - updateViewItems(); - } - - @Override - protected void abort() { - super.abort(); - connector.abort(); - gameStarter.setJoinPhaseMultiPlayerConnector(null); - } - - @Override - public void dispose() { - super.dispose(); - connector.setMultiplayerListener(null); - connector.getPlayers().setListener(null); - } - - @Override - public boolean startGame() { - return connector.startGame(); - } - - /** - * IMultiplayerListener implementation - */ - @Override - public void gameAborted() { - // TODO pop - } - - @Override - public void gameIsStarting(IStartingGame game) { - gameStarter.setJoinPhaseMultiPlayerConnector(null); - gameStarter.setStartingGame(game); - navigator.showGame(); - } - - /** - * ChangingListListener implementation - */ - @Override - public void listChanged(ChangingList list) { - updateSlots(); - updateViewItems(); // trigger a notify data set changed for now. Probably want to update the view more dynamically at some point - } - - /** - * ReadyListener implementation - */ - @Override - public void readyChanged(boolean ready) { - connector.setReady(ready); - } - - protected static void setHumanSlotPlayerTypes(PlayerSlotPresenter playerSlotPresenter) { - playerSlotPresenter.setPossiblePlayerTypes(new PlayerType[] { - new PlayerType(EPlayerType.HUMAN) - }); - playerSlotPresenter.setPlayerType(new PlayerType(EPlayerType.HUMAN)); - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/NewMultiPlayerSetupPresenterPop.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/NewMultiPlayerSetupPresenterPop.java deleted file mode 100644 index af28cde140..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/NewMultiPlayerSetupPresenterPop.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.presenters.setup; - -import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; - -/** - * Created by tompr on 03/02/2017. - */ -public class NewMultiPlayerSetupPresenterPop implements NewMultiPlayerSetupPresenter { - public NewMultiPlayerSetupPresenterPop(MainMenuNavigator navigator) { - navigator.popToMenuRoot(); - } - - @Override - public void initView() { - } - - @Override - public void updateViewTitle() { - } - - @Override - public void viewFinished() { - } - - @Override - public void dispose() { - } - - @Override - public boolean startGame() { - return false; - } - - @Override - public void playerCountSelected(PlayerCount item) { - } - - @Override - public void startResourcesSelected(StartResources item) { - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/NewSinglePlayerSetupPresenter.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/NewSinglePlayerSetupPresenter.java deleted file mode 100644 index 8736d65365..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/NewSinglePlayerSetupPresenter.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.presenters.setup; - -import java.util.List; - -import jsettlers.common.ai.EPlayerType; -import jsettlers.logic.map.loading.MapLoader; -import jsettlers.logic.player.PlayerSetting; -import jsettlers.main.JSettlersGame; -import jsettlers.main.android.core.AndroidPreferences; -import jsettlers.main.android.core.GameStarter; -import jsettlers.main.android.mainmenu.navigation.MainMenuNavigator; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.PlayerSlotPresenter; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.PlayerType; -import jsettlers.main.android.mainmenu.views.NewSinglePlayerSetupView; - -import static java8.util.stream.StreamSupport.stream; - -/** - * Created by tompr on 21/01/2017. - */ -public class NewSinglePlayerSetupPresenter extends MapSetupPresenterImpl { - private final MainMenuNavigator navigator; - private final GameStarter gameStarter; - private final MapLoader mapLoader; - - public NewSinglePlayerSetupPresenter(NewSinglePlayerSetupView view, MainMenuNavigator navigator, GameStarter gameStarter, AndroidPreferences androidPreferences, MapLoader mapLoader) { - super(view, gameStarter, mapLoader); - this.navigator = navigator; - this.gameStarter = gameStarter; - this.mapLoader = mapLoader; - - PlayerSlotPresenter humanPlayerSlot = getPlayerSlotPresenters().get(0); - humanPlayerSlot.setName(androidPreferences.getPlayerName()); - setHumanSlotPlayerTypes(humanPlayerSlot); - } - - @Override - public void initView() { - super.initView(); - updateViewItems(); - } - - @Override - public boolean startGame() { - List playerSlotPresenters = getPlayerSlotPresenters(); - PlayerSetting[] playerSettings = new PlayerSetting[playerSlotPresenters.size()]; - byte humanPlayerId = playerSlotPresenters.get(0).getPlayerId(); - - // Sort players by position - PlayerSlotPresenter[] sortedPlayers = stream(playerSlotPresenters) - .sorted((playerSlot, otherPlayerSlot) -> playerSlot.getStartPosition().asByte() - otherPlayerSlot.getStartPosition().asByte()) - .toArray(PlayerSlotPresenter[]::new); - - // Get player settings if player slot is within player count limit, otherwise use new PlayerSettings() for no player at that position - for (int i = 0; i < sortedPlayers.length; i++) { - PlayerSlotPresenter player = sortedPlayers[i]; - - if (playerSlotPresenters.indexOf(player) < getPlayerCount().getNumberOfPlayers()) { - playerSettings[i] = player.getPlayerSettings(); - } else { - playerSettings[i] = new PlayerSetting(); - } - } - - JSettlersGame game = new JSettlersGame(mapLoader, 4711L, humanPlayerId, playerSettings); - - gameStarter.setStartingGame(game.start()); - navigator.showGame(); - return true; - } - - private static void setHumanSlotPlayerTypes(PlayerSlotPresenter playerSlotPresenter) { - playerSlotPresenter.setPossiblePlayerTypes(new PlayerType[] { - new PlayerType(EPlayerType.HUMAN), - new PlayerType(EPlayerType.AI_VERY_HARD), - new PlayerType(EPlayerType.AI_HARD), - new PlayerType(EPlayerType.AI_EASY), - new PlayerType(EPlayerType.AI_VERY_EASY) - }); - playerSlotPresenter.setPlayerType(new PlayerType(EPlayerType.HUMAN)); - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/MapSetupPresenter.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/settings/PresenterFactory.java similarity index 70% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/MapSetupPresenter.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/settings/PresenterFactory.java index fbfa6b9665..e197746e82 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/setup/MapSetupPresenter.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/settings/PresenterFactory.java @@ -13,23 +13,21 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.presenters.setup; +package jsettlers.main.android.mainmenu.settings; + +import android.content.Context; + +import jsettlers.main.android.core.AndroidPreferences; +import jsettlers.main.android.mainmenu.settings.SettingsPresenter; +import jsettlers.main.android.mainmenu.settings.SettingsView; /** * Created by tompr on 03/02/2017. */ -public interface MapSetupPresenter { - void initView(); - - void updateViewTitle(); - - void viewFinished(); - - void dispose(); - - boolean startGame(); +public class PresenterFactory { - void playerCountSelected(PlayerCount item); + public static SettingsPresenter createSettingsPresenter(Context context, SettingsView view) { + return new SettingsPresenter(view, new AndroidPreferences(context)); + } - void startResourcesSelected(StartResources item); } diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/activities/SettingsActivity.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/settings/SettingsActivity.java similarity index 92% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/activities/SettingsActivity.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/settings/SettingsActivity.java index b03e525a57..094bf44bd8 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/activities/SettingsActivity.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/settings/SettingsActivity.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.ui.activities; +package jsettlers.main.android.mainmenu.settings; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.Click; @@ -23,9 +23,6 @@ import jsettlers.main.android.R; import jsettlers.main.android.core.ui.dialogs.EditTextDialog; -import jsettlers.main.android.mainmenu.factories.PresenterFactory; -import jsettlers.main.android.mainmenu.presenters.SettingsPresenter; -import jsettlers.main.android.mainmenu.views.SettingsView; import android.os.Bundle; import android.support.v7.app.ActionBar; diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/SettingsPresenter.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/settings/SettingsPresenter.java similarity index 93% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/SettingsPresenter.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/settings/SettingsPresenter.java index 6b5be7eb60..b8c221d0e5 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/presenters/SettingsPresenter.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/settings/SettingsPresenter.java @@ -13,10 +13,9 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.presenters; +package jsettlers.main.android.mainmenu.settings; import jsettlers.main.android.core.AndroidPreferences; -import jsettlers.main.android.mainmenu.views.SettingsView; /** * Created by tompr on 03/03/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/SettingsView.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/settings/SettingsView.java similarity index 96% rename from jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/SettingsView.java rename to jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/settings/SettingsView.java index cf02765296..9b328f3e27 100644 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/SettingsView.java +++ b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/settings/SettingsView.java @@ -13,7 +13,7 @@ * DEALINGS IN THE SOFTWARE. */ -package jsettlers.main.android.mainmenu.views; +package jsettlers.main.android.mainmenu.settings; /** * Created by tompr on 03/03/2017. diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/MainMenuFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/MainMenuFragment.java deleted file mode 100644 index ef9de66449..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/MainMenuFragment.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.ui.fragments; - -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_PAUSE; -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_QUIT; -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_QUIT_CANCELLED; -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_QUIT_CONFIRM; -import static jsettlers.main.android.mainmenu.navigation.Actions.ACTION_UNPAUSE; - -import org.androidannotations.annotations.AfterViews; -import org.androidannotations.annotations.Click; -import org.androidannotations.annotations.EFragment; -import org.androidannotations.annotations.OptionsMenu; -import org.androidannotations.annotations.Receiver; -import org.androidannotations.annotations.ViewById; - -import jsettlers.main.android.R; -import jsettlers.main.android.core.ui.FragmentUtil; -import jsettlers.main.android.mainmenu.factories.PresenterFactory; -import jsettlers.main.android.mainmenu.presenters.MainMenuPresenter; -import jsettlers.main.android.mainmenu.ui.activities.SettingsActivity_; -import jsettlers.main.android.mainmenu.ui.dialogs.DirectoryPickerDialog; -import jsettlers.main.android.mainmenu.views.MainMenuView; - -import android.Manifest; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.Fragment; -import android.support.v4.content.ContextCompat; -import android.support.v7.widget.Toolbar; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.Button; -import android.widget.LinearLayout; - -/** - * A simple {@link Fragment} subclass. - */ -@EFragment(R.layout.fragment_main_menu) -@OptionsMenu(R.menu.fragment_mainmenu) -public class MainMenuFragment extends Fragment implements MainMenuView, DirectoryPickerDialog.Listener { - private static final int REQUEST_CODE_PERMISSION_STORAGE = 10; - - private MainMenuPresenter presenter; - - @ViewById(R.id.linear_layout_main) - LinearLayout mainLinearLayout; - @ViewById(R.id.card_view_resume) - View resumeView; - @ViewById(R.id.button_pause) - Button pauseButton; - @ViewById(R.id.button_quit) - Button quitButton; - @ViewById(R.id.toolbar) - Toolbar toolbar; - - View resourcesView; - - private boolean showDirectoryPicker = false; - - public static MainMenuFragment create() { - return new MainMenuFragment_(); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - presenter = PresenterFactory.createMainMenuPresenter(getActivity(), this); - } - - @AfterViews - public void afterViews() { - FragmentUtil.setActionBar(this, toolbar); - presenter.initView(); - } - - @Override - public void onResume() { - super.onResume(); - getActivity().setTitle(R.string.app_name); - - // Work around for IllegalStateException when trying to show dialog from onPermissionResult which is too soon in the lifecycle. - if (showDirectoryPicker) { - showDirectoryPicker(); - showDirectoryPicker = false; - } - - presenter.updateResumeGameView(); - } - - @Override - public void onPause() { - super.onPause(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_item_settings: - SettingsActivity_.intent(this).start(); - break; - default: - return super.onOptionsItemSelected(item); - } - return true; - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - switch (requestCode) { - case REQUEST_CODE_PERMISSION_STORAGE: - if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - showDirectoryPicker = true; - } - break; - } - } - - /** - * MainMenuView implementation - */ - @Override - public void showResourcePicker() { - LayoutInflater inflater = LayoutInflater.from(getActivity()); - resourcesView = inflater.inflate(R.layout.include_resources_card, mainLinearLayout, false); - mainLinearLayout.addView(resourcesView, 0); - - Button button = (Button) resourcesView.findViewById(R.id.button_resources); - button.setOnClickListener(v -> showDirectoryPicker()); - } - - @Override - public void hideResourcePicker() { - mainLinearLayout.removeView(resourcesView); - } - - @Override - public void updatePauseButton(boolean paused) { - pauseButton.setText(paused ? R.string.game_menu_unpause : R.string.game_menu_pause); - } - - @Override - public void updateQuitButton(boolean canQuitConfirm) { - quitButton.setText(canQuitConfirm ? R.string.game_menu_quit_confirm : R.string.game_menu_quit); - } - - @Override - public void showResumeGameView() { - resumeView.setVisibility(View.VISIBLE); - } - - @Override - public void hideResumeGameView() { - resumeView.setVisibility(View.GONE); - } - - /** - * DirectoryPickerDialog.Listener implementation - */ - @Override - public void onDirectorySelected() { - presenter.resourceDirectoryChosen(); - } - - private void showDirectoryPicker() { - if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - requestPermissions(new String[] { Manifest.permission.READ_EXTERNAL_STORAGE }, REQUEST_CODE_PERMISSION_STORAGE); - } else { - DirectoryPickerDialog.newInstance().show(getChildFragmentManager(), null); - } - } - - @Click(R.id.card_view_resume) - void resumeView() { - presenter.resumeSelected(); - } - - @Click(R.id.button_quit) - void quitClicked() { - presenter.quitSelected(); - } - - @Click(R.id.button_pause) - void pauseClicked() { - presenter.pauseSelected(); - } - - @Click(R.id.button_new_single_player_game) - void newSinglePlayerGameClicked() { - presenter.newSinglePlayerSelected(); - } - - @Click(R.id.button_load_single_player_game) - void loadSinglePlayerGameClicked() { - presenter.loadSinglePlayerSelected(); - } - - @Click(R.id.button_new_multi_player_game) - void newMultiPlayerGameClicked() { - presenter.newMultiPlayerSelected(); - } - - @Click(R.id.button_join_multi_player_game) - void joinMultiplayerGameClicked() { - presenter.joinMultiPlayerSelected(); - } - - @Receiver(actions = ACTION_QUIT, local = true) - void quitReceived() { - presenter.updateResumeGameView(); - } - - @Receiver(actions = ACTION_QUIT_CONFIRM, local = true) - void quitConfirmReceived() { - presenter.updateResumeGameView(); - } - - @Receiver(actions = ACTION_QUIT_CANCELLED, local = true) - void quitCancelled() { - presenter.updateResumeGameView(); - } - - @Receiver(actions = ACTION_PAUSE, local = true) - void pauseReceived() { - presenter.updateResumeGameView(); - } - - @Receiver(actions = ACTION_UNPAUSE, local = true) - void unpauseReceived() { - presenter.updateResumeGameView(); - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/setup/JoinMultiPlayerSetupFragment.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/setup/JoinMultiPlayerSetupFragment.java deleted file mode 100644 index 809b6fa77f..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/ui/fragments/setup/JoinMultiPlayerSetupFragment.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.ui.fragments.setup; - -import org.androidannotations.annotations.EFragment; - -import jsettlers.common.menu.IMapDefinition; -import jsettlers.main.android.R; -import jsettlers.main.android.mainmenu.factories.PresenterFactory; -import jsettlers.main.android.mainmenu.presenters.setup.JoinMultiPlayerSetupPresenter; -import jsettlers.main.android.mainmenu.views.JoinMultiPlayerSetupView; - -import android.support.v4.app.Fragment; - -/** - * Created by tompr on 22/01/2017. - */ -@EFragment(R.layout.fragment_new_single_player_setup) -public class JoinMultiPlayerSetupFragment extends MapSetupFragment implements JoinMultiPlayerSetupView { - - public static Fragment create(IMapDefinition mapDefinition) { - return JoinMultiPlayerSetupFragment_.builder().mapId(mapDefinition.getMapId()).build(); - } - - @Override - protected JoinMultiPlayerSetupPresenter createPresenter() { - return PresenterFactory.createJoinMultiPlayerSetupPresenter(getActivity(), this, mapId); - } - - @Override - protected int getListItemLayoutId() { - return R.layout.item_multiplayer_playerslot; - } - - /** - * JoinMultiPlayerSetupView implementation - */ - @Override - public void disableHostOnlyControls() { - numberOfPlayersSpinner.setEnabled(false); - startResourcesSpinner.setEnabled(false); - peacetimeSpinner.setEnabled(false); - } -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/JoinMultiPlayerPickerView.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/JoinMultiPlayerPickerView.java deleted file mode 100644 index 98dec79044..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/JoinMultiPlayerPickerView.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.views; - -import java.util.List; - -import jsettlers.common.menu.IJoinableGame; - -/** - * Created by tompr on 22/01/2017. - */ -public interface JoinMultiPlayerPickerView { - void updateJoinableGames(List joinableGames); - - void setJoiningProgress(String stateString, int progressPercentage); - - void dismissJoiningProgress(); - - void showSearchingForGamesView(); - - void hideSearchingForGamesView(); - -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/JoinMultiPlayerSetupView.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/JoinMultiPlayerSetupView.java deleted file mode 100644 index a1b1925d9f..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/JoinMultiPlayerSetupView.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.views; - -/** - * Created by tompr on 22/01/2017. - */ -public interface JoinMultiPlayerSetupView extends MapSetupView { - void disableHostOnlyControls(); -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/LoadSinglePlayerPickerView.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/LoadSinglePlayerPickerView.java deleted file mode 100644 index 856dbd7354..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/LoadSinglePlayerPickerView.java +++ /dev/null @@ -1,10 +0,0 @@ -package jsettlers.main.android.mainmenu.views; - -/** - * Created by tompr on 07/05/2017. - */ - -public interface LoadSinglePlayerPickerView extends MapPickerView { - void hideNoGamesView(); - void showNoGamesView(); -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/MainMenuView.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/MainMenuView.java deleted file mode 100644 index 62ea31a691..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/MainMenuView.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.views; - -/** - * Created by tompr on 04/03/2017. - */ -public interface MainMenuView { - void showResourcePicker(); - - void hideResourcePicker(); - - void updatePauseButton(boolean paused); - - void updateQuitButton(boolean canQuitConfirm); - - void showResumeGameView(); - - void hideResumeGameView(); -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/MapSetupView.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/MapSetupView.java deleted file mode 100644 index f18c470651..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/MapSetupView.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.views; - -import java.util.List; - -import jsettlers.main.android.mainmenu.presenters.setup.Peacetime; -import jsettlers.main.android.mainmenu.presenters.setup.PlayerCount; -import jsettlers.main.android.mainmenu.presenters.setup.StartResources; -import jsettlers.main.android.mainmenu.presenters.setup.playeritem.PlayerSlotPresenter; - -/** - * Created by tompr on 22/01/2017. - */ -public interface MapSetupView { - void setNumberOfPlayersOptions(PlayerCount[] playerCounts); - - void setStartResourcesOptions(StartResources[] startResources); - - void setPeaceTimeOptions(Peacetime[] peaceTimeOptions); - - void setMapName(String mapName); - - void setMapImage(short[] image); - - void setItems(List items, int playerLimit); - - void setPlayerCount(PlayerCount playerCount); - - void setStartResources(StartResources item); -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/NewMultiPlayerPickerView.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/NewMultiPlayerPickerView.java deleted file mode 100644 index 6cca8b9db4..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/NewMultiPlayerPickerView.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.views; - -/** - * Created by tompr on 22/01/2017. - */ -public interface NewMultiPlayerPickerView extends MapPickerView { - void setJoiningProgress(String stateString, int progressPercentage); - - void dismissJoiningProgress(); -} diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/NewMultiPlayerSetupView.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/NewMultiPlayerSetupView.java deleted file mode 100644 index 5ce5dbc220..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/NewMultiPlayerSetupView.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.views; - -/** - * Created by tompr on 22/01/2017. - */ -public interface NewMultiPlayerSetupView extends MapSetupView { - // void setItems(List items); -} \ No newline at end of file diff --git a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/NewSinglePlayerSetupView.java b/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/NewSinglePlayerSetupView.java deleted file mode 100644 index feb254f5f6..0000000000 --- a/jsettlers.main.android/src/main/java/jsettlers/main/android/mainmenu/views/NewSinglePlayerSetupView.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package jsettlers.main.android.mainmenu.views; - -/** - * Created by tompr on 22/01/2017. - */ -public interface NewSinglePlayerSetupView extends MapSetupView { -} diff --git a/jsettlers.main.android/src/main/res/drawable-v21/bg_decrement.xml b/jsettlers.main.android/src/main/res/drawable-v21/bg_decrement.xml new file mode 100644 index 0000000000..f1b19b7723 --- /dev/null +++ b/jsettlers.main.android/src/main/res/drawable-v21/bg_decrement.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jsettlers.main.android/src/main/res/drawable-v21/bg_increment.xml b/jsettlers.main.android/src/main/res/drawable-v21/bg_increment.xml new file mode 100644 index 0000000000..f090ad7fe4 --- /dev/null +++ b/jsettlers.main.android/src/main/res/drawable-v21/bg_increment.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jsettlers.main.android/src/main/res/drawable/bg_decrement.xml b/jsettlers.main.android/src/main/res/drawable/bg_decrement.xml new file mode 100644 index 0000000000..dea5b0bd27 --- /dev/null +++ b/jsettlers.main.android/src/main/res/drawable/bg_decrement.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/jsettlers.main.android/src/main/res/drawable/bg_increment.xml b/jsettlers.main.android/src/main/res/drawable/bg_increment.xml new file mode 100644 index 0000000000..d18dc46d42 --- /dev/null +++ b/jsettlers.main.android/src/main/res/drawable/bg_increment.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/jsettlers.main.android/src/main/res/drawable/bg_material_count.xml b/jsettlers.main.android/src/main/res/drawable/bg_material_count.xml new file mode 100644 index 0000000000..fb54087113 --- /dev/null +++ b/jsettlers.main.android/src/main/res/drawable/bg_material_count.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/jsettlers.main.android/src/main/res/layout/dialog_directory_picker.xml b/jsettlers.main.android/src/main/res/layout/dialog_directory_picker.xml new file mode 100644 index 0000000000..c287f2f1ff --- /dev/null +++ b/jsettlers.main.android/src/main/res/layout/dialog_directory_picker.xml @@ -0,0 +1,19 @@ + + + + + + + + \ No newline at end of file diff --git a/jsettlers.main.android/src/main/res/layout/fragment_main_menu.xml b/jsettlers.main.android/src/main/res/layout/fragment_main_menu.xml index 9eebdea02d..53a52f57d2 100644 --- a/jsettlers.main.android/src/main/res/layout/fragment_main_menu.xml +++ b/jsettlers.main.android/src/main/res/layout/fragment_main_menu.xml @@ -1,192 +1,254 @@ - + - + + + - + android:layout_height="match_parent" + android:orientation="vertical" + tools:context=".mainmenu.ui.fragments.MainMenuFragment_"> - + + - - + + - - + android:animateLayoutChanges="true" + android:orientation="vertical" + android:paddingBottom="8dp" + android:paddingTop="8dp"> - + + android:orientation="vertical"> -