diff --git a/.editorconfig b/.editorconfig index d5efcf5..6e87a00 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,13 +4,10 @@ root = true [*] charset = utf-8 indent_style = space -indent_size = 4 +indent_size = 2 insert_final_newline = true trim_trailing_whitespace = true -[*.yaml] -indent_size = 2 - [*.md] max_line_length = off trim_trailing_whitespace = false diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 581850f..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "args": [ - "app:flash:test" - ], - "name": "app:flash:test", - "program": "${workspaceFolder}/node_modules/gulp/bin/gulp.js", - "request": "launch", - "skipFiles": [ - "/**" - ], - "type": "node" - }, - { - "args": [ - "server:cpp:test" - ], - "name": "server:cpp:test", - "program": "${workspaceFolder}/node_modules/gulp/bin/gulp.js", - "request": "launch", - "skipFiles": [ - "/**" - ], - "type": "node" - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index e0d34e9..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "haxe.executable": { - "path": "/home/shmyga/sdk/haxe/4.2.5/haxe", - "env": { - "HAXE_STD_PATH": "/home/shmyga/sdk/haxe/4.2.5/std", - }, - }, - "haxe.configurations": [ - ["build/app/flash/haxe/debug.hxml"], - ], - "haxe.displayServer": { - "arguments": [ - //"-v" - ], - } -} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..4dcd027 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +`.bashrc` +```bash +export NEKO_VERSION="2.2.0" +export HAXE_VERSION="4.2.5" + +export NEKO_SDK="$HOME/sdk/neko/$NEKO_VERSION" +export HAXE_SDK="$HOME/sdk/haxe/$HAXE_VERSION" + +alias haxe-activate=". $NEKO_SDK/activate && . $HAXE_SDK/activate" +``` diff --git a/config.example.json b/config.example.json index 8153e77..c8ef9fe 100644 --- a/config.example.json +++ b/config.example.json @@ -1,11 +1,11 @@ { - "SdkDir": "C:\\sdk", - "BuildDir": null, - "PublishDir": "", - "PublishUrl": "https://shmyga.ru/repo/puzzlez", - "Develop": false, - "Key": { - "store": "keystore.jks", - "pass": null - } + "SdkDir": "C:\\sdk", + "BuildDir": null, + "PublishDir": "", + "PublishUrl": "https://shmyga.ru/repo/puzzlez", + "Develop": false, + "Key": { + "store": "keystore.jks", + "pass": null + } } diff --git a/hxformat.json b/hxformat.json new file mode 100644 index 0000000..7bf0a43 --- /dev/null +++ b/hxformat.json @@ -0,0 +1,5 @@ +{ + "indentation": { + "character": " " + } +} diff --git a/package.json b/package.json index e87e273..07eaabf 100644 --- a/package.json +++ b/package.json @@ -1,24 +1,25 @@ { - "name": "puzzlez", - "version": "0.5.0", - "private": true, - "devDependencies": { - "dateformat": "^3.0.3", - "fs-extra": "^10.0.0", - "gulp": "^4.0.0", - "gulp-add": "0.0.2", - "gulp-clean": "^0.4.0", - "gulp-cli": "^2.2.0", - "gulp-haxetool": "^0.1.9", - "yargs": "^13.2.4" - }, - "haxeDependencies": { - "haxework": "2.1.0", - "lime": "8.0.0", - "openfl": "9.2.0", - "hxcpp": "4.2.1", - "svg": "1.1.3", - "protohx": "0.4.6" - }, - "haxe": "4.2.5" + "name": "puzzlez", + "version": "0.5.0", + "private": true, + "devDependencies": { + "dateformat": "^3.0.3", + "fs-extra": "^10.0.0", + "gulp": "^4.0.0", + "gulp-add": "0.0.2", + "gulp-clean": "^0.4.0", + "gulp-cli": "^2.2.0", + "gulp-haxetool": "^0.1.9", + "yargs": "^13.2.4" + }, + "haxeDependencies": { + "haxework": "2.1.0", + "lime": "8.0.0", + "openfl": "9.2.0", + "hxcpp": "4.2.1", + "svg": "1.1.3", + "protohx": "0.4.6", + "formatter": "1.16.0" + }, + "haxe": "4.2.5" } diff --git a/puzzlez.code-workspace b/puzzlez.code-workspace new file mode 100644 index 0000000..f5ff926 --- /dev/null +++ b/puzzlez.code-workspace @@ -0,0 +1,46 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "haxe.executable": { + "path": "/home/shmyga/sdk/haxe/4.2.5/haxe", + "env": { + "HAXE_STD_PATH": "/home/shmyga/sdk/haxe/4.2.5/std" + } + }, + "haxe.configurations": [["build/app/flash/haxe/debug.hxml"]], + "haxe.displayServer": { + "arguments": [ + //"-v" + ] + } + }, + "extensions": { + "recommendations": ["nadako.vshaxe"] + }, + "launch": { + "version": "0.2.0", + "configurations": [ + { + "args": ["app:flash:test"], + "name": "app:flash:test", + "program": "${workspaceFolder}/node_modules/gulp/bin/gulp.js", + "request": "launch", + "skipFiles": ["/**"], + "type": "node" + }, + { + "args": ["server:cpp:test"], + "name": "server:cpp:test", + "program": "${workspaceFolder}/node_modules/gulp/bin/gulp.js", + "request": "launch", + "skipFiles": ["/**"], + "type": "node" + } + ], + "compounds": [] + } +} diff --git a/scripts/format b/scripts/format new file mode 100755 index 0000000..6e13b0f --- /dev/null +++ b/scripts/format @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -e +cd "$(dirname $(dirname "$0"))" || exit + +source $NEKO_SDK/activate +source $HAXE_SDK/activate +haxelib install formatter +haxelib run formatter -s ./src/common/haxe -s ./src/app/haxe -s ./src/server/haxe diff --git a/scripts/lint b/scripts/lint new file mode 100755 index 0000000..8197f28 --- /dev/null +++ b/scripts/lint @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -e +cd "$(dirname $(dirname "$0"))" || exit + +source $NEKO_SDK/activate +source $HAXE_SDK/activate +haxelib install formatter +haxelib run formatter --check -s ./src/common/haxe -s ./src/app/haxe -s ./src/server/haxe diff --git a/scripts/setup b/scripts/setup new file mode 100755 index 0000000..c1b24e8 --- /dev/null +++ b/scripts/setup @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -e +cd "$(dirname $(dirname "$0"))" || exit + +npm ci \ No newline at end of file diff --git a/src/app/haxe/ru/m/AbstractEnumTools.hx b/src/app/haxe/ru/m/AbstractEnumTools.hx index 55a03b9..49e4934 100644 --- a/src/app/haxe/ru/m/AbstractEnumTools.hx +++ b/src/app/haxe/ru/m/AbstractEnumTools.hx @@ -3,36 +3,37 @@ package ru.m; #if macro import haxe.macro.Context; import haxe.macro.Expr; + using haxe.macro.Tools; #end class AbstractEnumTools { - public static macro function getValues(typePath:Expr):Expr { - // Get the type from a given expression converted to string. - // This will work for identifiers and field access which is what we need, - // it will also consider local imports. If expression is not a valid type path or type is not found, - // compiler will give a error here. - var type = Context.getType(typePath.toString()); + public static macro function getValues(typePath:Expr):Expr { + // Get the type from a given expression converted to string. + // This will work for identifiers and field access which is what we need, + // it will also consider local imports. If expression is not a valid type path or type is not found, + // compiler will give a error here. + var type = Context.getType(typePath.toString()); - // Switch on the type and check if it's an abstract with @:enum metadata - switch (type.follow()) { - case TAbstract(_.get() => ab, _) if (ab.meta.has(":enum")): - // @:enum abstract values are actually static fields of the abstract implementation class, - // marked with @:enum and @:impl metadata. We generate an array of expressions that access those fields. - // Note that this is a bit of implementation detail, so it can change in future Haxe versions, but it's been - // stable so far. - var valueExprs = []; - for (field in ab.impl.get().statics.get()) { - if (field.meta.has(":enum") && field.meta.has(":impl")) { - var fieldName = field.name; - valueExprs.push(macro $typePath.$fieldName); - } - } - // Return collected expressions as an array declaration. - return macro $a{valueExprs}; - default: - // The given type is not an abstract, or doesn't have @:enum metadata, show a nice error message. - throw new Error(type.toString() + " should be @:enum abstract", typePath.pos); + // Switch on the type and check if it's an abstract with @:enum metadata + switch (type.follow()) { + case TAbstract(_.get() => ab, _) if (ab.meta.has(":enum")): + // @:enum abstract values are actually static fields of the abstract implementation class, + // marked with @:enum and @:impl metadata. We generate an array of expressions that access those fields. + // Note that this is a bit of implementation detail, so it can change in future Haxe versions, but it's been + // stable so far. + var valueExprs = []; + for (field in ab.impl.get().statics.get()) { + if (field.meta.has(":enum") && field.meta.has(":impl")) { + var fieldName = field.name; + valueExprs.push(macro $typePath.$fieldName); + } } + // Return collected expressions as an array declaration. + return macro $a{valueExprs}; + default: + // The given type is not an abstract, or doesn't have @:enum metadata, show a nice error message. + throw new Error(type.toString() + " should be @:enum abstract", typePath.pos); } + } } diff --git a/src/app/haxe/ru/m/Device.hx b/src/app/haxe/ru/m/Device.hx index 57766ff..5e927e4 100644 --- a/src/app/haxe/ru/m/Device.hx +++ b/src/app/haxe/ru/m/Device.hx @@ -6,72 +6,68 @@ import flash.Lib; import hw.signal.Signal; enum abstract Platform(String) from String to String { - var ANDROID = "android"; - var LINUX = "linux"; - var WINDOWS = "windows"; - var FLASH = "flash"; - var HTML5 = "html5"; - var UNKNOWN = "unknown"; + var ANDROID = "android"; + var LINUX = "linux"; + var WINDOWS = "windows"; + var FLASH = "flash"; + var HTML5 = "html5"; + var UNKNOWN = "unknown"; } class Device { + public static var platform(get, null):Platform; - 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; + #elseif flash + return FLASH; + #elseif html5 + return HTML5; + #else + return UNKNOWN; + #end + } - private static function get_platform():Platform { - #if android - return ANDROID; - #elseif linux - return LINUX; - #elseif windows - return WINDOWS; - #elseif flash - return FLASH; - #elseif html5 - return HTML5; - #else - return UNKNOWN; - #end - } + private static var MOBILES(default, never):Array = ["Android", "webOS", "iPhone", "iPad", "iPod", "BlackBerry", "Windows Phone",]; - private static var MOBILES(default, never):Array = [ - "Android", "webOS", "iPhone", "iPad", "iPod", "BlackBerry", "Windows Phone", - ]; - - public static function isMobile():Bool { - #if android + 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; - #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 + } } + return false; + #else + return false; + #end + } - public static var fullScreenSignal(get, null):Signal; + public static var fullScreenSignal(get, null):Signal; - private static function get_fullScreenSignal():Signal { - if (fullScreenSignal == null) { - fullScreenSignal = new Signal(); - Lib.current.stage.addEventListener(FullScreenEvent.FULL_SCREEN, (event:FullScreenEvent) -> fullScreenSignal.emit(event.fullScreen)); - } - return fullScreenSignal; + private static function get_fullScreenSignal():Signal { + if (fullScreenSignal == null) { + fullScreenSignal = new Signal(); + Lib.current.stage.addEventListener(FullScreenEvent.FULL_SCREEN, (event:FullScreenEvent) -> fullScreenSignal.emit(event.fullScreen)); } + return fullScreenSignal; + } - public static var fullScreenSupport(get, never):Bool; + public static var fullScreenSupport(get, never):Bool; - public static function get_fullScreenSupport():Bool { - return Lib.current.stage.allowsFullScreen; - } + public static function get_fullScreenSupport():Bool { + return Lib.current.stage.allowsFullScreen; + } - public static function toggleFullScreen():Void { - Lib.current.stage.displayState = Lib.current.stage.displayState == StageDisplayState.NORMAL ? - StageDisplayState.FULL_SCREEN : StageDisplayState.NORMAL; - } + public static function toggleFullScreen():Void { + Lib.current.stage.displayState = Lib.current.stage.displayState == StageDisplayState.NORMAL ? StageDisplayState.FULL_SCREEN : StageDisplayState.NORMAL; + } } diff --git a/src/app/haxe/ru/m/ModernFileReference.hx b/src/app/haxe/ru/m/ModernFileReference.hx index c513850..1a44146 100644 --- a/src/app/haxe/ru/m/ModernFileReference.hx +++ b/src/app/haxe/ru/m/ModernFileReference.hx @@ -5,48 +5,39 @@ import openfl.net.FileReference; import openfl.utils.ByteArray; class Callback { - private var success:T -> Void; - private var fail:Dynamic -> Void; + private var success:T->Void; + private var fail:Dynamic->Void; - public function new(success: T -> Void, fail: Dynamic -> Void) { - this.success = success; - this.fail = fail; - } + public function new(success:T->Void, fail:Dynamic->Void) { + this.success = success; + this.fail = fail; + } - public function onSuccess(result:T):Void { - this.success(result); - } + public function onSuccess(result:T):Void { + this.success(result); + } - public function onFail(error:Dynamic):Void { - this.fail(error); - } + public function onFail(error:Dynamic):Void { + this.fail(error); + } } class ModernFileReference extends FileReference { - #if android - private static var fileUtilBrowse = lime.system.JNI.createStaticMethod( - "ru.m.android.FileUtil", - "browse", - "(Lorg/haxe/lime/HaxeObject;)V" - ); - #end + #if android + private static var fileUtilBrowse = lime.system.JNI.createStaticMethod("ru.m.android.FileUtil", "browse", "(Lorg/haxe/lime/HaxeObject;)V"); + #end - override public function browse(?typeFilter:Array):Bool { - #if android - fileUtilBrowse(new Callback( - function(result:haxe.io.BytesData):Void { - data = ByteArray.fromBytesData(result); - dispatchEvent(new flash.events.Event(flash.events.Event.COMPLETE)); - }, - function(error:Dynamic):Void { - dispatchEvent(new flash.events.IOErrorEvent( - flash.events.IOErrorEvent.IO_ERROR, false, false, Std.string(error) - )); - } - )); - return true; - #else - return super.browse(typeFilter); - #end - } + override public function browse(?typeFilter:Array):Bool { + #if android + fileUtilBrowse(new Callback(function(result:haxe.io.BytesData):Void { + data = ByteArray.fromBytesData(result); + dispatchEvent(new flash.events.Event(flash.events.Event.COMPLETE)); + }, function(error:Dynamic):Void { + dispatchEvent(new flash.events.IOErrorEvent(flash.events.IOErrorEvent.IO_ERROR, false, false, Std.string(error))); + })); + return true; + #else + return super.browse(typeFilter); + #end + } } diff --git a/src/app/haxe/ru/m/api/PixabayApi.hx b/src/app/haxe/ru/m/api/PixabayApi.hx new file mode 100644 index 0000000..ccefbd7 --- /dev/null +++ b/src/app/haxe/ru/m/api/PixabayApi.hx @@ -0,0 +1,76 @@ +package ru.m.api; + +import hw.net.JsonLoader; +import promhx.Promise; + +typedef PixabayImage = { + var id:Int; + var largeImageURL:String; + var webformatURL:String; + var previewURL:String; +} + +typedef PixabayResponse = { + var total:Int; + var totalHits:Int; + var hits:Array; +} + +enum abstract PixabayCategory(String) from String to String { + var FASHION = "fashion"; + var NATURE = "nature"; + var BACKGROUNDS = "backgrounds"; + var SCIENCE = "science"; + var EDUCATION = "education"; + var PEOPLE = "people"; + var FEELINGS = "feelings"; + var RELIGION = "religion"; + var HEALTH = "health"; + var PLACES = "places"; + var ANIMALS = "animals"; + var INDUSTRY = "industry"; + var FOOD = "food"; + var COMPUTER = "computer"; + var SPORTS = "sports"; + var TRANSPORTATION = "transportation"; + var TRAVEL = "travel"; + var BUILDINGS = "buildings"; + var BUSINESS = "business"; + var MUSIC = "music"; +} + +enum abstract PixabayImageType(String) from String to String { + var ALL = "all"; + var PHOTO = "photo"; + var ILLUSTRATION = "illustration"; + var VECTOR = "vector"; +} + +class PixabayApi { + private var baseUrl:String = "https://pixabay.com/api/"; + private var key:String; + + public function new(key:String) { + this.key = key; + } + + private function buildRequest(queryMap:Map):String { + queryMap.set("key", key); + var query = [for (k in queryMap.keys()) '${k}=${queryMap.get(k)}'].join("&"); + return '${baseUrl}?${query}'; + } + + public function getPage(page:Int, perPage:Int, category:PixabayCategory = PixabayCategory.NATURE):Promise { + return new JsonLoader().GET(buildRequest([ + "category" => category, + "image_type" => PixabayImageType.PHOTO, + "editors_choice" => true, + "per_page" => perPage, + "page" => page, + ])); + } + + public function get(id:Int):Promise { + return new JsonLoader().GET(buildRequest(["id" => id])).then((response:PixabayResponse) -> response.hits[0]); + } +} diff --git a/src/app/haxe/ru/m/api/UnsplashApi.hx b/src/app/haxe/ru/m/api/UnsplashApi.hx index 58ae4bb..ed1cc8f 100644 --- a/src/app/haxe/ru/m/api/UnsplashApi.hx +++ b/src/app/haxe/ru/m/api/UnsplashApi.hx @@ -4,59 +4,55 @@ import hw.net.JsonLoader; import promhx.Promise; typedef UnsplashImage = { - var id:String; - var width:Int; - var height:Int; - var urls:{ - raw:String, - full:String, - regular:String, - small:String, - thumb:String, - }; + var id:String; + var width:Int; + var height:Int; + var urls:{ + raw:String, + full:String, + regular:String, + small:String, + thumb:String, + }; } typedef UnsplashResponse = { - var total: Int; - var total_pages: Int; - var results: Array; + var total:Int; + var total_pages:Int; + var results:Array; } class UnsplashApi { - private var baseUrl:String = "https://api.unsplash.com"; - private var key:String; + private var baseUrl:String = "https://api.unsplash.com"; + private var key:String; - public function new(key:String) { - this.key = key; - } + public function new(key:String) { + this.key = key; + } - private function buildQuery(queryMap:Map):String { - return [for (k in queryMap.keys()) '${k}=${queryMap.get(k)}'].join("&"); - } + private function buildQuery(queryMap:Map):String { + return [for (k in queryMap.keys()) '${k}=${queryMap.get(k)}'].join("&"); + } - private function buildRequest(queryMap:Map):String { - queryMap.set("client_id", key); - var query = buildQuery(queryMap); - return '${baseUrl}/search/photos?${query}'; - } + private function buildRequest(queryMap:Map):String { + queryMap.set("client_id", key); + var query = buildQuery(queryMap); + return '${baseUrl}/search/photos?${query}'; + } - public function getPage(page:Int, perPage:Int, query:String):Promise { - return new JsonLoader() - .GET(buildRequest([ - "per_page" => perPage, - "page" => page, - "order_by" => "relevant", - "orientation" => "landscape", - "query" => query, - ])); - } + public function getPage(page:Int, perPage:Int, query:String):Promise { + return new JsonLoader().GET(buildRequest([ + "per_page" => perPage, + "page" => page, + "order_by" => "relevant", + "orientation" => "landscape", + "query" => query, + ])); + } - public function get(id:String):Promise { - var queryMap = [ - "client_id" => key, - ]; - var query = buildQuery(queryMap); - return new JsonLoader() - .GET('${baseUrl}/photos/${id}?${query}'); - } + public function get(id:String):Promise { + var queryMap = ["client_id" => key,]; + var query = buildQuery(queryMap); + return new JsonLoader().GET('${baseUrl}/photos/${id}?${query}'); + } } diff --git a/src/app/haxe/ru/m/cache/StorageCache.hx b/src/app/haxe/ru/m/cache/StorageCache.hx index 2dd1a04..65b7e24 100644 --- a/src/app/haxe/ru/m/cache/StorageCache.hx +++ b/src/app/haxe/ru/m/cache/StorageCache.hx @@ -5,34 +5,34 @@ import haxe.crypto.Md5; import haxe.io.Bytes; class StorageCache { - private static var DATA_KEY:String = "data"; + private static var DATA_KEY:String = "data"; - private var name:String; + private var name:String; - public function new() { - name = "cache"; + public function new() { + name = "cache"; + } + + private function resolveDataObject(key:String):SharedObject { + return SharedObject.getLocal('${name}/${Md5.encode(key)}'); + } + + public function exists(key:String):Bool { + var dataObject = resolveDataObject(key); + return Reflect.hasField(dataObject.data, DATA_KEY); + } + + public function get(key:String):Null { + var dataObject = resolveDataObject(key); + if (Reflect.hasField(dataObject.data, DATA_KEY)) { + return Bytes.ofHex(Reflect.field(dataObject.data, DATA_KEY)); } + return null; + } - private function resolveDataObject(key:String):SharedObject { - return SharedObject.getLocal('${name}/${Md5.encode(key)}'); - } - - public function exists(key:String):Bool { - var dataObject = resolveDataObject(key); - return Reflect.hasField(dataObject.data, DATA_KEY); - } - - public function get(key:String):Null { - var dataObject = resolveDataObject(key); - if (Reflect.hasField(dataObject.data, DATA_KEY)) { - return Bytes.ofHex(Reflect.field(dataObject.data, DATA_KEY)); - } - return null; - } - - public function set(key:String, data:Bytes):Void { - var dataObject = resolveDataObject(key); - dataObject.setProperty(DATA_KEY, data.toHex()); - dataObject.flush(); - } + public function set(key:String, data:Bytes):Void { + var dataObject = resolveDataObject(key); + dataObject.setProperty(DATA_KEY, data.toHex()); + dataObject.flush(); + } } diff --git a/src/app/haxe/ru/m/data/DataSource.hx b/src/app/haxe/ru/m/data/DataSource.hx index 6087489..c70e099 100644 --- a/src/app/haxe/ru/m/data/DataSource.hx +++ b/src/app/haxe/ru/m/data/DataSource.hx @@ -3,31 +3,32 @@ package ru.m.data; import promhx.Promise; typedef Filter = Map; + typedef Order = Array<{ - var field:String; - @:optional var reverse:Bool; + var field:String; + @:optional var reverse:Bool; }>; typedef Page = { - var index:Int; - var count:Int; - @:optional var filter:Filter; - @:optional var order:Order; + var index:Int; + var count:Int; + @:optional var filter:Filter; + @:optional var order:Order; } typedef DataPage = { - var page:Page; - var data:Array; - var total:Int; + var page:Page; + var data:Array; + var total:Int; } interface DataSource { - public function getPage(page:Page):Promise>; + public function getPage(page:Page):Promise>; } interface DataStorage extends DataSource { - public function getIndexPage(page:Page):Promise>; - public function get(id:I):Promise; - public function save(item:D):Promise; - public function delete(id:I):Promise; + public function getIndexPage(page:Page):Promise>; + public function get(id:I):Promise; + public function save(item:D):Promise; + public function delete(id:I):Promise; } diff --git a/src/app/haxe/ru/m/draw/DrawPath.hx b/src/app/haxe/ru/m/draw/DrawPath.hx index 51bb28f..c4a6b56 100644 --- a/src/app/haxe/ru/m/draw/DrawPath.hx +++ b/src/app/haxe/ru/m/draw/DrawPath.hx @@ -5,49 +5,49 @@ import flash.display.GraphicsPathCommand; import flash.Vector; enum DrawCommand { - MOVE_TO(x:Float, y:Float); - LINE_TO(x:Float, y:Float); - CURVE_TO(cx:Float, cy:Float, ax:Float, ay:Float); + MOVE_TO(x:Float, y:Float); + LINE_TO(x:Float, y:Float); + CURVE_TO(cx:Float, cy:Float, ax:Float, ay:Float); } class DrawPath { - public var commands(default, null):Array; + public var commands(default, null):Array; - public function new(commands:Array = null) { - this.commands = commands != null ? commands : []; - } + public function new(commands:Array = null) { + this.commands = commands != null ? commands : []; + } - public function draw(graphics:Graphics):Void { - var commands = new Vector(); - var data = new Vector(); - for (command in this.commands) { - switch command { - case MOVE_TO(x, y): - commands.push(GraphicsPathCommand.MOVE_TO); - data.push(x); - data.push(y); - case LINE_TO(x, y): - commands.push(GraphicsPathCommand.LINE_TO); - data.push(x); - data.push(y); - case CURVE_TO(cx, cy, ax, ay): - commands.push(GraphicsPathCommand.CURVE_TO); - data.push(cx); - data.push(cy); - data.push(ax); - data.push(ay); - } - } - graphics.drawPath(commands, data); + public function draw(graphics:Graphics):Void { + var commands = new Vector(); + var data = new Vector(); + for (command in this.commands) { + switch command { + case MOVE_TO(x, y): + commands.push(GraphicsPathCommand.MOVE_TO); + data.push(x); + data.push(y); + case LINE_TO(x, y): + commands.push(GraphicsPathCommand.LINE_TO); + data.push(x); + data.push(y); + case CURVE_TO(cx, cy, ax, ay): + commands.push(GraphicsPathCommand.CURVE_TO); + data.push(cx); + data.push(cy); + data.push(ax); + data.push(ay); + } } + graphics.drawPath(commands, data); + } - public function move(mx:Float, my:Float):DrawPath { - var result = new DrawPath(); - result.commands = commands.map(command -> switch command { - case MOVE_TO(x, y): MOVE_TO(x + mx, y + my); - case LINE_TO(x, y): LINE_TO(x + mx, y + my); - case CURVE_TO(cx, cy, ax, ay): CURVE_TO(cx + mx, cy + my, ax + mx, ay + my); - }); - return result; - } + public function move(mx:Float, my:Float):DrawPath { + var result = new DrawPath(); + result.commands = commands.map(command -> switch command { + case MOVE_TO(x, y): MOVE_TO(x + mx, y + my); + case LINE_TO(x, y): LINE_TO(x + mx, y + my); + case CURVE_TO(cx, cy, ax, ay): CURVE_TO(cx + mx, cy + my, ax + mx, ay + my); + }); + return result; + } } diff --git a/src/app/haxe/ru/m/event/GestureEvent.hx b/src/app/haxe/ru/m/event/GestureEvent.hx index 7bf87a8..4584827 100644 --- a/src/app/haxe/ru/m/event/GestureEvent.hx +++ b/src/app/haxe/ru/m/event/GestureEvent.hx @@ -2,6 +2,4 @@ package ru.m.event; import flash.events.Event; -class GestureEvent extends Event { - -} +class GestureEvent extends Event {} diff --git a/src/app/haxe/ru/m/event/GestureManager.hx b/src/app/haxe/ru/m/event/GestureManager.hx index 463b3f4..1e95d76 100644 --- a/src/app/haxe/ru/m/event/GestureManager.hx +++ b/src/app/haxe/ru/m/event/GestureManager.hx @@ -5,69 +5,68 @@ import flash.display.DisplayObject; import flash.events.TouchEvent; typedef Touch = { - var id:Int; - var point:Point; + var id:Int; + var point:Point; } class GestureManager { + private var target:DisplayObject; + private var touchesMap:Map; + private var touches:Array; + private var distance:Float; - private var target:DisplayObject; - private var touchesMap:Map; - private var touches:Array; - private var distance:Float; + public function new(target:DisplayObject) { + this.target = target; + touchesMap = new Map(); + touches = new Array(); + target.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin); + target.addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove); + target.addEventListener(TouchEvent.TOUCH_END, onTouchEnd); + } - public function new(target:DisplayObject) { - this.target = target; - touchesMap = new Map(); - touches = new Array(); - target.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin); - target.addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove); - target.addEventListener(TouchEvent.TOUCH_END, onTouchEnd); + private function addTouch(id:Int, point:Point):Void { + var touch:Touch = {id: id, point: point}; + touchesMap.set(touch.id, touch); + touches.push(touch); + if (touches.length == 2) { + distance = Point.distance(touches[0].point, touches[1].point); } + } - private function addTouch(id:Int, point:Point):Void { - var touch:Touch = {id: id, point: point}; - touchesMap.set(touch.id, touch); - touches.push(touch); - if (touches.length == 2) { - distance = Point.distance(touches[0].point, touches[1].point); - } + private function updateTouch(id:Int, point:Point):Void { + touchesMap.get(id).point = point; + if (touches.length == 2) { + var newDistance = Point.distance(touches[0].point, touches[1].point); + var event = new ZoomGestureEvent(ZoomGestureEvent.GESTURE_ZOOM); + event.zoom = (newDistance - distance) * 0.001; + distance = newDistance; + target.dispatchEvent(event); } + } - private function updateTouch(id:Int, point:Point):Void { - touchesMap.get(id).point = point; - if (touches.length == 2) { - var newDistance = Point.distance(touches[0].point, touches[1].point); - var event = new ZoomGestureEvent(ZoomGestureEvent.GESTURE_ZOOM); - event.zoom = (newDistance - distance) * 0.001; - distance = newDistance; - target.dispatchEvent(event); - } - } + private function removeTouch(id:Int):Void { + touches.remove(touchesMap.get(id)); + touchesMap.remove(id); + } - private function removeTouch(id:Int):Void { - touches.remove(touchesMap.get(id)); - touchesMap.remove(id); - } + private function onTouchBegin(event:TouchEvent):Void { + addTouch(event.touchPointID, new Point(event.stageX, event.stageY)); + } - private function onTouchBegin(event:TouchEvent):Void { - addTouch(event.touchPointID, new Point(event.stageX, event.stageY)); - } + private function onTouchMove(event:TouchEvent):Void { + updateTouch(event.touchPointID, new Point(event.stageX, event.stageY)); + } - private function onTouchMove(event:TouchEvent):Void { - updateTouch(event.touchPointID, new Point(event.stageX, event.stageY)); - } + private function onTouchEnd(event:TouchEvent):Void { + removeTouch(event.touchPointID); + } - private function onTouchEnd(event:TouchEvent):Void { - removeTouch(event.touchPointID); - } - - public function dispose():Void { - if (target != null) { - target.removeEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin); - target.removeEventListener(TouchEvent.TOUCH_MOVE, onTouchMove); - target.removeEventListener(TouchEvent.TOUCH_END, onTouchEnd); - target = null; - } + public function dispose():Void { + if (target != null) { + target.removeEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin); + target.removeEventListener(TouchEvent.TOUCH_MOVE, onTouchMove); + target.removeEventListener(TouchEvent.TOUCH_END, onTouchEnd); + target = null; } + } } diff --git a/src/app/haxe/ru/m/event/ZoomGestureEvent.hx b/src/app/haxe/ru/m/event/ZoomGestureEvent.hx index 838c26a..50360a3 100644 --- a/src/app/haxe/ru/m/event/ZoomGestureEvent.hx +++ b/src/app/haxe/ru/m/event/ZoomGestureEvent.hx @@ -1,7 +1,7 @@ package ru.m.event; class ZoomGestureEvent extends GestureEvent { - public static var GESTURE_ZOOM(default, never):String = "gesture_zoom"; + public static var GESTURE_ZOOM(default, never):String = "gesture_zoom"; - public var zoom(default, default):Float; + public var zoom(default, default):Float; } diff --git a/src/app/haxe/ru/m/pixabay/PixabayApi.hx b/src/app/haxe/ru/m/pixabay/PixabayApi.hx deleted file mode 100644 index 75702cd..0000000 --- a/src/app/haxe/ru/m/pixabay/PixabayApi.hx +++ /dev/null @@ -1,79 +0,0 @@ -package ru.m.pixabay; - -import hw.net.JsonLoader; -import promhx.Promise; - -typedef PixabayImage = { - var id:Int; - var largeImageURL:String; - var webformatURL:String; - var previewURL:String; -} - -typedef PixabayResponse = { - var total:Int; - var totalHits:Int; - var hits:Array; -} - -enum abstract PixabayCategory(String) from String to String { - var FASHION = "fashion"; - var NATURE = "nature"; - var BACKGROUNDS = "backgrounds"; - var SCIENCE = "science"; - var EDUCATION = "education"; - var PEOPLE = "people"; - var FEELINGS = "feelings"; - var RELIGION = "religion"; - var HEALTH = "health"; - var PLACES = "places"; - var ANIMALS = "animals"; - var INDUSTRY = "industry"; - var FOOD = "food"; - var COMPUTER = "computer"; - var SPORTS = "sports"; - var TRANSPORTATION = "transportation"; - var TRAVEL = "travel"; - var BUILDINGS = "buildings"; - var BUSINESS = "business"; - var MUSIC = "music"; -} - -enum abstract PixabayImageType(String) from String to String { - var ALL = "all"; - var PHOTO = "photo"; - var ILLUSTRATION = "illustration"; - var VECTOR = "vector"; -} - -class PixabayApi { - private var baseUrl:String = "https://pixabay.com/api/"; - private var key:String; - - public function new(key:String) { - this.key = key; - } - - private function buildRequest(queryMap:Map):String { - queryMap.set("key", key); - var query = [for (k in queryMap.keys()) '${k}=${queryMap.get(k)}'].join("&"); - return '${baseUrl}?${query}'; - } - - public function getPage(page:Int, perPage:Int, category:PixabayCategory = PixabayCategory.NATURE):Promise { - return new JsonLoader() - .GET(buildRequest([ - "category" => category, - "image_type" => PixabayImageType.PHOTO, - "editors_choice" => true, - "per_page" => perPage, - "page" => page, - ])); - } - - public function get(id:Int):Promise { - return new JsonLoader() - .GET(buildRequest(["id" => id])) - .then((response:PixabayResponse) -> response.hits[0]); - } -} diff --git a/src/app/haxe/ru/m/puzzlez/FileUtil.hx b/src/app/haxe/ru/m/puzzlez/FileUtil.hx index d76a187..3692af7 100644 --- a/src/app/haxe/ru/m/puzzlez/FileUtil.hx +++ b/src/app/haxe/ru/m/puzzlez/FileUtil.hx @@ -8,37 +8,36 @@ import promhx.Deferred; import promhx.Promise; typedef FileContent = { - var name:String; - var content:Bytes; + var name:String; + var content:Bytes; } class FileUtil { + public static function browse():Promise { + var d = new Deferred(); + var file = new ModernFileReference(); + file.addEventListener(Event.SELECT, (event:Event) -> { + cast(event.target, ModernFileReference).load(); + }); + file.addEventListener(IOErrorEvent.IO_ERROR, (event:IOErrorEvent) -> { + d.throwError(event); + }); + file.addEventListener(ProgressEvent.PROGRESS, (event:ProgressEvent) -> { + // trace('progress', '${event}'); + }); + file.addEventListener(Event.COMPLETE, (event:Event) -> { + var f:ModernFileReference = cast event.target; + d.resolve({ + name: f.name, + content: Bytes.ofData(f.data), + }); + }); + file.browse(); + return d.promise(); + } - public static function browse():Promise { - var d = new Deferred(); - var file = new ModernFileReference(); - file.addEventListener(Event.SELECT, (event:Event) -> { - cast(event.target, ModernFileReference).load(); - }); - file.addEventListener(IOErrorEvent.IO_ERROR, (event:IOErrorEvent) -> { - d.throwError(event); - }); - file.addEventListener(ProgressEvent.PROGRESS, (event:ProgressEvent) -> { - //trace('progress', '${event}'); - }); - file.addEventListener(Event.COMPLETE, (event:Event) -> { - var f:ModernFileReference = cast event.target; - d.resolve({ - name: f.name, - content: Bytes.ofData(f.data), - }); - }); - file.browse(); - return d.promise(); - } - - public static function save(content:FileContent):Void { - var file = new ModernFileReference(); - file.save(content.content.getData(), content.name); - } + public static function save(content:FileContent):Void { + var file = new ModernFileReference(); + file.save(content.content.getData(), content.name); + } } diff --git a/src/app/haxe/ru/m/puzzlez/ImageUtil.hx b/src/app/haxe/ru/m/puzzlez/ImageUtil.hx index 60f558f..1dd805d 100644 --- a/src/app/haxe/ru/m/puzzlez/ImageUtil.hx +++ b/src/app/haxe/ru/m/puzzlez/ImageUtil.hx @@ -11,17 +11,16 @@ import promhx.Deferred; import promhx.Promise; class ImageUtil { - - public static function bytesToImage(bytes:Bytes):Promise { - var def = new Deferred(); - var loader = new Loader(); - loader.contentLoaderInfo.addEventListener(Event.COMPLETE, (event:Event) -> { - def.resolve(cast(cast(event.target, LoaderInfo).content, Bitmap).bitmapData); - }); - loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, (event:IOErrorEvent) -> { - def.throwError(event); - }); - loader.loadBytes(bytes); - return def.promise(); - } + public static function bytesToImage(bytes:Bytes):Promise { + var def = new Deferred(); + var loader = new Loader(); + loader.contentLoaderInfo.addEventListener(Event.COMPLETE, (event:Event) -> { + def.resolve(cast(cast(event.target, LoaderInfo).content, Bitmap).bitmapData); + }); + loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, (event:IOErrorEvent) -> { + def.throwError(event); + }); + loader.loadBytes(bytes); + return def.promise(); + } } diff --git a/src/app/haxe/ru/m/puzzlez/PuzzlezApp.hx b/src/app/haxe/ru/m/puzzlez/PuzzlezApp.hx index 77e8189..6abfba3 100644 --- a/src/app/haxe/ru/m/puzzlez/PuzzlezApp.hx +++ b/src/app/haxe/ru/m/puzzlez/PuzzlezApp.hx @@ -15,25 +15,24 @@ import ru.m.puzzlez.view.PuzzlezAppView; import ru.m.update.Updater; class PuzzlezApp { + @:provide static var updater:Updater; + @:provide static var sourceBundle:ImageSourceBundle; - @:provide static var updater:Updater; - @:provide static var sourceBundle:ImageSourceBundle; - - public static function main() { - // ToDo: fix @:provide macro - Settings; - IPartBuilder; - GameStorage; - sourceBundle.register(new AssetImageSource()); - sourceBundle.register(new FileImageSource()); - sourceBundle.register(new PixabayImageSource()); - sourceBundle.register(new UnsplashImageSource()); - L.push(new TraceLogger()); - updater = new Updater(Const.instance.VERSION, "https://shmyga.ru/repo/puzzlez/packages.json"); - var app = new App(); - app.theme = new PuzzlezTheme(); - app.icon = openfl.Assets.getBitmapData("resources/icon.png"); - app.view = new PuzzlezAppView(); - L.d("Puzzlez", "started"); - } + public static function main() { + // ToDo: fix @:provide macro + Settings; + IPartBuilder; + GameStorage; + sourceBundle.register(new AssetImageSource()); + sourceBundle.register(new FileImageSource()); + sourceBundle.register(new PixabayImageSource()); + sourceBundle.register(new UnsplashImageSource()); + L.push(new TraceLogger()); + updater = new Updater(Const.instance.VERSION, "https://shmyga.ru/repo/puzzlez/packages.json"); + var app = new App(); + app.theme = new PuzzlezTheme(); + app.icon = openfl.Assets.getBitmapData("resources/icon.png"); + app.view = new PuzzlezAppView(); + L.d("Puzzlez", "started"); + } } diff --git a/src/app/haxe/ru/m/puzzlez/PuzzlezTheme.hx b/src/app/haxe/ru/m/puzzlez/PuzzlezTheme.hx index 2373d6a..81ad05b 100644 --- a/src/app/haxe/ru/m/puzzlez/PuzzlezTheme.hx +++ b/src/app/haxe/ru/m/puzzlez/PuzzlezTheme.hx @@ -10,75 +10,60 @@ import openfl.Assets; import ru.m.skin.ButtonSVGSkin; class PuzzlezTheme extends Theme { + private static var ICONS:Map = [ + "close" => "times-circle-solid.svg", + "setting" => "cog-solid.svg", + "image" => "image-polaroid.svg", + "lock" => "lock-alt-solid.svg", + "restore" => "window-restore-solid.svg", + "compress" => "compress-solid.svg", + "expand" => "expand-solid.svg", + ]; - private static var ICONS:Map = [ - "close" => "times-circle-solid.svg", - "setting" => "cog-solid.svg", - "image" => "image-polaroid.svg", - "lock" => "lock-alt-solid.svg", - "restore" => "window-restore-solid.svg", - "compress" => "compress-solid.svg", - "expand" => "expand-solid.svg", - ]; - - public function new() { - super({embed: true}, {light: "gray"}, {base: "4h"}); - register(new Style("frame", [ - "geometry.padding" => Box.fromFloat(8), - ])); - register(new Style("view", [ - "skin.background.color" => colors.light, - "skin.border.color" => colors.border, - "geometry.padding" => Box.fromFloat(3), - "geometry.width" => SizeValue.fromString("50h"), - "geometry.height" => SizeValue.fromString("40h"), - ])); - register(new Style("text.error", [ - "font.color" => Color.fromString("red"), - ], "text")); - register(new Style("icon", [ - "geometry.width" => SizeValue.fromString("8h"), - "geometry.height" => SizeValue.fromString("8h"), - "skin" => function() return new ButtonSVGSkin(), - "skin.color" => colors.light, - ])); - for (key in ICONS.keys()) { - register(new Style('icon.${key}', [ - "skin.svg" => Assets.getText('resources/icon/${ICONS.get(key)}'), - ])); - } - register(new Style("icon.small", [ - "geometry.width" => SizeValue.fromString("6h"), - "geometry.height" => SizeValue.fromString("6h"), - ])); - register(new Style("icon.red", [ - "skin.color" => 0xcc0000, - ])); - register(new Style("icon.orange", [ - "skin.color" => 0xcc5500, - ])); - register(new Style("icon.green", [ - "skin.color" => 0x00ff00, - ])); - register(new Style("icon.control", [ - "geometry.hAlign" => HAlign.RIGHT, - "geometry.vAlign" => VAlign.TOP, - "geometry.margin" => Box.fromFloat(3), - ])); - - register(new Style("button.red", [ - "skin.color" => 0xcc0000, - ], "button")); - - register(new Style("label.header", [ - "font.size" => SizeValue.fromString("5h"), - "geometry.hAlign" => HAlign.CENTER, - "geometry.margin.top" => 10, - "geometry.margin.bottom" => 10, - ], "label")); - register(new Style("button.background", [ - "geometry.width" => SizeValue.fromString("10h"), - "geometry.height" => SizeValue.fromString("10h"), - ])); + public function new() { + super({embed: true}, {light: "gray"}, {base: "4h"}); + register(new Style("frame", ["geometry.padding" => Box.fromFloat(8),])); + register(new Style("view", [ + "skin.background.color" => colors.light, + "skin.border.color" => colors.border, + "geometry.padding" => Box.fromFloat(3), + "geometry.width" => SizeValue.fromString("50h"), + "geometry.height" => SizeValue.fromString("40h"), + ])); + register(new Style("text.error", ["font.color" => Color.fromString("red"),], "text")); + register(new Style("icon", [ + "geometry.width" => SizeValue.fromString("8h"), + "geometry.height" => SizeValue.fromString("8h"), + "skin" => function() return new ButtonSVGSkin(), + "skin.color" => colors.light, + ])); + for (key in ICONS.keys()) { + register(new Style('icon.${key}', ["skin.svg" => Assets.getText('resources/icon/${ICONS.get(key)}'),])); } + register(new Style("icon.small", [ + "geometry.width" => SizeValue.fromString("6h"), + "geometry.height" => SizeValue.fromString("6h"), + ])); + register(new Style("icon.red", ["skin.color" => 0xcc0000,])); + register(new Style("icon.orange", ["skin.color" => 0xcc5500,])); + register(new Style("icon.green", ["skin.color" => 0x00ff00,])); + register(new Style("icon.control", [ + "geometry.hAlign" => HAlign.RIGHT, + "geometry.vAlign" => VAlign.TOP, + "geometry.margin" => Box.fromFloat(3), + ])); + + register(new Style("button.red", ["skin.color" => 0xcc0000,], "button")); + + register(new Style("label.header", [ + "font.size" => SizeValue.fromString("5h"), + "geometry.hAlign" => HAlign.CENTER, + "geometry.margin.top" => 10, + "geometry.margin.bottom" => 10, + ], "label")); + register(new Style("button.background", [ + "geometry.width" => SizeValue.fromString("10h"), + "geometry.height" => SizeValue.fromString("10h"), + ])); + } } diff --git a/src/app/haxe/ru/m/puzzlez/core/Action.hx b/src/app/haxe/ru/m/puzzlez/core/Action.hx index 27257ff..976862f 100644 --- a/src/app/haxe/ru/m/puzzlez/core/Action.hx +++ b/src/app/haxe/ru/m/puzzlez/core/Action.hx @@ -4,10 +4,10 @@ import ru.m.puzzlez.proto.game.ImageId; import ru.m.puzzlez.proto.game.GameState; enum GameAction { - START(state:GameState); + START(state:GameState); } enum Action { - GAME(state:GameState, ?delete:Bool); - IMAGE(image:ImageId); + GAME(state:GameState, ?delete:Bool); + IMAGE(image:ImageId); } diff --git a/src/app/haxe/ru/m/puzzlez/core/ImageSource.hx b/src/app/haxe/ru/m/puzzlez/core/ImageSource.hx index 1b82921..32356f4 100644 --- a/src/app/haxe/ru/m/puzzlez/core/ImageSource.hx +++ b/src/app/haxe/ru/m/puzzlez/core/ImageSource.hx @@ -5,6 +5,6 @@ import ru.m.data.DataSource; import ru.m.puzzlez.proto.game.ImageId; interface ImageSource extends DataSource { - public var id(default, never):String; - public function load(id:String, thumb:Bool = false):Promise; + public var id(default, never):String; + public function load(id:String, thumb:Bool = false):Promise; } diff --git a/src/app/haxe/ru/m/puzzlez/core/ImageValue.hx b/src/app/haxe/ru/m/puzzlez/core/ImageValue.hx index 7e5942d..dc37598 100644 --- a/src/app/haxe/ru/m/puzzlez/core/ImageValue.hx +++ b/src/app/haxe/ru/m/puzzlez/core/ImageValue.hx @@ -4,7 +4,7 @@ import haxe.io.Bytes; import flash.display.BitmapData; enum ImageValue { - BITMAP(value:BitmapData); - BYTES(value:Bytes); - URL(value:String); + BITMAP(value:BitmapData); + BYTES(value:Bytes); + URL(value:String); } diff --git a/src/app/haxe/ru/m/puzzlez/image/ImageData.hx b/src/app/haxe/ru/m/puzzlez/image/ImageData.hx index 1a6756a..c0bafc6 100644 --- a/src/app/haxe/ru/m/puzzlez/image/ImageData.hx +++ b/src/app/haxe/ru/m/puzzlez/image/ImageData.hx @@ -9,50 +9,49 @@ import ru.m.puzzlez.core.ImageValue; import ru.m.puzzlez.proto.game.ImageId; abstract ImageData(ImageId) from ImageId { + private static var cache:Map> = new Map(); + private static var storageCache:StorageCache = new StorageCache(); - private static var cache:Map> = new Map(); - private static var storageCache:StorageCache = new StorageCache(); + @:provide private var sourceBundle:ImageSourceBundle; - @:provide private var sourceBundle:ImageSourceBundle; + public function new(image:ImageId) { + this = image; + } - public function new(image: ImageId) { - this = image; - } + @:from public static function fromImageId(value:ImageId):ImageData { + return new ImageData(value); + } - @:from public static function fromImageId(value:ImageId):ImageData { - return new ImageData(value); - } + public function withThumb():ImageData { + return new ImageData(new ImageId().setSource(this.source).setId(this.id).setThumb(true)); + } - public function withThumb():ImageData { - return new ImageData(new ImageId().setSource(this.source).setId(this.id).setThumb(true)); - } - - private function extractImage(key:String, value:ImageValue):Promise { - return switch value { - case ImageValue.BITMAP(value): - Promise.promise(value); - case ImageValue.BYTES(value): - if (!storageCache.exists(key)) { - storageCache.set(key, value); - } - ImageUtil.bytesToImage(value); - case ImageValue.URL(value): - new BytesLoader().GET(value).pipe(bytes -> extractImage(key, ImageValue.BYTES(Bytes.ofData(bytes)))); + private function extractImage(key:String, value:ImageValue):Promise { + return switch value { + case ImageValue.BITMAP(value): + Promise.promise(value); + case ImageValue.BYTES(value): + if (!storageCache.exists(key)) { + storageCache.set(key, value); } + ImageUtil.bytesToImage(value); + case ImageValue.URL(value): + new BytesLoader().GET(value).pipe(bytes -> extractImage(key, ImageValue.BYTES(Bytes.ofData(bytes)))); } + } - public function resolve():Promise { - var key = '${this.source}:${this.id}'; - if (this.thumb) { - key = '${key}:thumb'; - } - if (!cache.exists(key)) { - if (storageCache.exists(key)) { - cache.set(key, extractImage(key, ImageValue.BYTES(storageCache.get(key)))); - } else { - cache.set(key, sourceBundle.get(this.source).load(this.id, this.thumb).pipe(value -> extractImage(key, value))); - } - } - return cache.get(key); + public function resolve():Promise { + var key = '${this.source}:${this.id}'; + if (this.thumb) { + key = '${key}:thumb'; } + if (!cache.exists(key)) { + if (storageCache.exists(key)) { + cache.set(key, extractImage(key, ImageValue.BYTES(storageCache.get(key)))); + } else { + cache.set(key, sourceBundle.get(this.source).load(this.id, this.thumb).pipe(value -> extractImage(key, value))); + } + } + return cache.get(key); + } } diff --git a/src/app/haxe/ru/m/puzzlez/image/ImageSourceBundle.hx b/src/app/haxe/ru/m/puzzlez/image/ImageSourceBundle.hx index 95820d7..f84806a 100644 --- a/src/app/haxe/ru/m/puzzlez/image/ImageSourceBundle.hx +++ b/src/app/haxe/ru/m/puzzlez/image/ImageSourceBundle.hx @@ -3,20 +3,20 @@ package ru.m.puzzlez.image; import ru.m.puzzlez.core.ImageSource; @:provide class ImageSourceBundle { - private var sources:Map; + private var sources:Map; - public function new() { - sources = new Map(); - } + public function new() { + sources = new Map(); + } - public function register(source:ImageSource):Void { - sources.set(source.id, source); - } + public function register(source:ImageSource):Void { + sources.set(source.id, source); + } - public function get(sourceId:String):ImageSource { - if (!sources.exists(sourceId)) { - throw 'ImageSource "$sourceId" not registered'; - } - return sources.get(sourceId); + public function get(sourceId:String):ImageSource { + if (!sources.exists(sourceId)) { + throw 'ImageSource "$sourceId" not registered'; } + return sources.get(sourceId); + } } diff --git a/src/app/haxe/ru/m/puzzlez/net/Network.hx b/src/app/haxe/ru/m/puzzlez/net/Network.hx index 0067420..d31c31f 100644 --- a/src/app/haxe/ru/m/puzzlez/net/Network.hx +++ b/src/app/haxe/ru/m/puzzlez/net/Network.hx @@ -22,99 +22,99 @@ import ru.m.puzzlez.proto.pack.Request; import ru.m.puzzlez.proto.pack.Response; @:provide class Network implements IDataSource { - public var userSignal:Signal = new Signal(); - public var notificationSignal:Signal = new Signal(); - public var listSignal:Signal = new Signal(); - public var joinSignal:Signal = new Signal(); - public var gameEventSignal:Signal = new Signal(); + public var userSignal:Signal = new Signal(); + public var notificationSignal:Signal = new Signal(); + public var listSignal:Signal = new Signal(); + public var joinSignal:Signal = new Signal(); + public var gameEventSignal:Signal = new Signal(); - private var connection:IConnection; - private var storage:SharedObjectStorage; + private var connection:IConnection; + private var storage:SharedObjectStorage; - private static var USER_KEY = "user"; + private static var USER_KEY = "user"; - public function new() { - storage = new SharedObjectStorage("network/2"); - connection = ConnectionFactory.buildClientConnection("127.0.0.1", 5000, Response); - connection.handler.connect(onConnectionChange); - connection.receiveHandler.connect(onReceivePacket); - connection.connect().catchError(_ -> {}); + public function new() { + storage = new SharedObjectStorage("network/2"); + connection = ConnectionFactory.buildClientConnection("127.0.0.1", 5000, Response); + connection.handler.connect(onConnectionChange); + connection.receiveHandler.connect(onReceivePacket); + connection.connect().catchError(_ -> {}); + } + + private function restoreUser():User { + if (storage.exists(USER_KEY)) { + return storage.read(USER_KEY); + } else { + return new User().setName('Anonimus #${IdUtil.generate()}'); } + } - private function restoreUser():User { - if (storage.exists(USER_KEY)) { - return storage.read(USER_KEY); - } else { - return new User().setName('Anonimus #${IdUtil.generate()}'); - } - } + public function auth():Promise { + connection.send(new Request().setAuth(new AuthRequest().setUser(restoreUser()))); + return userSignal.next(); + } - public function auth():Promise { - connection.send(new Request().setAuth(new AuthRequest().setUser(restoreUser()))); - return userSignal.next(); - } + public function createGame(preset:GamePreset):Promise { + connection.send(new Request().setJoin(new GameJoinRequest().setPreset(preset))); + return joinSignal.next(); + } - public function createGame(preset:GamePreset):Promise { - connection.send(new Request().setJoin(new GameJoinRequest().setPreset(preset))); - return joinSignal.next(); - } + public function joinGame(gameId:String):Promise { + connection.send(new Request().setJoin(new GameJoinRequest().setGameId(gameId))); + return joinSignal.next(); + } - public function joinGame(gameId:String):Promise { - connection.send(new Request().setJoin(new GameJoinRequest().setGameId(gameId))); - return joinSignal.next(); - } + public function leaveGame():Void { + connection.send(new Request().setLeave(new GameLeaveRequest())); + } - public function leaveGame():Void { - connection.send(new Request().setLeave(new GameLeaveRequest())); - } + public function sendGameAction(action:GameAction):Void { + connection.send(new Request().setAction(new GameActionRequest().setActions([action]))); + } - public function sendGameAction(action:GameAction):Void { - connection.send(new Request().setAction(new GameActionRequest().setActions([action]))); + private function onConnectionChange(event:ConnectionEvent):Void { + L.i("network", '${event}'); + switch event { + case CONNECTED: + auth().then(user -> storage.write(USER_KEY, user)); + case DISCONNECTED: + // + case ERROR(error): + // ToDo: reconnect } + } - private function onConnectionChange(event:ConnectionEvent):Void { - L.i("network", '${event}'); - switch event { - case CONNECTED: - auth().then(user -> storage.write(USER_KEY, user)); - case DISCONNECTED: - // - case ERROR(error): - // ToDo: reconnect - } + private function onReceivePacket(packet:Response):Void { + if (packet.hasAuth()) { + userSignal.emit(packet.auth.user); + } else if (packet.hasNotification()) { + notificationSignal.emit(packet.notification); + } else if (packet.hasList()) { + listSignal.emit(packet.list); + } else if (packet.hasJoin()) { + joinSignal.emit(packet.join.game); + } else if (packet.hasEvent()) { + for (event in packet.event.events) { + gameEventSignal.emit(event); + } } + } - private function onReceivePacket(packet:Response):Void { - if (packet.hasAuth()) { - userSignal.emit(packet.auth.user); - } else if (packet.hasNotification()) { - notificationSignal.emit(packet.notification); - } else if (packet.hasList()) { - listSignal.emit(packet.list); - } else if (packet.hasJoin()) { - joinSignal.emit(packet.join.game); - } else if (packet.hasEvent()) { - for (event in packet.event.events) { - gameEventSignal.emit(event); - } - } - } + public function getPage(page:Page):Promise> { + connection.send(new Request().setList(new GameListRequest().setCount(page.count).setPage(page.index))); + return listSignal.next().then((list:GameListResponse) -> ({ + page: { + index: list.page, + count: list.count, + filter: null, + order: null, + }, + total: list.total, + data: list.games, + })); + } - public function getPage(page:Page):Promise> { - connection.send(new Request().setList(new GameListRequest().setCount(page.count).setPage(page.index))); - return listSignal.next().then((list:GameListResponse) -> ({ - page: { - index: list.page, - count: list.count, - filter: null, - order: null, - }, - total: list.total, - data: list.games, - })); - } - - public function get(id:String):GameState { - return null; - } + public function get(id:String):GameState { + return null; + } } diff --git a/src/app/haxe/ru/m/puzzlez/net/NetworkGame.hx b/src/app/haxe/ru/m/puzzlez/net/NetworkGame.hx index f50e214..c8b7878 100644 --- a/src/app/haxe/ru/m/puzzlez/net/NetworkGame.hx +++ b/src/app/haxe/ru/m/puzzlez/net/NetworkGame.hx @@ -8,36 +8,36 @@ import ru.m.puzzlez.proto.event.GameEvent; import ru.m.puzzlez.proto.game.GameState; class NetworkGame implements IGame { - public var state(default, null):GameState; - public var events(default, null):Signal; + public var state(default, null):GameState; + public var events(default, null):Signal; - @:provide private var network:Network; + @:provide private var network:Network; - public function new(state:GameState) { - this.state = state; - events = new Signal(); - } + public function new(state:GameState) { + this.state = state; + events = new Signal(); + } - public function action(action:GameAction):Void { - network.sendGameAction(action); - } + public function action(action:GameAction):Void { + network.sendGameAction(action); + } - public function start():Void { - events.emit(new GameEvent().setStart(new GameStart().setState(state))); - network.gameEventSignal.connect(onEvent); - } + public function start():Void { + events.emit(new GameEvent().setStart(new GameStart().setState(state))); + network.gameEventSignal.connect(onEvent); + } - public function stop():Void { - network.gameEventSignal.disconnect(onEvent); - network.leaveGame(); - } + public function stop():Void { + network.gameEventSignal.disconnect(onEvent); + network.leaveGame(); + } - public function dispose():Void { - stop(); - events.dispose(); - } + public function dispose():Void { + stop(); + events.dispose(); + } - private function onEvent(event:GameEvent):Void { - events.emit(event); - } + private function onEvent(event:GameEvent):Void { + events.emit(event); + } } diff --git a/src/app/haxe/ru/m/puzzlez/render/Background.hx b/src/app/haxe/ru/m/puzzlez/render/Background.hx index dc6e708..b5d1fcc 100644 --- a/src/app/haxe/ru/m/puzzlez/render/Background.hx +++ b/src/app/haxe/ru/m/puzzlez/render/Background.hx @@ -4,7 +4,7 @@ import hw.color.Color; import ru.m.puzzlez.proto.game.ImageId; enum Background { - NONE; - COLOR(color:Color); - IMAGE(id:ImageId); + NONE; + COLOR(color:Color); + IMAGE(id:ImageId); } diff --git a/src/app/haxe/ru/m/puzzlez/render/CompleteView.hx b/src/app/haxe/ru/m/puzzlez/render/CompleteView.hx index 27d4726..3d66003 100644 --- a/src/app/haxe/ru/m/puzzlez/render/CompleteView.hx +++ b/src/app/haxe/ru/m/puzzlez/render/CompleteView.hx @@ -7,66 +7,65 @@ import flash.geom.Matrix; import ru.m.puzzlez.render.part.IPartBuilder; class CompleteView extends Shape { + public var parts:Array; + public var preset:GamePreset; - public var parts:Array; - public var preset:GamePreset; + @:provide static var builder:IPartBuilder; - @:provide static var builder:IPartBuilder; + public function new() { + super(); + parts = []; + } - public function new() { - super(); - parts = []; + public function addChild(part:PartView):Void { + if (part.parent != null) { + part.parent.removeChild(part); + } + parts.push(part); + } + + public function redraw():Void { + if (preset == null) { + return; } - public function addChild(part:PartView):Void { - if (part.parent != null) { - part.parent.removeChild(part); - } - parts.push(part); - } + var partWidth = preset.imageRect.width / preset.grid.x; + var partHeight = preset.imageRect.height / preset.grid.y; - public function redraw():Void { - if (preset == null) { - return; - } + graphics.clear(); + graphics.lineStyle(2, 0xCCCCCC); + graphics.beginFill(0x555555, 0.4); + graphics.drawRect(0, 0, preset.imageRect.width, preset.imageRect.height); + graphics.endFill(); + graphics.lineStyle(); - var partWidth = preset.imageRect.width / preset.grid.x; - var partHeight = preset.imageRect.height / preset.grid.y; + for (partView in parts) { + var part = partView.part; - graphics.clear(); - graphics.lineStyle(2, 0xCCCCCC); - graphics.beginFill(0x555555, 0.4); - graphics.drawRect(0, 0, preset.imageRect.width, preset.imageRect.height); + if (partView.currentImage != null) { + var image = partView.currentImage; + var m = new Matrix(); + m.translate(partView.x, partView.y); + graphics.beginBitmapFill(image, m, false, true); + graphics.drawRect(m.tx, m.ty, image.width, image.height); graphics.endFill(); + } + + var rect = cast(part.rect, RectangleExt).clone(); + rect.x = part.point.x * part.rect.width; + rect.y = part.point.y * part.rect.height; + var path = 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 (partView in parts) { - var part = partView.part; - - if (partView.currentImage != null) { - var image = partView.currentImage; - var m = new Matrix(); - m.translate(partView.x, partView.y); - graphics.beginBitmapFill(image, m, false, true); - graphics.drawRect(m.tx, m.ty, image.width, image.height); - graphics.endFill(); - } - - var rect = cast(part.rect, RectangleExt).clone(); - rect.x = part.point.x * part.rect.width; - rect.y = part.point.y * part.rect.height; - var path = 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(); - } - } + } } + } - public function clean():Void { - preset = null; - parts = []; - graphics.clear(); - } + public function clean():Void { + preset = null; + parts = []; + graphics.clear(); + } } diff --git a/src/app/haxe/ru/m/puzzlez/render/IRender.hx b/src/app/haxe/ru/m/puzzlez/render/IRender.hx index c296d94..2abc69f 100644 --- a/src/app/haxe/ru/m/puzzlez/render/IRender.hx +++ b/src/app/haxe/ru/m/puzzlez/render/IRender.hx @@ -6,9 +6,9 @@ import ru.m.puzzlez.proto.event.GameAction; import ru.m.puzzlez.proto.event.GameEvent; interface IRender extends IView { - public var actions(default, null):Signal; - public var scale(get, set):Float; - public var manager(default, null):RenderManager; + public var actions(default, null):Signal; + public var scale(get, set):Float; + public var manager(default, null):RenderManager; - public function onGameEvent(event:GameEvent):Void; + public function onGameEvent(event:GameEvent):Void; } diff --git a/src/app/haxe/ru/m/puzzlez/render/ImagePartBuilder.hx b/src/app/haxe/ru/m/puzzlez/render/ImagePartBuilder.hx index fab5906..e64b0bc 100644 --- a/src/app/haxe/ru/m/puzzlez/render/ImagePartBuilder.hx +++ b/src/app/haxe/ru/m/puzzlez/render/ImagePartBuilder.hx @@ -8,33 +8,32 @@ import ru.m.puzzlez.proto.game.Part; import ru.m.puzzlez.render.RenderUtil; typedef Result = { - var part:Part; - var image:PartImage; + var part:Part; + var image:PartImage; } class ImagePartBuilder { + private var image:BitmapData; - private var image:BitmapData; + public function new(image:BitmapData) { + this.image = image; + } - public function new(image:BitmapData) { - this.image = image; + private function buildPart(index:Int, count:Int, parts:Array, stream:PublicStream):Void { + for (i in index...index + count) { + if (i >= parts.length) { + return; + } + var part = parts[i]; + var image = RenderUtil.cropImagePart(image, part); + stream.update({part: part, image: image}); } + Timer.delay(() -> buildPart(index + count, count, parts, stream), 0); + } - private function buildPart(index:Int, count:Int, parts:Array, stream:PublicStream):Void { - for (i in index...index + count) { - if (i >= parts.length) { - return; - } - var part = parts[i]; - var image = RenderUtil.cropImagePart(image, part); - stream.update({part: part, image: image}); - } - Timer.delay(() -> buildPart(index + count, count, parts, stream), 0); - } - - public function build(parts:Array):Stream { - var stream = new PublicStream(); - Timer.delay(() -> buildPart(0, 5, parts, stream), 0); - return stream; - } + public function build(parts:Array):Stream { + var stream = new PublicStream(); + Timer.delay(() -> buildPart(0, 5, parts, stream), 0); + return stream; + } } diff --git a/src/app/haxe/ru/m/puzzlez/render/PartView.hx b/src/app/haxe/ru/m/puzzlez/render/PartView.hx index f5aab67..800f2f7 100644 --- a/src/app/haxe/ru/m/puzzlez/render/PartView.hx +++ b/src/app/haxe/ru/m/puzzlez/render/PartView.hx @@ -12,116 +12,114 @@ import ru.m.puzzlez.wrap.PointExt; import ru.m.puzzlez.wrap.RectangleExt; class PartView extends Sprite { + public var id(default, null):Int; + public var part(default, null):Part; + public var position(default, set):Point; + public var completed(default, default):Bool; + public var target(default, null):Point; - public var id(default, null):Int; - public var part(default, null):Part; - public var position(default, set):Point; - public var completed(default, default):Bool; - public var target(default, null):Point; + private function set_position(value:Point):Point { + position = cast(value, PointExt).clone(); + refresh(); + return position; + } - private function set_position(value:Point):Point { - position = cast(value, PointExt).clone(); - refresh(); - return position; + public var image(default, set):PartImage; + + private function set_image(value:PartImage):PartImage { + image = value; + redraw(); + refresh(); + return image; + } + + public var currentImage(get, never):BitmapData; + + private function get_currentImage():BitmapData { + if (image == null) { + return null; } + return completed ? image.borderedImage : image.shadedImage; + } - public var image(default, set):PartImage; + public var size(default, null):Point; - private function set_image(value:PartImage):PartImage { - image = value; - redraw(); - refresh(); - return image; + public var playerId(default, set):Null; + + private function set_playerId(value:Null):Null { + if (playerId != value) { + playerId = value; + redraw(); } + return playerId; + } - public var currentImage(get, never):BitmapData; + public function new(part:Part) { + super(); + this.id = part.id; + this.part = part; + this.size = cast(part.rect, RectangleExt).size; + this.target = new Point().setX(part.point.x * size.x).setY(part.point.y * size.y); + } - private function get_currentImage():BitmapData { - if (image == null) { - return null; - } - return completed ? image.borderedImage : image.shadedImage; + private function redraw():Void { + throw "Unimplemented"; + } + + private function refresh():Void { + if (position != null && image != null) { + x = position.x - (image.borderedImage.width - size.x) / 2; + y = position.y - (image.borderedImage.height - size.y) / 2; } + } - public var size(default, null):Point; + public function complete():Void { + position = target; + playerId = null; + completed = true; + refresh(); + redraw(); + } - public var playerId(default, set):Null; - - private function set_playerId(value:Null):Null { - if (playerId != value) { - playerId = value; - redraw(); - } - return playerId; - } - - public function new(part:Part) { - super(); - this.id = part.id; - this.part = part; - this.size = cast(part.rect, RectangleExt).size; - this.target = new Point().setX(part.point.x * size.x).setY(part.point.y * size.y); - } - - private function redraw():Void { - throw "Unimplemented"; - } - - private function refresh():Void { - if (position != null && image != null) { - x = position.x - (image.borderedImage.width - size.x) / 2; - y = position.y - (image.borderedImage.height - size.y) / 2; - } - } - - public function complete():Void { - position = target; - playerId = null; - completed = true; - refresh(); - redraw(); - } - - public static function factory(part:Part):PartView { - return new SpritePartView(part); - } + public static function factory(part:Part):PartView { + return new SpritePartView(part); + } } class SpritePartView extends PartView { + @:provide static var builder:IPartBuilder; - @:provide static var builder:IPartBuilder; - - override private function redraw():Void { - if (image == null) { - return; - } - var image = currentImage; - graphics.clear(); - graphics.beginBitmapFill(image, null, false, true); - graphics.drawRect(0, 0, image.width, image.height); - graphics.endFill(); - - if (playerId != null) { - var rect = cast(part.rect, RectangleExt).clone(); - rect.x += (image.width - size.x) / 2; - rect.y += (image.height - size.y) / 2; - var path = builder.build(rect, part.bounds); - graphics.lineStyle(4, 0xffff00, 0.3); - path.draw(graphics); - } + override private function redraw():Void { + if (image == null) { + return; } + var image = currentImage; + graphics.clear(); + graphics.beginBitmapFill(image, null, false, true); + graphics.drawRect(0, 0, image.width, image.height); + graphics.endFill(); + + if (playerId != null) { + var rect = cast(part.rect, RectangleExt).clone(); + rect.x += (image.width - size.x) / 2; + rect.y += (image.height - size.y) / 2; + var path = builder.build(rect, part.bounds); + graphics.lineStyle(4, 0xffff00, 0.3); + path.draw(graphics); + } + } } class BitmapPartView extends PartView { - private var bitmap:Bitmap; + private var bitmap:Bitmap; - public function new(part) { - super(part); - bitmap = new Bitmap(null, PixelSnapping.AUTO, true); - addChild(bitmap); - } + public function new(part) { + super(part); + bitmap = new Bitmap(null, PixelSnapping.AUTO, true); + addChild(bitmap); + } - override private function redraw():Void { - bitmap.bitmapData = currentImage; - } + override private function redraw():Void { + bitmap.bitmapData = currentImage; + } } diff --git a/src/app/haxe/ru/m/puzzlez/render/ProgressView.hx b/src/app/haxe/ru/m/puzzlez/render/ProgressView.hx index 3ae8416..9cadd16 100644 --- a/src/app/haxe/ru/m/puzzlez/render/ProgressView.hx +++ b/src/app/haxe/ru/m/puzzlez/render/ProgressView.hx @@ -3,19 +3,18 @@ package ru.m.puzzlez.render; import hw.view.form.LabelView; class ProgressView extends LabelView { + public function new() { + super(); + text = 'Loading...'; + } - public function new() { - super(); - text = 'Loading...'; - } + public function setProgress(current:Int, total:Int):Void { + text = 'Loading ${current}/${total}'; + } - public function setProgress(current:Int, total:Int):Void { - text = 'Loading ${current}/${total}'; - } - - override private function set_text(value:String):String { - var result = super.set_text(value); - update(); - return result; - } + override private function set_text(value:String):String { + var result = super.set_text(value); + update(); + return result; + } } diff --git a/src/app/haxe/ru/m/puzzlez/render/Render.hx b/src/app/haxe/ru/m/puzzlez/render/Render.hx index 50da822..fbb5e21 100644 --- a/src/app/haxe/ru/m/puzzlez/render/Render.hx +++ b/src/app/haxe/ru/m/puzzlez/render/Render.hx @@ -22,232 +22,217 @@ import ru.m.puzzlez.settings.Settings; import ru.m.puzzlez.wrap.PointExt; class Render extends SpriteView implements IRender { + public var actions(default, null):Signal; + public var scale(get, set):Float; + public var manager(default, null):RenderManager; - public var actions(default, null):Signal; - public var scale(get, set):Float; - public var manager(default, null):RenderManager; + @:provide static var settings:Settings; - @:provide static var settings:Settings; + private var playerId(get, never):String; - private var playerId(get, never):String; + private function get_playerId():String { + // ToDo: network user + return "local"; + } - private function get_playerId():String { - // ToDo: network user - return "local"; + private function get_scale():Float { + return tableView.scaleX; + } + + private function set_scale(value:Float):Float { + var result = tableView.scaleX = tableView.scaleY = value; + tableView.x = (width - state.preset.tableRect.width * value) / 2; + tableView.y = (height - state.preset.tableRect.height * value) / 2; + // setSize(table.width, table.height, 'table'); + return result; + } + + private var state:GameState; + private var image:BitmapData; + + private var progress:ProgressView; + private var container:Sprite; + private var tableView:Sprite; + private var imageView:CompleteView; + private var parts:Map; + private var activePart:PartView; + private var activePoint:PointExt; + + private var movePoint:FlashPoint; + + public function new() { + super(); + container = new Sprite(); + content.addChild(container); + manager = new RenderManager(content, container); + manager.locked = settings.locked; + progress = new ProgressView(); + actions = new Signal(); + tableView = new Sprite(); + tableView.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); + imageView = new CompleteView(); + tableView.addChild(imageView); + container.addChild(tableView); + parts = new Map(); + } + + public function onGameEvent(event:GameEvent):Void { + if (event.hasStart()) { + onStart(event.start.state); + } else if (event.hasChange()) { + var part:PartView = parts[event.change.partId]; + part.playerId = event.change.playerId; + part.position = event.change.position; + switch event.change.location { + case PartLocation.IMAGE: + part.complete(); + imageView.addChild(part); + imageView.redraw(); + case _: + } + } else if (event.hasComplete()) { + AlertView.alert("Complete!"); + } + } + + private function onStart(state:GameState):Void { + clean(); + this.state = state; + for (part in state.parts) { + var partView = PartView.factory(part); + parts.set(part.id, partView); + switch part.location { + case PartLocation.TABLE: + partView.position = part.position; + tableView.addChild(partView); + case PartLocation.IMAGE: + partView.complete(); + imageView.addChild(partView); + case _: + } } - private function get_scale():Float { - return tableView.scaleX; - } + imageView.x = state.preset.imageRect.x; + imageView.y = state.preset.imageRect.y; + imageView.preset = state.preset; + imageView.redraw(); + progress.text = "Loading image"; + content.addChild(progress.content); + ImageData.fromImageId(state.preset.image).resolve().then(onImageResolved); + toUpdate(); + } - private function set_scale(value:Float):Float { - var result = tableView.scaleX = tableView.scaleY = value; - tableView.x = (width - state.preset.tableRect.width * value) / 2; - tableView.y = (height - state.preset.tableRect.height * value) / 2; - //setSize(table.width, table.height, 'table'); - return result; - } - - private var state:GameState; - private var image:BitmapData; - - private var progress:ProgressView; - private var container:Sprite; - private var tableView:Sprite; - private var imageView:CompleteView; - private var parts:Map; - private var activePart:PartView; - private var activePoint:PointExt; - - private var movePoint:FlashPoint; - - public function new() { - super(); - container = new Sprite(); - content.addChild(container); - manager = new RenderManager(content, container); - manager.locked = settings.locked; - progress = new ProgressView(); - actions = new Signal(); - tableView = new Sprite(); - tableView.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); - imageView = new CompleteView(); - tableView.addChild(imageView); - container.addChild(tableView); - parts = new Map(); - } - - public function onGameEvent(event:GameEvent):Void { - if (event.hasStart()) { - onStart(event.start.state); - } else if (event.hasChange()) { - var part:PartView = parts[event.change.partId]; - part.playerId = event.change.playerId; - part.position = event.change.position; - switch event.change.location { - case PartLocation.IMAGE: - part.complete(); - imageView.addChild(part); - imageView.redraw(); - case _: - } - } else if (event.hasComplete()) { - AlertView.alert("Complete!"); + private function onImageResolved(image:BitmapData):Void { + this.image = RenderUtil.cropImage(image, state.preset.imageRect); + var builder = new ImagePartBuilder(this.image); + var i = 0; + 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) { + if (progress.content.parent != null) { + progress.content.parent.removeChild(progress.content); } - } - - private function onStart(state:GameState):Void { - clean(); - this.state = state; - for (part in state.parts) { - var partView = PartView.factory(part); - parts.set(part.id, partView); - switch part.location { - case PartLocation.TABLE: - partView.position = part.position; - tableView.addChild(partView); - case PartLocation.IMAGE: - partView.complete(); - imageView.addChild(partView); - case _: - } - } - - imageView.x = state.preset.imageRect.x; - imageView.y = state.preset.imageRect.y; - imageView.preset = state.preset; imageView.redraw(); - progress.text = "Loading image"; - content.addChild(progress.content); - ImageData.fromImageId(state.preset.image).resolve().then(onImageResolved); - toUpdate(); - } + } + }); + } - private function onImageResolved(image:BitmapData):Void { - this.image = RenderUtil.cropImage(image, state.preset.imageRect); - var builder = new ImagePartBuilder(this.image); - var i = 0; - 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) { - if (progress.content.parent != null) { - progress.content.parent.removeChild(progress.content); - } - imageView.redraw(); - } + override public function update():Void { + super.update(); + progress.x = (width - progress.width) / 2; + progress.y = (height - progress.height) / 2; + progress.update(); + if (state != null) { + scale = Math.min(width / state.preset.tableRect.width, height / state.preset.tableRect.height); + } + } + + override public function redraw():Void { + switch settings.background { + case Background.NONE: + super.redraw(); + case Background.COLOR(color): + content.graphics.clear(); + content.graphics.beginFill(color); + content.graphics.drawRect(0, 0, width, height); + content.graphics.endFill(); + case Background.IMAGE(id): + ImageData.fromImageId(id).resolve().then(result -> { + content.graphics.clear(); + content.graphics.beginBitmapFill(result); + content.graphics.drawRect(0, 0, width, height); + content.graphics.endFill(); }); } + } - override public function update():Void { - super.update(); - progress.x = (width - progress.width) / 2; - progress.y = (height - progress.height) / 2; - progress.update(); - if (state != null) { - scale = Math.min(width / state.preset.tableRect.width, height / state.preset.tableRect.height); + private function onMouseDown(event:MouseEvent):Void { + var point:FlashPoint = new FlashPoint(event.stageX, event.stageY); + var objects = tableView.getObjectsUnderPoint(point); + objects.reverse(); + var pointPart:PartView = null; + for (object in objects) { + if (Std.is(object, PartView)) { + var part:PartView = cast object; + var partPoint = part.globalToLocal(point); + var color = part.image.shadedImage.getPixel(Std.int(partPoint.x), Std.int(partPoint.y)); + if (color > 0) { + pointPart = part; + break; } + } } + if (pointPart != null) { + event.stopImmediatePropagation(); + if (event.ctrlKey) { + save(pointPart); + return; + } + if (pointPart.completed) { + return; + } + activePart = pointPart; + tableView.setChildIndex(activePart, tableView.numChildren - 1); + activePoint = tableView.globalToLocal(point); + tableView.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); + tableView.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); + actions.emit(new GameAction().setAction(Action.TAKE).setPlayerId(playerId).setPartId(activePart.id)); + } + } - override public function redraw():Void { - switch settings.background { - case Background.NONE: - super.redraw(); - case Background.COLOR(color): - content.graphics.clear(); - content.graphics.beginFill(color); - content.graphics.drawRect(0, 0, width, height); - content.graphics.endFill(); - case Background.IMAGE(id): - ImageData.fromImageId(id).resolve().then(result -> { - content.graphics.clear(); - content.graphics.beginBitmapFill(result); - content.graphics.drawRect(0, 0, width, height); - content.graphics.endFill(); - }); - } - } + private function onMouseMove(event:MouseEvent):Void { + var newPoint:PointExt = tableView.globalToLocal(new FlashPoint(event.stageX, event.stageY)); + var partPosition = cast(activePart.position, PointExt).add(newPoint).subtract(activePoint); + actions.emit(new GameAction().setAction(Action.MOVE).setPlayerId(playerId).setPartId(activePart.id).setPosition(partPosition)); + activePoint = newPoint; + } - private function onMouseDown(event:MouseEvent):Void { - var point:FlashPoint = new FlashPoint(event.stageX, event.stageY); - var objects = tableView.getObjectsUnderPoint(point); - objects.reverse(); - var pointPart:PartView = null; - for (object in objects) { - if (Std.is(object, PartView)) { - var part:PartView = cast object; - var partPoint = part.globalToLocal(point); - var color = part.image.shadedImage.getPixel(Std.int(partPoint.x), Std.int(partPoint.y)); - if (color > 0) { - pointPart = part; - break; - } - } - } - if (pointPart != null) { - event.stopImmediatePropagation(); - if (event.ctrlKey) { - save(pointPart); - return; - } - if (pointPart.completed) { - return; - } - activePart = pointPart; - tableView.setChildIndex(activePart, tableView.numChildren - 1); - activePoint = tableView.globalToLocal(point); - tableView.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); - tableView.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); - actions.emit(new GameAction() - .setAction(Action.TAKE) - .setPlayerId(playerId) - .setPartId(activePart.id) - ); - } - } + private function onMouseUp(event:MouseEvent):Void { + var newPoint:PointExt = tableView.globalToLocal(new FlashPoint(event.stageX, event.stageY)); + var partPosition = cast(activePart.position, PointExt).add(newPoint).subtract(activePoint); + actions.emit(new GameAction().setAction(Action.PUT).setPlayerId(playerId).setPartId(activePart.id).setPosition(partPosition)); + tableView.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); + tableView.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp); + activePart = null; + activePoint = null; + } - private function onMouseMove(event:MouseEvent):Void { - var newPoint:PointExt = tableView.globalToLocal(new FlashPoint(event.stageX, event.stageY)); - var partPosition = cast(activePart.position, PointExt).add(newPoint).subtract(activePoint); - actions.emit(new GameAction() - .setAction(Action.MOVE) - .setPlayerId(playerId) - .setPartId(activePart.id) - .setPosition(partPosition) - ); - activePoint = newPoint; - } + private function save(part:PartView):Void { + var file = new FileReference(); + 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"); + } - private function onMouseUp(event:MouseEvent):Void { - var newPoint:PointExt = tableView.globalToLocal(new FlashPoint(event.stageX, event.stageY)); - var partPosition = cast(activePart.position, PointExt).add(newPoint).subtract(activePoint); - actions.emit(new GameAction() - .setAction(Action.PUT) - .setPlayerId(playerId) - .setPartId(activePart.id) - .setPosition(partPosition) - ); - tableView.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); - tableView.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp); - activePart = null; - activePoint = null; - } - - private function save(part:PartView):Void { - var file = new FileReference(); - 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"); - } - - public function clean() { - for (partView in parts) { - if (partView.parent != null) { - partView.parent.removeChild(partView); - } - } - parts = new Map(); - imageView.clean(); + public function clean() { + for (partView in parts) { + if (partView.parent != null) { + partView.parent.removeChild(partView); + } } + parts = new Map(); + imageView.clean(); + } } diff --git a/src/app/haxe/ru/m/puzzlez/render/RenderManager.hx b/src/app/haxe/ru/m/puzzlez/render/RenderManager.hx index 55dcac7..b4692c8 100644 --- a/src/app/haxe/ru/m/puzzlez/render/RenderManager.hx +++ b/src/app/haxe/ru/m/puzzlez/render/RenderManager.hx @@ -7,62 +7,61 @@ import flash.events.MouseEvent; import flash.geom.Point; class RenderManager { + public var locked(default, default):Bool; - public var locked(default, default):Bool; + private var content:DisplayObject; + private var container:DisplayObject; + private var movePoint:Point; + private var gesture:GestureManager; - private var content:DisplayObject; - private var container:DisplayObject; - private var movePoint:Point; - private var gesture:GestureManager; + public function new(content:DisplayObject, container:DisplayObject) { + this.content = content; + this.container = container; + content.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); + content.addEventListener(ZoomGestureEvent.GESTURE_ZOOM, onGestureZoom); + gesture = new GestureManager(content); + } - public function new(content:DisplayObject, container:DisplayObject) { - this.content = content; - this.container = container; - content.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); - content.addEventListener(ZoomGestureEvent.GESTURE_ZOOM, onGestureZoom); - gesture = new GestureManager(content); + private function onGestureZoom(event:ZoomGestureEvent):Void { + if (locked) { + return; } + container.scaleX = container.scaleY += event.zoom; + } - private function onGestureZoom(event:ZoomGestureEvent):Void { - if (locked) { - return; - } - container.scaleX = container.scaleY += event.zoom; + private function onMouseDown(event:MouseEvent):Void { + if (locked) { + return; } + movePoint = new Point(event.stageX, event.stageY); + content.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); + content.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); + } - private function onMouseDown(event:MouseEvent):Void { - if (locked) { - return; - } - movePoint = new Point(event.stageX, event.stageY); - content.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); - content.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); - } + private function onMouseMove(event:MouseEvent):Void { + var newPoint = new Point(event.stageX, event.stageY); + var diff = newPoint.subtract(movePoint); + container.x += diff.x; + container.y += diff.y; + movePoint = newPoint; + } - private function onMouseMove(event:MouseEvent):Void { - var newPoint = new Point(event.stageX, event.stageY); - var diff = newPoint.subtract(movePoint); - container.x += diff.x; - container.y += diff.y; - movePoint = newPoint; - } + private function onMouseUp(event:MouseEvent):Void { + content.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); + content.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp); + movePoint = null; + } - private function onMouseUp(event:MouseEvent):Void { - content.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); - content.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp); - movePoint = null; - } + public function reset():Void { + container.x = 0; + container.y = 0; + } - public function reset():Void { - container.x = 0; - container.y = 0; - } - - public function dispose():Void { - if (gesture != null) { - gesture.dispose(); - gesture = null; - } - content.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); + public function dispose():Void { + if (gesture != null) { + gesture.dispose(); + gesture = null; } + content.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); + } } diff --git a/src/app/haxe/ru/m/puzzlez/render/RenderUtil.hx b/src/app/haxe/ru/m/puzzlez/render/RenderUtil.hx index 507ff54..44f099b 100644 --- a/src/app/haxe/ru/m/puzzlez/render/RenderUtil.hx +++ b/src/app/haxe/ru/m/puzzlez/render/RenderUtil.hx @@ -13,115 +13,113 @@ import ru.m.puzzlez.render.part.PartMask; import ru.m.puzzlez.wrap.RectangleExt; typedef DrawSetting = { - var offset:Point; - var color:Color; - var opacity:Float; + var offset:Point; + var color:Color; + var opacity:Float; } typedef PartImage = { - var borderedImage:BitmapData; - var shadedImage:BitmapData; + var borderedImage:BitmapData; + var shadedImage:BitmapData; } class RenderUtil { - public static var shadowSettings(default, null):Array = [ - {offset: new Point().setX(-2).setY(-2), color: 0x000000, opacity: 0.4}, - {offset: new Point().setX(2).setY(2), color: 0xffffff, opacity: 0.4}, - ]; + public static var shadowSettings(default, null):Array = [ + {offset: new Point().setX(-2).setY(-2), color: 0x000000, opacity: 0.4}, + {offset: new Point().setX(2).setY(2), color: 0xffffff, opacity: 0.4}, + ]; - public static var borderSettings(default, null):Array = [ - {offset: new Point().setX(-1).setY(-1), color: 0x555555, opacity: 0.4}, - {offset: new Point().setX(1).setY(1), color: 0xcccccc, opacity: 0.4}, - ]; + public static var borderSettings(default, null):Array = [ + {offset: new Point().setX(-1).setY(-1), color: 0x555555, opacity: 0.4}, + {offset: new Point().setX(1).setY(1), color: 0xcccccc, opacity: 0.4}, + ]; - @:provide static var builder:IPartBuilder; + @:provide static var builder:IPartBuilder; - public static function cropImage(source:BitmapData, rect:Rectangle):BitmapData { - var image = new BitmapData(Std.int(rect.width), Std.int(rect.height)); - var matrix = new Matrix(); - var scale = Math.max(rect.width / source.width, rect.height / source.height); - matrix.scale(scale, scale); - matrix.translate((rect.width - source.width * scale) / 2, (rect.height - source.height * scale) / 2); - image.draw(source, matrix); - return image; + public static function cropImage(source:BitmapData, rect:Rectangle):BitmapData { + var image = new BitmapData(Std.int(rect.width), Std.int(rect.height)); + var matrix = new Matrix(); + var scale = Math.max(rect.width / source.width, rect.height / source.height); + matrix.scale(scale, scale); + matrix.translate((rect.width - source.width * scale) / 2, (rect.height - source.height * scale) / 2); + image.draw(source, matrix); + return image; + } + + private static function buildPartGeometry(part:Part):{rect:Rectangle, drawRect:Rectangle} { + var source = new Rectangle().setX(part.rect.width * part.point.x) + .setY(part.rect.height * part.point.y) + .setWidth(part.rect.width) + .setHeight(part.rect.height); + var rect = cast(source, RectangleExt).clone(); + var offset = rect.width / 4 + rect.width * 0.05; + rect.x -= offset; + rect.y -= offset; + rect.width += offset * 2; + rect.height += offset * 2; + var drawRect = cast(source, RectangleExt).clone(); + drawRect.x = offset; + drawRect.y = offset; + return {rect: rect, drawRect: drawRect}; + } + + private static function drawShadow(source:BitmapData, path:DrawPath, values:Array):BitmapData { + var canvas = new Shape(); + canvas.cacheAsBitmap = true; + 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(); + var image = new BitmapData(source.width, source.height, true, 0x00000000); + image.draw(canvas, null, null, null, null, true); + return image; + } - private static function buildPartGeometry(part:Part):{rect:Rectangle, drawRect:Rectangle} { - var source = new Rectangle() - .setX(part.rect.width * part.point.x) - .setY(part.rect.height * part.point.y) - .setWidth(part.rect.width) - .setHeight(part.rect.height); - var rect = cast(source, RectangleExt).clone(); - var offset = rect.width / 4 + rect.width * 0.05; - rect.x -= offset; - rect.y -= offset; - rect.width += offset * 2; - rect.height += offset * 2; - var drawRect = cast(source, RectangleExt).clone(); - drawRect.x = offset; - drawRect.y = offset ; - return {rect:rect, drawRect:drawRect}; + private static function drawBorder(source:BitmapData, path:DrawPath, values:Array):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; + } - private static function drawShadow(source:BitmapData, path:DrawPath, values:Array):BitmapData { - var canvas = new Shape(); - canvas.cacheAsBitmap = true; - 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(); - 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(); + canvas.cacheAsBitmap = true; + canvas.mask = new PartMask(path); + var matrix = new Matrix(); + matrix.translate(-geometry.rect.x, -geometry.rect.y); + canvas.graphics.beginBitmapFill(source, matrix, false, true); + canvas.graphics.drawRect(0, 0, geometry.rect.width, geometry.rect.height); + 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); + var shadedImage = drawShadow(image, path, shadowSettings); + // var borderedImage = drawBorder(image, path, borderSettings); + return {borderedImage: image, shadedImage: shadedImage}; + } - private static function drawBorder(source:BitmapData, path:DrawPath, values:Array):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(); - canvas.cacheAsBitmap = true; - canvas.mask = new PartMask(path); - var matrix = new Matrix(); - matrix.translate(-geometry.rect.x, -geometry.rect.y); - canvas.graphics.beginBitmapFill(source, matrix, false, true); - canvas.graphics.drawRect(0, 0, geometry.rect.width, geometry.rect.height); - 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); - var shadedImage = drawShadow(image, path, shadowSettings); - //var borderedImage = drawBorder(image, path, borderSettings); - return {borderedImage: image, shadedImage: shadedImage}; - } - - public static function containRectangle(source:Rectangle, target:Rectangle):Rectangle { - var s = Math.min(1, Math.min(target.width / source.width, target.height / source.height)); - var width = source.width * s; - var height = source.height * s; - return new Rectangle() - .setX((target.width - width) / 2) - .setY((target.height - height) / 2) - .setWidth(width) - .setHeight(height); - } + public static function containRectangle(source:Rectangle, target:Rectangle):Rectangle { + var s = Math.min(1, Math.min(target.width / source.width, target.height / source.height)); + var width = source.width * s; + var height = source.height * s; + return new Rectangle().setX((target.width - width) / 2) + .setY((target.height - height) / 2) + .setWidth(width) + .setHeight(height); + } } diff --git a/src/app/haxe/ru/m/puzzlez/render/part/BasePartBuilder.hx b/src/app/haxe/ru/m/puzzlez/render/part/BasePartBuilder.hx index cb9fd19..98e909b 100644 --- a/src/app/haxe/ru/m/puzzlez/render/part/BasePartBuilder.hx +++ b/src/app/haxe/ru/m/puzzlez/render/part/BasePartBuilder.hx @@ -8,28 +8,25 @@ import ru.m.puzzlez.proto.game.PartBounds; import ru.m.puzzlez.render.part.IPartBuilder; class BasePartBuilder implements IPartBuilder { + public function new() {} - public function new() { - } + 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 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 {} - private function createBound(path:DrawPath, fromX:Float, fromY:Float, toX:Float, toY:Float, bound:PartBound):Void { - } - - public function build(rect:RectangleExt, bounds:PartBounds):DrawPath { - var path = new DrawPath(); - 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); - createAngle(path, rect.right, rect.bottom); - createBound(path, rect.right, rect.bottom, rect.left, rect.bottom, bounds.bottom); - createAngle(path, rect.left, rect.bottom); - createBound(path, rect.left, rect.bottom, rect.left, rect.top, bounds.left); - createAngle(path, rect.left, rect.top); - return path; - } + public function build(rect:RectangleExt, bounds:PartBounds):DrawPath { + var path = new DrawPath(); + 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); + createAngle(path, rect.right, rect.bottom); + createBound(path, rect.right, rect.bottom, rect.left, rect.bottom, bounds.bottom); + createAngle(path, rect.left, rect.bottom); + createBound(path, rect.left, rect.bottom, rect.left, rect.top, bounds.left); + createAngle(path, rect.left, rect.top); + return path; + } } diff --git a/src/app/haxe/ru/m/puzzlez/render/part/ClassicPartBuilder.hx b/src/app/haxe/ru/m/puzzlez/render/part/ClassicPartBuilder.hx index b8a6edc..7da45d4 100644 --- a/src/app/haxe/ru/m/puzzlez/render/part/ClassicPartBuilder.hx +++ b/src/app/haxe/ru/m/puzzlez/render/part/ClassicPartBuilder.hx @@ -5,42 +5,55 @@ import ru.m.puzzlez.proto.game.BoundType; import ru.m.puzzlez.proto.game.PartBound; class ClassicPartBuilder extends BasePartBuilder { - - override private function createBound(path:DrawPath, fromX:Float, fromY:Float, toX:Float, toY:Float, bound:PartBound):Void { - var dx = toX == fromX ? 0 : (toX - fromX) / Math.abs(toX - fromX); - var dy = toY == fromY ? 0 : (toY - fromY) / Math.abs(toY - fromY); - var boundLength = Math.max(Math.abs(toX - fromX), Math.abs(toY - fromY)); - var spikeWidth = boundLength * 0.2; - var spikeOffset = (boundLength - spikeWidth) / 2; - var spikeDepth = switch bound.spike { - case BoundType.IN: spikeWidth; - case BoundType.OUT: -spikeWidth; - case _: 0; - }; - var spikeSideOffset = switch bound.side { - case BoundType.IN: boundLength * -0.04; - case BoundType.OUT: boundLength * 0.04; - case _: 0; - } - switch bound.spike { - case BoundType.IN | BoundType.OUT: - path.commands.push(LINE_TO( - fromX + spikeOffset * dx + spikeSideOffset * dy, - fromY + spikeOffset * dy + spikeSideOffset * dx - )); - path.commands.push(CURVE_TO( - fromX + (spikeOffset * 0.7) * dx - spikeDepth * dy + spikeSideOffset * dy, - fromY + spikeDepth * dx + (spikeOffset * 0.7) * dy + spikeSideOffset * dx, - fromX + (spikeOffset + spikeWidth / 2) * dx - (spikeDepth * 1.1) * dy + spikeSideOffset * dy, - fromY + (spikeDepth * 1.1) * dx + (spikeOffset + spikeWidth / 2) * dy + spikeSideOffset * dx - )); - path.commands.push(CURVE_TO( - fromX + (spikeOffset + spikeWidth + spikeOffset * 0.3) * dx - spikeDepth * dy + spikeSideOffset * dy, - fromY + spikeDepth * dx + (spikeOffset + spikeWidth + spikeOffset * 0.3) * dy + spikeSideOffset * dx, - fromX + (spikeOffset + spikeWidth) * dx + spikeSideOffset * dy, - fromY + (spikeOffset + spikeWidth) * dy + spikeSideOffset * dx - )); - case _: - } + override private function createBound(path:DrawPath, fromX:Float, fromY:Float, toX:Float, toY:Float, bound:PartBound):Void { + var dx = toX == fromX ? 0 : (toX - fromX) / Math.abs(toX - fromX); + var dy = toY == fromY ? 0 : (toY - fromY) / Math.abs(toY - fromY); + var boundLength = Math.max(Math.abs(toX - fromX), Math.abs(toY - fromY)); + var spikeWidth = boundLength * 0.2; + var spikeOffset = (boundLength - spikeWidth) / 2; + var spikeDepth = switch bound.spike { + case BoundType.IN: spikeWidth; + case BoundType.OUT: -spikeWidth; + case _: 0; + }; + var spikeSideOffset = switch bound.side { + case BoundType.IN: boundLength * -0.04; + case BoundType.OUT: boundLength * 0.04; + case _: 0; } + switch bound.spike { + case BoundType.IN | BoundType.OUT: + path.commands.push(LINE_TO(fromX + spikeOffset * dx + spikeSideOffset * dy, fromY + spikeOffset * dy + spikeSideOffset * dx)); + path.commands.push(CURVE_TO(fromX + + (spikeOffset * 0.7) * dx + - spikeDepth * dy + + spikeSideOffset * dy, + fromY + + spikeDepth * dx + + (spikeOffset * 0.7) * dy + + spikeSideOffset * dx, + fromX + + (spikeOffset + spikeWidth / 2) * dx + - (spikeDepth * 1.1) * dy + + spikeSideOffset * dy, + fromY + + (spikeDepth * 1.1) * dx + + (spikeOffset + spikeWidth / 2) * dy + + spikeSideOffset * dx)); + path.commands.push(CURVE_TO(fromX + + (spikeOffset + spikeWidth + spikeOffset * 0.3) * dx + - spikeDepth * dy + + spikeSideOffset * dy, + fromY + + spikeDepth * dx + + (spikeOffset + spikeWidth + spikeOffset * 0.3) * dy + + spikeSideOffset * dx, + fromX + + (spikeOffset + spikeWidth) * dx + + spikeSideOffset * dy, fromY + + (spikeOffset + spikeWidth) * dy + + spikeSideOffset * dx)); + case _: + } + } } diff --git a/src/app/haxe/ru/m/puzzlez/render/part/IPartBuilder.hx b/src/app/haxe/ru/m/puzzlez/render/part/IPartBuilder.hx index 40ee83a..4de79ea 100644 --- a/src/app/haxe/ru/m/puzzlez/render/part/IPartBuilder.hx +++ b/src/app/haxe/ru/m/puzzlez/render/part/IPartBuilder.hx @@ -5,5 +5,5 @@ import ru.m.puzzlez.proto.game.PartBounds; import ru.m.puzzlez.wrap.RectangleExt; @:provide(ClassicPartBuilder) interface IPartBuilder { - public function build(rect:RectangleExt, bound:PartBounds):DrawPath; + public function build(rect:RectangleExt, bound:PartBounds):DrawPath; } diff --git a/src/app/haxe/ru/m/puzzlez/render/part/PartMask.hx b/src/app/haxe/ru/m/puzzlez/render/part/PartMask.hx index 46520b5..a6521c0 100644 --- a/src/app/haxe/ru/m/puzzlez/render/part/PartMask.hx +++ b/src/app/haxe/ru/m/puzzlez/render/part/PartMask.hx @@ -4,11 +4,10 @@ import flash.display.Shape; import ru.m.draw.DrawPath; class PartMask extends Shape { - - public function new(path:DrawPath) { - super(); - graphics.beginFill(0xff00ff, 1); - path.draw(graphics); - graphics.endFill(); - } + public function new(path:DrawPath) { + super(); + graphics.beginFill(0xff00ff, 1); + path.draw(graphics); + graphics.endFill(); + } } diff --git a/src/app/haxe/ru/m/puzzlez/render/part/SquarePartBuilder.hx b/src/app/haxe/ru/m/puzzlez/render/part/SquarePartBuilder.hx index 8ab3330..2426b75 100644 --- a/src/app/haxe/ru/m/puzzlez/render/part/SquarePartBuilder.hx +++ b/src/app/haxe/ru/m/puzzlez/render/part/SquarePartBuilder.hx @@ -5,37 +5,24 @@ import ru.m.puzzlez.proto.game.BoundType; import ru.m.puzzlez.proto.game.PartBound; class SquarePartBuilder extends BasePartBuilder { - - override private function createBound(path:DrawPath, fromX:Float, fromY:Float, toX:Float, toY:Float, bound:PartBound):Void { - var dx = toX == fromX ? 0 : (toX - fromX) / Math.abs(toX - fromX); - var dy = toY == fromY ? 0 : (toY - fromY) / Math.abs(toY - fromY); - var boundLength = Math.max(Math.abs(toX - fromX), Math.abs(toY - fromY)); - var spikeWidth = boundLength * 0.2; - var spikeOffset = (boundLength - spikeWidth) / 2; - var spikeDepth = switch bound.spike { - case BoundType.NONE: 0; - case BoundType.IN: spikeWidth; - case BoundType.OUT: -spikeWidth; - } - switch bound.spike { - case BoundType.NONE: - case BoundType.IN | BoundType.OUT: - path.commands.push(LINE_TO( - fromX + spikeOffset * dx, - fromY + spikeOffset * dy - )) - path.commands.push(LINE_TO( - fromX + spikeOffset * dx - spikeDepth * dy, - fromY + spikeDepth * dx + spikeOffset * dy - )); - path.commands.push(LINE_TO( - fromX + (spikeOffset + spikeWidth) * dx - spikeDepth * dy, - fromY + spikeDepth * dx + (spikeOffset + spikeWidth) * dy - )); - path.commands.push(LINE_TO( - fromX + (spikeOffset + spikeWidth) * dx, - fromY + (spikeOffset + spikeWidth) * dy - )); - } + override private function createBound(path:DrawPath, fromX:Float, fromY:Float, toX:Float, toY:Float, bound:PartBound):Void { + var dx = toX == fromX ? 0 : (toX - fromX) / Math.abs(toX - fromX); + var dy = toY == fromY ? 0 : (toY - fromY) / Math.abs(toY - fromY); + var boundLength = Math.max(Math.abs(toX - fromX), Math.abs(toY - fromY)); + var spikeWidth = boundLength * 0.2; + var spikeOffset = (boundLength - spikeWidth) / 2; + var spikeDepth = switch bound.spike { + case BoundType.NONE: 0; + case BoundType.IN: spikeWidth; + case BoundType.OUT: -spikeWidth; } + switch bound.spike { + case BoundType.NONE: + case BoundType.IN | BoundType.OUT: + path.commands.push(LINE_TO(fromX + spikeOffset * dx, + fromY + spikeOffset * dy)) path.commands.push(LINE_TO(fromX + spikeOffset * dx - spikeDepth * dy, fromY + spikeDepth * dx + spikeOffset * dy)); + path.commands.push(LINE_TO(fromX + (spikeOffset + spikeWidth) * dx - spikeDepth * dy, fromY + spikeDepth * dx + (spikeOffset + spikeWidth) * dy)); + path.commands.push(LINE_TO(fromX + (spikeOffset + spikeWidth) * dx, fromY + (spikeOffset + spikeWidth) * dy)); + } + } } diff --git a/src/app/haxe/ru/m/puzzlez/settings/Settings.hx b/src/app/haxe/ru/m/puzzlez/settings/Settings.hx index 06d126e..d5b9c32 100644 --- a/src/app/haxe/ru/m/puzzlez/settings/Settings.hx +++ b/src/app/haxe/ru/m/puzzlez/settings/Settings.hx @@ -4,33 +4,33 @@ import hw.storage.SharedObjectStorage; import ru.m.puzzlez.render.Background; @:provide class Settings extends SharedObjectStorage { - private inline static var VERSION = 2; - private inline static var BACKGROUND_KEY = "background"; - private inline static var LOCKED_KEY = "locked"; + private inline static var VERSION = 2; + private inline static var BACKGROUND_KEY = "background"; + private inline static var LOCKED_KEY = "locked"; - public var background(get, set):Background; + public var background(get, set):Background; - private inline function get_background():Background { - return exists(BACKGROUND_KEY) ? read(BACKGROUND_KEY) : NONE; - } + private inline function get_background():Background { + return exists(BACKGROUND_KEY) ? read(BACKGROUND_KEY) : NONE; + } - private inline function set_background(value:Background):Background { - write(BACKGROUND_KEY, value); - return value; - } + private inline function set_background(value:Background):Background { + write(BACKGROUND_KEY, value); + return value; + } - public var locked(get, set):Bool; + public var locked(get, set):Bool; - private inline function get_locked():Bool { - return exists(LOCKED_KEY) ? read(LOCKED_KEY) : false; - } + private inline function get_locked():Bool { + return exists(LOCKED_KEY) ? read(LOCKED_KEY) : false; + } - private inline function set_locked(value:Bool):Bool { - write(LOCKED_KEY, value); - return value; - } + private inline function set_locked(value:Bool):Bool { + write(LOCKED_KEY, value); + return value; + } - public function new() { - super('setting/${VERSION}'); - } + public function new() { + super('setting/${VERSION}'); + } } diff --git a/src/app/haxe/ru/m/puzzlez/source/AssetImageSource.hx b/src/app/haxe/ru/m/puzzlez/source/AssetImageSource.hx index 691d340..599a4ce 100644 --- a/src/app/haxe/ru/m/puzzlez/source/AssetImageSource.hx +++ b/src/app/haxe/ru/m/puzzlez/source/AssetImageSource.hx @@ -9,34 +9,36 @@ import ru.m.puzzlez.core.ImageValue; import ru.m.puzzlez.proto.game.ImageId; class AssetImageSource implements ImageSource { - public var id(default, never):String = "asset"; + public var id(default, never):String = "asset"; - private var _data:Array; - private var data(get, null):Array; + private var _data:Array; + private var data(get, null):Array; - private function get_data():Array { - if (_data == null) { - _data = resolveData(); - } - return _data; + private function get_data():Array { + if (_data == null) { + _data = resolveData(); } + return _data; + } - public function new() { - } + public function new() {} - private function resolveData():Array { - return [for (name in Assets.list(AssetType.IMAGE).filter((name:String) -> name.substr(0, 15) == "resources/image")) new ImageId().setSource(id).setId(name)]; - } + private function resolveData():Array { + return [ + for (name in Assets.list(AssetType.IMAGE).filter((name:String) -> name.substr(0, 15) == "resources/image")) + new ImageId().setSource(id).setId(name) + ]; + } - public function getPage(page:Page):Promise> { - return Promise.promise({ - page: page, - data: data.slice(page.index * page.count, page.count), - total: data.length, - }); - } + public function getPage(page:Page):Promise> { + return Promise.promise({ + page: page, + data: data.slice(page.index * page.count, page.count), + total: data.length, + }); + } - public function load(id:String, thumb:Bool = false):Promise { - return Promise.promise(ImageValue.BITMAP(Assets.getBitmapData(id))); - } + public function load(id:String, thumb:Bool = false):Promise { + return Promise.promise(ImageValue.BITMAP(Assets.getBitmapData(id))); + } } diff --git a/src/app/haxe/ru/m/puzzlez/source/FileImageSource.hx b/src/app/haxe/ru/m/puzzlez/source/FileImageSource.hx index c6a1698..7b640a4 100644 --- a/src/app/haxe/ru/m/puzzlez/source/FileImageSource.hx +++ b/src/app/haxe/ru/m/puzzlez/source/FileImageSource.hx @@ -8,24 +8,23 @@ import ru.m.puzzlez.proto.game.ImageId; import ru.m.puzzlez.storage.FileStorage; class FileImageSource implements ImageSource { - public var id(default, never):String = "file"; + public var id(default, never):String = "file"; - @:provide private var storage:FileStorage; + @:provide private var storage:FileStorage; - public function new() { - } + public function new() {} - public function getPage(page:Page):Promise> { - return storage.getIndexPage(page).then((response:DataPage) -> { - return { - page: response.page, - data: response.data.map(key -> new ImageId().setSource(id).setId(key)), - total: response.total, - } - }); - } + public function getPage(page:Page):Promise> { + return storage.getIndexPage(page).then((response:DataPage) -> { + return { + page: response.page, + data: response.data.map(key -> new ImageId().setSource(id).setId(key)), + total: response.total, + } + }); + } - public function load(id:String, thumb:Bool = false):Promise { - return storage.get(id).then(bytes -> ImageValue.BYTES(bytes)); - } + public function load(id:String, thumb:Bool = false):Promise { + return storage.get(id).then(bytes -> ImageValue.BYTES(bytes)); + } } diff --git a/src/app/haxe/ru/m/puzzlez/source/PixabayImageSource.hx b/src/app/haxe/ru/m/puzzlez/source/PixabayImageSource.hx index b77fbd1..d200fe4 100644 --- a/src/app/haxe/ru/m/puzzlez/source/PixabayImageSource.hx +++ b/src/app/haxe/ru/m/puzzlez/source/PixabayImageSource.hx @@ -1,53 +1,53 @@ package ru.m.puzzlez.source; import promhx.Promise; +import ru.m.api.PixabayApi; import ru.m.data.DataSource; -import ru.m.pixabay.PixabayApi; import ru.m.puzzlez.core.ImageSource; import ru.m.puzzlez.core.ImageValue; import ru.m.puzzlez.proto.game.ImageId; class PixabayImageSource implements ImageSource { - public var id(default, never):String = "pixabay"; + public var id(default, never):String = "pixabay"; - private var api:PixabayApi; - private static var imageUrlsCache:Map = new Map(); + private var api:PixabayApi; - public function new() { - var key:String = CompilationOption.get("PIXABAY_KEY"); - api = new PixabayApi(key); + private static var imageUrlsCache:Map = new Map(); + + public function new() { + var key:String = CompilationOption.get("PIXABAY_KEY"); + api = new PixabayApi(key); + } + + public function getPage(page:Page):Promise> { + return this.api.getPage(page.index + 1, page.count, page.filter.get("category")).then((response:PixabayResponse) -> { + var data:Array = []; + for (hit in response.hits) { + imageUrlsCache.set('${hit.id}', hit.largeImageURL); + data.push(new ImageId().setSource(id).setId(Std.string(hit.id))); + } + return { + page: page, + data: data, + total: response.totalHits, + } + }); + } + + public function load(id:String, thumb:Bool = false):Promise { + var imageId = Std.parseInt(id); + var key = id; + if (thumb) { + key = '${key}:thumb'; } - - public function getPage(page:Page):Promise> { - return this.api.getPage(page.index + 1, page.count, page.filter.get("category")) - .then((response:PixabayResponse) -> { - var data:Array = []; - for (hit in response.hits) { - imageUrlsCache.set('${hit.id}', hit.largeImageURL); - data.push(new ImageId().setSource(id).setId(Std.string(hit.id))); - } - return { - page: page, - data: data, - total: response.totalHits, - } - }); - } - - public function load(id:String, thumb:Bool = false):Promise { - var imageId = Std.parseInt(id); - var key = id; - if (thumb) { - key = '${key}:thumb'; - } - if (imageUrlsCache.exists(key)) { - return Promise.promise(ImageValue.URL(imageUrlsCache.get(key))); - } else { - return api.get(imageId).then((data:PixabayImage) -> { - var url = thumb ? data.previewURL : data.largeImageURL; - imageUrlsCache.set(key, url); - return ImageValue.URL(url); - }); - } + if (imageUrlsCache.exists(key)) { + return Promise.promise(ImageValue.URL(imageUrlsCache.get(key))); + } else { + return api.get(imageId).then((data:PixabayImage) -> { + var url = thumb ? data.previewURL : data.largeImageURL; + imageUrlsCache.set(key, url); + return ImageValue.URL(url); + }); } + } } diff --git a/src/app/haxe/ru/m/puzzlez/source/UnsplashImageSource.hx b/src/app/haxe/ru/m/puzzlez/source/UnsplashImageSource.hx index 9ee0710..3b48203 100644 --- a/src/app/haxe/ru/m/puzzlez/source/UnsplashImageSource.hx +++ b/src/app/haxe/ru/m/puzzlez/source/UnsplashImageSource.hx @@ -7,76 +7,75 @@ import ru.m.puzzlez.core.ImageSource; import ru.m.puzzlez.core.ImageValue; import ru.m.puzzlez.proto.game.ImageId; - -typedef Resolver = (id:String, thumb: Bool) -> Promise; - +typedef Resolver = (id:String, thumb:Bool) -> Promise; class ImageResolver { + private var cache:Map; + private var resolver:Resolver; - private var cache: Map; - private var resolver:Resolver; + public function new(resolver:Resolver) { + this.cache = new Map(); + this.resolver = resolver; + } - public function new(resolver:Resolver) { - this.cache = new Map(); - this.resolver = resolver; + private function buildKey(id:String, thumb:Bool = false):String { + var key = id; + if (thumb) { + key = '${key}:thumb'; } + return key; + } - private function buildKey(id:String, thumb:Bool = false):String { - var key = id; - if (thumb) { - key = '${key}:thumb'; - } - return key; - } + public function setValue(id:String, url:String, thumb:Bool = false):Void { + var key = buildKey(id, thumb); + cache.set(key, url); + } - public function setValue(id:String, url:String):Void { - cache.set(id, url); - } - - public function resolve(id:String, thumb:Bool = false) { - var key = buildKey(id, thumb); - if (cache.exists(key)) { - return Promise.promise(ImageValue.URL(cache.get(key))); - } else { - return resolver(id, thumb).then(url -> { - cache.set(key, url); - return ImageValue.URL(url); - }); - } + public function resolve(id:String, thumb:Bool = false) { + var key = buildKey(id, thumb); + if (cache.exists(key)) { + return Promise.promise(ImageValue.URL(cache.get(key))); + } else { + return resolver(id, thumb).then(url -> { + cache.set(key, url); + return ImageValue.URL(url); + }); } + } } class UnsplashImageSource implements ImageSource { - public var id(default, never):String = "unsplash"; + public var id(default, never):String = "unsplash"; - private var api:UnsplashApi; - private static var resolver:ImageResolver; + private var api:UnsplashApi; - public function new() { - var key:String = CompilationOption.get("UNSPLASH_KEY"); - api = new UnsplashApi(key); - resolver = new ImageResolver((imageId, thumb) -> { - return api.get(imageId).then(data -> thumb ? data.urls.thumb : data.urls.regular); - }); - } + private static var resolver:ImageResolver; - public function getPage(page:Page):Promise> { - return this.api.getPage(page.index + 1, page.count, page.filter.get("category")) - .then((response:UnsplashResponse) -> { - var data:Array = []; - for (image in response.results) { - resolver.setValue(image.id, image.urls.regular); - data.push(new ImageId().setSource(id).setId(image.id)); - } - return { - page: page, - data: data, - total: response.total, - } - }); - } + public function new() { + var key:String = CompilationOption.get("UNSPLASH_KEY"); + api = new UnsplashApi(key); + resolver = new ImageResolver((imageId, thumb) -> { + return api.get(imageId).then(data -> thumb ? data.urls.small : data.urls.regular); + }); + } - public function load(id:String, thumb:Bool = false):Promise { - return resolver.resolve(id, thumb); - } + public function getPage(page:Page):Promise> { + return this.api.getPage(page.index + 1, page.count, page.filter.get("category")).then((response:UnsplashResponse) -> { + var data:Array = []; + for (image in response.results) { + resolver.setValue(image.id, image.urls.small, true); + resolver.setValue(image.id, image.urls.regular); + data.push(new ImageId().setSource(id).setId(image.id)); + } + return { + page: page, + data: data, + total: response.total, + } + }); + } + + public function load(id:String, thumb:Bool = false):Promise { + return resolver.resolve(id, thumb); + } } diff --git a/src/app/haxe/ru/m/puzzlez/storage/FileStorage.hx b/src/app/haxe/ru/m/puzzlez/storage/FileStorage.hx index 42e54eb..ade797d 100644 --- a/src/app/haxe/ru/m/puzzlez/storage/FileStorage.hx +++ b/src/app/haxe/ru/m/puzzlez/storage/FileStorage.hx @@ -4,8 +4,7 @@ import haxe.io.Bytes; import ru.m.storage.SharedObjectDataStorage; @:provide class FileStorage extends SharedObjectDataStorage { - - public function new() { - super("file", new DefaultHelper()); - } + public function new() { + super("file", new DefaultHelper()); + } } diff --git a/src/app/haxe/ru/m/puzzlez/storage/GameStorage.hx b/src/app/haxe/ru/m/puzzlez/storage/GameStorage.hx index 8573753..d3e94d3 100644 --- a/src/app/haxe/ru/m/puzzlez/storage/GameStorage.hx +++ b/src/app/haxe/ru/m/puzzlez/storage/GameStorage.hx @@ -7,42 +7,36 @@ import ru.m.puzzlez.proto.game.ImageId; import ru.m.storage.SharedObjectDataStorage; class GameStorageHelper implements DataHelper { - public function new() { + public function new() {} - } + public function idKey(id:ImageId):String { + return '${id.source}:${id.id}'; + } - public function idKey(id:ImageId):String { - return '${id.source}:${id.id}'; - } + public function keyId(key:String):ImageId { + var keyArray = key.split(":"); + return new ImageId().setSource(keyArray[0]).setId(keyArray[1]); + } - public function keyId(key:String):ImageId { - var keyArray = key.split(":"); - return new ImageId().setSource(keyArray[0]).setId(keyArray[1]); - } + public function dataId(data:GameState):ImageId { + return data.preset.image; + } - public function dataId(data:GameState):ImageId { - return data.preset.image; - } + public function dataBytes(data:GameState):Bytes { + return PacketUtil.toBytes(data); + } - public function dataBytes(data:GameState):Bytes { - return PacketUtil.toBytes(data); - } + public function bytesData(bytes:Bytes):GameState { + return PacketUtil.fromBytes(bytes, GameState); + } - public function bytesData(bytes:Bytes):GameState { - return PacketUtil.fromBytes(bytes, GameState); - } - - public function dataMeta(data:GameState):DataMeta { - return [ - "status" => data.status, - "date" => Date.now(), - ]; - } + public function dataMeta(data:GameState):DataMeta { + return ["status" => data.status, "date" => Date.now(),]; + } } @:provide class GameStorage extends SharedObjectDataStorage { - - public function new() { - super("game", new GameStorageHelper()); - } + public function new() { + super("game", new GameStorageHelper()); + } } diff --git a/src/app/haxe/ru/m/puzzlez/view/GameFrame.hx b/src/app/haxe/ru/m/puzzlez/view/GameFrame.hx index ea6511f..ca81a22 100644 --- a/src/app/haxe/ru/m/puzzlez/view/GameFrame.hx +++ b/src/app/haxe/ru/m/puzzlez/view/GameFrame.hx @@ -17,86 +17,85 @@ import ru.m.puzzlez.view.popup.BackgroundPopup; import ru.m.puzzlez.view.popup.PreviewPopup; @:template class GameFrame extends FrameView { - public static var ID = "game"; + public static var ID = "game"; - @:view private var render:IRender; - private var game:IGame; - @:provide var switcher:FrameSwitcher; - @:provide var storage:GameStorage; - @:provide var settings:Settings; + @:view private var render:IRender; + private var game:IGame; + @:provide var switcher:FrameSwitcher; + @:provide var storage:GameStorage; + @:provide var settings:Settings; - private var saveTimer:Timer; + private var saveTimer:Timer; - public function new() { - super(ID); + public function new() { + super(ID); + } + + override public function onShow(state:GameState):Void { + onHide(); + if (state.online) { + // game = new NetworkGame(state); + } else { + game = new Game(state); } + game.events.connect(render.onGameEvent); + game.events.connect(onGameEvent); + render.actions.connect(game.action); + game.start(); + } - override public function onShow(state:GameState):Void { - onHide(); - if (state.online) { - //game = new NetworkGame(state); - } else { - game = new Game(state); - } - game.events.connect(render.onGameEvent); - game.events.connect(onGameEvent); - render.actions.connect(game.action); - game.start(); + override public function onHide():Void { + if (saveTimer != null) { + save(); } + if (game != null) { + render.actions.disconnect(game.action); + game.stop(); + game.dispose(); + game = null; + } + } - override public function onHide():Void { - if (saveTimer != null) { - save(); - } - if (game != null) { - render.actions.disconnect(game.action); - game.stop(); - game.dispose(); - game = null; - } + private function toSave():Void { + if (saveTimer == null) { + saveTimer = Timer.delay(save, 5000); } + } - private function toSave():Void { - if (saveTimer == null) { - saveTimer = Timer.delay(save, 5000); - } + private function save():Void { + if (saveTimer != null) { + saveTimer.stop(); + saveTimer = null; } + if (game != null) { + storage.save(game.state); + } + } - private function save():Void { - if (saveTimer != null) { - saveTimer.stop(); - saveTimer = null; - } - if (game != null) { - storage.save(game.state); - } + private function onGameEvent(event:GameEvent):Void { + if (event.hasStart() || event.hasAction()) { + toSave(); } + } - private function onGameEvent(event:GameEvent):Void { - if (event.hasStart() || event.hasAction()) { - toSave(); - } - } + private function showPreview():Void { + PreviewPopup.instance.showPreview(game.state); + } - private function showPreview():Void { - PreviewPopup.instance.showPreview(game.state); - } + private function choiseBackground():Void { + BackgroundPopup.instance.choise(settings.background).then(background -> { + if (background != null) { + settings.background = background; + render.toRedraw(); + } + }); + } - private function choiseBackground():Void { - BackgroundPopup.instance.choise(settings.background).then(background -> { - if (background != null) { - settings.background = background; - render.toRedraw(); - } - }); - } - - private function back():Void { - (game.state.status == GameStatus.COMPLETE ? Promise.promise(true) : ConfirmView.confirm("Exit?")) - .then(result -> { - if (result) { - switcher.change(StartFrame.ID); - } - }); - } + private function back():Void { + (game.state.status == GameStatus.COMPLETE ? Promise.promise(true) : ConfirmView.confirm("Exit?")).then(result -> { + if (result) { + switcher.change(StartFrame.ID); + } + }); + } } diff --git a/src/app/haxe/ru/m/puzzlez/view/GameListFrame.hx b/src/app/haxe/ru/m/puzzlez/view/GameListFrame.hx index dddc789..c149abe 100644 --- a/src/app/haxe/ru/m/puzzlez/view/GameListFrame.hx +++ b/src/app/haxe/ru/m/puzzlez/view/GameListFrame.hx @@ -10,37 +10,37 @@ import ru.m.data.DataSource.Filter; import hw.view.frame.FrameView; typedef GameListConfig = { - var title:String; - var source:DataSource; - @:optional var filter:Filter; + var title:String; + var source:DataSource; + @:optional var filter:Filter; } @:template class GameListFrame extends FrameView { - public static var ID(default, never) = "game_list"; + public static var ID(default, never) = "game_list"; - @:view var header:LabelView; - @:view var games:DataList; - @:provide var switcher:FrameSwitcher; + @:view var header:LabelView; + @:view var games:DataList; + @:provide var switcher:FrameSwitcher; - public function new() { - super(ID); + public function new() { + super(ID); + } + + override public function onShow(data:GameListConfig):Void { + games.reset(); + if (data != null) { + header.text = data.title; + games.page.filter = data.filter; + games.source = data.source; + games.refresh(); } + } - override public function onShow(data:GameListConfig):Void { - games.reset(); - if (data != null) { - header.text = data.title; - games.page.filter = data.filter; - games.source = data.source; - games.refresh(); - } - } + public function start(state:GameState):Void { + switcher.change(GameFrame.ID, state); + } - public function start(state:GameState):Void { - switcher.change(GameFrame.ID, state); - } - - private function back():Void { - switcher.change(StartFrame.ID); - } + private function back():Void { + switcher.change(StartFrame.ID); + } } diff --git a/src/app/haxe/ru/m/puzzlez/view/ImageListFrame.hx b/src/app/haxe/ru/m/puzzlez/view/ImageListFrame.hx index 5c703c7..a2f0593 100644 --- a/src/app/haxe/ru/m/puzzlez/view/ImageListFrame.hx +++ b/src/app/haxe/ru/m/puzzlez/view/ImageListFrame.hx @@ -10,38 +10,38 @@ import ru.m.puzzlez.image.ImageSourceBundle; import ru.m.puzzlez.proto.game.ImageId; typedef ImageListConfig = { - var title:String; - var sourceId:String; - @:optional var filter:Filter; + var title:String; + var sourceId:String; + @:optional var filter:Filter; } @:template class ImageListFrame extends FrameView { - public static var ID = "image_list"; + public static var ID = "image_list"; - @:view var header:LabelView; - @:view var images:DataList; - @:provide var switcher:FrameSwitcher; - @:provide var sourceBundle:ImageSourceBundle; + @:view var header:LabelView; + @:view var images:DataList; + @:provide var switcher:FrameSwitcher; + @:provide var sourceBundle:ImageSourceBundle; - public function new() { - super(ID); + public function new() { + super(ID); + } + + override public function onShow(data:ImageListConfig):Void { + images.reset(); + if (data != null) { + header.text = data.title; + images.page.filter = data.filter; + images.source = sourceBundle.get(data.sourceId); + images.refresh(); } + } - override public function onShow(data:ImageListConfig):Void { - images.reset(); - if (data != null) { - header.text = data.title; - images.page.filter = data.filter; - images.source = sourceBundle.get(data.sourceId); - images.refresh(); - } - } + private function start(imageId:ImageId):Void { + switcher.change(PresetFrame.ID, imageId); + } - private function start(imageId:ImageId):Void { - switcher.change(PresetFrame.ID, imageId); - } - - private function back():Void { - switcher.change(StartFrame.ID); - } + private function back():Void { + switcher.change(StartFrame.ID); + } } diff --git a/src/app/haxe/ru/m/puzzlez/view/PresetFrame.hx b/src/app/haxe/ru/m/puzzlez/view/PresetFrame.hx index fb7bbda..5b9c5b8 100644 --- a/src/app/haxe/ru/m/puzzlez/view/PresetFrame.hx +++ b/src/app/haxe/ru/m/puzzlez/view/PresetFrame.hx @@ -10,57 +10,57 @@ import ru.m.puzzlez.proto.game.ImageId; import ru.m.puzzlez.view.common.PresetView; @:template class PresetFrame extends FrameView { - public static var ID = "preset"; + public static var ID = "preset"; - @:view("image") var imageView:PresetView; - @:view("sizes") var sizesView:DataView; + @:view("image") var imageView:PresetView; + @:view("sizes") var sizesView:DataView; - @:provide var switcher:FrameSwitcher; - //@:provide var network:Network; + @:provide var switcher:FrameSwitcher; - private var imageId:ImageId; + // @:provide var network:Network; + private var imageId:ImageId; - public function new() { - super(ID); - 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), - ]; + public function new() { + super(ID); + 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]; } + } - private function factory(index:Int, size:IntPoint):ToggleButtonView { - var result = new ToggleButtonView(); - result.text = '${size.x}x${size.y}'; - return result; - } + override public function onShow(data:ImageId):Void { + super.onShow(data); + imageId = data; + selectSize(sizesView.data[sizesView.data.length - 1]); + } - 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]; - } + private function start(online:Bool = false):Void { + if (online) { + // network.createGame(imageView.state.preset).then(state -> switcher.change(GameFrame.ID, state)); + } else { + switcher.change(GameFrame.ID, imageView.state); } + } - override public function onShow(data:ImageId):Void { - super.onShow(data); - imageId = data; - selectSize(sizesView.data[sizesView.data.length - 1]); - } - - private function start(online:Bool = false):Void { - if (online) { - //network.createGame(imageView.state.preset).then(state -> switcher.change(GameFrame.ID, state)); - } else { - switcher.change(GameFrame.ID, imageView.state); - } - } - - private function back():Void { - switcher.change(ImageListFrame.ID); - } + private function back():Void { + switcher.change(ImageListFrame.ID); + } } diff --git a/src/app/haxe/ru/m/puzzlez/view/PuzzlezAppView.hx b/src/app/haxe/ru/m/puzzlez/view/PuzzlezAppView.hx index aaf7ac0..44c56b2 100644 --- a/src/app/haxe/ru/m/puzzlez/view/PuzzlezAppView.hx +++ b/src/app/haxe/ru/m/puzzlez/view/PuzzlezAppView.hx @@ -9,28 +9,27 @@ import hw.view.frame.FrameSwitcher; import hw.view.group.VGroupView; @:template class PuzzlezAppView extends VGroupView { + @:view("switcher") var switcherView:FrameSwitcher; + @:view("fullscreen") var fullscreenButton:ButtonView; + @:view("user") var userLabel:LabelView; - @:view("switcher") var switcherView:FrameSwitcher; - @:view("fullscreen") var fullscreenButton:ButtonView; - @:view("user") var userLabel:LabelView; + @:provide static var switcher:FrameSwitcher; + @:provide static var app:App; - @:provide static var switcher:FrameSwitcher; - @:provide static var app:App; - - public function new() { - super(); - fullscreenButton.visible = app.fullScreenSupport; - app.fullScreenSignal.connect(fs -> fullscreenButton.style = 'icon.${fs ? "compress" : "expand"}'); - switcher = switcherView; - switcher.change(StartFrame.ID); - stage.addEventListener(KeyboardEvent.KEY_DOWN, (event:KeyboardEvent) -> { - switch event.keyCode { - case Keyboard.ESCAPE: - //switcher.change(StartFrame.ID); - case Keyboard.F: - app.fullScreen = !app.fullScreen; - case _: - } - }); - } + public function new() { + super(); + fullscreenButton.visible = app.fullScreenSupport; + app.fullScreenSignal.connect(fs -> fullscreenButton.style = 'icon.${fs ? "compress" : "expand"}'); + switcher = switcherView; + switcher.change(StartFrame.ID); + stage.addEventListener(KeyboardEvent.KEY_DOWN, (event:KeyboardEvent) -> { + switch event.keyCode { + case Keyboard.ESCAPE: + // switcher.change(StartFrame.ID); + case Keyboard.F: + app.fullScreen = !app.fullScreen; + case _: + } + }); + } } diff --git a/src/app/haxe/ru/m/puzzlez/view/StartFrame.hx b/src/app/haxe/ru/m/puzzlez/view/StartFrame.hx index 4285186..5346ca9 100644 --- a/src/app/haxe/ru/m/puzzlez/view/StartFrame.hx +++ b/src/app/haxe/ru/m/puzzlez/view/StartFrame.hx @@ -4,79 +4,79 @@ import hw.view.data.DataView; import hw.view.form.ButtonView; import hw.view.frame.FrameSwitcher; import hw.view.frame.FrameView; -import ru.m.pixabay.PixabayApi; +import ru.m.api.PixabayApi; import ru.m.puzzlez.FileUtil; import ru.m.puzzlez.proto.game.GameStatus; import ru.m.puzzlez.storage.FileStorage; import ru.m.puzzlez.storage.GameStorage; -import ru.m.puzzlez.view.ImageListFrame; import ru.m.puzzlez.view.GameListFrame; +import ru.m.puzzlez.view.ImageListFrame; import ru.m.update.Updater; @:template class StartFrame extends FrameView { - public static var ID = "start"; + public static var ID = "start"; - @:view var sources:DataView; - @:view var startedButton:ButtonView; - @:view var completedButton:ButtonView; - @:view var updateButton:ButtonView; + @:view var sources:DataView; + @:view var startedButton:ButtonView; + @:view var completedButton:ButtonView; + @:view var updateButton:ButtonView; - @:provide var switcher:FrameSwitcher; - @:provide static var appUpdater:Updater; - @:provide var fileStorage:FileStorage; - @:provide var gameStorage:GameStorage; + @:provide var switcher:FrameSwitcher; - private var fileSource:ImageListConfig = {title: "Files", sourceId: "file"}; - private var startedGames:GameListConfig = {title: "Started", source: gameStorage, filter: ["status" => GameStatus.STARTED]}; - private var completedGames:GameListConfig = {title: "Completed", source: gameStorage, filter: ["status" => GameStatus.COMPLETE]}; + @:provide static var appUpdater:Updater; - public function new() { - super(ID); - var data:Array = []; - // data.push({title: "Assets", sourceId: "asset"}); - data.push(fileSource); - for (type in AbstractEnumTools.getValues(PixabayCategory)) { - data.push({title: type, sourceId: "unsplash", filter: ["category" => type]}); - } - sources.data = data; + @:provide var fileStorage:FileStorage; + @:provide var gameStorage:GameStorage; + + private var fileSource:ImageListConfig = {title: "Files", sourceId: "file"}; + private var startedGames:GameListConfig = {title: "Started", source: gameStorage, filter: ["status" => GameStatus.STARTED]}; + private var completedGames:GameListConfig = {title: "Completed", source: gameStorage, filter: ["status" => GameStatus.COMPLETE]}; + + public function new() { + super(ID); + var data:Array = []; + // data.push({title: "Assets", sourceId: "asset"}); + data.push(fileSource); + for (type in AbstractEnumTools.getValues(PixabayCategory)) { + data.push({title: type, sourceId: "unsplash", filter: ["category" => type]}); } + sources.data = data; + } - private function sourceViewFactory(index:Int, source:ImageListConfig):ButtonView { - var result = new ButtonView(); - result.text = source.title; - return result; - } + private function sourceViewFactory(index:Int, source:ImageListConfig):ButtonView { + var result = new ButtonView(); + result.text = source.title; + return result; + } - public function upload():Void { - FileUtil.browse() - .pipe((data:FileContent) -> fileStorage.save(data.content)) - .then(_ -> showSource(fileSource)); - } + public function upload():Void { + FileUtil.browse().pipe((data:FileContent) -> fileStorage.save(data.content)).then(_ -> showSource(fileSource)); + } - public function showSource(config:ImageListConfig):Void { - switcher.change(ImageListFrame.ID, config); - } + public function showSource(config:ImageListConfig):Void { + switcher.change(ImageListFrame.ID, config); + } - public function showGames(config:GameListConfig):Void { - switcher.change(GameListFrame.ID, config); - } + public function showGames(config:GameListConfig):Void { + switcher.change(GameListFrame.ID, config); + } - override public function onShow(data:Dynamic):Void { - appUpdater.check().then((info:Null) -> { - if (info != null) { - updateButton.visible = true; - updateButton.text = 'Update ${info.version}'; - } - }).catchError(error -> L.w('Update', 'failed: ${error}')); - refresh(); - } + override public function onShow(data:Dynamic):Void { + appUpdater.check().then((info:Null) -> { + if (info != null) { + updateButton.visible = true; + updateButton.text = 'Update ${info.version}'; + } + }).catchError(error -> L.w('Update', 'failed: ${error}')); + refresh(); + } - private function refresh():Void { - gameStorage.getIndexPage({index:0, count:0, filter:startedGames.filter}).then(response -> { - startedButton.text = response.total > 0 ? 'Started (${response.total})' : 'Started'; - }); - gameStorage.getIndexPage({index:0, count:0, filter:completedGames.filter}).then(response -> { - completedButton.text = response.total > 0 ? 'Completed (${response.total})' : 'Completed'; - }); - } + private function refresh():Void { + gameStorage.getIndexPage({index: 0, count: 0, filter: startedGames.filter}).then(response -> { + startedButton.text = response.total > 0 ? 'Started (${response.total})' : 'Started'; + }); + gameStorage.getIndexPage({index: 0, count: 0, filter: completedGames.filter}).then(response -> { + completedButton.text = response.total > 0 ? 'Completed (${response.total})' : 'Completed'; + }); + } } diff --git a/src/app/haxe/ru/m/puzzlez/view/common/GameStateView.hx b/src/app/haxe/ru/m/puzzlez/view/common/GameStateView.hx index 78eccb7..3955f6a 100644 --- a/src/app/haxe/ru/m/puzzlez/view/common/GameStateView.hx +++ b/src/app/haxe/ru/m/puzzlez/view/common/GameStateView.hx @@ -7,28 +7,28 @@ import ru.m.puzzlez.image.GameUtil; import ru.m.puzzlez.proto.game.GameState; @:template class GameStateView extends GroupView { - public var state(default, set):GameState; + public var state(default, set):GameState; - private function set_state(value:GameState):GameState { - state = value; - image.imageId = state.preset.image; - var progress = GameUtil.calcProgress(state); - label.text = '${progress.complete}/${progress.total}'; - return state; + private function set_state(value:GameState):GameState { + state = value; + image.imageId = state.preset.image; + var progress = GameUtil.calcProgress(state); + label.text = '${progress.complete}/${progress.total}'; + return state; + } + + @:view var image:ImageIdView; + @:view var label:LabelView; + + public function new(?state:GameState, ?style:StyleId) { + super(); + this.style = style; + if (state != null) { + this.state = state; } + } - @:view var image:ImageIdView; - @:view var label:LabelView; - - public function new(?state:GameState, ?style: StyleId) { - super(); - this.style = style; - if (state != null) { - this.state = state; - } - } - - public static function factory(index:Int, value:GameState):GameStateView { - return new GameStateView(value, "view"); - } + public static function factory(index:Int, value:GameState):GameStateView { + return new GameStateView(value, "view"); + } } diff --git a/src/app/haxe/ru/m/puzzlez/view/common/ImageIdView.hx b/src/app/haxe/ru/m/puzzlez/view/common/ImageIdView.hx index 44424e6..3a21b0e 100644 --- a/src/app/haxe/ru/m/puzzlez/view/common/ImageIdView.hx +++ b/src/app/haxe/ru/m/puzzlez/view/common/ImageIdView.hx @@ -8,41 +8,38 @@ import ru.m.puzzlez.proto.game.ImageId; import ru.m.view.LoadingWrapper; @:template class ImageIdView extends GroupView { + public var thumb:Bool = false; - public var thumb:Bool = false; + public var imageId(default, set):ImageId; - public var imageId(default, set):ImageId; - private function set_imageId(value:ImageId):ImageId { - imageId = value; - var imageData = ImageData - .fromImageId(imageId); - if (thumb) { - imageData = imageData.withThumb(); - } - loading.promise = imageData - .resolve() - .then(data -> this.imageView.image = data); - return imageId; + private function set_imageId(value:ImageId):ImageId { + imageId = value; + var imageData = ImageData.fromImageId(imageId); + if (thumb) { + imageData = imageData.withThumb(); } + loading.promise = imageData.resolve().then(data -> this.imageView.image = data); + return imageId; + } - @:view("image") var imageView:ImageView; - private var loading:LoadingWrapper; + @:view("image") var imageView:ImageView; + private var loading:LoadingWrapper; - public function new(?imageId:ImageId, ?style: StyleId, ?thumb: Bool = false) { - super(); - this.style = style; - this.thumb = thumb; - loading = new LoadingWrapper(this); - if (imageId != null) { - this.imageId = imageId; - } + public function new(?imageId:ImageId, ?style:StyleId, ?thumb:Bool = false) { + super(); + this.style = style; + this.thumb = thumb; + loading = new LoadingWrapper(this); + if (imageId != null) { + this.imageId = imageId; } + } - public static function factory(index:Int, value:ImageId):ImageIdView { - return new ImageIdView(value, "view"); - } + public static function factory(index:Int, value:ImageId):ImageIdView { + return new ImageIdView(value, "view"); + } - public static function factoryThumb(index:Int, value:ImageId):ImageIdView { - return new ImageIdView(value, "view", true); - } + public static function factoryThumb(index:Int, value:ImageId):ImageIdView { + return new ImageIdView(value, "view", true); + } } diff --git a/src/app/haxe/ru/m/puzzlez/view/common/PresetView.hx b/src/app/haxe/ru/m/puzzlez/view/common/PresetView.hx index f8de7e9..43b41a7 100644 --- a/src/app/haxe/ru/m/puzzlez/view/common/PresetView.hx +++ b/src/app/haxe/ru/m/puzzlez/view/common/PresetView.hx @@ -12,77 +12,77 @@ import ru.m.puzzlez.render.RenderUtil; import ru.m.puzzlez.wrap.RectangleExt; class PresetView extends GroupView { - @:provide static var builder:IPartBuilder; + @:provide static var builder:IPartBuilder; - public var scale(get, set):Float; + public var scale(get, set):Float; - private function get_scale():Float { - return table.scaleX; + private function get_scale():Float { + return table.scaleX; + } + + private function set_scale(value:Float):Float { + var result = table.scaleX = table.scaleY = value; + table.x = (width - state.preset.imageRect.width * value) / 2; + table.y = (height - state.preset.imageRect.height * value) / 2; + return result; + } + + public var state(default, set):GameState; + + private function set_state(value:GameState):GameState { + state = value; + this.image = null; + table.graphics.clear(); + loading.promise = ImageData.fromImageId(state.preset.image).resolve().then(image -> { + this.image = RenderUtil.cropImage(image, state.preset.imageRect); + toRedraw(); + toUpdate(); + }); + return state; + } + + private var loading:LoadingWrapper; + + public function new() { + super(); + table = new Shape(); + content.addChild(table); + loading = new LoadingWrapper(this); + } + + private var table:Shape; + private var image:BitmapData; + + override public function redraw():Void { + if (state == null || image == null) { + return; } + var preset = state.preset; + var partWidth = preset.imageRect.width / preset.grid.x; + var partHeight = preset.imageRect.height / preset.grid.y; + var graphics:Graphics = table.graphics; + graphics.clear(); + graphics.beginBitmapFill(image, null, false, true); + graphics.drawRect(0, 0, preset.imageRect.width, preset.imageRect.height); + graphics.endFill(); - private function set_scale(value:Float):Float { - var result = table.scaleX = table.scaleY = value; - table.x = (width - state.preset.imageRect.width * value) / 2; - table.y = (height - state.preset.imageRect.height * value) / 2; - return result; + for (part in state.parts) { + var rect = cast(part.rect, RectangleExt).clone(); + rect.x = part.point.x * part.rect.width; + rect.y = part.point.y * part.rect.height; + var path = 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(); + } } + } - public var state(default, set):GameState; - - private function set_state(value:GameState):GameState { - state = value; - this.image = null; - table.graphics.clear(); - loading.promise = ImageData.fromImageId(state.preset.image).resolve().then(image -> { - this.image = RenderUtil.cropImage(image, state.preset.imageRect); - toRedraw(); - toUpdate(); - }); - return state; - } - - private var loading:LoadingWrapper; - - public function new() { - super(); - table = new Shape(); - content.addChild(table); - loading = new LoadingWrapper(this); - } - - private var table:Shape; - private var image:BitmapData; - - override public function redraw():Void { - if (state == null || image == null) { - return; - } - var preset = state.preset; - var partWidth = preset.imageRect.width / preset.grid.x; - var partHeight = preset.imageRect.height / preset.grid.y; - var graphics:Graphics = table.graphics; - graphics.clear(); - graphics.beginBitmapFill(image, null, false, true); - graphics.drawRect(0, 0, preset.imageRect.width, preset.imageRect.height); - graphics.endFill(); - - for (part in state.parts) { - var rect = cast(part.rect, RectangleExt).clone(); - rect.x = part.point.x * part.rect.width; - rect.y = part.point.y * part.rect.height; - var path = 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(); - } - } - } - - override public function update():Void { - super.update(); - if (state != null) { - scale = Math.min(width / state.preset.imageRect.width, height / state.preset.imageRect.height); - } + override public function update():Void { + super.update(); + if (state != null) { + scale = Math.min(width / state.preset.imageRect.width, height / state.preset.imageRect.height); } + } } diff --git a/src/app/haxe/ru/m/puzzlez/view/popup/BackgroundPopup.hx b/src/app/haxe/ru/m/puzzlez/view/popup/BackgroundPopup.hx index c545e2c..48d5b1c 100644 --- a/src/app/haxe/ru/m/puzzlez/view/popup/BackgroundPopup.hx +++ b/src/app/haxe/ru/m/puzzlez/view/popup/BackgroundPopup.hx @@ -15,82 +15,66 @@ import ru.m.puzzlez.proto.game.ImageId; import ru.m.puzzlez.render.Background; @:singleton @:template class BackgroundPopup extends PopupView { + private static var colorsList:Array = [ + '#FFFFFF', '#001f3f', '#0074D9', '#7FDBFF', '#39CCCC', '#3D9970', '#2ECC40', '#01FF70', '#FFDC00', '#FF851B', '#FF4136', '#85144b', '#F012BE', '#B10DC9', + '#111111', '#AAAAAA', '#DDDDDD', + ]; - private static var colorsList:Array = [ - '#FFFFFF', - '#001f3f', - '#0074D9', - '#7FDBFF', - '#39CCCC', - '#3D9970', - '#2ECC40', - '#01FF70', - '#FFDC00', - '#FF851B', - '#FF4136', - '#85144b', - '#F012BE', - '#B10DC9', - '#111111', - '#AAAAAA', - '#DDDDDD', - ]; + @:view("selected") var selectedView:SpriteView; + @:view("colors") var colorsView:DataView; + @:view("textures") var texturesView:DataView; - @:view("selected") var selectedView:SpriteView; - @:view("colors") var colorsView:DataView; - @:view("textures") var texturesView:DataView; + public var selected(default, set):Background; - public var selected(default, set):Background; + // @:provide static var imageStorage:ImageStorage; - // @:provide static var imageStorage:ImageStorage; - - public function new() { - super(); - colorsView.data = colorsList; - var textures = []; - for (name in Assets.list(AssetType.IMAGE)) { - if (StringTools.startsWith(name, 'resources/texture')) { - textures.push(new ImageId().setSource('asset').setId(name)); - } - } - texturesView.data = textures; + public function new() { + super(); + colorsView.data = colorsList; + var textures = []; + for (name in Assets.list(AssetType.IMAGE)) { + if (StringTools.startsWith(name, 'resources/texture')) { + textures.push(new ImageId().setSource('asset').setId(name)); + } } + texturesView.data = textures; + } - private function set_selected(value:Background):Background { - selected = value; - switch selected { - case NONE: - selectedView.skin = null; - case COLOR(color): - selectedView.skin = Skin.color(color); - case IMAGE(id): - ImageData.fromImageId(id).resolve().then(result -> { - selectedView.skin = Skin.bitmap(result, REPEAT); - selectedView.toRedraw(); - }); - } - selectedView.toRedraw(); - return selected; + private function set_selected(value:Background):Background { + selected = value; + switch selected { + case NONE: + selectedView.skin = null; + case COLOR(color): + selectedView.skin = Skin.color(color); + case IMAGE(id): + ImageData.fromImageId(id).resolve().then(result -> { + selectedView.skin = Skin.bitmap(result, REPEAT); + selectedView.toRedraw(); + }); } + selectedView.toRedraw(); + return selected; + } - private function colorButtonFactory(index:Int, color:Color):ButtonView { - var result = new ButtonView(); - result.style = "button.background"; - result.text = " "; - result.skin = Skin.buttonColor(color); - return result; - } + private function colorButtonFactory(index:Int, color:Color):ButtonView { + var result = new ButtonView(); + result.style = "button.background"; + result.text = " "; + result.skin = Skin.buttonColor(color); + return result; + } - private function textureButtonFactory(index:Int, imageId:ImageId):ButtonView { - var result = new ButtonView(); - result.style = "button.background"; - result.text = " "; - result.skin = Skin.buttonBitmap(Assets.getBitmapData(imageId.id), REPEAT); - return result; - } + private function textureButtonFactory(index:Int, imageId:ImageId):ButtonView { + var result = new ButtonView(); + result.style = "button.background"; + result.text = " "; + result.skin = Skin.buttonBitmap(Assets.getBitmapData(imageId.id), REPEAT); + return result; + } - public function choise(current:Background):Promise { - selected = current; - return show(); - } + public function choise(current:Background):Promise { + selected = current; + return show(); + } } diff --git a/src/app/haxe/ru/m/puzzlez/view/popup/PreviewPopup.hx b/src/app/haxe/ru/m/puzzlez/view/popup/PreviewPopup.hx index dccd948..522f073 100644 --- a/src/app/haxe/ru/m/puzzlez/view/popup/PreviewPopup.hx +++ b/src/app/haxe/ru/m/puzzlez/view/popup/PreviewPopup.hx @@ -7,16 +7,15 @@ import promhx.Promise; import ru.m.puzzlez.view.common.PresetView; @:singleton @:template class PreviewPopup extends PopupView { + @:view("preview") var previewView:PresetView; - @:view("preview") var previewView:PresetView; + public function new() { + super(); + content.addEventListener(MouseEvent.CLICK, _ -> close(null)); + } - public function new() { - super(); - content.addEventListener(MouseEvent.CLICK, _ -> close(null)); - } - - public function showPreview(state:GameState):Promise { - previewView.state = state; - return show(); - } + public function showPreview(state:GameState):Promise { + previewView.state = state; + return show(); + } } diff --git a/src/app/haxe/ru/m/skin/ButtonSVGSkin.hx b/src/app/haxe/ru/m/skin/ButtonSVGSkin.hx index 5835751..09c1386 100644 --- a/src/app/haxe/ru/m/skin/ButtonSVGSkin.hx +++ b/src/app/haxe/ru/m/skin/ButtonSVGSkin.hx @@ -10,59 +10,58 @@ using StringTools; using hw.color.ColorUtil; @:style class ButtonSVGSkin implements ISkin { + @:style(null) public var svg:String; + @:style(0) public var color:Null; + @:style(false) public var solid:Null; - @:style(null) public var svg:String; - @:style(0) public var color:Null; - @:style(false) public var solid:Null; + private var svgs:Map; + private var needUpdate:Bool; - private var svgs:Map; - private var needUpdate:Bool; + public function new(?svg:String, ?color:Color, ?solid:Bool) { + this.svg = svg; + this.color = color; + this.solid = solid; + this.needUpdate = true; + } - public function new(?svg:String, ?color:Color, ?solid:Bool) { - this.svg = svg; - this.color = color; - this.solid = solid; - this.needUpdate = true; + private inline function buildSVG(color:Color):SVG { + return new SVG(svg.replace("currentColor", '#${color}')); + } + + private function update():Void { + if (needUpdate && svg != null) { + var color = color; + if (solid) { + color = color.multiply(1.5); + } + svgs = new Map(); + svgs.set(UP, buildSVG(color)); + svgs.set(DOWN, buildSVG(color.diff(-24))); + svgs.set(OVER, buildSVG(color.diff(24))); + svgs.set(DISABLED, buildSVG(color.grey())); + needUpdate = false; } + } - private inline function buildSVG(color:Color):SVG { - return new SVG(svg.replace("currentColor", '#${color}')); + public function draw(view:ButtonView):Void { + update(); + var svg = svgs.get(view.state); + var graphics = view.content.graphics; + var color = this.color; + if (Std.is(view, ToggleButtonView)) { + if (!cast(view, ToggleButtonView).on) { + color = color.multiply(0.5); + } } - - private function update():Void { - if (needUpdate && svg != null) { - var color = color; - if (solid) { - color = color.multiply(1.5); - } - svgs = new Map(); - svgs.set(UP, buildSVG(color)); - svgs.set(DOWN, buildSVG(color.diff(-24))); - svgs.set(OVER, buildSVG(color.diff(24))); - svgs.set(DISABLED, buildSVG(color.grey())); - needUpdate = false; - } - } - - public function draw(view:ButtonView):Void { - update(); - var svg = svgs.get(view.state); - var graphics = view.content.graphics; - var color = this.color; - if (Std.is(view, ToggleButtonView)) { - if (!cast(view, ToggleButtonView).on) { - color = color.multiply(0.5); - } - } - graphics.beginFill(0, 0); - graphics.drawRect(0, 0, view.width, view.height); - graphics.beginFill(color); - if (!solid) { - graphics.lineStyle(2, color.multiply(1.5)); - } - // ToDo: padding - svg.render(graphics, 0, 0, Std.int(view.width * 0.8), Std.int(view.height * 0.8)); - graphics.lineStyle(); - graphics.endFill(); + graphics.beginFill(0, 0); + graphics.drawRect(0, 0, view.width, view.height); + graphics.beginFill(color); + if (!solid) { + graphics.lineStyle(2, color.multiply(1.5)); } + // ToDo: padding + svg.render(graphics, 0, 0, Std.int(view.width * 0.8), Std.int(view.height * 0.8)); + graphics.lineStyle(); + graphics.endFill(); + } } diff --git a/src/app/haxe/ru/m/storage/SharedObjectDataStorage.hx b/src/app/haxe/ru/m/storage/SharedObjectDataStorage.hx index e94b1b8..af28af6 100644 --- a/src/app/haxe/ru/m/storage/SharedObjectDataStorage.hx +++ b/src/app/haxe/ru/m/storage/SharedObjectDataStorage.hx @@ -11,167 +11,165 @@ import ru.m.data.DataSource; typedef DataMeta = Map; typedef IdMeta = { - var id:I; - var meta:DataMeta; + var id:I; + var meta:DataMeta; } interface DataHelper { - public function idKey(id:I):String; + public function idKey(id:I):String; - public function keyId(key:String):I; + public function keyId(key:String):I; - public function dataId(data:D):I; + public function dataId(data:D):I; - public function dataBytes(data:D):Bytes; + public function dataBytes(data:D):Bytes; - public function bytesData(bytes:Bytes):D; + public function bytesData(bytes:Bytes):D; - public function dataMeta(data:D):DataMeta; + public function dataMeta(data:D):DataMeta; } class DefaultHelper implements DataHelper { - public function new() { + public function new() {} - } + public function idKey(id:String):String { + return id; + } - public function idKey(id:String):String { - return id; - } + public function keyId(key:String):String { + return key; + } - public function keyId(key:String):String { - return key; - } + public function dataId(data:Bytes):String { + return Md5.make(data).toHex(); + } - public function dataId(data:Bytes):String { - return Md5.make(data).toHex(); - } + public function dataBytes(data:Bytes):Bytes { + return data; + } - public function dataBytes(data:Bytes):Bytes { - return data; - } + public function bytesData(bytes:Bytes):Bytes { + return bytes; + } - public function bytesData(bytes:Bytes):Bytes { - return bytes; - } - - public function dataMeta(data:Bytes):DataMeta { - return ["date" => Date.now()]; - } + public function dataMeta(data:Bytes):DataMeta { + return ["date" => Date.now()]; + } } class SharedObjectDataStorage implements DataStorage { - private static var DATA_KEY:String = "data"; + private static var DATA_KEY:String = "data"; - public var name(default, null):String; - public var version(default, null):Int; + public var name(default, null):String; + public var version(default, null):Int; - private var helper:DataHelper; + private var helper:DataHelper; - private var _indexObject:SharedObject; - private var indexObject(get, null):SharedObject; + private var _indexObject:SharedObject; + private var indexObject(get, null):SharedObject; - private function get_indexObject():SharedObject { - if (_indexObject == null) { - _indexObject = SharedObject.getLocal('${name}/${version}/index'); + private function get_indexObject():SharedObject { + if (_indexObject == null) { + _indexObject = SharedObject.getLocal('${name}/${version}/index'); + } + return _indexObject; + } + + public function new(name:String, helper:DataHelper, version:Int = 1) { + this.name = name; + this.version = version; + this.helper = helper; + } + + private function resolveDataObject(id:I):SharedObject { + var idKey = helper.idKey(id); + return SharedObject.getLocal('${name}/${version}/${Md5.encode(idKey)}'); + } + + private function applyFilter(filter:Null, meta:DataMeta):Bool { + if (filter != null) { + for (k in filter.keys()) { + if (meta.exists(k) && meta.get(k) != filter.get(k)) { + return false; } - return _indexObject; + } } + return true; + } - public function new(name:String, helper:DataHelper, version:Int = 1) { - this.name = name; - this.version = version; - this.helper = helper; - } - - private function resolveDataObject(id:I):SharedObject { - var idKey = helper.idKey(id); - return SharedObject.getLocal('${name}/${version}/${Md5.encode(idKey)}'); - } - - private function applyFilter(filter:Null, meta:DataMeta):Bool { - if (filter != null) { - for (k in filter.keys()) { - if (meta.exists(k) && meta.get(k) != filter.get(k)) { - return false; - } - } + private function applyOrder(order:Order, values:Array>):Void { + if (order != null) { + values.sort((a:IdMeta, b:IdMeta) -> { + for (item in order) { + var av = a.meta.get(item.field); + var bv = b.meta.get(item.field); + if (av > bv) { + return item.reverse ? -1 : 1; + } else if (av < bv) { + return item.reverse ? 1 : -1; + } } - return true; + return 0; + }); } + } - private function applyOrder(order:Order, values:Array>):Void { - if (order != null) { - values.sort((a:IdMeta, b:IdMeta) -> { - for (item in order) { - var av = a.meta.get(item.field); - var bv = b.meta.get(item.field); - if (av > bv) { - return item.reverse ? -1 : 1; - } else if (av < bv) { - return item.reverse ? 1 : -1; - } - } - return 0; - }); + public function getIndexPage(page:Page):Promise> { + var data = indexObject.data; + var values:Array> = []; + for (k in Reflect.fields(data)) { + var meta = Unserializer.run(Reflect.field(data, k)); + if (applyFilter(page.filter, meta)) { + values.push({id: helper.keyId(k), meta: meta}); + } + } + applyOrder(page.order, values); + var result:Array = values.slice(page.index * page.count, page.index * page.count + page.count).map(value -> value.id); + return Promise.promise({ + page: page, + total: values.length, + data: result, + }); + } + + public function getPage(page:Page):Promise> { + return getIndexPage(page).pipe((indexPage:DataPage) -> { + return Promise.whenAll([for (id in indexPage.data) get(id)]).then((data:Array) -> { + return { + page: indexPage.page, + total: indexPage.total, + data: data, } - } + }); + }); + } - public function getIndexPage(page:Page):Promise> { - var data = indexObject.data; - var values:Array> = []; - for (k in Reflect.fields(data)) { - var meta = Unserializer.run(Reflect.field(data, k)); - if (applyFilter(page.filter, meta)) { - values.push({id: helper.keyId(k), meta: meta}); - } - } - applyOrder(page.order, values); - var result:Array = values.slice(page.index * page.count, page.index * page.count + page.count).map(value -> value.id); - return Promise.promise({ - page: page, - total: values.length, - data: result, - }); + public function get(id:I):Promise { + var dataObject = resolveDataObject(id); + if (Reflect.hasField(dataObject.data, DATA_KEY)) { + return Promise.promise(helper.bytesData(Bytes.ofHex(Reflect.field(dataObject.data, DATA_KEY)))); } + return Promise.promise(null); + } - public function getPage(page:Page):Promise> { - return getIndexPage(page).pipe((indexPage:DataPage) -> { - return Promise.whenAll([for (id in indexPage.data) get(id)]).then((data:Array) -> { - return { - page: indexPage.page, - total: indexPage.total, - data: data, - } - }); - }); - } + public function save(item:D):Promise { + var id = helper.dataId(item); + var dataObject = resolveDataObject(id); + dataObject.setProperty(DATA_KEY, helper.dataBytes(item).toHex()); + dataObject.flush(); + indexObject.setProperty(helper.idKey(id), Serializer.run(helper.dataMeta(item))); + indexObject.flush(); + return Promise.promise(item); + } - public function get(id:I):Promise { - var dataObject = resolveDataObject(id); - if (Reflect.hasField(dataObject.data, DATA_KEY)) { - return Promise.promise(helper.bytesData(Bytes.ofHex(Reflect.field(dataObject.data, DATA_KEY)))); - } - return Promise.promise(null); - } - - public function save(item:D):Promise { - var id = helper.dataId(item); - var dataObject = resolveDataObject(id); - dataObject.setProperty(DATA_KEY, helper.dataBytes(item).toHex()); - dataObject.flush(); - indexObject.setProperty(helper.idKey(id), Serializer.run(helper.dataMeta(item))); - indexObject.flush(); - return Promise.promise(item); - } - - public function delete(id:I):Promise { - var dataObject = resolveDataObject(id); - if (Reflect.hasField(dataObject.data, DATA_KEY)) { - dataObject.clear(); - Reflect.deleteField(indexObject.data, helper.idKey(id)); - indexObject.flush(); - return Promise.promise(true); - } - return Promise.promise(false); + public function delete(id:I):Promise { + var dataObject = resolveDataObject(id); + if (Reflect.hasField(dataObject.data, DATA_KEY)) { + dataObject.clear(); + Reflect.deleteField(indexObject.data, helper.idKey(id)); + indexObject.flush(); + return Promise.promise(true); } + return Promise.promise(false); + } } diff --git a/src/app/haxe/ru/m/update/Updater.hx b/src/app/haxe/ru/m/update/Updater.hx index 7295b5a..e238983 100644 --- a/src/app/haxe/ru/m/update/Updater.hx +++ b/src/app/haxe/ru/m/update/Updater.hx @@ -8,76 +8,72 @@ 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"; + 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; + 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; + var name:String; + var version:String; + var packages:Array; } class Updater { + private static inline var TAG = "Update"; - private static inline var TAG = "Update"; + public var type(get, null):PackageType; + public var bundle(get, null):Promise; - public var type(get, null):PackageType; - public var bundle(get, null):Promise; + private function get_bundle():Promise { + if (bundle == null) { + bundle = new JsonLoader().GET(url); + } + return bundle; + } - private function get_bundle():Promise { - if (bundle == null) { - bundle = new JsonLoader().GET(url); + private var url:String; + private var version:Version; + + public function new(version:Version, 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> { + 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 { + 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 bundle; - } - - private var url:String; - private var version:Version; - - public function new(version:Version, 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> { - 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 { - 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; - }); - } + } + return false; + }); + } } diff --git a/src/app/haxe/ru/m/update/Version.hx b/src/app/haxe/ru/m/update/Version.hx index 49af272..6ca4fc9 100644 --- a/src/app/haxe/ru/m/update/Version.hx +++ b/src/app/haxe/ru/m/update/Version.hx @@ -1,52 +1,45 @@ package ru.m.update; abstract Version(Array) { + public function new(mayor:Int, minor:Int, patch:Int, snapshot:Bool = false) { + this = [mayor, minor, patch, snapshot ? -1 : 0,]; + } - 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; } - - @: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; + 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 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 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; + @: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); - } + @: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" : ""}'; - } + @:to public function toString():String { + return '${this[0]}.${this[1]}.${this[2]}${this[3] < 0 ? "-SNAPSHOT" : ""}'; + } } diff --git a/src/app/haxe/ru/m/view/DataList.hx b/src/app/haxe/ru/m/view/DataList.hx index 6e1fb9e..257ffc9 100644 --- a/src/app/haxe/ru/m/view/DataList.hx +++ b/src/app/haxe/ru/m/view/DataList.hx @@ -7,39 +7,39 @@ import ru.m.data.DataSource; import ru.m.view.LoadingWrapper; @:template class DataList> extends VGroupView { + public var source:DataSource; + public var page:Page; - public var source:DataSource; - public var page:Page; + @:view public var list(default, null):DataView; - @:view public var list(default, null):DataView; - @:view private var paginator:PaginatorView; - private var loading:LoadingWrapper; + @:view private var paginator:PaginatorView; + private var loading:LoadingWrapper; - public var data(default, set):DataPage; + public var data(default, set):DataPage; - private function set_data(value:DataPage):DataPage { - data = value; - list.data = data.data; - paginator.page = data; - return data; - } + private function set_data(value:DataPage):DataPage { + data = value; + list.data = data.data; + paginator.page = data; + return data; + } - public function new() { - super(); - loading = new LoadingWrapper(list); - page = {index: 0, count: 6, order: [{field: "date", reverse: true}]}; - } + public function new() { + super(); + loading = new LoadingWrapper(list); + page = {index: 0, count: 6, order: [{field: "date", reverse: true}]}; + } - public function refresh():Void { - loading.promise = source.getPage(page).then(data -> this.data = data); - } + public function refresh():Void { + loading.promise = source.getPage(page).then(data -> this.data = data); + } - public function reset():Void { - page.index = 0; - data = { - page: page, - total: 0, - data: [], - }; - } + public function reset():Void { + page.index = 0; + data = { + page: page, + total: 0, + data: [], + }; + } } diff --git a/src/app/haxe/ru/m/view/LoadingWrapper.hx b/src/app/haxe/ru/m/view/LoadingWrapper.hx index eeb1e5a..f48b455 100644 --- a/src/app/haxe/ru/m/view/LoadingWrapper.hx +++ b/src/app/haxe/ru/m/view/LoadingWrapper.hx @@ -10,98 +10,96 @@ import hw.view.text.TextView; import promhx.Promise; enum State { - NONE; - LOADING; - ERROR(error:Dynamic); + NONE; + LOADING; + ERROR(error:Dynamic); } class LoadingWrapper { - public var promise(null, set):Promise; + public var promise(null, set):Promise; - private function set_promise(value:Promise):Promise { - state = LOADING; - value - .then(_ -> state = NONE) - .catchError(error -> state = ERROR(error)); - return value; + private function set_promise(value:Promise):Promise { + state = LOADING; + value.then(_ -> state = NONE).catchError(error -> state = ERROR(error)); + return value; + } + + public var state(default, set):State; + + private function set_state(value:State):State { + if (state != value) { + state = value; + switch state { + case NONE: + overlay = null; + case LOADING: + overlay = loadingView; + case ERROR(error): + L.e("wrapper", "", error); + cast(errorView, TextView).text = Std.string(error); + overlay = errorView; + } } + return state; + } - public var state(default, set):State; + private var view:IGroupView; - private function set_state(value:State):State { - if (state != value) { - state = value; - switch state { - case NONE: - overlay = null; - case LOADING: - overlay = loadingView; - case ERROR(error): - L.e("wrapper", "", error); - cast(errorView, TextView).text = Std.string(error); - overlay = errorView; - } - } - return state; + private var overlay(default, set):IView; + + private function set_overlay(value:IView):IView { + if (overlay != null && view.containsView(overlay)) { + view.removeView(overlay); } - - private var view:IGroupView; - - private var overlay(default, set):IView; - - private function set_overlay(value:IView):IView { - if (overlay != null && view.containsView(overlay)) { - view.removeView(overlay); - } - overlay = value; - if (overlay != null) { - view.addView(overlay); - } - return overlay; + overlay = value; + if (overlay != null) { + view.addView(overlay); } + return overlay; + } - private var loadingView(get, null):IView; + private var loadingView(get, null):IView; - private function get_loadingView():IView { - if (loadingView == null) { - loadingView = buildLoadingView(); - } - return loadingView; + private function get_loadingView():IView { + if (loadingView == null) { + loadingView = buildLoadingView(); } + return loadingView; + } - private var errorView(get, null):IView; + private var errorView(get, null):IView; - private function get_errorView():IView { - if (errorView == null) { - errorView = buildErrorView(); - } - return errorView; + private function get_errorView():IView { + if (errorView == null) { + errorView = buildErrorView(); } + return errorView; + } - public function new(view:IGroupView) { - this.view = view; - } + public function new(view:IGroupView) { + this.view = view; + } - private function buildLoadingView():IView { - var view = new LabelView(); - view.geometry.position = ABSOLUTE; - view.geometry.hAlign = CENTER; - view.geometry.vAlign = MIDDLE; - view.text = "Loading..."; - return view; - } + private function buildLoadingView():IView { + var view = new LabelView(); + view.geometry.position = ABSOLUTE; + view.geometry.hAlign = CENTER; + view.geometry.vAlign = MIDDLE; + view.text = "Loading..."; + return view; + } - private function buildErrorView():IView { - var view = new TextView(); - view.geometry.position = ABSOLUTE; - view.geometry.hAlign = CENTER; - view.geometry.vAlign = MIDDLE; - view.geometry.stretch = true; - view.style = "text.error"; - return view; - } + private function buildErrorView():IView { + var view = new TextView(); + view.geometry.position = ABSOLUTE; + view.geometry.hAlign = CENTER; + view.geometry.vAlign = MIDDLE; + view.geometry.stretch = true; + view.style = "text.error"; + return view; + } - public function reset():Void { - overlay = null; - } + public function reset():Void { + overlay = null; + } } diff --git a/src/app/haxe/ru/m/view/PaginatorView.hx b/src/app/haxe/ru/m/view/PaginatorView.hx index 037aef7..1a9245e 100644 --- a/src/app/haxe/ru/m/view/PaginatorView.hx +++ b/src/app/haxe/ru/m/view/PaginatorView.hx @@ -7,76 +7,75 @@ import hw.view.form.ToggleButtonView; import hw.view.layout.TailLayout; enum PaginatorAction { - START; - JUMP(distance:Int); - INDEX(index:Int); - END; + START; + JUMP(distance:Int); + INDEX(index:Int); + END; } class PaginatorButtonView extends ToggleButtonView { - public var action(default, set):PaginatorAction; + public var action(default, set):PaginatorAction; - private function set_action(value:PaginatorAction):PaginatorAction { - action = value; - text = switch action { - case INDEX(index): Std.string(index); - case x: Std.string(x); - } - return action; + private function set_action(value:PaginatorAction):PaginatorAction { + action = value; + text = switch action { + case INDEX(index): Std.string(index); + case x: Std.string(x); } + return action; + } - public static function factory(index:Int, action:PaginatorAction):PaginatorButtonView { - var result = new PaginatorButtonView(); - result.action = action; - return result; - } + public static function factory(index:Int, action:PaginatorAction):PaginatorButtonView { + var result = new PaginatorButtonView(); + result.action = action; + return result; + } } class PaginatorView extends DataView { + public var page(default, set):DataPage; + public var onPageSelect(default, null):Signal; - public var page(default, set):DataPage; - public var onPageSelect(default, null):Signal; + private function set_page(value:DataPage):DataPage { + page = value; + refresh(); + return page; + } - private function set_page(value:DataPage):DataPage { - page = value; - refresh(); - return page; + public function new() { + super(new TailLayout()); + layout.margin = 3; + onPageSelect = new Signal(); + factory = PaginatorButtonView.factory; + onDataSelect.connect(onAction); + } + + private function onAction(action:PaginatorAction):Void { + onPageSelect.emit(switch action { + case START: 0; + case INDEX(index): index; + case JUMP(distance): page.page.index + distance; + case END: Std.int((page.total - 1) / page.page.count); + }); + } + + private function refresh():Void { + var total:Int = Std.int((page.total - 1) / page.page.count); + var start:Int = Std.int(Math.max(page.page.index - 2, 0)); + var end:Int = Std.int(Math.min(page.page.index + 2, total)); + var data = [for (index in start...end + 1) INDEX(index)]; + if (start > 0) { + data.unshift(START); } - - public function new() { - super(new TailLayout()); - layout.margin = 3; - onPageSelect = new Signal(); - factory = PaginatorButtonView.factory; - onDataSelect.connect(onAction); + if (end < total) { + data.push(END); } - - private function onAction(action:PaginatorAction):Void { - onPageSelect.emit(switch action { - case START: 0; - case INDEX(index): index; - case JUMP(distance): page.page.index + distance; - case END: Std.int((page.total - 1) / page.page.count); - }); - } - - private function refresh():Void { - var total:Int = Std.int((page.total - 1) / page.page.count); - var start:Int = Std.int(Math.max(page.page.index - 2, 0)); - var end:Int = Std.int(Math.min(page.page.index + 2, total)); - var data = [for (index in start...end + 1) INDEX(index)]; - if (start > 0) { - data.unshift(START); - } - if (end < total) { - data.push(END); - } - this.data = data; - for (button in dataViews) { - button.on = switch button.action { - case INDEX(index): index == page.page.index; - case x: false; - } - } + this.data = data; + for (button in dataViews) { + button.on = switch button.action { + case INDEX(index): index == page.page.index; + case x: false; + } } + } } diff --git a/src/common/haxe/ru/m/IdUtil.hx b/src/common/haxe/ru/m/IdUtil.hx index 6c90e29..e0818e9 100644 --- a/src/common/haxe/ru/m/IdUtil.hx +++ b/src/common/haxe/ru/m/IdUtil.hx @@ -4,7 +4,7 @@ import com.hurlant.crypto.prng.Random; import com.hurlant.crypto.extra.UUID; class IdUtil { - public static function generate():String { - return UUID.generateRandom(new Random()).toString().split("-").shift(); - } + public static function generate():String { + return UUID.generateRandom(new Random()).toString().split("-").shift(); + } } diff --git a/src/common/haxe/ru/m/puzzlez/image/EventUtil.hx b/src/common/haxe/ru/m/puzzlez/image/EventUtil.hx index 3527ca8..ef8ea37 100644 --- a/src/common/haxe/ru/m/puzzlez/image/EventUtil.hx +++ b/src/common/haxe/ru/m/puzzlez/image/EventUtil.hx @@ -9,28 +9,19 @@ import ru.m.puzzlez.proto.event.GameEvent; import ru.m.puzzlez.proto.game.GameState; class EventUtil { + public static function start(state:GameState, resume:Bool):GameEvent { + return new GameEvent().setStart(new GameStart().setState(state).setResume(resume)); + } - public static function start(state:GameState, resume: Bool):GameEvent { - return new GameEvent().setStart(new GameStart() - .setState(state) - .setResume(resume) - ); - } + public static function complete():GameEvent { + return new GameEvent().setComplete(new GameComplete()); + } - public static function complete():GameEvent { - return new GameEvent().setComplete(new GameComplete()); - } + public static function action(action:GameAction):GameEvent { + return new GameEvent().setAction(action); + } - public static function action(action:GameAction):GameEvent { - return new GameEvent().setAction(action); - } - - public static function change(part:Part):GameEvent { - return new GameEvent().setChange(new GameChange() - .setPartId(part.id) - .setLocation(part.location) - .setPosition(part.position) - .setPlayerId(part.playerId) - ); - } + public static function change(part:Part):GameEvent { + return new GameEvent().setChange(new GameChange().setPartId(part.id).setLocation(part.location).setPosition(part.position).setPlayerId(part.playerId)); + } } diff --git a/src/common/haxe/ru/m/puzzlez/image/Game.hx b/src/common/haxe/ru/m/puzzlez/image/Game.hx index d9d34d1..7a29cda 100644 --- a/src/common/haxe/ru/m/puzzlez/image/Game.hx +++ b/src/common/haxe/ru/m/puzzlez/image/Game.hx @@ -12,109 +12,108 @@ import ru.m.puzzlez.proto.game.PartLocation; import ru.m.puzzlez.wrap.PointExt; class Game implements IGame { - public var state(default, null):GameState; - public var events(default, null):Signal; + public var state(default, null):GameState; + public var events(default, null):Signal; - private var partsById:Map; + private var partsById:Map; - public function new(state:GameState) { - this.state = state; - partsById = new Map(); - for (part in state.parts) { - partsById[part.id] = part; - } - events = new Signal(); - events.connect(onGameEvent); + public function new(state:GameState) { + this.state = state; + partsById = new Map(); + for (part in state.parts) { + partsById[part.id] = part; } + events = new Signal(); + events.connect(onGameEvent); + } - public function action(action:GameAction):Void { - events.emit(EventUtil.action(action)); + public function action(action:GameAction):Void { + events.emit(EventUtil.action(action)); + } + + public function start():Void { + switch state.status { + case GameStatus.READY: + shuffle(); + state.status = GameStatus.STARTED; + events.emit(EventUtil.start(state, false)); + case _: + events.emit(EventUtil.start(state, true)); } + } - public function start():Void { - switch state.status { - case GameStatus.READY: - shuffle(); - state.status = GameStatus.STARTED; - events.emit(EventUtil.start(state, false)); + private function shuffle():Void { + for (part in state.parts) { + switch part.location { + case PartLocation.TABLE: + var bound = part.rect.width * 0.25; + var x = bound + Math.random() * (state.preset.tableRect.width - part.rect.width - bound * 2); + var y = bound + Math.random() * (state.preset.tableRect.height - part.rect.height - bound * 2); + part.position = new PointExt(x, y); + case _: + } + } + } + + private static function distance(a:PointExt, b:PointExt):Float { + var diff:Point = a.subtract(b); + return Math.abs(diff.x) + Math.abs(diff.y); + } + + private function checkIsComplete():Bool { + for (part in partsById) { + switch part.location { + case PartLocation.IMAGE: + case _: + return false; + } + } + return true; + } + + private function onGameEvent(event:GameEvent):Void { + if (event.hasAction()) { + var part:Part = partsById[event.action.partId]; + switch event.action.action { + case Action.TAKE: + switch part.location { + case PartLocation.TABLE: + part.location = PartLocation.HAND; + part.playerId = event.action.playerId; + events.emit(EventUtil.change(part)); case _: - events.emit(EventUtil.start(state, true)); - } - } - - private function shuffle():Void { - for (part in state.parts) { - switch part.location { - case PartLocation.TABLE: - var bound = part.rect.width * 0.25; - var x = bound + Math.random() * (state.preset.tableRect.width - part.rect.width - bound * 2); - var y = bound + Math.random() * (state.preset.tableRect.height - part.rect.height - bound * 2); - part.position = new PointExt(x, y); - case _: + } + case Action.MOVE: + switch part.location { + case PartLocation.HAND if (event.action.playerId == part.playerId): + part.position = event.action.position; + events.emit(EventUtil.change(part)); + case _: + } + case Action.PUT: + part.playerId = null; + var target = new PointExt(state.preset.imageRect.x, + state.preset.imageRect.y).add(new PointExt(part.point.x * part.rect.width, part.point.y * part.rect.height)); + var d = distance(target, event.action.position); + if (d < 70) { + part.location = PartLocation.IMAGE; + events.emit(EventUtil.change(part)); + if (checkIsComplete()) { + state.status = GameStatus.COMPLETE; + events.emit(EventUtil.complete()); } - } + } else { + part.location = PartLocation.TABLE; + part.position = event.action.position; + events.emit(EventUtil.change(part)); + } + } } + } - private static function distance(a:PointExt, b:PointExt):Float { - var diff:Point = a.subtract(b); - return Math.abs(diff.x) + Math.abs(diff.y); - } + public function stop():Void {} - private function checkIsComplete():Bool { - for (part in partsById) { - switch part.location { - case PartLocation.IMAGE: - case _: return false; - } - } - return true; - } - - private function onGameEvent(event:GameEvent):Void { - if (event.hasAction()) { - var part:Part = partsById[event.action.partId]; - switch event.action.action { - case Action.TAKE: - switch part.location { - case PartLocation.TABLE: - part.location = PartLocation.HAND; - part.playerId = event.action.playerId; - events.emit(EventUtil.change(part)); - case _: - } - case Action.MOVE: - switch part.location { - case PartLocation.HAND if (event.action.playerId == part.playerId): - part.position = event.action.position; - events.emit(EventUtil.change(part)); - case _: - } - case Action.PUT: - part.playerId = null; - var target = new PointExt(state.preset.imageRect.x, state.preset.imageRect.y) - .add(new PointExt(part.point.x * part.rect.width, part.point.y * part.rect.height)); - var d = distance(target, event.action.position); - if (d < 70) { - part.location = PartLocation.IMAGE; - events.emit(EventUtil.change(part)); - if (checkIsComplete()) { - state.status = GameStatus.COMPLETE; - events.emit(EventUtil.complete()); - } - } else { - part.location = PartLocation.TABLE; - part.position = event.action.position; - events.emit(EventUtil.change(part)); - } - } - } - } - - public function stop():Void { - - } - - public function dispose():Void { - events.dispose(); - } + public function dispose():Void { + events.dispose(); + } } diff --git a/src/common/haxe/ru/m/puzzlez/image/GameUtil.hx b/src/common/haxe/ru/m/puzzlez/image/GameUtil.hx index b3f9278..f708643 100644 --- a/src/common/haxe/ru/m/puzzlez/image/GameUtil.hx +++ b/src/common/haxe/ru/m/puzzlez/image/GameUtil.hx @@ -15,139 +15,125 @@ import ru.m.puzzlez.proto.game.PartBounds; import ru.m.puzzlez.proto.game.PartLocation; class BoundsMap { + private var grid:IntPoint; + private var bounds:Array; - private var grid:IntPoint; - private var bounds:Array; - - public function new(grid:IntPoint) { - this.grid = grid; - bounds = []; - for (x in 0...grid.x + 1) { - for (y in 0...grid.y + 1) { - bounds.push(buildPartBound()); - bounds.push(buildPartBound()); - } - } + public function new(grid:IntPoint) { + this.grid = grid; + bounds = []; + for (x in 0...grid.x + 1) { + for (y in 0...grid.y + 1) { + bounds.push(buildPartBound()); + bounds.push(buildPartBound()); + } } + } - public function buildBound():Int { - return Math.random() > 0.5 ? BoundType.OUT : BoundType.IN; - } + public function buildBound():Int { + return Math.random() > 0.5 ? BoundType.OUT : BoundType.IN; + } - public function buildPartBound():PartBound { - return new PartBound().setSpike(buildBound()).setSide(buildBound()); - } + public function buildPartBound():PartBound { + return new PartBound().setSpike(buildBound()).setSide(buildBound()); + } - public function buildNonePartBound():PartBound { - return new PartBound().setSpike(BoundType.NONE).setSide(BoundType.NONE); - } + public function buildNonePartBound():PartBound { + return new PartBound().setSpike(BoundType.NONE).setSide(BoundType.NONE); + } - public function revert(type:Int):Int { - return switch type { - case BoundType.IN: BoundType.OUT; - case BoundType.OUT: BoundType.IN; - case _: BoundType.NONE; - } + public function revert(type:Int):Int { + return switch type { + case BoundType.IN: BoundType.OUT; + case BoundType.OUT: BoundType.IN; + case _: BoundType.NONE; } + } - public function getBound(x:Int, y:Int, side:Side):PartBound { - var index = switch side { - case TOP: x + (grid.x + 1) * (y * 2); - case LEFT: x + (grid.x + 1) * (y + 1); - case RIGHT: x + (grid.x + 1) * (y + 1) + 1; - case BOTTOM: x + (grid.x + 1) * (y * 2) + (grid.x + 1) * 2; - } - return switch side { - case TOP | LEFT: new PartBound().setSpike(revert(bounds[index].spike)).setSide(revert(bounds[index].side)); - case _: bounds[index]; - } + public function getBound(x:Int, y:Int, side:Side):PartBound { + var index = switch side { + case TOP: x + (grid.x + 1) * (y * 2); + case LEFT: x + (grid.x + 1) * (y + 1); + case RIGHT: x + (grid.x + 1) * (y + 1) + 1; + case BOTTOM: x + (grid.x + 1) * (y * 2) + (grid.x + 1) * 2; } + return switch side { + case TOP | LEFT: new PartBound().setSpike(revert(bounds[index].spike)).setSide(revert(bounds[index].side)); + case _: bounds[index]; + } + } } class GameUtil { + private static inline var MAX_SIZE = 20; - 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; + } - 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(image:ImageId, width:Int = 8, height:Int = MAX_SIZE):GamePreset { + width = normilizeSize(width); + height = normilizeSize(height); + var offsetX = 500; + var offsetY = 200; + var imageSize = 1024; + var s = width / height; + var imageRect = new Rectangle().setX(offsetX).setY(offsetY).setWidth(imageSize).setHeight(imageSize / s); + var tableRect = new Rectangle().setX(0) + .setY(0) + .setWidth(imageRect.width + offsetX * 2) + .setHeight(imageRect.height + offsetY * 2); + return new GamePreset().setImage(image) + .setGrid(new IntPoint().setX(width).setY(height)) + .setTableRect(tableRect) + .setImageRect(imageRect); + } - public static function buildPreset(image: ImageId, width:Int = 8, height:Int = MAX_SIZE):GamePreset { - width = normilizeSize(width); - height = normilizeSize(height); - var offsetX = 500; - var offsetY = 200; - var imageSize = 1024; - var s = width / height; - var imageRect = new Rectangle() - .setX(offsetX) - .setY(offsetY) - .setWidth(imageSize) - .setHeight(imageSize / s); - var tableRect = new Rectangle() - .setX(0) - .setY(0) - .setWidth(imageRect.width + offsetX * 2) - .setHeight(imageRect.height + offsetY * 2); - return new GamePreset() - .setImage(image) - .setGrid(new IntPoint().setX(width).setY(height)) - .setTableRect(tableRect) - .setImageRect(imageRect); - } - - public static function buildState(preset:GamePreset):GameState { - var parts:Array = []; - var partWidth = preset.imageRect.width / preset.grid.x; - var partHeight = preset.imageRect.height / preset.grid.y; - var position = new Point().setX(preset.imageRect.x).setY(preset.imageRect.y); - var boundsMap = new BoundsMap(preset.grid); - for (y in 0...preset.grid.y) { - for (x in 0...preset.grid.x) { - var bounds:PartBounds = new PartBounds() - .setLeft(boundsMap.getBound(x, y, LEFT)) - .setRight(boundsMap.getBound(x, y, RIGHT)) - .setTop(boundsMap.getBound(x, y, TOP)) - .setBottom(boundsMap.getBound(x, y, BOTTOM)); - if (x == 0) { - bounds.left = boundsMap.buildNonePartBound(); - } - if (y == 0) { - bounds.top = boundsMap.buildNonePartBound(); - } - if (x == preset.grid.x - 1) { - bounds.right = boundsMap.buildNonePartBound(); - } - if (y == preset.grid.y - 1) { - bounds.bottom = boundsMap.buildNonePartBound(); - } - var id = (x << 16) + y; - var position = new Point().setX(position.x + x * partWidth).setY(position.y + y * partHeight); - parts.push(new Part() - .setId(id) - .setPoint(new IntPoint().setX(x).setY(y)) - .setLocation(PartLocation.TABLE) - .setPosition(position) - .setBounds(bounds) - .setRect(new Rectangle().setX(0).setY(0).setWidth(partWidth).setHeight(partHeight)) - ); - } + public static function buildState(preset:GamePreset):GameState { + var parts:Array = []; + var partWidth = preset.imageRect.width / preset.grid.x; + var partHeight = preset.imageRect.height / preset.grid.y; + var position = new Point().setX(preset.imageRect.x).setY(preset.imageRect.y); + var boundsMap = new BoundsMap(preset.grid); + for (y in 0...preset.grid.y) { + for (x in 0...preset.grid.x) { + var bounds:PartBounds = new PartBounds().setLeft(boundsMap.getBound(x, y, LEFT)) + .setRight(boundsMap.getBound(x, y, RIGHT)) + .setTop(boundsMap.getBound(x, y, TOP)) + .setBottom(boundsMap.getBound(x, y, BOTTOM)); + if (x == 0) { + bounds.left = boundsMap.buildNonePartBound(); } - return new GameState() - .setId(IdUtil.generate()) - .setStatus(GameStatus.READY) - .setPreset(preset) - .setParts(parts); - } - - public static function calcProgress(state:GameState):{complete:Int, total:Int} { - var complete = 0; - for (part in state.parts) { - switch part.location { - case PartLocation.IMAGE: complete++; - case _: - } + if (y == 0) { + bounds.top = boundsMap.buildNonePartBound(); } - return {complete:complete, total:state.parts.length}; + if (x == preset.grid.x - 1) { + bounds.right = boundsMap.buildNonePartBound(); + } + if (y == preset.grid.y - 1) { + bounds.bottom = boundsMap.buildNonePartBound(); + } + var id = (x << 16) + y; + var position = new Point().setX(position.x + x * partWidth).setY(position.y + y * partHeight); + parts.push(new Part().setId(id) + .setPoint(new IntPoint().setX(x).setY(y)) + .setLocation(PartLocation.TABLE) + .setPosition(position) + .setBounds(bounds) + .setRect(new Rectangle().setX(0).setY(0).setWidth(partWidth).setHeight(partHeight))); + } } + return new GameState().setId(IdUtil.generate()).setStatus(GameStatus.READY).setPreset(preset).setParts(parts); + } + + public static function calcProgress(state:GameState):{complete:Int, total:Int} { + var complete = 0; + for (part in state.parts) { + switch part.location { + case PartLocation.IMAGE: + complete++; + case _: + } + } + return {complete: complete, total: state.parts.length}; + } } diff --git a/src/common/haxe/ru/m/puzzlez/image/IGame.hx b/src/common/haxe/ru/m/puzzlez/image/IGame.hx index 63c895a..01e67d0 100644 --- a/src/common/haxe/ru/m/puzzlez/image/IGame.hx +++ b/src/common/haxe/ru/m/puzzlez/image/IGame.hx @@ -6,14 +6,14 @@ import ru.m.puzzlez.proto.event.GameEvent; import ru.m.puzzlez.proto.game.GameState; interface IGame { - public var state(default, null):GameState; - public var events(default, null):Signal; + public var state(default, null):GameState; + public var events(default, null):Signal; - public function action(action:GameAction):Void; + public function action(action:GameAction):Void; - public function start():Void; + public function start():Void; - public function stop():Void; + public function stop():Void; - public function dispose():Void; + public function dispose():Void; } diff --git a/src/common/haxe/ru/m/puzzlez/image/Side.hx b/src/common/haxe/ru/m/puzzlez/image/Side.hx index ee8637b..cb8342f 100644 --- a/src/common/haxe/ru/m/puzzlez/image/Side.hx +++ b/src/common/haxe/ru/m/puzzlez/image/Side.hx @@ -1,8 +1,8 @@ package ru.m.puzzlez.image; enum Side { - TOP; - LEFT; - RIGHT; - BOTTOM; + TOP; + LEFT; + RIGHT; + BOTTOM; } diff --git a/src/common/haxe/ru/m/puzzlez/wrap/PointExt.hx b/src/common/haxe/ru/m/puzzlez/wrap/PointExt.hx index 4a06041..873ef62 100644 --- a/src/common/haxe/ru/m/puzzlez/wrap/PointExt.hx +++ b/src/common/haxe/ru/m/puzzlez/wrap/PointExt.hx @@ -6,36 +6,25 @@ import flash.geom.Point as FlashPoint; #end abstract PointExt(Point) from Point to Point { + public function new(x:Float = 0, y:Float = 0) { + this = new Point().setX(x).setY(y); + } - public function new(x: Float = 0, y: Float = 0) { - this = new Point() - .setX(x) - .setY(y); - } + public function clone():PointExt { + return new Point().setX(this.x).setY(this.y); + } - public function clone():PointExt { - return new Point() - .setX(this.x) - .setY(this.y); - } + public function add(point:Point):PointExt { + return new Point().setX(this.x + point.x).setY(this.y + point.y); + } - public function add(point:Point):PointExt { - return new Point() - .setX(this.x + point.x) - .setY(this.y + point.y); - } + public function subtract(point:Point):PointExt { + return new Point().setX(this.x - point.x).setY(this.y - point.y); + } - public function subtract(point:Point):PointExt { - return new Point() - .setX(this.x - point.x) - .setY(this.y - point.y); - } - - #if app - @:from public static function fromFlashPoint(point:FlashPoint):PointExt { - return new Point() - .setX(point.x) - .setY(point.y); - } - #end + #if app + @:from public static function fromFlashPoint(point:FlashPoint):PointExt { + return new Point().setX(point.x).setY(point.y); + } + #end } diff --git a/src/common/haxe/ru/m/puzzlez/wrap/RectangleExt.hx b/src/common/haxe/ru/m/puzzlez/wrap/RectangleExt.hx index 440b106..9862814 100644 --- a/src/common/haxe/ru/m/puzzlez/wrap/RectangleExt.hx +++ b/src/common/haxe/ru/m/puzzlez/wrap/RectangleExt.hx @@ -4,47 +4,37 @@ import ru.m.puzzlez.proto.core.Point; import ru.m.puzzlez.proto.core.Rectangle; abstract RectangleExt(Rectangle) from Rectangle to Rectangle { - public var left(get, never):Float; - public var right(get, never):Float; - public var top(get, never):Float; - public var bottom(get, never):Float; - public var size(get, never):Point; + public var left(get, never):Float; + public var right(get, never):Float; + public var top(get, never):Float; + public var bottom(get, never):Float; + public var size(get, never):Point; - public function new(x:Float = 0, y:Float = 0, width:Float = 0, height:Float = 0) { - this = new Rectangle() - .setX(x) - .setY(y) - .setWidth(width) - .setHeight(height); - } + public function new(x:Float = 0, y:Float = 0, width:Float = 0, height:Float = 0) { + this = new Rectangle().setX(x).setY(y).setWidth(width).setHeight(height); + } - private function get_left():Float { - return this.x; - } + private function get_left():Float { + return this.x; + } - private function get_right():Float { - return this.x + this.width; - } + private function get_right():Float { + return this.x + this.width; + } - private function get_top():Float { - return this.y; - } + private function get_top():Float { + return this.y; + } - private function get_bottom():Float { - return this.y + this.height; - } + private function get_bottom():Float { + return this.y + this.height; + } - private function get_size():Point { - return new Point() - .setX(this.width) - .setY(this.height); - } + private function get_size():Point { + return new Point().setX(this.width).setY(this.height); + } - public function clone():Rectangle { - return new Rectangle() - .setX(this.x) - .setY(this.y) - .setWidth(this.width) - .setHeight(this.height); - } + public function clone():Rectangle { + return new Rectangle().setX(this.x).setY(this.y).setWidth(this.width).setHeight(this.height); + } } diff --git a/src/server/haxe/ru/m/puzzlez/GameSession.hx b/src/server/haxe/ru/m/puzzlez/GameSession.hx index bdad1fe..aff4a49 100644 --- a/src/server/haxe/ru/m/puzzlez/GameSession.hx +++ b/src/server/haxe/ru/m/puzzlez/GameSession.hx @@ -24,122 +24,120 @@ import ru.m.puzzlez.proto.pack.Response; import sys.net.Socket; class GameSession extends ProtoSession { - private static inline var TAG = "Session"; + private static inline var TAG = "Session"; - public static var gamesById(default, null):Map = new Map(); - public static var sessionsById(default, null):Map = new Map(); + public static var gamesById(default, null):Map = new Map(); + public static var sessionsById(default, null):Map = new Map(); - public var user(default, null):User; - public var game(default, null):Game; + public var user(default, null):User; + public var game(default, null):Game; - private var subscribed:Bool; - private var tag(get, never):String; + private var subscribed:Bool; + private var tag(get, never):String; - private function get_tag():String { - return '[${id}|${user == null ? '-' : user.uuid}|${game == null ? '-' : game.state.id}]'; + private function get_tag():String { + return '[${id}|${user == null ? '-' : user.uuid}|${game == null ? '-' : game.state.id}]'; + } + + public function new(socket:Socket) { + super(socket, Request); + sessionsById.set(id, this); + } + + private function sendError(code:Int, message:String):Void { + send(new Response().setError(new ErrorResponse().setCode(code).setMessage(message))); + } + + override public function send(packet:Response):Void { + #if proto_debug L.d(TAG, '$tag send: ${packet}'); #end + try { + super.send(packet); + } catch (error:Dynamic) { + L.e(TAG, '$tag send ', error); } + } - public function new(socket:Socket) { - super(socket, Request); - sessionsById.set(id, this); + private function auth(auth:AuthRequest):Void { + user = auth.hasUser() ? auth.user : new User().setUuid(IdUtil.generate()).setName('Anonim #${IdUtil.generate()}'); + send(new Response().setAuth(new AuthResponse().setUser(user))); + send(new Response().setNotification(new NotificationResponse().setGames(Lambda.count(gamesById)))); + } + + private function list(list:GameListRequest):Void { + var games = Lambda.array(gamesById); + var pageGames = games.slice(list.page * list.count, list.count); + send(new Response().setList(new GameListResponse().setPage(list.page) + .setCount(list.count) + .setTotal(games.length) + .setGames(pageGames.map(game -> game.state)))); + } + + private function create(create:GameCreateRequest):Void { + var game = new Game(GameUtil.buildState(create.preset).setOnline(true)); + game.start(); + gamesById.set(game.state.id, game); + join(game.state.id); + for (session in sessionsById) { + session.send(new Response().setNotification(new NotificationResponse().setGames(Lambda.count(gamesById)))); } + } - private function sendError(code:Int, message:String):Void { - send(new Response().setError(new ErrorResponse().setCode(code).setMessage(message))); - } + private function join(gameId:String):Void { + game = gamesById.get(gameId); + game.events.connect(onGameEvent); + game.events.emit(new GameEvent().setPlayer(new GamePlayer().setPlayer(user).setAction(GamePlayerAction.JOIN))); + send(new Response().setJoin(new GameJoinResponse().setGame(game.state))); + } - override public function send(packet:Response):Void { - #if proto_debug L.d(TAG, '$tag send: ${packet}'); #end - try { - super.send(packet); - } catch (error:Dynamic) { - L.e(TAG, '$tag send ', error); + private function leave():Void { + game.events.disconnect(onGameEvent); + game.events.emit(new GameEvent().setPlayer(new GamePlayer().setPlayer(user).setAction(GamePlayerAction.LEAVE))); + send(new Response().setLeave(new GameLeaveResponse())); + } + + private function action(action:GameAction):Void { + game.events.emit(new GameEvent().setAction(action)); + } + + override private function onRequest(request:Request):Void { + #if proto_debug L.d(TAG, '$tag onRequest: ${request}'); #end + try { + if (!request.hasAuth() && user == null) { + throw "Not Authorized"; + } + if (request.hasAuth()) { + auth(request.auth); + } else if (request.hasList()) { + list(request.list); + } else if (request.hasCreate()) { + create(request.create); + } else if (request.hasJoin()) { + join(request.join.gameId); + } else if (request.hasLeave()) { + leave(); + } else if (request.hasAction()) { + for (action in request.action.actions) { + this.action(action); } + } + } catch (error:Dynamic) { + L.e(TAG, '$tag onRequest ', error); + sendError(500, LoggerUtil.printError(error)); } + } - private function auth(auth:AuthRequest):Void { - user = auth.hasUser() ? auth.user : new User().setUuid(IdUtil.generate()).setName('Anonim #${IdUtil.generate()}'); - send(new Response().setAuth(new AuthResponse().setUser(user))); - send(new Response().setNotification(new NotificationResponse().setGames(Lambda.count(gamesById)))); - } + private function onGameEvent(event:GameEvent):Void { + send(new Response().setEvent(new GameEventResponse().setEvents([event]))); + } - private function list(list:GameListRequest):Void { - var games = Lambda.array(gamesById); - var pageGames = games.slice(list.page * list.count, list.count); - send(new Response().setList(new GameListResponse() - .setPage(list.page) - .setCount(list.count) - .setTotal(games.length) - .setGames(pageGames.map(game -> game.state)) - )); - } - - private function create(create:GameCreateRequest):Void { - var game = new Game(GameUtil.buildState(create.preset).setOnline(true)); - game.start(); - gamesById.set(game.state.id, game); - join(game.state.id); - for (session in sessionsById) { - session.send(new Response().setNotification(new NotificationResponse().setGames(Lambda.count(gamesById)))); - } - } - - private function join(gameId:String):Void { - game = gamesById.get(gameId); - game.events.connect(onGameEvent); - game.events.emit(new GameEvent().setPlayer(new GamePlayer().setPlayer(user).setAction(GamePlayerAction.JOIN))); - send(new Response().setJoin(new GameJoinResponse().setGame(game.state))); - } - - private function leave():Void { - game.events.disconnect(onGameEvent); - game.events.emit(new GameEvent().setPlayer(new GamePlayer().setPlayer(user).setAction(GamePlayerAction.LEAVE))); - send(new Response().setLeave(new GameLeaveResponse())); - } - - private function action(action:GameAction):Void { - game.events.emit(new GameEvent().setAction(action)); - } - - override private function onRequest(request:Request):Void { - #if proto_debug L.d(TAG, '$tag onRequest: ${request}'); #end - try { - if (!request.hasAuth() && user == null) { - throw "Not Authorized"; - } - if (request.hasAuth()) { - auth(request.auth); - } else if (request.hasList()) { - list(request.list); - } else if (request.hasCreate()) { - create(request.create); - } else if (request.hasJoin()) { - join(request.join.gameId); - } else if (request.hasLeave()) { - leave(); - } else if (request.hasAction()) { - for (action in request.action.actions) { - this.action(action); - } - } - } catch (error:Dynamic) { - L.e(TAG, '$tag onRequest ', error); - sendError(500, LoggerUtil.printError(error)); - } - } - - private function onGameEvent(event:GameEvent):Void { - send(new Response().setEvent(new GameEventResponse().setEvents([event]))); - } - - override public function disconnect():Void { - L.d(TAG, '$tag disconnect'); - if (game != null) { - leave(); - game = null; - } - user = null; - sessionsById.remove(id); - super.disconnect(); + override public function disconnect():Void { + L.d(TAG, '$tag disconnect'); + if (game != null) { + leave(); + game = null; } + user = null; + sessionsById.remove(id); + super.disconnect(); + } } diff --git a/src/server/haxe/ru/m/puzzlez/PuzzlezServer.hx b/src/server/haxe/ru/m/puzzlez/PuzzlezServer.hx index 686415a..f0b495e 100644 --- a/src/server/haxe/ru/m/puzzlez/PuzzlezServer.hx +++ b/src/server/haxe/ru/m/puzzlez/PuzzlezServer.hx @@ -8,41 +8,40 @@ import haxe.io.Bytes; typedef Message = Bytes; typedef ClientMessage = { - var msg:M; - var bytes:Int; + var msg:M; + var bytes:Int; } class PuzzlezServer extends ThreadServer { + private static inline var TAG = 'Server'; - private static inline var TAG = 'Server'; + override public function clientConnected(socket:Socket):GameSession { + var session = new GameSession(socket); + L.d(TAG, 'Client connected'); + return session; + } - override public function clientConnected(socket:Socket):GameSession { - var session = new GameSession(socket); - L.d(TAG, 'Client connected'); - return session; - } + override public function clientDisconnected(session:GameSession) { + L.d(TAG, 'Client disconnected'); + session.disconnect(); + } - override public function clientDisconnected(session:GameSession) { - L.d(TAG, 'Client disconnected'); - session.disconnect(); - } + override public function readClientMessage(session:GameSession, buf:Bytes, pos:Int, len:Int):ClientMessage { + // L.d(TAG, 'Client message: ${buf}'); + return {msg: buf.sub(pos, len), bytes: len}; + } - override public function readClientMessage(session:GameSession, buf:Bytes, pos:Int, len:Int): ClientMessage { - //L.d(TAG, 'Client message: ${buf}'); - return {msg: buf.sub(pos, len), bytes: len}; - } + override public function clientMessage(session:GameSession, message:Message) { + session.pushData(message); + } - override public function clientMessage(session:GameSession, message:Message) { - session.pushData(message); - } - - public static function main():Void { - L.push(new TraceLogger()); - L.i(TAG, 'Build: ${CompilationOption.get("build")}'); - var host:String = Sys.args().length > 0 ? Sys.args()[0] : "0.0.0.0"; - var port:Int = Sys.args().length > 1 ? Std.parseInt(Sys.args()[1]) : 5000; - var wserver = new PuzzlezServer(); - L.i(TAG, 'Start on ${host}:${port}'); - wserver.run(host, port); - } + public static function main():Void { + L.push(new TraceLogger()); + L.i(TAG, 'Build: ${CompilationOption.get("build")}'); + var host:String = Sys.args().length > 0 ? Sys.args()[0] : "0.0.0.0"; + var port:Int = Sys.args().length > 1 ? Std.parseInt(Sys.args()[1]) : 5000; + var wserver = new PuzzlezServer(); + L.i(TAG, 'Start on ${host}:${port}'); + wserver.run(host, port); + } } diff --git a/tasks/gulp-publish.js b/tasks/gulp-publish.js index ad2136a..0b1c729 100755 --- a/tasks/gulp-publish.js +++ b/tasks/gulp-publish.js @@ -1,114 +1,134 @@ -const gulp = require('gulp'); -const fs = require('fs'); -const fse = require('fs-extra'); -const path = require('path'); -const through = require('through2'); +const gulp = require("gulp"); +const fs = require("fs"); +const fse = require("fs-extra"); +const path = require("path"); +const through = require("through2"); class Package { + constructor(platform, type, version, versionInt) { + this.platform = platform; + this.type = type; + this.version = version; + this.versionInt = versionInt; + } - constructor(platform, type, version, versionInt) { - this.platform = platform; - this.type = type; - this.version = version; - this.versionInt = versionInt; - } + get key() { + return [this.platform, this.type].join(":"); + } - get key() { - return [this.platform, this.type].join(':'); + static getPlatform(filename) { + for (const [platform, r] of [ + ["android", /^.*?\.apk$/], + ["linux", /^.*?\.deb$/], + ["linux", /^.*?linux\.tar\.gz$/], + ["windows", /^.*?win\.zip$/], + ["windows", /^.*?\.exe$/], + ]) { + if (r.test(filename)) { + return platform; + } } + return null; + } - static getPlatform(filename) { - for (const [platform, r] of [ - ['android', /^.*?\.apk$/], - ['linux', /^.*?\.deb$/], - ['linux', /^.*?linux\.tar\.gz$/], - ['windows', /^.*?win\.zip$/], - ['windows', /^.*?\.exe$/], - ]) { - if (r.test(filename)) { - return platform; - } - } - return null; + static getType(filename) { + for (const [type, r] of [ + ["apk", /^.*?\.apk$/], + ["deb", /^.*?\.deb$/], + ["archive", /^.*?\.tar\.gz$/], + ["archive", /^.*?\.zip$/], + ["exe", /^.*?\.exe$/], + ]) { + if (r.test(filename)) { + return type; + } } + return null; + } - static getType(filename) { - for (const [type, r] of [ - ['apk', /^.*?\.apk$/], - ['deb', /^.*?\.deb$/], - ['archive', /^.*?\.tar\.gz$/], - ['archive', /^.*?\.zip$/], - ['exe', /^.*?\.exe$/], - ]) { - if (r.test(filename)) { - return type; - } - } - return null; + static getVersion(filename) { + const m = /(\d+)\.(\d+)\.(\d+)/.exec(filename); + if (m) { + return [ + m[0], + parseInt(m[1]) * 10000 + parseInt(m[2]) * 100 + parseInt(m[3]), + ]; } + return null; + } - static getVersion(filename) { - const m = /(\d+)\.(\d+)\.(\d+)/.exec(filename); - if (m) { - return [m[0], parseInt(m[1]) * 10000 + parseInt(m[2]) * 100 + parseInt(m[3])]; - } - return null; - } - - static parseFilename(filename) { - const platform = this.getPlatform(filename); - const type = this.getType(filename); - const version = this.getVersion(filename); - if (platform && type && version) { - return new Package(platform, type, version[0], version[1]); - } - return null; + static parseFilename(filename) { + const platform = this.getPlatform(filename); + const type = this.getType(filename); + const version = this.getVersion(filename); + if (platform && type && version) { + return new Package(platform, type, version[0], version[1]); } + return null; + } } -module.exports = (name, version, publishDir, publishUrl) => function publish(cb) { +module.exports = (name, version, publishDir, publishUrl) => + function publish(cb) { const packages = {}; fse.ensureDirSync(publishDir); return gulp.series([ - function copy() { - return gulp.src('target/app/@(android|archive|debian|installer)/*') - .pipe(through.obj(function (file, enc, cb) { - const pack = Package.parseFilename(file.path); - if (pack) { - this.push(file); - } - cb(null); - })) - .pipe(gulp.dest(publishDir)) - }, - function generate() { - return gulp.src(`${publishDir}/*/*`) - .pipe(through.obj(function (file, enc, cb) { - const basepath = file.path.replace(file.base + path.sep, ''); - const pack = Package.parseFilename(file.path); - if (pack) { - if (!packages[pack.key] || packages[pack.key].versionInt < pack.versionInt) { - packages[pack.key] = { - platform: pack.platform, - type: pack.type, - version: pack.version, - versionInt: pack.versionInt, - path: basepath, - filename: basepath.split(path.sep).pop(), - url: `${publishUrl}/${basepath.replace(path.sep, "/")}`, - } - } - } - cb(null); - })).on('end', function () { - fs.writeFileSync(path.join(publishDir, 'packages.json'), JSON.stringify({ - name: name, - version: version, - packages: Object.values(packages), - }, null, 4)); - }) - } + function copy() { + return gulp + .src("target/app/@(android|archive|debian|installer)/*") + .pipe( + through.obj(function (file, enc, cb) { + const pack = Package.parseFilename(file.path); + if (pack) { + this.push(file); + } + cb(null); + }) + ) + .pipe(gulp.dest(publishDir)); + }, + function generate() { + return gulp + .src(`${publishDir}/*/*`) + .pipe( + through.obj(function (file, enc, cb) { + const basepath = file.path.replace(file.base + path.sep, ""); + const pack = Package.parseFilename(file.path); + if (pack) { + if ( + !packages[pack.key] || + packages[pack.key].versionInt < pack.versionInt + ) { + packages[pack.key] = { + platform: pack.platform, + type: pack.type, + version: pack.version, + versionInt: pack.versionInt, + path: basepath, + filename: basepath.split(path.sep).pop(), + url: `${publishUrl}/${basepath.replace(path.sep, "/")}`, + }; + } + } + cb(null); + }) + ) + .on("end", function () { + fs.writeFileSync( + path.join(publishDir, "packages.json"), + JSON.stringify( + { + name: name, + version: version, + packages: Object.values(packages), + }, + null, + 4 + ) + ); + }); + }, ])(cb); -}; + }; module.exports.Package = Package;