Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation since 07/25/2019 in all areas

  1. 5 points
    lynkfs

    console

    I recently revisited the console object, available in all browsers, and discovered some newbies I didn't know about. The methods and properties below may be sometimes useful for debugging purposes. The console object is tied to the global window object, so access either by browserapi.window.console.log('whatever'); or define a reference to the window object : var window external 'window': variant; and call like window.console.dirxml(self); Some console methods are wrapped in SmartCL.System (like writeln ea) and SmartCL.Console The console.dirxml() above gives an xml representation of any object, which is way better than the 'object Object' result of a console.log(some object) instruction For performance testing, console also offers native timers console.time() console.timeLog() console.timeEnd() The above respectively initiate, report and destroy a named timer. The maximum nr of concurrent timers is 10,000 (!) To see how this works I created a stock new visual project with a single form and no visual controls. A timer was inserted at the beginning of the generated js projectfile, at the initialization of the form and at the ApplicationStarting, InitializeForm, InitializeObject and Resize events. Results : console.timeLog top of main.js : 0.0009765625 ms Initialization 10.574951171875 ms applicationstarting 17.234130859375 ms InitializeObject 21.23095703125 ms ReSize 62.385986328125 ms ReSize 101.25 ms InitializeForm 225.994140625 ms ReSize 226.757080078125 ms Wondering about the multiple ReSize calls and the relatively large time lag between InitializeObject and InitializeForm. There is another feature built into browsers re performance : the window.performance object with its own api's The most useful methods of this object are performance.now(), which gives a high res timestamp, and performance.toJSON() which gives a json representation of the attributes of the performance object Below the 'console.timer' and 'performance.now' results of a minimum project with 1 form and no visual controls in the native framework : console.timeLog performance.now() top of main.js : 0.001953125 ms / 118.28000005334616 timestamps Initialization 2.16186523437 ms / 120.43999996967614 InitializeForm 3.61083984375 ms / 121.92000006325543 InitializeObject 4.32080078125 ms / 122.65000003390014 and some values for the attributes of the performance object itself (console.log(window.JSON.stringify(window.performance.toJSON()));) timeOrigin : 1564383720413.3972 timestamps navigationStart: 1564383720413 redirectStart: 0 redirectEnd: 0 fetchStart: 1564383720414 domainLookupStart: 1564383720418 domainLookupEnd: 1564383720418 connectStart: 1564383720418 connectEnd: 1564383720418 secureConnectionStart: 0 requestStart: 1564383720418 responseStart: 1564383720423 responseEnd: 1564383720426 unloadEventStart: 1564383720432 unloadEventEnd: 1564383720432 domLoading: 1564383720435 domInteractive: 0 domContentLoadedEventStart:0 domContentLoadedEventEnd: 0 domComplete: 0 loadEventStart: 0 loadEventEnd: 0
  2. 3 points
    lynkfs

    tensorflow

    edited Been a while since I had a look at Googles Tensorflow deep learning library (js version) In the meantime this library has expanded quite a bit, most notably it enables using pre-built models for a variety of tasks. This one takes any image and detects up to 90 categories of objects in the image (persons, dogs, traffic lights etc) The library correctly identifies 2 objects of type "person" in the above image (image 620*408 pixels, bbox coordinates x,y,width,height) Usage is incredibly simple : load the libraries, display an image in the browser and issue a detect command var Script := document.createElement('script'); Script.src := 'https://cdn.jsdelivr.net/npm/@tensorflow/tfjs'; console.log('init tensorflow'); document.head.appendChild(Script); Script.onload := procedure begin console.log('tensorflow loaded'); var Script := document.createElement('script'); Script.src := 'https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd'; console.log('init coco-ssd'); document.head.appendChild(Script); Script.onload := procedure begin console.log('coco-ssd loaded'); var Image1 := TW3Image.Create(Self); Image1.SetBounds(0, 0, 620, 408); Image1.src := 'puydesancy.jpg'; var img := Image1.handle; asm //quick and dirty : cocoSsd.load().then(model => { // detect objects in the image. model.detect(@img).then(predictions => { console.log('Predictions: ', predictions); }); }); end; end; end; (should have checked for image1.onload). Anyway, demo here. Works from server only due to cors constraints, otherwise results in 'tainted image' errors. edited and another random image
  3. 2 points
    jarto

    Waiting for controls to be ready

    The ReadyExecute uses timeouts and it does an even weaker check than TW3Dispatch.WaitFor. I suppose it'd be a good idea to unify these to use the same methods. I had a little stab at testing MutationObservers. The RTL supports them in SmartCL.Observer.pas When the Observer reports the new control, it is already ready for action, which is nice. However, in my tests the current method we use in the RTL (ReadySync using timeouts) is faster.
  4. 1 point
    lynkfs

    Creating a mobile app for Android and iOS

    This link is from feb 2019 (nasa related), so may work : https://www.jakenherman.com/articles/2019-02/push-notifi-cordova-firebase (there are more links as a result of googling 'cordova push notifications plugin 2019', which may be of relevance)
  5. 1 point
    jarto

    Creating a mobile app for Android and iOS

    I've been having a look at this today. Google Play changed their requirements for generated packages. Seems like Phonegap Build does not yet have an updated push notification plugin - or the old one is not compatible with Cordova 9.0.0, which is required by Google - or the way push notifications are handled in Android these days have changed. These are not specifically problems with Smart Mobile Studio itself as the same issues do happen with any html5-app. I hope I can crack this or that someone else can contribute. On the plus side, push notifications seem to work on phonegap's mobile test client, which is helpful.
  6. 1 point
    jarto

    Creating a mobile app for Android and iOS

    Yes, the push notifications are a great way for alerting users. I'll have a look to see if anything needs to be updated and upload the demo again.
  7. 1 point
    jarto

    Waiting for controls to be ready

    Waiting for controls to be ready for action is an interesting topic, which resurfaces from time to time. It's pretty challenging as there is not one simple right way to handle the problem. Try this little test program. It creates a panel which has three labels unit Form1; interface uses System.Types, System.Types.Convert, System.Objects, System.Time, System.IOUtils, System.Device.Storage, SmartCL.System, SmartCL.Time, SmartCL.Graphics, SmartCL.Components, SmartCL.FileUtils, SmartCL.Device.Storage, SmartCL.Forms, SmartCL.Fonts, SmartCL.Theme, SmartCL.Borders, SmartCL.Application, SmartCL.Controls.Panel, SmartCL.Controls.Label; type TForm1 = class(TW3Form) private {$I 'Form1:intf'} protected procedure InitializeForm; override; procedure InitializeObject; override; procedure Resize; override; end; TTestPanel = class(TW3Panel) protected procedure InitializeObject; override; procedure ObjectReady; override; end; implementation { TForm1 } procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components var Pan:=TTestPanel.Create(Self); WriteLn('Panel created'); Pan.SetBounds(0,0,200,150); WriteLn('Panel SetBounds done -> Creating Label3'); var Lab3:=TW3Label.Create(Self); Lab3.Caption:='Can you see me three?'; Lab3.SetBounds(10,70,150,30); WriteLn('All done'); end; procedure TForm1.InitializeObject; begin inherited; {$I 'Form1:impl'} end; procedure TForm1.Resize; begin inherited; end; { TTestPanel } procedure TTestPanel.InitializeObject; begin inherited; WriteLn('InitializeObject called -> Creating Label'); var Lab:=TW3Label.Create(Self); Lab.Caption:='Can you see me?'; Lab.SetBounds(10,10,150,30); WriteLn('InitializeObject done'); end; procedure TTestPanel.ObjectReady; begin inherited; WriteLn('ObjectReady called -> Creating Label2'); var Lab2:=TW3Label.Create(Self); Lab2.Caption:='Can you see me too?'; Lab2.SetBounds(10,40,150,30); WriteLn('ObjectReady done'); end; initialization Forms.RegisterForm({$I %FILE%}, TForm1); end. When you run this, we get the following debug: InitializeObject called -> Creating Label [line #472] InitializeObject done [line #472] Panel created [line #472] Panel SetBounds done -> Creating Label3 [line #472] All done [line #472] ObjectReady called -> Creating Label2 [line #472] ObjectReady done [line #472] All three labels are created but only two are visible. Fire up DevTools and you'll see that the first label (the one created at InitializeObject) does not have a size - even though we did use SetBounds on it. The reason this happens is inside of SetBounds where the code adjusts left, top, width and height according to the object's margins and parent's padding. The SetBounds happens too early, so the computed styles for the element return NaN as values. Now, there is a simple trick to fix this: Change w3_getPropertyAsInt to return 0 if the value is NaN. I'll surely do that but that won't solve the whole problem. If the styles actually had margins or the parent has padding, we will still move the control into wrong position. Another way to prevent this problem is to not create subcontrols inside InitializeObject and only do that in ObjectReady. And yes, this does work most of the time. However, once you start creating more and more complicated apps, the chance of you accessing or changing a not-initialized element increases. There are some ways to wait. You can actually create that 1st label inside InitializeObject lilke this: procedure TTestPanel.InitializeObject; begin inherited; WriteLn('InitializeObject called -> Creating Label'); var Lab:=TW3Label.Create(Self); TW3Dispatch.WaitFor([Lab], procedure begin WriteLn('Wait done!'); Lab.Caption:='Can you see me?'; Lab.SetBounds(10,10,150,30); end); WriteLn('InitializeObject done'); end; Here we create the Label early but wait for it to be ready before setting the propeties. However, code like this is not pretty, which made me think about various ways of solving this in a more beautiful way. When we've discussed this within the team, we've been thinking about using a Promise or a MutationObserver. But before we get there, lets have a look at when an element is actually ready for action: The code in SetBounds actually does properly check the parent's handle: if (Parent.Handle) then begin var PCSHandle:=TW3CustomBrowserAPI.GetComputedStylesFor(Parent.Handle); if (PCSHandle) then begin LLeft+=w3_getPropertyAsInt(PCSHandle,'paddingLeft'); LTop+=w3_getPropertyAsInt(PCSHandle,'paddingTop'); end; end; However, that does not stop paddingLeft from being returned as NaN for the 1st label. Testing it like this works: if (Parent.Handle) and (Parent.Handle.Ready) then Digging deeper, we'll find that TW3Dispatch.WaitFor checks also the display and visibility of the computed styles. One page I found ( https://browsee.io/blog/puppeteer-how-to-check-visibility-of-an-element/ ) even checks element.boxModel So, the challenge is to find a beautiful and simple way for us to wait for the objects to be ready. And as we need to check more thant just the Handle, I wonder if it's even possible to solve this with a Promise or a MutationObserver.
  8. 1 point
    lynkfs

    bluetooth

    How to connect webapp to a bluetooth enabled printer. Basically there are 2 avenues to do that : a) going native and b) the web bluetooth api Going native This involves using PhoneGap or Cordova, plus installing a plugin to make the bluetooth capacities of the mobile target platform available in the js world. I found this plugin on github, a cordova plugin, so used cordova rather than phonegap. The install sequence for a clean install of everything looks something like see https://cordova.apache.org/docs/en/latest/guide/cli/ install node install npm install cordova : npm install -g cordova install pre-requisites : see https://cordova.apache.org/docs/en/latest/guide/platforms/android/index.html#requirements-and-support java development kit (jdk) gradle android studio / android sdk set environment and path variables JAVA_HOME ANDROID_HOME PATH create app structure create app : cordova create bluetoothprinter com.smartmobilestudio.bluetoothprinter BluetoothPrinter install plugin cordova plugin add https://github.com/srehanuddin/Cordova-Plugin-Bluetooth-Printer.git create remainder of app add platform : cordova platform add android create SMS project copy SMS project output into the cordova app structure (www directory) build app : cordova build android install apk file on android Amazingly this all works out. Some gotcha's : - environment and path variables don't allow spaces, so for instance .../Program Files/... has to be shortened to .../Progra~1/... - cordova now requires plugins to have their own package.json file. The selected plugin doesn't have that, so I had to download the git repository, create a package.json file and install the plugin from local (cordova plugin add cordova-plugin-bluetooth-printer --save --searchpath ../plugin) - the SMS project needs these entries in its template index file <script type="text/javascript" charset="utf-8" src="cordova.js"></script> <script type="text/javascript" charset="utf-8" src="BluetoothPrinter.js"></script> and compile may end up in errors. However the cordova build process takes care of that and produces a viable apk file. It is a bit of a process to go through, but works out well in the end.
  9. 1 point
    lynkfs

    bluetooth

    For this app I used the HOP-H58 bluetooth printer. It comes with bluetooth and usb connectivity, and even a socket for a cash drawer. At an unbeatable price of $26 USD delivered (!), this gives me a mobile POS (invoice print) solution, where only the printer and a mobile phone is needed. Amazing.
  10. 1 point
    lynkfs

    kodi grid

    @lennart posted a reference to a scrollable grid in Delphi Developer. See post here. Since he produced this grid in Smart Pascal, it might be of interest to forum members. This grid basically takes items of irregular dimensions and determines how to best fit those items in rows/columns. The code he posted doesn't work in my (latest) version of Smart, but with a few tweaks here and there I got it going. At least for strings that is. Icons/images are not fully implemented in the source he posted, but I'll take another look. Won't be too difficult. I like the marching ants selection. See demo. kodi := TWbIconView.Create(self); kodi.setbounds(10,10,500,500); //by way of demo : just split any sentence into words and use these as variable length cell items var s : string := #'This grid basically takes items of irregular dimensions and determines how to best fit those items in rows/columns.'; var a : array of string := StrSplit(s,' '); for var i := 0 to a.length-1 do begin kodi.AddText(a[i]); end;
  11. 1 point
    lynkfs

    Combobox items work like "read-only" mode

    don't use the items object : procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components W3ComboBox1.add('Line 1'); W3ComboBox1.add('Line 2'); W3ComboBox1.add('Line 3'); end; procedure TForm1.W3Button1Click(Sender: TObject); begin W3ComboBox1.Clear; end;
  12. 1 point
    jarto

    TryStrToInt bug

    Sorry for taking a long time to answer this. We're working on upgrading the compiler to use the newest DWS. While doing that, I made a quick test. Unfortunately this bug is still there. So we need to dig deeper.
  13. 1 point
    jarto

    Responsive Design

    @lynkfs You can do your first example also by using a div with big margins. That takes care of the outer edges. Inside the div you then add the three controls. Set the height for the header and Align to alTop. Also set the height for the footer and Align to alBottom. Last, set Align to alClient for the middle panel.
  14. 1 point
    lynkfs

    Waiting for controls to be ready

    To make this work using MutationObservers I would probably do something like this: demo, project Essentially the TestPanel is put here under the surveillance of a MutationObserver, which triggers when all changes to the panel have been applied (including the original sizing). After that it is ready to accept the label etc. procedure TTestPanel.InitializeObject; begin inherited; WriteLn('InitializeObject called -> Creating Label'); self.observe; self.handle.addEventListener('readytogo', procedure(e:variant) begin writeln('heard readytogo'); var Lab:=TW3Label.Create(Self); Lab.Caption:='Can you see me?'; Lab.SetBounds(10,10,150,30); WriteLn('InitializeObject done'); end); end; The code in this demo works, but is a bit ugly. It would be better to include the observe method standard in a constructor, put it in the TControlHandle rather than the TPanel, rewrite the eventlistener similar to the standard ReadyExecute method etc. But hey, demo. As a matter of fact, using the standard ReadyExecute method instead of MutationObservers works here as well. I think the latter is a bit better though as observers don't rely on timeouts and a single observer does handle multiple changes. /* self.Handle.ReadyExecute(procedure() begin var Lab:=TW3Label.Create(Self); Lab.Caption:='Can you see me?'; Lab.SetBounds(10,10,150,30); WriteLn('InitializeObject done'); end); */ Maybe the rtl could be made to handle all child inserts in this manner
  15. 1 point
    Daniel Eiszele

    Learning Smart Mobile Studio

    I would also suggest Jon Lennart Aasenden's blog, https://jonlennartaasenden.wordpress.com/news/ as invaluable for understanding the Smart Mobile studio paradigm. His blog is not solely about Smart Mobile Studio but putting them in as search terms should return a wealth of knowledge on the subject.
  16. 1 point
    lynkfs

    Learning Smart Mobile Studio

    Look at Primož Gabrijelčič's book on SMS, available on https://leanpub.com/asmartbook Very valuable and I still consult it on a regular basis There is some info on http://www.pp4s.co.uk/main/smart-gettingstarted.html as well
  17. 1 point
    jarto

    Creating a mobile app for Android and iOS

    After writing that, I noticed that newer versions of iTunes do not install ipa-packages any more. To get around that, there are some ways: https://codeburst.io/latest-itunes-12-7-removed-the-apps-option-how-to-install-ipa-on-the-device-3c7d4a2bc788 I myself decided to use an older version of iTunes, that you can download from that page. That let me install the PhonegapTest.ipa, which I created in Phonegap build. And guess what? The app was installed in my iPad It started and initialized Phonegap properly I clicked on "Init push notifications", which registered itself properly and returned a Token What did not work: Saving the token as the plugin I had used for selecting the folder is strictly Android only However, there are many other plugins that you can use and there's no problem defining different plugins for Android and iOS in the config.xml -file. But basically, your Smart Mobile Studio app is now ready to receive push notifications on both Android and iOS.
×