Jump to content

All Activity

This stream auto-updates     

  1. Yesterday
  2. My most significant challenge, I find, is making a webpage/app properly responsive. The tlayout is not inuitiove and has weird side effects. Will the new designer make it easier to create responsive programs? Also, side thought, the css is pretty extensive but also difficult and resistant to reskinning for a different look/feel.
  3. Hi all, as you have probably noticed, we've been a bit quiet lately. That's because we've been hard at work on exciting new changes and features to Smart Mobile Studio. I'd like to share with you, what we're doing to the Visual Designer. We're rewriting the Visual Designer from scratch. This new one is completely WYSIWYG as it's actually a Smart Mobile Studio app itself, running inside the IDE in Embedded Chrome. This lets us accurately show what components look like, instead of the dull old boxes in the old designer. You can set Align, Anchors, Angle and any other property and they are accurately reflected in the component in the Designer - like the blue panel (Align Top) or the rotated List box. The new designer also lets us support non-visual components, which will add a number of new components into our component palette. TW3Timer was the first one to be added and it already works just like in Delphi. We'll also be able to expand the concept into a full featured Multi Device Designer, so you could design forms for multiple devices, multiple screen sizes and multiple themes. The Designer also has support for Wizards and Component specific designers, so you'll be able to design popup menus in a Menu Designer and all the tabs in the Tab Control.
  4. jarto

    Expired Licence ????

    Good to hear that you received the new license. I did answer you on Zendesk yesterday. I wonder if the answer went to your spam folder?
  5. Last week
  6. Alistair

    Expired Licence ????

    Updated Licence just received - Thanks
  7. Alistair

    Expired Licence ????

    I now get an error saying my licence has expired and the software will not run. Quote from your 'Store': All licenses include one year of first class support. After that period the software will continue to work, but we don’t give support and it won’t be possible to install further updates. What is going on? It would also appear that Zendesk isnt working either as my email logged via zendesk appears to have fallen into a black hole
  8. jarto

    Development updates

    New update available in the development-channel: RTL: Improvements to TW3ScrollBox: AutoUpdate-property. If true, the scrollbox monitors changes in child components and updates itself automatically. ForceParent-property. If true, child components are automatically moved to the Content-component. Bug fixes to ToggleSwitch: Did not work properly on Firefox Value of Checked-property changed only after the animation was completed Parent can now be changed, so components can be moved to different parents just like in Delphi Align: If multiple components have same alignment, decide order based on component coordinates Change w3_getPropertyAsInt to return 0 if value is NaN as NaN messes up any calculations using that value SmartCL.Effects: Animations like fxMove did not work in Firefox The changes to TW3ScrollBox lets you now use the ScrollBox also in the Visual Designer.
  9. jarto

    toggle switch in Firefox browser not working

    Thank you @kockas This is now fixed in the Development-channel. There were a few problems: The animation code did not work in Firefox The value of checked was changed only in the end of the animation. Now it changes before the animation.
  10. It seems the good looking toggle switch component not working with the firefox desktop versions. Chrome, Opera, Brave no problem and even the Firefox Android also ok, just the desktop Firefox(32 and 64 bit version also, windows/Linux same wrong result). Probably inside the component the "checked:=not(checked)" procedure happening to fast. //anyway with this additional code the toggle switch component give a little bit better user experience procedure TForm1.W3ToggleSwitch1Click(Sender: TObject); begin W3ToggleSwitch1.checked:=not(W3ToggleSwitch1.checked) end;
  11. Earlier
  12. lynkfs

    HTML programming

    A bit of a weird topic name for a product which elevates Object Pascal using javascript. I could have named it 'Web Components' (as I did a while ago) or maybe better 'Api Programming'. There are a number of organisations which look after the web api's. W3C is the most known one, but there are others looking after specific parts (WhatWG, Khronos etc.). What they have in common is that they publish the web api's they're looking after in a specific formal format (WebIDL). Smart has transformed these specifications in corresponding pascal classes, contained in the APIs directory in the RTL. These classes basically map directly onto functions and data available in the browser itself, and using them is sort of similar to for instance incorporating Microsoft Office functions in a Delphi program (although technically very different from using COM). The RTL uses some of these api's under the hood, this post is about a mini-rtl if you like consisting of just 1 component. I use this approach a lot for non-form based projects, single-page-apps (or multiple) and websites. Demo of a semi-static SPA The inheritance chain of the DOM looks like - EventTarget - Node - Element - HTMLElement with all the various html elements underneath : HTMLDivElement for a <div>, HTMLAnchorElement for a <a> etc. The code below wraps the HTMLElement, but allows its constructor to create any of the specialised sub-elements. unit JElement; interface uses W3C.HTML5, W3C.DOM, W3C.CSS; type THTMLElement = class private FHTMLElement: JHTMLElement; public constructor Create(element: String; parent: THTMLElement; className: String; innerHTML : String); end; implementation { THTMLElement } constructor THTMLElement.Create(element: String; parent: THTMLElement; className: String; innerHTML : String); begin // cache element and set innerHTML and className FHTMLElement := JHTMLElement(Document.createElement(element)); FHTMLElement.innerHTML := innerHTML; FHTMLElement.className := ClassName; If parent = nil then document.body.appendChild(FHTMLElement) else parent.FHTMLElement.appendchild(FHTMLElement); end; HTMLElements have as specifiers 'attributes' and 'properties'. Properties are any of the values in the 'style' attribute : in the html expression style="left=10px; color=white;" href="#" both 'left' and 'color' are properties, and both 'style' and 'href' are attributes. So we need to add the setters for these parameters : Procedure THTMLElement.SetProperty(s1: String; S2: String); begin var FElementStyle := JElementCSSInlineStyle(FHTMLElement).style; FElementStyle.setProperty(S1, S2); end; Procedure THTMLElement.SetAttribute(S1: String; S2: String); begin FHTMLElement.setAttribute(S1, S2); end; The first part of the demo app is an image, which fills the complete viewport on any device and orientation, a slightly darker tinted bar on top, and a button in the bar linking to an email form further down. This header can be constructed as per below : unit JHeader; interface uses JHTMLElement, smartcl.system; type THeader = class(THTMLElement) public constructor Create(props: Variant); end; implementation { THeader } constructor THeader.Create(props: Variant); begin //hero image var hdr0 := THTMLElement.Create('div', nil, 'div'); hdr0.setProperty('width', '100%'); hdr0.setProperty('height', '100%'); hdr0.setProperty('min-height', '100vh'); hdr0.setProperty('background-image','url('+props['header-img']+')'); hdr0.setProperty('background-size','cover'); //top bar 100px var hdr11 := THTMLElement.Create('div', hdr0, 'div'); hdr11.setProperty('width', '100%'); hdr11.setProperty('height', '100px'); hdr11.setProperty('background-color','rgb(21,21,21,0.2)'); //contact button var hdr21 := THTMLElement.Create('a', hdr11, 'div', 'Contact'); hdr21.SetBounds(20,30,75,35); hdr21.setProperty('color', 'white'); hdr21.SetAttribute('type', 'button'); hdr21.setAttribute('href', '#contact'); hdr21.SetProperty('background-color', 'rgb(21,21,21,0.2)'); which can be instantiated as in (with a variable for the image) //THeader props['header-img'] := 'assets/img/blueprint.jpg'; THeader.Create(props); and which on execution time resolves in <div class="div" style="width: 100%; height: 100%; min-height: 100vh; background-image: url(http://127.0.0.1:8090/assets/img/blueprint.jpg); background-size: cover;"> <div class="div" style="width: 100%; height: 100px;"> <a class="div" type="button" href="#contact" style="visibility: visible; display: inline-block; position: absolute; overflow: auto; left: 20px; top: 30px; width: 75px; height: 35px; color: white;"> Contact </a> </div> </div> Hence the title of this post : HTML programming. The advantage of this approach is that once there are a number of these multi-purpose constructs like THeader available, making up another webpage is as easy as providing values for constructor parameters and stringing them together. At some stage I created the constructs listed here They need to be updated and streamlined a bit.
  13. lynkfs

    Expand Combobox using code

    Basically the <select> element where the combobox is based on, is under control of the browser. And can't be manipulated from pascal/js. There is a hack (there is a hack for everything) to fake it : procedure TForm1.InitializeForm; begin inherited; // this is a good place to initialize components var W3ComboBox1 : Tw3ComboBox := TW3ComboBox.Create(self); W3ComboBox1.SetBounds(50,70,250,30); W3ComboBox1.Add('line 1'); W3ComboBox1.Add('line 2'); W3ComboBox1.Add('line 3'); W3ComboBox1.handle.style['opacity'] := 0; var W3Panel1 : TW3Panel := TW3Panel.Create(self); W3Panel1.SetBounds(50,70,250,30); W3Panel1.handle.style['z-index'] := 0; W3Panel1.handle.setAttribute('class',''); //get rid of all styling var W3Button1 : TW3Button := TW3Button.Create(W3Panel1); W3Button1.Caption := 'MyButton'; W3Button1.SetBounds(0,0,250,30); W3ComboBox1.OnChanged := procedure (Sender: TObject) begin W3Button1.Caption := W3ComboBox1.Items[W3ComboBox1.SelectedIndex]; end; end; works on Chrome and other browsers. Works on mobile too Demo Wouldn't recommend it though .... edited : as per @IElite suggestion: it would also be possible to make the combobox invisible, read its items on the click of a button and display them in a listbox or memo. Better, in my opinion and if really necessary, is to create a dedicated control which does exactly what you want, based on a listbox rather than on a <select> htmlelement
  14. IElite

    Expand Combobox using code

    @jarto Is it possible to fake it with a window displaying the items from the combobox ?
  15. jarto

    Expand Combobox using code

    Looks like this is not possible in javascript.
  16. COMFIED

    Expand Combobox using code

    Hi Is there a way to trigger a combobox to expand and show the list without clicking on it - by using code under another visual component like a button?
  17. Took some time, but I was able to create a test apk and install it on my phone. First of all, set up your folders the way I did in https://forums.smartmobilestudio.com/topic/4524-creating-a-mobile-app-for-android-and-ios/?do=findComment&comment=22461 That will let you have one folder for all the Phonegap-related stuff and another folder for your SMS app. Here's my config.xml, which should be in the phonegap-project's folder: <?xml version='1.0' encoding='utf-8'?> <widget id="com.smartmobilestudio.phonegaptest" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:gap="http://phonegap.com/ns/1.0"> <name>PhonegapTest</name> <description> Push sample application that receives push notifications. </description> <author email="youremail@example.com" href="https://www.smartmobilestudio.com"> Smart Mobile Studio </author> <preference name="phonegap-version" value="cli-9.0.0" /> <preference name="android-minSdkVersion" value="19" /> <preference name="android-targetSdkVersion" value="28" /> <content src="index.html" /> <preference name="DisallowOverscroll" value="true" /> <preference name="StatusBarOverlaysWebView" value="false" /> <preference name="StatusBarBackgroundColor" value="#ee6e73" /> <preference name="StatusBarStyle" value="blacktranslucent" /> <plugin name="com.ourcodeworld.plugins.Filebrowser" spec="https://github.com/ourcodeworld/cordova-ourcodeworld-filebrowser.git" /> <plugin name="cordova-plugin-geolocation" /> <plugin name="cordova-plugin-device" /> <plugin name="cordova-plugin-vibration" /> <plugin name="cordova-plugin-file" /> <plugin name="cordova-plugin-statusbar" source="npm" /> <plugin name="phonegap-plugin-push" source="npm" spec="~2.2.3" /> <plugin name="cordova-plugin-console" source="npm" /> <plugin name="cordova-plugin-dialogs" source="npm" /> <plugin name="cordova-plugin-whitelist" source="npm" /> <platform name="android"> <resource-file src="google-services.json" target="app/google-services.json" /> </platform> <platform name="android"> <icon density="ldpi" src="www/res/icon/android/drawable-ldpi-icon.png" /> <icon density="mdpi" src="www/res/icon/android/drawable-mdpi-icon.png" /> <icon density="hdpi" src="www/res/icon/android/drawable-hdpi-icon.png" /> <icon density="xhdpi" src="www/res/icon/android/drawable-xhdpi-icon.png" /> <icon density="xxhdpi" src="www/res/icon/android/drawable-xxhdpi-icon.png" /> <icon density="xxxhdpi" src="www/res/icon/android/drawable-xxxhdpi-icon.png" /> <splash density="land-ldpi" src="www/res/screen/android/drawable-land-ldpi-screen.png" /> <splash density="land-mdpi" src="www/res/screen/android/drawable-land-mdpi-screen.png" /> <splash density="land-hdpi" src="www/res/screen/android/drawable-land-hdpi-screen.png" /> <splash density="land-xhdpi" src="www/res/screen/android/drawable-land-xhdpi-screen.png" /> <splash density="land-xxhdpi" src="www/res/screen/android/drawable-land-xxhdpi-screen.png" /> <splash density="land-xxxhdpi" src="www/res/screen/android/drawable-land-xxxhdpi-screen.png" /> <splash density="port-ldpi" src="www/res/screen/android/drawable-port-ldpi-screen.png" /> <splash density="port-mdpi" src="www/res/screen/android/drawable-port-mdpi-screen.png" /> <splash density="port-hdpi" src="www/res/screen/android/drawable-port-hdpi-screen.png" /> <splash density="port-xhdpi" src="www/res/screen/android/drawable-port-xhdpi-screen.png" /> <splash density="port-xxhdpi" src="www/res/screen/android/drawable-port-xxhdpi-screen.png" /> <splash density="port-xxxhdpi" src="www/res/screen/android/drawable-port-xxxhdpi-screen.png" /> </platform> <platform name="ios"> <icon height="57" platform="ios" src="www/res/icon/ios/icon.png" width="57" /> <icon height="114" platform="ios" src="www/res/icon/ios/icon@2x.png" width="114" /> <icon height="40" platform="ios" src="www/res/icon/ios/icon-40.png" width="40" /> <icon height="80" platform="ios" src="www/res/icon/ios/icon-40@2x.png" width="80" /> <icon height="50" platform="ios" src="www/res/icon/ios/icon-50.png" width="50" /> <icon height="100" platform="ios" src="www/res/icon/ios/icon-50@2x.png" width="100" /> <icon height="60" platform="ios" src="www/res/icon/ios/icon-60.png" width="60" /> <icon height="120" platform="ios" src="www/res/icon/ios/icon-60@2x.png" width="120" /> <icon height="180" platform="ios" src="www/res/icon/ios/icon-60@3x.png" width="180" /> <icon height="72" platform="ios" src="www/res/icon/ios/icon-72.png" width="72" /> <icon height="144" platform="ios" src="www/res/icon/ios/icon-72@2x.png" width="144" /> <icon height="76" platform="ios" src="www/res/icon/ios/icon-76.png" width="76" /> <icon height="152" platform="ios" src="www/res/icon/ios/icon-76@2x.png" width="152" /> <icon height="29" platform="ios" src="www/res/icon/ios/icon-small.png" width="29" /> <icon height="58" platform="ios" src="www/res/icon/ios/icon-small@2x.png" width="58" /> <icon height="87" platform="ios" src="www/res/icon/ios/icon-small@3x.png" width="87" /> <splash height="1136" platform="ios" src="www/res/screen/ios/Default-568h@2x~iphone.png" width="640" /> <splash height="1334" platform="ios" src="www/res/screen/ios/Default-667h.png" width="750" /> <splash height="2208" platform="ios" src="www/res/screen/ios/Default-736h.png" width="1242" /> <splash height="1242" platform="ios" src="www/res/screen/ios/Default-Landscape-736h.png" width="2208" /> <splash height="1536" platform="ios" src="www/res/screen/ios/Default-Landscape@2x~ipad.png" width="2048" /> <splash height="768" platform="ios" src="www/res/screen/ios/Default-Landscape~ipad.png" width="1024" /> <splash height="2048" platform="ios" src="www/res/screen/ios/Default-Portrait@2x~ipad.png" width="1536" /> <splash height="1024" platform="ios" src="www/res/screen/ios/Default-Portrait~ipad.png" width="768" /> <splash height="960" platform="ios" src="www/res/screen/ios/Default@2x~iphone.png" width="640" /> <splash height="480" platform="ios" src="www/res/screen/ios/Default~iphone.png" width="320" /> </platform> <platform name="wp8"> <icon height="99" platform="wp8" src="www/res/icon/wp8/ApplicationIcon.png" width="99" /> <icon height="159" platform="wp8" src="www/res/icon/wp8/Background.png" width="159" /> <splash height="1280" platform="wp8" src="www/res/screen/wp8/screen-portrait.jpg" width="768" /> </platform> <platform name="windows"> <icon height="150" platform="windows" src="www/res/icon/windows/Square150x150Logo.scale-100.png" width="150" /> <icon height="30" platform="windows" src="www/res/icon/windows/Square30x30Logo.scale-100.png" width="30" /> <icon height="50" platform="windows" src="www/res/icon/windows/StoreLogo.scale-100.png" width="50" /> <splash height="300" platform="windows" src="www/res/screen/windows/SplashScreen.scale-100.png" width="620" /> <icon height="120" platform="windows" src="www/res/icon/windows/StoreLogo.scale-240.png" width="120" /> <icon height="44" platform="windows" src="www/res/icon/windows/Square44x44Logo.scale-100.png" width="44" /> <icon height="106" platform="windows" src="www/res/icon/windows/Square44x44Logo.scale-240.png" width="106" /> <icon height="70" platform="windows" src="www/res/icon/windows/Square70x70Logo.scale-100.png" width="70" /> <icon height="71" platform="windows" src="www/res/icon/windows/Square71x71Logo.scale-100.png" width="71" /> <icon height="170" platform="windows" src="www/res/icon/windows/Square71x71Logo.scale-240.png" width="170" /> <icon height="360" platform="windows" src="www/res/icon/windows/Square150x150Logo.scale-240.png" width="360" /> <icon height="310" platform="windows" src="www/res/icon/windows/Square310x310Logo.scale-100.png" width="310" /> <icon height="150" platform="windows" src="www/res/icon/windows/Wide310x150Logo.scale-100.png" width="310" /> <icon height="360" platform="windows" src="www/res/icon/windows/Wide310x150Logo.scale-240.png" width="744" /> <splash height="1920" platform="windows" src="www/res/screen/windows/SplashScreenPhone.scale-240.png" width="1152" /> </platform> <access origin="*" /> <allow-intent href="http://*/*" /> <allow-intent href="https://*/*" /> <allow-intent href="tel:*" /> <allow-intent href="sms:*" /> <allow-intent href="mailto:*" /> <allow-intent href="geo:*" /> <platform name="android"> <allow-intent href="market:*" /> </platform> <platform name="ios"> <allow-intent href="itms:*" /> <allow-intent href="itms-apps:*" /> </platform> </widget> You also have to register your app with FCM using the advice in the link that @lynkfsjust provided. Then download the google-services.json file and save it in the folder where your config.xml is. Lastly, when you are installing the apk on your phone, you may need to disable Play Protect in the Play Store. Here's the source code I'm currently using for testing. Note, that the parts that use the file dialogs is not pretty at all. You can simply ignore those parts and the FileBrowser-plugin when you make your own implementation. unit Form1; interface uses System.Types, System.Types.Convert, System.Objects, System.Time, System.json, SmartCL.System, SmartCL.Time, SmartCL.Graphics, SmartCL.Components, SmartCL.FileUtils, SmartCL.Forms, SmartCL.Fonts, SmartCL.Theme, SmartCL.Borders, SmartCL.Application, SmartCL.Controls.Button, SmartCL.Controls.Label, SmartCL.Controls.EditBox, PhoneGapApi, SmartCL.Controls.Memo, SmartCL.Controls.Image, System.Device.Storage, SmartCL.Device.Storage, System.IOUtils, System.Streams, System.Writer, SmartCL.Dialogs, SmartCL.Geolocation; type TForm1 = class(TW3Form) private {$I 'Form1:intf'} procedure AddToLog(const Value: String); procedure FileDialogError(data: Variant); procedure InitPushNotifications(Sender: TObject); procedure PhoneGapReady; procedure PushInitialized(data: Variant); procedure PushReceived(data: Variant); procedure PushError(data: Variant); procedure OpenSaveDialog(Sender: TObject); procedure SavePushToken(NewFileName: String); protected procedure InitializeForm; override; procedure InitializeObject; override; procedure Resize; override; end; implementation uses PGStripe; { TForm1 } procedure TForm1.AddToLog(const Value: String); begin LogMemo.Add(Value+#13#10); end; procedure TForm1.InitPushNotifications(Sender: TObject); begin var Id := SenderId.Text; PhoneGap.InitPushNotifications(Id, @PushInitialized, @PushReceived, @PushError); end; procedure TForm1.InitializeForm; begin inherited; AddToLog('Waiting for deviceready in PhoneGap'); SenderId.Enabled := False; InitPush.Enabled := False; SaveToken.Enabled := False; PhoneGap.OnReady(PhoneGapReady); end; procedure TForm1.InitializeObject; begin inherited; {$I 'Form1:impl'} end; procedure TForm1.PhoneGapReady; begin LogMemo.Clear; AddToLog('uuid: '+PhoneGap.Device.uuid); AddToLog('version: '+PhoneGap.Device.version); AddToLog('model: '+PhoneGap.Device.model); AddToLog('manufacturer: '+PhoneGap.Device.manufacturer); AddToLog('platform: '+PhoneGap.Device.platform); AddToLog('cordova: '+PhoneGap.Device.cordova); AddToLog('serial: '+PhoneGap.Device.serial); //Where are we? var GL:=TW3GeoLocation.Create; GL.OnPosition:=procedure (Sender: TObject; Position: TW3Position) begin AddToLog(''); AddToLog('Got position!'); AddToLog(' Time: '+FormatDateTime('dd.mm.yyyy hh:nn:ss.zzz',Position.Timestamp)); AddToLog(' Lat: '+Variant(Position.Coords.Latitude)); AddToLog(' Lng: '+Variant(Position.Coords.Longitude)); AddToLog(' Alt: '+Variant(Position.Coords.Altitude)); AddToLog(' Acc: '+Variant(Position.Coords.Accuracy)); AddToLog(' AltAcc: '+Variant(Position.Coords.AltitudeAccuracy)); AddToLog(' Head: '+Variant(Position.Coords.Heading)); AddToLog(' Speed: '+Variant(Position.Coords.Speed)); AddToLog(''); end; GL.OnPositionError:=procedure (Sender: TObject; Msg: TW3PositionError) begin AddToLog('Got an error'); AddToLog('Message: '+Msg.ErrorMessage); end; GL.QueryCurrentPosition; SenderId.Enabled := True; InitPush.Enabled := True; InitPush.OnClick := @InitPushNotifications; PhoneGap.Notification.vibrate(1000); end; procedure TForm1.PushInitialized(data: Variant); begin AddToLog('Push init ok'); AddToLog('Token: '+PhoneGap.RegistrationId); SenderId.Enabled := False; InitPush.Enabled := False; SaveToken.Enabled := True; SaveToken.OnClick := @OpenSaveDialog; end; procedure TForm1.PushReceived(data: Variant); begin AddToLog('Push: '+data.message); end; procedure TForm1.PushError(data: Variant); begin AddToLog('Push error: '+data.message); end; procedure TForm1.OpenSaveDialog(Sender: TObject); // Uses https://github.com/ourcodeworld/cordova-ourcodeworld-filebrowser procedure DoSave(data: Variant); begin SavePushToken(data); end; begin asm window.OurCodeWorld.Filebrowser.createFileDialog({ success: function(data) { @DoSave(data); }, error: function(data) { @FileDialogError(data); } }); end; end; procedure TForm1.FileDialogError(data: Variant); begin AddToLog("Error calling createFileDialog: "+data.message); end; procedure TForm1.SavePushToken(NewFileName: String); var NewFilePath: String; procedure fail(err: Variant); begin AddToLog('Error saving push notification token'); end; procedure FileWriterCreated(FileWriter: Variant); begin var TokenToWrite := PhoneGap.RegistrationId; asm FileWriter.onerror = @fail; FileWriter.write(@TokenToWrite); end; end; procedure FileCreated(fileEntry: Variant); begin AddToLog('File created'); asm fileEntry.createWriter(@FileWriterCreated); end; end; procedure onDirectorySuccess(dirEntry: Variant); begin AddToLog('Got directory access'); asm dirEntry.getFile(NewFileName, {create: true, exclusive: false}, @FileCreated, @fail); end; end; begin AddToLog('Saving push notification token'); //Split NewFileName to path and file for var a:=Length(NewFileName) downto 1 do if NewFileName[a]='/' then begin NewFilePath := copy(NewFileName,1,a); NewFileName := copy(NewFileName,a+1,Length(NewFileName)); break; end; asm window.resolveLocalFileSystemURL(@NewFilePath, @onDirectorySuccess); end; end; procedure TForm1.Resize; begin var h:=ClientHeight; if h=0 then exit; var w:=ClientWidth; SaveToken.SetBounds(0,h-40,w,40); dec(h,40); InitPush.SetBounds(0,h-40,w,40); dec(h,40); SenderId.SetBounds(0,h-32,w,32); dec(h,32); LogMemo.SetBounds(0,0,w,h); inherited; end; initialization Forms.RegisterForm({$I %FILE%}, TForm1); end.
  18. 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)
  19. 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.
  20. 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.
  21. HI, I am keen make an app for our tutors to manage their shifts. The push notification system would seem to be an ideal solution for alerting tutors that their shift-roster is available or changes have been made. However, the demos above are no longer available. This is an area I have zero experience in so an example demo or other helpful information would be super helpful.
  22. jarto

    Waiting for controls to be ready

    Sure, but this does not force any existing code to be changed. Anyone creating controls by code can continue to use any method. This new method I'm working on is mainly for code that the compiler generates and adds to the form's InitializeForm -section.
  23. lynkfs

    Waiting for controls to be ready

    could the 'readyexecute' method be repurposed so that code changes to existing projects could be avoided ?
  24. jarto

    Waiting for controls to be ready

    Time to make a small update here. The aim I have here is to make it as easy as possible to wait properly and to make this a standard way of creating components and setting properties. When we have that, we can improve the Visual Designer tremendously. Here's my latest suggestion: Pan:=TW3Panel.Create(Self); Pan.OnObjectReady:=lambda Pan.SetBounds(10,500,200,200); //... and any other properties Lab:=TW3Label.Create(Pan); Lab.OnObjectReady:=lambda Lab.SetBounds(10,10,150,30); Lab.Caption:='Hello world!'; //... and any other properties end; end; The idea is to always use that OnObjectReady to initialize controls. Especially in code that the compiler generates for visual components. Looks pretty clean and neat to me.
  25. 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.
  26. 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.
  27. 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;
  28. kockas

    Combobox items work like "read-only" mode

    Thanks!! // those damn delphis habits ...
  1. Load more activity
×