Jump to content

jarto

Administrators
  • Content Count

    568
  • Joined

  • Last visited

  • Days Won

    94

Everything posted by jarto

  1. This topic will go through all the steps that it takes to make a real mobile application for Android and iOS with Smart Mobile Studio. This first post gives some background while later I'll go deeper into details with proper examples. I've done this before three years ago. At that point I had to do a few hacks to work around problems. My plan is to make this as easy as possible in SMS and to fix any bugs that may pop up. To make proper applications for the Android and iOS app stores, we will be using Adobe's Phonegap. It's a service that can be used to turn a html5 application to a package that you can submit to the Android or iOS store. Phonegap's free plan will most likely be enough for you: Phonegap plans You can also install Cordova, which Phonegap actuallty is, on your own computer. If someone has done it, please feel free to contribute. However, when I did develop my own app three years ago, Phonegap worked beautifully. So, to get that Phonegap account, sign up to the free plan. Once you've logged in, you can choose between an open-source app or a private app. Phonegap lets you use existing Git repositorys, but I'll be using a zip -file. Now, how do you do that zip file? As an example: Start Smart Mobile Studio Open the Tabs, Scrolling and Listbox -demo from Featured Demos Build Go to the www -folder in File explorer Select all files inside the www-folder and zip them
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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.
  8. jarto

    Waiting for controls to be ready

    I've used a test case where I create a panel which creates a about a thousand labels/checkboxes/divs inside itself, sets captions and resizes them. It gives the browser quite a lot of work to do.
  9. 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.
  10. 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.
  11. jarto

    Bugs and Features 3.1.0.88

    This is weird. I was able to reproduce this once, but most often it does comment both lines.
  12. jarto

    Bugs and Features 3.1.0.88

    @tristan The development-channel has now an update, which fixes the bugs in TW3TabControl
  13. jarto

    Development updates

    New update available: IDE: Zip Entire Project did not include Form .sfm -files RTL: Bug fixes to TW3TabControl
  14. The Development-channel in SmartUpdate contains all the latest changes in Smart Mobile Studio. It's a good channel to follow for those who want all the new features and bug fixes right away, instead of waiting for the next formal release. To follow the Development-channel: Make a new folder and add: SmartUpdate.exe Your own user.lic from your current Smart Mobile Studio folder. To get all the latest changes in the Development-channel: Run: SmartUpdate /changechannel /showhidden When asked for which channel to follow, choose Development The purpose of this topic is to inform about all the new features and fixes.
  15. jarto

    Getting user's input from input box

    A simple solution is Prompt, like @Daniel Eiszelewrote: var Answer:=Prompt('Question'); WriteLn(Answer); If you want a more beautiful solution, then you can make a form for the input and show it modally. That way you can control everything.
  16. jarto

    Bugs and Features 3.1.0.88

    Thank you. Now I can reproduce the problem. Gonna have a look.
  17. jarto

    Bugs and Features 3.1.0.88

    Thank you bvery much for reporting these. TabForms.zip does not contain the form sfm-files, so I can't test that bug right away. Can you manyally zip the folder so all files are included?
  18. jarto

    TW3StringGrid is available

    Thank you @tristan and @IElite Yeah, creating new culumn types is really as simple as generating the right html. Especially with images. With images you probably don't even have to override SetColumnEvents. It's mainly used with controls where the used can change the cell value, like Edit, Combo and Boolean.
  19. A new update is available in the development-channel of SmartUpdate. It contains a completely new Grid: TW3StringGrid. It's a completely new design, which was made to be very fast and able to handle lots of data. This is achieved through dynamic drawing: Only the visible grid lines are rendered. There is a new StringGrid-demo in the Featured Demos. It downloads a json file and populates the grid with data from it. TW3StringGrid supports six different column types: Text (column class TW3StringGridTextColumn) Numeric (column class TW3StringGridNumericColumn) EditBox (column class TW3StringGridEditColumn) ComboBox (column class TW3StringGridComboColumn) Checkmark (column class TW3StringGridCheckmarkColumn) Button (column class TW3StringGridButtonColumn) Columns are created by calling: MyNewColumn:=Grid.AddColumn(ColumnClass); If no ColumnClass is given, a Text column is created. Column properties: Caption Width BorderType Default is btLightBorderRight. Set to btNone if you don't want any vertical borders. Backgroundtype Default is btNone to let the line color through. AlignText (The same way as in TW3Label) taLeft (default) taCenter taRight SelectOptions (for TW3StringGridComboColumn only) This is an array of selectable values. First value (index 0) is the value for no selection. For example: SelectOptions:=['','First','Second','Third']; RowBorderType: Default is btLightBorderBottom. Set to btNone if you don't want any horizontal borders. RowBackgroundType: Default is bsListItemBackground. Set to bsDecorativeListItemBackground (or test other backgrounds) to change the background style for even rows. RowOddBorderType: Default is btLightBorderBottom. Set to btNone if you don't want any horizontal borders. Affects odd rows. RowOddBackgroundType: Default is bsListItemBackground. Set to bsDecorativeListItemBackground (or test other backgrounds) to change the background style for odd rows. Grid properties: RowCount: Set number of rows to show FixedColumns: How many columns should be fixed (aka not scrollable horizontally) LineHeight MultiSelect Events: OnCellClick: Is triggered when the row is clicked. OnCellChanged: Is triggered when cell content changes through editing (for example: through editing) OnDrawGridLineTheme: Can be used to set custom backgrounds and borders for a row. (for example, set background to bsErrorBackground for lines that should be highlighted to the user) Methods: InvalidateGrid: Triggers a repaint of the grid. Sort Sorting TW3StringGrid supports sorting based on one of multiple columns. Clicking on the column headers sets or reverses sort order. You can also control sorting in code: procedure AddSortColumn(Index: Integer; SortOrder: TW3SortOrder = soNormal); overload; procedure AddSortColumn(Col: TW3StringGridColumn; SortOrder: TW3SortOrder = soNormal); overload; procedure SetSortColumn(Index: Integer; SortOrder: TW3SortOrder = soNormal); overload; procedure SetSortColumn(Col: TW3StringGridColumn; SortOrder: TW3SortOrder = soNormal); overload; procedure ToggleSortColumn(Index: Integer); For example: Grid.SortOptions.AddSortColumn(3,soReverse); //Set primary sort column Grid.SortOptions.AddSortColumn(1); //Add secondary sort columns Grid.Sort; Working with sorted data When the Grid is sorted, it only affects how data is shown. Sorting does not change Grid data itself at all. When you work with a sorted grid events and indexes (for example SelectedIndex) always refer to the index in the grid data itself and NOT the visible line number. TW3StringGrid uses these events: TW3StringGridColumnEvent = procedure(const Sender: TW3StringGridColumn; const Row: Integer); TW3StringGridEvent = procedure(const Sender: TObject; const Row, Col: Integer); If you have a Grid where "Australia" is on line 2, SelectedIndex:=2 selects that row regardless of how the grid is sorted. Clicking on that row or changing data on that row also returns Row=2 regardless of how the grid is sorted.
  20. jarto

    Issue with DEVELOPMENT-branch (was BETA) building APP

    @Tim Koscielski Here's my best guess about what is going on: I assume you have added the Grid in the Designer. That means that the Grid control is created in Form.InitializeObject here: {$I 'Form_ProjectMasterListN:impl'} The compiler generates the code to create the grid and set its properties. After that you call InitGrid. Now, when a control is created in JavaScript, the browser initializes it asynchronously. This means that your code continues to run but it takes some time before the control is actually ready. It may be that on your computer it takes so long that the Grid's handle is not ready when you start accessing it. In the latest development update I changed the code that is created for that impl section. When earlier the control was just created and properties were set, now the generated code waits for the object to be ready. Only after that it starts setting properties. It eliminates random problems. To be sure that the Grid is ready, you can call InitGrid like this: TW3Dispatch.WaitFor([W3Grid1], procedure begin InitGrid; end); That's the same way the code generated by the IDE does it.
  21. jarto

    Development updates

    New update is available in the development-channel: IDE: Anchors (and other sets) can be set in the Object Inspector Improvements to generated Form implementation code: Wait until created components are ready before setting properties and creating children Set Anchors last Prevent conflicting keyboard shortcuts from being saved Use better default project options (no manifests, do not embed Javascript) Add new units to units defaults and improve formatting RTL: Add xml-js to Libraries. New ECMA.Promise unit from api docs System.JSON: Support for adding/setting JSON arrays Add TJSONObject.Delete Set form size to 100% before calling InitializeObject Add missing units to SmartCL.Controls Setting control's angle did not work in Firefox Don't raise an exception while freeing a form which is not registered Themes: default styles were not applied for all elements in Android and iOS Fixes a bug where textarea's size is too big in TW3Memo Note, that while the anchors can be set in the Object Inspector, it does not result in visible changes in the Visual Designer.
  22. jarto

    TW3StringGrid is available

    Use SelectedIndex to set or read the index. The grid does not use ContentSelectionMode.
  23. jarto

    Getting user's input from input box

    This is new for me. Looks like the InputBox is from DWS. When the code is compiled and run, you can see in the source that InputBox is called but absolutely nothing happens - not even an error. Very weird.
  24. jarto

    Node.js API in a Visual Components Project

    I don't think you can use NodeJS api in a Visual Components Project.
  25. jarto

    Building an application

    @IElite already posted a link to my tutorial. If the problem you have is only to get the apk to your phone, I usually just connect my phone to my laptop via a usb cable and copy the apk to a folder. Then I start the file manager app in the Android phone, go to that folder, locate the apk and install it.
×