Clean up asset upload functionality
This commit is contained in:
parent
b7a27944cf
commit
a8063a74d7
6 changed files with 2940 additions and 796 deletions
|
@ -4,7 +4,7 @@ import 'dart:math';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:contacts_plus_plus/models/records/asset_digest.dart';
|
import 'package:contacts_plus_plus/models/records/asset_digest.dart';
|
||||||
import 'package:contacts_plus_plus/models/records/image_template.dart';
|
import 'package:contacts_plus_plus/models/records/json_template.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ class RecordApi {
|
||||||
final imageData = await decodeImageFromList(imageDigest.data);
|
final imageData = await decodeImageFromList(imageDigest.data);
|
||||||
|
|
||||||
final objectJson = jsonEncode(
|
final objectJson = jsonEncode(
|
||||||
ImageTemplate(imageUri: imageDigest.dbUri, width: imageData.width, height: imageData.height).data);
|
JsonTemplate.image(imageUri: imageDigest.dbUri, width: imageData.width, height: imageData.height).data);
|
||||||
final objectBytes = Uint8List.fromList(utf8.encode(objectJson));
|
final objectBytes = Uint8List.fromList(utf8.encode(objectJson));
|
||||||
|
|
||||||
final objectDigest = await AssetDigest.fromData(objectBytes, "${basenameWithoutExtension(image.path)}.json");
|
final objectDigest = await AssetDigest.fromData(objectBytes, "${basenameWithoutExtension(image.path)}.json");
|
||||||
|
@ -183,4 +183,37 @@ class RecordApi {
|
||||||
progressCallback?.call(1);
|
progressCallback?.call(1);
|
||||||
return record;
|
return record;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<Record> uploadRawFile(ApiClient client, {required File file, required String machineId, void Function(double progress)? progressCallback}) async {
|
||||||
|
progressCallback?.call(0);
|
||||||
|
final fileDigest = await AssetDigest.fromData(await file.readAsBytes(), basename(file.path));
|
||||||
|
|
||||||
|
final objectJson = jsonEncode(JsonTemplate.rawFile(assetUri: fileDigest.dbUri, filename: fileDigest.name).data);
|
||||||
|
final objectBytes = Uint8List.fromList(utf8.encode(objectJson));
|
||||||
|
|
||||||
|
final objectDigest = await AssetDigest.fromData(objectBytes, "${basenameWithoutExtension(file.path)}.json");
|
||||||
|
|
||||||
|
final digests = [fileDigest, objectDigest];
|
||||||
|
|
||||||
|
final record = Record.fromRequiredData(
|
||||||
|
recordType: RecordType.texture,
|
||||||
|
userId: client.userId,
|
||||||
|
machineId: machineId,
|
||||||
|
assetUri: objectDigest.dbUri,
|
||||||
|
filename: fileDigest.name,
|
||||||
|
thumbnailUri: JsonTemplate.thumbUrl,
|
||||||
|
digests: digests,
|
||||||
|
);
|
||||||
|
progressCallback?.call(.1);
|
||||||
|
final status = await tryPreprocessRecord(client, record: record);
|
||||||
|
final toUpload = status.resultDiffs.whereNot((element) => element.isUploaded);
|
||||||
|
progressCallback?.call(.2);
|
||||||
|
|
||||||
|
await uploadAssets(
|
||||||
|
client,
|
||||||
|
assets: digests.where((digest) => toUpload.any((diff) => digest.asset.hash == diff.hash)).toList(),
|
||||||
|
progressCallback: (progress) => progressCallback?.call(.2 + progress * .6));
|
||||||
|
progressCallback?.call(1);
|
||||||
|
return record;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,757 +0,0 @@
|
||||||
import 'dart:ui';
|
|
||||||
|
|
||||||
import 'package:uuid/uuid.dart';
|
|
||||||
|
|
||||||
class ImageTemplate {
|
|
||||||
late final Map data;
|
|
||||||
|
|
||||||
ImageTemplate({required String imageUri, required int width, required int height}) {
|
|
||||||
final texture2dUid = const Uuid().v4();
|
|
||||||
final quadMeshUid = const Uuid().v4();
|
|
||||||
final quadMeshSizeUid = const Uuid().v4();
|
|
||||||
final materialId = const Uuid().v4();
|
|
||||||
final boxColliderSizeUid = const Uuid().v4();
|
|
||||||
data = {
|
|
||||||
"Object": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Components": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
{
|
|
||||||
"Type": "FrooxEngine.Grabbable",
|
|
||||||
"Data": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"persistent-ID": const Uuid().v4(),
|
|
||||||
"UpdateOrder": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0
|
|
||||||
},
|
|
||||||
"Enabled": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"ReparentOnRelease": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"PreserveUserSpace": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"DestroyOnRelease": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"GrabPriority": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0
|
|
||||||
},
|
|
||||||
"GrabPriorityWhenGrabbed": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": null
|
|
||||||
},
|
|
||||||
"CustomCanGrabCheck": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": {
|
|
||||||
"Target": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"EditModeOnly": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"AllowSteal": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"DropOnDisable": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"ActiveUserFilter": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": "Disabled"
|
|
||||||
},
|
|
||||||
"OnlyUsers": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": []
|
|
||||||
},
|
|
||||||
"Scalable": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"Receivable": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"AllowOnlyPhysicalGrab": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"_grabber": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": null
|
|
||||||
},
|
|
||||||
"_lastParent": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": null
|
|
||||||
},
|
|
||||||
"_lastParentIsUserSpace": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"__legacyActiveUserRootOnly-ID": const Uuid().v4()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Type": "FrooxEngine.StaticTexture2D",
|
|
||||||
"Data": {
|
|
||||||
"ID": texture2dUid,
|
|
||||||
"persistent-ID": const Uuid().v4(),
|
|
||||||
"UpdateOrder": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0
|
|
||||||
},
|
|
||||||
"Enabled": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"URL": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": "@$imageUri"
|
|
||||||
},
|
|
||||||
"FilterMode": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": "Anisotropic"
|
|
||||||
},
|
|
||||||
"AnisotropicLevel": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 16
|
|
||||||
},
|
|
||||||
"Uncompressed": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"DirectLoad": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"ForceExactVariant": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"PreferredFormat": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": null
|
|
||||||
},
|
|
||||||
"MipMapBias": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0.0
|
|
||||||
},
|
|
||||||
"IsNormalMap": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"WrapModeU": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": "Repeat"
|
|
||||||
},
|
|
||||||
"WrapModeV": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": "Repeat"
|
|
||||||
},
|
|
||||||
"PowerOfTwoAlignThreshold": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0.05
|
|
||||||
},
|
|
||||||
"CrunchCompressed": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"MaxSize": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": null
|
|
||||||
},
|
|
||||||
"MipMaps": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"MipMapFilter": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": "Box"
|
|
||||||
},
|
|
||||||
"Readable": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Type": "FrooxEngine.ItemTextureThumbnailSource",
|
|
||||||
"Data": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"persistent-ID": const Uuid().v4(),
|
|
||||||
"UpdateOrder": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0
|
|
||||||
},
|
|
||||||
"Enabled": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"Texture": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": texture2dUid
|
|
||||||
},
|
|
||||||
"Crop": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Type": "FrooxEngine.SnapPlane",
|
|
||||||
"Data": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"persistent-ID": const Uuid().v4(),
|
|
||||||
"UpdateOrder": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0
|
|
||||||
},
|
|
||||||
"Enabled": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"Normal": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
1.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"SnapParent": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Type": "FrooxEngine.ReferenceProxy",
|
|
||||||
"Data": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"persistent-ID": const Uuid().v4(),
|
|
||||||
"UpdateOrder": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0
|
|
||||||
},
|
|
||||||
"Enabled": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"Reference": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": texture2dUid
|
|
||||||
},
|
|
||||||
"SpawnInstanceOnTrigger": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Type": "FrooxEngine.AssetProxy`1[[FrooxEngine.Texture2D, FrooxEngine, Version=2022.1.28.1335, Culture=neutral, PublicKeyToken=null]]",
|
|
||||||
"Data": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"persistent-ID": const Uuid().v4(),
|
|
||||||
"UpdateOrder": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0
|
|
||||||
},
|
|
||||||
"Enabled": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"AssetReference": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": texture2dUid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Type": "FrooxEngine.UnlitMaterial",
|
|
||||||
"Data": {
|
|
||||||
"ID": materialId,
|
|
||||||
"persistent-ID": const Uuid().v4(),
|
|
||||||
"UpdateOrder": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0
|
|
||||||
},
|
|
||||||
"Enabled": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"HighPriorityIntegration": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"TintColor": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
1.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Texture": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": texture2dUid
|
|
||||||
},
|
|
||||||
"TextureScale": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
1.0,
|
|
||||||
1.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"TextureOffset": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
0.0,
|
|
||||||
0.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"MaskTexture": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": null
|
|
||||||
},
|
|
||||||
"MaskScale": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
1.0,
|
|
||||||
1.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"MaskOffset": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
0.0,
|
|
||||||
0.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"MaskMode": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": "MultiplyAlpha"
|
|
||||||
},
|
|
||||||
"BlendMode": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": "Alpha"
|
|
||||||
},
|
|
||||||
"AlphaCutoff": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0.5
|
|
||||||
},
|
|
||||||
"UseVertexColors": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"Sidedness": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": "Double"
|
|
||||||
},
|
|
||||||
"ZWrite": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": "Auto"
|
|
||||||
},
|
|
||||||
"OffsetTexture": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": null
|
|
||||||
},
|
|
||||||
"OffsetMagnitude": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
0.0,
|
|
||||||
0.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"OffsetTextureScale": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
1.0,
|
|
||||||
1.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"OffsetTextureOffset": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
0.0,
|
|
||||||
0.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"PolarUVmapping": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"PolarPower": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 1.0
|
|
||||||
},
|
|
||||||
"StereoTextureTransform": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"RightEyeTextureScale": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
1.0,
|
|
||||||
1.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"RightEyeTextureOffset": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
0.0,
|
|
||||||
0.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"DecodeAsNormalMap": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"UseBillboardGeometry": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"UsePerBillboardScale": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"UsePerBillboardRotation": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"UsePerBillboardUV": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"BillboardSize": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
0.005,
|
|
||||||
0.005
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"OffsetFactor": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0.0
|
|
||||||
},
|
|
||||||
"OffsetUnits": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0.0
|
|
||||||
},
|
|
||||||
"RenderQueue": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": -1
|
|
||||||
},
|
|
||||||
"_unlit-ID": const Uuid().v4(),
|
|
||||||
"_unlitBillboard-ID": const Uuid().v4()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Type": "FrooxEngine.QuadMesh",
|
|
||||||
"Data": {
|
|
||||||
"ID": quadMeshUid,
|
|
||||||
"persistent-ID": const Uuid().v4(),
|
|
||||||
"UpdateOrder": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0
|
|
||||||
},
|
|
||||||
"Enabled": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"HighPriorityIntegration": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"OverrideBoundingBox": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"OverridenBoundingBox": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": {
|
|
||||||
"Min": [
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0
|
|
||||||
],
|
|
||||||
"Max": [
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Rotation": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
1.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Size": {
|
|
||||||
"ID": quadMeshSizeUid,
|
|
||||||
"Data": [
|
|
||||||
1,
|
|
||||||
height/width
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"UVScale": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
1.0,
|
|
||||||
1.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ScaleUVWithSize": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"UVOffset": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
0.0,
|
|
||||||
0.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"DualSided": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"UseVertexColors": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"UpperLeftColor": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
1.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"LowerLeftColor": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
1.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"LowerRightColor": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
1.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"UpperRightColor": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
1.0
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Type": "FrooxEngine.MeshRenderer",
|
|
||||||
"Data": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"persistent-ID": const Uuid().v4(),
|
|
||||||
"UpdateOrder": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0
|
|
||||||
},
|
|
||||||
"Enabled": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"Mesh": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": quadMeshUid
|
|
||||||
},
|
|
||||||
"Materials": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
{
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": materialId
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"MaterialPropertyBlocks": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": []
|
|
||||||
},
|
|
||||||
"ShadowCastMode": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": "On"
|
|
||||||
},
|
|
||||||
"MotionVectorMode": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": "Object"
|
|
||||||
},
|
|
||||||
"SortingOrder": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Type": "FrooxEngine.BoxCollider",
|
|
||||||
"Data": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"persistent-ID": const Uuid().v4(),
|
|
||||||
"UpdateOrder": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 1000000
|
|
||||||
},
|
|
||||||
"Enabled": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"Offset": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
0.0
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": "NoCollision"
|
|
||||||
},
|
|
||||||
"Mass": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 1.0
|
|
||||||
},
|
|
||||||
"CharacterCollider": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"IgnoreRaycasts": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": false
|
|
||||||
},
|
|
||||||
"Size": {
|
|
||||||
"ID": boxColliderSizeUid,
|
|
||||||
"Data": [
|
|
||||||
0.7071067,
|
|
||||||
0.7071067,
|
|
||||||
0.0
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Type": "FrooxEngine.Float2ToFloat3SwizzleDriver",
|
|
||||||
"Data": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"persistent-ID": const Uuid().v4(),
|
|
||||||
"UpdateOrder": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0
|
|
||||||
},
|
|
||||||
"Enabled": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"Source": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": quadMeshSizeUid
|
|
||||||
},
|
|
||||||
"Target": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": boxColliderSizeUid
|
|
||||||
},
|
|
||||||
"X": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0
|
|
||||||
},
|
|
||||||
"Y": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 1
|
|
||||||
},
|
|
||||||
"Z": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": "alice"
|
|
||||||
},
|
|
||||||
"Tag": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": null
|
|
||||||
},
|
|
||||||
"Active": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": true
|
|
||||||
},
|
|
||||||
"Persistent-ID": const Uuid().v4(),
|
|
||||||
"Position": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
0.8303015,
|
|
||||||
1.815294,
|
|
||||||
0.494639724
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Rotation": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
1.05315749E-07,
|
|
||||||
0.0222634021,
|
|
||||||
-1.08297385E-07,
|
|
||||||
0.999752164
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Scale": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": [
|
|
||||||
0.9999994,
|
|
||||||
0.999999464,
|
|
||||||
0.99999994
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"OrderOffset": {
|
|
||||||
"ID": const Uuid().v4(),
|
|
||||||
"Data": 0
|
|
||||||
},
|
|
||||||
"ParentReference": const Uuid().v4(),
|
|
||||||
"Children": []
|
|
||||||
},
|
|
||||||
"TypeVersions": {
|
|
||||||
"FrooxEngine.Grabbable": 2,
|
|
||||||
"FrooxEngine.QuadMesh": 1,
|
|
||||||
"FrooxEngine.BoxCollider": 1
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
2799
lib/models/records/json_template.dart
Normal file
2799
lib/models/records/json_template.dart
Normal file
File diff suppressed because it is too large
Load diff
|
@ -51,6 +51,7 @@ class MessageAsset extends StatelessWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
errorWidget: (context, url, error) => const Icon(Icons.image_not_supported, size: 128,),
|
||||||
placeholder: (context, uri) => const CircularProgressIndicator(),
|
placeholder: (context, uri) => const CircularProgressIndicator(),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8,),
|
const SizedBox(height: 8,),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:contacts_plus_plus/widgets/messages/message_camera_view.dart';
|
import 'package:contacts_plus_plus/widgets/messages/message_camera_view.dart';
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -8,8 +9,8 @@ import 'package:path/path.dart';
|
||||||
class MessageAttachmentList extends StatefulWidget {
|
class MessageAttachmentList extends StatefulWidget {
|
||||||
const MessageAttachmentList({required this.onChange, required this.disabled, this.initialFiles, super.key});
|
const MessageAttachmentList({required this.onChange, required this.disabled, this.initialFiles, super.key});
|
||||||
|
|
||||||
final List<File>? initialFiles;
|
final List<(FileType, File)>? initialFiles;
|
||||||
final Function(List<File> files) onChange;
|
final Function(List<(FileType, File)> files) onChange;
|
||||||
final bool disabled;
|
final bool disabled;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -17,7 +18,7 @@ class MessageAttachmentList extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MessageAttachmentListState extends State<MessageAttachmentList> {
|
class _MessageAttachmentListState extends State<MessageAttachmentList> {
|
||||||
final List<File> _loadedFiles = [];
|
final List<(FileType, File)> _loadedFiles = [];
|
||||||
final ScrollController _scrollController = ScrollController();
|
final ScrollController _scrollController = ScrollController();
|
||||||
bool _showShadow = true;
|
bool _showShadow = true;
|
||||||
|
|
||||||
|
@ -71,7 +72,7 @@ class _MessageAttachmentListState extends State<MessageAttachmentList> {
|
||||||
title: const Text("Remove attachment"),
|
title: const Text("Remove attachment"),
|
||||||
content: Text(
|
content: Text(
|
||||||
"This will remove attachment '${basename(
|
"This will remove attachment '${basename(
|
||||||
file.path)}', are you sure?"),
|
file.$2.path)}', are you sure?"),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
@ -104,8 +105,11 @@ class _MessageAttachmentListState extends State<MessageAttachmentList> {
|
||||||
width: 1
|
width: 1
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
label: Text(basename(file.path)),
|
label: Text(basename(file.$2.path)),
|
||||||
icon: const Icon(Icons.attach_file),
|
icon: switch (file.$1) {
|
||||||
|
FileType.image => const Icon(Icons.image),
|
||||||
|
_ => const Icon(Icons.attach_file)
|
||||||
|
}
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
).toList()
|
).toList()
|
||||||
|
@ -115,10 +119,13 @@ class _MessageAttachmentListState extends State<MessageAttachmentList> {
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: widget.disabled ? null : () async {
|
onPressed: widget.disabled ? null : () async {
|
||||||
final result = await FilePicker.platform.pickFiles(type: FileType.image);
|
final result = await FilePicker.platform.pickFiles(type: FileType.image, allowMultiple: true);
|
||||||
if (result != null && result.files.single.path != null) {
|
if (result != null) {
|
||||||
_loadedFiles.add(File(result.files.single.path!));
|
setState(() {
|
||||||
await widget.onChange(_loadedFiles);
|
_loadedFiles.addAll(
|
||||||
|
result.files.map((e) => e.path != null ? (FileType.image, File(e.path!)) : null)
|
||||||
|
.whereNotNull());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.add_photo_alternate),
|
icon: const Icon(Icons.add_photo_alternate),
|
||||||
|
@ -134,6 +141,18 @@ class _MessageAttachmentListState extends State<MessageAttachmentList> {
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.add_a_photo),
|
icon: const Icon(Icons.add_a_photo),
|
||||||
),
|
),
|
||||||
|
IconButton(
|
||||||
|
onPressed: widget.disabled ? null : () async {
|
||||||
|
final result = await FilePicker.platform.pickFiles(type: FileType.any, allowMultiple: true);
|
||||||
|
if (result != null) {
|
||||||
|
setState(() {
|
||||||
|
_loadedFiles.addAll(
|
||||||
|
result.files.map((e) => e.path != null ? (FileType.any, File(e.path!)) : null).whereNotNull());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.file_present_rounded),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:contacts_plus_plus/apis/record_api.dart';
|
import 'package:contacts_plus_plus/apis/record_api.dart';
|
||||||
import 'package:contacts_plus_plus/client_holder.dart';
|
import 'package:contacts_plus_plus/client_holder.dart';
|
||||||
import 'package:contacts_plus_plus/clients/api_client.dart';
|
import 'package:contacts_plus_plus/clients/api_client.dart';
|
||||||
|
@ -32,7 +34,7 @@ class _MessagesListState extends State<MessagesList> with SingleTickerProviderSt
|
||||||
final TextEditingController _messageTextController = TextEditingController();
|
final TextEditingController _messageTextController = TextEditingController();
|
||||||
final ScrollController _sessionListScrollController = ScrollController();
|
final ScrollController _sessionListScrollController = ScrollController();
|
||||||
final ScrollController _messageScrollController = ScrollController();
|
final ScrollController _messageScrollController = ScrollController();
|
||||||
final List<File> _loadedFiles = [];
|
final List<(FileType, File)> _loadedFiles = [];
|
||||||
|
|
||||||
bool _hasText = false;
|
bool _hasText = false;
|
||||||
bool _isSending = false;
|
bool _isSending = false;
|
||||||
|
@ -145,6 +147,27 @@ class _MessagesListState extends State<MessagesList> with SingleTickerProviderSt
|
||||||
_hasText = false;
|
_hasText = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> sendRawFileMessage(ApiClient client, MessagingClient mClient, File file, String machineId,
|
||||||
|
void Function(double progress) progressCallback) async {
|
||||||
|
final record = await RecordApi.uploadRawFile(
|
||||||
|
client,
|
||||||
|
file: file,
|
||||||
|
machineId: machineId,
|
||||||
|
progressCallback: progressCallback,
|
||||||
|
);
|
||||||
|
final message = Message(
|
||||||
|
id: record.extractMessageId() ?? Message.generateId(),
|
||||||
|
recipientId: widget.friend.id,
|
||||||
|
senderId: client.userId,
|
||||||
|
type: MessageType.object,
|
||||||
|
content: jsonEncode(record.toMap()),
|
||||||
|
sendTime: DateTime.now().toUtc(),
|
||||||
|
);
|
||||||
|
mClient.sendMessage(message);
|
||||||
|
_messageTextController.clear();
|
||||||
|
_hasText = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -319,10 +342,14 @@ class _MessagesListState extends State<MessagesList> with SingleTickerProviderSt
|
||||||
children: [
|
children: [
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
onPressed: _isSending ? null : () async {
|
onPressed: _isSending ? null : () async {
|
||||||
final result = await FilePicker.platform.pickFiles(type: FileType.image);
|
final result = await FilePicker.platform.pickFiles(
|
||||||
if (result != null && result.files.single.path != null) {
|
type: FileType.image, allowMultiple: true);
|
||||||
|
if (result != null) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_loadedFiles.add(File(result.files.single.path!));
|
_loadedFiles.addAll(
|
||||||
|
result.files.map((e) =>
|
||||||
|
e.path != null ? (FileType.image, File(e.path!)) : null)
|
||||||
|
.whereNotNull());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -332,29 +359,45 @@ class _MessagesListState extends State<MessagesList> with SingleTickerProviderSt
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
onPressed: _isSending ? null : () async {
|
onPressed: _isSending ? null : () async {
|
||||||
final picture = await Navigator.of(context).push(
|
final picture = await Navigator.of(context).push(
|
||||||
MaterialPageRoute(builder: (context) => const MessageCameraView()));
|
MaterialPageRoute(builder: (context) => const MessageCameraView())) as File?;
|
||||||
if (picture != null) {
|
if (picture != null) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_loadedFiles.add(picture);
|
_loadedFiles.add((FileType.image, picture));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.camera_alt),
|
icon: const Icon(Icons.camera_alt),
|
||||||
label: const Text("Camera"),
|
label: const Text("Camera"),
|
||||||
),
|
),
|
||||||
|
TextButton.icon(
|
||||||
|
onPressed: _isSending ? null : () async {
|
||||||
|
final result = await FilePicker.platform.pickFiles(
|
||||||
|
type: FileType.any, allowMultiple: true);
|
||||||
|
if (result != null) {
|
||||||
|
setState(() {
|
||||||
|
_loadedFiles.addAll(
|
||||||
|
result.files.map((e) =>
|
||||||
|
e.path != null ? (FileType.any, File(e.path!)) : null)
|
||||||
|
.whereNotNull());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.file_present_rounded),
|
||||||
|
label: const Text("Document"),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
(false, []) => null,
|
(false, []) => null,
|
||||||
(_, _) =>
|
(_, _) =>
|
||||||
MessageAttachmentList(
|
MessageAttachmentList(
|
||||||
disabled: _isSending,
|
disabled: _isSending,
|
||||||
initialFiles: _loadedFiles,
|
initialFiles: _loadedFiles,
|
||||||
onChange: (List<File> loadedFiles) =>
|
onChange: (List<(FileType, File)> loadedFiles) =>
|
||||||
setState(() {
|
setState(() {
|
||||||
_loadedFiles.clear();
|
_loadedFiles.clear();
|
||||||
_loadedFiles.addAll(loadedFiles);
|
_loadedFiles.addAll(loadedFiles);
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -490,7 +533,11 @@ class _MessagesListState extends State<MessagesList> with SingleTickerProviderSt
|
||||||
splashRadius: 24,
|
splashRadius: 24,
|
||||||
onPressed: _isSending ? null : () async {
|
onPressed: _isSending ? null : () async {
|
||||||
final sMsgnr = ScaffoldMessenger.of(context);
|
final sMsgnr = ScaffoldMessenger.of(context);
|
||||||
final toSend = List.from(_loadedFiles);
|
final settings = ClientHolder
|
||||||
|
.of(context)
|
||||||
|
.settingsClient
|
||||||
|
.currentSettings;
|
||||||
|
final toSend = List<(FileType, File)>.from(_loadedFiles);
|
||||||
setState(() {
|
setState(() {
|
||||||
_isSending = true;
|
_isSending = true;
|
||||||
_sendProgress = 0;
|
_sendProgress = 0;
|
||||||
|
@ -501,19 +548,21 @@ class _MessagesListState extends State<MessagesList> with SingleTickerProviderSt
|
||||||
for (int i = 0; i < toSend.length; i++) {
|
for (int i = 0; i < toSend.length; i++) {
|
||||||
final totalProgress = i / toSend.length;
|
final totalProgress = i / toSend.length;
|
||||||
final file = toSend[i];
|
final file = toSend[i];
|
||||||
await sendImageMessage(apiClient, mClient, file, ClientHolder
|
if (file.$1 == FileType.image) {
|
||||||
.of(context)
|
await sendImageMessage(
|
||||||
.settingsClient
|
apiClient, mClient, file.$2, settings.machineId.valueOrDefault,
|
||||||
.currentSettings
|
(progress) =>
|
||||||
.machineId
|
setState(() {
|
||||||
.valueOrDefault,
|
_sendProgress = totalProgress + progress * 1 / toSend.length;
|
||||||
(progress) =>
|
}),
|
||||||
setState(() {
|
);
|
||||||
_sendProgress = totalProgress + progress * 1 / toSend.length;
|
} else {
|
||||||
}),
|
await sendRawFileMessage(
|
||||||
);
|
apiClient, mClient, file.$2, settings.machineId.valueOrDefault, (progress) =>
|
||||||
|
setState(() =>
|
||||||
|
_sendProgress = totalProgress + progress * 1 / toSend.length));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_sendProgress = null;
|
_sendProgress = null;
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue