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 'package:collection/collection.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:flutter/material.dart';
|
||||
|
||||
|
@ -125,7 +125,7 @@ class RecordApi {
|
|||
final imageData = await decodeImageFromList(imageDigest.data);
|
||||
|
||||
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 objectDigest = await AssetDigest.fromData(objectBytes, "${basenameWithoutExtension(image.path)}.json");
|
||||
|
@ -183,4 +183,37 @@ class RecordApi {
|
|||
progressCallback?.call(1);
|
||||
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(),
|
||||
),
|
||||
const SizedBox(height: 8,),
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:contacts_plus_plus/widgets/messages/message_camera_view.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -8,8 +9,8 @@ import 'package:path/path.dart';
|
|||
class MessageAttachmentList extends StatefulWidget {
|
||||
const MessageAttachmentList({required this.onChange, required this.disabled, this.initialFiles, super.key});
|
||||
|
||||
final List<File>? initialFiles;
|
||||
final Function(List<File> files) onChange;
|
||||
final List<(FileType, File)>? initialFiles;
|
||||
final Function(List<(FileType, File)> files) onChange;
|
||||
final bool disabled;
|
||||
|
||||
@override
|
||||
|
@ -17,7 +18,7 @@ class MessageAttachmentList extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _MessageAttachmentListState extends State<MessageAttachmentList> {
|
||||
final List<File> _loadedFiles = [];
|
||||
final List<(FileType, File)> _loadedFiles = [];
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
bool _showShadow = true;
|
||||
|
||||
|
@ -71,7 +72,7 @@ class _MessageAttachmentListState extends State<MessageAttachmentList> {
|
|||
title: const Text("Remove attachment"),
|
||||
content: Text(
|
||||
"This will remove attachment '${basename(
|
||||
file.path)}', are you sure?"),
|
||||
file.$2.path)}', are you sure?"),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
|
@ -104,8 +105,11 @@ class _MessageAttachmentListState extends State<MessageAttachmentList> {
|
|||
width: 1
|
||||
),
|
||||
),
|
||||
label: Text(basename(file.path)),
|
||||
icon: const Icon(Icons.attach_file),
|
||||
label: Text(basename(file.$2.path)),
|
||||
icon: switch (file.$1) {
|
||||
FileType.image => const Icon(Icons.image),
|
||||
_ => const Icon(Icons.attach_file)
|
||||
}
|
||||
),
|
||||
),
|
||||
).toList()
|
||||
|
@ -115,10 +119,13 @@ class _MessageAttachmentListState extends State<MessageAttachmentList> {
|
|||
),
|
||||
IconButton(
|
||||
onPressed: widget.disabled ? null : () async {
|
||||
final result = await FilePicker.platform.pickFiles(type: FileType.image);
|
||||
if (result != null && result.files.single.path != null) {
|
||||
_loadedFiles.add(File(result.files.single.path!));
|
||||
await widget.onChange(_loadedFiles);
|
||||
final result = await FilePicker.platform.pickFiles(type: FileType.image, allowMultiple: true);
|
||||
if (result != null) {
|
||||
setState(() {
|
||||
_loadedFiles.addAll(
|
||||
result.files.map((e) => e.path != null ? (FileType.image, File(e.path!)) : null)
|
||||
.whereNotNull());
|
||||
});
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.add_photo_alternate),
|
||||
|
@ -134,6 +141,18 @@ class _MessageAttachmentListState extends State<MessageAttachmentList> {
|
|||
},
|
||||
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:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:contacts_plus_plus/apis/record_api.dart';
|
||||
import 'package:contacts_plus_plus/client_holder.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 ScrollController _sessionListScrollController = ScrollController();
|
||||
final ScrollController _messageScrollController = ScrollController();
|
||||
final List<File> _loadedFiles = [];
|
||||
final List<(FileType, File)> _loadedFiles = [];
|
||||
|
||||
bool _hasText = false;
|
||||
bool _isSending = false;
|
||||
|
@ -145,6 +147,27 @@ class _MessagesListState extends State<MessagesList> with SingleTickerProviderSt
|
|||
_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
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -319,10 +342,14 @@ class _MessagesListState extends State<MessagesList> with SingleTickerProviderSt
|
|||
children: [
|
||||
TextButton.icon(
|
||||
onPressed: _isSending ? null : () async {
|
||||
final result = await FilePicker.platform.pickFiles(type: FileType.image);
|
||||
if (result != null && result.files.single.path != null) {
|
||||
final result = await FilePicker.platform.pickFiles(
|
||||
type: FileType.image, allowMultiple: true);
|
||||
if (result != null) {
|
||||
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(
|
||||
onPressed: _isSending ? null : () async {
|
||||
final picture = await Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (context) => const MessageCameraView()));
|
||||
MaterialPageRoute(builder: (context) => const MessageCameraView())) as File?;
|
||||
if (picture != null) {
|
||||
setState(() {
|
||||
_loadedFiles.add(picture);
|
||||
_loadedFiles.add((FileType.image, picture));
|
||||
});
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.camera_alt),
|
||||
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,
|
||||
(_, _) =>
|
||||
MessageAttachmentList(
|
||||
disabled: _isSending,
|
||||
initialFiles: _loadedFiles,
|
||||
onChange: (List<File> loadedFiles) =>
|
||||
setState(() {
|
||||
_loadedFiles.clear();
|
||||
_loadedFiles.addAll(loadedFiles);
|
||||
}),
|
||||
)
|
||||
disabled: _isSending,
|
||||
initialFiles: _loadedFiles,
|
||||
onChange: (List<(FileType, File)> loadedFiles) =>
|
||||
setState(() {
|
||||
_loadedFiles.clear();
|
||||
_loadedFiles.addAll(loadedFiles);
|
||||
}),
|
||||
)
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -490,7 +533,11 @@ class _MessagesListState extends State<MessagesList> with SingleTickerProviderSt
|
|||
splashRadius: 24,
|
||||
onPressed: _isSending ? null : () async {
|
||||
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(() {
|
||||
_isSending = true;
|
||||
_sendProgress = 0;
|
||||
|
@ -501,19 +548,21 @@ class _MessagesListState extends State<MessagesList> with SingleTickerProviderSt
|
|||
for (int i = 0; i < toSend.length; i++) {
|
||||
final totalProgress = i / toSend.length;
|
||||
final file = toSend[i];
|
||||
await sendImageMessage(apiClient, mClient, file, ClientHolder
|
||||
.of(context)
|
||||
.settingsClient
|
||||
.currentSettings
|
||||
.machineId
|
||||
.valueOrDefault,
|
||||
(progress) =>
|
||||
setState(() {
|
||||
_sendProgress = totalProgress + progress * 1 / toSend.length;
|
||||
}),
|
||||
);
|
||||
if (file.$1 == FileType.image) {
|
||||
await sendImageMessage(
|
||||
apiClient, mClient, file.$2, settings.machineId.valueOrDefault,
|
||||
(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(() {
|
||||
_sendProgress = null;
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue