diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index d87d758..18954dc 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -41,5 +41,13 @@
UIViewControllerBasedStatusBarAppearance
+
+
+ NSPhotoLibraryUsageDescription
+ For uploading images for posts/avatars
+ NSCameraUsageDescription
+ For uploading images for posts/avatars
+ NSMicrophoneUsageDescription
+ For recording videos for posts
diff --git a/lib/hooks/image_picker.dart b/lib/hooks/image_picker.dart
new file mode 100644
index 0000000..8f2babd
--- /dev/null
+++ b/lib/hooks/image_picker.dart
@@ -0,0 +1,4 @@
+import 'package:flutter_hooks/flutter_hooks.dart';
+import 'package:image_picker/image_picker.dart';
+
+ImagePicker useImagePicker() => useMemoized(() => ImagePicker());
diff --git a/lib/pages/create_post.dart b/lib/pages/create_post.dart
index 7535aa8..c2c6d4b 100644
--- a/lib/pages/create_post.dart
+++ b/lib/pages/create_post.dart
@@ -1,14 +1,17 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
+import 'package:image_picker/image_picker.dart';
import 'package:lemmy_api_client/lemmy_api_client.dart';
import '../hooks/delayed_loading.dart';
+import '../hooks/image_picker.dart';
import '../hooks/logged_in_action.dart';
import '../hooks/memo_future.dart';
import '../hooks/stores.dart';
import '../util/extensions/api.dart';
import '../util/goto.dart';
+import '../util/pictrs.dart';
import '../util/spaced.dart';
import '../widgets/markdown_text.dart';
import 'full_post.dart';
@@ -48,6 +51,9 @@ class CreatePost extends HookWidget {
final showFancy = useState(false);
final nsfw = useState(false);
final delayed = useDelayedLoading();
+ final imagePicker = useImagePicker();
+ final imageUploadLoading = useState(false);
+ final pictrsDeleteToken = useState(null);
final allCommunitiesSnap = useMemoFuture(
() => LemmyApi(selectedInstance.value)
@@ -66,6 +72,39 @@ class CreatePost extends HookWidget {
[selectedInstance.value],
);
+ uploadPicture() async {
+ try {
+ final pic = await imagePicker.getImage(source: ImageSource.gallery);
+ // pic is null when the picker was cancelled
+ if (pic != null) {
+ imageUploadLoading.value = true;
+
+ final pictrs = LemmyApi(selectedInstance.value).pictrs;
+ final upload = await pictrs.upload(pic.path);
+
+ pictrsDeleteToken.value = upload.files[0];
+ urlController.text =
+ pathToPictrs(selectedInstance.value, upload.files[0].file);
+ }
+ // ignore: avoid_catches_without_on_clauses
+ } catch (e) {
+ scaffoldKey.currentState
+ .showSnackBar(SnackBar(content: Text('Failed to upload image')));
+ } finally {
+ imageUploadLoading.value = false;
+ }
+ }
+
+ removePicture() {
+ LemmyApi(selectedInstance.value)
+ .pictrs
+ .delete(pictrsDeleteToken.value)
+ .catchError((_) {});
+
+ pictrsDeleteToken.value = null;
+ urlController.text = '';
+ }
+
// TODO: use drop down from AddAccountPage
final instanceDropdown = InputDecorator(
decoration: const InputDecoration(
@@ -113,13 +152,30 @@ class CreatePost extends HookWidget {
),
);
- final url = TextField(
- controller: urlController,
- decoration: InputDecoration(
- border: OutlineInputBorder(),
- labelText: 'URL',
- suffixIcon: Icon(Icons.link)),
- );
+ final url = Row(children: [
+ Expanded(
+ child: TextField(
+ enabled: pictrsDeleteToken.value == null,
+ controller: urlController,
+ decoration: InputDecoration(
+ border: OutlineInputBorder(),
+ labelText: 'URL',
+ suffixIcon: Icon(Icons.link)),
+ ),
+ ),
+ SizedBox(width: 5),
+ IconButton(
+ icon: imageUploadLoading.value
+ ? CircularProgressIndicator()
+ : Icon(pictrsDeleteToken.value == null
+ ? Icons.add_photo_alternate
+ : Icons.close),
+ onPressed:
+ pictrsDeleteToken.value == null ? uploadPicture : removePicture,
+ tooltip:
+ pictrsDeleteToken.value == null ? 'Add picture' : 'Delete picture',
+ )
+ ]);
final title = TextField(
controller: titleController,
diff --git a/lib/util/pictrs.dart b/lib/util/pictrs.dart
new file mode 100644
index 0000000..e0b7d55
--- /dev/null
+++ b/lib/util/pictrs.dart
@@ -0,0 +1,2 @@
+String pathToPictrs(String instanceUrl, String imgId) =>
+ 'https://$instanceUrl/pictrs/image/$imgId';
diff --git a/pubspec.lock b/pubspec.lock
index 621e2d1..dd26301 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -265,6 +265,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0+2"
+ flutter_plugin_android_lifecycle:
+ dependency: transitive
+ description:
+ name: flutter_plugin_android_lifecycle
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.11"
flutter_slidable:
dependency: "direct main"
description:
@@ -338,6 +345,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.4"
+ image_picker:
+ dependency: "direct main"
+ description:
+ name: image_picker
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.6.7+12"
+ image_picker_platform_interface:
+ dependency: transitive
+ description:
+ name: image_picker_platform_interface
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.1.1"
intl:
dependency: transitive
description:
@@ -379,7 +400,7 @@ packages:
name: lemmy_api_client
url: "https://pub.dartlang.org"
source: hosted
- version: "0.6.0"
+ version: "0.7.3"
logging:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 2900aac..b087627 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -34,6 +34,7 @@ dependencies:
url_launcher: ^5.5.1
shared_preferences: ">=0.5.0 <2.0.0"
package_info: ^0.4.3
+ image_picker: ^0.6.7
# state management
flutter_hooks: ^0.13.2
@@ -44,7 +45,7 @@ dependencies:
# utils
timeago: ^2.0.27
fuzzy: <1.0.0
- lemmy_api_client: ^0.6.0
+ lemmy_api_client: ^0.7.3
flutter:
sdk: flutter