diff --git a/package.json b/package.json index eedbee1..e471bf7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "puzzlez", - "version": "0.2.0", + "version": "0.2.1", "private": true, "devDependencies": { "dateformat": "^3.0.3", diff --git a/src/haxe/ru/m/puzzlez/PuzzlezTheme.hx b/src/haxe/ru/m/puzzlez/PuzzlezTheme.hx index 9ed0ab8..5726286 100644 --- a/src/haxe/ru/m/puzzlez/PuzzlezTheme.hx +++ b/src/haxe/ru/m/puzzlez/PuzzlezTheme.hx @@ -1,6 +1,8 @@ package ru.m.puzzlez; +import haxework.color.Color; import haxework.view.geometry.Box; +import haxework.view.geometry.SizeValue; import haxework.view.theme.Theme; class PuzzlezTheme extends Theme { @@ -12,6 +14,11 @@ class PuzzlezTheme extends Theme { "skin.background.color" => colors.light, "skin.border.color" => colors.border, "geometry.padding" => Box.fromFloat(3), + "geometry.width" => SizeValue.fromInt(192), + "geometry.height" => SizeValue.fromInt(128), ])); + register(new Style("text.error", [ + "font.color" => Color.fromString("red"), + ], "text")); } } diff --git a/src/haxe/ru/m/puzzlez/view/ImagesFrame.hx b/src/haxe/ru/m/puzzlez/view/ImagesFrame.hx index 8776109..29bcef6 100644 --- a/src/haxe/ru/m/puzzlez/view/ImagesFrame.hx +++ b/src/haxe/ru/m/puzzlez/view/ImagesFrame.hx @@ -1,29 +1,61 @@ package ru.m.puzzlez.view; +import haxework.view.group.GroupView; import haxework.view.data.DataView; import haxework.view.form.ButtonView; import haxework.view.frame.FrameSwitcher; import haxework.view.frame.FrameView; import haxework.view.ImageView; import haxework.view.utils.DrawUtil; -import openfl.Assets; import ru.m.puzzlez.core.Id; import ru.m.puzzlez.FileUtil; import ru.m.puzzlez.storage.FileSource; import ru.m.puzzlez.storage.ImageStorage; + +class PuzzleImageView extends GroupView { + + public var imageId(null, set):ImageId; + + private function set_imageId(value:ImageId):ImageId { + if (imageId != value) { + imageId = value; + loading.promise = imageStorage.resolve(imageId, true).then(function(data) image.image = data); + } + return imageId; + } + + private var image:ImageView; + private var loading:LoadingWrapper; + @:provide var imageStorage:ImageStorage; + + public function new() { + super(); + style = "view"; + image = new ImageView(); + image.geometry.stretch = true; + image.stretch = false; + image.fillType = COVER; + addView(image); + loading = new LoadingWrapper(this); + } +} + + @:template class ImagesFrame extends FrameView> { public static var ID = "images"; - @:view var images:DataView; + @:view var images:DataView; @:view var select:ButtonView; @:provide var imageStorage:ImageStorage; @:provide var switcher:FrameSwitcher; private var source:ImageListSource; + private var loading:LoadingWrapper; public function new() { super(ID); + loading = new LoadingWrapper(images); } override public function onShow(data:ImageListSource):Void { @@ -31,7 +63,7 @@ import ru.m.puzzlez.storage.ImageStorage; source = data; select.visible = source.source.id == FileSource.ID; images.data = []; - data.source.getList(data.type).then(function(result) images.data = result); + loading.promise = data.source.getList(data.type).then(function(result) images.data = result); } } @@ -39,16 +71,9 @@ import ru.m.puzzlez.storage.ImageStorage; //images.data = []; } - private function imageViewFactory(index:Int, image:ImageId):ImageView { - var result = new ImageView(); - result.style = "view"; - result.stretch = false; - result.fillType = FillType.COVER; - result.setSize(192, 128); - result.image = Assets.getBitmapData("resources/icon.png"); - imageStorage.resolve(image, true) - .then(function(image) result.image = image) - .catchError(function(error) L.e("ImageStorage", "", error)); + private function imageViewFactory(index:Int, imageId:ImageId):PuzzleImageView { + var result = new PuzzleImageView(); + result.imageId = imageId; return result; } diff --git a/src/haxe/ru/m/puzzlez/view/LoadingWrapper.hx b/src/haxe/ru/m/puzzlez/view/LoadingWrapper.hx new file mode 100644 index 0000000..50562f8 --- /dev/null +++ b/src/haxe/ru/m/puzzlez/view/LoadingWrapper.hx @@ -0,0 +1,107 @@ +package ru.m.puzzlez.view; + +import haxework.view.form.LabelView; +import flash.text.TextFormatAlign; +import haxework.view.geometry.HAlign; +import haxework.view.geometry.Position; +import haxework.view.geometry.VAlign; +import haxework.view.group.IGroupView; +import haxework.view.IView; +import haxework.view.text.TextView; +import promhx.Promise; + +enum State { + NONE; + LOADING; + ERROR(error:Dynamic); +} + +class LoadingWrapper { + public var promise(null, set):Promise; + + private function set_promise(value:Promise):Promise { + state = LOADING; + value + .then(function(_) state = NONE) + .catchError(function(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): + cast(errorView, TextView).text = Std.string(error); + overlay = errorView; + } + } + return state; + } + + 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; + } + + private var loadingView(get, null):IView; + + private function get_loadingView():IView { + if (loadingView == null) { + loadingView = buildLoadingView(); + } + return loadingView; + } + + private var errorView(get, null):IView; + + private function get_errorView():IView { + if (errorView == null) { + errorView = buildErrorView(); + } + return errorView; + } + + 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 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; + } +} diff --git a/src/haxe/ru/m/puzzlez/view/PresetView.hx b/src/haxe/ru/m/puzzlez/view/PresetView.hx index 6211069..4d0cbc4 100644 --- a/src/haxe/ru/m/puzzlez/view/PresetView.hx +++ b/src/haxe/ru/m/puzzlez/view/PresetView.hx @@ -4,12 +4,12 @@ import flash.display.BitmapData; import flash.display.Graphics; import flash.display.Shape; import flash.geom.Matrix; -import haxework.view.SpriteView; +import haxework.view.group.GroupView; import ru.m.puzzlez.core.GamePreset; import ru.m.puzzlez.render.RenderUtil; import ru.m.puzzlez.storage.ImageStorage; -class PresetView extends SpriteView { +class PresetView extends GroupView { @:provide var imageStorage:ImageStorage; public var scale(get, set):Float; @@ -29,8 +29,9 @@ class PresetView extends SpriteView { private function set_preset(value:GamePreset) { preset = value; + this.image = null; table.graphics.clear(); - imageStorage.resolve(preset.image).then(function(image) { + loading.promise = imageStorage.resolve(preset.image).then(function(image) { this.image = RenderUtil.cropImage(image, preset.imageRect); toRedraw(); toUpdate(); @@ -38,10 +39,13 @@ class PresetView extends SpriteView { return preset; } + private var loading:LoadingWrapper; + public function new() { super(); table = new Shape(); content.addChild(table); + loading = new LoadingWrapper(this); } private var table:Shape;