Compare commits
3 Commits
b2a6ca7244
...
0a5604d0ff
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a5604d0ff | |||
| 5e754ad233 | |||
| 5b9c92e4d3 |
@@ -70,6 +70,12 @@
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="com.yalantis.ucrop.UCropActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
|
||||
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
@@ -17,7 +18,9 @@ class AboutScreen extends StatelessWidget {
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset('assets/logo.png', width: 64, height: 64),
|
||||
Image.asset('assets/logo.png', width: 64, height: 64)
|
||||
.animate(onPlay: (c) => c.repeat())
|
||||
.rotate(duration: 1000.ms),
|
||||
Text(
|
||||
'Solian',
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:image_cropper/image_cropper.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:solian/exts.dart';
|
||||
@@ -50,26 +51,24 @@ class _PersonalizeScreenState extends State<PersonalizeScreen> {
|
||||
}
|
||||
|
||||
void _syncWidget() async {
|
||||
setState(() => _isBusy = true);
|
||||
_isBusy = true;
|
||||
|
||||
final AuthProvider auth = Get.find();
|
||||
final prof = auth.userProfile.value!;
|
||||
setState(() {
|
||||
_usernameController.text = prof['name'];
|
||||
_nicknameController.text = prof['nick'];
|
||||
_descriptionController.text = prof['description'];
|
||||
_firstNameController.text = prof['profile']['first_name'];
|
||||
_lastNameController.text = prof['profile']['last_name'];
|
||||
_avatar = prof['avatar'];
|
||||
_banner = prof['banner'];
|
||||
if (prof['profile']['birthday'] != null) {
|
||||
_birthday = DateTime.parse(prof['profile']['birthday']);
|
||||
_birthdayController.text =
|
||||
DateFormat('yyyy-MM-dd').format(_birthday!.toLocal());
|
||||
}
|
||||
_usernameController.text = prof['name'];
|
||||
_nicknameController.text = prof['nick'];
|
||||
_descriptionController.text = prof['description'];
|
||||
_firstNameController.text = prof['profile']['first_name'];
|
||||
_lastNameController.text = prof['profile']['last_name'];
|
||||
_avatar = prof['avatar'];
|
||||
_banner = prof['banner'];
|
||||
if (prof['profile']['birthday'] != null) {
|
||||
_birthday = DateTime.parse(prof['profile']['birthday']);
|
||||
_birthdayController.text =
|
||||
DateFormat('yyyy-MM-dd').format(_birthday!.toLocal());
|
||||
}
|
||||
|
||||
_isBusy = false;
|
||||
});
|
||||
_isBusy = false;
|
||||
}
|
||||
|
||||
Future<void> _editImage(String position) async {
|
||||
@@ -79,15 +78,40 @@ class _PersonalizeScreenState extends State<PersonalizeScreen> {
|
||||
final image = await _imagePicker.pickImage(source: ImageSource.gallery);
|
||||
if (image == null) return;
|
||||
|
||||
CroppedFile? croppedFile = await ImageCropper().cropImage(
|
||||
sourcePath: image.path,
|
||||
uiSettings: [
|
||||
AndroidUiSettings(
|
||||
toolbarTitle: 'cropImage'.tr,
|
||||
toolbarColor: Theme.of(context).colorScheme.primary,
|
||||
toolbarWidgetColor: Theme.of(context).colorScheme.onPrimary,
|
||||
aspectRatioPresets: [CropAspectRatioPreset.square],
|
||||
),
|
||||
IOSUiSettings(
|
||||
title: 'cropImage'.tr,
|
||||
aspectRatioPresets: [CropAspectRatioPreset.square],
|
||||
),
|
||||
WebUiSettings(
|
||||
context: context,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
if (croppedFile == null) return;
|
||||
final file = File(croppedFile.path);
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final AttachmentProvider provider = Get.find();
|
||||
|
||||
Response? attachResp;
|
||||
try {
|
||||
final file = File(image.path);
|
||||
attachResp = await provider.createAttachment(
|
||||
await file.readAsBytes(), file.path, 'p.$position', null);
|
||||
await file.readAsBytes(),
|
||||
file.path,
|
||||
'p.$position',
|
||||
null,
|
||||
);
|
||||
} catch (e) {
|
||||
setState(() => _isBusy = false);
|
||||
context.showErrorDialog(e);
|
||||
@@ -142,8 +166,7 @@ class _PersonalizeScreenState extends State<PersonalizeScreen> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
Future.delayed(Duration.zero, () => _syncWidget());
|
||||
_syncWidget();
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
abstract class ServiceFinder {
|
||||
static const bool devFlag = true;
|
||||
static const bool devFlag = false;
|
||||
|
||||
static const String dealerUrl =
|
||||
devFlag ? 'http://localhost:8442' : 'https://api.sn.solsynth.dev';
|
||||
|
||||
@@ -326,4 +326,5 @@ const i18nEnglish = {
|
||||
'themeColorLuka': 'Luka Pink',
|
||||
'themeColorApplied': 'Global theme color has been applied.',
|
||||
'attachmentSaved': 'Attachment saved to your system album.',
|
||||
'cropImage': 'Crop Image',
|
||||
};
|
||||
|
||||
@@ -303,4 +303,5 @@ const i18nSimplifiedChinese = {
|
||||
'themeColorLuka': '流音粉',
|
||||
'themeColorApplied': '全局主题颜色已应用',
|
||||
'attachmentSaved': '附件已保存到系统相册',
|
||||
'cropImage': '裁剪图片',
|
||||
};
|
||||
|
||||
@@ -8,9 +8,10 @@ import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:image_cropper/image_cropper.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:pasteboard/pasteboard.dart';
|
||||
import 'package:path/path.dart' show basename;
|
||||
import 'package:path/path.dart' show basename, extension;
|
||||
import 'package:solian/exts.dart';
|
||||
import 'package:solian/models/attachment.dart';
|
||||
import 'package:solian/platform.dart';
|
||||
@@ -203,6 +204,31 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _cropAttachment(int queueIndex) async {
|
||||
final task = _uploadController.queueOfUpload[queueIndex];
|
||||
CroppedFile? croppedFile = await ImageCropper().cropImage(
|
||||
sourcePath: task.file.path,
|
||||
uiSettings: [
|
||||
AndroidUiSettings(
|
||||
toolbarTitle: 'cropImage'.tr,
|
||||
toolbarColor: Theme.of(context).colorScheme.primary,
|
||||
toolbarWidgetColor: Theme.of(context).colorScheme.onPrimary,
|
||||
aspectRatioPresets: CropAspectRatioPreset.values,
|
||||
),
|
||||
IOSUiSettings(
|
||||
title: 'cropImage'.tr,
|
||||
aspectRatioPresets: CropAspectRatioPreset.values,
|
||||
),
|
||||
WebUiSettings(
|
||||
context: context,
|
||||
),
|
||||
],
|
||||
);
|
||||
if (croppedFile == null) return;
|
||||
_uploadController.queueOfUpload[queueIndex].file = File(croppedFile.path);
|
||||
_uploadController.queueOfUpload.refresh();
|
||||
}
|
||||
|
||||
Future<void> _deleteAttachment(Attachment element) async {
|
||||
setState(() => _isBusy = true);
|
||||
try {
|
||||
@@ -216,6 +242,9 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
||||
}
|
||||
|
||||
Widget _buildQueueEntry(AttachmentUploadTask element, int index) {
|
||||
final extName = extension(element.file.path).substring(1);
|
||||
final canBeCrop = ['png', 'jpg', 'jpeg', 'gif'].contains(extName);
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.only(left: 16, right: 8, bottom: 16),
|
||||
child: Card(
|
||||
@@ -269,23 +298,38 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
|
||||
child: Icon(Icons.check),
|
||||
),
|
||||
),
|
||||
if (!element.isCompleted && canBeCrop)
|
||||
Obx(
|
||||
() => IconButton(
|
||||
color: Colors.teal,
|
||||
icon: const Icon(Icons.crop),
|
||||
visualDensity: const VisualDensity(horizontal: -4),
|
||||
onPressed: _uploadController.isUploading.value
|
||||
? null
|
||||
: () {
|
||||
_cropAttachment(index);
|
||||
},
|
||||
),
|
||||
),
|
||||
if (!element.isCompleted && !element.isUploading)
|
||||
IconButton(
|
||||
color: Colors.green,
|
||||
icon: const Icon(Icons.play_arrow),
|
||||
visualDensity: const VisualDensity(horizontal: -4),
|
||||
onPressed: _uploadController.isUploading.value
|
||||
? null
|
||||
: () {
|
||||
_uploadController
|
||||
.performSingleTask(index)
|
||||
.then((r) {
|
||||
widget.onAdd(r.id);
|
||||
if (mounted) {
|
||||
setState(() => _attachments.add(r));
|
||||
}
|
||||
});
|
||||
},
|
||||
Obx(
|
||||
() => IconButton(
|
||||
color: Colors.green,
|
||||
icon: const Icon(Icons.play_arrow),
|
||||
visualDensity: const VisualDensity(horizontal: -4),
|
||||
onPressed: _uploadController.isUploading.value
|
||||
? null
|
||||
: () {
|
||||
_uploadController
|
||||
.performSingleTask(index)
|
||||
.then((r) {
|
||||
widget.onAdd(r.id);
|
||||
if (mounted) {
|
||||
setState(() => _attachments.add(r));
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
if (!element.isCompleted && !element.isUploading)
|
||||
IconButton(
|
||||
|
||||
@@ -2,7 +2,7 @@ name: solian
|
||||
description: "The Solar Network App"
|
||||
publish_to: "none"
|
||||
|
||||
version: 1.2.0+6
|
||||
version: 1.2.0+7
|
||||
|
||||
environment:
|
||||
sdk: ">=3.3.4 <4.0.0"
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
<meta name="apple-mobile-web-app-title" content="solian" />
|
||||
<link rel="apple-touch-icon" href="icons/Icon-192.png" />
|
||||
|
||||
<!-- Cropper.js -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.6.2/cropper.css" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.6.2/cropper.min.js"></script>
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user