Decided to move the loading of client.js into its own helper class for now. When dart has real support for Google client apis none of this will be needed. As of now this serves as good practice and examples of javascript/dart interop.
/** * Sample google api client loader. */classGoogleApiClientLoader{staticconstString_CLIENT_ID='299615367852.apps.googleusercontent.com';staticconstString_SCOPE='https://www.googleapis.com/auth/drive';staticconstString_handleClientLoadName="handleClientLoad";staticvoid_loadScript(){/** * Create and load script element. */ScriptElementscript=newScriptElement();script.src="http://apis.google.com/js/client.js?onload=$_handleClientLoadName";script.type="text/javascript";document.body.children.add(script);}staticvoid_createScopedCallbacks(varcompleter){js.scoped((){/** * handleAuthResult is called from javascript when * the function to call once the login process is complete. */js.context.handleAuthResult=newjs.Callback.many((js.ProxyauthResult){MapdartAuthResult=JSON.parse(js.context.JSON.stringify(authResult));completer.complete(dartAuthResult);});/** * This javascript method is called when the client.js script * is loaded. */js.context.handleClientLoad=newjs.Callback.many((){js.context.window.setTimeout(js.context.checkAuth,1);});/** * Authorization check if the client allows this * application to access its google drive. */js.context.checkAuth=newjs.Callback.many((){js.context.gapi.auth.authorize(js.map({'client_id':_CLIENT_ID,'scope':_SCOPE,'immediate':true}),js.context.handleAuthResult);});});}/** * Load the google client api, future returns * map results. */staticFuture<Map>load(){varcompleter=newCompleter();_createScopedCallbacks(completer);_loadScript();returncompleter.future;}}
The calling of load() returns a future with our authentication results. Eases the process of having the google drive scope available to the client application.
A simple dart Drive class created gives access to the list call from the javascript apis. The interesting point for me to learn is knowing that client.js has to load the drive api. In the load() future we call js.context.gapi.client.load which will take the api and version to be loaded for the client application.
/** * Sample google drive class. */classDrive{js.Proxy_drive;boolget_isLoaded=>_drive!=null;/** * Load the gapi.client.drive api. */Future<bool>load(){varcompleter=newCompleter();js.scoped((){js.context.gapi.client.load('drive','v2',newjs.Callback.once((){_drive=js.context.gapi.client.drive;js.retain(_drive);completer.complete(true);}));});returncompleter.future;}/** * Check if gapi.client.drive is loaded, if not * load before executing. */void_loadederExecute(Functionfunction){if(_isLoaded){function();}else{load().then((s){if(s==true){function();}else{throw"loadedExecute failed";}});}}/** * List files with gapi.drive.files.list() */Future<Map>list(){varcompleter=newCompleter();_loadederExecute((){js.scoped((){varrequest=_drive.files.list();request.execute(newjs.Callback.once((js.ProxyjsonResp,varrawResp){Mapm=JSON.parse(js.context.JSON.stringify(jsonResp));completer.complete(m);}));});});returncompleter.future;}}
With the following sugar classes it was easy to just list files from my google drive account.