Compare commits
13 Commits
835777e562
...
ee4b3ef439
Author | SHA1 | Date | |
---|---|---|---|
ee4b3ef439 | |||
cda8874547 | |||
4f53120d11 | |||
fed94fa543 | |||
b93e048509 | |||
9f09905f31 | |||
20d9d3391c | |||
961ca473c7 | |||
64297a2d28 | |||
84c965b175 | |||
5e528d2a21 | |||
7be01d0955 | |||
2812bb3a2d |
1
api/.gitignore
vendored
1
api/.gitignore
vendored
@ -8,3 +8,4 @@ config-prod.yml
|
||||
envfile
|
||||
firebase.json
|
||||
.DS_Store
|
||||
migration_projects/
|
@ -29,6 +29,9 @@ def get(user, id):
|
||||
owner = user and (user.get('_id') == proj['user'])
|
||||
if not owner and proj['visibility'] != 'public':
|
||||
raise util.errors.BadRequest('Forbidden')
|
||||
if obj['type'] == 'pattern' and 'preview' in obj and '.png' in obj['preview']:
|
||||
obj['previewUrl'] = uploads.get_presigned_url('projects/{0}/{1}'.format(proj['_id'], obj['preview']))
|
||||
del obj['preview']
|
||||
return obj
|
||||
|
||||
def copy_to_project(user, id, project_id):
|
||||
|
@ -122,6 +122,9 @@ def get_objects(user, username, path):
|
||||
for obj in objs:
|
||||
if obj['type'] == 'file' and 'storedName' in obj:
|
||||
obj['url'] = uploads.get_presigned_url('projects/{0}/{1}'.format(project['_id'], obj['storedName']))
|
||||
if obj['type'] == 'pattern' and 'preview' in obj and '.png' in obj['preview']:
|
||||
obj['previewUrl'] = uploads.get_presigned_url('projects/{0}/{1}'.format(project['_id'], obj['preview']))
|
||||
del obj['preview']
|
||||
return objs
|
||||
|
||||
def create_object(user, username, path, data):
|
||||
|
@ -91,6 +91,9 @@ def explore(page = 1):
|
||||
objects = list(db.objects.find({'project': {'$in': all_public_project_ids}, 'name': {'$not': re.compile('untitled pattern', re.IGNORECASE)}, 'preview': {'$exists': True}}, {'project': 1, 'name': 1, 'createdAt': 1, 'preview': 1}).sort('createdAt', pymongo.DESCENDING).skip((page - 1) * per_page).limit(per_page))
|
||||
for object in objects:
|
||||
object['projectObject'] = project_map.get(object['project'])
|
||||
if 'preview' in object and '.png' in object['preview']:
|
||||
object['previewUrl'] = uploads.get_presigned_url('projects/{0}/{1}'.format(object['project'], object['preview']))
|
||||
del object['preview']
|
||||
authors = list(db.users.find({'_id': {'$in': list(map(lambda o: o.get('projectObject', {}).get('user'), objects))}}, {'username': 1, 'avatar': 1, 'isSilverSupporter': 1, 'isGoldSupporter': 1}))
|
||||
for a in authors:
|
||||
if 'avatar' in a:
|
||||
|
@ -4,7 +4,7 @@ from bson.objectid import ObjectId
|
||||
import boto3
|
||||
from botocore.client import Config
|
||||
import blurhash
|
||||
from util import database
|
||||
from util import database, util
|
||||
|
||||
def sanitise_filename(s):
|
||||
bad_chars = re.compile('[^a-zA-Z0-9_.]')
|
||||
|
21
api/migrations/object_previews.py
Normal file
21
api/migrations/object_previews.py
Normal file
@ -0,0 +1,21 @@
|
||||
# Script to migrate from the old data: string URLs for images to image files directly on S3.
|
||||
|
||||
from pymongo import MongoClient
|
||||
import base64, os
|
||||
|
||||
db = MongoClient('mongodb://USER:PASS@db/admin')['treadl']
|
||||
|
||||
os.makedirs('migration_projects/projects', exist_ok=True)
|
||||
|
||||
for obj in db.objects.find({'preview': {'$regex': '^data:'}}, {'preview': 1, 'project': 1}):
|
||||
preview = obj['preview']
|
||||
preview = preview.replace('data:image/png;base64,', '')
|
||||
|
||||
imgdata = base64.b64decode(preview)
|
||||
filename = 'some_image.png'
|
||||
|
||||
os.makedirs('migration_projects/projects/'+str(obj['project']), exist_ok=True)
|
||||
with open('migration_projects/projects/'+str(obj['project'])+'/preview_'+str(obj['_id'])+'.png' , 'wb') as f:
|
||||
f.write(imgdata)
|
||||
db.objects.update_one({'_id': obj['_id']}, {'$set': {'previewNew': 'preview_'+str(obj['_id'])+'.png'}})
|
||||
#exit()
|
@ -21,6 +21,6 @@
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>9.0</string>
|
||||
<string>11.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Uncomment this line to define a global platform for your project
|
||||
# platform :ios, '9.0'
|
||||
# platform :ios, '11.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
@ -1,108 +1,91 @@
|
||||
PODS:
|
||||
- Firebase/CoreOnly (8.11.0):
|
||||
- FirebaseCore (= 8.11.0)
|
||||
- Firebase/Messaging (8.11.0):
|
||||
- Firebase/CoreOnly (10.9.0):
|
||||
- FirebaseCore (= 10.9.0)
|
||||
- Firebase/Messaging (10.9.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseMessaging (~> 8.11.0)
|
||||
- firebase_core (1.13.1):
|
||||
- Firebase/CoreOnly (= 8.11.0)
|
||||
- FirebaseMessaging (~> 10.9.0)
|
||||
- firebase_core (2.13.1):
|
||||
- Firebase/CoreOnly (= 10.9.0)
|
||||
- Flutter
|
||||
- firebase_messaging (11.2.8):
|
||||
- Firebase/Messaging (= 8.11.0)
|
||||
- firebase_messaging (14.6.2):
|
||||
- Firebase/Messaging (= 10.9.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- FirebaseCore (8.11.0):
|
||||
- FirebaseCoreDiagnostics (~> 8.0)
|
||||
- GoogleUtilities/Environment (~> 7.7)
|
||||
- GoogleUtilities/Logger (~> 7.7)
|
||||
- FirebaseCoreDiagnostics (8.12.0):
|
||||
- GoogleDataTransport (~> 9.1)
|
||||
- GoogleUtilities/Environment (~> 7.7)
|
||||
- GoogleUtilities/Logger (~> 7.7)
|
||||
- nanopb (~> 2.30908.0)
|
||||
- FirebaseInstallations (8.12.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- GoogleUtilities/Environment (~> 7.7)
|
||||
- GoogleUtilities/UserDefaults (~> 7.7)
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- FirebaseMessaging (8.11.0):
|
||||
- FirebaseCore (~> 8.0)
|
||||
- FirebaseInstallations (~> 8.0)
|
||||
- GoogleDataTransport (~> 9.1)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.7)
|
||||
- GoogleUtilities/Environment (~> 7.7)
|
||||
- GoogleUtilities/Reachability (~> 7.7)
|
||||
- GoogleUtilities/UserDefaults (~> 7.7)
|
||||
- nanopb (~> 2.30908.0)
|
||||
- FirebaseCore (10.9.0):
|
||||
- FirebaseCoreInternal (~> 10.0)
|
||||
- GoogleUtilities/Environment (~> 7.8)
|
||||
- GoogleUtilities/Logger (~> 7.8)
|
||||
- FirebaseCoreInternal (10.10.0):
|
||||
- "GoogleUtilities/NSData+zlib (~> 7.8)"
|
||||
- FirebaseInstallations (10.10.0):
|
||||
- FirebaseCore (~> 10.0)
|
||||
- GoogleUtilities/Environment (~> 7.8)
|
||||
- GoogleUtilities/UserDefaults (~> 7.8)
|
||||
- PromisesObjC (~> 2.1)
|
||||
- FirebaseMessaging (10.9.0):
|
||||
- FirebaseCore (~> 10.0)
|
||||
- FirebaseInstallations (~> 10.0)
|
||||
- GoogleDataTransport (~> 9.2)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 7.8)
|
||||
- GoogleUtilities/Environment (~> 7.8)
|
||||
- GoogleUtilities/Reachability (~> 7.8)
|
||||
- GoogleUtilities/UserDefaults (~> 7.8)
|
||||
- nanopb (< 2.30910.0, >= 2.30908.0)
|
||||
- Flutter (1.0.0)
|
||||
- fluttertoast (0.0.2):
|
||||
- Flutter
|
||||
- Toast
|
||||
- GoogleDataTransport (9.1.2):
|
||||
- GoogleUtilities/Environment (~> 7.2)
|
||||
- nanopb (~> 2.30908.0)
|
||||
- GoogleDataTransport (9.2.3):
|
||||
- GoogleUtilities/Environment (~> 7.7)
|
||||
- nanopb (< 2.30910.0, >= 2.30908.0)
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- GoogleUtilities/AppDelegateSwizzler (7.7.0):
|
||||
- GoogleUtilities/AppDelegateSwizzler (7.11.1):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network
|
||||
- GoogleUtilities/Environment (7.7.0):
|
||||
- GoogleUtilities/Environment (7.11.1):
|
||||
- PromisesObjC (< 3.0, >= 1.2)
|
||||
- GoogleUtilities/Logger (7.7.0):
|
||||
- GoogleUtilities/Logger (7.11.1):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Network (7.7.0):
|
||||
- GoogleUtilities/Network (7.11.1):
|
||||
- GoogleUtilities/Logger
|
||||
- "GoogleUtilities/NSData+zlib"
|
||||
- GoogleUtilities/Reachability
|
||||
- "GoogleUtilities/NSData+zlib (7.7.0)"
|
||||
- GoogleUtilities/Reachability (7.7.0):
|
||||
- "GoogleUtilities/NSData+zlib (7.11.1)"
|
||||
- GoogleUtilities/Reachability (7.11.1):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/UserDefaults (7.7.0):
|
||||
- GoogleUtilities/UserDefaults (7.11.1):
|
||||
- GoogleUtilities/Logger
|
||||
- image_picker (0.0.1):
|
||||
- image_picker_ios (0.0.1):
|
||||
- Flutter
|
||||
- nanopb (2.30908.0):
|
||||
- nanopb/decode (= 2.30908.0)
|
||||
- nanopb/encode (= 2.30908.0)
|
||||
- nanopb/decode (2.30908.0)
|
||||
- nanopb/encode (2.30908.0)
|
||||
- PromisesObjC (2.0.0)
|
||||
- shared_preferences_ios (0.0.1):
|
||||
- nanopb (2.30909.0):
|
||||
- nanopb/decode (= 2.30909.0)
|
||||
- nanopb/encode (= 2.30909.0)
|
||||
- nanopb/decode (2.30909.0)
|
||||
- nanopb/encode (2.30909.0)
|
||||
- PromisesObjC (2.2.0)
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
- Flutter
|
||||
- Toast (4.0.0)
|
||||
- FlutterMacOS
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
- video_player_avfoundation (0.0.1):
|
||||
- Flutter
|
||||
- wakelock (0.0.1):
|
||||
- Flutter
|
||||
- webview_flutter_wkwebview (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
||||
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
|
||||
- image_picker (from `.symlinks/plugins/image_picker/ios`)
|
||||
- shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
|
||||
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`)
|
||||
- wakelock (from `.symlinks/plugins/wakelock/ios`)
|
||||
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- Firebase
|
||||
- FirebaseCore
|
||||
- FirebaseCoreDiagnostics
|
||||
- FirebaseCoreInternal
|
||||
- FirebaseInstallations
|
||||
- FirebaseMessaging
|
||||
- GoogleDataTransport
|
||||
- GoogleUtilities
|
||||
- nanopb
|
||||
- PromisesObjC
|
||||
- Toast
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
firebase_core:
|
||||
@ -111,43 +94,30 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/firebase_messaging/ios"
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
fluttertoast:
|
||||
:path: ".symlinks/plugins/fluttertoast/ios"
|
||||
image_picker:
|
||||
:path: ".symlinks/plugins/image_picker/ios"
|
||||
shared_preferences_ios:
|
||||
:path: ".symlinks/plugins/shared_preferences_ios/ios"
|
||||
image_picker_ios:
|
||||
:path: ".symlinks/plugins/image_picker_ios/ios"
|
||||
shared_preferences_foundation:
|
||||
:path: ".symlinks/plugins/shared_preferences_foundation/ios"
|
||||
url_launcher_ios:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
video_player_avfoundation:
|
||||
:path: ".symlinks/plugins/video_player_avfoundation/ios"
|
||||
wakelock:
|
||||
:path: ".symlinks/plugins/wakelock/ios"
|
||||
webview_flutter_wkwebview:
|
||||
:path: ".symlinks/plugins/webview_flutter_wkwebview/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Firebase: 44dd9724c84df18b486639e874f31436eaa9a20c
|
||||
firebase_core: 08f6a85f62060111de5e98d6a214810d11365de9
|
||||
firebase_messaging: 36238f3d0b933af8c919aef608408aae06ba22e8
|
||||
FirebaseCore: 2f4f85b453cc8fea4bb2b37e370007d2bcafe3f0
|
||||
FirebaseCoreDiagnostics: 3b40dfadef5b90433a60ae01f01e90fe87aa76aa
|
||||
FirebaseInstallations: 25764cf322e77f99449395870a65b2bef88e1545
|
||||
FirebaseMessaging: 02e248e8997f71fa8cc9d78e9d49ec1a701ba14a
|
||||
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
|
||||
fluttertoast: 16fbe6039d06a763f3533670197d01fc73459037
|
||||
GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940
|
||||
GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1
|
||||
image_picker: 541dcbb3b9cf32d87eacbd957845d8651d6c62c3
|
||||
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
|
||||
PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58
|
||||
shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
|
||||
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
|
||||
url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
|
||||
video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff
|
||||
wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f
|
||||
webview_flutter_wkwebview: 005fbd90c888a42c5690919a1527ecc6649e1162
|
||||
Firebase: bd152f0f3d278c4060c5c71359db08ebcfd5a3e2
|
||||
firebase_core: ce64b0941c6d87c6ef5022ae9116a158236c8c94
|
||||
firebase_messaging: 42912365e62efc1ea3e00724e5eecba6068ddb88
|
||||
FirebaseCore: b68d3616526ec02e4d155166bbafb8eca64af557
|
||||
FirebaseCoreInternal: 971029061d326000d65bfdc21f5502c75c8b0893
|
||||
FirebaseInstallations: 52153982b057d3afcb4e1fbb3eb0b6d00611e681
|
||||
FirebaseMessaging: 6b7052cc3da7bc8e5f72bef871243e8f04a14eed
|
||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
||||
GoogleDataTransport: f0308f5905a745f94fb91fea9c6cbaf3831cb1bd
|
||||
GoogleUtilities: 9aa0ad5a7bc171f8bae016300bfcfa3fb8425749
|
||||
image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
|
||||
nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431
|
||||
PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef
|
||||
shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c
|
||||
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
|
||||
|
||||
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
|
||||
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
|
||||
|
||||
COCOAPODS: 1.10.1
|
||||
COCOAPODS: 1.12.0
|
||||
|
@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 51;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@ -232,6 +232,7 @@
|
||||
};
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
@ -246,6 +247,7 @@
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
|
@ -46,5 +46,9 @@
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -6,23 +6,23 @@ import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class Api {
|
||||
|
||||
String _token;
|
||||
String? _token;
|
||||
final String apiBase = 'https://api.treadl.com';
|
||||
//final String apiBase = 'http://localhost:2001';
|
||||
//final String apiBase = 'http://192.168.5.86:2001';
|
||||
|
||||
Future<String> loadToken() async {
|
||||
Future<String?> loadToken() async {
|
||||
if (_token != null) {
|
||||
return _token;
|
||||
return _token!;
|
||||
}
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
final String token = prefs.getString('apiToken');
|
||||
String? token = prefs.getString('apiToken');
|
||||
return token;
|
||||
}
|
||||
Future<Map<String,String>> getHeaders(method) async {
|
||||
Map<String,String> headers = {};
|
||||
String token = await loadToken();
|
||||
String? token = await loadToken();
|
||||
if (token != null) {
|
||||
headers['Authorization'] = 'Bearer ' + token;
|
||||
headers['Authorization'] = 'Bearer ' + token!;
|
||||
}
|
||||
if (method == 'POST' || method == 'DELETE') {
|
||||
headers['Content-Type'] = 'application/json';
|
||||
@ -34,17 +34,23 @@ class Api {
|
||||
http.Client client = http.Client();
|
||||
return await client.get(url, headers: await getHeaders('GET'));
|
||||
}
|
||||
Future<http.Response> _post(Uri url, Map<String, dynamic> data) async {
|
||||
String json = jsonEncode(data);
|
||||
Future<http.Response> _post(Uri url, Map<String, dynamic>? data) async {
|
||||
String? json = null;
|
||||
if (data != null) {
|
||||
json = jsonEncode(data!);
|
||||
}
|
||||
http.Client client = http.Client();
|
||||
return await client.post(url, headers: await getHeaders('POST'), body: json);
|
||||
}
|
||||
Future<http.Response> _put(Uri url, Map<String, dynamic> data) async {
|
||||
String json = jsonEncode(data);
|
||||
Future<http.Response> _put(Uri url, Map<String, dynamic>? data) async {
|
||||
String? json = null;
|
||||
if (data != null) {
|
||||
json = jsonEncode(data!);
|
||||
}
|
||||
http.Client client = http.Client();
|
||||
return await client.put(url, headers: await getHeaders('POST'), body: json);
|
||||
}
|
||||
Future<http.Response> _delete(Uri url, [Map<String, dynamic> data]) async {
|
||||
Future<http.Response> _delete(Uri url, [Map<String, dynamic>? data]) async {
|
||||
http.Client client = http.Client();
|
||||
if (data != null) {
|
||||
String json = jsonEncode(data);
|
||||
@ -54,10 +60,10 @@ class Api {
|
||||
}
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> request(String method, String path, [Map<String, dynamic> data]) async {
|
||||
Future<Map<String, dynamic>> request(String method, String path, [Map<String, dynamic>? data]) async {
|
||||
String url = apiBase + path;
|
||||
Uri uri = Uri.parse(url);
|
||||
http.Response response;
|
||||
http.Response? response;
|
||||
if (method == 'POST') {
|
||||
response = await _post(uri, data);
|
||||
}
|
||||
@ -70,16 +76,19 @@ class Api {
|
||||
if (method == 'DELETE') {
|
||||
response = await _delete(uri, data);
|
||||
}
|
||||
int status = response.statusCode;
|
||||
if (response == null) {
|
||||
return {'success': false, 'message': 'No response for your request'};
|
||||
}
|
||||
int status = response!.statusCode;
|
||||
if (status == 200) {
|
||||
print('SUCCESS');
|
||||
Map<String, dynamic> respData = jsonDecode(response.body);
|
||||
Map<String, dynamic> respData = jsonDecode(response!.body);
|
||||
return {'success': true, 'payload': respData};
|
||||
}
|
||||
else {
|
||||
print('ERROR');
|
||||
Map<String, dynamic> respData = jsonDecode(response.body);
|
||||
return {'success': false, 'code': response.statusCode, 'message': respData['message']};
|
||||
Map<String, dynamic> respData = jsonDecode(response!.body);
|
||||
return {'success': false, 'code': status, 'message': respData['message']};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,8 +13,8 @@ class Alert extends StatelessWidget {
|
||||
final String title;
|
||||
final String description;
|
||||
final String actionText;
|
||||
final Widget descriptionWidget;
|
||||
final Function action;
|
||||
final Widget? descriptionWidget;
|
||||
final Function? action;
|
||||
Alert({this.type = 'info', this.title = '', this.description = '', this.descriptionWidget = null, this.actionText = 'Click here', this.action}) {}
|
||||
|
||||
@override
|
||||
@ -39,7 +39,7 @@ class Alert extends StatelessWidget {
|
||||
color: accentColor,
|
||||
borderRadius: new BorderRadius.all(Radius.circular(10.0)),
|
||||
boxShadow: [
|
||||
BoxShadow(color: Colors.grey[50], spreadRadius: 5),
|
||||
BoxShadow(color: Colors.grey[50]!, spreadRadius: 5),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
@ -48,12 +48,12 @@ class Alert extends StatelessWidget {
|
||||
Icon(icon, color: color),
|
||||
SizedBox(height: 20),
|
||||
Text(description, textAlign: TextAlign.center),
|
||||
descriptionWidget,
|
||||
descriptionWidget != null ? descriptionWidget! : Text(""),
|
||||
action != null ? CupertinoButton(
|
||||
child: Text(actionText),
|
||||
onPressed: action,
|
||||
) : null
|
||||
].where((o) => o != null).toList()
|
||||
onPressed: () => action!(),
|
||||
) : Text("")
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -61,8 +61,8 @@ class Alert extends StatelessWidget {
|
||||
|
||||
class NoticeboardPost extends StatefulWidget {
|
||||
final Map<String,dynamic> _entry;
|
||||
final Function onDelete;
|
||||
final Function onReply;
|
||||
final Function? onDelete;
|
||||
final Function? onReply;
|
||||
NoticeboardPost(this._entry, {this.onDelete = null, this.onReply = null});
|
||||
_NoticeboardPostState createState() => _NoticeboardPostState(_entry, onDelete: onDelete, onReply: onReply);
|
||||
}
|
||||
@ -70,8 +70,8 @@ class _NoticeboardPostState extends State<NoticeboardPost> {
|
||||
final Map<String,dynamic> _entry;
|
||||
final Util utils = new Util();
|
||||
final Api api = new Api();
|
||||
final Function onDelete;
|
||||
final Function onReply;
|
||||
final Function? onDelete;
|
||||
final Function? onReply;
|
||||
final TextEditingController _replyController = TextEditingController();
|
||||
bool _isReplying = false;
|
||||
bool _replying = false;
|
||||
@ -84,7 +84,9 @@ class _NoticeboardPostState extends State<NoticeboardPost> {
|
||||
if (data['success'] == true) {
|
||||
_replyController.value = TextEditingValue(text: '');
|
||||
FocusScope.of(context).requestFocus(FocusNode());
|
||||
onReply(data['payload']);
|
||||
if (onReply != null) {
|
||||
onReply!(data['payload']);
|
||||
}
|
||||
setState(() {
|
||||
_replying = false;
|
||||
_isReplying = false;
|
||||
@ -95,7 +97,9 @@ class _NoticeboardPostState extends State<NoticeboardPost> {
|
||||
void _deletePost() async {
|
||||
var data = await api.request('DELETE', '/groups/' + _entry['group'] + '/entries/' + _entry['_id']);
|
||||
if (data['success'] == true) {
|
||||
onDelete(_entry);
|
||||
if (onDelete != null) {
|
||||
onDelete!(_entry);
|
||||
}
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
@ -104,17 +108,17 @@ class _NoticeboardPostState extends State<NoticeboardPost> {
|
||||
Widget build(BuildContext context) {
|
||||
var createdAt = DateTime.parse(_entry['createdAt']);
|
||||
bool isReply = _entry['inReplyTo'] != null;
|
||||
int replyCount = _entry['replies'] == null ? 0 : _entry['replies'].length;
|
||||
int replyCount = _entry['replies'] == null ? 0 : _entry['replies']!.length;
|
||||
String replyText = 'Write a reply...';
|
||||
if (replyCount == 1) replyText = '1 Reply';
|
||||
if (replyCount > 1) replyText = replyCount.toString() + ' replies';
|
||||
if (_isReplying) replyText = 'Cancel reply';
|
||||
List<Widget> replyWidgets = [];
|
||||
if (_entry['replies'] != null) {
|
||||
for (int i = 0; i < _entry['replies'].length; i++) {
|
||||
for (int i = 0; i < _entry['replies']!.length; i++) {
|
||||
replyWidgets.add(new Container(
|
||||
key: Key(_entry['replies'][i]['_id']),
|
||||
child: NoticeboardPost(_entry['replies'][i], onDelete: onDelete)
|
||||
key: Key(_entry['replies']![i]['_id']),
|
||||
child: NoticeboardPost(_entry['replies']![i], onDelete: onDelete)
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -127,20 +131,20 @@ class _NoticeboardPostState extends State<NoticeboardPost> {
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
RaisedButton(
|
||||
color: Colors.orange,
|
||||
ElevatedButton(
|
||||
//color: Colors.orange,
|
||||
onPressed: () {
|
||||
launch('https://www.treadl.com');
|
||||
},
|
||||
child: Text('Report this post'),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
RaisedButton(
|
||||
color: Colors.red,
|
||||
ElevatedButton(
|
||||
//color: Colors.red,
|
||||
onPressed: _deletePost,
|
||||
child: Text('Delete post'),
|
||||
),
|
||||
FlatButton(
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
@ -176,18 +180,18 @@ class _NoticeboardPostState extends State<NoticeboardPost> {
|
||||
!isReply ? GestureDetector(
|
||||
onTap: () => setState(() => _isReplying = !_isReplying),
|
||||
child: Text(replyText, style: TextStyle(color: replyCount > 0 ? Colors.pink : Colors.black, fontSize: 10, fontWeight: FontWeight.bold)),
|
||||
): null,
|
||||
].where((o) => o != null).toList(),
|
||||
): SizedBox(width: 0),
|
||||
],
|
||||
),
|
||||
Row(children: [
|
||||
SizedBox(width: 45),
|
||||
Expanded(child: Text(_entry['content'], textAlign: TextAlign.left))
|
||||
]),
|
||||
_isReplying ? NoticeboardInput(_replyController, _sendReply, _replying, label: 'Reply to this post') : null,
|
||||
_isReplying ? NoticeboardInput(_replyController, _sendReply, _replying, label: 'Reply to this post') : SizedBox(width: 0),
|
||||
Column(
|
||||
children: replyWidgets
|
||||
),
|
||||
].where((o) => o != null).toList(),
|
||||
],
|
||||
))
|
||||
);
|
||||
}
|
||||
@ -215,7 +219,7 @@ class NoticeboardInput extends StatelessWidget {
|
||||
),
|
||||
)),
|
||||
IconButton(
|
||||
onPressed: _onPost,
|
||||
onPressed: () => _onPost!(),
|
||||
color: Colors.pink,
|
||||
icon: _posting ? CircularProgressIndicator() : Icon(Icons.send),
|
||||
)
|
||||
|
@ -80,9 +80,9 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
)]
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
RaisedButton(
|
||||
ElevatedButton(
|
||||
onPressed: () => _submit(context),
|
||||
color: Colors.pink,
|
||||
//color: Colors.pink,
|
||||
child: _loggingIn ? SizedBox(height: 20, width: 20, child:CircularProgressIndicator(backgroundColor: Colors.white)) : Text("Login",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(color: Colors.white, fontSize: 15)
|
||||
|
@ -3,7 +3,7 @@ import 'package:provider/provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
//import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'api.dart';
|
||||
import 'store.dart';
|
||||
import 'welcome.dart';
|
||||
@ -42,7 +42,7 @@ class _AppState extends State<MyApp> {
|
||||
title: 'Treadl',
|
||||
theme: ThemeData(
|
||||
primarySwatch: Colors.pink,
|
||||
textSelectionColor: Colors.blue,
|
||||
//textSelectionColor: Colors.blue,
|
||||
),
|
||||
home: Startup(),
|
||||
routes: <String, WidgetBuilder>{
|
||||
@ -64,12 +64,12 @@ class Startup extends StatelessWidget {
|
||||
Startup() {
|
||||
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
|
||||
if (message.notification != null) {
|
||||
print(message.notification.body);
|
||||
print(message.notification!);
|
||||
String text = '';
|
||||
if (message.notification != null && message.notification.body != null) {
|
||||
text = message.notification.body;
|
||||
if (message.notification != null && message.notification!.body != null) {
|
||||
text = message.notification!.body!;
|
||||
}
|
||||
Fluttertoast.showToast(
|
||||
/*Fluttertoast.showToast(
|
||||
msg: text,
|
||||
toastLength: Toast.LENGTH_LONG,
|
||||
gravity: ToastGravity.TOP,
|
||||
@ -77,7 +77,7 @@ class Startup extends StatelessWidget {
|
||||
backgroundColor: Colors.grey[100],
|
||||
textColor: Colors.black,
|
||||
fontSize: 16.0
|
||||
);
|
||||
);*/
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -86,9 +86,9 @@ class Startup extends StatelessWidget {
|
||||
if (_handled) return;
|
||||
_handled = true;
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
final String token = prefs.getString('apiToken');
|
||||
String? token = prefs.getString('apiToken');
|
||||
if (token != null) {
|
||||
Provider.of<Store>(context, listen: false).setToken(token);
|
||||
Provider.of<Store>(context, listen: false).setToken(token!);
|
||||
|
||||
FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
|
||||
await _firebaseMessaging.requestPermission(
|
||||
@ -100,16 +100,14 @@ class Startup extends StatelessWidget {
|
||||
provisional: false,
|
||||
sound: true,
|
||||
);
|
||||
String _pushToken = await _firebaseMessaging.getToken();
|
||||
String? _pushToken = await _firebaseMessaging.getToken();
|
||||
if (_pushToken != null) {
|
||||
print("sending push");
|
||||
Api api = Api();
|
||||
api.request('PUT', '/accounts/pushToken', {'pushToken': _pushToken});
|
||||
api.request('PUT', '/accounts/pushToken', {'pushToken': _pushToken!});
|
||||
}
|
||||
print('111');
|
||||
// Push without including current route in stack:
|
||||
Navigator.of(context, rootNavigator: true).pushNamedAndRemoveUntil('/home', (Route<dynamic> route) => false);
|
||||
print('222');
|
||||
} else {
|
||||
Navigator.of(context).pushNamedAndRemoveUntil('/welcome', (Route<dynamic> route) => false);
|
||||
}
|
||||
|
@ -6,11 +6,13 @@ import 'package:flutter_html/flutter_html.dart';
|
||||
import 'api.dart';
|
||||
|
||||
class _ObjectScreenState extends State<ObjectScreen> {
|
||||
final Map<String,dynamic> _object;
|
||||
final Map<String,dynamic> _project;
|
||||
Map<String,dynamic> _object;
|
||||
final Function _onUpdate;
|
||||
final Function _onDelete;
|
||||
final Api api = Api();
|
||||
|
||||
_ObjectScreenState(this._object, this._onDelete) { }
|
||||
_ObjectScreenState(this._object, this._project, this._onUpdate, this._onDelete) { }
|
||||
|
||||
void _deleteObject(BuildContext context, BuildContext modalContext) async {
|
||||
var data = await api.request('DELETE', '/objects/' + _object['_id']);
|
||||
@ -26,7 +28,7 @@ class _ObjectScreenState extends State<ObjectScreen> {
|
||||
showDialog(
|
||||
context: modalContext,
|
||||
builder: (BuildContext context) => CupertinoAlertDialog(
|
||||
title: new Text('Really delete this object?'),
|
||||
title: new Text('Really delete this item?'),
|
||||
content: new Text('This action cannot be undone.'),
|
||||
actions: <Widget>[
|
||||
CupertinoDialogAction(
|
||||
@ -44,6 +46,47 @@ class _ObjectScreenState extends State<ObjectScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
void _renameObject(BuildContext context) {
|
||||
TextEditingController renameController = TextEditingController();
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text('Rename this item'),
|
||||
content: TextField(
|
||||
autofocus: true,
|
||||
controller: renameController,
|
||||
decoration: InputDecoration(hintText: "Enter a new name for the item"),
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
child: Text('CANCEL'),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: Text('OK'),
|
||||
onPressed: () async {
|
||||
print(renameController.text);
|
||||
var data = await api.request('PUT', '/objects/' + _object['_id'], {'name': renameController.text});
|
||||
if (data['success']) {
|
||||
Navigator.pop(context);
|
||||
_object['name'] = data['payload']['name'];
|
||||
_onUpdate(_object['_id'], data['payload']);
|
||||
setState(() {
|
||||
_object = _object;
|
||||
});
|
||||
}
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _showSettingsModal(context) {
|
||||
showCupertinoModalPopup(
|
||||
context: context,
|
||||
@ -55,9 +98,13 @@ class _ObjectScreenState extends State<ObjectScreen> {
|
||||
child: Text('Cancel')
|
||||
),
|
||||
actions: [
|
||||
CupertinoActionSheetAction(
|
||||
onPressed: () => _renameObject(context),
|
||||
child: Text('Rename item'),
|
||||
),
|
||||
CupertinoActionSheetAction(
|
||||
onPressed: () => _confirmDeleteObject(modalContext),
|
||||
child: Text('Delete object'),
|
||||
child: Text('Delete item'),
|
||||
isDestructiveAction: true,
|
||||
),
|
||||
]
|
||||
@ -71,11 +118,22 @@ class _ObjectScreenState extends State<ObjectScreen> {
|
||||
return Image.network(_object['url']);
|
||||
}
|
||||
else if (_object['type'] == 'pattern') {
|
||||
var dat = Uri.parse(_object['preview']).data;
|
||||
return Image.memory(dat.contentAsBytes());
|
||||
if (_object['previewUrl'] != null) {
|
||||
return Image.network(_object['previewUrl']!);;
|
||||
}
|
||||
else {
|
||||
return RaisedButton(child: Text('View file'), onPressed: () {
|
||||
return Column(
|
||||
children: [
|
||||
SizedBox(height: 50),
|
||||
Icon(Icons.pattern, size: 40),
|
||||
SizedBox(height: 20),
|
||||
Text('A preview of this pattern is not yet available'),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ElevatedButton(child: Text('View file'), onPressed: () {
|
||||
launch(_object['url']);
|
||||
});
|
||||
}
|
||||
@ -113,8 +171,10 @@ class _ObjectScreenState extends State<ObjectScreen> {
|
||||
|
||||
class ObjectScreen extends StatefulWidget {
|
||||
final Map<String,dynamic> _object;
|
||||
final Map<String,dynamic> _project;
|
||||
final Function _onUpdate;
|
||||
final Function _onDelete;
|
||||
ObjectScreen(this._object, this._onDelete) { }
|
||||
ObjectScreen(this._object, this._project, this._onUpdate, this._onDelete) { }
|
||||
@override
|
||||
_ObjectScreenState createState() => _ObjectScreenState(_object, _onDelete);
|
||||
_ObjectScreenState createState() => _ObjectScreenState(_object, _project, _onUpdate, _onDelete);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ class _OnboardingScreenState extends State<OnboardingScreen> {
|
||||
);
|
||||
final Api api = Api();
|
||||
bool _loading = false;
|
||||
String _pushToken;
|
||||
String? _pushToken;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
@ -36,7 +36,7 @@ class _OnboardingScreenState extends State<OnboardingScreen> {
|
||||
);
|
||||
_pushToken = await _firebaseMessaging.getToken();*/
|
||||
if (_pushToken != null) {
|
||||
api.request('PUT', '/accounts/pushToken', {'pushToken': _pushToken});
|
||||
api.request('PUT', '/accounts/pushToken', {'pushToken': _pushToken!});
|
||||
}
|
||||
setState(() => _loading = false);
|
||||
_controller.animateToPage(2, duration: Duration(milliseconds: 500), curve: Curves.easeInOut);
|
||||
@ -63,7 +63,7 @@ class _OnboardingScreenState extends State<OnboardingScreen> {
|
||||
SizedBox(height: 10),
|
||||
Text('You can create as many projects as you like. Upload weaving draft patterns, images, and other files to your projects to store and showcase your work.', style: TextStyle(color: Colors.white, fontSize: 13), textAlign: TextAlign.center),
|
||||
SizedBox(height: 10),
|
||||
RaisedButton(
|
||||
ElevatedButton(
|
||||
child: Text('OK, I know what projects are!'),
|
||||
onPressed: () => _controller.animateToPage(1, duration: Duration(milliseconds: 500), curve: Curves.easeInOut),
|
||||
)
|
||||
@ -84,12 +84,12 @@ class _OnboardingScreenState extends State<OnboardingScreen> {
|
||||
SizedBox(height: 10),
|
||||
Text('We recommend enabling push notifications so you can keep up-to-date with your groups and projects.', style: TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.bold), textAlign: TextAlign.center),
|
||||
SizedBox(height: 10),
|
||||
RaisedButton(
|
||||
ElevatedButton(
|
||||
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
_loading ? CircularProgressIndicator() : null,
|
||||
_loading ? SizedBox(width: 5) : null,
|
||||
_loading ? CircularProgressIndicator() : SizedBox(width: 0),
|
||||
_loading ? SizedBox(width: 5) : SizedBox(width: 0),
|
||||
Text('What\'s next?'),
|
||||
].where((o) => o != null).toList()),
|
||||
]),
|
||||
onPressed: _requestPushPermissions,
|
||||
)
|
||||
]
|
||||
@ -107,7 +107,7 @@ class _OnboardingScreenState extends State<OnboardingScreen> {
|
||||
SizedBox(height: 10),
|
||||
Text('You\'re ready to get started. If you have any questions or want to get in touch then just send us a quick tweet.', style: TextStyle(color: Colors.white, fontSize: 13), textAlign: TextAlign.center),
|
||||
SizedBox(height: 10),
|
||||
RaisedButton(
|
||||
ElevatedButton(
|
||||
child: Text('Let\'s go'),
|
||||
onPressed: () => Navigator.of(context).pushNamedAndRemoveUntil('/home', (Route<dynamic> route) => false),
|
||||
),
|
||||
|
@ -6,86 +6,8 @@ import 'dart:io';
|
||||
import 'api.dart';
|
||||
import 'object.dart';
|
||||
|
||||
class _ProjectSettingsDialog extends StatelessWidget {
|
||||
final Map<String,dynamic> _project;
|
||||
final Function _onDelete;
|
||||
final Function _onUpdateProject;
|
||||
final Api api = Api();
|
||||
_ProjectSettingsDialog(this._project, this._onDelete, this._onUpdateProject) {}
|
||||
|
||||
void _toggleVisibility(BuildContext context, bool checked) async {
|
||||
var data = await api.request('PUT', '/projects/' + _project['owner']['username'] + '/' + _project['path'], {'visibility': checked ? 'private': 'public'});
|
||||
if (data['success']) {
|
||||
Navigator.pop(context);
|
||||
_onUpdateProject(data['payload']);
|
||||
}
|
||||
}
|
||||
|
||||
void _deleteProject(BuildContext context, BuildContext modalContext) async {
|
||||
var data = await api.request('DELETE', '/projects/' + _project['owner']['username'] + '/' + _project['path']);
|
||||
if (data['success']) {
|
||||
Navigator.pop(context);
|
||||
Navigator.pop(modalContext);
|
||||
_onDelete();
|
||||
}
|
||||
}
|
||||
|
||||
void _confirmDeleteProject(BuildContext modalContext) {
|
||||
showDialog(
|
||||
context: modalContext,
|
||||
builder: (BuildContext context) => CupertinoAlertDialog(
|
||||
title: new Text('Really delete this project?'),
|
||||
content: new Text('This will remove any files and objects inside the project. This action cannot be undone.'),
|
||||
actions: <Widget>[
|
||||
CupertinoDialogAction(
|
||||
isDefaultAction: true,
|
||||
child: Text('No'),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
CupertinoDialogAction(
|
||||
isDestructiveAction: true,
|
||||
child: Text('Yes'),
|
||||
onPressed: () => _deleteProject(context, modalContext),
|
||||
),
|
||||
],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CupertinoActionSheet(
|
||||
title: Text('Manage this project'),
|
||||
cancelButton: CupertinoActionSheetAction(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text('Cancel')
|
||||
),
|
||||
actions: [
|
||||
Container(
|
||||
padding: EdgeInsets.all(5.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CupertinoSwitch(
|
||||
value: _project['visibility'] == 'private',
|
||||
onChanged: (c) => _toggleVisibility(context, c),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Text('Private project', style: Theme.of(context).textTheme.bodyText1),
|
||||
]
|
||||
)
|
||||
),
|
||||
CupertinoActionSheetAction(
|
||||
onPressed: () { _confirmDeleteProject(context); },
|
||||
child: Text('Delete project'),
|
||||
isDestructiveAction: true,
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ProjectScreenState extends State<ProjectScreen> {
|
||||
final Function _onUpdate;
|
||||
final Function _onDelete;
|
||||
final picker = ImagePicker();
|
||||
final Api api = Api();
|
||||
@ -94,7 +16,7 @@ class _ProjectScreenState extends State<ProjectScreen> {
|
||||
bool _loading = false;
|
||||
bool _creating = false;
|
||||
|
||||
_ProjectScreenState(this._project, this._onDelete) { }
|
||||
_ProjectScreenState(this._project, this._onUpdate, this._onDelete) { }
|
||||
|
||||
@override
|
||||
initState() {
|
||||
@ -122,8 +44,20 @@ class _ProjectScreenState extends State<ProjectScreen> {
|
||||
setState(() {
|
||||
_project = project;
|
||||
});
|
||||
_onUpdate(project['_id'], project);
|
||||
}
|
||||
|
||||
void _onUpdateObject(String id, Map<String,dynamic> update) {
|
||||
List<dynamic> _newObjects = _objects.map((o) {
|
||||
if (o['_id'] == id) {
|
||||
o.addAll(update);
|
||||
}
|
||||
return o;
|
||||
}).toList();
|
||||
setState(() {
|
||||
_objects = _newObjects;
|
||||
});
|
||||
}
|
||||
void _onDeleteObject(String id) {
|
||||
List<dynamic> _newObjects = _objects.where((p) => p['_id'] != id).toList();
|
||||
setState(() {
|
||||
@ -196,7 +130,7 @@ class _ProjectScreenState extends State<ProjectScreen> {
|
||||
showCupertinoModalPopup(context: context, builder: (BuildContext context) => settingsDialog);
|
||||
}
|
||||
|
||||
Widget getImageBox(data, [bool isMemory, bool isNetwork]) {
|
||||
Widget getMemoryImageBox(data, [bool? isMemory, bool? isNetwork]) {
|
||||
return new AspectRatio(
|
||||
aspectRatio: 1 / 1,
|
||||
child: new Container(
|
||||
@ -204,7 +138,21 @@ class _ProjectScreenState extends State<ProjectScreen> {
|
||||
image: new DecorationImage(
|
||||
fit: BoxFit.fitWidth,
|
||||
alignment: FractionalOffset.topCenter,
|
||||
image: isMemory == true ? new MemoryImage(data) : new NetworkImage(data)
|
||||
image: new MemoryImage(data),
|
||||
)
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
Widget getNetworkImageBox(String url) {
|
||||
return new AspectRatio(
|
||||
aspectRatio: 1 / 1,
|
||||
child: new Container(
|
||||
decoration: new BoxDecoration(
|
||||
image: new DecorationImage(
|
||||
fit: BoxFit.fitWidth,
|
||||
alignment: FractionalOffset.topCenter,
|
||||
image: new NetworkImage(url),
|
||||
)
|
||||
),
|
||||
),
|
||||
@ -232,17 +180,30 @@ class _ProjectScreenState extends State<ProjectScreen> {
|
||||
|
||||
if (object['isImage'] == true) {
|
||||
type = 'Image';
|
||||
leader = getImageBox(object['url']);
|
||||
if (object['url'] != null) {
|
||||
leader = getNetworkImageBox(object['url']!);
|
||||
}
|
||||
else if (object['type'] == 'pattern' && object['preview'] != null) {
|
||||
else {
|
||||
leader = getIconBox(Icon(Icons.photo));
|
||||
}
|
||||
}
|
||||
else if (object['type'] == 'pattern') {
|
||||
type = 'Weaving pattern';
|
||||
var dat = Uri.parse(object['preview']).data;
|
||||
leader = getImageBox(dat.contentAsBytes(), true);
|
||||
if (object['previewUrl'] != null) {
|
||||
leader = getNetworkImageBox(object['previewUrl']!);
|
||||
}
|
||||
else {
|
||||
leader = getIconBox(Icon(Icons.pattern));
|
||||
}
|
||||
}
|
||||
else if (object['type'] == 'file') {
|
||||
type = 'File';
|
||||
leader = getIconBox(Icon(Icons.insert_drive_file));
|
||||
}
|
||||
else {
|
||||
type = 'Unknown';
|
||||
leader = getIconBox(Icon(Icons.file_present));
|
||||
}
|
||||
|
||||
return new Card(
|
||||
child: InkWell(
|
||||
@ -250,7 +211,7 @@ class _ProjectScreenState extends State<ProjectScreen> {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ObjectScreen(object, _onDeleteObject),
|
||||
builder: (context) => ObjectScreen(object, _project, _onUpdateObject, _onDeleteObject),
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -319,8 +280,129 @@ class _ProjectScreenState extends State<ProjectScreen> {
|
||||
|
||||
class ProjectScreen extends StatefulWidget {
|
||||
final Map<String,dynamic> _project;
|
||||
final Function _onUpdate;
|
||||
final Function _onDelete;
|
||||
ProjectScreen(this._project, this._onDelete) { }
|
||||
ProjectScreen(this._project, this._onUpdate, this._onDelete) { }
|
||||
@override
|
||||
_ProjectScreenState createState() => _ProjectScreenState(_project, _onDelete);
|
||||
_ProjectScreenState createState() => _ProjectScreenState(_project, _onUpdate, _onDelete);
|
||||
}
|
||||
|
||||
class _ProjectSettingsDialog extends StatelessWidget {
|
||||
final Map<String,dynamic> _project;
|
||||
final Function _onDelete;
|
||||
final Function _onUpdateProject;
|
||||
final Api api = Api();
|
||||
_ProjectSettingsDialog(this._project, this._onDelete, this._onUpdateProject) {}
|
||||
|
||||
void _renameProject(BuildContext context) async {
|
||||
TextEditingController renameController = TextEditingController();
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text('Rename your project'),
|
||||
content: TextField(
|
||||
autofocus: true,
|
||||
controller: renameController,
|
||||
decoration: InputDecoration(hintText: "Enter a new name for the project"),
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
child: Text('CANCEL'),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: Text('OK'),
|
||||
onPressed: () async {
|
||||
print(renameController.text);
|
||||
var data = await api.request('PUT', '/projects/' + _project['owner']['username'] + '/' + _project['path'], {'name': renameController.text});
|
||||
if (data['success']) {
|
||||
Navigator.pop(context);
|
||||
_onUpdateProject(data['payload']);
|
||||
}
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _toggleVisibility(BuildContext context, bool checked) async {
|
||||
var data = await api.request('PUT', '/projects/' + _project['owner']['username'] + '/' + _project['path'], {'visibility': checked ? 'private': 'public'});
|
||||
if (data['success']) {
|
||||
Navigator.pop(context);
|
||||
_onUpdateProject(data['payload']);
|
||||
}
|
||||
}
|
||||
|
||||
void _deleteProject(BuildContext context, BuildContext modalContext) async {
|
||||
var data = await api.request('DELETE', '/projects/' + _project['owner']['username'] + '/' + _project['path']);
|
||||
if (data['success']) {
|
||||
Navigator.pop(context);
|
||||
Navigator.pop(modalContext);
|
||||
_onDelete();
|
||||
}
|
||||
}
|
||||
|
||||
void _confirmDeleteProject(BuildContext modalContext) {
|
||||
showDialog(
|
||||
context: modalContext,
|
||||
builder: (BuildContext context) => CupertinoAlertDialog(
|
||||
title: new Text('Really delete this project?'),
|
||||
content: new Text('This will remove any files and objects inside the project. This action cannot be undone.'),
|
||||
actions: <Widget>[
|
||||
CupertinoDialogAction(
|
||||
isDefaultAction: true,
|
||||
child: Text('No'),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
CupertinoDialogAction(
|
||||
isDestructiveAction: true,
|
||||
child: Text('Yes'),
|
||||
onPressed: () => _deleteProject(context, modalContext),
|
||||
),
|
||||
],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CupertinoActionSheet(
|
||||
title: Text('Manage this project'),
|
||||
cancelButton: CupertinoActionSheetAction(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text('Cancel')
|
||||
),
|
||||
actions: [
|
||||
Container(
|
||||
padding: EdgeInsets.all(5.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CupertinoSwitch(
|
||||
value: _project['visibility'] == 'private',
|
||||
onChanged: (c) => _toggleVisibility(context, c),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Text('Private project', style: Theme.of(context).textTheme.bodyText1),
|
||||
]
|
||||
)
|
||||
),
|
||||
CupertinoActionSheetAction(
|
||||
onPressed: () { _renameProject(context); },
|
||||
child: Text('Rename project'),
|
||||
),
|
||||
CupertinoActionSheetAction(
|
||||
onPressed: () { _confirmDeleteProject(context); },
|
||||
child: Text('Delete project'),
|
||||
isDestructiveAction: true,
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
@ -6,6 +6,164 @@ import 'api.dart';
|
||||
import 'project.dart';
|
||||
import 'settings.dart';
|
||||
|
||||
class _ProjectsTabState extends State<ProjectsTab> {
|
||||
List<dynamic> _projects = [];
|
||||
bool _loading = false;
|
||||
bool _creatingProject = false;
|
||||
final Api api = Api();
|
||||
|
||||
@override
|
||||
initState() {
|
||||
super.initState();
|
||||
getProjects();
|
||||
}
|
||||
|
||||
void getProjects() async {
|
||||
setState(() {
|
||||
_loading = true;
|
||||
});
|
||||
var data = await api.request('GET', '/users/me/projects');
|
||||
if (data['success'] == true) {
|
||||
setState(() {
|
||||
_projects = data['payload']['projects'];
|
||||
_loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _onCreatingProject() {
|
||||
setState(() {
|
||||
_creatingProject = true;
|
||||
});
|
||||
}
|
||||
void _onCreateProject(newProject) {
|
||||
List<dynamic> _newProjects = _projects;
|
||||
_newProjects.insert(0, newProject);
|
||||
setState(() {
|
||||
_projects = _newProjects;
|
||||
_creatingProject = false;
|
||||
});
|
||||
}
|
||||
|
||||
void _onUpdateProject(String id, Map<String,dynamic> update) {
|
||||
List<dynamic> _newProjects = _projects.map((p) {
|
||||
if (p['_id'] == id) {
|
||||
p.addAll(update);
|
||||
}
|
||||
return p;
|
||||
}).toList();
|
||||
setState(() {
|
||||
_projects = _newProjects;
|
||||
});
|
||||
}
|
||||
|
||||
void _onDeleteProject(String id) {
|
||||
List<dynamic> _newProjects = _projects.where((p) => p['_id'] != id).toList();
|
||||
setState(() {
|
||||
_projects = _newProjects;
|
||||
});
|
||||
}
|
||||
|
||||
void showNewProjectDialog() async {
|
||||
Widget simpleDialog = new _NewProjectDialog(_onCreatingProject, _onCreateProject);
|
||||
showDialog(context: context, builder: (BuildContext context) => simpleDialog);
|
||||
}
|
||||
|
||||
Widget buildProjectCard(Map<String,dynamic> project) {
|
||||
String description = project['description'] != null ? project['description'].replaceAll("\n", " ") : '';
|
||||
if (description != null && description.length > 80) {
|
||||
description = description.substring(0, 77) + '...';
|
||||
}
|
||||
if (project['visibility'] == 'public') {
|
||||
description = "PUBLIC PROJECT\n" + description;
|
||||
}
|
||||
else description = "PRIVATE PROJECT\n" + description;
|
||||
return new Card(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ProjectScreen(project, _onUpdateProject, _onDeleteProject),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
new ListTile(
|
||||
leading: Icon(Icons.folder_open),
|
||||
trailing: Icon(Icons.keyboard_arrow_right),
|
||||
title: Text(project['name'] != null ? project['name'] : 'Untitled project'),
|
||||
subtitle: Text(description),
|
||||
),
|
||||
]
|
||||
),
|
||||
)
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Your Projects'),
|
||||
actions: <Widget>[
|
||||
IconButton(
|
||||
icon: Icon(Icons.info_outline),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => SettingsScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
]
|
||||
),
|
||||
body: _loading ?
|
||||
Container(
|
||||
margin: const EdgeInsets.all(10.0),
|
||||
alignment: Alignment.center,
|
||||
child: CircularProgressIndicator()
|
||||
)
|
||||
: Container(
|
||||
margin: const EdgeInsets.all(10.0),
|
||||
alignment: Alignment.center,
|
||||
child: (_projects != null && _projects.length > 0) ?
|
||||
ListView.builder(
|
||||
itemCount: _projects.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return buildProjectCard(_projects[index]);
|
||||
},
|
||||
)
|
||||
:
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text('Create your first project', style: TextStyle(fontSize: 20), textAlign: TextAlign.center),
|
||||
Image(image: AssetImage('assets/reading.png'), width: 300),
|
||||
Text('Projects contain all the files and patterns that make up a piece of work. Create one using the + button below.', textAlign: TextAlign.center),
|
||||
])
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: showNewProjectDialog,
|
||||
child: _creatingProject ? CircularProgressIndicator(backgroundColor: Colors.white) : Icon(Icons.add),
|
||||
backgroundColor: Colors.pink[500],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ProjectsTab extends StatefulWidget {
|
||||
@override
|
||||
_ProjectsTabState createState() => _ProjectsTabState();
|
||||
}
|
||||
|
||||
class _NewProjectDialogState extends State<_NewProjectDialog> {
|
||||
final TextEditingController _newProjectNameController = TextEditingController();
|
||||
final Function _onStart;
|
||||
@ -82,155 +240,3 @@ class _NewProjectDialog extends StatefulWidget {
|
||||
@override
|
||||
_NewProjectDialogState createState() => _NewProjectDialogState(_onStart, _onComplete);
|
||||
}
|
||||
|
||||
class _ProjectsTabState extends State<ProjectsTab> {
|
||||
List<dynamic> _projects = [];
|
||||
bool _loading = false;
|
||||
bool _creatingProject = false;
|
||||
final Api api = Api();
|
||||
|
||||
@override
|
||||
initState() {
|
||||
super.initState();
|
||||
getProjects();
|
||||
}
|
||||
|
||||
void getProjects() async {
|
||||
setState(() {
|
||||
_loading = true;
|
||||
});
|
||||
var data = await api.request('GET', '/users/me/projects');
|
||||
if (data['success'] == true) {
|
||||
setState(() {
|
||||
_projects = data['payload']['projects'];
|
||||
_loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _onCreatingProject() {
|
||||
setState(() {
|
||||
_creatingProject = true;
|
||||
});
|
||||
}
|
||||
void _onCreateProject(newProject) {
|
||||
List<dynamic> _newProjects = _projects;
|
||||
_newProjects.insert(0, newProject);
|
||||
setState(() {
|
||||
_projects = _newProjects;
|
||||
_creatingProject = false;
|
||||
});
|
||||
}
|
||||
|
||||
void _onDeleteProject(String id) {
|
||||
List<dynamic> _newProjects = _projects.where((p) => p['_id'] != id).toList();
|
||||
setState(() {
|
||||
_projects = _newProjects;
|
||||
});
|
||||
}
|
||||
|
||||
void showNewProjectDialog() async {
|
||||
Widget simpleDialog = new _NewProjectDialog(_onCreatingProject, _onCreateProject);
|
||||
showDialog(context: context, builder: (BuildContext context) => simpleDialog);
|
||||
}
|
||||
|
||||
Widget buildProjectCard(Map<String,dynamic> project) {
|
||||
String description = project['description'] != null ? project['description'] : '';
|
||||
if (description != null && description.length > 80) {
|
||||
description = description.substring(0, 77) + '...';
|
||||
}
|
||||
return new Card(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ProjectScreen(project, _onDeleteProject),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
new ListTile(
|
||||
leading: Icon(Icons.folder_open),
|
||||
trailing: Icon(Icons.keyboard_arrow_right),
|
||||
title: Text(project['name'] != null ? project['name'] : 'Untitled project'),
|
||||
subtitle: Text(description.replaceAll("\n", " ")),
|
||||
),
|
||||
/*ButtonBar(
|
||||
children: <Widget>[
|
||||
FlatButton(
|
||||
child: const Text('VIEW'),
|
||||
onPressed: () {
|
||||
|
||||
}
|
||||
),
|
||||
],
|
||||
),*/
|
||||
]
|
||||
),
|
||||
)
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Your Projects'),
|
||||
actions: <Widget>[
|
||||
IconButton(
|
||||
icon: Icon(Icons.info_outline),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => SettingsScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
]
|
||||
),
|
||||
body: _loading ?
|
||||
Container(
|
||||
margin: const EdgeInsets.all(10.0),
|
||||
alignment: Alignment.center,
|
||||
child: CircularProgressIndicator()
|
||||
)
|
||||
: Container(
|
||||
margin: const EdgeInsets.all(10.0),
|
||||
alignment: Alignment.center,
|
||||
child: (_projects != null && _projects.length > 0) ?
|
||||
ListView.builder(
|
||||
itemCount: _projects.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return buildProjectCard(_projects[index]);
|
||||
},
|
||||
)
|
||||
:
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text('Create your first project', style: TextStyle(fontSize: 20), textAlign: TextAlign.center),
|
||||
Image(image: AssetImage('assets/reading.png'), width: 300),
|
||||
Text('Projects contain all the files and patterns that make up a piece of work. Create one using the + button below.', textAlign: TextAlign.center),
|
||||
])
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: showNewProjectDialog,
|
||||
child: _creatingProject ? CircularProgressIndicator(backgroundColor: Colors.white) : Icon(Icons.add),
|
||||
backgroundColor: Colors.pink[500],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ProjectsTab extends StatefulWidget {
|
||||
@override
|
||||
_ProjectsTabState createState() => _ProjectsTabState();
|
||||
}
|
||||
|
@ -97,9 +97,9 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
||||
),
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
RaisedButton(
|
||||
ElevatedButton(
|
||||
onPressed: () => _submit(context),
|
||||
color: Colors.pink,
|
||||
//color: Colors.pink,
|
||||
child: _registering ? SizedBox(height: 20, width: 20, child:CircularProgressIndicator(backgroundColor: Colors.white)) : Text("Register",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(color: Colors.white, fontSize: 15)
|
||||
|
@ -31,11 +31,11 @@ class SettingsScreen extends StatelessWidget {
|
||||
),
|
||||
]),
|
||||
actions: [
|
||||
FlatButton(
|
||||
TextButton(
|
||||
child: Text('Cancel'),
|
||||
onPressed: () { Navigator.of(context).pop(); }
|
||||
),
|
||||
RaisedButton(
|
||||
ElevatedButton(
|
||||
child: Text('Delete Account'),
|
||||
onPressed: () async {
|
||||
Api api = Api();
|
||||
|
@ -1,9 +1,9 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class Store extends ChangeNotifier {
|
||||
String apiToken;
|
||||
String? apiToken;
|
||||
|
||||
void setToken(String newToken) {
|
||||
void setToken(String? newToken) {
|
||||
apiToken = newToken;
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ class _UserScreenState extends State<UserScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String created;
|
||||
String? created;
|
||||
if (_user['createdAt'] != null) {
|
||||
DateTime createdAt = DateTime.parse(_user['createdAt']);
|
||||
created = DateFormat('MMMM y').format(createdAt);
|
||||
@ -68,7 +68,7 @@ class _UserScreenState extends State<UserScreen> {
|
||||
Text(_user['location'])
|
||||
]) : SizedBox(height: 1),
|
||||
SizedBox(height: 10),
|
||||
Text('Member' + (created != null ? (' since ' + created) : ''),
|
||||
Text('Member' + (created != null ? (' since ' + created!) : ''),
|
||||
style: TextStyle(color: Colors.grey[500])
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
|
@ -1,167 +1,182 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
_flutterfire_internals:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _flutterfire_internals
|
||||
sha256: "9ebe81588e666f7e2b21309f2b5653bd9642d7f27fd0a6894278d2ff40cb9481"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
archive:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: archive
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.1"
|
||||
version: "3.3.7"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
version: "2.4.2"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.8.2"
|
||||
version: "2.10.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.1.1"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: charcode
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
chewie:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: chewie
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
chewie_audio:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: chewie_audio
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.2.1"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: clock
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.1.1"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.15.0"
|
||||
version: "1.17.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: convert
|
||||
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
cross_file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cross_file
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.2"
|
||||
version: "0.3.3+4"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: crypto
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
version: "3.0.3"
|
||||
csslib:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: csslib
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "831883fb353c8bdc1d71979e5b342c7d88acfbc643113c14ae51e2442ea0f20f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.17.1"
|
||||
version: "0.17.3"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cupertino_icons
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
version: "1.0.5"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.3.1"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: ffi
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "2.0.2"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.2"
|
||||
version: "6.1.4"
|
||||
firebase_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: e9b36b391690cf329c6fb1de220045e97c13784c303820cd33962319580a56c6
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.13.1"
|
||||
version: "2.13.1"
|
||||
firebase_core_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: b63e3be6c96ef5c33bdec1aab23c91eb00696f6452f0519401d640938c94cba2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.5"
|
||||
version: "4.8.0"
|
||||
firebase_core_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_web
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "8c0f4c87d20e2d001a5915df238c1f9c88704231f591324205f5a5d2a7740a45"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.6.1"
|
||||
version: "2.5.0"
|
||||
firebase_messaging:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_messaging
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: a01d7b9eb43a4bad54a411edb2b4124089d88eab029191893e83c39e18ab19f7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "11.2.8"
|
||||
version: "14.6.2"
|
||||
firebase_messaging_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: c2fef3e30fbfa3a71d74477df102d1c2f5aad860bb68bb4086b0af3b12abedf3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.1"
|
||||
version: "4.5.2"
|
||||
firebase_messaging_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_web
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "8d280f0110ca4946b9863e578b9879874066ac486ffa596a609aab329fb6fa7e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.9"
|
||||
version: "3.5.2"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@ -171,44 +186,26 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_html
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "02ad69e813ecfc0728a455e4bf892b9379983e050722b1dce00192ee2e41d1ee"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
version: "3.0.0-beta.2"
|
||||
flutter_launcher_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_launcher_icons
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "559c600f056e7c704bd843723c21e01b5fba47e8824bd02422165bcc02a5de1d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.2"
|
||||
flutter_layout_grid:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_layout_grid
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
flutter_math_fork:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_math_fork
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.5.0"
|
||||
version: "0.9.3"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_plugin_android_lifecycle
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "950e77c2bbe1692bc0874fc7fb491b96a4dc340457f4ea1641443d0a6c1ea360"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
flutter_svg:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_svg
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.23.0+1"
|
||||
version: "2.0.15"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
@ -219,251 +216,270 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
fluttertoast:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: fluttertoast
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "8.0.9"
|
||||
html:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: html
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "58e3491f7bf0b6a4ea5110c0c688877460d1a6366731155c4a4580e7ded773e8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.15.0"
|
||||
version: "0.15.3"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.13.4"
|
||||
version: "0.13.6"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
version: "4.0.2"
|
||||
image:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "02bafd3b4f399bfeb10034deba9753d93b55ce41cd0c4d3d8b355626f80e5b32"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
image_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: image_picker
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "9978d3510af4e6a902e545ce19229b926e6de6a1828d6134d3aab2e129a4d270"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.4+10"
|
||||
version: "0.8.7+5"
|
||||
image_picker_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_android
|
||||
sha256: "3083c3a3245adf9f3eb7bacf0eaa6a1f087dd538fab73a13a2f7907602601692"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.6+19"
|
||||
image_picker_for_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_for_web
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "98f50d6b9f294c8ba35e25cc0d13b04bfddd25dbc8d32fa9d566a6572f2c081c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.6"
|
||||
version: "2.1.12"
|
||||
image_picker_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_ios
|
||||
sha256: d779210bda268a03b57e923fb1e410f32f5c5e708ad256348bcbf1f44f558fd0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.7+4"
|
||||
image_picker_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "1991219d9dbc42a99aff77e663af8ca51ced592cd6685c9485e3458302d3d4f8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.4"
|
||||
version: "2.6.3"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: intl
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.17.0"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.3"
|
||||
version: "0.6.5"
|
||||
list_counter:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: list_counter
|
||||
sha256: c447ae3dfcd1c55f0152867090e67e219d42fe6d4f2807db4bbe8b8d69912237
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.11"
|
||||
version: "0.12.13"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.3"
|
||||
version: "0.2.0"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.7.0"
|
||||
version: "1.8.0"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: nested
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
numerus:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: numerus
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.8.0"
|
||||
path_drawing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_drawing
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.5.1+1"
|
||||
path_parsing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_parsing
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.1"
|
||||
version: "1.8.2"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_linux
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.5"
|
||||
version: "2.1.11"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
version: "2.0.6"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
version: "2.1.7"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: petitparser
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.4.0"
|
||||
version: "5.1.0"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
version: "2.1.4"
|
||||
pointycastle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pointycastle
|
||||
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.7.3"
|
||||
process:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: process
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.4"
|
||||
provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: provider
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.2"
|
||||
quiver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: quiver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.1+1"
|
||||
version: "6.0.5"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "16d3fb6b3692ad244a695c0183fca18cf81fd4b821664394a781de42386bf022"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.13"
|
||||
version: "2.1.1"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "6478c6bbbecfe9aced34c483171e90d7c078f5883558b30ec3163cf18402c749"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.11"
|
||||
shared_preferences_ios:
|
||||
version: "2.1.4"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_ios
|
||||
url: "https://pub.dartlang.org"
|
||||
name: shared_preferences_foundation
|
||||
sha256: e014107bb79d6d3297196f4f2d0db54b5d1f85b8ea8ff63b8e8b391a02700feb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.2.2"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "9d387433ca65717bbf1be88f4d5bb18f10508917a8fa2fb02e0fd0d7479a9afa"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
shared_preferences_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
version: "2.2.0"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: fb5cf25c0235df2d0640ac1b1174f6466bd311f621574997ac59018a6664548d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
version: "2.2.0"
|
||||
shared_preferences_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "74083203a8eae241e0de4a0d597dbedab3b8fef5563f33cf3c12d7e93c655ca5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
version: "2.1.0"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "5e588e2efef56916a3b229c3bfe81e6a525665a454519ca51dbcc4236a274173"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.2.0"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@ -473,254 +489,162 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.8.1"
|
||||
version: "1.9.1"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.0"
|
||||
version: "1.11.0"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.1.1"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.2.0"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.2.1"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.8"
|
||||
tuple:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: tuple
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
version: "0.4.16"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: typed_data
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.3.2"
|
||||
url_launcher:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: url_launcher
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.20"
|
||||
version: "6.1.11"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: eed4e6a1164aa9794409325c3b707ff424d4d1c2a785e7db67f8bbda00e36e51
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.15"
|
||||
version: "6.0.35"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.15"
|
||||
version: "6.1.4"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_linux
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "3.0.5"
|
||||
url_launcher_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "91ee3e75ea9dadf38036200c5d3743518f4a5eb77a8d13fda1ee5764373f185e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "3.0.5"
|
||||
url_launcher_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "6c9ca697a5ae218ce56cece69d46128169a58aa8653c1b01d26fcd4aad8c4370"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
version: "2.1.2"
|
||||
url_launcher_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_web
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "6bb1e5d7fe53daf02a8fee85352432a40b1f868a81880e99ec7440113d5cfcab"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.9"
|
||||
version: "2.0.17"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "254708f17f7c20a9c8c471f67d86d76d4a3f9c1591aad1e15292008aceb82771"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "3.0.6"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
very_good_analysis:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: very_good_analysis
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
video_player:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: video_player
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.19"
|
||||
video_player_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: video_player_android
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
video_player_avfoundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: video_player_avfoundation
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
video_player_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: video_player_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.1.0"
|
||||
video_player_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: video_player_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.7"
|
||||
wakelock:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: wakelock
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.1+1"
|
||||
wakelock_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: wakelock_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.0"
|
||||
wakelock_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: wakelock_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
wakelock_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: wakelock_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.0"
|
||||
wakelock_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: wakelock_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
webview_flutter:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.8.0"
|
||||
webview_flutter_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_android
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.8.3"
|
||||
webview_flutter_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.1"
|
||||
webview_flutter_wkwebview:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_wkwebview
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.7.1"
|
||||
version: "2.1.4"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: a6f0236dbda0f63aa9a25ad1ff9a9d8a4eaaa5012da0dc59d21afdb1dc361ca4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
version: "3.1.4"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xdg_directories
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.0+1"
|
||||
version: "1.0.0"
|
||||
xml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xml
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "80d494c09849dc3f899d227a78c30c5b949b985ededf884cb3f3bcd39f4b447a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.3.1"
|
||||
version: "5.4.1"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: yaml
|
||||
url: "https://pub.dartlang.org"
|
||||
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "3.1.2"
|
||||
sdks:
|
||||
dart: ">=2.16.0 <3.0.0"
|
||||
flutter: ">=2.10.0"
|
||||
dart: ">=2.19.0 <3.0.0"
|
||||
flutter: ">=3.3.0"
|
||||
|
@ -15,25 +15,25 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 1.0.2+7
|
||||
version: 1.1.0+8
|
||||
|
||||
environment:
|
||||
sdk: ">=2.7.0 <3.0.0"
|
||||
sdk: '>=2.17.0 <3.0.0'
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
cupertino_icons: ^1.0.3
|
||||
http: ^0.13.3
|
||||
shared_preferences: ^2.0.11
|
||||
provider: ^6.0.1
|
||||
url_launcher: ^6.0.17
|
||||
flutter_html: ^2.2.1
|
||||
cupertino_icons: ^1.0.4
|
||||
http: ^0.13.4
|
||||
shared_preferences: ^2.0.15
|
||||
provider: ^6.0.3
|
||||
url_launcher: ^6.1.2
|
||||
flutter_html: ^3.0.0-alpha.3
|
||||
intl: ^0.17.0
|
||||
image_picker: ^0.8.4
|
||||
image_picker: ^0.8.5+3
|
||||
flutter_launcher_icons: ^0.9.0
|
||||
firebase_messaging: ^11.2.3
|
||||
fluttertoast: ^8.0.9
|
||||
firebase_messaging: ^14.4.0
|
||||
#fluttertoast: ^8.0.9
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
@ -6,4 +6,26 @@ export const uploads = {
|
||||
}, success, fail) {
|
||||
api.authenticatedRequest('GET', `/uploads/file/request?name=${name}&size=${size}&type=${type}&forType=${forType}&forId=${forId}`, null, success, fail);
|
||||
},
|
||||
uploadFile(forType, forId, name, file, success, fail) {
|
||||
uploads.generateFileUploadRequest({
|
||||
forType, forId, name, size: file.size, type: file.type || 'image/png',
|
||||
}, (response) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('PUT', response.signedRequest);
|
||||
xhr.setRequestHeader('Content-Type', file.type);
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status === 200) {
|
||||
// We pass back the original file name so it can be displayed nicely
|
||||
success && success({ storedName: response.fileName, name: file.name, type: 'file' });
|
||||
} else if (onError) {
|
||||
fail && fail({ message: 'Unable to upload file' });
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.send(file);
|
||||
}, (err) => {
|
||||
fail && fail(err);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
@ -7,7 +7,7 @@ export default function PatternCard({ object, project, user }) {
|
||||
if (!object) return null;
|
||||
return (
|
||||
<Card raised key={object._id} style={{ cursor: 'pointer' }} as={Link} to={`/${user?.username}/${project?.path}/${object._id}`}>
|
||||
<div style={{ height: 200, backgroundImage: `url(${object.preview})`, backgroundSize: 'cover', backgroundPosition: 'top right', position: 'relative' }}>
|
||||
<div style={{ height: 200, backgroundImage: `url(${object.previewUrl})`, backgroundSize: 'cover', backgroundPosition: 'top right', position: 'relative' }}>
|
||||
{user &&
|
||||
<div style={{position: 'absolute', top: 5, left: 5, padding: '3px 6px', background: 'rgba(250,250,250,0.8)', borderRadius: 5}}>
|
||||
<UserChip user={user} />
|
||||
|
@ -8,7 +8,6 @@ import utils from '../../../utils/utils.js';
|
||||
import DiscoverCard from '../../includes/DiscoverCard';
|
||||
import PatternCard from '../../includes/PatternCard';
|
||||
import PatternLoader from '../../includes/PatternLoader';
|
||||
import DraftPreview from '../projects/objects/DraftPreview';
|
||||
|
||||
export default function Explore() {
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
@ -104,9 +104,9 @@ function ObjectList({ compact }) {
|
||||
{object.isImage &&
|
||||
<div style={{width:40, height:40, backgroundImage:`url(${utils.resizeUrl(object.url, 50)})`, backgroundSize:'cover', backgroundPosition:'center center'}} />
|
||||
}
|
||||
{object.type === 'pattern' && (object.preview
|
||||
{object.type === 'pattern' && (object.previewUrl
|
||||
? (
|
||||
<div style={{ height: 40, width:40, backgroundImage: `url(${object.preview})`, backgroundSize: 'cover', backgroundPosition: 'top right' }}
|
||||
<div style={{ height: 40, width:40, backgroundImage: `url(${object.previewUrl})`, backgroundSize: 'cover', backgroundPosition: 'top right' }}
|
||||
/>
|
||||
)
|
||||
: <div style={{ height: 40, width:40, backgroundImage: `url(${logoGreyShort})`, backgroundSize: '50px' }} />
|
||||
@ -145,9 +145,9 @@ function ObjectList({ compact }) {
|
||||
{filteredObjects.map((object, index) => (
|
||||
<Card raised key={object._id} style={{ cursor: 'pointer' }} as={Link} to={`/${fullProjectPath}/${object._id}`}>
|
||||
{object.type === 'pattern'
|
||||
&& (object.preview
|
||||
&& (object.previewUrl
|
||||
? (
|
||||
<div style={{ height: 200, backgroundImage: `url(${object.preview})`, backgroundSize: 'cover', backgroundPosition: 'top right' }}
|
||||
<div style={{ height: 200, backgroundImage: `url(${object.previewUrl})`, backgroundSize: 'cover', backgroundPosition: 'top right' }}
|
||||
/>
|
||||
)
|
||||
: <div style={{ height: 200, backgroundImage: `url(${logoGreyShort})`, backgroundSize: '50px' }} />
|
||||
|
@ -85,7 +85,7 @@ function ObjectViewer() {
|
||||
|
||||
const downloadDrawdownImage = (object) => {
|
||||
const element = document.createElement('a');
|
||||
element.setAttribute('href', object.preview);
|
||||
element.setAttribute('href', object.previewUrl);
|
||||
element.setAttribute('download', `${object.name.replace(/ /g, '_')}-drawdown.png`);
|
||||
element.style.display = 'none';
|
||||
document.body.appendChild(element);
|
||||
@ -118,10 +118,10 @@ function ObjectViewer() {
|
||||
<Helmet title={`${object.name || 'Project Item'} | ${project?.name || 'Project'}`} />
|
||||
|
||||
<div style={{ display: 'flex', justifyContent: 'end' }}>
|
||||
{object.type === 'pattern' && (project.user === (user && user._id) || project.openSource || object.preview) && <>
|
||||
{object.type === 'pattern' && (project.user === (user && user._id) || project.openSource || object.previewUrl) && <>
|
||||
<Dropdown direction='left' icon={null} trigger={<Button size='small' secondary icon='download' content='Download pattern' loading={downloading} disabled={downloading}/>}>
|
||||
<Dropdown.Menu>
|
||||
{object.preview &&
|
||||
{object.previewUrl &&
|
||||
<Dropdown.Item onClick={e => downloadDrawdownImage(object)} content='Download drawdown as an image' icon='file outline' />
|
||||
}
|
||||
{(project.user === (user && user._id) || project.openSource) &&
|
||||
|
@ -7,6 +7,7 @@ import styled from 'styled-components';
|
||||
import ElementPan from '../../../includes/ElementPan';
|
||||
import HelpLink from '../../../includes/HelpLink';
|
||||
import Tour, { ReRunTour } from '../../../includes/Tour';
|
||||
import util from '../../../../utils/utils.js';
|
||||
|
||||
import Warp from './Warp';
|
||||
import Weft from './Weft';
|
||||
@ -56,9 +57,10 @@ function Draft() {
|
||||
|
||||
const saveObject = () => {
|
||||
setSaving(true);
|
||||
const canvas = document.getElementsByClassName('drawdown')[0];
|
||||
util.generatePatternPreview(object, previewUrl => {
|
||||
dispatch(actions.objects.update(objectId, 'previewUrl', previewUrl));
|
||||
});
|
||||
const newObject = Object.assign({}, object);
|
||||
newObject.preview = canvas.toDataURL();
|
||||
newObject.pattern = pattern;
|
||||
api.objects.update(objectId, newObject, (o) => {
|
||||
toast.success('Pattern saved');
|
||||
|
@ -3,6 +3,7 @@ import { useDispatch } from 'react-redux';
|
||||
import { Loader } from 'semantic-ui-react';
|
||||
import actions from '../../../../actions';
|
||||
import api from '../../../../api';
|
||||
import util from '../../../../utils/utils.js';
|
||||
|
||||
import ElementPan from '../../../includes/ElementPan';
|
||||
import { StyledPattern } from '../../../main/projects/objects/Draft';
|
||||
@ -17,18 +18,6 @@ function DraftPreview({ object }) {
|
||||
const dispatch = useDispatch();
|
||||
const objectId = object?._id;
|
||||
|
||||
const generatePreview = useCallback(() => {
|
||||
setTimeout(() => {
|
||||
const c = document.getElementsByClassName('drawdown')[0];
|
||||
const preview = c?.toDataURL();
|
||||
if (preview) {
|
||||
api.objects.update(objectId, { preview }, () => {
|
||||
dispatch(actions.objects.update(objectId, 'preview', preview));
|
||||
});
|
||||
}
|
||||
}, 1000);
|
||||
}, [dispatch, objectId]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(actions.objects.updateEditor({ tool: 'pan' }));
|
||||
setLoading(true);
|
||||
@ -36,10 +25,17 @@ function DraftPreview({ object }) {
|
||||
setLoading(false);
|
||||
if (o.pattern && o.pattern.warp) {
|
||||
setPattern(o.pattern);
|
||||
if (!o.preview) generatePreview();
|
||||
// Generate the preview if not yet set (e.g. if from uploaded WIF)
|
||||
if (!o.previewUrl) {
|
||||
setTimeout(() => {
|
||||
util.generatePatternPreview(object, previewUrl => {
|
||||
dispatch(actions.objects.update(objectId, 'previewUrl', previewUrl));
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
}, err => setLoading(false));
|
||||
}, [dispatch, objectId, generatePreview]);
|
||||
}, [dispatch, objectId]);
|
||||
|
||||
const unifyCanvas = useCallback(() => {
|
||||
if (!pattern) return;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { createConfirmation } from 'react-confirm';
|
||||
import ConfirmModal from '../components/includes/ConfirmModal';
|
||||
import api from '../api';
|
||||
|
||||
import avatar1 from '../images/avatars/1.png';
|
||||
import avatar2 from '../images/avatars/2.png';
|
||||
@ -103,6 +104,18 @@ const utils = {
|
||||
if (IMAGE_SERVER) return `${import.meta.env.VITE_IMAGINARY_URL}/resize?width=${width}&url=${url}`;
|
||||
return url;
|
||||
},
|
||||
generatePatternPreview(object, callback) {
|
||||
const c = document.getElementsByClassName('drawdown')[0];
|
||||
c?.toBlob(blob => {
|
||||
if (blob) {
|
||||
api.uploads.uploadFile('project', object.project, `preview-${object._id}.png`, blob, response => {
|
||||
api.objects.update(object._id, { preview: response.storedName }, ({ previewUrl }) => {
|
||||
callback && callback(previewUrl);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default utils;
|
||||
|
Loading…
Reference in New Issue
Block a user