avm2: Implement FileReference browse
This commit is contained in:
parent
e7b8b75d07
commit
fff841a22e
|
@ -325,6 +325,34 @@ pub fn make_error_2008<'gc>(activation: &mut Activation<'_, 'gc>, param_name: &s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
#[cold]
|
||||||
|
pub fn make_error_2037<'gc>(activation: &mut Activation<'_, 'gc>) -> Error<'gc> {
|
||||||
|
let err = error(
|
||||||
|
activation,
|
||||||
|
"Error #2037: Functions called in incorrect sequence, or earlier call was unsuccessful.",
|
||||||
|
2037,
|
||||||
|
);
|
||||||
|
match err {
|
||||||
|
Ok(err) => Error::AvmError(err),
|
||||||
|
Err(err) => err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
#[cold]
|
||||||
|
pub fn make_error_2097<'gc>(activation: &mut Activation<'_, 'gc>) -> Error<'gc> {
|
||||||
|
let err = argument_error(
|
||||||
|
activation,
|
||||||
|
"Error #2097: The FileFilter Array is not in the correct format.",
|
||||||
|
2097,
|
||||||
|
);
|
||||||
|
match err {
|
||||||
|
Ok(err) => Error::AvmError(err),
|
||||||
|
Err(err) => err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
#[cold]
|
#[cold]
|
||||||
pub fn make_error_2126<'gc>(activation: &mut Activation<'_, 'gc>) -> Error<'gc> {
|
pub fn make_error_2126<'gc>(activation: &mut Activation<'_, 'gc>) -> Error<'gc> {
|
||||||
|
|
|
@ -168,6 +168,7 @@ pub struct SystemClasses<'gc> {
|
||||||
pub statusevent: ClassObject<'gc>,
|
pub statusevent: ClassObject<'gc>,
|
||||||
pub contextmenuevent: ClassObject<'gc>,
|
pub contextmenuevent: ClassObject<'gc>,
|
||||||
pub filereference: ClassObject<'gc>,
|
pub filereference: ClassObject<'gc>,
|
||||||
|
pub filefilter: ClassObject<'gc>,
|
||||||
pub font: ClassObject<'gc>,
|
pub font: ClassObject<'gc>,
|
||||||
pub textline: ClassObject<'gc>,
|
pub textline: ClassObject<'gc>,
|
||||||
pub sampledataevent: ClassObject<'gc>,
|
pub sampledataevent: ClassObject<'gc>,
|
||||||
|
@ -298,6 +299,7 @@ impl<'gc> SystemClasses<'gc> {
|
||||||
statusevent: object,
|
statusevent: object,
|
||||||
contextmenuevent: object,
|
contextmenuevent: object,
|
||||||
filereference: object,
|
filereference: object,
|
||||||
|
filefilter: object,
|
||||||
font: object,
|
font: object,
|
||||||
textline: object,
|
textline: object,
|
||||||
sampledataevent: object,
|
sampledataevent: object,
|
||||||
|
@ -809,6 +811,7 @@ fn load_playerglobal<'gc>(
|
||||||
("flash.media", "Video", video),
|
("flash.media", "Video", video),
|
||||||
("flash.net", "URLVariables", urlvariables),
|
("flash.net", "URLVariables", urlvariables),
|
||||||
("flash.net", "FileReference", filereference),
|
("flash.net", "FileReference", filereference),
|
||||||
|
("flash.net", "FileFilter", filefilter),
|
||||||
("flash.utils", "ByteArray", bytearray),
|
("flash.utils", "ByteArray", bytearray),
|
||||||
("flash.system", "ApplicationDomain", application_domain),
|
("flash.system", "ApplicationDomain", application_domain),
|
||||||
("flash.text", "Font", font),
|
("flash.text", "Font", font),
|
||||||
|
|
|
@ -4,8 +4,8 @@ use crate::avm2::error::type_error;
|
||||||
use crate::avm2::object::TObject;
|
use crate::avm2::object::TObject;
|
||||||
use crate::avm2::{Activation, Error, Object, Value};
|
use crate::avm2::{Activation, Error, Object, Value};
|
||||||
|
|
||||||
pub mod local_connection;
|
|
||||||
pub mod file_reference;
|
pub mod file_reference;
|
||||||
|
pub mod local_connection;
|
||||||
pub mod net_connection;
|
pub mod net_connection;
|
||||||
pub mod net_stream;
|
pub mod net_stream;
|
||||||
pub mod object_encoding;
|
pub mod object_encoding;
|
||||||
|
|
|
@ -9,7 +9,6 @@ package flash.net
|
||||||
{
|
{
|
||||||
private var _creationDate: Date;
|
private var _creationDate: Date;
|
||||||
private var _creator: String;
|
private var _creator: String;
|
||||||
private var _data: ByteArray;
|
|
||||||
private var _extension: String;
|
private var _extension: String;
|
||||||
private var _modificationDate: Date;
|
private var _modificationDate: Date;
|
||||||
private var _name: String;
|
private var _name: String;
|
||||||
|
@ -29,9 +28,7 @@ package flash.net
|
||||||
return this._creator;
|
return this._creator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get data(): ByteArray {
|
public native function get data(): ByteArray;
|
||||||
return this._data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function get extension(): String {
|
public function get extension(): String {
|
||||||
return this._extension;
|
return this._extension;
|
||||||
|
@ -57,9 +54,7 @@ package flash.net
|
||||||
return this._type;
|
return this._type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function browse(typeFilter:Array = null):Boolean {
|
public native function browse(typeFilter:Array = null): Boolean;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function cancel():void {
|
public function cancel():void {
|
||||||
stub_method("flash.net.FileReference", "cancel");
|
stub_method("flash.net.FileReference", "cancel");
|
||||||
|
@ -69,9 +64,7 @@ package flash.net
|
||||||
stub_method("flash.net.FileReference", "download");
|
stub_method("flash.net.FileReference", "download");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function load():void {
|
public native function load():void;
|
||||||
stub_method("flash.net.FileReference", "load");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function requestPermission():void {
|
public function requestPermission():void {
|
||||||
stub_method("flash.net.FileReference", "requestPermission");
|
stub_method("flash.net.FileReference", "requestPermission");
|
||||||
|
|
|
@ -1 +1,132 @@
|
||||||
pub use crate::avm2::object::file_reference_allocator;
|
use crate::avm2::bytearray::ByteArrayStorage;
|
||||||
|
use crate::avm2::error::{make_error_2037, make_error_2097};
|
||||||
|
pub use crate::avm2::object::file_reference_allocator;
|
||||||
|
use crate::avm2::object::{ByteArrayObject, FileReference};
|
||||||
|
use crate::avm2::{Activation, Avm2, Error, EventObject, Object, TObject, Value};
|
||||||
|
use crate::backend::ui::FileFilter;
|
||||||
|
|
||||||
|
pub fn get_data<'gc>(
|
||||||
|
activation: &mut Activation<'_, 'gc>,
|
||||||
|
this: Object<'gc>,
|
||||||
|
_args: &[Value<'gc>],
|
||||||
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
|
let this = this.as_file_reference().unwrap();
|
||||||
|
|
||||||
|
let bytearray = match *this.file_reference() {
|
||||||
|
FileReference::FileDialogResult(ref dialog_result) if this.loaded() => {
|
||||||
|
let bytes = dialog_result.contents();
|
||||||
|
let storage = ByteArrayStorage::from_vec(bytes.to_vec());
|
||||||
|
ByteArrayObject::from_storage(activation, storage)?
|
||||||
|
}
|
||||||
|
// Contrary to other getters `data` will return null instead of throwing.
|
||||||
|
_ => return Ok(Value::Null),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(bytearray.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn browse<'gc>(
|
||||||
|
activation: &mut Activation<'_, 'gc>,
|
||||||
|
this: Object<'gc>,
|
||||||
|
args: &[Value<'gc>],
|
||||||
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
|
let this = this.as_file_reference().unwrap();
|
||||||
|
|
||||||
|
let mut filters = Vec::new();
|
||||||
|
if let Value::Object(obj) = args[0] {
|
||||||
|
if let Some(array_storage) = obj.as_array_storage() {
|
||||||
|
for filter in array_storage.iter() {
|
||||||
|
if let Some(Value::Object(obj)) = filter {
|
||||||
|
let filefilter = activation
|
||||||
|
.avm2()
|
||||||
|
.classes()
|
||||||
|
.filefilter
|
||||||
|
.inner_class_definition();
|
||||||
|
if !obj.is_of_type(filefilter, &mut activation.context) {
|
||||||
|
return Err(make_error_2097(activation));
|
||||||
|
}
|
||||||
|
|
||||||
|
let description = obj.get_public_property("description", activation)?;
|
||||||
|
let extension = obj.get_public_property("extension", activation)?;
|
||||||
|
let mac_type = obj.get_public_property("macType", activation)?;
|
||||||
|
|
||||||
|
// The description and extension must be non-empty strings.
|
||||||
|
match (description, extension) {
|
||||||
|
(Value::String(description), Value::String(extension))
|
||||||
|
if !description.is_empty() && !extension.is_empty() =>
|
||||||
|
{
|
||||||
|
let mac_type = match mac_type {
|
||||||
|
Value::String(mac_type) if !mac_type.is_empty() => {
|
||||||
|
Some(mac_type.to_string())
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
filters.push(FileFilter {
|
||||||
|
description: description.to_string(),
|
||||||
|
extensions: extension.to_string(),
|
||||||
|
mac_type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => return Err(make_error_2097(activation)),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(make_error_2097(activation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let dialog = activation.context.ui.display_file_open_dialog(filters);
|
||||||
|
let result = match dialog {
|
||||||
|
Some(dialog) => {
|
||||||
|
let process = activation.context.load_manager.select_file_dialog_avm2(
|
||||||
|
activation.context.player.clone(),
|
||||||
|
this,
|
||||||
|
dialog,
|
||||||
|
);
|
||||||
|
|
||||||
|
activation.context.navigator.spawn_future(process);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
None => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(result.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load<'gc>(
|
||||||
|
activation: &mut Activation<'_, 'gc>,
|
||||||
|
this: Object<'gc>,
|
||||||
|
_args: &[Value<'gc>],
|
||||||
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
|
let this = this.as_file_reference().unwrap();
|
||||||
|
|
||||||
|
// Somewhat unexpectedly, we don't need to load anything here, because
|
||||||
|
// that already happened during browse() or save().
|
||||||
|
|
||||||
|
let size = match *this.file_reference() {
|
||||||
|
FileReference::None => return Err(make_error_2037(activation)),
|
||||||
|
FileReference::FileDialogResult(ref dialog_result) => dialog_result.size().unwrap_or(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
let open_evt = EventObject::bare_default_event(&mut activation.context, "open");
|
||||||
|
Avm2::dispatch_event(&mut activation.context, open_evt, this.into());
|
||||||
|
|
||||||
|
let progress_evt = EventObject::progress_event(activation, "progress", 0, size, false, false);
|
||||||
|
Avm2::dispatch_event(&mut activation.context, progress_evt, this.into());
|
||||||
|
|
||||||
|
let open_evt2 = EventObject::bare_default_event(&mut activation.context, "open");
|
||||||
|
Avm2::dispatch_event(&mut activation.context, open_evt2, this.into());
|
||||||
|
|
||||||
|
let progress_evt2 =
|
||||||
|
EventObject::progress_event(activation, "progress", size, size, false, false);
|
||||||
|
Avm2::dispatch_event(&mut activation.context, progress_evt2, this.into());
|
||||||
|
|
||||||
|
this.set_loaded(true);
|
||||||
|
|
||||||
|
let complete_evt = EventObject::bare_default_event(&mut activation.context, "complete");
|
||||||
|
Avm2::dispatch_event(&mut activation.context, complete_evt, this.into());
|
||||||
|
|
||||||
|
Ok(Value::Undefined)
|
||||||
|
}
|
||||||
|
|
|
@ -88,7 +88,9 @@ pub use crate::avm2::object::domain_object::{
|
||||||
};
|
};
|
||||||
pub use crate::avm2::object::error_object::{error_allocator, ErrorObject, ErrorObjectWeak};
|
pub use crate::avm2::object::error_object::{error_allocator, ErrorObject, ErrorObjectWeak};
|
||||||
pub use crate::avm2::object::event_object::{event_allocator, EventObject, EventObjectWeak};
|
pub use crate::avm2::object::event_object::{event_allocator, EventObject, EventObjectWeak};
|
||||||
pub use crate::avm2::object::file_reference_object::{file_reference_allocator, FileReferenceObject, FileReferenceObjectWeak};
|
pub use crate::avm2::object::file_reference_object::{
|
||||||
|
file_reference_allocator, FileReference, FileReferenceObject, FileReferenceObjectWeak,
|
||||||
|
};
|
||||||
pub use crate::avm2::object::font_object::{font_allocator, FontObject, FontObjectWeak};
|
pub use crate::avm2::object::font_object::{font_allocator, FontObject, FontObjectWeak};
|
||||||
pub use crate::avm2::object::function_object::{
|
pub use crate::avm2::object::function_object::{
|
||||||
function_allocator, FunctionObject, FunctionObjectWeak,
|
function_allocator, FunctionObject, FunctionObjectWeak,
|
||||||
|
|
|
@ -211,6 +211,38 @@ impl<'gc> EventObject<'gc> {
|
||||||
)
|
)
|
||||||
.unwrap() // we don't expect to break here
|
.unwrap() // we don't expect to break here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn progress_event<S>(
|
||||||
|
activation: &mut Activation<'_, 'gc>,
|
||||||
|
event_type: S,
|
||||||
|
bytes_loaded: u64,
|
||||||
|
bytes_total: u64,
|
||||||
|
bubbles: bool,
|
||||||
|
cancelable: bool,
|
||||||
|
) -> Object<'gc>
|
||||||
|
where
|
||||||
|
S: Into<AvmString<'gc>>,
|
||||||
|
{
|
||||||
|
let event_type: AvmString<'gc> = event_type.into();
|
||||||
|
|
||||||
|
let progress_event_cls = activation.avm2().classes().progressevent;
|
||||||
|
progress_event_cls
|
||||||
|
.construct(
|
||||||
|
activation,
|
||||||
|
&[
|
||||||
|
event_type.into(),
|
||||||
|
// bubbles
|
||||||
|
bubbles.into(),
|
||||||
|
// cancelable
|
||||||
|
cancelable.into(),
|
||||||
|
// bytesLoaded
|
||||||
|
(bytes_loaded as f64).into(),
|
||||||
|
// bytesToal
|
||||||
|
(bytes_total as f64).into(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap() // we don't expect to break here
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> TObject<'gc> for EventObject<'gc> {
|
impl<'gc> TObject<'gc> for EventObject<'gc> {
|
||||||
|
|
|
@ -2,6 +2,7 @@ use crate::avm2::object::script_object::ScriptObjectData;
|
||||||
use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject};
|
use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject};
|
||||||
use crate::avm2::value::Value;
|
use crate::avm2::value::Value;
|
||||||
use crate::avm2::{Activation, Error};
|
use crate::avm2::{Activation, Error};
|
||||||
|
use crate::backend::ui::FileDialogResult;
|
||||||
use gc_arena::barrier::unlock;
|
use gc_arena::barrier::unlock;
|
||||||
use gc_arena::{lock::RefLock, Collect, Gc};
|
use gc_arena::{lock::RefLock, Collect, Gc};
|
||||||
use gc_arena::{GcWeak, Mutation};
|
use gc_arena::{GcWeak, Mutation};
|
||||||
|
@ -18,12 +19,13 @@ pub fn file_reference_allocator<'gc>(
|
||||||
activation.context.gc(),
|
activation.context.gc(),
|
||||||
FileReferenceObjectData {
|
FileReferenceObjectData {
|
||||||
base,
|
base,
|
||||||
|
reference: RefCell::new(FileReference::None),
|
||||||
|
loaded: Cell::new(false),
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Collect, Copy)]
|
#[derive(Clone, Collect, Copy)]
|
||||||
#[collect(no_drop)]
|
#[collect(no_drop)]
|
||||||
pub struct FileReferenceObject<'gc>(pub Gc<'gc, FileReferenceObjectData<'gc>>);
|
pub struct FileReferenceObject<'gc>(pub Gc<'gc, FileReferenceObjectData<'gc>>);
|
||||||
|
@ -54,11 +56,40 @@ impl<'gc> TObject<'gc> for FileReferenceObject<'gc> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'gc> FileReferenceObject<'gc> {
|
||||||
|
pub fn init_from_dialog_result(&self, result: Box<dyn FileDialogResult>) -> FileReference {
|
||||||
|
self.0
|
||||||
|
.reference
|
||||||
|
.replace(FileReference::FileDialogResult(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn file_reference(&self) -> Ref<'_, FileReference> {
|
||||||
|
self.0.reference.borrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_loaded(&self, value: bool) {
|
||||||
|
self.0.loaded.set(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn loaded(&self) -> bool {
|
||||||
|
self.0.loaded.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum FileReference {
|
||||||
|
None,
|
||||||
|
FileDialogResult(Box<dyn FileDialogResult>),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Collect)]
|
#[derive(Collect)]
|
||||||
#[collect(no_drop)]
|
#[collect(no_drop)]
|
||||||
pub struct FileReferenceObjectData<'gc> {
|
pub struct FileReferenceObjectData<'gc> {
|
||||||
/// Base script object
|
/// Base script object
|
||||||
base: RefLock<ScriptObjectData<'gc>>,
|
base: RefLock<ScriptObjectData<'gc>>,
|
||||||
|
|
||||||
|
reference: RefCell<FileReference>,
|
||||||
|
|
||||||
|
loaded: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for FileReferenceObject<'_> {
|
impl fmt::Debug for FileReferenceObject<'_> {
|
||||||
|
|
|
@ -6,7 +6,8 @@ use crate::avm1::{ExecutionReason, NativeObject};
|
||||||
use crate::avm1::{Object, SoundObject, TObject, Value};
|
use crate::avm1::{Object, SoundObject, TObject, Value};
|
||||||
use crate::avm2::bytearray::ByteArrayStorage;
|
use crate::avm2::bytearray::ByteArrayStorage;
|
||||||
use crate::avm2::object::{
|
use crate::avm2::object::{
|
||||||
ByteArrayObject, EventObject as Avm2EventObject, LoaderStream, TObject as _,
|
ByteArrayObject, EventObject as Avm2EventObject, FileReferenceObject, LoaderStream,
|
||||||
|
TObject as _,
|
||||||
};
|
};
|
||||||
use crate::avm2::{
|
use crate::avm2::{
|
||||||
Activation as Avm2Activation, Avm2, Domain as Avm2Domain, Object as Avm2Object,
|
Activation as Avm2Activation, Avm2, Domain as Avm2Domain, Object as Avm2Object,
|
||||||
|
@ -248,6 +249,7 @@ impl<'gc> LoadManager<'gc> {
|
||||||
| Loader::SoundAvm2 { self_handle, .. }
|
| Loader::SoundAvm2 { self_handle, .. }
|
||||||
| Loader::NetStream { self_handle, .. }
|
| Loader::NetStream { self_handle, .. }
|
||||||
| Loader::FileDialog { self_handle, .. }
|
| Loader::FileDialog { self_handle, .. }
|
||||||
|
| Loader::FileDialogAvm2 { self_handle, .. }
|
||||||
| Loader::DownloadFileDialog { self_handle, .. }
|
| Loader::DownloadFileDialog { self_handle, .. }
|
||||||
| Loader::UploadFile { self_handle, .. }
|
| Loader::UploadFile { self_handle, .. }
|
||||||
| Loader::MovieUnloader { self_handle, .. } => *self_handle = Some(handle),
|
| Loader::MovieUnloader { self_handle, .. } => *self_handle = Some(handle),
|
||||||
|
@ -504,6 +506,22 @@ impl<'gc> LoadManager<'gc> {
|
||||||
loader.file_dialog_loader(player, dialog)
|
loader.file_dialog_loader(player, dialog)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn select_file_dialog_avm2(
|
||||||
|
&mut self,
|
||||||
|
player: Weak<Mutex<Player>>,
|
||||||
|
target_object: FileReferenceObject<'gc>,
|
||||||
|
dialog: DialogResultFuture,
|
||||||
|
) -> OwnedFuture<(), Error> {
|
||||||
|
let loader = Loader::FileDialogAvm2 {
|
||||||
|
self_handle: None,
|
||||||
|
target_object,
|
||||||
|
};
|
||||||
|
let handle = self.add_loader(loader);
|
||||||
|
let loader = self.get_loader_mut(handle).unwrap();
|
||||||
|
loader.file_dialog_loader(player, dialog)
|
||||||
|
}
|
||||||
|
|
||||||
/// Display a dialog allowing a user to download a file
|
/// Display a dialog allowing a user to download a file
|
||||||
///
|
///
|
||||||
/// Returns a future that will be resolved when a file is selected and the download has completed
|
/// Returns a future that will be resolved when a file is selected and the download has completed
|
||||||
|
@ -708,6 +726,16 @@ pub enum Loader<'gc> {
|
||||||
target_object: Object<'gc>,
|
target_object: Object<'gc>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Loader that is choosing a file from an AVM2 scope.
|
||||||
|
FileDialogAvm2 {
|
||||||
|
/// The handle to refer to this loader instance.
|
||||||
|
#[collect(require_static)]
|
||||||
|
self_handle: Option<Handle>,
|
||||||
|
|
||||||
|
/// The target AVM2 object to set to the selected file path.
|
||||||
|
target_object: FileReferenceObject<'gc>,
|
||||||
|
},
|
||||||
|
|
||||||
/// Loader that is downloading a file from an AVM1 object scope.
|
/// Loader that is downloading a file from an AVM1 object scope.
|
||||||
DownloadFileDialog {
|
DownloadFileDialog {
|
||||||
/// The handle to refer to this loader instance.
|
/// The handle to refer to this loader instance.
|
||||||
|
@ -2399,7 +2427,7 @@ impl<'gc> Loader<'gc> {
|
||||||
dialog: DialogResultFuture,
|
dialog: DialogResultFuture,
|
||||||
) -> OwnedFuture<(), Error> {
|
) -> OwnedFuture<(), Error> {
|
||||||
let handle = match self {
|
let handle = match self {
|
||||||
Loader::FileDialog { self_handle, .. } => {
|
Loader::FileDialog { self_handle, .. } | Loader::FileDialogAvm2 { self_handle, .. } => {
|
||||||
self_handle.expect("Loader not self-introduced")
|
self_handle.expect("Loader not self-introduced")
|
||||||
}
|
}
|
||||||
_ => return Box::pin(async { Err(Error::NotFileDialogLoader) }),
|
_ => return Box::pin(async { Err(Error::NotFileDialogLoader) }),
|
||||||
|
@ -2418,50 +2446,89 @@ impl<'gc> Loader<'gc> {
|
||||||
// Fire the load handler.
|
// Fire the load handler.
|
||||||
player.lock().unwrap().update(|uc| -> Result<(), Error> {
|
player.lock().unwrap().update(|uc| -> Result<(), Error> {
|
||||||
let loader = uc.load_manager.get_loader(handle);
|
let loader = uc.load_manager.get_loader(handle);
|
||||||
let target_object = match loader {
|
match loader {
|
||||||
Some(&Loader::FileDialog { target_object, .. }) => target_object,
|
Some(&Loader::FileDialog { target_object, .. }) => {
|
||||||
None => return Err(Error::Cancelled),
|
let file_ref = match target_object.native() {
|
||||||
_ => return Err(Error::NotFileDialogLoader),
|
NativeObject::FileReference(fr) => fr,
|
||||||
};
|
_ => panic!("NativeObject must be FileReference"),
|
||||||
|
};
|
||||||
|
|
||||||
let file_ref = match target_object.native() {
|
let mut activation = Activation::from_stub(
|
||||||
NativeObject::FileReference(fr) => fr,
|
uc.reborrow(),
|
||||||
_ => panic!("NativeObject must be FileReference"),
|
ActivationIdentifier::root("[File Dialog]"),
|
||||||
};
|
);
|
||||||
|
|
||||||
let mut activation = Activation::from_stub(
|
match dialog_result {
|
||||||
uc.reborrow(),
|
Ok(dialog_result) => {
|
||||||
ActivationIdentifier::root("[File Dialog]"),
|
use crate::avm1::globals::as_broadcaster;
|
||||||
);
|
|
||||||
|
|
||||||
match dialog_result {
|
if !dialog_result.is_cancelled() {
|
||||||
Ok(dialog_result) => {
|
file_ref.init_from_dialog_result(
|
||||||
use crate::avm1::globals::as_broadcaster;
|
&mut activation,
|
||||||
|
dialog_result.borrow(),
|
||||||
if !dialog_result.is_cancelled() {
|
);
|
||||||
file_ref
|
as_broadcaster::broadcast_internal(
|
||||||
.init_from_dialog_result(&mut activation, dialog_result.borrow());
|
&mut activation,
|
||||||
as_broadcaster::broadcast_internal(
|
target_object,
|
||||||
&mut activation,
|
&[target_object.into()],
|
||||||
target_object,
|
"onSelect".into(),
|
||||||
&[target_object.into()],
|
)?;
|
||||||
"onSelect".into(),
|
} else {
|
||||||
)?;
|
as_broadcaster::broadcast_internal(
|
||||||
} else {
|
&mut activation,
|
||||||
as_broadcaster::broadcast_internal(
|
target_object,
|
||||||
&mut activation,
|
&[target_object.into()],
|
||||||
target_object,
|
"onCancel".into(),
|
||||||
&[target_object.into()],
|
)?;
|
||||||
"onCancel".into(),
|
}
|
||||||
)?;
|
}
|
||||||
|
Err(err) => {
|
||||||
|
tracing::warn!("Error on file dialog: {:?}", err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Some(&Loader::FileDialogAvm2 { target_object, .. }) => {
|
||||||
tracing::warn!("Error on file dialog: {:?}", err);
|
match dialog_result {
|
||||||
}
|
Ok(dialog_result) => {
|
||||||
}
|
if !dialog_result.is_cancelled() {
|
||||||
|
target_object.init_from_dialog_result(dialog_result);
|
||||||
|
|
||||||
Ok(())
|
let mut activation =
|
||||||
|
Avm2Activation::from_nothing(uc.reborrow());
|
||||||
|
let select_event = Avm2EventObject::bare_default_event(
|
||||||
|
&mut activation.context,
|
||||||
|
"select",
|
||||||
|
);
|
||||||
|
Avm2::dispatch_event(
|
||||||
|
&mut activation.context,
|
||||||
|
select_event,
|
||||||
|
target_object.into(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let mut activation =
|
||||||
|
Avm2Activation::from_nothing(uc.reborrow());
|
||||||
|
let cancel_event = Avm2EventObject::bare_default_event(
|
||||||
|
&mut activation.context,
|
||||||
|
"cancel",
|
||||||
|
);
|
||||||
|
Avm2::dispatch_event(
|
||||||
|
&mut activation.context,
|
||||||
|
cancel_event,
|
||||||
|
target_object.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
tracing::warn!("Error on file dialog: {:?}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
None => Err(Error::Cancelled),
|
||||||
|
_ => Err(Error::NotFileDialogLoader),
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue