Image may be NSFW. Clik here to view.Developer Luxophia on Github released an implementation of the TriFlip model available for Delphi Berlin and FireMonkey. The Torus is an OBJ file and the texture is a BMP file. The demo is for Win32 and Win64 but it works on Android, IOS, and Mac OSX with some changes. There is some inline assembly code that can be commented out and some other changes to make it multi device ready. The TriFlip model is actually a data structure that holds the information about the triangular faces of each polygon adjacent to each other. This feature allows the model to perform Euler operations (cut or combine polygons). In solid modeling and computer-aided design, the Euler operators modify the graph of connections to add or remove details of a mesh while preserving its topology. The boundary representation for a solid object, its surface, is a polygon mesh of vertices, edges and faces. It’s topology is captured by the graph of the connections between faces. A given mesh may actually contain multiple unconnected shells (or bodies); each body may be partitioned into multiple connected components each defined by their edge loop boundary. To represent a hollow object, the inside and outside surfaces are separate shells. In Geometry, Euler operators modify the mesh’s graph creating or removing faces, edges and vertices according to simple rules while preserving the overall topology thus maintaining a valid boundary (i.e. not introducing holes). The TriFlip model implementation is provided as a demo for you to try out in FireMonkey under Delphi 10 Berlin.
Image may be NSFW. Clik here to view.Developer David Nottage proposes a slick solution to background fetches on iOS, by decoupling the method calling the completion handler from the actual background fetching code. Background fetches were introduced in iOS 7 and can be used to fetch small amounts of data for a limited time (30 seconds) when the application is in background (i.e. to check if the user has new mail messages). In order for applications to be enabled for background fetch, the “fetch” option needs to be checked in the UIBackgroundModes key in the Version Info section in the project options. The method that handles the background fetching, on iOS, is called performFetchWithCompletionHandler. In FireMonkey, there is no such method, however you can add missing methods to the application delegate, using the Objective-C runtime function class_addmethod.
class procedure TPlatformBackgroundFetch.performFetchWithCompletionHandler(self: id; _cmd: SEL; application: PUIApplication;
completionHandler: id);
var
LResult: TBackgroundFetchResult;
LPlatformResult: NSUInteger;
begin
if FFetch <> nil then
begin
// Assume no data
LResult := TBackgroundFetchResult.NoData;
// Call the handler if assigned
FFetch.DoFetch(LResult);
LPlatformResult := BackgroundFetchResultToPlatform(LResult);
// The completion handler *must* be called, if the app is continue to receive background fetch messages
CallBlockImplementation(self, _cmd, completionHandler, LPlatformResult);
end;
end;
You can also set the fetch interval with setMinimumBackgroundFetchInterval, however you should not that the maximum time amount is 30 seconds.
procedure TPlatformBackgroundFetch.UpdateFetchInterval;
begin
SharedApplication.setMinimumBackgroundFetchInterval(CocoaDoubleConst(libUIKit, 'UIApplicationBackgroundFetchIntervalMinimum'));
end;
The demo project implements the background fetch as a platform service (makes use of TPlatformServices), it sets the OnFetch handler, and you have to provide an implementation for it.
Image may be NSFW. Clik here to view.Developer Luxophia on Github developed a powerful library, MyMaterial, that works with Direct 3D and lets you create your own material and apply them to 3D objects in Delphi 10 Berlin with FireMonkey. Normally in FireMonkey in order to give a texture, such as colors and patterns to 3D components, TColorMaterialSource, TTextureMaterialSource and TLightMaterialSource are used but if you require more complex material you have to create your own. At the core of MyMaterial library stand: TShaderSource, TShaderVar which are used in TMaterial. The TShaderVar contains information about the color, vertex, light, shader of the material. One thing to remember is that Direct3D uses HLSL (High-Level Shader Language or High-Level Shading Language), a proprietary shading language used to describe the shader. MyMaterial library translated the HLSL into TShaderSource and TShaderVar, thus you are no longer required to describe each shader variable, it will do this automatically. You can even load the shader from an external file (text file).
TMyMaterialSource is the component that puts the textures on top of the 3D components. MyMaterial library is available for Delphi 10 Berlin with FireMonkey and it looks to be open source. Demos are available for you to test its features. For those developers who want to study the source code, it is available on Github. With MyMaterial libray you can easily create your own custom textures and effects and apply them to the components you create.
Image may be NSFW. Clik here to view.Developer TMS Software released their amazing framework code-named Aurelius, an ORM (Object Relational Mapping) now available for FireMonkey and Delphi 10 Berlin. This powerful framework lets you easily integrate database in your applications. It supports several database servers (MS SQL Server, Firebird, MySQL, DB2, Interbase, Oracle and many other) and several database-access components (dbExpress, AnyDac, SQLDirect, ADO, IBX and many others). You are no longer required to test your complex SQL statements at run-time, since we are now dealing with entity objects in an object-oriented way. When writing queries, Aurelius provides a robust query API using criteria expressions, projections, grouping, conditions and even logical operators in a LINQ-like approach. You also benefit from the OOP concepts and you can make use of inheritance mapping and polymorphism – map a full class hierarchy into the database. At the core of the framework lies TaureliusDataSet, which can be easily integrated with the existing DB-aware controls in VCL, thus making this framework independent of the database engine and components you use as a developer, and you can write the same code to manage multiple databases in a transparent way. Aurelius framework is a multi platform solution – available on Windows 32/64, macOS, iOS and Android. As a developer, you can choose from the free version (only available for Delphi Berlin) and the paid version which is available for older versions of Delphi and you have access to source code and also gives you fast support from the TMS team.
Image may be NSFW. Clik here to view.Delphi with the FireMonkey framework is a great tool to quickly build REST clients. I wanted to build out a Delphi project to go along with the Christmas holiday and I came up with a project where I combined the REST Client in Delphi with the Open Movie Database REST API to display Christmas movies. There is a blog post of the whole build over on the Embarcadero Community site which explains it in detail. The FireMonkey client should run on Android, IOS, MacOSX, and Windows. Source code for the full project is up on GitHub for free. In the project there are some good concepts explored like: downloading an image from a URL and displaying it, using FireMonkey premium styles to theme out the app, dynamically displaying image content and paging through it, dynamically configuring the display of content based on the device, deploying the TTabControl as a view controller, using TFrame to visually build out a re-usable component, utilizing the low code LiveBindings to display a lot of content quickly, and automatically importing JSON from the REST API to a TFDMemTable. You should be able to use these same concepts in C++Builder as well. If you are looking to consume your own REST API with Delphi be sure to read the full blog post and check out the source as there are some nice pointers in there on what worked for me.
Image may be NSFW. Clik here to view.SWIG is a tool which will automatically (mostly) create an interface for a C and C++ project for a variety of other programming languages. It does this by translating the C/C++ headers into the target language and sometimes by creating a wrapper library around the original library to make interfacing easier. Historically Delphi was not one of the languages supported in SWIG. There was an effort made a few years ago which got a working version of SWIG 2.0 for Delphi but the latest version of SWIG is 3.0. That older version is available over on BitBucket. I had a developer over on UpWork put quite a bit of time into adding support for Delphi into SWIG 3.0 and that code is now available on Github. The Delphi support in not 100% as of yet but it is workable and greatly simplifies the process of making C and C++ libraries available to your Delphi code. At the moment you may have to do some fix it work on the generated code after running SWIG on the header files. Feel free to submit fixes back to the GitHub repo and/or report any problems with creating interfaces you may find so everyone can benefit from an improved tool. SWIG is pretty complex so it is not for the faint of heart but if you need access to serious C and C++ libraries from Delphi it is a good place to start. You can find out more information about SWIG over on their website. You will need to create a SWIG interface file like the below in order to process a C or C++ header file with SWIG. You can also customize the interface file for any manual translation of objects or code that needs to take place for the specific library you are running SWIG against.
Example libGIF interface file for SWIG:
/* File : gif_lib.i */
%module gif_lib
%{
#include "gif_lib.h"
#include "gif_hash.h"
#include "gif_lib_private.h"
%}
/* Let's just grab the original header file here */
%include "gif_lib.h"
%include "gif_hash.h"
%include "gif_lib_private.h"
Image may be NSFW. Clik here to view.Calculating fields together with LiveBindings in Delphi FireMonkey can be a good low code alternative to writing a bunch of code to do the same. LiveBindings makes it relatively easy to add fields together using it’s CustomFormat property. LiveBindings supports a wide variety of operations in the CustomFormat property can you can check out more information about that in the Embarcadero DocWiki. There is a demo with this post that shows how to add three fields together and output the result to a fourth field. You should be able to use the demo cross platform on Android, IOS, OSX, and Windows. The demo uses components from the TMS FMX UI component set but the components are probably not required if you implemented these ideas in your own app. There is a TFDMemTable in the project with 4 fields called FieldEdit1, FieldEdit2, FieldEdit3, and FieldEdit4. The four fields are bound with LiveBindings to 4 edit controls called Edit1, Edit2, Edit3, and Edit4. You can also see the contents of the TFDMemTable in the featured TTMSFMXLiveGrid. Entering number values into any of the Edit1, Edit2, and Edit3 controls will add those 3 values together and give you a final value in the Edit4 control. You can see that when you add values into the Edit1, Edit2, and Edit3 controls that the value is automatically updated in the TFDMemTable. Finally, pressing the included Save button will store the calculated value from the fourth Edit4 control into the TFDMemTable as well. In the calculation demo the LinkControlToField1.CustomFormat property is set as the following:
Note: Self.Owner.FieldEdit1, Self.Owner.FieldEdit2, Self.Owner.FieldEdit3
are the names of the fields in the TFDMemTable.
The reason it uses the IfThen() function is to keep any conversion errors from happening. If it’s blank use zero otherwise use the field value. The TTMSFMXEdit is setup to only allow number characters.
I put together a small Delphi FireMonkey project called UnitResolver which allows you to enter a class, function, or procedure name and then does a search via Google Custom Search to see if it can predict what Unit that class/function/procedure is in so that you can add it to the Uses clause of your current Unit. The Delphi IDE has a built in function that does this to a certain extent if you select some text and press CTRL-SHIFT-A but for the most part I have never found it to give very good results. In the UnitResolver project I have Google Custom Search set up so that it only searches docwiki.embarcadero.com (you can try this yourself in the regular Google search by adding site:docwiki.embarcadero.com to the end of your search). I have the Google Custom Search results piped through a PHP page on FMXExpress.com so keep my Google API key secure. I used the REST Debugger to automatically consume the JSON from Google Custom Search and load it into a TFDMemTable automatically. Lastly, I use the Levenshtein distance algorithm (which is a fuzzy matching solution) to try and predict which of the results is closest to the correct unit. Feel free to test it out and see how well it does finding units for classes, functions, and procedures in the Delphi RTL.
Image may be NSFW. Clik here to view.Embarcadero has released a Hospitality Survey App template for Delphi 10.2 Tokyo through their GetIt platform. The Hospitality Survey App consists of four different projects. A client app built with FireMonkey for Android, IOS, OSX, and Windows where users can fill out survey information. A web app built with AngularJS for viewing survey stats. A REST server built with RAD Server for Windows and Linux. And a setup app which is used to configure the whole system. You can customize the questions during the setup process but not afterward. What is missing from these four projects is a way to edit the dynamic form questions on the server after you deploy the template to production. I have created a Hospitality Survey Editor app which will connect to your existing Hospitality Survey database and allow you to customize the questions which are asked in the client. The questions are stored in a table in the database and then downloaded to the client as JSON through RAD Server. The Hospitality Survey Client app loads the JSON and then dynamically creates the input fields using TFrames. The Hospitality Survey Editor app was created by stripping down the Hospitality Survey Setup app and connecting it directly to the Hospitality Survey database. Here is a list of the dynamic fields that you can customize in this new editor:
ID – An ID for the question. You should increment the number of the ID for each new question you add.
name – A short name for the question with no spaces.
title – The text of the question as it will appear in the survey.
type – The type of question controls which question template is loaded on the client. The existing types are: rating, yesno, edit, options
options – If the type of the question is set to options this field is used to populate the options. It’s value is a JSON array of options.
value – The value is where the user submitted data is stored. It can be left blank but could be used to provide a default answer.
category – The category of the question. This field is provided for expandability.
tenant_id – The tenant ID of the question. If the tenant_id field is blank all tenants will get the question. If it is set to a tenant only that tenant will get the question.
Image may be NSFW. Clik here to view.Embarcadero has four mobile arcade game projects for Delphi in Object Pascal available for free over on GitHub. All of the projects run on Android, IOS, OSX, and Windows. One of the projects is called Space Rocks and I modified this project to allow the player to customize the game at runtime (for more info about Space Rocks check out this blog post). The modified game is called Deep Space Rocks. I also re-skinned the game a but with a new background, player character, and enemy characters. The new Customize Game functionality that I added to the project allows you to modified the following settings at runtime: Player Image, Enemy Image, Asteroid1 Image, Asteroid2 Image, Asteroid3 Image, Powerup Image, Background Image, Player Health, Collect Item Duration, Collect Item Speed, Rock Speed, Enemy Proj Speed, Enemy Speed, Player Proj Speed, Player Fire Speed, Player Rotation Speed, Player Speed, and Player Lives. This allows the player to tweak the settings and play it how they want to play it. It also allows you to easily play test and tweak the game yourself to get the best settings. Allowing players to customize your game like this can increase player retention of your game. The player customize-able settings could also be expanded to include more settings like the sound and music. Full source code is provided for this modified version of the game.
Image may be NSFW. Clik here to view.The Hospitality Survey App template that Embarcadero has released for Delphi 10.2 Tokyo through their GetIt platform is quite extensive. I have put together a developer guide video for the project which explains more in depth. The video explains each of the four different projects that make up the Hospitality Survey App. These projects include:
A client app built with FireMonkey for Android, IOS, OSX, and Windows where users can fill out survey information.
A web app built with AngularJS for viewing survey stats. There is a second version of the web app built in Sencha which will also be available.
Image may be NSFW. Clik here to view.The Hospitality Survey Client project is part of the Hospitality Survey App template for Delphi 10.2 Tokyo that Embarcadero has released through their GetIt platform. The Hospitality Survey App consists of four different projects. In this blog post I will cover the progress/activity dialog TFrame that is built into the Hospitality Survey Client project.
The progress/activity functionality is built as a TFrame and then included in the Main Form and set to Align := Contents. Align := Contents means that it ignores all of the other aligned elements and just fills it’s parent container (which in this case is the Main Form). Inside of the TFrame there is a semi-transparent background rectangle to cover the entire interface under the TFrame and then there is a TCircle in the center of the TFrame. Inside of the TCircle is a second smaller TCircle and a TArc component.
The TArc component has a 90 degree arc which fills in the space between the two circle (see the diagram). A TFloatAnimation component on the TArc allows it’s RotationAngle property to animation and the end result is that the TArc spins around in between the two TCircles creating a nice looking progress/activity dialog. You can see on the TFloatAnimation component that the StartValue is 0 and the StopValue is 360.
Throughout the app where it needs to show a “working” dialog and disable the user interface it calls ShowActivity (see below) before starting the long operation and then when the long operation is complete it calls HideActivity.
procedure TMainForm.ShowActivity;
begin
MultiView.Enabled := False;
ProgressFrame.ShowActivity;
end;
procedure TMainForm.HideActivity;
begin
ProgressFrame.HideActivity;
MultiView.Enabled := True;
end;
Inside the TProgressFrame these two functions Show and Hide the TFrame and enable/disable the animation.
procedure TProgressFrame.ShowActivity;
begin
Self.Visible := True;
ProgFloatAnimation.Enabled := True;
end;
procedure TProgressFrame.HideActivity;
begin
ProgFloatAnimation.Enabled := False;
Self.Visible := False;
end;
And that’s all there is to it. There is no other code to write. This responsive progress/activity dialog should work across Android, iOS, macOS, and Windows.
Image may be NSFW. Clik here to view.The Hospitality Survey Client project is part of the Hospitality Survey App template for Delphi 10.2.1 Tokyo that Embarcadero has released through their GetIt platform. The Hospitality Survey App consists of four different projects. In this blog post I will cover the dynamic form generator that is built into the Hospitality Survey Client project. Also keep in mind that the client can be deployed to Android, iOS, macOS, and Windows with a single code base and a single responsive UI.
Basically how it works is on the server there is a database table which contains the list of survey questions to be asked to patrons from each tenant (in this case restaurant). The /survey/ end point in RAD Server is called from TBackendEndpoint (which is basically a TRESTClient) in the Survey App Client. The RAD Server end point returns the contents of the Questions table as the FireDAC JSON format. You can customize the questions using the Hospitality Survey Editor. The Client saves out the FireDAC JSON to a surveys.json file which is then loaded into an TFDMemTable. The GenerateSurvey() function (see below) loops through the records in the TFDMemTable and creates a TFrame for each record. Each record corresponds to a question in the database and you can see the different fields in a record below:
ID – An ID for the question.
name – A short name for the question with no spaces.
title – The text of the question as it will appear in the survey.
type – The type of question controls which question template is loaded on the client. The existing types are: rating, yesno, edit, options
options – If the type of the question is set to options this field is used to populate the options. It’s value is a JSON array of options.
value – The value is where the user submitted data is stored. It can be left blank but could be used to provide a default answer.
category – The category of the question. This field is provided for expandability.
tenant_id – The tenant ID of the question. If the tenant_id field is blank all tenants will get the question. If it is set to a tenant only that tenant will get the question.
The Type column determines which TFrame is loaded for that record. The built in types are: rating, yesno, edit, options. You can add your own row types as well by modifying the GenerateSurvey() procedure. You can see the units below for each of the dynamic TFrames including a header frame and a complete button frame for submitting the form.
uSurveyHeaderFrame.pas – Contains the header for the top of the survey.
uRatingBarFrame.pas – Contains the star rating track bar survey question type.
uYesNoFrame.pas – Contains the Yes/No survey question type.
uEditFrame.pas – Contains the edit survey question type.
uComboBoxFrame.pas – Contains the combo box survey question type.
uCompleteFrame.pas – Contains the complete button for the survey.
The GenerateSurvey() procedure itself is pretty simple. It loops through the TFDMemTable dataset and checks the type field to see which TFrame to load and populate for that record. The options field is a JSON array that is used to populate the values for the yesno type and options type. The ID field is used to mark the TFrame with the specific question it was created from (FrameItem.Tag := BindSourceDBForm.DataSet.FieldByName(‘ID’).AsInteger;) so that the value field can be filled out with the answer from the user.
//
procedure TMainForm.GenerateSurvey(Sender: TObject);
var
FrameItem: TFrame;
FieldType: String;
FieldCategory: Integer;
JSONArray: TJSONArray;
I: Integer;
begin
FrameItem := TSurveyHeaderFrame.Create(TFMXObject(Sender));
FrameItem.Parent := TFMXObject(Sender);
FrameItem.Name := 'FSurveyHeader';
FrameItem.Align := TAlignLayout.Top;
FrameItem.Position.Y := 0;
BindSourceDBForm.DataSet.First;
while not BindSourceDBForm.DataSet.Eof do
begin
FieldCategory := BindSourceDBForm.DataSet.FieldByName('category').AsInteger;
FieldType := BindSourceDBForm.DataSet.FieldByName('type').AsString;
if FieldType = 'edit' then
begin
FrameItem := TEditFrame.Create(TFMXObject(Sender));
FrameItem.Parent := TFMXObject(Sender);
TEditFrame(FrameItem).QuestionText.Text :=
BindSourceDBForm.DataSet.FieldByName('title').AsString;
end;
if FieldType = 'yesno' then
begin
FrameItem := TYesNoFrame.Create(TFMXObject(Sender));
FrameItem.Parent := TFMXObject(Sender);
TYesNoFrame(FrameItem).QuestionText.Text := BindSourceDBForm.DataSet.FieldByName('title').AsString;
JSONArray := TJSONObject.ParseJSONValue(BindSourceDBForm.DataSet.FieldByName('options').AsString) as TJSONArray;
for I := 0 to JSONArray.Count - 1 do
begin
case I of
0:
begin
TYesNoFrame(FrameItem).ValueSpeedButton1.Text := JSONArray.Items[I].Value;
TYesNoFrame(FrameItem).ValueSpeedButton1.GroupName := BindSourceDBForm.DataSet.FieldByName('name').AsString;
end;
1:
begin
TYesNoFrame(FrameItem).ValueSpeedButton2.Text := JSONArray.Items[I].Value;
TYesNoFrame(FrameItem).ValueSpeedButton2.GroupName := BindSourceDBForm.DataSet.FieldByName('name').AsString;
end;
end;
end;
JSONArray.Free;
end;
if FieldType = 'rating' then
begin
FrameItem := TRatingBarFrame.Create(TFMXObject(Sender));
FrameItem.Parent := TFMXObject(Sender);
TRatingBarFrame(FrameItem).QuestionText.Text := BindSourceDBForm.DataSet.FieldByName('title').AsString;
end;
if FieldType = 'options' then
begin
FrameItem := TOptionsFrame.Create(TFMXObject(Sender));
FrameItem.Parent := TFMXObject(Sender);
TOptionsFrame(FrameItem).QuestionText.Text := BindSourceDBForm.DataSet.FieldByName('title').AsString;
JSONArray := TJSONObject.ParseJSONValue(BindSourceDBForm.DataSet.FieldByName('options').AsString) as TJSONArray;
TOptionsFrame(FrameItem).ValueComboBox.Items.BeginUpdate;
for I := 0 to JSONArray.Count - 1 do
begin
TOptionsFrame(FrameItem).ValueComboBox.Items.Add(JSONArray.Items[I].Value);
end;
TOptionsFrame(FrameItem).ValueComboBox.Items.EndUpdate;
JSONArray.Free;
end;
FrameItem.Name := 'F' + BindSourceDBForm.DataSet.FieldByName('ID').AsString;
FrameItem.Align := TAlignLayout.Top;
FrameItem.Tag := BindSourceDBForm.DataSet.FieldByName('ID').AsInteger;
FrameItem.Position.Y := BindSourceDBForm.DataSet.FieldByName('ID').AsInteger * 100;
BindSourceDBForm.DataSet.Next;
Application.ProcessMessages;
end;
FrameItem := TCompleteFrame.Create(TFMXObject(Sender));
FrameItem.Parent := TFMXObject(Sender);
FrameItem.Name := 'FComplete';
FrameItem.Align := TAlignLayout.Top;
FrameItem.Position.Y := 1000000;
TCompleteFrame(FrameItem).CompleteButton.OnClick := CompleteClick;
end;
The selected option in each TFrame gets sent back to the TFDMemTable via the UpdateValueByID() procedure as you can see below. In the below code the Self.Tag field corresponds to the ID field of the question.
//
procedure TOptionsFrame.ValueComboBoxChange(Sender: TObject);
begin
MainForm.UpdateValueByID(Self.Tag,ValueComboBox.Items[ValueComboBox.ItemIndex]);
end;
The UpdateValueByID() procedure uses the Locate() procedure on the DataSet to find the correct record and then update the value field.
//
procedure TMainForm.UpdateValueByID(ID: Integer; const Value: string);
begin
if BindSourceDBForm.DataSet.Locate('ID', VarArrayOf([ID]), []) = True then
begin
BindSourceDBForm.DataSet.Edit;
BindSourceDBForm.DataSet.FieldByName('value').AsString := Value;
BindSourceDBForm.DataSet.Post;
end;
end;
Once the survey has been completed by the user then the entire contents of the TFDMemTable are saved out to the FireDAC JSON format and uploaded back to the server via a POST from a TBackendEndpoint component to the /survey/complete endpoint. In the case of the Hospitality Survey App all of the uploaded records are saved for each collected survey. This allows the survey questions to be created, removed, and changed without affecting any of the existing surveys that have already been collected.
Image may be NSFW. Clik here to view.The Hospitality Survey Client project is part of the Hospitality Survey App template for Delphi 10.2.1 Tokyo that Embarcadero has released through their GetIt platform. The Hospitality Survey App consists of four different projects plus a Survey Question Editor. And now there is a sixth project I am releasing for the Hospitality Survey App which is a Hospitality Survey Admin Client built in Delphi 10.2 Tokyo. The original business stats dashboard included with the Hospitality Survey App is built in AngularJS but I wanted to also build this same dashboard in Delphi.
I based the Hospitality Survey Admin Client off of the Hospitality Survey Client source code and just modified it a bit. The original client only downloaded the survey questions and then uploaded the results. I modified the client so that it downloads the admin business stats, a CSV file of the email addresses for the users who filled out the survey, the list of completed surveys, and the details of each individual survey. I only needed to add 4 new REST API calls to do this. The code to dynamically generate the client survey form was modified to display the survey results dynamically. The relevant new API calls in the Admin Client are listed below:
GET /survey/results/* – Download the survey results in a paged fashion in FireDAC JSON format. The page number is placed where the * is.
GET /survey/stats/all – Download various stats about the survey results in FireDAC JSON format.
GET /survey/details/* – Download the questions and answers from a specific survey ID in FireDAC JSON format. The survey ID is placed where the * is.
GET /survey/emails/csv – Download a list of all of the email addresses from completed surveys in CSV format.
The JSON that is returned is already in FireDAC JSON format (from RAD Server) so it can be easily loaded into a TFDMemTable. The stats dashboard itself uses various FireMonkey objects to display some of the stats and it also uses TeeChart Lite which comes with Delphi 10.2 Tokyo to display the 3 charts. I tried to achieve the same look in feel of the dashboard in the Admin Client as the original AngularJS admin client. Here is the code below to load up the stats into the business dashboard. As you can see TeeChart Lite is pretty easy to use and the charts work across Android, IOS, OSX, and Windows with a single codebase and single UI. What is not visible in the code for TeeChart Lite is that the first Series chart has to be created by right clicking the chart component and selecting Edit Chart… and then choosing the Add… button to create the first chart Series. Once you create the first chart and select the chart type you can then start adding data to the chart via code.
Delphi 10.2 Tokyo has a build in project statistics package which shows you where you are using your time in the IDE when you are developing a project. Below is a screenshot of the time it could to modify the Hospitality Survey Client and turn it into the Hospitality Survey Admin Client. There was some extra debugging time needed to work out some display issues with TeeChart Lite on Android but other than that it was a pretty fast build.
Finally, here is a screenshot (see below) of the Delphi 10.2 Tokyo Hospitality Survey Admin Client which uses FireMonkey styling and TeeChart Lite for the business stats dashboard.
Image may be NSFW. Clik here to view.One thing that can really add polish to your application is setting it up so that when an edit field receives focus it automatically appears above the keyboard on mobile devices. If this is not done the keyboard can sometimes cover the edit field so you are unable to see what you are typing. There are a number of different ways to do this in Delphi 10.2 Tokyo (and previous versions). We’ve written about this before can you can check out those posts here and here. There is also an example from Embarcadero called FMX.ScrollableForm on how to do this. The ScrollableForm example works well and I have used it in the past. However, in Delphi 10.2 Tokyo and Delphi 10.2.1 Tokyo it does not work quite right on Android. Developer Dave Nottage has come up with a solution to this problem and provided some source code to fix it. First you need his free library from GitHub called Kastri Free. Next he posted some code to use with the library to make it all happen. Here is the code snippet:
//
//
// Include System.Messaging in the uses clause
type
TForm1 = class(TForm)
private
procedure VirtualKeyboardRectChangeMessageHandler(const Sender: TObject; const M: TMessage);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
...
uses
DW.Messaging, DW.VirtualKeyboard.Helpers;
constructor TForm1.Create(AOwner: TComponent);
begin
inherited;
TMessageManager.DefaultManager.SubscribeToMessage(TVirtualKeyboardRectChangeMessage,
VirtualKeyboardRectChangeMessageHandler);
end;
destructor TForm1.Destroy;
begin
TMessageManager.DefaultManager.Unsubscribe(TVirtualKeyboardRectChangeMessage,
VirtualKeyboardRectChangeMessageHandler);
inherited;
end;
procedure TForm1.VirtualKeyboardRectChangeMessageHandler(const Sender: TObject; const M: TMessage);
var
LRect: TRect;
begin
LRect := TVirtualKeyboardRectChangeMessage(M).Value;
// LRect now contains the actual rect of the VK
end;
The full source code is available in a forum thread on the Embarcadero Forums site. You can head over there and see the full thread. The source code is mainly for Android but probably also works on IOS. I would assume it is not meant for Windows, OSX, or Linux. The Kastri Free library also has a lot of other functionality you can check out as well.
Image may be NSFW. Clik here to view.Developer zhaoyipeng has released a massive set of free custom FireMonkey components for Delphi 10.2 Tokyo over on GitHub. It would appear that most of this components support one or more of the FireMonkey platforms which are Android, IOS, OSX, and Windows (plus Linux unofficially through FMXLinux). The components look like they are available for free with source code from Github. Additionally, there are a number of demos plus screenshots showing the usage of the components. The current components are:
TFMXQRCode is a wrapper around the ZXing QRCode port to Delphi for generating QRCode images.
TFMXToast is a control that allows you to pop Android Toast style messages in FireMonkey apps.
TFMXSeg7Shape is a component for what appears to be displaying displaying LED style numbers.
There is a BaiduMap SDK wrapper for Firemonkey which looks useful for using the BaiduMap SDK in your Delphi apps.
TFMXCalendarControl is a custom calendar component in the IOS style for choosing dates on a calendar.
TFMXGuesturePassword is a keypad style control that takes gestures to generate a pin number like an unlock code.
TFMXSimpleBBCodeText is a simple control which looks like it formst BBCode text (which includes text colors) for display.
TFMXImageSlider is an easy to use image slider which can hold a group of images and allow you to slide between them.
TFMXCircleScoreIndicator is a circular progress indicator component that contains a number label in the center.
TFMXRatingBar is a custom control that allows you to set a star rating (as in a 5 star display).
TFMXScrollableList is a scrollable list component that looks similar to have the IOS date time or calendar picker works.
TFMXLoadingIndicator looks like a fantastic loading indicator library with a variety of loading animations.
graphics32 is a FireMonkey (and I assume cross platform) version of the popular graphics32 library for Delphi.
TFMXCallout is an upgraded version of TCallout that uses the INativeCanvas to draw with smooth lines.
INativeCanvas is a custom helper class for TCanvas which gives you smooth lines across platforms.
TFMXRotatingText is a rotating text component similar to a the rolls on a slot machine.
Image may be NSFW. Clik here to view.If you are looking to build cross platform apps in FireMonkey for languages that read right to left (also known as bi-directional or BiDi support) there are a number of different solutions. One of those solutions is the FMXRTL library which I assume stands for FireMonkey Right To Left (verses RunTime Library). FMXRTL has a version for Delphi 10.2 Tokyo and Delphi 10.1 Berlin. Apparently part of how it works is there is a TFMXRTL component which changes some core objects in FireMonkey that handle text presentation. These changes cause BiDi support to trickle down to all of your existing FireMonkey controls. It doesn’t mention which platforms are explicitly supported by FMXRTL but I would assume Android, IOS, OSX, and Windows are probably supported. At the moment it appears that the FMXRTL package is free but also appears to be in beta or at least experimental. You may have to just download it and check it out for yourself to see if it can solve your BiDi needs. Some other BiDi solutions include using the Delphi HTML Component Library as your presentation layer or using TurboCocoa for your presentation layer (which allows you to use Xcode and Android Studio to build your interface).
Image may be NSFW. Clik here to view.A Startup Weekend competition was held in Southern California where teams competed to build a startup in 54 hours. I participated on one of the teams and built this app prototype using Delphi FireMonkey. Our team won first place in the competition. We had about 21 actual hours to work on the project (read more about it here). Some other teams were using XCode and the time savings that Delphi provided was real. Time was limited so I built all of the screens (20+) in a graphics program and then exported them to PNG files. I based the look and feel of the app on the Emerald Crystal FireMonkey premium style because I knew I would be able to quickly transition from a prototype to a real app using the style. The app runs on Android, IOS, OSX, and Windows with a single codebase and single UI. For the competition we only deployed the app to Android and Windows. I used a TTabControl with one screen in a TImage on each TTabItem. It is a prototype so I just used a TRectangle that is set to transparent above each button to catch the clicks and navigate through the screens. Here is the code from each transparent button:
//
//
procedure TForm1.Rectangle10Click(Sender: TObject);
begin
TB.SetActiveTabWithTransition(AllergiesTab,TTabTransition.Slide);
end;
What was interesting about the build is that I thought it would work across screen sizes but I should have used a TScaledLayout to handle the changing button sizes. Instead I found that my buttons didn’t line up with the image buttons between a Phone and a Tablet screen size (so I ended up making 1 app for each size because of the time limit). If I had used TScaledLayout I think it would have handled the two screen sizes correctly. The other functionality I built into the prototype was making a phone call within the app. One of the screens allows a medical professional to contact a patient and that code was simple in Delphi so I included it. Here is that code (requires FMX.Platform and FMX.PhoneDialer in the uses clause):
//
//
procedure TForm1.Rectangle40Click(Sender: TObject);
var
PhoneDialerService: IFMXPhoneDialerService;
begin
{ test whether the PhoneDialer services are supported }
if TPlatformServices.Current.SupportsPlatformService(IFMXPhoneDialerService, IInterface(PhoneDialerService)) then
begin
{ if the Telephone Number is entered in the edit box then make the call, else
display an error message }
PhoneDialerService.Call('1234567890');
end;
end;
Some other functionality which the solution needs but I wasn’t able to include due to the time limit was QR code scanning. QR code scanning is really simple in Delphi as there are a number of third party components available to drop in and go. One such library for that is the OBR library from Winsoft. Another functionality of the enterprise solution in the project was a QR code printer and there is also a third party solution from Winsoft for that as well.
Image may be NSFW. Clik here to view.Embarcadero has released an Update for Delphi 10.2.2 Firemonkey with quite a few bug fixes for Firemonkey, the REST client, JSON, mobile keyboard bounds checking, Android performance issues, and deploying to Android and IOS devices. In addition to the Firemonkey fixes there are additional fixes across the product line including fixes in the compilers, FireDAC, BaaS, and the IDE. If you are on the Update Subscription you can download it now. If you are not on the Update Subscription you should be. According to the release notes there are also: “Several key new features were added, including FireMonkey Quick Edit support, a number of new VCL controls, a new dark themed IDE option, a RAD Server single site deployment license in Enterprise and Architect editions, installer and welcome page enhancements and more.” Macro Cantu has a blog post up about the Update with more information. Here are the important fixes that jump out:
[NET] TNetHTTPClient.Head + HandleRedirects = Recives not the Full Header
[NET] TURI SetParameter doesn’t update the Query
[REST] Rest component seems not disconnecting
[NET] TNetHTTPClient/TRESTRequest: TLS 1.1 and 1.2 unsupported
[NET] THttpClient with TLS1.1 and TLS1.2 on older Windows systems
[NET] HttpClient not process 304 correctly
[JSON] TJSONObject.ToString() crashes after 1057 chars (unicode)
[REST] TRESTRequest – Root element cannot start with a dot (Dropbox)
[REST] TRESTClient handle/memory leak
[REST] REST Redirect 302 behaviour changed Berlin
[NET] THTTPClient POST redriects(301,302,303) has to be sent as GET
[JSON] TJSONMarshal / TJSONUnMarshal causes conversion error w/ TDateTime field
[JSON] TJson.Format() outputs invalid JSON
[NET] HTTPClient handling 304 as redirection
[REST] URIEncode function from REST.Utils doesn’t work properly
[JSON] TJSON.ObjectToJsonObject raise an exception when object is nil
[REST] TRESTRequest AfterExecute called twice if ExecuteAsyncused
Image may be NSFW. Clik here to view.Integrating with Bitcoin Cryptocurrency exchange APIs can sound like a daunting task but it was relatively easy to do with Delphi and FireMonkey. Unless you have been living under a rock you probably know that Bitcoin and other cryptocurrency have really seen a surge in value throughout 2017. If you HAVE been living under a rock you can check out this newbies guide to bitcoin and cryptocurrency. GDAX is an exchange owned by the popular Coinbase company. I literally built a REST client that talks to the GDAX API in 5 minutes and was able to start downloading the list of currencies on the exchange and getting price quotes for a currency. This is the first step to building an automated trading client, bot, or AI for cryptocurrencies. In addition to that because I used FireMonkey that same app client will deploy to Android, IOS, Mac, and Windows with a single code base and single UI.
You can check out the documentation for GDAX for yourself to see the rest of the REST API end points. I grabbed the products endpoint and the products book endpoint and used those two endpoints in the REST Debugger to quickly and easily download the data and LiveBind it to controls in my Delphi client. The first /products/ API I used directly because it doesn’t have any parameters. Once you select one of the cryptocurrency pairs at runtime it will use that for the next request to the /products/{currency}/book endpoint. The variable there can be set using code like the below and then it will automatically be filled in when the RESTRequest is executed (it is of type pkURLSEGMENT). The “/products/{currency}/book” string goes in the Resource property of the TRESTRequest component. I ended up only writing three lines of code for the whole app.
//
//
procedure TForm1.Button1Click(Sender: TObject);
begin
RESTRequest1.Execute;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
RESTRequest2.Params.ParameterByName('currency').Value := Edit1.Text;
RESTRequest2.Execute;
end;
I also applied the Jet premium style (which gives the dark look to the client). As you can see in the screenshot I am also running the new dark theme in Delphi 10.2.2. As you can see it is really easy to get started using Delphi as a platform for creating your own bitcoin cryptocurrency AI bot GUI apps. You could also use Python on the back and and just have Delphi execute your various Python commands if you already have a command line based Python cryptocurrency trading bot.