[update] big update
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "puzzlez",
|
"name": "puzzlez",
|
||||||
"version": "0.3.1",
|
"version": "0.3.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"dateformat": "^3.0.3",
|
"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.GameStorage;
|
||||||
import ru.m.puzzlez.storage.ImageStorage;
|
import ru.m.puzzlez.storage.ImageStorage;
|
||||||
import ru.m.puzzlez.view.PuzzlezAppView;
|
import ru.m.puzzlez.view.PuzzlezAppView;
|
||||||
|
import ru.m.update.Updater;
|
||||||
|
|
||||||
class PuzzlezApp extends App {
|
class PuzzlezApp extends App {
|
||||||
|
|
||||||
|
@:provide static var updater:Updater;
|
||||||
|
|
||||||
public static function main() {
|
public static function main() {
|
||||||
// ToDo: fix @:provide macro
|
// ToDo: fix @:provide macro
|
||||||
GameStorage;
|
GameStorage;
|
||||||
ImageStorage;
|
ImageStorage;
|
||||||
L.push(new TraceLogger());
|
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 app = new PuzzlezApp(new PuzzlezTheme(), openfl.Assets.getBitmapData("resources/icon.png"));
|
||||||
var view = new PuzzlezAppView();
|
var view = new PuzzlezAppView();
|
||||||
app.start(view);
|
app.start(view);
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ package ru.m.puzzlez.core;
|
|||||||
import haxework.geom.Point;
|
import haxework.geom.Point;
|
||||||
import haxework.geom.Rectangle;
|
import haxework.geom.Rectangle;
|
||||||
import ru.m.puzzlez.core.BoundType;
|
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.Id;
|
||||||
import ru.m.puzzlez.core.Part;
|
import ru.m.puzzlez.core.Part;
|
||||||
|
import ru.m.puzzlez.core.PartLocation;
|
||||||
import ru.m.puzzlez.core.Side;
|
import ru.m.puzzlez.core.Side;
|
||||||
|
|
||||||
class BoundsMap {
|
class BoundsMap {
|
||||||
@@ -66,11 +67,13 @@ class BoundsMap {
|
|||||||
|
|
||||||
class GameUtil {
|
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;
|
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);
|
width = normilizeSize(width);
|
||||||
height = normilizeSize(height);
|
height = normilizeSize(height);
|
||||||
var offsetX = 500;
|
var offsetX = 500;
|
||||||
@@ -119,7 +122,7 @@ class GameUtil {
|
|||||||
id: id,
|
id: id,
|
||||||
gridX: x,
|
gridX: x,
|
||||||
gridY: y,
|
gridY: y,
|
||||||
location: PartLocation.TABLE(position),
|
location: TABLE(position),
|
||||||
bounds: bounds,
|
bounds: bounds,
|
||||||
rect: new Rectangle(0, 0, partWidth, partHeight),
|
rect: new Rectangle(0, 0, partWidth, partHeight),
|
||||||
});
|
});
|
||||||
@@ -136,7 +139,7 @@ class GameUtil {
|
|||||||
var complete = 0;
|
var complete = 0;
|
||||||
for (part in state.parts) {
|
for (part in state.parts) {
|
||||||
switch part.location {
|
switch part.location {
|
||||||
case PartLocation.IMAGE: complete++;
|
case IMAGE: complete++;
|
||||||
case _:
|
case _:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ru.m.puzzlez.render;
|
package ru.m.puzzlez.render;
|
||||||
|
|
||||||
|
import ru.m.puzzlez.render.RenderUtil;
|
||||||
import flash.display.BitmapData;
|
import flash.display.BitmapData;
|
||||||
import haxe.Timer;
|
import haxe.Timer;
|
||||||
import promhx.PublicStream;
|
import promhx.PublicStream;
|
||||||
@@ -8,7 +9,7 @@ import ru.m.puzzlez.core.Part;
|
|||||||
|
|
||||||
typedef Result = {
|
typedef Result = {
|
||||||
var part:Part;
|
var part:Part;
|
||||||
var image:BitmapData;
|
var image:PartImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ImagePartBuilder {
|
class ImagePartBuilder {
|
||||||
@@ -25,8 +26,8 @@ class ImagePartBuilder {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var part = parts[i];
|
var part = parts[i];
|
||||||
var partImage = RenderUtil.cropImagePart(image, part);
|
var image = RenderUtil.cropImagePart(image, part);
|
||||||
stream.update({part: part, image: partImage});
|
stream.update({part: part, image: image});
|
||||||
}
|
}
|
||||||
Timer.delay(() -> buildPart(index + count, count, parts, stream), 0);
|
Timer.delay(() -> buildPart(index + count, count, parts, stream), 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package ru.m.puzzlez.render;
|
package ru.m.puzzlez.render;
|
||||||
|
|
||||||
import flash.display.Bitmap;
|
import flash.display.Bitmap;
|
||||||
import flash.display.BitmapData;
|
|
||||||
import flash.display.PixelSnapping;
|
import flash.display.PixelSnapping;
|
||||||
import flash.display.Sprite;
|
import flash.display.Sprite;
|
||||||
import haxework.geom.Point;
|
import haxework.geom.Point;
|
||||||
import ru.m.puzzlez.core.Part;
|
import ru.m.puzzlez.core.Part;
|
||||||
|
import ru.m.puzzlez.render.RenderUtil;
|
||||||
|
|
||||||
class PartView extends Sprite {
|
class PartView extends Sprite {
|
||||||
|
|
||||||
@@ -20,9 +20,9 @@ class PartView extends Sprite {
|
|||||||
return position;
|
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;
|
image = value;
|
||||||
redraw();
|
redraw();
|
||||||
refresh();
|
refresh();
|
||||||
@@ -44,14 +44,15 @@ class PartView extends Sprite {
|
|||||||
|
|
||||||
private function refresh():Void {
|
private function refresh():Void {
|
||||||
if (position != null && image != null) {
|
if (position != null && image != null) {
|
||||||
x = position.x - (image.width - size.x) / 2;
|
x = position.x - (image.borderedImage.width - size.x) / 2;
|
||||||
y = position.y - (image.height - size.y) / 2;
|
y = position.y - (image.borderedImage.height - size.y) / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function complete():Void {
|
public function complete():Void {
|
||||||
position = target;
|
position = target;
|
||||||
completed = true;
|
completed = true;
|
||||||
|
redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function factory(part:Part):PartView {
|
public static function factory(part:Part):PartView {
|
||||||
@@ -62,6 +63,10 @@ class PartView extends Sprite {
|
|||||||
class SpritePartView extends PartView {
|
class SpritePartView extends PartView {
|
||||||
|
|
||||||
override private function redraw():Void {
|
override private function redraw():Void {
|
||||||
|
if (image == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var image = completed ? image.borderedImage : image.shadedImage;
|
||||||
graphics.clear();
|
graphics.clear();
|
||||||
graphics.beginBitmapFill(image, null, false, true);
|
graphics.beginBitmapFill(image, null, false, true);
|
||||||
graphics.drawRect(0, 0, image.width, image.height);
|
graphics.drawRect(0, 0, image.width, image.height);
|
||||||
@@ -79,6 +84,6 @@ class BitmapPartView extends PartView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override private function redraw():Void {
|
override private function redraw():Void {
|
||||||
bitmap.bitmapData = image;
|
bitmap.bitmapData = completed ? image.borderedImage : image.shadedImage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package ru.m.puzzlez.render;
|
package ru.m.puzzlez.render;
|
||||||
|
|
||||||
import haxework.geom.Point;
|
|
||||||
import flash.display.BitmapData;
|
import flash.display.BitmapData;
|
||||||
import flash.display.PNGEncoderOptions;
|
import flash.display.PNGEncoderOptions;
|
||||||
import flash.display.Sprite;
|
import flash.display.Sprite;
|
||||||
@@ -9,12 +8,14 @@ import flash.geom.Point as FlashPoint;
|
|||||||
import flash.geom.Rectangle;
|
import flash.geom.Rectangle;
|
||||||
import flash.net.FileReference;
|
import flash.net.FileReference;
|
||||||
import flash.utils.ByteArray;
|
import flash.utils.ByteArray;
|
||||||
|
import haxework.geom.Point;
|
||||||
import haxework.signal.Signal;
|
import haxework.signal.Signal;
|
||||||
import haxework.view.popup.AlertView;
|
import haxework.view.popup.AlertView;
|
||||||
import haxework.view.SpriteView;
|
import haxework.view.SpriteView;
|
||||||
import ru.m.puzzlez.core.GameEvent;
|
import ru.m.puzzlez.core.GameEvent;
|
||||||
import ru.m.puzzlez.core.GameState;
|
import ru.m.puzzlez.core.GameState;
|
||||||
import ru.m.puzzlez.core.PartLocation;
|
import ru.m.puzzlez.core.PartLocation;
|
||||||
|
import ru.m.puzzlez.render.ImagePartBuilder;
|
||||||
import ru.m.puzzlez.storage.ImageStorage;
|
import ru.m.puzzlez.storage.ImageStorage;
|
||||||
|
|
||||||
class Render extends SpriteView implements IRender {
|
class Render extends SpriteView implements IRender {
|
||||||
@@ -110,7 +111,7 @@ class Render extends SpriteView implements IRender {
|
|||||||
this.image = RenderUtil.cropImage(image, state.preset.imageRect);
|
this.image = RenderUtil.cropImage(image, state.preset.imageRect);
|
||||||
var builder = new ImagePartBuilder(this.image);
|
var builder = new ImagePartBuilder(this.image);
|
||||||
var i = 0;
|
var i = 0;
|
||||||
builder.build(state.parts).then(function(result) {
|
builder.build(state.parts).then((result:Result) -> {
|
||||||
parts[result.part.id].image = result.image;
|
parts[result.part.id].image = result.image;
|
||||||
progress.setProgress(++i, state.parts.length);
|
progress.setProgress(++i, state.parts.length);
|
||||||
if (i >= state.parts.length - 1) {
|
if (i >= state.parts.length - 1) {
|
||||||
@@ -166,7 +167,7 @@ class Render extends SpriteView implements IRender {
|
|||||||
|
|
||||||
private function save(part:PartView):Void {
|
private function save(part:PartView):Void {
|
||||||
var file = new FileReference();
|
var file = new FileReference();
|
||||||
var image = part.image;
|
var image = part.image.shadedImage;
|
||||||
var data = new ByteArray();
|
var data = new ByteArray();
|
||||||
image.encode(new Rectangle(0, 0, image.width, image.height), new PNGEncoderOptions(), data);
|
image.encode(new Rectangle(0, 0, image.width, image.height), new PNGEncoderOptions(), data);
|
||||||
file.save(data, "icon.png");
|
file.save(data, "icon.png");
|
||||||
|
|||||||
@@ -1,17 +1,40 @@
|
|||||||
package ru.m.puzzlez.render;
|
package ru.m.puzzlez.render;
|
||||||
|
|
||||||
import ru.m.draw.DrawPath;
|
|
||||||
import flash.display.BitmapData;
|
import flash.display.BitmapData;
|
||||||
import flash.display.Shape;
|
import flash.display.Shape;
|
||||||
import flash.geom.Matrix;
|
import flash.geom.Matrix;
|
||||||
|
import haxework.color.Color;
|
||||||
|
import haxework.geom.Point;
|
||||||
import haxework.geom.Rectangle;
|
import haxework.geom.Rectangle;
|
||||||
|
import ru.m.draw.DrawPath;
|
||||||
import ru.m.puzzlez.core.Part;
|
import ru.m.puzzlez.core.Part;
|
||||||
import ru.m.puzzlez.render.part.ClassicPartBuilder;
|
import ru.m.puzzlez.render.part.ClassicPartBuilder;
|
||||||
import ru.m.puzzlez.render.part.IPartBuilder;
|
import ru.m.puzzlez.render.part.IPartBuilder;
|
||||||
import ru.m.puzzlez.render.part.PartMask;
|
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 {
|
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 {
|
public static function cropImage(source:BitmapData, rect:Rectangle):BitmapData {
|
||||||
var image = new BitmapData(Std.int(rect.width), Std.int(rect.height));
|
var image = new BitmapData(Std.int(rect.width), Std.int(rect.height));
|
||||||
@@ -37,17 +60,14 @@ class RenderUtil {
|
|||||||
return {rect:rect, drawRect:drawRect};
|
return {rect:rect, drawRect:drawRect};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function drawShadow(source:BitmapData, path:DrawPath):BitmapData {
|
private static function drawShadow(source:BitmapData, path:DrawPath, values:Array<DrawSetting>):BitmapData {
|
||||||
var shadow = 2;
|
|
||||||
var opacity = 0.4;
|
|
||||||
var canvas = new Shape();
|
var canvas = new Shape();
|
||||||
canvas.cacheAsBitmap = true;
|
canvas.cacheAsBitmap = true;
|
||||||
canvas.graphics.beginFill(0x000000, opacity);
|
for (value in values) {
|
||||||
path.move(-shadow, -shadow).draw(canvas.graphics);
|
canvas.graphics.beginFill(value.color, value.opacity);
|
||||||
canvas.graphics.endFill();
|
path.move(value.offset.x, value.offset.y).draw(canvas.graphics);
|
||||||
canvas.graphics.beginFill(0xffffff, opacity);
|
canvas.graphics.endFill();
|
||||||
path.move(shadow, shadow).draw(canvas.graphics);
|
}
|
||||||
canvas.graphics.endFill();
|
|
||||||
canvas.graphics.beginBitmapFill(source, null, false, true);
|
canvas.graphics.beginBitmapFill(source, null, false, true);
|
||||||
canvas.graphics.drawRect(0, 0, source.width, source.height);
|
canvas.graphics.drawRect(0, 0, source.width, source.height);
|
||||||
canvas.graphics.endFill();
|
canvas.graphics.endFill();
|
||||||
@@ -56,7 +76,23 @@ class RenderUtil {
|
|||||||
return image;
|
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 geometry = buildPartGeometry(part);
|
||||||
var path = builder.build(geometry.drawRect, part.bounds);
|
var path = builder.build(geometry.drawRect, part.bounds);
|
||||||
var canvas:Shape = new Shape();
|
var canvas:Shape = new Shape();
|
||||||
@@ -69,7 +105,9 @@ class RenderUtil {
|
|||||||
canvas.graphics.endFill();
|
canvas.graphics.endFill();
|
||||||
var image = new BitmapData(Std.int(geometry.rect.width), Std.int(geometry.rect.height), true, 0x00000000);
|
var image = new BitmapData(Std.int(geometry.rect.width), Std.int(geometry.rect.height), true, 0x00000000);
|
||||||
image.draw(canvas, null, null, null, null, true);
|
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 {
|
public static function containRectangle(source:Rectangle, target:Rectangle):Rectangle {
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ class BasePartBuilder implements IPartBuilder {
|
|||||||
public function new() {
|
public function new() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createAngle(path:DrawPath, x:Float, y:Float):Void {
|
private function createAngle(path:DrawPath, x:Float, y:Float, first: Bool = false):Void {
|
||||||
path.commands.push(LINE_TO(x, y));
|
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 {
|
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 {
|
public function build(rect:Rectangle, bounds:PartBounds):DrawPath {
|
||||||
var path = new 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);
|
createBound(path, rect.left, rect.top, rect.right, rect.top, bounds.top);
|
||||||
createAngle(path, rect.right, rect.top);
|
createAngle(path, rect.right, rect.top);
|
||||||
createBound(path, rect.right, rect.top, rect.right, rect.bottom, bounds.right);
|
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 {
|
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();
|
statusData.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ru.m.puzzlez.view;
|
package ru.m.puzzlez.view;
|
||||||
|
|
||||||
|
import haxe.Timer;
|
||||||
import haxework.view.frame.FrameSwitcher;
|
import haxework.view.frame.FrameSwitcher;
|
||||||
import haxework.view.frame.FrameView;
|
import haxework.view.frame.FrameView;
|
||||||
import ru.m.puzzlez.core.Game;
|
import ru.m.puzzlez.core.Game;
|
||||||
@@ -17,7 +18,7 @@ import ru.m.puzzlez.storage.GameStorage;
|
|||||||
@:provide var switcher:FrameSwitcher;
|
@:provide var switcher:FrameSwitcher;
|
||||||
@:provide var storage:GameStorage;
|
@:provide var storage:GameStorage;
|
||||||
|
|
||||||
private var toSave:Bool;
|
private var saveTimer:Timer;
|
||||||
|
|
||||||
public function new() {
|
public function new() {
|
||||||
super(ID);
|
super(ID);
|
||||||
@@ -33,6 +34,7 @@ import ru.m.puzzlez.storage.GameStorage;
|
|||||||
}
|
}
|
||||||
|
|
||||||
override public function onHide():Void {
|
override public function onHide():Void {
|
||||||
|
save();
|
||||||
if (game != null) {
|
if (game != null) {
|
||||||
render.signal.disconnect(game.signal.emit);
|
render.signal.disconnect(game.signal.emit);
|
||||||
game.stop();
|
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 {
|
private function onGameEvent(event:GameEvent):Void {
|
||||||
switch event {
|
switch event {
|
||||||
case START(state):
|
case START(state):
|
||||||
storage.save(state);
|
toSave();
|
||||||
case ACTION(PART_PUT(_, _)):
|
case ACTION(PART_PUT(_, _)):
|
||||||
storage.save(game.state);
|
toSave();
|
||||||
case _:
|
case _:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package ru.m.puzzlez.view;
|
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.FrameSwitcher;
|
||||||
import haxework.view.frame.FrameView;
|
import haxework.view.frame.FrameView;
|
||||||
import haxework.view.list.ScrollBarView;
|
|
||||||
import ru.m.puzzlez.core.GameUtil;
|
import ru.m.puzzlez.core.GameUtil;
|
||||||
import ru.m.puzzlez.core.Id;
|
import ru.m.puzzlez.core.Id;
|
||||||
import ru.m.puzzlez.storage.ImageStorage;
|
import ru.m.puzzlez.storage.ImageStorage;
|
||||||
@@ -11,9 +13,7 @@ import ru.m.puzzlez.storage.ImageStorage;
|
|||||||
public static var ID = "preset";
|
public static var ID = "preset";
|
||||||
|
|
||||||
@:view("image") var imageView:PresetView;
|
@:view("image") var imageView:PresetView;
|
||||||
@:view("scroll") var scrollView:ScrollBarView;
|
@:view("sizes") var sizesView:DataView<IntPoint, ToggleButtonView>;
|
||||||
@:view("width") var widthView:InputView;
|
|
||||||
@:view("height") var heightView:InputView;
|
|
||||||
|
|
||||||
@:provide var imageStorage:ImageStorage;
|
@:provide var imageStorage:ImageStorage;
|
||||||
@:provide var switcher:FrameSwitcher;
|
@:provide var switcher:FrameSwitcher;
|
||||||
@@ -22,32 +22,38 @@ import ru.m.puzzlez.storage.ImageStorage;
|
|||||||
|
|
||||||
public function new() {
|
public function new() {
|
||||||
super(ID);
|
super(ID);
|
||||||
widthView.text = "8";
|
sizesView.data = [
|
||||||
heightView.text = "8";
|
new IntPoint(3, 2),
|
||||||
scrollView.position = 0.8;
|
new IntPoint(4, 3),
|
||||||
widthView.update();
|
new IntPoint(5, 4),
|
||||||
heightView.update();
|
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 {
|
override public function onShow(data:ImageId):Void {
|
||||||
super.onShow(data);
|
super.onShow(data);
|
||||||
imageId = data;
|
imageId = data;
|
||||||
updatePreset();
|
selectSize(sizesView.data[sizesView.data.length - 1]);
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function start():Void {
|
private function start():Void {
|
||||||
switcher.change(GameFrame.ID, GameUtil.buildState(imageView.preset));
|
switcher.change(GameFrame.ID, imageView.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function back():Void {
|
private function back():Void {
|
||||||
|
|||||||
@@ -1,32 +1,25 @@
|
|||||||
---
|
---
|
||||||
style: frame
|
style: frame
|
||||||
|
layout.margin: 10
|
||||||
views:
|
views:
|
||||||
- $type: haxework.view.group.HGroupView
|
- $type: haxework.view.group.HGroupView
|
||||||
geometry.width: 100%
|
geometry.width: 100%
|
||||||
layout.hAlign: center
|
layout.hAlign: center
|
||||||
layout.vAlign: middle
|
layout.vAlign: middle
|
||||||
views:
|
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
|
- $type: haxework.view.form.ButtonView
|
||||||
geometry.margin.left: 15
|
geometry.margin.left: 15
|
||||||
text: Start
|
text: Start
|
||||||
+onPress: ~start()
|
+onPress: ~start()
|
||||||
- id: scroll
|
- id: sizes
|
||||||
$type: haxework.view.list.HScrollBarView
|
$type: haxework.view.data.DataView
|
||||||
geometry.width: 100%
|
geometry.width: 100%
|
||||||
geometry.height: 20
|
layout:
|
||||||
ratio: 0.2
|
$type: haxework.view.layout.TailLayout
|
||||||
position: 0.8
|
hAlign: center
|
||||||
+onScroll: ~updateGrid
|
margin: 5
|
||||||
|
factory: ~factory
|
||||||
|
+onDataSelect: ~selectSize
|
||||||
- id: image
|
- id: image
|
||||||
$type: ru.m.puzzlez.view.PresetView
|
$type: ru.m.puzzlez.view.PresetView
|
||||||
geometry.stretch: true
|
geometry.stretch: true
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import flash.display.Graphics;
|
|||||||
import flash.display.Shape;
|
import flash.display.Shape;
|
||||||
import flash.geom.Matrix;
|
import flash.geom.Matrix;
|
||||||
import haxework.view.group.GroupView;
|
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.render.RenderUtil;
|
||||||
import ru.m.puzzlez.storage.ImageStorage;
|
import ru.m.puzzlez.storage.ImageStorage;
|
||||||
|
|
||||||
@@ -20,23 +20,23 @@ class PresetView extends GroupView {
|
|||||||
|
|
||||||
private function set_scale(value:Float):Float {
|
private function set_scale(value:Float):Float {
|
||||||
var result = table.scaleX = table.scaleY = value;
|
var result = table.scaleX = table.scaleY = value;
|
||||||
table.x = (width - preset.tableRect.width * value) / 2;
|
table.x = (width - state.preset.tableRect.width * value) / 2;
|
||||||
table.y = (height - preset.tableRect.height * value) / 2;
|
table.y = (height - state.preset.tableRect.height * value) / 2;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public var preset(default, set):GamePreset;
|
public var state(default, set):GameState;
|
||||||
|
|
||||||
private function set_preset(value:GamePreset) {
|
private function set_state(value:GameState):GameState {
|
||||||
preset = value;
|
state = value;
|
||||||
this.image = null;
|
this.image = null;
|
||||||
table.graphics.clear();
|
table.graphics.clear();
|
||||||
loading.promise = imageStorage.resolve(preset.imageId).then(image -> {
|
loading.promise = imageStorage.resolve(state.preset.imageId).then(image -> {
|
||||||
this.image = RenderUtil.cropImage(image, preset.imageRect);
|
this.image = RenderUtil.cropImage(image, state.preset.imageRect);
|
||||||
toRedraw();
|
toRedraw();
|
||||||
toUpdate();
|
toUpdate();
|
||||||
});
|
});
|
||||||
return preset;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
private var loading:LoadingWrapper;
|
private var loading:LoadingWrapper;
|
||||||
@@ -52,9 +52,10 @@ class PresetView extends GroupView {
|
|||||||
private var image:BitmapData;
|
private var image:BitmapData;
|
||||||
|
|
||||||
override public function redraw():Void {
|
override public function redraw():Void {
|
||||||
if (preset == null || image == null) {
|
if (state == null || image == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var preset = state.preset;
|
||||||
var partWidth = preset.imageRect.width / preset.grid.width;
|
var partWidth = preset.imageRect.width / preset.grid.width;
|
||||||
var partHeight = preset.imageRect.height / preset.grid.height;
|
var partHeight = preset.imageRect.height / preset.grid.height;
|
||||||
var graphics:Graphics = table.graphics;
|
var graphics:Graphics = table.graphics;
|
||||||
@@ -64,32 +65,24 @@ class PresetView extends GroupView {
|
|||||||
graphics.beginBitmapFill(image, matrix, false, true);
|
graphics.beginBitmapFill(image, matrix, false, true);
|
||||||
graphics.drawRect(preset.imageRect.x, preset.imageRect.y, preset.imageRect.width, preset.imageRect.height);
|
graphics.drawRect(preset.imageRect.x, preset.imageRect.y, preset.imageRect.width, preset.imageRect.height);
|
||||||
graphics.endFill();
|
graphics.endFill();
|
||||||
graphics.lineStyle(1, 0x555555);
|
|
||||||
for (x in 0...preset.grid.width + 1) {
|
for (part in state.parts) {
|
||||||
graphics.moveTo(preset.imageRect.x + x * partWidth, preset.imageRect.y);
|
var rect = part.rect.clone();
|
||||||
graphics.lineTo(preset.imageRect.x + x * partWidth, preset.imageRect.y + preset.imageRect.height);
|
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 {
|
override public function update():Void {
|
||||||
super.update();
|
super.update();
|
||||||
if (preset != null) {
|
if (state != null) {
|
||||||
scale = Math.min(width / preset.tableRect.width, height / preset.tableRect.height);
|
scale = Math.min(width / state.preset.tableRect.width, height / state.preset.tableRect.height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ru.m.puzzlez.view;
|
package ru.m.puzzlez.view;
|
||||||
|
|
||||||
|
import ru.m.update.Updater;
|
||||||
import haxework.view.data.DataView;
|
import haxework.view.data.DataView;
|
||||||
import haxework.view.form.ButtonView;
|
import haxework.view.form.ButtonView;
|
||||||
import haxework.view.frame.FrameSwitcher;
|
import haxework.view.frame.FrameSwitcher;
|
||||||
@@ -18,10 +19,12 @@ import ru.m.puzzlez.storage.ImageStorage;
|
|||||||
@:view var sources:DataView<ImageListSource<Dynamic>, ButtonView>;
|
@:view var sources:DataView<ImageListSource<Dynamic>, ButtonView>;
|
||||||
@:view("load") var loadButton:ButtonView;
|
@:view("load") var loadButton:ButtonView;
|
||||||
@:view("complete") var completeButton:ButtonView;
|
@:view("complete") var completeButton:ButtonView;
|
||||||
|
@:view("update") var updateButton:ButtonView;
|
||||||
|
|
||||||
@:provide var storage:ImageStorage;
|
@:provide var storage:ImageStorage;
|
||||||
@:provide var switcher:FrameSwitcher;
|
@:provide var switcher:FrameSwitcher;
|
||||||
@:provide var gameStorage:GameStorage;
|
@:provide var gameStorage:GameStorage;
|
||||||
|
@:provide static var appUpdater:Updater;
|
||||||
|
|
||||||
public function new() {
|
public function new() {
|
||||||
super(ID);
|
super(ID);
|
||||||
@@ -45,6 +48,12 @@ import ru.m.puzzlez.storage.ImageStorage;
|
|||||||
|
|
||||||
override public function onShow(data:Dynamic):Void {
|
override public function onShow(data:Dynamic):Void {
|
||||||
refresh();
|
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 {
|
private function sourceViewFactory(index:Int, source:ImageListSource<Dynamic>):ButtonView {
|
||||||
|
|||||||
@@ -38,6 +38,11 @@ views:
|
|||||||
text: Clean
|
text: Clean
|
||||||
+onPress: ~clean()
|
+onPress: ~clean()
|
||||||
visible: false
|
visible: false
|
||||||
|
- id: update
|
||||||
|
$type: haxework.view.form.ButtonView
|
||||||
|
style: button.active
|
||||||
|
+onPress: ~appUpdater.download()
|
||||||
|
visible: false
|
||||||
- $type: haxework.view.form.LabelView
|
- $type: haxework.view.form.LabelView
|
||||||
text: $r:text:version
|
text: $r:text:version
|
||||||
geometry.position: absolute
|
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