final commit
This commit is contained in:
		
							parent
							
								
									2813e72647
								
							
						
					
					
						commit
						42155d9e31
					
				@ -202,7 +202,35 @@ class MyHomePageState extends State<MyHomePage> {
 | 
				
			|||||||
                );
 | 
					                );
 | 
				
			||||||
              },
 | 
					              },
 | 
				
			||||||
              child: const Text('Thumbnail'),
 | 
					              child: const Text('Thumbnail'),
 | 
				
			||||||
            )
 | 
					            ),
 | 
				
			||||||
 | 
					            ElevatedButton(
 | 
				
			||||||
 | 
					              onPressed: () async {
 | 
				
			||||||
 | 
					                final result = await MoxplatformPlugin.platform.pickFiles(FilePickerType.image, false);
 | 
				
			||||||
 | 
					                print('Picked files $result');
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              child: const Text('Pick image'),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            ElevatedButton(
 | 
				
			||||||
 | 
					              onPressed: () async {
 | 
				
			||||||
 | 
					                final result = await MoxplatformPlugin.platform.pickFiles(FilePickerType.image, true);
 | 
				
			||||||
 | 
					                print('Picked files $result');
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              child: const Text('Pick multiple images'),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            ElevatedButton(
 | 
				
			||||||
 | 
					              onPressed: () async {
 | 
				
			||||||
 | 
					                final result = await MoxplatformPlugin.platform.pickFiles(FilePickerType.imageAndVideo, true);
 | 
				
			||||||
 | 
					                print('Picked files $result');
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              child: const Text('Pick multiple images and videos'),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            ElevatedButton(
 | 
				
			||||||
 | 
					              onPressed: () async {
 | 
				
			||||||
 | 
					                final result = await MoxplatformPlugin.platform.pickFiles(FilePickerType.generic, true);
 | 
				
			||||||
 | 
					                print('Picked files $result');
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              child: const Text('Pick multiple generic files'),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
          ],
 | 
					          ],
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
 | 
				
			|||||||
@ -44,4 +44,5 @@ android {
 | 
				
			|||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
    implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
 | 
					    implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
 | 
				
			||||||
    implementation 'androidx.core:core:1.10.1'
 | 
					    implementation 'androidx.core:core:1.10.1'
 | 
				
			||||||
 | 
					    implementation 'androidx.activity:activity:1.7.2'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -81,6 +81,19 @@ public class Api {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public enum FilePickerType {
 | 
				
			||||||
 | 
					    IMAGE(0),
 | 
				
			||||||
 | 
					    VIDEO(1),
 | 
				
			||||||
 | 
					    IMAGE_AND_VIDEO(2),
 | 
				
			||||||
 | 
					    GENERIC(3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final int index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private FilePickerType(final int index) {
 | 
				
			||||||
 | 
					      this.index = index;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Generated class from Pigeon that represents data sent in messages. */
 | 
					  /** Generated class from Pigeon that represents data sent in messages. */
 | 
				
			||||||
  public static final class CryptographyResult {
 | 
					  public static final class CryptographyResult {
 | 
				
			||||||
    private @NonNull byte[] plaintextHash;
 | 
					    private @NonNull byte[] plaintextHash;
 | 
				
			||||||
@ -211,6 +224,8 @@ public class Api {
 | 
				
			|||||||
    /** Media APIs */
 | 
					    /** Media APIs */
 | 
				
			||||||
    @NonNull 
 | 
					    @NonNull 
 | 
				
			||||||
    Boolean generateVideoThumbnail(@NonNull String src, @NonNull String dest, @NonNull Long maxWidth);
 | 
					    Boolean generateVideoThumbnail(@NonNull String src, @NonNull String dest, @NonNull Long maxWidth);
 | 
				
			||||||
 | 
					    /** Picker */
 | 
				
			||||||
 | 
					    void pickFiles(@NonNull FilePickerType type, @NonNull Boolean pickMultiple, @NonNull Result<List<String>> result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** The codec used by MoxplatformApi. */
 | 
					    /** The codec used by MoxplatformApi. */
 | 
				
			||||||
    static @NonNull MessageCodec<Object> getCodec() {
 | 
					    static @NonNull MessageCodec<Object> getCodec() {
 | 
				
			||||||
@ -457,6 +472,36 @@ public class Api {
 | 
				
			|||||||
          channel.setMessageHandler(null);
 | 
					          channel.setMessageHandler(null);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        BasicMessageChannel<Object> channel =
 | 
				
			||||||
 | 
					            new BasicMessageChannel<>(
 | 
				
			||||||
 | 
					                binaryMessenger, "dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.pickFiles", getCodec());
 | 
				
			||||||
 | 
					        if (api != null) {
 | 
				
			||||||
 | 
					          channel.setMessageHandler(
 | 
				
			||||||
 | 
					              (message, reply) -> {
 | 
				
			||||||
 | 
					                ArrayList<Object> wrapped = new ArrayList<Object>();
 | 
				
			||||||
 | 
					                ArrayList<Object> args = (ArrayList<Object>) message;
 | 
				
			||||||
 | 
					                FilePickerType typeArg = args.get(0) == null ? null : FilePickerType.values()[(int) args.get(0)];
 | 
				
			||||||
 | 
					                Boolean pickMultipleArg = (Boolean) args.get(1);
 | 
				
			||||||
 | 
					                Result<List<String>> resultCallback =
 | 
				
			||||||
 | 
					                    new Result<List<String>>() {
 | 
				
			||||||
 | 
					                      public void success(List<String> result) {
 | 
				
			||||||
 | 
					                        wrapped.add(0, result);
 | 
				
			||||||
 | 
					                        reply.reply(wrapped);
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                      public void error(Throwable error) {
 | 
				
			||||||
 | 
					                        ArrayList<Object> wrappedError = wrapError(error);
 | 
				
			||||||
 | 
					                        reply.reply(wrappedError);
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                api.pickFiles(typeArg, pickMultipleArg, resultCallback);
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          channel.setMessageHandler(null);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,8 @@ import static androidx.core.content.ContextCompat.startActivity;
 | 
				
			|||||||
import static me.polynom.moxplatform_android.ConstantsKt.MOXPLATFORM_FILEPROVIDER_ID;
 | 
					import static me.polynom.moxplatform_android.ConstantsKt.MOXPLATFORM_FILEPROVIDER_ID;
 | 
				
			||||||
import static me.polynom.moxplatform_android.ConstantsKt.SHARED_PREFERENCES_KEY;
 | 
					import static me.polynom.moxplatform_android.ConstantsKt.SHARED_PREFERENCES_KEY;
 | 
				
			||||||
import static me.polynom.moxplatform_android.CryptoKt.*;
 | 
					import static me.polynom.moxplatform_android.CryptoKt.*;
 | 
				
			||||||
 | 
					import static me.polynom.moxplatform_android.PickerKt.filePickerRequest;
 | 
				
			||||||
 | 
					import static me.polynom.moxplatform_android.PickerKt.onActivityResultImpl;
 | 
				
			||||||
import static me.polynom.moxplatform_android.RecordSentMessageKt.*;
 | 
					import static me.polynom.moxplatform_android.RecordSentMessageKt.*;
 | 
				
			||||||
import static me.polynom.moxplatform_android.ThumbnailsKt.generateVideoThumbnailImplementation;
 | 
					import static me.polynom.moxplatform_android.ThumbnailsKt.generateVideoThumbnailImplementation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -31,6 +33,8 @@ import android.provider.MediaStore;
 | 
				
			|||||||
import android.util.Log;
 | 
					import android.util.Log;
 | 
				
			||||||
import android.util.Size;
 | 
					import android.util.Size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import androidx.activity.result.PickVisualMediaRequest;
 | 
				
			||||||
 | 
					import androidx.activity.result.contract.ActivityResultContracts;
 | 
				
			||||||
import androidx.annotation.NonNull;
 | 
					import androidx.annotation.NonNull;
 | 
				
			||||||
import androidx.annotation.Nullable;
 | 
					import androidx.annotation.Nullable;
 | 
				
			||||||
import androidx.core.app.NotificationManagerCompat;
 | 
					import androidx.core.app.NotificationManagerCompat;
 | 
				
			||||||
@ -42,7 +46,11 @@ import java.io.ByteArrayOutputStream;
 | 
				
			|||||||
import java.io.File;
 | 
					import java.io.File;
 | 
				
			||||||
import java.io.FileOutputStream;
 | 
					import java.io.FileOutputStream;
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.Collection;
 | 
				
			||||||
 | 
					import java.util.HashMap;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					import java.util.Set;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import io.flutter.embedding.engine.plugins.FlutterPlugin;
 | 
					import io.flutter.embedding.engine.plugins.FlutterPlugin;
 | 
				
			||||||
import io.flutter.embedding.engine.plugins.service.ServiceAware;
 | 
					import io.flutter.embedding.engine.plugins.service.ServiceAware;
 | 
				
			||||||
@ -55,11 +63,14 @@ import io.flutter.plugin.common.MethodChannel;
 | 
				
			|||||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
 | 
					import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
 | 
				
			||||||
import io.flutter.plugin.common.MethodChannel.Result;
 | 
					import io.flutter.plugin.common.MethodChannel.Result;
 | 
				
			||||||
import io.flutter.plugin.common.PluginRegistry.Registrar;
 | 
					import io.flutter.plugin.common.PluginRegistry.Registrar;
 | 
				
			||||||
 | 
					import io.flutter.plugin.common.PluginRegistry;
 | 
				
			||||||
import io.flutter.plugin.common.JSONMethodCodec;
 | 
					import io.flutter.plugin.common.JSONMethodCodec;
 | 
				
			||||||
 | 
					import io.flutter.embedding.engine.plugins.activity.ActivityAware;
 | 
				
			||||||
 | 
					import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
 | 
				
			||||||
import kotlin.Unit;
 | 
					import kotlin.Unit;
 | 
				
			||||||
import kotlin.jvm.functions.Function1;
 | 
					import kotlin.jvm.functions.Function1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class MoxplatformAndroidPlugin extends BroadcastReceiver implements FlutterPlugin, MethodCallHandler, ServiceAware, MoxplatformApi {
 | 
					public class MoxplatformAndroidPlugin extends BroadcastReceiver implements FlutterPlugin, MethodCallHandler, ServiceAware, ActivityAware, PluginRegistry.ActivityResultListener, MoxplatformApi {
 | 
				
			||||||
    public static final String entrypointKey = "entrypoint_handle";
 | 
					    public static final String entrypointKey = "entrypoint_handle";
 | 
				
			||||||
    public static final String extraDataKey = "extra_data";
 | 
					    public static final String extraDataKey = "extra_data";
 | 
				
			||||||
    private static final String autoStartAtBootKey = "auto_start_at_boot";
 | 
					    private static final String autoStartAtBootKey = "auto_start_at_boot";
 | 
				
			||||||
@ -72,13 +83,17 @@ public class MoxplatformAndroidPlugin extends BroadcastReceiver implements Flutt
 | 
				
			|||||||
    private MethodChannel channel;
 | 
					    private MethodChannel channel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static Activity activity;
 | 
					    public static Activity activity;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    private Context context;
 | 
					    private Context context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public MoxplatformAndroidPlugin() {
 | 
					    public MoxplatformAndroidPlugin() {
 | 
				
			||||||
        _instances.add(this);
 | 
					        _instances.add(this);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
 | 
				
			||||||
 | 
					        return onActivityResultImpl(context, requestCode, resultCode, data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
 | 
					    public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
 | 
				
			||||||
        channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), methodChannelKey);
 | 
					        channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), methodChannelKey);
 | 
				
			||||||
@ -279,4 +294,25 @@ public class MoxplatformAndroidPlugin extends BroadcastReceiver implements Flutt
 | 
				
			|||||||
    public Boolean generateVideoThumbnail(@NonNull String src, @NonNull String dest, @NonNull Long maxWidth) {
 | 
					    public Boolean generateVideoThumbnail(@NonNull String src, @NonNull String dest, @NonNull Long maxWidth) {
 | 
				
			||||||
        return generateVideoThumbnailImplementation(src, dest, maxWidth);
 | 
					        return generateVideoThumbnailImplementation(src, dest, maxWidth);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void pickFiles(@NonNull FilePickerType type, @NonNull Boolean pickMultiple, @NonNull Api.Result<List<String>> result) {
 | 
				
			||||||
 | 
					        filePickerRequest(context, activity, type, pickMultiple, result);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onAttachedToActivity(ActivityPluginBinding binding) {
 | 
				
			||||||
 | 
					        activity = binding.getActivity();
 | 
				
			||||||
 | 
					        binding.addActivityResultListener(this);
 | 
				
			||||||
 | 
					        Log.d(TAG, "Activity attached");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onDetachedFromActivity() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onDetachedFromActivityForConfigChanges() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,226 @@
 | 
				
			|||||||
 | 
					package me.polynom.moxplatform_android
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.app.Activity
 | 
				
			||||||
 | 
					import android.content.ContentResolver
 | 
				
			||||||
 | 
					import android.content.Context
 | 
				
			||||||
 | 
					import android.content.Intent
 | 
				
			||||||
 | 
					import android.database.Cursor
 | 
				
			||||||
 | 
					import android.net.Uri
 | 
				
			||||||
 | 
					import android.provider.MediaStore
 | 
				
			||||||
 | 
					import android.util.Log
 | 
				
			||||||
 | 
					import android.webkit.MimeTypeMap
 | 
				
			||||||
 | 
					import androidx.activity.result.PickVisualMediaRequest
 | 
				
			||||||
 | 
					import androidx.activity.result.contract.ActivityResultContracts
 | 
				
			||||||
 | 
					import java.io.File
 | 
				
			||||||
 | 
					import java.io.FileOutputStream
 | 
				
			||||||
 | 
					import java.io.IOException
 | 
				
			||||||
 | 
					import java.io.InputStream
 | 
				
			||||||
 | 
					import java.io.OutputStream
 | 
				
			||||||
 | 
					import java.util.UUID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object RequestTracker {
 | 
				
			||||||
 | 
					    val requests: MutableMap<Int, Api.Result<Any>> = mutableMapOf()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const val PICK_FILE_REQUEST = 41;
 | 
				
			||||||
 | 
					const val PICK_FILES_REQUEST = 42;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun genericFilePickerRequest(activity: Activity?, pickMultiple: Boolean, result: Api.Result<List<String>>) {
 | 
				
			||||||
 | 
					    val pickIntent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
 | 
				
			||||||
 | 
					        addCategory(Intent.CATEGORY_OPENABLE)
 | 
				
			||||||
 | 
					        type = "*/*"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        putExtra(Intent.EXTRA_ALLOW_MULTIPLE, pickMultiple);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    RequestTracker.requests[PICK_FILE_REQUEST] = result as Api.Result<Any>;
 | 
				
			||||||
 | 
					    activity?.startActivityForResult(pickIntent, PICK_FILE_REQUEST)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun filePickerRequest(
 | 
				
			||||||
 | 
					    context: Context,
 | 
				
			||||||
 | 
					    activity: Activity?,
 | 
				
			||||||
 | 
					    type: Api.FilePickerType,
 | 
				
			||||||
 | 
					    pickMultiple: Boolean,
 | 
				
			||||||
 | 
					    result: Api.Result<List<String>>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    if (type == Api.FilePickerType.GENERIC) {
 | 
				
			||||||
 | 
					        return genericFilePickerRequest(activity, pickMultiple, result)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val pickerType = when (type) {
 | 
				
			||||||
 | 
					        Api.FilePickerType.IMAGE -> ActivityResultContracts.PickVisualMedia.ImageOnly
 | 
				
			||||||
 | 
					        Api.FilePickerType.VIDEO -> ActivityResultContracts.PickVisualMedia.VideoOnly
 | 
				
			||||||
 | 
					        Api.FilePickerType.IMAGE_AND_VIDEO -> ActivityResultContracts.PickVisualMedia.ImageAndVideo
 | 
				
			||||||
 | 
					        // TODO
 | 
				
			||||||
 | 
					        Api.FilePickerType.GENERIC -> ActivityResultContracts.PickVisualMedia.ImageAndVideo
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val pick = when (pickMultiple) {
 | 
				
			||||||
 | 
					        false -> ActivityResultContracts.PickVisualMedia()
 | 
				
			||||||
 | 
					        true -> ActivityResultContracts.PickMultipleVisualMedia()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val requestCode = if (pickMultiple) PICK_FILES_REQUEST else PICK_FILE_REQUEST
 | 
				
			||||||
 | 
					    val pickIntent = pick.createIntent(context, PickVisualMediaRequest(pickerType))
 | 
				
			||||||
 | 
					    RequestTracker.requests[requestCode] = result as Api.Result<Any>
 | 
				
			||||||
 | 
					    Log.d(TAG, "Tracked size ${RequestTracker.requests.size}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (activity == null) {
 | 
				
			||||||
 | 
					        Log.w(TAG, "Activity is null")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    activity?.startActivityForResult(pickIntent, requestCode);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copies the file from the given content URI to a temporary directory, retaining the original
 | 
				
			||||||
 | 
					 * file name if possible.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Each file is placed in its own directory to avoid conflicts according to the following
 | 
				
			||||||
 | 
					 * scheme: {cacheDir}/{randomUuid}/{fileName}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * File extension is changed to match MIME type of the file, if known. Otherwise, the extension
 | 
				
			||||||
 | 
					 * is left unchanged.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If the original file name is unknown, a predefined "image_picker" filename is used and the
 | 
				
			||||||
 | 
					 * file extension is deduced from the mime type (with fallback to ".jpg" in case of failure).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					fun getPathFromUri(context: Context, uri: Uri): String? {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					        context.contentResolver.openInputStream(uri).use { inputStream ->
 | 
				
			||||||
 | 
					            val uuid = UUID.randomUUID().toString()
 | 
				
			||||||
 | 
					            val targetDirectory = File(context.cacheDir, uuid)
 | 
				
			||||||
 | 
					            targetDirectory.mkdir()
 | 
				
			||||||
 | 
					            // TODO(SynSzakala) according to the docs, `deleteOnExit` does not work reliably on Android; we should preferably
 | 
				
			||||||
 | 
					            //  just clear the picked files after the app startup.
 | 
				
			||||||
 | 
					            targetDirectory.deleteOnExit()
 | 
				
			||||||
 | 
					            var fileName = getImageName(context, uri)
 | 
				
			||||||
 | 
					            var extension = getImageExtension(context, uri)
 | 
				
			||||||
 | 
					            if (fileName == null) {
 | 
				
			||||||
 | 
					                Log.w("FileUtils", "Cannot get file name for $uri")
 | 
				
			||||||
 | 
					                if (extension == null) extension = ".jpg"
 | 
				
			||||||
 | 
					                fileName = "image_picker$extension"
 | 
				
			||||||
 | 
					            } else if (extension != null) {
 | 
				
			||||||
 | 
					                fileName = getBaseName(fileName) + extension
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            val file = File(targetDirectory, fileName)
 | 
				
			||||||
 | 
					            FileOutputStream(file).use { outputStream ->
 | 
				
			||||||
 | 
					                copy(inputStream!!, outputStream)
 | 
				
			||||||
 | 
					                return file.path
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } catch (e: IOException) {
 | 
				
			||||||
 | 
					        // If closing the output stream fails, we cannot be sure that the
 | 
				
			||||||
 | 
					        // target file was written in full. Flushing the stream merely moves
 | 
				
			||||||
 | 
					        // the bytes into the OS, not necessarily to the file.
 | 
				
			||||||
 | 
					        return null
 | 
				
			||||||
 | 
					    } catch (e: SecurityException) {
 | 
				
			||||||
 | 
					        // Calling `ContentResolver#openInputStream()` has been reported to throw a
 | 
				
			||||||
 | 
					        // `SecurityException` on some devices in certain circumstances. Instead of crashing, we
 | 
				
			||||||
 | 
					        // return `null`.
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        // See https://github.com/flutter/flutter/issues/100025 for more details.
 | 
				
			||||||
 | 
					        return null
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @return extension of image with dot, or null if it's empty.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					private fun getImageExtension(context: Context, uriImage: Uri): String? {
 | 
				
			||||||
 | 
					    val extension: String?
 | 
				
			||||||
 | 
					    extension = try {
 | 
				
			||||||
 | 
					        if (uriImage.scheme == ContentResolver.SCHEME_CONTENT) {
 | 
				
			||||||
 | 
					            val mime = MimeTypeMap.getSingleton()
 | 
				
			||||||
 | 
					            mime.getExtensionFromMimeType(context.contentResolver.getType(uriImage))
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            MimeTypeMap.getFileExtensionFromUrl(
 | 
				
			||||||
 | 
					                Uri.fromFile(File(uriImage.path)).toString()
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } catch (e: Exception) {
 | 
				
			||||||
 | 
					        return null
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return if (extension == null || extension.isEmpty()) {
 | 
				
			||||||
 | 
					        null
 | 
				
			||||||
 | 
					    } else ".$extension"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @return name of the image provided by ContentResolver; this may be null.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					private fun getImageName(context: Context, uriImage: Uri): String? {
 | 
				
			||||||
 | 
					    queryImageName(context, uriImage).use { cursor ->
 | 
				
			||||||
 | 
					        return if (cursor == null || !cursor.moveToFirst() || (cursor.columnCount < 1)) null else cursor.getString(
 | 
				
			||||||
 | 
					            0
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private fun queryImageName(context: Context, uriImage: Uri): Cursor? {
 | 
				
			||||||
 | 
					    return context
 | 
				
			||||||
 | 
					        .contentResolver
 | 
				
			||||||
 | 
					        .query(uriImage, arrayOf(MediaStore.MediaColumns.DISPLAY_NAME), null, null, null)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Throws(IOException::class)
 | 
				
			||||||
 | 
					private fun copy(`in`: InputStream, out: OutputStream) {
 | 
				
			||||||
 | 
					    val buffer = ByteArray(4 * 1024)
 | 
				
			||||||
 | 
					    var bytesRead: Int
 | 
				
			||||||
 | 
					    while (`in`.read(buffer).also { bytesRead = it } != -1) {
 | 
				
			||||||
 | 
					        out.write(buffer, 0, bytesRead)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    out.flush()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private fun getBaseName(fileName: String): String {
 | 
				
			||||||
 | 
					    val lastDotIndex = fileName.lastIndexOf('.')
 | 
				
			||||||
 | 
					    return if (lastDotIndex < 0) {
 | 
				
			||||||
 | 
					        fileName
 | 
				
			||||||
 | 
					    } else fileName.substring(0, lastDotIndex)
 | 
				
			||||||
 | 
					    // Basename is everything before the last '.'.
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun onActivityResultImpl(context: Context, requestCode: Int, resultCode: Int, data: Intent?): Boolean {
 | 
				
			||||||
 | 
					    Log.d(TAG, "Got result for $requestCode with result $resultCode (${data?.action})")
 | 
				
			||||||
 | 
					    if (requestCode == PICK_FILE_REQUEST || requestCode == PICK_FILES_REQUEST) {
 | 
				
			||||||
 | 
					        Log.d(TAG, "Extra data ${data?.data}")
 | 
				
			||||||
 | 
					        val result = RequestTracker.requests.remove(requestCode);
 | 
				
			||||||
 | 
					        if (result == null) {
 | 
				
			||||||
 | 
					            Log.w(TAG, "Untracked response.")
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (resultCode != Activity.RESULT_OK) {
 | 
				
			||||||
 | 
					            // No files picked
 | 
				
			||||||
 | 
					            result!!.success(listOf<String>())
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val pickedMultiple = requestCode == PICK_FILES_REQUEST
 | 
				
			||||||
 | 
					        val pickedFiles = mutableListOf<String>()
 | 
				
			||||||
 | 
					        if (pickedMultiple) {
 | 
				
			||||||
 | 
					            val intentUris = data!!.clipData
 | 
				
			||||||
 | 
					            if (data!!.clipData != null) {
 | 
				
			||||||
 | 
					                for (i in 0 until data!!.clipData!!.itemCount) {
 | 
				
			||||||
 | 
					                    val path = getPathFromUri(context, data!!.clipData!!.getItemAt(i).uri)
 | 
				
			||||||
 | 
					                    if (path != null) {
 | 
				
			||||||
 | 
					                        pickedFiles.add(path )
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            val path = getPathFromUri(context, data!!.data!!)
 | 
				
			||||||
 | 
					            if (path != null) {
 | 
				
			||||||
 | 
					                pickedFiles.add(path )
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result!!.success(pickedFiles)
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -30,4 +30,10 @@ class AndroidPlatformImplementation extends PlatformImplementation {
 | 
				
			|||||||
  ) async {
 | 
					  ) async {
 | 
				
			||||||
    return MoxplatformInterface.api.generateVideoThumbnail(src, dest, width);
 | 
					    return MoxplatformInterface.api.generateVideoThumbnail(src, dest, width);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Future<List<String>> pickFiles(FilePickerType type, bool pickMultiple) async {
 | 
				
			||||||
 | 
					    final result = await MoxplatformInterface.api.pickFiles(type, pickMultiple);
 | 
				
			||||||
 | 
					    return result.cast<String>();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -20,6 +20,13 @@ enum FallbackIconType {
 | 
				
			|||||||
  notes,
 | 
					  notes,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum FilePickerType {
 | 
				
			||||||
 | 
					  image,
 | 
				
			||||||
 | 
					  video,
 | 
				
			||||||
 | 
					  imageAndVideo,
 | 
				
			||||||
 | 
					  generic,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CryptographyResult {
 | 
					class CryptographyResult {
 | 
				
			||||||
  CryptographyResult({
 | 
					  CryptographyResult({
 | 
				
			||||||
    required this.plaintextHash,
 | 
					    required this.plaintextHash,
 | 
				
			||||||
@ -61,7 +68,7 @@ class _MoxplatformApiCodec extends StandardMessageCodec {
 | 
				
			|||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Object? readValueOfType(int type, ReadBuffer buffer) {
 | 
					  Object? readValueOfType(int type, ReadBuffer buffer) {
 | 
				
			||||||
    switch (type) {
 | 
					    switch (type) {
 | 
				
			||||||
      case 128:
 | 
					      case 128: 
 | 
				
			||||||
        return CryptographyResult.decode(readValue(buffer)!);
 | 
					        return CryptographyResult.decode(readValue(buffer)!);
 | 
				
			||||||
      default:
 | 
					      default:
 | 
				
			||||||
        return super.readValueOfType(type, buffer);
 | 
					        return super.readValueOfType(type, buffer);
 | 
				
			||||||
@ -82,10 +89,10 @@ class MoxplatformApi {
 | 
				
			|||||||
  /// Platform APIs
 | 
					  /// Platform APIs
 | 
				
			||||||
  Future<String> getPersistentDataPath() async {
 | 
					  Future<String> getPersistentDataPath() async {
 | 
				
			||||||
    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
					    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
				
			||||||
        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.getPersistentDataPath',
 | 
					        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.getPersistentDataPath', codec,
 | 
				
			||||||
        codec,
 | 
					 | 
				
			||||||
        binaryMessenger: _binaryMessenger);
 | 
					        binaryMessenger: _binaryMessenger);
 | 
				
			||||||
    final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
 | 
					    final List<Object?>? replyList =
 | 
				
			||||||
 | 
					        await channel.send(null) as List<Object?>?;
 | 
				
			||||||
    if (replyList == null) {
 | 
					    if (replyList == null) {
 | 
				
			||||||
      throw PlatformException(
 | 
					      throw PlatformException(
 | 
				
			||||||
        code: 'channel-error',
 | 
					        code: 'channel-error',
 | 
				
			||||||
@ -109,10 +116,10 @@ class MoxplatformApi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  Future<String> getCacheDataPath() async {
 | 
					  Future<String> getCacheDataPath() async {
 | 
				
			||||||
    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
					    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
				
			||||||
        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.getCacheDataPath',
 | 
					        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.getCacheDataPath', codec,
 | 
				
			||||||
        codec,
 | 
					 | 
				
			||||||
        binaryMessenger: _binaryMessenger);
 | 
					        binaryMessenger: _binaryMessenger);
 | 
				
			||||||
    final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
 | 
					    final List<Object?>? replyList =
 | 
				
			||||||
 | 
					        await channel.send(null) as List<Object?>?;
 | 
				
			||||||
    if (replyList == null) {
 | 
					    if (replyList == null) {
 | 
				
			||||||
      throw PlatformException(
 | 
					      throw PlatformException(
 | 
				
			||||||
        code: 'channel-error',
 | 
					        code: 'channel-error',
 | 
				
			||||||
@ -136,10 +143,10 @@ class MoxplatformApi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  Future<void> openBatteryOptimisationSettings() async {
 | 
					  Future<void> openBatteryOptimisationSettings() async {
 | 
				
			||||||
    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
					    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
				
			||||||
        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.openBatteryOptimisationSettings',
 | 
					        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.openBatteryOptimisationSettings', codec,
 | 
				
			||||||
        codec,
 | 
					 | 
				
			||||||
        binaryMessenger: _binaryMessenger);
 | 
					        binaryMessenger: _binaryMessenger);
 | 
				
			||||||
    final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
 | 
					    final List<Object?>? replyList =
 | 
				
			||||||
 | 
					        await channel.send(null) as List<Object?>?;
 | 
				
			||||||
    if (replyList == null) {
 | 
					    if (replyList == null) {
 | 
				
			||||||
      throw PlatformException(
 | 
					      throw PlatformException(
 | 
				
			||||||
        code: 'channel-error',
 | 
					        code: 'channel-error',
 | 
				
			||||||
@ -158,10 +165,10 @@ class MoxplatformApi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  Future<bool> isIgnoringBatteryOptimizations() async {
 | 
					  Future<bool> isIgnoringBatteryOptimizations() async {
 | 
				
			||||||
    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
					    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
				
			||||||
        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.isIgnoringBatteryOptimizations',
 | 
					        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.isIgnoringBatteryOptimizations', codec,
 | 
				
			||||||
        codec,
 | 
					 | 
				
			||||||
        binaryMessenger: _binaryMessenger);
 | 
					        binaryMessenger: _binaryMessenger);
 | 
				
			||||||
    final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
 | 
					    final List<Object?>? replyList =
 | 
				
			||||||
 | 
					        await channel.send(null) as List<Object?>?;
 | 
				
			||||||
    if (replyList == null) {
 | 
					    if (replyList == null) {
 | 
				
			||||||
      throw PlatformException(
 | 
					      throw PlatformException(
 | 
				
			||||||
        code: 'channel-error',
 | 
					        code: 'channel-error',
 | 
				
			||||||
@ -184,18 +191,12 @@ class MoxplatformApi {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Contacts APIs
 | 
					  /// Contacts APIs
 | 
				
			||||||
  Future<void> recordSentMessage(String arg_name, String arg_jid,
 | 
					  Future<void> recordSentMessage(String arg_name, String arg_jid, String? arg_avatarPath, FallbackIconType arg_fallbackIcon) async {
 | 
				
			||||||
      String? arg_avatarPath, FallbackIconType arg_fallbackIcon) async {
 | 
					 | 
				
			||||||
    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
					    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
				
			||||||
        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.recordSentMessage',
 | 
					        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.recordSentMessage', codec,
 | 
				
			||||||
        codec,
 | 
					 | 
				
			||||||
        binaryMessenger: _binaryMessenger);
 | 
					        binaryMessenger: _binaryMessenger);
 | 
				
			||||||
    final List<Object?>? replyList = await channel.send(<Object?>[
 | 
					    final List<Object?>? replyList =
 | 
				
			||||||
      arg_name,
 | 
					        await channel.send(<Object?>[arg_name, arg_jid, arg_avatarPath, arg_fallbackIcon.index]) as List<Object?>?;
 | 
				
			||||||
      arg_jid,
 | 
					 | 
				
			||||||
      arg_avatarPath,
 | 
					 | 
				
			||||||
      arg_fallbackIcon.index
 | 
					 | 
				
			||||||
    ]) as List<Object?>?;
 | 
					 | 
				
			||||||
    if (replyList == null) {
 | 
					    if (replyList == null) {
 | 
				
			||||||
      throw PlatformException(
 | 
					      throw PlatformException(
 | 
				
			||||||
        code: 'channel-error',
 | 
					        code: 'channel-error',
 | 
				
			||||||
@ -213,25 +214,12 @@ class MoxplatformApi {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Cryptography APIs
 | 
					  /// Cryptography APIs
 | 
				
			||||||
  Future<CryptographyResult?> encryptFile(
 | 
					  Future<CryptographyResult?> encryptFile(String arg_sourcePath, String arg_destPath, Uint8List arg_key, Uint8List arg_iv, CipherAlgorithm arg_algorithm, String arg_hashSpec) async {
 | 
				
			||||||
      String arg_sourcePath,
 | 
					 | 
				
			||||||
      String arg_destPath,
 | 
					 | 
				
			||||||
      Uint8List arg_key,
 | 
					 | 
				
			||||||
      Uint8List arg_iv,
 | 
					 | 
				
			||||||
      CipherAlgorithm arg_algorithm,
 | 
					 | 
				
			||||||
      String arg_hashSpec) async {
 | 
					 | 
				
			||||||
    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
					    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
				
			||||||
        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.encryptFile',
 | 
					        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.encryptFile', codec,
 | 
				
			||||||
        codec,
 | 
					 | 
				
			||||||
        binaryMessenger: _binaryMessenger);
 | 
					        binaryMessenger: _binaryMessenger);
 | 
				
			||||||
    final List<Object?>? replyList = await channel.send(<Object?>[
 | 
					    final List<Object?>? replyList =
 | 
				
			||||||
      arg_sourcePath,
 | 
					        await channel.send(<Object?>[arg_sourcePath, arg_destPath, arg_key, arg_iv, arg_algorithm.index, arg_hashSpec]) as List<Object?>?;
 | 
				
			||||||
      arg_destPath,
 | 
					 | 
				
			||||||
      arg_key,
 | 
					 | 
				
			||||||
      arg_iv,
 | 
					 | 
				
			||||||
      arg_algorithm.index,
 | 
					 | 
				
			||||||
      arg_hashSpec
 | 
					 | 
				
			||||||
    ]) as List<Object?>?;
 | 
					 | 
				
			||||||
    if (replyList == null) {
 | 
					    if (replyList == null) {
 | 
				
			||||||
      throw PlatformException(
 | 
					      throw PlatformException(
 | 
				
			||||||
        code: 'channel-error',
 | 
					        code: 'channel-error',
 | 
				
			||||||
@ -248,25 +236,12 @@ class MoxplatformApi {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<CryptographyResult?> decryptFile(
 | 
					  Future<CryptographyResult?> decryptFile(String arg_sourcePath, String arg_destPath, Uint8List arg_key, Uint8List arg_iv, CipherAlgorithm arg_algorithm, String arg_hashSpec) async {
 | 
				
			||||||
      String arg_sourcePath,
 | 
					 | 
				
			||||||
      String arg_destPath,
 | 
					 | 
				
			||||||
      Uint8List arg_key,
 | 
					 | 
				
			||||||
      Uint8List arg_iv,
 | 
					 | 
				
			||||||
      CipherAlgorithm arg_algorithm,
 | 
					 | 
				
			||||||
      String arg_hashSpec) async {
 | 
					 | 
				
			||||||
    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
					    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
				
			||||||
        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.decryptFile',
 | 
					        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.decryptFile', codec,
 | 
				
			||||||
        codec,
 | 
					 | 
				
			||||||
        binaryMessenger: _binaryMessenger);
 | 
					        binaryMessenger: _binaryMessenger);
 | 
				
			||||||
    final List<Object?>? replyList = await channel.send(<Object?>[
 | 
					    final List<Object?>? replyList =
 | 
				
			||||||
      arg_sourcePath,
 | 
					        await channel.send(<Object?>[arg_sourcePath, arg_destPath, arg_key, arg_iv, arg_algorithm.index, arg_hashSpec]) as List<Object?>?;
 | 
				
			||||||
      arg_destPath,
 | 
					 | 
				
			||||||
      arg_key,
 | 
					 | 
				
			||||||
      arg_iv,
 | 
					 | 
				
			||||||
      arg_algorithm.index,
 | 
					 | 
				
			||||||
      arg_hashSpec
 | 
					 | 
				
			||||||
    ]) as List<Object?>?;
 | 
					 | 
				
			||||||
    if (replyList == null) {
 | 
					    if (replyList == null) {
 | 
				
			||||||
      throw PlatformException(
 | 
					      throw PlatformException(
 | 
				
			||||||
        code: 'channel-error',
 | 
					        code: 'channel-error',
 | 
				
			||||||
@ -283,14 +258,12 @@ class MoxplatformApi {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<Uint8List?> hashFile(
 | 
					  Future<Uint8List?> hashFile(String arg_sourcePath, String arg_hashSpec) async {
 | 
				
			||||||
      String arg_sourcePath, String arg_hashSpec) async {
 | 
					 | 
				
			||||||
    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
					    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
				
			||||||
        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.hashFile',
 | 
					        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.hashFile', codec,
 | 
				
			||||||
        codec,
 | 
					 | 
				
			||||||
        binaryMessenger: _binaryMessenger);
 | 
					        binaryMessenger: _binaryMessenger);
 | 
				
			||||||
    final List<Object?>? replyList = await channel
 | 
					    final List<Object?>? replyList =
 | 
				
			||||||
        .send(<Object?>[arg_sourcePath, arg_hashSpec]) as List<Object?>?;
 | 
					        await channel.send(<Object?>[arg_sourcePath, arg_hashSpec]) as List<Object?>?;
 | 
				
			||||||
    if (replyList == null) {
 | 
					    if (replyList == null) {
 | 
				
			||||||
      throw PlatformException(
 | 
					      throw PlatformException(
 | 
				
			||||||
        code: 'channel-error',
 | 
					        code: 'channel-error',
 | 
				
			||||||
@ -308,14 +281,12 @@ class MoxplatformApi {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Media APIs
 | 
					  /// Media APIs
 | 
				
			||||||
  Future<bool> generateVideoThumbnail(
 | 
					  Future<bool> generateVideoThumbnail(String arg_src, String arg_dest, int arg_maxWidth) async {
 | 
				
			||||||
      String arg_src, String arg_dest, int arg_maxWidth) async {
 | 
					 | 
				
			||||||
    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
					    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
				
			||||||
        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.generateVideoThumbnail',
 | 
					        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.generateVideoThumbnail', codec,
 | 
				
			||||||
        codec,
 | 
					 | 
				
			||||||
        binaryMessenger: _binaryMessenger);
 | 
					        binaryMessenger: _binaryMessenger);
 | 
				
			||||||
    final List<Object?>? replyList = await channel
 | 
					    final List<Object?>? replyList =
 | 
				
			||||||
        .send(<Object?>[arg_src, arg_dest, arg_maxWidth]) as List<Object?>?;
 | 
					        await channel.send(<Object?>[arg_src, arg_dest, arg_maxWidth]) as List<Object?>?;
 | 
				
			||||||
    if (replyList == null) {
 | 
					    if (replyList == null) {
 | 
				
			||||||
      throw PlatformException(
 | 
					      throw PlatformException(
 | 
				
			||||||
        code: 'channel-error',
 | 
					        code: 'channel-error',
 | 
				
			||||||
@ -336,4 +307,32 @@ class MoxplatformApi {
 | 
				
			|||||||
      return (replyList[0] as bool?)!;
 | 
					      return (replyList[0] as bool?)!;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Picker
 | 
				
			||||||
 | 
					  Future<List<String?>> pickFiles(FilePickerType arg_type, bool arg_pickMultiple) async {
 | 
				
			||||||
 | 
					    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
 | 
				
			||||||
 | 
					        'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.pickFiles', codec,
 | 
				
			||||||
 | 
					        binaryMessenger: _binaryMessenger);
 | 
				
			||||||
 | 
					    final List<Object?>? replyList =
 | 
				
			||||||
 | 
					        await channel.send(<Object?>[arg_type.index, arg_pickMultiple]) as List<Object?>?;
 | 
				
			||||||
 | 
					    if (replyList == null) {
 | 
				
			||||||
 | 
					      throw PlatformException(
 | 
				
			||||||
 | 
					        code: 'channel-error',
 | 
				
			||||||
 | 
					        message: 'Unable to establish connection on channel.',
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    } else if (replyList.length > 1) {
 | 
				
			||||||
 | 
					      throw PlatformException(
 | 
				
			||||||
 | 
					        code: replyList[0]! as String,
 | 
				
			||||||
 | 
					        message: replyList[1] as String?,
 | 
				
			||||||
 | 
					        details: replyList[2],
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    } else if (replyList[0] == null) {
 | 
				
			||||||
 | 
					      throw PlatformException(
 | 
				
			||||||
 | 
					        code: 'null-error',
 | 
				
			||||||
 | 
					        message: 'Host platform returned null value for non-null return value.',
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      return (replyList[0] as List<Object?>?)!.cast<String?>();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					import 'package:moxplatform_platform_interface/src/api.g.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
abstract class PlatformImplementation {
 | 
					abstract class PlatformImplementation {
 | 
				
			||||||
  /// Returns the path where persistent data should be stored.
 | 
					  /// Returns the path where persistent data should be stored.
 | 
				
			||||||
  Future<String> getPersistentDataPath();
 | 
					  Future<String> getPersistentDataPath();
 | 
				
			||||||
@ -17,4 +19,6 @@ abstract class PlatformImplementation {
 | 
				
			|||||||
  /// aspect ratio in tact to [width], and write it to [dest]. If we were successful, returns true.
 | 
					  /// aspect ratio in tact to [width], and write it to [dest]. If we were successful, returns true.
 | 
				
			||||||
  /// If no thumbnail was generated, returns false.
 | 
					  /// If no thumbnail was generated, returns false.
 | 
				
			||||||
  Future<bool> generateVideoThumbnail(String src, String dest, int width);
 | 
					  Future<bool> generateVideoThumbnail(String src, String dest, int width);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<List<String>> pickFiles(FilePickerType type, bool pickMultiple);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					import 'package:moxplatform_platform_interface/src/api.g.dart';
 | 
				
			||||||
import 'package:moxplatform_platform_interface/src/platform.dart';
 | 
					import 'package:moxplatform_platform_interface/src/platform.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class StubPlatformImplementation extends PlatformImplementation {
 | 
					class StubPlatformImplementation extends PlatformImplementation {
 | 
				
			||||||
@ -22,4 +23,7 @@ class StubPlatformImplementation extends PlatformImplementation {
 | 
				
			|||||||
    int width,
 | 
					    int width,
 | 
				
			||||||
  ) async =>
 | 
					  ) async =>
 | 
				
			||||||
      false;
 | 
					      false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Future<List<String>> pickFiles(FilePickerType type, bool pickMultiple) async => [];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -32,6 +32,13 @@ enum FallbackIconType {
 | 
				
			|||||||
  notes;
 | 
					  notes;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum FilePickerType {
 | 
				
			||||||
 | 
					  image,
 | 
				
			||||||
 | 
					  video,
 | 
				
			||||||
 | 
					  imageAndVideo,
 | 
				
			||||||
 | 
					  generic,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@HostApi()
 | 
					@HostApi()
 | 
				
			||||||
abstract class MoxplatformApi {
 | 
					abstract class MoxplatformApi {
 | 
				
			||||||
  /// Platform APIs
 | 
					  /// Platform APIs
 | 
				
			||||||
@ -50,4 +57,8 @@ abstract class MoxplatformApi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /// Media APIs
 | 
					  /// Media APIs
 | 
				
			||||||
  bool generateVideoThumbnail(String src, String dest, int maxWidth);
 | 
					  bool generateVideoThumbnail(String src, String dest, int maxWidth);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Picker
 | 
				
			||||||
 | 
					  @async
 | 
				
			||||||
 | 
					  List<String> pickFiles(FilePickerType type, bool pickMultiple);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user