[refactoring] #1

This commit is contained in:
2020-09-09 14:09:38 +03:00
parent edbc587e2e
commit 9a8f171552
52 changed files with 423 additions and 1019 deletions

View File

@@ -0,0 +1,22 @@
package ru.m.data;
import promhx.Promise;
typedef PageParams = Map<String, Dynamic>;
typedef Page = {
var index:Int;
var count:Int;
@:optional var params:PageParams;
}
typedef DataPage<D> = {
var page:Page;
var data:Array<D>;
var total:Int;
}
interface DataSource<D> {
public function getPage(page:Page):Promise<DataPage<D>>;
// public function get(id):D;
}

View File

@@ -1,202 +0,0 @@
package ru.m.data;
import flash.net.SharedObject;
import haxe.DynamicAccess;
import haxe.io.Bytes;
import haxe.Serializer;
import haxe.Unserializer;
import hw.connect.PacketUtil;
import promhx.Promise;
import ru.m.data.IDataSource;
class Converter<D, S> {
private var serializer:D -> S;
private var desirealizer:S -> D;
public function new(serializer:D -> S, desirealizer:S -> D) {
this.serializer = serializer;
this.desirealizer = desirealizer;
}
public inline function serialize(item:D):S {
return serializer(item);
}
public inline function deserialize(data:S):D {
return desirealizer(data);
}
}
class DefaultConverter<D> extends Converter<D, String> {
public function new () {
super(
item -> Serializer.run(item),
data -> new Unserializer(data).unserialize()
);
}
}
class ProtoConverter<D:protohx.Message> extends Converter<D, String> {
public function new(messageClass:Class<D>) {
super(
item -> PacketUtil.toBytes(item).toHex(),
data -> PacketUtil.fromBytes(Bytes.ofHex(data), messageClass)
);
}
}
class EmptyConverter<T> extends Converter<T, T> {
public function new() {
super(item -> item, data -> data);
}
}
class MetaBuilder<D> extends DefaultConverter<DataMeta> {
private var builder:D -> DataMeta;
public function new(builder:D -> DataMeta) {
super();
this.builder = builder;
}
public function build(item:D):DataMeta {
return builder(item);
}
}
typedef DataMeta = Filter;
typedef IdValue<I> = {id:I, meta:DataMeta};
class DataStorage<I, D> implements IDataManager<I, D> implements IDataIndex<I> {
inline private static var DATA_KEY = "item";
private var name:String;
private var metaBuilder:MetaBuilder<D>;
private var idConverter:Converter<I, String>;
private var dataConverter:Converter<D, Dynamic>;
private var indexData:SharedObject;
public function new(
name:String,
metaBuilder:MetaBuilder<D>,
idConverter:Converter<I, String> = null,
dataConverter:Converter<D, Dynamic> = null
) {
this.name = name;
this.metaBuilder = metaBuilder;
this.idConverter = idConverter != null ? idConverter : new DefaultConverter();
this.dataConverter = dataConverter != null ? dataConverter : new DefaultConverter();
this.indexData = SharedObject.getLocal('${name}/index');
}
private function serializeId(id:I):String {
return idConverter.serialize(id);
}
private function desirealizeId(data:String):I {
return idConverter.deserialize(data);
}
private function buildMeta(item:D):DataMeta {
return metaBuilder.build(item);
}
private function checkFilter(filter:Null<Filter>, meta:DataMeta):Bool {
if (filter != null) {
for (k => v in filter) {
if (meta.exists(k) && meta.get(k) != v) {
return false;
}
}
}
return true;
}
private function sort(order:Order, values:Array<IdValue<I>>):Void {
if (order != null) {
values.sort((a:IdValue<I>, b:IdValue<I>) -> {
for (item in order) {
var av = a.meta.get(item.key);
var bv = b.meta.get(item.key);
if (av > bv) {
return item.reverse ? - 1 : 1;
} else if (av < bv) {
return item.reverse ? 1 : -1;
}
}
return 0;
});
}
}
private function serialize(item:D):Dynamic {
return dataConverter.serialize(item);
}
private function unserialize(data:Dynamic):D {
return dataConverter.deserialize(data);
}
public function getIndexPage(page:Page):Promise<DataPage<I>> {
var data:DynamicAccess<String> = indexData.data;
var values:Array<IdValue<I>> = [];
for (k => v in data) {
var meta = metaBuilder.deserialize(v);
if (checkFilter(page.filter, meta)) {
values.push({id: desirealizeId(k), meta: meta});
}
}
sort(page.order, values);
var result:Array<I> = 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<DataPage<D>> {
return getIndexPage(page).pipe((indexPage:DataPage<I>) -> {
return Promise.whenAll([for (id in indexPage.data) get(id)]).then((data:Array<D>) -> {
return {
page: indexPage.page,
total: indexPage.total,
data: data,
}
});
});
}
public function get(id:I):Promise<D> {
var stringId = serializeId(id);
var itemData = SharedObject.getLocal('${name}/${stringId}');
var result:D = null;
if (Reflect.hasField(itemData.data, DATA_KEY)) {
result = unserialize(Reflect.field(itemData.data, DATA_KEY));
}
return Promise.promise(result);
}
public function save(item:D):Promise<D> {
var meta = metaBuilder.build(item);
var stringId = meta.get("id");
var itemData = SharedObject.getLocal('${name}/${stringId}');
itemData.setProperty(DATA_KEY, serialize(item));
itemData.flush();
indexData.setProperty(stringId, metaBuilder.serialize(meta));
indexData.flush();
return Promise.promise(item);
}
public function delete(id:I):Promise<Bool> {
var stringId = serializeId(id);
var itemData = SharedObject.getLocal('${name}/${stringId}');
itemData.clear();
var data:DynamicAccess<String> = indexData.data;
data.remove(stringId);
indexData.flush();
return Promise.promise(true);
}
}

View File

@@ -1,34 +0,0 @@
package ru.m.data;
import promhx.Promise;
typedef Filter = Map<String, String>;
typedef Order = Array<{key: String, ?reverse:Bool}>;
typedef Page = {
var index:Int;
var count:Int;
@:optional var order:Order;
@:optional var filter:Filter;
}
typedef DataPage<T> = {
var page:Page;
var total:Int;
var data:Array<T>;
}
interface IDataIndex<I> {
public function getIndexPage(page:Page):Promise<DataPage<I>>;
}
interface IDataSource<I, D> {
public function getPage(page:Page):Promise<DataPage<D>>;
public function get(id:I):Promise<D>;
}
interface IDataManager<I, D> extends IDataSource<I, D> {
public function save(item:D):Promise<D>;
public function delete(id:I):Promise<Bool>;
}

View File

@@ -2,7 +2,6 @@ package ru.m.pixabay;
import hw.net.JsonLoader;
import promhx.Promise;
import ru.m.data.IDataSource;
typedef PixabayImage = {
var id:Int;
@@ -47,7 +46,7 @@ enum abstract PixabayImageType(String) from String to String {
var VECTOR = "vector";
}
class PixabayApi implements IDataSource<Int, PixabayImage> {
class PixabayApi {
private var baseUrl:String = "https://pixabay.com/api/";
private var key:String;
@@ -61,24 +60,15 @@ class PixabayApi implements IDataSource<Int, PixabayImage> {
return '${baseUrl}?${query}';
}
public function getPage(page:Page):Promise<DataPage<PixabayImage>> {
var category = PixabayCategory.NATURE;
if (page.filter != null && page.filter.exists("type")) {
category = page.filter.get("type");
}
public function getPage(page:Int, perPage:Int, category:PixabayCategory = PixabayCategory.NATURE):Promise<PixabayResponse> {
return new JsonLoader<PixabayResponse>()
.GET(buildRequest([
"category" => category,
"image_type" => PixabayImageType.PHOTO,
"editors_choice" => true,
"per_page" => page.count,
"page" => page.index + 1,
]))
.then((response:PixabayResponse) -> ({
page: page,
total: response.totalHits,
data: response.hits,
}));
"per_page" => perPage,
"page" => page,
]));
}
public function get(id:Int):Promise<PixabayImage> {

View File

@@ -1,25 +1,27 @@
package ru.m.puzzlez;
import ru.m.puzzlez.image.PixabayImageSource;
import ru.m.puzzlez.render.part.IPartBuilder;
import ru.m.puzzlez.image.AssetImageSource;
import ru.m.puzzlez.image.ImageSourceBundle;
import ru.m.puzzlez.settings.Settings;
import ru.m.puzzlez.view.PuzzlezAppView;
import hw.app.App;
import hw.app.Const;
import hw.log.TraceLogger;
import ru.m.puzzlez.render.part.IPartBuilder;
import ru.m.puzzlez.storage.GameStorage;
import ru.m.puzzlez.storage.ImageStorage;
import ru.m.puzzlez.storage.SettingsStorage;
import ru.m.puzzlez.view.PuzzlezAppView;
import ru.m.update.Updater;
class PuzzlezApp {
@:provide static var updater:Updater;
@:provide static var sourceBundle:ImageSourceBundle;
public static function main() {
// ToDo: fix @:provide macro
GameStorage;
ImageStorage;
SettingsStorage;
Settings;
IPartBuilder;
sourceBundle.register(new AssetImageSource());
sourceBundle.register(new PixabayImageSource());
L.push(new TraceLogger());
updater = new Updater(Const.instance.VERSION, "https://shmyga.ru/repo/puzzlez/packages.json");
var app = new App();

View File

@@ -0,0 +1,26 @@
package ru.m.puzzlez.image;
import openfl.utils.Assets;
import promhx.Promise;
import ru.m.data.DataSource;
import ru.m.puzzlez.image.ImageSource;
import ru.m.puzzlez.proto.game.ImageId;
class AssetImageSource implements ImageSource {
public var id(default, never):String = "asset";
public function new() {
}
public function getPage(page:Page):Promise<DataPage<ImageId>> {
return Promise.promise({
page: page,
data: [],
total: 0,
});
}
public function load(id:String):Promise<ImageValue> {
return Promise.promise(ImageValue.BITMAP(Assets.getBitmapData(id)));
}
}

View File

@@ -0,0 +1,50 @@
package ru.m.puzzlez.image;
import flash.display.BitmapData;
import haxe.io.Bytes;
import hw.net.BytesLoader;
import promhx.Promise;
import ru.m.puzzlez.image.ImageSource;
import ru.m.puzzlez.proto.game.ImageId;
abstract ImageData(ImageId) from ImageId {
private static var cache:Map<String, Promise<BitmapData>> = new Map();
private static var storageCache:StorageCache = new StorageCache();
@:provide private var sourceBundle:ImageSourceBundle;
public function new(image: ImageId) {
this = image;
}
@:from public static function fromImageId(value:ImageId):ImageData {
return new ImageData(value);
}
private function extractImage(key:String, value:ImageValue):Promise<BitmapData> {
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<BitmapData> {
var key = '${this.source}:${this.id}';
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).pipe(value -> extractImage(key, value)));
}
}
return cache.get(key);
}
}

View File

@@ -0,0 +1,18 @@
package ru.m.puzzlez.image;
import flash.display.BitmapData;
import haxe.io.Bytes;
import promhx.Promise;
import ru.m.data.DataSource;
import ru.m.puzzlez.proto.game.ImageId;
enum ImageValue {
BITMAP(value:BitmapData);
BYTES(value:Bytes);
URL(value:String);
}
interface ImageSource extends DataSource<ImageId> {
public var id(default, never):String;
public function load(id:String):Promise<ImageValue>;
}

View File

@@ -0,0 +1,20 @@
package ru.m.puzzlez.image;
@:provide class ImageSourceBundle {
private var sources:Map<String, ImageSource>;
public function new() {
sources = new Map();
}
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);
}
}

View File

@@ -0,0 +1,45 @@
package ru.m.puzzlez.image;
import promhx.Promise;
import ru.m.data.DataSource;
import ru.m.pixabay.PixabayApi;
import ru.m.puzzlez.image.ImageSource;
import ru.m.puzzlez.proto.game.ImageId;
class PixabayImageSource implements ImageSource {
public var id(default, never):String = "pixabay";
private var api:PixabayApi;
private static var imageUrlsCache:Map<Int, String> = new Map();
public function new() {
api = new PixabayApi("14915210-5eae157281211e0ad28bc8def");
}
public function getPage(page:Page):Promise<DataPage<ImageId>> {
return this.api.getPage(page.index + 1, page.count).then((response:PixabayResponse) -> {
var data:Array<ImageId> = [];
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):Promise<ImageValue> {
var imageId = Std.parseInt(id);
if (imageUrlsCache.exists(imageId)) {
return Promise.promise(ImageValue.URL(imageUrlsCache.get(imageId)));
} else {
return api.get(imageId).then((data:PixabayImage) -> {
imageUrlsCache.set(imageId, data.largeImageURL);
return ImageValue.URL(data.largeImageURL);
});
}
}
}

View File

@@ -0,0 +1,38 @@
package ru.m.puzzlez.image;
import flash.net.SharedObject;
import haxe.crypto.Md5;
import haxe.io.Bytes;
class StorageCache {
private static var DATA_KEY:String = "data";
private var name:String;
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<Bytes> {
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();
}
}

View File

@@ -6,7 +6,6 @@ import hw.signal.Signal;
import hw.storage.SharedObjectStorage;
import promhx.Promise;
import ru.m.data.IDataSource;
import ru.m.puzzlez.core.Id;
import ru.m.puzzlez.proto.core.User;
import ru.m.puzzlez.proto.event.GameAction;
import ru.m.puzzlez.proto.event.GameEvent;
@@ -22,7 +21,7 @@ import ru.m.puzzlez.proto.pack.NotificationResponse;
import ru.m.puzzlez.proto.pack.Request;
import ru.m.puzzlez.proto.pack.Response;
@:provide class Network implements IDataIndex<ImageId> {
@:provide class Network implements IDataSource<String, GameState> {
public var userSignal:Signal<User> = new Signal();
public var notificationSignal:Signal<NotificationResponse> = new Signal();
public var listSignal:Signal<GameListResponse> = new Signal();
@@ -101,7 +100,7 @@ import ru.m.puzzlez.proto.pack.Response;
}
}
public function getIndexPage(page:Page):Promise<DataPage<ImageId>> {
public function getPage(page:Page):Promise<DataPage<GameState>> {
connection.send(new Request().setList(new GameListRequest().setCount(page.count).setPage(page.index)));
return listSignal.next().then((list:GameListResponse) -> ({
page: {
@@ -111,7 +110,11 @@ import ru.m.puzzlez.proto.pack.Response;
order: null,
},
total: list.total,
data: list.games.map(item -> ImageId.fromString(item.preset.imageId)),
data: list.games,
}));
}
public function get(id:String):GameState {
return null;
}
}

View File

@@ -2,7 +2,7 @@ package ru.m.puzzlez.net;
import ru.m.puzzlez.proto.event.GameStart;
import hw.signal.Signal;
import ru.m.puzzlez.core.IGame;
import ru.m.puzzlez.image.IGame;
import ru.m.puzzlez.proto.event.GameAction;
import ru.m.puzzlez.proto.event.GameEvent;
import ru.m.puzzlez.proto.game.GameState;

View File

@@ -1,7 +1,7 @@
package ru.m.puzzlez.render;
import hw.color.Color;
import ru.m.puzzlez.core.Id;
import ru.m.puzzlez.proto.game.ImageId;
enum Background {
NONE;

View File

@@ -4,7 +4,6 @@ import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.PixelSnapping;
import flash.display.Sprite;
import ru.m.puzzlez.core.Id;
import ru.m.puzzlez.proto.core.Point;
import ru.m.puzzlez.proto.game.Part;
import ru.m.puzzlez.render.part.IPartBuilder;
@@ -46,9 +45,9 @@ class PartView extends Sprite {
public var size(default, null):Point;
public var playerId(default, set):Null<PlayerId>;
public var playerId(default, set):Null<String>;
private function set_playerId(value:Null<PlayerId>):Null<PlayerId> {
private function set_playerId(value:Null<String>):Null<String> {
if (playerId != value) {
playerId = value;
redraw();

View File

@@ -1,5 +1,6 @@
package ru.m.puzzlez.render;
import ru.m.puzzlez.image.ImageData;
import flash.display.BitmapData;
import flash.display.PNGEncoderOptions;
import flash.display.Sprite;
@@ -11,16 +12,13 @@ import flash.utils.ByteArray;
import hw.signal.Signal;
import hw.view.popup.AlertView;
import hw.view.SpriteView;
import ru.m.puzzlez.core.Id;
import ru.m.puzzlez.net.Network;
import ru.m.puzzlez.proto.event.gameaction.Action;
import ru.m.puzzlez.proto.event.GameAction;
import ru.m.puzzlez.proto.event.GameEvent;
import ru.m.puzzlez.proto.game.GameState;
import ru.m.puzzlez.proto.game.PartLocation;
import ru.m.puzzlez.render.ImagePartBuilder;
import ru.m.puzzlez.storage.ImageStorage;
import ru.m.puzzlez.storage.SettingsStorage;
import ru.m.puzzlez.settings.Settings;
import ru.m.puzzlez.wrap.PointExt;
class Render extends SpriteView implements IRender {
@@ -29,12 +27,11 @@ class Render extends SpriteView implements IRender {
public var scale(get, set):Float;
public var manager(default, null):RenderManager;
@:provide static var settings:SettingsStorage;
@:provide static var network:Network;
@:provide static var settings:Settings;
private var playerId(get, never):PlayerId;
private var playerId(get, never):String;
private function get_playerId():PlayerId {
private function get_playerId():String {
// ToDo: network user
return "local";
}
@@ -64,7 +61,7 @@ class Render extends SpriteView implements IRender {
private var movePoint:FlashPoint;
@:provide var imageStorage:ImageStorage;
//@:provide var imageStorage:ImageStorage;
public function new() {
super();
@@ -123,7 +120,7 @@ class Render extends SpriteView implements IRender {
imageView.redraw();
progress.text = "Loading image";
content.addChild(progress.content);
imageStorage.resolve(state.preset.imageId).then(onImageResolved);
ImageData.fromImageId(state.preset.image).resolve().then(onImageResolved);
toUpdate();
}
@@ -163,12 +160,12 @@ class Render extends SpriteView implements IRender {
content.graphics.drawRect(0, 0, width, height);
content.graphics.endFill();
case Background.IMAGE(id):
imageStorage.resolve(id).then(result -> {
/*imageStorage.resolve(id).then(result -> {
content.graphics.clear();
content.graphics.beginBitmapFill(result);
content.graphics.drawRect(0, 0, width, height);
content.graphics.endFill();
});
});*/
}
}

View File

@@ -1,10 +1,10 @@
package ru.m.puzzlez.storage;
package ru.m.puzzlez.settings;
import hw.storage.SharedObjectStorage;
import ru.m.puzzlez.render.Background;
@:provide class SettingsStorage extends SharedObjectStorage {
private inline static var VERSION = 1;
@:provide class Settings extends SharedObjectStorage {
private inline static var VERSION = 2;
private inline static var BACKGROUND_KEY = "background";
public var background(get, set):Background;

View File

@@ -1,39 +0,0 @@
package ru.m.puzzlez.source;
import ru.m.data.IDataSource;
import flash.display.BitmapData;
import openfl.Assets;
import openfl.utils.AssetType;
import promhx.Promise;
import ru.m.puzzlez.core.Id;
class AssetSource implements IImageSource {
public static var ID:SourceId = "asset";
public var id(default, never):SourceId = ID;
private var data:Array<ImageId>;
public function new() {
}
private function resolveData():Array<ImageId> {
return [for (name in Assets.list(AssetType.IMAGE).filter((name:String) -> name.substr(0, 15) == "resources/image")) new ImageId(id, name)];
}
public function getIndexPage(page:Page):Promise<DataPage<ImageId>> {
if (data == null) {
data = resolveData();
}
// ToDo: pagination
return Promise.promise({
page: page,
total: data.length,
data: data,
});
}
public function loadImage(id:ImageId, preview:Bool = false):Promise<BitmapData> {
return Promise.promise(Assets.getBitmapData(id.id));
}
}

View File

@@ -1,40 +0,0 @@
package ru.m.puzzlez.source;
import flash.display.BitmapData;
import haxe.io.Bytes;
import promhx.Promise;
import ru.m.data.IDataSource;
import ru.m.puzzlez.core.Id;
import ru.m.puzzlez.storage.FileStorage;
class FileSource implements IImageSource {
public static var ID:SourceId = "file";
public var id(default, never):SourceId = ID;
private var storage:FileStorage;
public function new() {
storage = new FileStorage();
}
public function getIndexPage(page:Page):Promise<DataPage<ImageId>> {
return storage.getIndexPage(page).then(data -> ({page: data.page, total: data.total, data: data.data.map(item -> new ImageId(id, item))}));
}
public function loadImage(id:ImageId, preview:Bool = false):Promise<BitmapData> {
return storage.get(id.id).pipe(ImageUtil.bytesToImage);
}
public function append(data:Bytes):Promise<Dynamic> {
return storage.save(data);
}
public function remove(id:ImageId):Promise<Dynamic> {
return storage.delete(id.id);
}
public function clean():Void {
}
}

View File

@@ -1,11 +0,0 @@
package ru.m.puzzlez.source;
import flash.display.BitmapData;
import promhx.Promise;
import ru.m.data.IDataSource;
import ru.m.puzzlez.core.Id;
interface IImageSource extends IDataIndex<ImageId> {
public var id(default, never):SourceId;
public function loadImage(id:ImageId, preview:Bool = false):Promise<BitmapData>;
}

View File

@@ -1,53 +0,0 @@
package ru.m.puzzlez.source;
import flash.display.BitmapData;
import flash.utils.ByteArray;
import haxe.io.Bytes;
import hw.net.BytesLoader;
import promhx.Promise;
import ru.m.data.IDataSource;
import ru.m.pixabay.PixabayApi;
import ru.m.puzzlez.core.Id;
import ru.m.puzzlez.core.ImageListSource;
import ru.m.puzzlez.storage.CacheStorage;
class PixabaySource implements IImageSource {
public static var ID:SourceId = "pixabay";
public var id(default, never):SourceId = ID;
private var api:PixabayApi;
@:provide static var imageCache:CacheStorage;
public function new() {
api = new PixabayApi("14915210-5eae157281211e0ad28bc8def");
}
public function getIndexPage(page:Page):Promise<DataPage<ImageId>> {
return api.getPage(page).then(data -> ({page: data.page, total: data.total, data: data.data.map(item -> new ImageId(id, Std.string(item.id)))}));
}
public function loadImage(id:ImageId, preview:Bool = false):Promise<BitmapData> {
var key = '${id}_${preview}';
if (imageCache.exists(key)) {
return ImageUtil.bytesToImage(imageCache.read(key));
} else {
return api.get(Std.parseInt(id.id))
.pipe((data:PixabayImage) -> new BytesLoader().GET(preview ? data.webformatURL : data.largeImageURL))
.pipe((data:ByteArray) -> {
var bytes = Bytes.ofData(data);
imageCache.write(key, bytes);
return ImageUtil.bytesToImage(bytes);
});
}
}
public function categorySource(category:PixabayCategory):ImageListSource {
return {
title: category,
source: this,
filter: ["type" => category],
}
}
}

View File

@@ -1,66 +0,0 @@
package ru.m.puzzlez.storage;
import flash.net.SharedObject;
import haxe.io.Bytes;
#if html5
@:provide class CacheStorage {
public function new() {
}
public function exists(key:String):Bool {
return false;
}
public function read(key:String):Null<Bytes> {
return null;
}
public function write(key:String, data:Bytes):Void {
}
public function remove(key:String):Void {
}
public function clean():Void {
}
}
#else
@:provide class CacheStorage {
public function new() {
}
private inline function getSharedObject(key:String):SharedObject {
key = StringTools.replace(key, "/", "_");
key = StringTools.replace(key, ":", "_");
key = StringTools.replace(key, ".", "_");
return SharedObject.getLocal('cache/${key}');
}
public function exists(key:String):Bool {
var so = getSharedObject(key);
return so.size > 0 && Reflect.hasField(so.data, "data");
}
public function read(key:String):Null<Bytes> {
var so = getSharedObject(key);
return Bytes.ofData(Reflect.field(so.data, "data"));
}
public function write(key:String, data:Bytes):Void {
var so = getSharedObject(key);
so.setProperty("data", data.getData());
so.flush();
}
public function remove(key:String):Void {
var so = getSharedObject(key);
so.clear();
}
public function clean():Void {
//SharedObject.deleteAll("cache/");
}
}
#end

View File

@@ -1,19 +0,0 @@
package ru.m.puzzlez.storage;
import haxe.crypto.Md5;
import haxe.io.Bytes;
import ru.m.data.DataStorage;
class FileStorage extends DataStorage<String, Bytes> {
inline private static var NAME = "file";
inline private static var VERSION = 1;
public function new() {
super(
'${NAME}/${VERSION}',
new MetaBuilder<Bytes>(item -> ["id" => Md5.make(item).toHex(), "date" => Date.now().toString()]),
new EmptyConverter<String>(),
new Converter<Bytes, String>(item -> item.toHex(), data -> Bytes.ofHex(data))
);
}
}

View File

@@ -1,32 +0,0 @@
package ru.m.puzzlez.storage;
import ru.m.data.DataStorage;
import ru.m.puzzlez.core.Id;
import ru.m.puzzlez.core.ImageListSource;
import ru.m.puzzlez.proto.game.GameState;
@:provide class GameStorage extends DataStorage<ImageId, GameState> {
inline private static var NAME = "game";
inline private static var VERSION = 6;
public function new() {
super(
'${NAME}/${VERSION}',
new MetaBuilder<GameState>(item -> [
"id" => item.preset.imageId,
"status" => Std.string(item.status),
"date" => Date.now().toString()
]),
new Converter<ImageId, String>(id -> id.toString(), data -> ImageId.fromString(data)),
new ProtoConverter(GameState)
);
}
public function statusSource(status:Int):ImageListSource {
return {
title: Std.string(status), // # ToDo:
source: this,
filter: ["status" => Std.string(status)],
}
}
}

View File

@@ -1,51 +0,0 @@
package ru.m.puzzlez.storage;
import flash.display.BitmapData;
import flash.net.SharedObject;
import promhx.Promise;
import Reflect;
import ru.m.puzzlez.core.Id;
import ru.m.puzzlez.source.AssetSource;
import ru.m.puzzlez.source.FileSource;
import ru.m.puzzlez.source.IImageSource;
import ru.m.puzzlez.source.PixabaySource;
@:provide class ImageStorage {
public var sources(default, null):Map<SourceId, IImageSource>;
private var cache:Map<String, Promise<BitmapData>>;
public function new() {
sources = new Map();
cache = new Map();
register(new AssetSource());
register(new FileSource());
register(new PixabaySource());
}
public function register(source:IImageSource):Void {
sources.set(source.id, source);
}
public function read(id:ImageId):BitmapData {
var so = SharedObject.getLocal(id);
return Reflect.field(so.data, "");
}
public function write(id:ImageId, data:BitmapData):Void {
var so = SharedObject.getLocal(id);
so.setProperty("", data);
so.flush();
}
public function resolve(id:ImageId, preview:Bool = false):Promise<BitmapData> {
var key = '${id}_${preview}';
if (cache.exists(key)) {
return cache.get(key);
}
var result = sources.get(id.source).loadImage(id, preview);
cache.set(key, result);
return result;
}
}

View File

@@ -1,19 +1,18 @@
package ru.m.puzzlez.view;
import ru.m.puzzlez.proto.game.GameStatus;
import haxe.Timer;
import hw.view.frame.FrameSwitcher;
import hw.view.frame.FrameView;
import hw.view.popup.ConfirmView;
import promhx.Promise;
import ru.m.puzzlez.core.Game;
import ru.m.puzzlez.core.IGame;
import ru.m.puzzlez.net.NetworkGame;
import ru.m.puzzlez.image.Game;
import ru.m.puzzlez.image.IGame;
//import ru.m.puzzlez.net.NetworkGame;
import ru.m.puzzlez.proto.event.GameEvent;
import ru.m.puzzlez.proto.game.GameState;
import ru.m.puzzlez.proto.game.GameStatus;
import ru.m.puzzlez.render.IRender;
import ru.m.puzzlez.storage.GameStorage;
import ru.m.puzzlez.storage.SettingsStorage;
import ru.m.puzzlez.settings.Settings;
import ru.m.puzzlez.view.popup.BackgroundPopup;
import ru.m.puzzlez.view.popup.PreviewPopup;
@@ -23,8 +22,8 @@ import ru.m.puzzlez.view.popup.PreviewPopup;
@:view private var render:IRender;
private var game:IGame;
@:provide var switcher:FrameSwitcher;
@:provide var storage:GameStorage;
@:provide var settings:SettingsStorage;
// @:provide var storage:GameStorage;
@:provide var settings:Settings;
private var saveTimer:Timer;
@@ -35,7 +34,7 @@ import ru.m.puzzlez.view.popup.PreviewPopup;
override public function onShow(state:GameState):Void {
onHide();
if (state.online) {
game = new NetworkGame(state);
//game = new NetworkGame(state);
} else {
game = new Game(state);
}
@@ -69,7 +68,7 @@ import ru.m.puzzlez.view.popup.PreviewPopup;
saveTimer = null;
}
if (game != null) {
storage.save(game.state);
// storage.save(game.state);
}
}
@@ -96,7 +95,8 @@ import ru.m.puzzlez.view.popup.PreviewPopup;
(game.state.status == GameStatus.COMPLETE ? Promise.promise(true) : ConfirmView.confirm("Exit?"))
.then(result -> {
if (result) {
switcher.change(ImageListFrame.ID, storage.statusSource(game.state.status));
switcher.change(StartFrame.ID);
// switcher.change(ImageListFrame.ID, storage.statusSource(game.state.status));
}
});
}

View File

@@ -1,51 +0,0 @@
package ru.m.puzzlez.view;
import hw.view.form.ButtonView;
import hw.view.form.LabelView;
import hw.view.frame.FrameSwitcher;
import hw.view.frame.FrameView;
import ru.m.puzzlez.core.ImageListSource;
import ru.m.puzzlez.FileUtil;
import ru.m.puzzlez.source.FileSource;
import ru.m.puzzlez.storage.GameStorage;
import ru.m.puzzlez.storage.ImageStorage;
import ru.m.puzzlez.view.common.ImageDataList;
@:template class ImageListFrame extends FrameView<ImageListSource> {
public static var ID = "image_list";
@:view("header") var headerView:LabelView;
@:view("images") var imagesView:ImageDataList;
@:view var select:ButtonView;
@:provide var gameStorage:GameStorage;
@:provide var imageStorage:ImageStorage;
@:provide var switcher:FrameSwitcher;
public function new() {
super(ID);
}
override public function onShow(data:ImageListSource):Void {
imagesView.reset();
if (data != null) {
headerView.text = data.title;
// ToDo:
select.visible = Std.is(data.source, FileSource);
imagesView.page.filter = data.filter;
imagesView.source = data.source;
imagesView.refresh();
}
}
private function selectFile():Void {
FileUtil.browse().then((data:FileContent) -> {
var fileSource:FileSource = cast imageStorage.sources.get(FileSource.ID);
fileSource.append(data.content).then(_ -> imagesView.refresh());
});
}
private function back():Void {
switcher.change(StartFrame.ID);
}
}

View File

@@ -0,0 +1,46 @@
package ru.m.puzzlez.view;
import hw.view.form.LabelView;
import hw.view.frame.FrameSwitcher;
import hw.view.frame.FrameView;
import ru.m.puzzlez.image.GameUtil;
import ru.m.puzzlez.image.ImageSourceBundle;
import ru.m.puzzlez.proto.game.ImageId;
import ru.m.puzzlez.view.common.ImageDataList;
typedef ImageSourceConfig = {
var title:String;
var sourceId:String;
}
@:template class ImageSourceFrame extends FrameView<ImageSourceConfig> {
public static var ID = "source";
@:view var header:LabelView;
@:view var images:ImageDataList;
@:provide var switcher:FrameSwitcher;
@:provide var sourceBundle:ImageSourceBundle;
public function new() {
super(ID);
}
override public function onShow(data:ImageSourceConfig):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 {
var state = GameUtil.buildState(GameUtil.buildPreset(imageId, 2, 2));
switcher.change(GameFrame.ID, state);
}
private function back():Void {
switcher.change(StartFrame.ID);
}
}

View File

@@ -7,11 +7,7 @@ views:
- id: images
$type: ru.m.puzzlez.view.common.ImageDataList
geometry.stretch: true
- id: select
$type: hw.view.form.ButtonView
text: Select...
+onPress: ~selectFile()
visible: false
+onImageSelect: ~start
- $type: hw.view.form.ButtonView
text: Back
geometry.position: absolute

View File

@@ -1,14 +1,14 @@
package ru.m.puzzlez.view;
import ru.m.puzzlez.net.Network;
import hw.geom.IntPoint;
import hw.view.data.DataView;
import hw.view.form.ToggleButtonView;
import hw.view.frame.FrameSwitcher;
import hw.view.frame.FrameView;
import ru.m.puzzlez.core.GameUtil;
import ru.m.puzzlez.core.Id;
import ru.m.puzzlez.storage.ImageStorage;
import ru.m.puzzlez.image.GameUtil;
import ru.m.puzzlez.net.Network;
import ru.m.puzzlez.proto.game.ImageId;
import ru.m.puzzlez.settings.ImageStorage;
import ru.m.puzzlez.view.common.PresetView;
@:template class PresetFrame extends FrameView<ImageId> {

View File

@@ -7,7 +7,6 @@ import hw.view.form.ButtonView;
import hw.view.form.LabelView;
import hw.view.frame.FrameSwitcher;
import hw.view.group.VGroupView;
import ru.m.puzzlez.net.Network;
@:template class PuzzlezAppView extends VGroupView {
@@ -16,7 +15,6 @@ import ru.m.puzzlez.net.Network;
@:view("user") var userLabel:LabelView;
@:provide static var switcher:FrameSwitcher;
@:provide static var network:Network;
@:provide static var app:App;
public function new() {
@@ -28,12 +26,11 @@ import ru.m.puzzlez.net.Network;
stage.addEventListener(KeyboardEvent.KEY_DOWN, (event:KeyboardEvent) -> {
switch event.keyCode {
case Keyboard.ESCAPE:
switcher.change(StartFrame.ID);
//switcher.change(StartFrame.ID);
case Keyboard.F:
app.fullScreen = !app.fullScreen;
case _:
}
});
network.userSignal.connect(user -> userLabel.text = user.name);
}
}

View File

@@ -6,8 +6,8 @@ views:
style: dark
factory:
_start_: {$class: ru.m.puzzlez.view.StartFrame}
_image_list_: {$class: ru.m.puzzlez.view.ImageListFrame}
_preset_: {$class: ru.m.puzzlez.view.PresetFrame}
_source_: {$class: ru.m.puzzlez.view.ImageSourceFrame}
#_preset_: {$class: ru.m.puzzlez.view.PresetFrame}
_game_: {$class: ru.m.puzzlez.view.GameFrame}
- $type: hw.view.group.HGroupView
geometry.position: absolute

View File

@@ -1,101 +1,33 @@
package ru.m.puzzlez.view;
import hw.view.data.DataView;
import hw.view.form.ButtonView;
import hw.view.frame.FrameSwitcher;
import hw.view.frame.FrameView;
import ru.m.data.IDataSource;
import ru.m.pixabay.PixabayApi;
import ru.m.puzzlez.core.ImageListSource;
import ru.m.puzzlez.net.Network;
import ru.m.puzzlez.proto.game.GameStatus;
import ru.m.puzzlez.proto.pack.NotificationResponse;
import ru.m.puzzlez.source.AssetSource;
import ru.m.puzzlez.source.FileSource;
import ru.m.puzzlez.source.PixabaySource;
import ru.m.puzzlez.storage.GameStorage;
import ru.m.puzzlez.storage.ImageStorage;
import ru.m.puzzlez.view.ImageSourceFrame;
import ru.m.update.Updater;
@:template class StartFrame extends FrameView<Dynamic> {
public static var ID = "start";
@:view var sources:DataView<ImageListSource, ButtonView>;
@:view("load") var loadButton:ButtonView;
@:view("complete") var completeButton:ButtonView;
@:view("network") var networkButton:ButtonView;
@:view("update") var updateButton:ButtonView;
@:view var updateButton:ButtonView;
@:provide var storage:ImageStorage;
@:provide var switcher:FrameSwitcher;
@:provide var gameStorage:GameStorage;
@:provide var network:Network;
@:provide static var appUpdater:Updater;
public function new() {
super(ID);
var data:Array<ImageListSource> = [];
data.push({title: "Assets", source: storage.sources.get(AssetSource.ID)});
data.push({title: "Files", source: storage.sources.get(FileSource.ID)});
var pixabay:PixabaySource = cast storage.sources.get(PixabaySource.ID);
for (type in AbstractEnumTools.getValues(PixabayCategory)) {
data.push(pixabay.categorySource(type));
}
sources.data = data;
}
private function refresh():Void {
var startedRequest:Page = {index: 0, count: 0, filter: ["status" => Std.string(GameStatus.STARTED)]};
gameStorage.getIndexPage(startedRequest).then(page -> {
var total = page.total;
loadButton.text = 'Resume (${total})';
loadButton.disabled = total == 0;
});
var completeRequest:Page = {index: 0, count: 0, filter: ["status" => Std.string(GameStatus.COMPLETE)]};
gameStorage.getIndexPage(completeRequest).then(page -> {
var total = page.total;
completeButton.text = 'Complete (${total})';
completeButton.disabled = total == 0;
});
network.notificationSignal.next().then(onNotification);
}
private function onNotification(notification:NotificationResponse):Void {
var total = notification.games;
networkButton.text = 'Network (${total})';
networkButton.disabled = total == 0;
public function openSource(source:ImageSourceConfig):Void {
switcher.change(ImageSourceFrame.ID, source);
}
override public function onShow(data:Dynamic):Void {
refresh();
appUpdater.check().then((info:Null<PackageInfo>) -> {
if (info != null) {
updateButton.visible = true;
updateButton.text = 'Update ${info.version}';
}
}).catchError(error -> L.w('Update', 'failed: ${error}'));
network.notificationSignal.connect(onNotification);
}
override public function onHide():Void {
network.notificationSignal.disconnect(onNotification);
}
private function sourceViewFactory(index:Int, source:ImageListSource):ButtonView {
var result = new ButtonView();
result.text = source.title;
return result;
}
private function load(source:ImageListSource):Void {
switcher.change(ImageListFrame.ID, source);
}
private function openGames(status:Int):Void {
switcher.change(ImageListFrame.ID, gameStorage.statusSource(status));
}
private function openNetwork():Void {
switcher.change(ImageListFrame.ID, {title: 'Network', source: network});
}
}

View File

@@ -15,43 +15,16 @@ views:
- $type: hw.view.form.LabelView
text: $r:text:app.name
font.size: 50
- id: sources
$type: hw.view.data.DataView
layout:
$type: hw.view.layout.TailLayout
rowSize: 5
margin: 10
vAlign: middle
geometry.stretch: true
factory: ~sourceViewFactory
+onDataSelect: ~load
geometry.margin: 5
overflow.y: scroll
- $type: hw.view.group.HGroupView
geometry.width: 100%
layout.vAlign: middle
layout.margin: 10
views:
- id: load
$type: hw.view.form.ButtonView
text: Load
+onPress: ~openGames(1)
- id: complete
$type: hw.view.form.ButtonView
text: Complete
+onPress: ~openGames(2)
- id: network
$type: hw.view.form.ButtonView
text: Network
+onPress: ~openNetwork()
- $type: hw.view.SpriteView
geometry.width: 100%
- $type: hw.view.form.ButtonView
text: Pixabay
geometry.hAlign: center
+onPress: "~openSource({title: 'Pixabay', sourceId: 'pixabay'})"
- $type: hw.view.form.LabelView
text: $r:text:app.version
geometry.position: absolute
geometry.hAlign: right
geometry.vAlign: top
- id: update
- id: updateButton
$type: hw.view.form.ButtonView
style: button.active
geometry.position: absolute

View File

@@ -1,34 +1,30 @@
package ru.m.puzzlez.view.common;
import ru.m.puzzlez.net.Network;
import hw.signal.Signal;
import hw.view.data.DataView;
import hw.view.form.ToggleButtonView;
import hw.view.frame.FrameSwitcher;
import hw.view.group.VGroupView;
import hw.view.popup.ConfirmView;
import ru.m.data.IDataSource;
import ru.m.puzzlez.core.Id;
import ru.m.puzzlez.source.FileSource;
import ru.m.puzzlez.storage.GameStorage;
import ru.m.puzzlez.storage.ImageStorage;
import ru.m.puzzlez.view.common.PuzzleImageView;
import ru.m.data.DataSource.DataPage;
import ru.m.data.DataSource.Page;
import ru.m.puzzlez.image.ImageSource;
import ru.m.puzzlez.proto.game.ImageId;
@:template class ImageDataList extends VGroupView {
public var source:IDataIndex<ImageId>;
public var source:ImageSource;
public var page:Page;
@:view("images") var imagesView:ActionDataView<ImageId, PuzzleImageView, Action>;
@:view("images") var imagesView:DataView<ImageId, ImageIdView>;
@:view("paginator") var paginatorView:PaginatorView;
private var loading:LoadingWrapper;
@:provide var switcher:FrameSwitcher;
@:provide var gameStorage:GameStorage;
@:provide var imageStorage:ImageStorage;
@:provide var network:Network;
public var data(default, set):DataPage<ImageId>;
public var onImageSelect(default, null):Signal<ImageId> = new Signal();
private function set_data(value:DataPage<ImageId>):DataPage<ImageId> {
data = value;
imagesView.data = data.data;
@@ -39,7 +35,7 @@ import ru.m.puzzlez.view.common.PuzzleImageView;
public function new() {
super();
loading = new LoadingWrapper(imagesView);
page = {index: 0, count: 6, order: [{key: "date", reverse: true}]};
page = {index: 0, count: 6};
}
private function pageFactory(index:Int, value:Int):ToggleButtonView {
@@ -49,40 +45,8 @@ import ru.m.puzzlez.view.common.PuzzleImageView;
return result;
}
private function start(imageId:ImageId):Void {
gameStorage.get(imageId).then(state -> {
if (state != null) {
switcher.change(GameFrame.ID, state);
} else {
switcher.change(PresetFrame.ID, imageId);
}
});
}
private function onAction(imageId:ImageId, action:Action):Void {
switch action {
case REMOVE:
var fileSource:FileSource = cast imageStorage.sources.get(FileSource.ID);
if (fileSource != null) {
ConfirmView.confirm("Delete image?").then(result -> {
if (result) {
fileSource.remove(imageId).then(_ -> refresh());
}
});
}
case CLEAN:
ConfirmView.confirm("Delete state?").then(result -> {
if (result) {
gameStorage.delete(imageId).then(_ -> refresh());
}
});
case JOIN:
// ToDo:
}
}
public function refresh():Void {
loading.promise = source.getIndexPage(page).then(data -> this.data = data);
loading.promise = source.getPage(page).then(data -> this.data = data);
}
public function reset():Void {

View File

@@ -1,16 +1,15 @@
---
views:
- id: images
$type: hw.view.data.ActionDataView
$type: hw.view.data.DataView
layout:
$type: hw.view.layout.TailLayout
rowSize: 3
margin: 5
vAlign: middle
geometry.stretch: true
factory: ~ru.m.puzzlez.view.common.PuzzleImageView.factory
+onDataSelect: ~start
+onDataAction: ~onAction
factory: ~ru.m.puzzlez.view.common.ImageIdView.factory
+onDataSelect: ~onImageSelect.emit
geometry.margin: 5
overflow.y: scroll
- id: paginator

View File

@@ -0,0 +1,30 @@
package ru.m.puzzlez.view.common;
import hw.view.utils.DrawUtil;
import hw.view.ImageView;
import ru.m.puzzlez.image.ImageData;
import ru.m.puzzlez.proto.game.ImageId;
class ImageIdView extends ImageView {
public var imageId(default, set):ImageId;
private function set_imageId(value:ImageId):ImageId {
imageId = value;
ImageData.fromImageId(imageId).resolve().then(data -> this.image = data);
return imageId;
}
public function new(imageId:ImageId = null) {
super();
style = "view";
stretch = false;
fillType = FillType.COVER;
if (imageId != null) {
this.imageId = imageId;
}
}
public static function factory(index:Int, value:ImageId):ImageIdView {
return new ImageIdView(value);
}
}

View File

@@ -1,10 +1,10 @@
package ru.m.puzzlez.view.common;
import ru.m.data.DataSource;
import hw.signal.Signal;
import hw.view.data.DataView;
import hw.view.form.ToggleButtonView;
import hw.view.layout.TailLayout;
import ru.m.data.IDataSource.DataPage;
enum PaginatorAction {
START;

View File

@@ -1,17 +1,16 @@
package ru.m.puzzlez.view.common;
import ru.m.puzzlez.wrap.RectangleExt;
import ru.m.puzzlez.proto.game.GameState;
import flash.display.Graphics;
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Shape;
import hw.view.group.GroupView;
import ru.m.puzzlez.image.ImageData;
import ru.m.puzzlez.proto.game.GameState;
import ru.m.puzzlez.render.part.IPartBuilder;
import ru.m.puzzlez.render.RenderUtil;
import ru.m.puzzlez.storage.ImageStorage;
import ru.m.puzzlez.wrap.RectangleExt;
class PresetView extends GroupView {
@:provide var imageStorage:ImageStorage;
@:provide static var builder:IPartBuilder;
public var scale(get, set):Float;
@@ -33,7 +32,7 @@ class PresetView extends GroupView {
state = value;
this.image = null;
table.graphics.clear();
loading.promise = imageStorage.resolve(state.preset.imageId).then(image -> {
loading.promise = ImageData.fromImageId(state.preset.image).resolve().then(image -> {
this.image = RenderUtil.cropImage(image, state.preset.imageRect);
toRedraw();
toUpdate();

View File

@@ -1,85 +0,0 @@
package ru.m.puzzlez.view.common;
import ru.m.puzzlez.net.Network;
import hw.view.data.DataView;
import hw.view.form.ButtonView;
import hw.view.form.LabelView;
import hw.view.group.GroupView;
import hw.view.ImageView;
import ru.m.puzzlez.core.GameUtil;
import ru.m.puzzlez.core.Id;
import ru.m.puzzlez.source.FileSource;
import ru.m.puzzlez.storage.GameStorage;
import ru.m.puzzlez.storage.ImageStorage;
enum Action {
CLEAN;
REMOVE;
JOIN;
}
@:template class PuzzleImageView extends GroupView {
public var imageId(default, set):ImageId;
private function set_imageId(value:ImageId):ImageId {
if (imageId != value) {
imageId = value;
loading.promise = imageStorage.resolve(imageId, true).then(data -> imageView.image = data);
}
return imageId;
}
public var text(default, set):String;
private function set_text(value:String):String {
if (text != value) {
text = value;
labelView.text = text;
}
return text;
}
@:view("image") var imageView:ImageView;
@:view("label") var labelView:LabelView;
@:view("clean") var cleanButton:ButtonView;
@:view("remove") var removeButton:ButtonView;
@:view("join") var joinButton:ButtonView;
@:provide static var imageStorage:ImageStorage;
@:provide static var gameStorage:GameStorage;
@:provide static var network:Network;
private var loading:LoadingWrapper;
public function new() {
super();
cleanButton.visible = false;
removeButton.visible = false;
joinButton.visible = false;
loading = new LoadingWrapper(this);
}
private function emit(action:Action):Void {
var dataView:ActionDataView<Dynamic, PuzzleImageView, Action> = Std.instance(parent, ActionDataView);
if (dataView != null) {
var index = dataView.dataViews.indexOf(this);
dataView.onDataAction.emit(dataView.data[index], action);
}
}
public static function factory(index:Int, imageId:ImageId):PuzzleImageView {
var result = new PuzzleImageView();
result.imageId = imageId;
gameStorage.get(imageId).then(state -> {
if (state != null) {
var progress = GameUtil.calcProgress(state);
result.text = '${progress.complete}/${progress.total}';
result.cleanButton.visible = true;
} else if (imageId.source == FileSource.ID) {
result.removeButton.visible = true;
}
});
// ToDo:
result.joinButton.visible = false;
return result;
}
}

View File

@@ -1,25 +0,0 @@
---
style: view
views:
- id: image
$type: hw.view.ImageView
geometry.stretch: true
stretch: false
fillType: COVER
- id: label
$type: hw.view.form.LabelView
- id: remove
$type: hw.view.form.ButtonView
propagation: false
style: icon.control.small.close.red
+onPress: ~emit(Action.REMOVE)
- id: clean
$type: hw.view.form.ButtonView
propagation: false
style: icon.control.small.close.orange
+onPress: ~emit(Action.CLEAN)
- id: join
$type: hw.view.form.ButtonView
propagation: false
style: icon.control.small.close.green
+onPress: ~emit(Action.JOIN)

View File

@@ -10,9 +10,9 @@ import hw.view.utils.DrawUtil;
import openfl.Assets;
import openfl.utils.AssetType;
import promhx.Promise;
import ru.m.puzzlez.core.Id.ImageId;
import ru.m.puzzlez.proto.game.ImageId;
import ru.m.puzzlez.render.Background;
import ru.m.puzzlez.storage.ImageStorage;
// import ru.m.puzzlez.settings.ImageStorage;
@:singleton @:template class BackgroundPopup extends PopupView<Background> {
@@ -42,7 +42,7 @@ import ru.m.puzzlez.storage.ImageStorage;
public var selected(default, set):Background;
@:provide static var imageStorage:ImageStorage;
// @:provide static var imageStorage:ImageStorage;
public function new() {
super();
@@ -50,7 +50,7 @@ import ru.m.puzzlez.storage.ImageStorage;
var textures = [];
for (name in Assets.list(AssetType.IMAGE)) {
if (StringTools.startsWith(name, 'resources/texture')) {
textures.push(new ImageId('asset', name));
textures.push(new ImageId().setSource('asset').setId(name));
}
}
texturesView.data = textures;
@@ -64,10 +64,10 @@ import ru.m.puzzlez.storage.ImageStorage;
case COLOR(color):
selectedView.skin = Skin.color(color);
case IMAGE(id):
imageStorage.resolve(id).then(result -> {
/*imageStorage.resolve(id).then(result -> {
selectedView.skin = Skin.bitmap(result, REPEAT);
selectedView.toRedraw();
});
});*/
}
selectedView.toRedraw();
return selected;