[update] big update
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "puzzlez",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.2",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"dateformat": "^3.0.3",
|
||||
|
||||
44
src/haxe/ru/m/Device.hx
Normal file
44
src/haxe/ru/m/Device.hx
Normal file
@@ -0,0 +1,44 @@
|
||||
package ru.m;
|
||||
|
||||
@:enum abstract Platform(String) from String to String {
|
||||
var ANDROID = "android";
|
||||
var LINUX = "linux";
|
||||
var WINDOWS = "windows";
|
||||
}
|
||||
|
||||
class Device {
|
||||
|
||||
public static var platform(get, null):Platform;
|
||||
|
||||
private static function get_platform():Platform {
|
||||
#if android
|
||||
return ANDROID;
|
||||
#elseif linux
|
||||
return LINUX;
|
||||
#elseif windows
|
||||
return WINDOWS;
|
||||
#else
|
||||
return null;
|
||||
#end
|
||||
}
|
||||
|
||||
private static var MOBILES(default, never):Array<String> = [
|
||||
"Android", "webOS", "iPhone", "iPad", "iPod", "BlackBerry", "Windows Phone",
|
||||
];
|
||||
|
||||
public static function isMobile():Bool {
|
||||
#if android
|
||||
return true;
|
||||
#elseif js
|
||||
var userAgent = js.Browser.navigator.userAgent;
|
||||
for (mobile in MOBILES) {
|
||||
if (userAgent.indexOf(mobile) > -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#end
|
||||
}
|
||||
}
|
||||
@@ -5,14 +5,18 @@ import haxework.log.TraceLogger;
|
||||
import ru.m.puzzlez.storage.GameStorage;
|
||||
import ru.m.puzzlez.storage.ImageStorage;
|
||||
import ru.m.puzzlez.view.PuzzlezAppView;
|
||||
import ru.m.update.Updater;
|
||||
|
||||
class PuzzlezApp extends App {
|
||||
|
||||
@:provide static var updater:Updater;
|
||||
|
||||
public static function main() {
|
||||
// ToDo: fix @:provide macro
|
||||
GameStorage;
|
||||
ImageStorage;
|
||||
L.push(new TraceLogger());
|
||||
updater = new Updater(Const.VERSION, "https://shmyga.ru/repo/puzzlez/packages.json");
|
||||
var app = new PuzzlezApp(new PuzzlezTheme(), openfl.Assets.getBitmapData("resources/icon.png"));
|
||||
var view = new PuzzlezAppView();
|
||||
app.start(view);
|
||||
|
||||
@@ -3,9 +3,10 @@ package ru.m.puzzlez.core;
|
||||
import haxework.geom.Point;
|
||||
import haxework.geom.Rectangle;
|
||||
import ru.m.puzzlez.core.BoundType;
|
||||
import ru.m.puzzlez.core.GameState.GameStatus;
|
||||
import ru.m.puzzlez.core.GameState;
|
||||
import ru.m.puzzlez.core.Id;
|
||||
import ru.m.puzzlez.core.Part;
|
||||
import ru.m.puzzlez.core.PartLocation;
|
||||
import ru.m.puzzlez.core.Side;
|
||||
|
||||
class BoundsMap {
|
||||
@@ -66,11 +67,13 @@ class BoundsMap {
|
||||
|
||||
class GameUtil {
|
||||
|
||||
private static function normilizeSize(size:Int, maxValue:Int = 8):Int {
|
||||
private static inline var MAX_SIZE = 20;
|
||||
|
||||
private static function normilizeSize(size:Int, maxValue:Int = MAX_SIZE):Int {
|
||||
return Math.isNaN(size) ? maxValue : size < 1 ? 1 : size > maxValue ? maxValue : size;
|
||||
}
|
||||
|
||||
public static function buildPreset(imageId:ImageId, width:Int = 8, height:Int = 8):GamePreset {
|
||||
public static function buildPreset(imageId:ImageId, width:Int = 8, height:Int = MAX_SIZE):GamePreset {
|
||||
width = normilizeSize(width);
|
||||
height = normilizeSize(height);
|
||||
var offsetX = 500;
|
||||
@@ -119,7 +122,7 @@ class GameUtil {
|
||||
id: id,
|
||||
gridX: x,
|
||||
gridY: y,
|
||||
location: PartLocation.TABLE(position),
|
||||
location: TABLE(position),
|
||||
bounds: bounds,
|
||||
rect: new Rectangle(0, 0, partWidth, partHeight),
|
||||
});
|
||||
@@ -136,7 +139,7 @@ class GameUtil {
|
||||
var complete = 0;
|
||||
for (part in state.parts) {
|
||||
switch part.location {
|
||||
case PartLocation.IMAGE: complete++;
|
||||
case IMAGE: complete++;
|
||||
case _:
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package ru.m.puzzlez.render;
|
||||
|
||||
import ru.m.puzzlez.render.RenderUtil;
|
||||
import flash.display.BitmapData;
|
||||
import haxe.Timer;
|
||||
import promhx.PublicStream;
|
||||
@@ -8,7 +9,7 @@ import ru.m.puzzlez.core.Part;
|
||||
|
||||
typedef Result = {
|
||||
var part:Part;
|
||||
var image:BitmapData;
|
||||
var image:PartImage;
|
||||
}
|
||||
|
||||
class ImagePartBuilder {
|
||||
@@ -25,8 +26,8 @@ class ImagePartBuilder {
|
||||
return;
|
||||
}
|
||||
var part = parts[i];
|
||||
var partImage = RenderUtil.cropImagePart(image, part);
|
||||
stream.update({part: part, image: partImage});
|
||||
var image = RenderUtil.cropImagePart(image, part);
|
||||
stream.update({part: part, image: image});
|
||||
}
|
||||
Timer.delay(() -> buildPart(index + count, count, parts, stream), 0);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package ru.m.puzzlez.render;
|
||||
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.PixelSnapping;
|
||||
import flash.display.Sprite;
|
||||
import haxework.geom.Point;
|
||||
import ru.m.puzzlez.core.Part;
|
||||
import ru.m.puzzlez.render.RenderUtil;
|
||||
|
||||
class PartView extends Sprite {
|
||||
|
||||
@@ -20,9 +20,9 @@ class PartView extends Sprite {
|
||||
return position;
|
||||
}
|
||||
|
||||
public var image(default, set):BitmapData;
|
||||
public var image(default, set):PartImage;
|
||||
|
||||
private function set_image(value:BitmapData):BitmapData {
|
||||
private function set_image(value:PartImage):PartImage {
|
||||
image = value;
|
||||
redraw();
|
||||
refresh();
|
||||
@@ -44,14 +44,15 @@ class PartView extends Sprite {
|
||||
|
||||
private function refresh():Void {
|
||||
if (position != null && image != null) {
|
||||
x = position.x - (image.width - size.x) / 2;
|
||||
y = position.y - (image.height - size.y) / 2;
|
||||
x = position.x - (image.borderedImage.width - size.x) / 2;
|
||||
y = position.y - (image.borderedImage.height - size.y) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
public function complete():Void {
|
||||
position = target;
|
||||
completed = true;
|
||||
redraw();
|
||||
}
|
||||
|
||||
public static function factory(part:Part):PartView {
|
||||
@@ -62,6 +63,10 @@ class PartView extends Sprite {
|
||||
class SpritePartView extends PartView {
|
||||
|
||||
override private function redraw():Void {
|
||||
if (image == null) {
|
||||
return;
|
||||
}
|
||||
var image = completed ? image.borderedImage : image.shadedImage;
|
||||
graphics.clear();
|
||||
graphics.beginBitmapFill(image, null, false, true);
|
||||
graphics.drawRect(0, 0, image.width, image.height);
|
||||
@@ -79,6 +84,6 @@ class BitmapPartView extends PartView {
|
||||
}
|
||||
|
||||
override private function redraw():Void {
|
||||
bitmap.bitmapData = image;
|
||||
bitmap.bitmapData = completed ? image.borderedImage : image.shadedImage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package ru.m.puzzlez.render;
|
||||
|
||||
import haxework.geom.Point;
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.PNGEncoderOptions;
|
||||
import flash.display.Sprite;
|
||||
@@ -9,12 +8,14 @@ import flash.geom.Point as FlashPoint;
|
||||
import flash.geom.Rectangle;
|
||||
import flash.net.FileReference;
|
||||
import flash.utils.ByteArray;
|
||||
import haxework.geom.Point;
|
||||
import haxework.signal.Signal;
|
||||
import haxework.view.popup.AlertView;
|
||||
import haxework.view.SpriteView;
|
||||
import ru.m.puzzlez.core.GameEvent;
|
||||
import ru.m.puzzlez.core.GameState;
|
||||
import ru.m.puzzlez.core.PartLocation;
|
||||
import ru.m.puzzlez.render.ImagePartBuilder;
|
||||
import ru.m.puzzlez.storage.ImageStorage;
|
||||
|
||||
class Render extends SpriteView implements IRender {
|
||||
@@ -110,7 +111,7 @@ class Render extends SpriteView implements IRender {
|
||||
this.image = RenderUtil.cropImage(image, state.preset.imageRect);
|
||||
var builder = new ImagePartBuilder(this.image);
|
||||
var i = 0;
|
||||
builder.build(state.parts).then(function(result) {
|
||||
builder.build(state.parts).then((result:Result) -> {
|
||||
parts[result.part.id].image = result.image;
|
||||
progress.setProgress(++i, state.parts.length);
|
||||
if (i >= state.parts.length - 1) {
|
||||
@@ -166,7 +167,7 @@ class Render extends SpriteView implements IRender {
|
||||
|
||||
private function save(part:PartView):Void {
|
||||
var file = new FileReference();
|
||||
var image = part.image;
|
||||
var image = part.image.shadedImage;
|
||||
var data = new ByteArray();
|
||||
image.encode(new Rectangle(0, 0, image.width, image.height), new PNGEncoderOptions(), data);
|
||||
file.save(data, "icon.png");
|
||||
|
||||
@@ -1,17 +1,40 @@
|
||||
package ru.m.puzzlez.render;
|
||||
|
||||
import ru.m.draw.DrawPath;
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.Shape;
|
||||
import flash.geom.Matrix;
|
||||
import haxework.color.Color;
|
||||
import haxework.geom.Point;
|
||||
import haxework.geom.Rectangle;
|
||||
import ru.m.draw.DrawPath;
|
||||
import ru.m.puzzlez.core.Part;
|
||||
import ru.m.puzzlez.render.part.ClassicPartBuilder;
|
||||
import ru.m.puzzlez.render.part.IPartBuilder;
|
||||
import ru.m.puzzlez.render.part.PartMask;
|
||||
|
||||
typedef DrawSetting = {
|
||||
var offset:Point;
|
||||
var color:Color;
|
||||
var opacity:Float;
|
||||
}
|
||||
|
||||
typedef PartImage = {
|
||||
var borderedImage:BitmapData;
|
||||
var shadedImage:BitmapData;
|
||||
}
|
||||
|
||||
class RenderUtil {
|
||||
private static var builder:IPartBuilder = new ClassicPartBuilder();
|
||||
public static var shadowSettings(default, null):Array<DrawSetting> = [
|
||||
{offset: new Point(-2, -2), color: 0x000000, opacity: 0.4},
|
||||
{offset: new Point(2, 2), color: 0xffffff, opacity: 0.4},
|
||||
];
|
||||
|
||||
public static var borderSettings(default, null):Array<DrawSetting> = [
|
||||
{offset: new Point(-1, -1), color: 0x555555, opacity: 0.4},
|
||||
{offset: new Point(1, 1), color: 0xcccccc, opacity: 0.4},
|
||||
];
|
||||
|
||||
public static var builder(default, null):IPartBuilder = new ClassicPartBuilder();
|
||||
|
||||
public static function cropImage(source:BitmapData, rect:Rectangle):BitmapData {
|
||||
var image = new BitmapData(Std.int(rect.width), Std.int(rect.height));
|
||||
@@ -37,17 +60,14 @@ class RenderUtil {
|
||||
return {rect:rect, drawRect:drawRect};
|
||||
}
|
||||
|
||||
private static function drawShadow(source:BitmapData, path:DrawPath):BitmapData {
|
||||
var shadow = 2;
|
||||
var opacity = 0.4;
|
||||
private static function drawShadow(source:BitmapData, path:DrawPath, values:Array<DrawSetting>):BitmapData {
|
||||
var canvas = new Shape();
|
||||
canvas.cacheAsBitmap = true;
|
||||
canvas.graphics.beginFill(0x000000, opacity);
|
||||
path.move(-shadow, -shadow).draw(canvas.graphics);
|
||||
canvas.graphics.endFill();
|
||||
canvas.graphics.beginFill(0xffffff, opacity);
|
||||
path.move(shadow, shadow).draw(canvas.graphics);
|
||||
canvas.graphics.endFill();
|
||||
for (value in values) {
|
||||
canvas.graphics.beginFill(value.color, value.opacity);
|
||||
path.move(value.offset.x, value.offset.y).draw(canvas.graphics);
|
||||
canvas.graphics.endFill();
|
||||
}
|
||||
canvas.graphics.beginBitmapFill(source, null, false, true);
|
||||
canvas.graphics.drawRect(0, 0, source.width, source.height);
|
||||
canvas.graphics.endFill();
|
||||
@@ -56,7 +76,23 @@ class RenderUtil {
|
||||
return image;
|
||||
}
|
||||
|
||||
public static function cropImagePart(source:BitmapData, part:Part):BitmapData {
|
||||
private static function drawBorder(source:BitmapData, path:DrawPath, values:Array<DrawSetting>):BitmapData {
|
||||
var canvas = new Shape();
|
||||
canvas.cacheAsBitmap = true;
|
||||
for (value in values) {
|
||||
canvas.graphics.lineStyle(2, value.color, value.opacity);
|
||||
path.move(value.offset.x, value.offset.y).draw(canvas.graphics);
|
||||
canvas.graphics.lineStyle();
|
||||
}
|
||||
canvas.graphics.beginBitmapFill(source, null, false, true);
|
||||
canvas.graphics.drawRect(0, 0, source.width, source.height);
|
||||
canvas.graphics.endFill();
|
||||
var image = new BitmapData(source.width, source.height, true, 0x00000000);
|
||||
image.draw(canvas, null, null, null, null, true);
|
||||
return image;
|
||||
}
|
||||
|
||||
public static function cropImagePart(source:BitmapData, part:Part, completed:Bool = false):PartImage {
|
||||
var geometry = buildPartGeometry(part);
|
||||
var path = builder.build(geometry.drawRect, part.bounds);
|
||||
var canvas:Shape = new Shape();
|
||||
@@ -69,7 +105,9 @@ class RenderUtil {
|
||||
canvas.graphics.endFill();
|
||||
var image = new BitmapData(Std.int(geometry.rect.width), Std.int(geometry.rect.height), true, 0x00000000);
|
||||
image.draw(canvas, null, null, null, null, true);
|
||||
return drawShadow(image, path);
|
||||
var shadedImage = drawShadow(image, path, shadowSettings);
|
||||
var borderedImage = drawBorder(image, path, borderSettings);
|
||||
return {borderedImage: borderedImage, shadedImage: shadedImage};
|
||||
}
|
||||
|
||||
public static function containRectangle(source:Rectangle, target:Rectangle):Rectangle {
|
||||
|
||||
@@ -10,8 +10,8 @@ class BasePartBuilder implements IPartBuilder {
|
||||
public function new() {
|
||||
}
|
||||
|
||||
private function createAngle(path:DrawPath, x:Float, y:Float):Void {
|
||||
path.commands.push(LINE_TO(x, y));
|
||||
private function createAngle(path:DrawPath, x:Float, y:Float, first: Bool = false):Void {
|
||||
path.commands.push(first ? MOVE_TO(x, y) : LINE_TO(x, y));
|
||||
}
|
||||
|
||||
private function createBound(path:DrawPath, fromX:Float, fromY:Float, toX:Float, toY:Float, bound:PartBound):Void {
|
||||
@@ -19,7 +19,7 @@ class BasePartBuilder implements IPartBuilder {
|
||||
|
||||
public function build(rect:Rectangle, bounds:PartBounds):DrawPath {
|
||||
var path = new DrawPath();
|
||||
createAngle(path, rect.left, rect.top);
|
||||
createAngle(path, rect.left, rect.top, true);
|
||||
createBound(path, rect.left, rect.top, rect.right, rect.top, bounds.top);
|
||||
createAngle(path, rect.right, rect.top);
|
||||
createBound(path, rect.right, rect.top, rect.right, rect.bottom, bounds.right);
|
||||
|
||||
@@ -44,7 +44,10 @@ import ru.m.puzzlez.core.Id;
|
||||
}
|
||||
|
||||
public function delete(imageId:ImageId):Void {
|
||||
Reflect.deleteField(statusData.data, imageId);
|
||||
var gameData = SharedObject.getLocal('${path}/${imageId}');
|
||||
gameData.clear();
|
||||
var data:DynamicAccess<GameStatus> = statusData.data;
|
||||
data.remove(imageId);
|
||||
statusData.flush();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package ru.m.puzzlez.view;
|
||||
|
||||
import haxe.Timer;
|
||||
import haxework.view.frame.FrameSwitcher;
|
||||
import haxework.view.frame.FrameView;
|
||||
import ru.m.puzzlez.core.Game;
|
||||
@@ -17,7 +18,7 @@ import ru.m.puzzlez.storage.GameStorage;
|
||||
@:provide var switcher:FrameSwitcher;
|
||||
@:provide var storage:GameStorage;
|
||||
|
||||
private var toSave:Bool;
|
||||
private var saveTimer:Timer;
|
||||
|
||||
public function new() {
|
||||
super(ID);
|
||||
@@ -33,6 +34,7 @@ import ru.m.puzzlez.storage.GameStorage;
|
||||
}
|
||||
|
||||
override public function onHide():Void {
|
||||
save();
|
||||
if (game != null) {
|
||||
render.signal.disconnect(game.signal.emit);
|
||||
game.stop();
|
||||
@@ -41,12 +43,28 @@ import ru.m.puzzlez.storage.GameStorage;
|
||||
}
|
||||
}
|
||||
|
||||
private function toSave():Void {
|
||||
if (saveTimer != null) {
|
||||
saveTimer = Timer.delay(save, 500);
|
||||
}
|
||||
}
|
||||
|
||||
private function save():Void {
|
||||
if (saveTimer != null) {
|
||||
saveTimer.stop();
|
||||
saveTimer = null;
|
||||
}
|
||||
if (game != null) {
|
||||
storage.save(game.state);
|
||||
}
|
||||
}
|
||||
|
||||
private function onGameEvent(event:GameEvent):Void {
|
||||
switch event {
|
||||
case START(state):
|
||||
storage.save(state);
|
||||
toSave();
|
||||
case ACTION(PART_PUT(_, _)):
|
||||
storage.save(game.state);
|
||||
toSave();
|
||||
case _:
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package ru.m.puzzlez.view;
|
||||
import haxework.view.form.InputView;
|
||||
|
||||
import haxework.geom.IntPoint;
|
||||
import haxework.view.data.DataView;
|
||||
import haxework.view.form.ToggleButtonView;
|
||||
import haxework.view.frame.FrameSwitcher;
|
||||
import haxework.view.frame.FrameView;
|
||||
import haxework.view.list.ScrollBarView;
|
||||
import ru.m.puzzlez.core.GameUtil;
|
||||
import ru.m.puzzlez.core.Id;
|
||||
import ru.m.puzzlez.storage.ImageStorage;
|
||||
@@ -11,9 +13,7 @@ import ru.m.puzzlez.storage.ImageStorage;
|
||||
public static var ID = "preset";
|
||||
|
||||
@:view("image") var imageView:PresetView;
|
||||
@:view("scroll") var scrollView:ScrollBarView;
|
||||
@:view("width") var widthView:InputView;
|
||||
@:view("height") var heightView:InputView;
|
||||
@:view("sizes") var sizesView:DataView<IntPoint, ToggleButtonView>;
|
||||
|
||||
@:provide var imageStorage:ImageStorage;
|
||||
@:provide var switcher:FrameSwitcher;
|
||||
@@ -22,32 +22,38 @@ import ru.m.puzzlez.storage.ImageStorage;
|
||||
|
||||
public function new() {
|
||||
super(ID);
|
||||
widthView.text = "8";
|
||||
heightView.text = "8";
|
||||
scrollView.position = 0.8;
|
||||
widthView.update();
|
||||
heightView.update();
|
||||
sizesView.data = [
|
||||
new IntPoint(3, 2),
|
||||
new IntPoint(4, 3),
|
||||
new IntPoint(5, 4),
|
||||
new IntPoint(6, 5),
|
||||
new IntPoint(7, 6),
|
||||
new IntPoint(8, 7),
|
||||
new IntPoint(10, 8),
|
||||
];
|
||||
}
|
||||
|
||||
private function factory(index:Int, size:IntPoint):ToggleButtonView {
|
||||
var result = new ToggleButtonView();
|
||||
result.text = '${size.x}x${size.y}';
|
||||
return result;
|
||||
}
|
||||
|
||||
private function selectSize(size:IntPoint):Void {
|
||||
imageView.state = GameUtil.buildState(GameUtil.buildPreset(imageId, size.x, size.y));
|
||||
for (i in 0...sizesView.dataViews.length) {
|
||||
sizesView.dataViews[i].on = size == sizesView.data[i];
|
||||
}
|
||||
}
|
||||
|
||||
override public function onShow(data:ImageId):Void {
|
||||
super.onShow(data);
|
||||
imageId = data;
|
||||
updatePreset();
|
||||
}
|
||||
|
||||
private function updateGrid(value:Float):Void {
|
||||
var size = 2 + Std.int(value * 8);
|
||||
widthView.text = Std.string(size);
|
||||
heightView.text = Std.string(size);
|
||||
imageView.preset = GameUtil.buildPreset(imageId, size, size);
|
||||
}
|
||||
|
||||
private function updatePreset():Void {
|
||||
imageView.preset = GameUtil.buildPreset(imageId, Std.parseInt(widthView.text), Std.parseInt(heightView.text));
|
||||
selectSize(sizesView.data[sizesView.data.length - 1]);
|
||||
}
|
||||
|
||||
private function start():Void {
|
||||
switcher.change(GameFrame.ID, GameUtil.buildState(imageView.preset));
|
||||
switcher.change(GameFrame.ID, imageView.state);
|
||||
}
|
||||
|
||||
private function back():Void {
|
||||
|
||||
@@ -1,32 +1,25 @@
|
||||
---
|
||||
style: frame
|
||||
layout.margin: 10
|
||||
views:
|
||||
- $type: haxework.view.group.HGroupView
|
||||
geometry.width: 100%
|
||||
layout.hAlign: center
|
||||
layout.vAlign: middle
|
||||
views:
|
||||
- id: width
|
||||
$type: haxework.view.form.InputView
|
||||
geometry.width: 100
|
||||
+onChange: ~updatePreset()
|
||||
- $type: haxework.view.form.LabelView
|
||||
text: x
|
||||
- id: height
|
||||
$type: haxework.view.form.InputView
|
||||
geometry.width: 100
|
||||
+onChange: ~updatePreset()
|
||||
- $type: haxework.view.form.ButtonView
|
||||
geometry.margin.left: 15
|
||||
text: Start
|
||||
+onPress: ~start()
|
||||
- id: scroll
|
||||
$type: haxework.view.list.HScrollBarView
|
||||
- id: sizes
|
||||
$type: haxework.view.data.DataView
|
||||
geometry.width: 100%
|
||||
geometry.height: 20
|
||||
ratio: 0.2
|
||||
position: 0.8
|
||||
+onScroll: ~updateGrid
|
||||
layout:
|
||||
$type: haxework.view.layout.TailLayout
|
||||
hAlign: center
|
||||
margin: 5
|
||||
factory: ~factory
|
||||
+onDataSelect: ~selectSize
|
||||
- id: image
|
||||
$type: ru.m.puzzlez.view.PresetView
|
||||
geometry.stretch: true
|
||||
|
||||
@@ -5,7 +5,7 @@ import flash.display.Graphics;
|
||||
import flash.display.Shape;
|
||||
import flash.geom.Matrix;
|
||||
import haxework.view.group.GroupView;
|
||||
import ru.m.puzzlez.core.GamePreset;
|
||||
import ru.m.puzzlez.core.GameState;
|
||||
import ru.m.puzzlez.render.RenderUtil;
|
||||
import ru.m.puzzlez.storage.ImageStorage;
|
||||
|
||||
@@ -20,23 +20,23 @@ class PresetView extends GroupView {
|
||||
|
||||
private function set_scale(value:Float):Float {
|
||||
var result = table.scaleX = table.scaleY = value;
|
||||
table.x = (width - preset.tableRect.width * value) / 2;
|
||||
table.y = (height - preset.tableRect.height * value) / 2;
|
||||
table.x = (width - state.preset.tableRect.width * value) / 2;
|
||||
table.y = (height - state.preset.tableRect.height * value) / 2;
|
||||
return result;
|
||||
}
|
||||
|
||||
public var preset(default, set):GamePreset;
|
||||
public var state(default, set):GameState;
|
||||
|
||||
private function set_preset(value:GamePreset) {
|
||||
preset = value;
|
||||
private function set_state(value:GameState):GameState {
|
||||
state = value;
|
||||
this.image = null;
|
||||
table.graphics.clear();
|
||||
loading.promise = imageStorage.resolve(preset.imageId).then(image -> {
|
||||
this.image = RenderUtil.cropImage(image, preset.imageRect);
|
||||
loading.promise = imageStorage.resolve(state.preset.imageId).then(image -> {
|
||||
this.image = RenderUtil.cropImage(image, state.preset.imageRect);
|
||||
toRedraw();
|
||||
toUpdate();
|
||||
});
|
||||
return preset;
|
||||
return state;
|
||||
}
|
||||
|
||||
private var loading:LoadingWrapper;
|
||||
@@ -52,9 +52,10 @@ class PresetView extends GroupView {
|
||||
private var image:BitmapData;
|
||||
|
||||
override public function redraw():Void {
|
||||
if (preset == null || image == null) {
|
||||
if (state == null || image == null) {
|
||||
return;
|
||||
}
|
||||
var preset = state.preset;
|
||||
var partWidth = preset.imageRect.width / preset.grid.width;
|
||||
var partHeight = preset.imageRect.height / preset.grid.height;
|
||||
var graphics:Graphics = table.graphics;
|
||||
@@ -64,32 +65,24 @@ class PresetView extends GroupView {
|
||||
graphics.beginBitmapFill(image, matrix, false, true);
|
||||
graphics.drawRect(preset.imageRect.x, preset.imageRect.y, preset.imageRect.width, preset.imageRect.height);
|
||||
graphics.endFill();
|
||||
graphics.lineStyle(1, 0x555555);
|
||||
for (x in 0...preset.grid.width + 1) {
|
||||
graphics.moveTo(preset.imageRect.x + x * partWidth, preset.imageRect.y);
|
||||
graphics.lineTo(preset.imageRect.x + x * partWidth, preset.imageRect.y + preset.imageRect.height);
|
||||
|
||||
for (part in state.parts) {
|
||||
var rect = part.rect.clone();
|
||||
rect.x = preset.imageRect.x + part.gridX * part.rect.width;
|
||||
rect.y = preset.imageRect.y + part.gridY * part.rect.height;
|
||||
var path = RenderUtil.builder.build(rect, part.bounds);
|
||||
for (value in RenderUtil.borderSettings) {
|
||||
graphics.lineStyle(1, value.color, value.opacity);
|
||||
path.move(value.offset.x, value.offset.y).draw(graphics);
|
||||
graphics.lineStyle();
|
||||
}
|
||||
}
|
||||
for (y in 0...preset.grid.height + 1) {
|
||||
graphics.moveTo(preset.imageRect.x, preset.imageRect.y + y * partHeight);
|
||||
graphics.lineTo(preset.imageRect.x + preset.imageRect.width, preset.imageRect.y + y * partHeight);
|
||||
}
|
||||
graphics.lineStyle(1, 0xcccccc);
|
||||
var offset = 1;
|
||||
for (x in 0...preset.grid.width + 1) {
|
||||
graphics.moveTo(offset + preset.imageRect.x + x * partWidth, preset.imageRect.y);
|
||||
graphics.lineTo(offset + preset.imageRect.x + x * partWidth, preset.imageRect.y + preset.imageRect.height);
|
||||
}
|
||||
for (y in 0...preset.grid.height + 1) {
|
||||
graphics.moveTo(preset.imageRect.x, offset + preset.imageRect.y + y * partHeight);
|
||||
graphics.lineTo(preset.imageRect.x + preset.imageRect.width, offset + preset.imageRect.y + y * partHeight);
|
||||
}
|
||||
graphics.lineStyle();
|
||||
}
|
||||
|
||||
override public function update():Void {
|
||||
super.update();
|
||||
if (preset != null) {
|
||||
scale = Math.min(width / preset.tableRect.width, height / preset.tableRect.height);
|
||||
if (state != null) {
|
||||
scale = Math.min(width / state.preset.tableRect.width, height / state.preset.tableRect.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package ru.m.puzzlez.view;
|
||||
|
||||
import ru.m.update.Updater;
|
||||
import haxework.view.data.DataView;
|
||||
import haxework.view.form.ButtonView;
|
||||
import haxework.view.frame.FrameSwitcher;
|
||||
@@ -18,10 +19,12 @@ import ru.m.puzzlez.storage.ImageStorage;
|
||||
@:view var sources:DataView<ImageListSource<Dynamic>, ButtonView>;
|
||||
@:view("load") var loadButton:ButtonView;
|
||||
@:view("complete") var completeButton:ButtonView;
|
||||
@:view("update") var updateButton:ButtonView;
|
||||
|
||||
@:provide var storage:ImageStorage;
|
||||
@:provide var switcher:FrameSwitcher;
|
||||
@:provide var gameStorage:GameStorage;
|
||||
@:provide static var appUpdater:Updater;
|
||||
|
||||
public function new() {
|
||||
super(ID);
|
||||
@@ -45,6 +48,12 @@ import ru.m.puzzlez.storage.ImageStorage;
|
||||
|
||||
override public function onShow(data:Dynamic):Void {
|
||||
refresh();
|
||||
appUpdater.check().then((info:Null<PackageInfo>) -> {
|
||||
if (info != null) {
|
||||
updateButton.visible = true;
|
||||
updateButton.text = 'Update ${info.version}';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function sourceViewFactory(index:Int, source:ImageListSource<Dynamic>):ButtonView {
|
||||
|
||||
@@ -38,6 +38,11 @@ views:
|
||||
text: Clean
|
||||
+onPress: ~clean()
|
||||
visible: false
|
||||
- id: update
|
||||
$type: haxework.view.form.ButtonView
|
||||
style: button.active
|
||||
+onPress: ~appUpdater.download()
|
||||
visible: false
|
||||
- $type: haxework.view.form.LabelView
|
||||
text: $r:text:version
|
||||
geometry.position: absolute
|
||||
|
||||
83
src/haxe/ru/m/update/Updater.hx
Normal file
83
src/haxe/ru/m/update/Updater.hx
Normal file
@@ -0,0 +1,83 @@
|
||||
package ru.m.update;
|
||||
|
||||
import haxework.net.JsonLoader;
|
||||
import openfl.Lib;
|
||||
import openfl.net.URLRequest;
|
||||
import promhx.Promise;
|
||||
import ru.m.Device;
|
||||
import ru.m.update.Version;
|
||||
|
||||
@:enum abstract PackageType(String) from String to String {
|
||||
var APK = "apk";
|
||||
var DEB = "deb";
|
||||
var EXE = "exe";
|
||||
var ARCHIVE = "archive";
|
||||
}
|
||||
|
||||
typedef PackageInfo = {
|
||||
var platform:Platform;
|
||||
var type:PackageType;
|
||||
var path:String;
|
||||
var filename:String;
|
||||
var url:String;
|
||||
var version:String;
|
||||
}
|
||||
|
||||
typedef PackagesBundle = {
|
||||
var name:String;
|
||||
var version:String;
|
||||
var packages:Array<PackageInfo>;
|
||||
}
|
||||
|
||||
class Updater {
|
||||
|
||||
private static inline var TAG = "Update";
|
||||
|
||||
public var type(get, null):PackageType;
|
||||
public var bundle(get, null):Promise<PackagesBundle>;
|
||||
|
||||
private function get_bundle():Promise<PackagesBundle> {
|
||||
if (bundle == null) {
|
||||
bundle = new JsonLoader().GET(url);
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
||||
private var url:String;
|
||||
private var version:Version;
|
||||
|
||||
public function new(version:String, url:String) {
|
||||
this.url = url;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
private function get_type():PackageType {
|
||||
return switch Device.platform {
|
||||
case ANDROID: APK;
|
||||
case LINUX: DEB;
|
||||
case WINDOWS: EXE;
|
||||
case _: null;
|
||||
}
|
||||
}
|
||||
|
||||
public function check():Promise<Null<PackageInfo>> {
|
||||
return bundle.then((bundle:PackagesBundle) -> Lambda.find(bundle.packages, item -> (
|
||||
item.platform == Device.platform &&
|
||||
item.type == type &&
|
||||
version < Version.fromString(item.version)
|
||||
)));
|
||||
}
|
||||
|
||||
public function download():Promise<Bool> {
|
||||
return bundle.then((bundle:PackagesBundle) -> {
|
||||
for (item in bundle.packages) {
|
||||
if (item.platform == Device.platform && item.type == type) {
|
||||
L.i(TAG, 'download: ${item.url}');
|
||||
Lib.getURL(new URLRequest(item.url));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
52
src/haxe/ru/m/update/Version.hx
Normal file
52
src/haxe/ru/m/update/Version.hx
Normal file
@@ -0,0 +1,52 @@
|
||||
package ru.m.update;
|
||||
|
||||
abstract Version(Array<Int>) {
|
||||
|
||||
public function new(mayor:Int, minor:Int, patch:Int, snapshot:Bool = false) {
|
||||
this = [
|
||||
mayor,
|
||||
minor,
|
||||
patch,
|
||||
snapshot ? -1 : 0,
|
||||
];
|
||||
}
|
||||
|
||||
@:arrayAccess public inline function get(key:Int) return this[key];
|
||||
|
||||
public function compare(other:Version):Int {
|
||||
if (other == null) {
|
||||
return 1;
|
||||
}
|
||||
for (i in 0...4) {
|
||||
var d = this[i] - other[i];
|
||||
if (d != 0) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@:op(A > B) static function gt(a:Version, b:Version):Bool return a.compare(b) > 0;
|
||||
|
||||
@:op(A == B) static function eq(a:Version, b:Version):Bool return a.compare(b) == 0;
|
||||
|
||||
@:op(A < B) static function lt(a:Version, b:Version):Bool return a.compare(b) < 0;
|
||||
|
||||
@:from public static function fromString(value:String):Version {
|
||||
var r = ~/(\d+)\.(\d+)\.(\d+)(-SNAPSHOT)?/;
|
||||
return if (r.match(value)) {
|
||||
new Version(
|
||||
Std.parseInt(r.matched(1)),
|
||||
Std.parseInt(r.matched(2)),
|
||||
Std.parseInt(r.matched(3)),
|
||||
r.matched(4) != null
|
||||
);
|
||||
} else {
|
||||
new Version(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@:to public function toString():String {
|
||||
return '${this[0]}.${this[1]}.${this[2]}${this[3] < 0 ? "-SNAPSHOT" : ""}';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user