Extending DroidScript Code to Desktop application

885 views
Skip to first unread message

jjts...@gmail.com

unread,
Jun 19, 2021, 1:24:26 PM6/19/21
to DroidScript
I've always been trying to make this come true and here is my concept.
If there's anyone who has other opinions or suggestions, it is very welcome!
.
# Utilizing Electron (skip this part if already familiar with it)
Electron is a mature tool for javascript developers to design desktop app, I'll briefly explain how it works: a main.js as node.js entry point, creating a browser window and loading the html css javascript into it, then inject some node.js functions into the browser window's context. That's it!
# Using DroidScript webview control as a sandbox
Prerequisite: Why not use the html mode in the new app's option?
If you're ever gonna import external library into your DS app by script tags, it'll get all the permissions given by the app object, which is extremely dangerous.
So we'll go the Electron way: only expose self-defined APIs for your webview.
And to do that we need to communicate with the main window.
# Communication between webview and the main window
This part might be rather tricky and is a polyfill given that I didn't know the formal way DS have built in (if it exists?) to communicate with the webview window.
Starting with the webview demo app in DS, I only changed the code from OnProgress to OnConsole and wrote some code in OnConsole. It loads my own blog's code testing page.
When you finished loading, put the red code below into the textarea of my page and press test. You'll get two alerts coming from the main window and webview.

function OnStart()
{
    lay = app.CreateLayout( "linear", "VCenter,FillXY" );

    web = app.CreateWebView( 1, 1, "Progress" );
    web.SetOnConsole( web_OnConsole );
    lay.AddChild( web );

    app.AddLayout( lay );

}

function web_OnConsole( consoleMsg )
{
    alert("From main I got: " + consoleMsg);
    web.Execute( "window.resolveConsole('Sent msg from main to webview');" );
    //app.Debug( "progress = " + progress );
}

(async ()=>{
  window.promiseConsole=new Promise(resolve=>
   {
    window.resolveConsole=resolve;
   });
  console.log("Sending msg from webview to main")
  alert("From webview I got: " + await window.promiseConsole)
})()

The above code makes it able to communicate between the webview and the main window. If there's a formal way to do this please tell me!
# Design a dual-fit API for Electron's browser window and the DS webview
I'm planning to get this done recently which supports basic file system operations.
At the Electron side, I'll try to use ajax inside the browser window to request something like 127.0.0.1:8088/file/copy/path1/path2, and in main.js use node.js to start an application server by express to achieve the file operations. The reason for this way is that if you want to move the whole thing to the Web later, you'll just need a few adjustments and it's done.
At the DroidScript side, I'll use the console.log method above to send commands to the main window to achieve the same file operations. The reason why I didn't use ajax on this side is that DroidScript's CreateWebServer seems to lack complete support for advanced use, like POST body, headers, data by json, etc.
# Deploying your app
Finally if all of the above is available, you'll build your Linux/MacOS X/Windows app by Electron and build your Android APK by DroidScript's APK Builder (requires purchasing).
Voila! You have successfully ported your DroidScript code to all the platforms! (Except for iOS, a platform I had no idea about)

Dave

unread,
Jun 19, 2021, 5:58:27 PM6/19/21
to DroidScript
Hi,

You might like to know that we are already making DS multi-platform and utilising Electron for our framework for Windows, LInux and MacOS.  However we are re-branding DS as EnjineIO for this project.  


If you want a sandbox option for the WebView it would not be hard for us to add a 'Sandbox' option to the WebView control.  Add it to the 'Tell use what you want' thread and it will have more of a chance of getting done.

BTW. The proper way to communicate with the main app from inside a webview is to use the app.Execute() method :)

jjts...@gmail.com

unread,
Jun 29, 2021, 2:47:12 AM6/29/21
to DroidScript
Dear All,
I have finished a session of development of what I mentioned above.
Electron for Windows/Linux/MacOS, Node.js+Express for Web,
and DroidScript for Android.
And I have put it on github here:
https://github.com/jjtseng93/Android-Node.js-Common-Interface
Wish this could inspire and help someone!
Dave 在 2021年6月20日 星期日上午5:58:27 [UTC+8] 的信中寫道:

Alan Hendry

unread,
Jul 2, 2021, 10:47:19 AM7/2/21
to DroidScript
Hi,
Windows 11 will include the ability to run Android Apps.
Apparently it will download apps from the Amazon App Store
(not sure what hoops you have to jump thru to get apps on Amazon App Store).
It would require investigation (would DS run on Win 11, would apps written in DS run?)
Regards, ah

Alan Hendry

unread,
Dec 11, 2021, 4:23:11 PM12/11/21
to DroidScript
HI,
Is there an approximate time scale for enjine.io?
Will it be compatible with javascript and/or HTML apps written in DS?
What about plugins and nodejs?
I presume that enjine.io apps will (largely) run on different platforms 
(AFAIK Android has specific parameter values for intents that may not correspond to IOS). 
Does one subscription cover all platforms?
Will there be a discount for those that have bought DS Lifetime Premium?
Regards, ah

Dave

unread,
Dec 12, 2021, 8:11:08 AM12/12/21
to DroidScript
Hi Alan,

We have no timescale for enjine.io, however some of its features will appear in DS first as that is a good place to prove it works and this will benefit DS users too.

Jumar is working on a WYSIWYG UI editor and a cross platform (HTML based) UI library which will appear in V3 of DS first as a new type of app which we will probably call a 'Hybrid' app. 

The UI parts of this new library will work cross-platform and probably be under the ui.* namespace whereas the existing app.* namespace will have to be partially ported to other platforms as we bring them online.  Enjine.io will be free for hobby users, so you won't need another subscription.

We are hoping to use a new plugin format that will be supported in both DS and enjine.io

If you want a sneak preview of the new 'Hybrid' UI ,then paste the following code into the latest beta version of DS.... but don't tell anyone about this yet as it's top secret ;)

Whooops!

//Configure for Hybrid app.
cfg.Hybrid

//Called after application is started.
function onStart()
{
    mainLay = ui.addLayout(null, "linear")

    apb = ui.addAppBar(mainLay, "My App", "menu", 1)
    apb.setOnMenu(openDrawer)

    apbLay = ui.addLayout(null, "Linear", "Horizontal,Right,NoDom,VCenter")
    apbTextField = ui.addTextField(apbLay, "", "outlined,secondary,small", 0.2)
    apbTextField.setPlaceholder('Search something...')
    apbBadge = ui.addButton(apbLay, "notifications", "icon")
    apbBadge.setTextColor('#ffffff')
    apbBadge.setBadge(9, 'primary')
    apbBtn = ui.addButton(apbLay, "account_circle", "Icon")
    apbBtn.setTextColor('#ffffff')
    apbBtn = ui.addButton(apbLay, "more_vert", "Icon")
    apbBtn.setTextColor('#ffffff')

    apb.addLayout(apbLay)
    
    //Dark/light toggle button
    btnBright = ui.addButton( mainLay, "brightness_5", "icon,primary" )
    btnBright.setOnTouch(btnBright_onTouch)

        // buttons lay
        btnLay = ui.addLayout(mainLay, "linear")
        btnLay.setOptions("Horizontal")
        btnLay.setMargins(0, 0.01, 0, 0)

        btnLay1 = ui.addLayout(btnLay, "Linear", "VCenter", 0.48)

            btn1 = ui.addButton( btnLay1, "Primary", "primary")
            btn1.setOnTouch( function() {
                this.setText('This is another long text')
            } )
            btn1.setFontFile('fonts/ExtraBold.ttf')

            btn2 = ui.addButton( btnLay1, "Secondary", "secondary" )
            btn2.setOnTouch( function() { ui.showPopup( this.margins.top ); Vibrate() })
            
            //Text buttons
            layHoriz = ui.addLayout( btnLay1, "Linear", "Horizontal")
            btn = ui.addButton( layHoriz, "Default", "text")
            btn = ui.addButton( layHoriz, "Primary", "text,primary")
            btn = ui.addButton( layHoriz, "Secondary", "text,secondary" )
          
            //Outlined buttons
            layHoriz = ui.addLayout( btnLay1, "Linear", "Horizontal")
            btn = ui.addButton( layHoriz, "Default", "outlined")
            btn = ui.addButton( layHoriz, "Primary", "outlined,primary")
            btn = ui.addButton( layHoriz, "Secondary", "outlined,secondary")
            
            
            layHoriz = ui.addLayout( btnLay1, "Linear", "Horizontal" )
            btnSmall = ui.addButton( layHoriz, "Small", "small")
            btnMed = ui.addButton( layHoriz, "Medium", "medium" )
            btnLarge = ui.addButton( layHoriz, "Large", "large")
            
            btnUpload = ui.addButton( btnLay1, "Upload", "upload,primary")
            btnUploadIcon = ui.addButton( btnLay1, "photo_camera", "upload,icon,primary" )


    // creates a drawer layout
    var drawerWidth = 0.2
    drawerLay = ui.addLayout(null, "Linear", "VCenter,NoDom", drawerWidth)

    drawer = ui.createDrawer(drawerLay, 'left', "persistent")
    drawer.setOnClose( () => {console.log('Close')})
    drawer.setOnOpen( () => {console.log('onOpen')} )

    lstMenu1 = ui.addList(drawerLay, "Audios::music_note, Videos::movie, Documents::insert_drive_file", "icon", drawerWidth)
    lstMenu1.setOnTouch(closeDrawer)

    div = ui.addDivider(drawerLay, drawerWidth)

    lstMenu2 = ui.addList(drawerLay, "All Mail::mail,Inbox::inbox, Outbox::drafts, Sent::send", "icon", drawerWidth)
    lstMenu2.setOnTouch(closeDrawer)
}

function btg4_onTouch(item, index)
{
    alert(item)
}

function openDrawer()
{
    drawer.open()
}

function closeDrawer(title, body, icon, index)
{
    drawer.close()
    //ui.showPopup(title)
}


//Toggle light/dark theme.
function btnBright_onTouch() 
    if( btnBright.text=="ui." )  
    {
        //btnBright.SetText( "brightness_5" )
        btnBright.text = "brightness_5"
        ui.setTheme( "light" )
    }
    else 
    {
        //btnBright.SetText( "ui." ) 
        btnBright.text = "ui."
        ui.setTheme( "dark" )
    }
}

function Vibrate()
{
    app.Vibrate( "0,100,30,100,50,300" )
}


Alan Hendry

unread,
Jan 9, 2022, 12:12:01 PM1/9/22
to DroidScript
HI,
v. Nice!
In portrait the Drawer is pretty narrow (I changed my copy to 0.8).
There are obvious differences with old DS code (ui not app, initial of methods not capitalized,parameters)
A simple text substitution could convert some existing code
 lay = app.CreateLayout( "Linear", "Vertical" ) becomes lay = ui.addLayout(null, "linear","vertical")
but other code may not be straightforward (for example CreateButton options)
Not sure if it's worth writing 2 sets of functions for upward compatibility 
(in 2 js files, including 1 in your project)
Usage - lay = NewLayout("Linear","Vertical")
Existing - function NewLayout(type,options) {return app.CreateLayout(type,options); }
Hybrid - function NewLayout(type,options) {return ui.addLayout(null,type,options); }
Regards, ah

Alan Hendry

unread,
Jan 9, 2022, 2:00:53 PM1/9/22
to DroidScript
Hi,
In Landscape I can't see the camera icon (at the bottom)
WiFi Debug shows a message
  %cDownload the React DevTools for a better development experience: https://fb.me/react-devtools ...
Not sure if but1 is showing as extra bold (may need ttf)
I Don't see any code invoking - function btg4_onTouch(item, index)
I see a digit 9 as a superscript to the notification icon
Regards, ah

Alan Hendry

unread,
Jan 11, 2022, 8:13:43 AM1/11/22
to DroidScript
HI,

A few more observations ...
The text on the Buttons is always converted to UPPER CASE
I modified to lstMenu1.setOnTouch(btg4_onTouch) and it displays the item :-)
I didn't see the line that sets the badge to 9 
Some options have "icon" and some "Icon" so I presume that the case is corrected at run time
I guess that some differences are due to using a different "engine" -
MUI App Bar has multiple controls and (one) SetControlTouch which receives btntext and index
Hybrid AppBar uses an extra layout which can contain buttons and textfield, with individual callbacks.
app Drawer can have 1 left and 1 right, app.open method specifies Left/Right, one OnDrawer function
Hybrid drawers are defined as left/right, the object is opened/closed, callbacks for open/close per object.
Hybrid option upload seems to open ChooseFile, but what happens next?

https://gineerslife.com/get-mui-post?postId=8 has revised documentation on MUI Controls, for example
MUI.AddButton(parent,text,width,height,options)
I propose a set of functions to be used with MUI that would pass those parameters to MUI
function AddButton(parent, text, width, height, mui_options,hybrid_options){
return MUI.AddButton(parent, text, width, height, mui_options);}
Then to migrate use a set of functions designed for Hybrid
function AddButton(parent, text, width, height, mui_options,hybrid_options){
return ui.addButton(parent, text, hybrid_options);}
As an alternative to passing two sets of options code could transform them, for example
Hybrid button outlined to MUI Button outline
Hybrid small/medium/large into MUI SetFontSize
Hybrid Primary/Secondary to MUI SetTextColor/SetBackColor
A large proportion of my code is Create/Add Layout/Text/Button/List,
Set Size/Backcolor/Textcolor/Textsize/Margins/Padding and Touch/Long/Down
so I reckon a reasonable number of functions would suffice.

Regards, ah

Alan Hendry

unread,
Jan 11, 2022, 6:49:34 PM1/11/22
to DroidScript
HI,
More observations ...
It has mainLay = ui.addLayout(null,"linear") near the start, but no app.AddLayout(mainLay) near the end
I changed the margins on btnLay to 0.1, now I can see it works
AddLayout for btnLay1 has parameter 0.48, presumably a width 
There's ShowPopup(this.margins.top) - not sure how we can read margins on app or MUI objects
Icons seem to be MUI icon names, but List Items are in app format (title::icon)
No idea how to switch between Light and Dark schemes mid-execution in app or MUI.
Layout option NoDom seems new, as does "persistent" for a Drawer
Regards, ah

Alan Hendry

unread,
Jan 14, 2022, 12:41:27 PM1/14/22
to DroidScript
Hi,

(In the below when I say Default I mean that Primary and Secondary are omitted)
I added a button with empty options string, and it displayed a button with white bg, black text.
I also mixed small/medium/large with Default/primary/secondary - they look OK
text with small/medium/large look good
And icon with primary/secondary/Default - changes icon colour
small and medium on icon seem to be ignored, and large on an icon gives an error
if icon is specified then outlined seems to be ignored
I presume that text and icon are mutually exclusive, 

I presume that images will be forthcoming, 
and text boxes (although Buttons with option "text" fulfill a good part of that role)

Regards, ah

Alan Hendry

unread,
Jan 15, 2022, 4:34:47 PM1/15/22
to DroidScript
HI,

The code has
if( btnBright.text=="ui." )
and 
btnBright.text = "ui."
If "brightness_7" is specified then the icon changes.

I note that text can be set as above (thru a property) and thru a method
this.setText('This is another long text')

So far it all seems to work (ui. objects and methods and properties, and using ui. and app. together)

Regards, ah

Alan Hendry

unread,
Jan 16, 2022, 1:39:38 PM1/16/22
to DroidScript
HI,

This is the code that changes the icon and switches the dark/light theme

    btnBright = ui.addButton( layHoriz, "brightness_7", "icon,secondary" )
    btnBright.setOnTouch(btnBright_onTouch)
...
function btnBright_onTouch()  {
    if( btnBright.text=="brightness_5" ) {
        this.setText("brightness_7")
        ui.setTheme( "light" )
    } else {
        this.setText("brightness_5")
        ui.setTheme( "dark" )
    }
}

Regards, ah

Reply all
Reply to author
Forward
This conversation is locked
You cannot reply and perform actions on locked conversations.
0 new messages