1+ import ajax from "@deadlyjack/ajax" ;
12import Contextmenu from "components/contextmenu" ;
23import inputhints from "components/inputhints" ;
34import Page from "components/page" ;
@@ -16,6 +17,7 @@ import prompt from "dialogs/prompt";
1617import select from "dialogs/select" ;
1718import fsOperation from "fileSystem" ;
1819import keyboardHandler from "handlers/keyboard" ;
20+ import purchaseListener from "handlers/purchase" ;
1921import windowResize from "handlers/windowResize" ;
2022import actionStack from "lib/actionStack" ;
2123import commands from "lib/commands" ;
@@ -154,9 +156,8 @@ export default class Acode {
154156 exec ( key , val ) {
155157 if ( key in commands ) {
156158 return commands [ key ] ( val ) ;
157- } else {
158- return false ;
159159 }
160+ return false ;
160161 }
161162
162163 /**
@@ -166,67 +167,117 @@ export default class Acode {
166167 * @returns {Promise<void> }
167168 */
168169 installPlugin ( pluginId , installerPluginName ) {
169- return new Promise ( async ( resolve , reject ) => {
170- try {
171- const confirmation = await confirm (
172- strings [ "install" ] ,
173- `Do you want to install plugin '${ pluginId } '${ installerPluginName ? ` requested by ${ installerPluginName } ` : "" } ?` ,
174- ) ;
175-
176- if ( ! confirmation ) {
177- reject ( new Error ( "User cancelled installation" ) ) ;
178- return ;
179- }
180-
181- const isPluginExists = await fsOperation (
182- Url . join ( PLUGIN_DIR , pluginId ) ,
183- ) . exists ( ) ;
184- if ( isPluginExists ) {
185- reject ( new Error ( "PLugin already installed" ) ) ;
186- return ;
187- }
188-
189- let purchaseToken = null ;
190-
191- const pluginUrl = Url . join ( constants . API_BASE , `plugin/${ pluginId } ` ) ;
192- const remotePlugin = await fsOperation ( pluginUrl )
193- . readFile ( "json" )
194- . catch ( ( ) => {
195- reject ( new Error ( "Failed to fetch plugin details" ) ) ;
196- return null ;
197- } ) ;
198-
199- if ( remotePlugin ) {
200- if ( Number . parseFloat ( remotePlugin . price ) > 0 ) {
201- try {
202- const [ product ] = await helpers . promisify ( iap . getProducts , [
203- remotePlugin . sku ,
204- ] ) ;
205- if ( product ) {
206- async function getPurchase ( sku ) {
207- const purchases = await helpers . promisify ( iap . getPurchases ) ;
208- const purchase = purchases . find ( ( p ) =>
209- p . productIds . includes ( sku ) ,
210- ) ;
211- return purchase ;
212- }
213- const purchase = await getPurchase ( product . productId ) ;
214- purchaseToken = purchase ?. purchaseToken ;
215- }
216- } catch ( error ) {
217- helpers . error ( error ) ;
218- reject ( new Error ( "Failed to validate purchase" ) ) ;
219- return ;
220- }
170+ return new Promise ( ( resolve , reject ) => {
171+ confirm (
172+ strings . install ,
173+ `Do you want to install plugin '${ pluginId } '${ installerPluginName ? ` requested by ${ installerPluginName } ` : "" } ?` ,
174+ )
175+ . then ( ( confirmation ) => {
176+ if ( ! confirmation ) {
177+ reject ( new Error ( "User cancelled installation" ) ) ;
178+ return ;
221179 }
222- }
223180
224- const { default : installPlugin } = await import ( "lib/installPlugin" ) ;
225- await installPlugin ( pluginId , remotePlugin . name , purchaseToken ) ;
226- resolve ( ) ;
227- } catch ( error ) {
228- reject ( error ) ;
229- }
181+ fsOperation ( Url . join ( PLUGIN_DIR , pluginId ) )
182+ . exists ( )
183+ . then ( ( isPluginExists ) => {
184+ if ( isPluginExists ) {
185+ reject ( new Error ( "Plugin already installed" ) ) ;
186+ return ;
187+ }
188+
189+ let purchaseToken ;
190+ let product ;
191+ const pluginUrl = Url . join (
192+ constants . API_BASE ,
193+ `plugin/${ pluginId } ` ,
194+ ) ;
195+ fsOperation ( pluginUrl )
196+ . readFile ( "json" )
197+ . catch ( ( ) => {
198+ reject ( new Error ( "Failed to fetch plugin details" ) ) ;
199+ return null ;
200+ } )
201+ . then ( ( remotePlugin ) => {
202+ if ( remotePlugin ) {
203+ const isPaid = remotePlugin . price > 0 ;
204+ helpers
205+ . promisify ( iap . getProducts , [ remotePlugin . sku ] )
206+ . then ( ( products ) => {
207+ [ product ] = products ;
208+ if ( product ) {
209+ return getPurchase ( product . productId ) ;
210+ }
211+ return null ;
212+ } )
213+ . then ( ( purchase ) => {
214+ purchaseToken = purchase ?. purchaseToken ;
215+
216+ if ( isPaid && ! purchaseToken ) {
217+ if ( ! product ) throw new Error ( "Product not found" ) ;
218+ return helpers . checkAPIStatus ( ) . then ( ( apiStatus ) => {
219+ if ( ! apiStatus ) {
220+ alert ( strings . error , strings . api_error ) ;
221+ return ;
222+ }
223+
224+ iap . setPurchaseUpdatedListener (
225+ ...purchaseListener ( onpurchase , onerror ) ,
226+ ) ;
227+ return helpers . promisify (
228+ iap . purchase ,
229+ product . json ,
230+ ) ;
231+ } ) ;
232+ }
233+ } )
234+ . then ( ( ) => {
235+ import ( "lib/installPlugin" ) . then (
236+ ( { default : installPlugin } ) => {
237+ installPlugin (
238+ pluginId ,
239+ remotePlugin . name ,
240+ purchaseToken ,
241+ ) . then ( ( ) => {
242+ resolve ( ) ;
243+ } ) ;
244+ } ,
245+ ) ;
246+ } ) ;
247+
248+ async function onpurchase ( e ) {
249+ const purchase = await getPurchase ( product . productId ) ;
250+ await ajax . post (
251+ Url . join ( constants . API_BASE , "plugin/order" ) ,
252+ {
253+ data : {
254+ id : remotePlugin . id ,
255+ token : purchase ?. purchaseToken ,
256+ package : BuildInfo . packageName ,
257+ } ,
258+ } ,
259+ ) ;
260+ purchaseToken = purchase ?. purchaseToken ;
261+ }
262+
263+ async function onerror ( error ) {
264+ throw error ;
265+ }
266+ }
267+ } ) ;
268+
269+ async function getPurchase ( sku ) {
270+ const purchases = await helpers . promisify ( iap . getPurchases ) ;
271+ const purchase = purchases . find ( ( p ) =>
272+ p . productIds . includes ( sku ) ,
273+ ) ;
274+ return purchase ;
275+ }
276+ } ) ;
277+ } )
278+ . catch ( ( error ) => {
279+ reject ( error ) ;
280+ } ) ;
230281 } ) ;
231282 }
232283
@@ -235,6 +286,7 @@ export default class Acode {
235286 if ( numFiles ) {
236287 return strings [ "unsaved files close app" ] ;
237288 }
289+ return null ;
238290 }
239291
240292 setLoadingMessage ( message ) {
@@ -296,11 +348,11 @@ export default class Acode {
296348 ( formatter ) => formatter . id !== id ,
297349 ) ;
298350 const { formatter } = appSettings . value ;
299- Object . keys ( formatter ) . forEach ( ( mode ) => {
351+ for ( const mode of Object . keys ( formatter ) ) {
300352 if ( formatter [ mode ] === id ) {
301353 delete formatter [ mode ] ;
302354 }
303- } ) ;
355+ }
304356 appSettings . update ( false ) ;
305357 }
306358
@@ -316,7 +368,8 @@ export default class Acode {
316368 formatterSettings ( name ) ;
317369 this . #afterSelectFormatter( name ) ;
318370 return ;
319- } else if ( ! formatter && ! selectIfNull ) {
371+ }
372+ if ( ! formatter && ! selectIfNull ) {
320373 toast ( strings [ "please select a formatter" ] ) ;
321374 }
322375 }
@@ -355,12 +408,12 @@ export default class Acode {
355408 */
356409 getFormatterFor ( extensions ) {
357410 const options = [ [ null , strings . none ] ] ;
358- this . formatters . forEach ( ( { id, name, exts } ) => {
411+ for ( const { id, name, exts } of this . formatters ) {
359412 const supports = exts . some ( ( ext ) => extensions . includes ( ext ) ) ;
360413 if ( supports || exts . includes ( "*" ) ) {
361414 options . push ( [ id , name ] ) ;
362415 }
363- } ) ;
416+ }
364417 return options ;
365418 }
366419
@@ -414,8 +467,8 @@ export default class Acode {
414467 }
415468
416469 async toInternalUrl ( url ) {
417- url = await helpers . toInternalUri ( url ) ;
418- return url ;
470+ const internalUrl = await helpers . toInternalUri ( url ) ;
471+ return internalUrl ;
419472 }
420473 /**
421474 * Push a notification
0 commit comments