[refactoring] #1
This commit is contained in:
22
src/app/haxe/ru/m/data/DataSource.hx
Normal file
22
src/app/haxe/ru/m/data/DataSource.hx
Normal 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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -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> {
|
||||
|
||||
@@ -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();
|
||||
|
||||
26
src/app/haxe/ru/m/puzzlez/image/AssetImageSource.hx
Normal file
26
src/app/haxe/ru/m/puzzlez/image/AssetImageSource.hx
Normal 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)));
|
||||
}
|
||||
}
|
||||
50
src/app/haxe/ru/m/puzzlez/image/ImageData.hx
Normal file
50
src/app/haxe/ru/m/puzzlez/image/ImageData.hx
Normal 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);
|
||||
}
|
||||
}
|
||||
18
src/app/haxe/ru/m/puzzlez/image/ImageSource.hx
Normal file
18
src/app/haxe/ru/m/puzzlez/image/ImageSource.hx
Normal 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>;
|
||||
}
|
||||
20
src/app/haxe/ru/m/puzzlez/image/ImageSourceBundle.hx
Normal file
20
src/app/haxe/ru/m/puzzlez/image/ImageSourceBundle.hx
Normal 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);
|
||||
}
|
||||
}
|
||||
45
src/app/haxe/ru/m/puzzlez/image/PixabayImageSource.hx
Normal file
45
src/app/haxe/ru/m/puzzlez/image/PixabayImageSource.hx
Normal 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
38
src/app/haxe/ru/m/puzzlez/image/StorageCache.hx
Normal file
38
src/app/haxe/ru/m/puzzlez/image/StorageCache.hx
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -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],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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)],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
46
src/app/haxe/ru/m/puzzlez/view/ImageSourceFrame.hx
Normal file
46
src/app/haxe/ru/m/puzzlez/view/ImageSourceFrame.hx
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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> {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
30
src/app/haxe/ru/m/puzzlez/view/common/ImageIdView.hx
Normal file
30
src/app/haxe/ru/m/puzzlez/view/common/ImageIdView.hx
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
package ru.m.puzzlez.core;
|
||||
|
||||
typedef SourceId = String;
|
||||
|
||||
abstract ImageId({source:SourceId, id:String}) {
|
||||
public var source(get, never):SourceId;
|
||||
|
||||
private inline function get_source():SourceId return this.source;
|
||||
|
||||
public var id(get, never):String;
|
||||
|
||||
private inline function get_id():String return this.id;
|
||||
|
||||
public function new(source:SourceId, id:String) {
|
||||
this = {source: source, id: id};
|
||||
}
|
||||
|
||||
@:from public static function fromString(value:String):ImageId {
|
||||
var args = value.split("_");
|
||||
return new ImageId(args[0], args[1]);
|
||||
}
|
||||
|
||||
@:to public function toString():String {
|
||||
return '${this.source}_${this.id}';
|
||||
}
|
||||
}
|
||||
|
||||
typedef PlayerId = String;
|
||||
|
||||
typedef PartId = Int;
|
||||
@@ -1,10 +0,0 @@
|
||||
package ru.m.puzzlez.core;
|
||||
|
||||
import ru.m.data.IDataSource;
|
||||
import ru.m.puzzlez.core.Id;
|
||||
|
||||
typedef ImageListSource = {
|
||||
var title:String;
|
||||
var source:IDataIndex<ImageId>;
|
||||
@:optional var filter:Filter;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package ru.m.puzzlez.core;
|
||||
package ru.m.puzzlez.image;
|
||||
|
||||
import ru.m.puzzlez.proto.event.GameComplete;
|
||||
import ru.m.puzzlez.proto.event.GameChange;
|
||||
@@ -1,7 +1,7 @@
|
||||
package ru.m.puzzlez.core;
|
||||
package ru.m.puzzlez.image;
|
||||
|
||||
import ru.m.puzzlez.proto.core.Point;
|
||||
import hw.signal.Signal;
|
||||
import ru.m.puzzlez.proto.core.Point;
|
||||
import ru.m.puzzlez.proto.event.gameaction.Action;
|
||||
import ru.m.puzzlez.proto.event.GameAction;
|
||||
import ru.m.puzzlez.proto.event.GameEvent;
|
||||
@@ -1,7 +1,7 @@
|
||||
package ru.m.puzzlez.core;
|
||||
package ru.m.puzzlez.image;
|
||||
|
||||
import ru.m.puzzlez.core.Id;
|
||||
import ru.m.puzzlez.core.Side;
|
||||
import ru.m.puzzlez.proto.game.ImageId;
|
||||
import ru.m.puzzlez.image.Side;
|
||||
import ru.m.puzzlez.proto.core.IntPoint;
|
||||
import ru.m.puzzlez.proto.core.Point;
|
||||
import ru.m.puzzlez.proto.core.Rectangle;
|
||||
@@ -72,7 +72,7 @@ class GameUtil {
|
||||
return Math.isNaN(size) ? maxValue : size < 1 ? 1 : size > maxValue ? maxValue : size;
|
||||
}
|
||||
|
||||
public static function buildPreset(imageId:ImageId, width:Int = 8, height:Int = MAX_SIZE):GamePreset {
|
||||
public static function buildPreset(image: ImageId, width:Int = 8, height:Int = MAX_SIZE):GamePreset {
|
||||
width = normilizeSize(width);
|
||||
height = normilizeSize(height);
|
||||
var offsetX = 500;
|
||||
@@ -90,7 +90,7 @@ class GameUtil {
|
||||
.setWidth(imageRect.width + offsetX * 2)
|
||||
.setHeight(imageRect.height + offsetY * 2);
|
||||
return new GamePreset()
|
||||
.setImageId(imageId)
|
||||
.setImage(image)
|
||||
.setGrid(new IntPoint().setX(width).setY(height))
|
||||
.setTableRect(tableRect)
|
||||
.setImageRect(imageRect);
|
||||
@@ -1,4 +1,4 @@
|
||||
package ru.m.puzzlez.core;
|
||||
package ru.m.puzzlez.image;
|
||||
|
||||
import hw.signal.Signal;
|
||||
import ru.m.puzzlez.proto.event.GameAction;
|
||||
@@ -1,4 +1,4 @@
|
||||
package ru.m.puzzlez.core;
|
||||
package ru.m.puzzlez.image;
|
||||
|
||||
enum Side {
|
||||
TOP;
|
||||
@@ -4,6 +4,11 @@ import "core.proto";
|
||||
|
||||
package ru.m.puzzlez.proto.game;
|
||||
|
||||
message ImageId {
|
||||
string source = 1;
|
||||
string id = 2;
|
||||
}
|
||||
|
||||
enum BoundType {
|
||||
NONE = 0;
|
||||
OUT = 1;
|
||||
@@ -39,7 +44,7 @@ message Part {
|
||||
}
|
||||
|
||||
message GamePreset {
|
||||
string imageId = 1;
|
||||
ImageId image = 1;
|
||||
ru.m.puzzlez.proto.core.IntPoint grid = 2;
|
||||
ru.m.puzzlez.proto.core.Rectangle tableRect = 3;
|
||||
ru.m.puzzlez.proto.core.Rectangle imageRect = 4;
|
||||
@@ -53,9 +58,9 @@ enum GameStatus {
|
||||
|
||||
message GameState {
|
||||
string id = 1;
|
||||
GameStatus status = 2;
|
||||
GamePreset preset = 3;
|
||||
repeated ru.m.puzzlez.proto.core.User users = 4;
|
||||
repeated Part parts = 5;
|
||||
bool online = 6;
|
||||
GameStatus status = 3;
|
||||
GamePreset preset = 4;
|
||||
repeated ru.m.puzzlez.proto.core.User users = 5;
|
||||
repeated Part parts = 6;
|
||||
bool online = 7;
|
||||
}
|
||||
|
||||
@@ -23,11 +23,13 @@ message AuthResponse {
|
||||
ru.m.puzzlez.proto.core.User user = 1;
|
||||
}
|
||||
|
||||
message GameCreateRequest {
|
||||
bytes image = 1;
|
||||
ru.m.puzzlez.proto.game.GamePreset preset = 2;
|
||||
}
|
||||
|
||||
message GameJoinRequest {
|
||||
oneof content {
|
||||
ru.m.puzzlez.proto.game.GamePreset preset = 1;
|
||||
string gameId = 2;
|
||||
}
|
||||
string gameId = 1;
|
||||
}
|
||||
|
||||
message GameJoinResponse {
|
||||
@@ -67,6 +69,7 @@ message Request {
|
||||
oneof content {
|
||||
AuthRequest auth = 10;
|
||||
GameListRequest list = 20;
|
||||
GameCreateRequest create = 25;
|
||||
GameJoinRequest join = 30;
|
||||
GameLeaveRequest leave = 40;
|
||||
GameActionRequest action = 100;
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
package ru.m.puzzlez;
|
||||
|
||||
import ru.m.puzzlez.proto.pack.GameCreateRequest;
|
||||
import ru.m.puzzlez.proto.pack.GameListResponse;
|
||||
import ru.m.puzzlez.proto.pack.GameListRequest;
|
||||
import hw.connect.session.ProtoSession;
|
||||
import hw.log.BaseLogger.LoggerUtil;
|
||||
import ru.m.puzzlez.core.Game;
|
||||
import ru.m.puzzlez.core.GameUtil;
|
||||
import ru.m.puzzlez.image.Game;
|
||||
import ru.m.puzzlez.image.GameUtil;
|
||||
import ru.m.puzzlez.proto.core.User;
|
||||
import ru.m.puzzlez.proto.event.GameAction;
|
||||
import ru.m.puzzlez.proto.event.GameEvent;
|
||||
import ru.m.puzzlez.proto.event.gameplayer.GamePlayerAction;
|
||||
import ru.m.puzzlez.proto.event.GamePlayer;
|
||||
import ru.m.puzzlez.proto.game.GamePreset;
|
||||
import ru.m.puzzlez.proto.pack.AuthRequest;
|
||||
import ru.m.puzzlez.proto.pack.AuthResponse;
|
||||
import ru.m.puzzlez.proto.pack.ErrorResponse;
|
||||
@@ -74,8 +74,8 @@ class GameSession extends ProtoSession<Response, Request> {
|
||||
));
|
||||
}
|
||||
|
||||
private function create(preset:GamePreset):Void {
|
||||
var game = new Game(GameUtil.buildState(preset).setOnline(true));
|
||||
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);
|
||||
@@ -111,12 +111,10 @@ class GameSession extends ProtoSession<Response, Request> {
|
||||
auth(request.auth);
|
||||
} else if (request.hasList()) {
|
||||
list(request.list);
|
||||
} else if (request.hasCreate()) {
|
||||
create(request.create);
|
||||
} else if (request.hasJoin()) {
|
||||
if (request.join.hasPreset()) {
|
||||
create(request.join.preset);
|
||||
} else if (request.join.hasGameId()) {
|
||||
join(request.join.gameId);
|
||||
}
|
||||
} else if (request.hasLeave()) {
|
||||
leave();
|
||||
} else if (request.hasAction()) {
|
||||
|
||||
Reference in New Issue
Block a user