Source Code Delphi Samples with Sources

Статус
В этой теме нельзя размещать новые ответы.

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
Easy way to save and use your Week Day in BIN format and reversing it to string:
like:
  • my StrigBin initial:1101010
  • my ShortDayNames used in Bin string: sun, mon, wed fri
  • my StringBin recreated: 1101010
Bin_to_ShortDayNames.png


[SHOWTOGROUPS=4,19,20]
Код:
procedure TForm1.Button1Click(Sender: TObject);
var
  lFS                      : TFormatSettings;
  i, z                     : integer;
  lMyStringBin             : string;
  lMyStringShortCutDayNames: string;
  lMyArrayString           : TArray<string>;
  //
begin
  Memo1.Lines.Clear;
  //
  lFS := TFormatSettings.Create('pt-BR');
  //
  // It should accept ONLY THIS FORMAT using  0 and 1 chars OK??? because this is the propose here
  /
  lMyStringBin              := '0101010'; // bin = 8 - 1 = 7 digits {"0" to mostleft is not used if you want!!!}
  lMyStringShortCutDayNames := '';
  //
  Memo1.Lines.Add('my StrigBin initial:' + lMyStringBin);
  //
  for I := 0 to 6 do // char[ is "0" based ]
  begin
    if lMyStringBin.Chars[i] <> '0' then
      lMyStringShortCutDayNames := lMyStringShortCutDayNames + ' ' + lFS.ShortDayNames[i + 1]; // 1..7 else 0 = Month-Name
  end;
  //
  Memo1.Lines.Add('my ShortDayNames used in Bin string: ' + Trim(lMyStringShortCutDayNames));
  //
  lMyArrayString := Trim(lMyStringShortCutDayNames).Split([' ']);
  //
  lMyStringBin := lMyStringBin.Create('0', 7);
  //
  for i := 1 to 7 do
  begin
    for z := 0 to 6 do // high(lMyArrayString)
      if lFS.ShortDayNames[i].Contains(lMyArrayString[z]) then
      begin
        lMyStringBin[i] := '1';
        break;
      end;
  end;
  //
  Memo1.Lines.Add('my StringBin recreated: ' + lMyStringBin);

  // change names order...
  lFS.ShortDayNames[1] := 'Mon';
  Memo1.Lines.Add(lfs.Invariant.ShortDayNames[1]); // Invariant order!!! only English locale!
  Memo1.Lines.Add(lfs.ShortDayNames[1]);
  //
  end;
[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
Quick Tip: Fixing “Could not convert variant of type (Null) into type…”
thansk to CodeSmithing

...I often use the XML Data Binding wizard in Delphi. However, it doesn’t seem to have been given a lot of attention from Borland/Inprise/Borland/CodeGear/Embarcadero/Idera. And unfortunately, out of the box what it generates is often error prone, apparently not supporting optional elements/attributes.

[SHOWTOGROUPS=4,19,20]
When the generated code tries to read an optional element or attribute, you will get a “Could not convert variant of type (Null) into type” exception.
The offending code usually looks like this:
Код:
function TXMLMyType.Get_OptionalElement: Single;
begin
    Result := ChildNodes['OptionalName'].NodeValue;
end;

If you do a little googling, you will see that people are still asking questions about this even pretty recently. The suggested fix you will often discover is labor intensive if you have a lot of optional elements/attributes and will get wiped out if you rerun the XML Data Binding wizard:
Код:
if VarIsNull(ChildNodes['selected'].NodeValue) then
    Result := 0; // or false or empty string, etc
else
    Result := ChildNodes['selected'].NodeValue;

Hilariously in my mind, there is still an open ticket from 2002 about this issue: Для просмотра ссылки Войди или Зарегистрируйся
However, it seems the <insert-company-name-which-owns-Delphi> addressed this issue, probably years ago, and the fix/workaround is easy. You need to include the Variants unit and set the NullStrictConvert global variable to false:
Код:
    NullStrictConvert := False

As the documentation states:
NullStrictConvert determines the outcome of attempts to convert Для просмотра ссылки Войди или Зарегистрируйся variants to other types.
If NullStrictConvert is true (default), attempting to convert a Для просмотра ссылки Войди или Зарегистрируйся variant raises a Для просмотра ссылки Войди или Зарегистрируйся, unless the conversion is to a custom variant that defines a conversion from Для просмотра ссылки Войди или Зарегистрируйся. If NullStrictConvert is false, then conversion from Для просмотра ссылки Войди или Зарегистрируйся follows the following rules

Now, the XML Data Binding code will silently convert NULL to 0, false, or empty string without a problem. I wanted to publicize this fix. I have been bitten by this exception more times than I can count and if I had known of the workaround, it would have made my life much easier.

That’s it for today. I hope everyone is enjoying their Summer (or Winter in the southern hemisphere).

Thanks to CodeSmithing!
[/SHOWTOGROUPS]
 

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
Easy way to change your StatusBar color on Android app by ZuBy
Developer ZuBy has made some demo code available for changing the StatusBar color on Android in your apps.
The status bar is the bar at the top of your device with the various icons and other information in it.
[SHOWTOGROUPS=4,19,20]
In a Java based Android app to change StatusBar color you can do it either by modifying the styles.xml file and adding the following line:

1586205887995.png

Код:
<item name=”android:statusBarColor”>@color/color_primary</item>

or by changing at runtime (implementations may differ) through code using:

Код:
window.setStatusBarColor(activity.getResources().getColor(R.color.my_statusbar_color)).

However, in FireMonkey you must use the JNI (Java Native Interface).

JNI enables Java code running in a Java Virtual Machine (JVM) to call and be called by native applications (programs specific to a hardware and operating system platform) and libraries written in other languages.

Thus, you can call JNI Java code from Delphi 10 Berlin with FireMonkey and make the necessary changes.

In order to make use of this change, make sure you are using Android 5 (Lollipop) and above.

This code does not apply to Windows, IOS, or OSX.

Notice that the code bellow is very similar to the Java implementation on Android.

Код:
procedure StatusBarSetColor(const aColor: TAlphaColor);
{$IFDEF ANDROID}
var
  Window: JWindowExt;
{$ENDIF}
begin
{$IFDEF ANDROID}
  CallInUIThread(
    procedure
    begin
      if TOSVersion.Check(5, 0) then
      begin
        Window := GetWindowExt;
        Window.addFlags(TJWindowManager_LayoutParams.JavaClass.FLAG_TRANSLUCENT_STATUS);
        Window.addFlags(TJWindowManager_LayoutParamsExt.JavaClass.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

        Window.setFlags(TJWindowManager_LayoutParams.JavaClass.FLAG_TRANSLUCENT_STATUS,
          TJWindowManager_LayoutParams.JavaClass.FLAG_TRANSLUCENT_STATUS);
        Window.setFlags(TJWindowManager_LayoutParamsExt.JavaClass.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
          TJWindowManager_LayoutParamsExt.JavaClass.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

        Window.setStatusBarColor(TJcolor.JavaClass.TRANSPARENT); );
      end;
    end);
{$ENDIF}
{$IFDEF IOS}
  SetStatusBarBackgroundColor(aColor);
{$ENDIF}
end;

Full Source for Android and iOS on my GitHub
Для просмотра ссылки Войди или Зарегистрируйся

updated
Для просмотра ссылки Войди или Зарегистрируйся

[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
Android ADB Terminator (code source)
If you need terminate ADB for any error while compiling (by Ray Vecchio)
[SHOWTOGROUPS=4,19,20]
Embarcadero - Code Central

ID: 30160, A tool to terminate Android ADB when it locks files in the IDE
by Ray Vecchio

- For Delphi, Version 12.0 (it can works in later editions) - RAD Studo 10.3.3 Arch - It's WORKING for me!!!
- Updated on Fri, 11 Sep 2015 02:58:42 GMT
- Originally uploaded on Tue, 10 Mar 2015 08:28:19 GMT


DESCRIPTION
Under some circumstance it looks as if the Android ADB locks files and prevents the compilation or debugging of an application.

This package will add an option under the "Run" menu that will run adb and allow it to cleanly terminate any servers left running in on your system.

There is full source code to the package so you can modify it as you like, perhaps add call in the finalization code of the package to shut adb down when the IDE is closed too.

I changed the package to check if there is an adb running and NOT read the location from the registry.
pastedimage1586207147168v2.png


Full sources:
Для просмотра ссылки Войди или Зарегистрируйся[/SHOWTOGROUPS]
 

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
GeekAlarm!
screenshot.png

GeekAlarm! is a unique way for you to keep track of when you should take a break while using your computer. By taking breaks you can increase your productivity, reduce eye strain, and allay fatigue. GeekAlarm! has varying degrees of break enforcement including passive, medium, and aggressive enforcement. This helpful utility is a must have for anyone that uses a computer for long periods of time.
[SHOWTOGROUPS=4,20]
This is a unique Delphi 25th Anniversary edition.
Для просмотра ссылки Войди или Зарегистрируйся
[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
My simple way to show FireMonkey Forms in Fade effect - no Animate components!!!
prjFMX_Forms_Fade_In_Effect.png
[SHOWTOGROUPS=4,20]
Код:
unit uFormMain;

interface

uses
  System.SysUtils,
  System.Types,
  System.UITypes,
  System.Classes,
  System.Variants,
  FMX.Types,
  FMX.Controls,
  FMX.Forms,
  FMX.Graphics,
  FMX.Dialogs,
  FMX.Controls.Presentation,
  FMX.StdCtrls,
  FMX.Objects,
  FMX.Layouts;

type
  TfrmFormMain = class(TForm)
    btnCallFormSecond: TButton;
    Layout1: TLayout;
    btnHowManyFormsCreated: TButton;
    procedure btnCallFormSecondClick(Sender: TObject);
    procedure btnHowManyFormsCreatedClick(Sender: TObject);
  private
  public
  end;

var
  frmFormMain: TfrmFormMain;

implementation

{$R *.fmx}

uses
  uFormSecond;

procedure TfrmFormMain.btnCallFormSecondClick(Sender: TObject);
begin
  //
  btnCallFormSecond.Enabled := False; // avoid create anothers forms here! But dont worry = click many times to test!
  //
  frmFormSecond := TfrmFormSecond.Create(self);
  try
    Layout1.AddObject(frmFormSecond.Layout1);
    // frmFormSecond.Show; {not needs}
  finally
  end;
end;

procedure TfrmFormMain.btnHowManyFormsCreatedClick(Sender: TObject);
var
  i                   : integer;
  sFormsCreateOnMemory: string;
begin
  for I                  := 0 to (Screen.FormCount - 1) do
    sFormsCreateOnMemory := sFormsCreateOnMemory + Screen.Forms[i].ToString + #13#10;
  //
  ShowMessage(sFormsCreateOnMemory);
end;

end.
Код:
unit uFormSecond;

interface

uses
  System.SysUtils,
  System.Types,
  System.UITypes,
  System.Classes,
  System.Variants,
  FMX.Types,
  FMX.Controls,
  FMX.Forms,
  FMX.Graphics,
  FMX.Dialogs,
  FMX.Ani,
  FMX.Controls.Presentation,
  FMX.StdCtrls,
  FMX.ScrollBox,
  FMX.Memo,
  FMX.Objects,
  FMX.Layouts,
  FMX.ListBox,
  FMX.Edit;

type
  TfrmFormSecond = class(TForm)
    Panel1: TPanel;
    Timer1: TTimer;
    Edit1: TEdit;
    btnCloseMe: TButton;
    ListBox1: TListBox;
    Layout1: TLayout;
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure btnCloseMeClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    iMyOpacityCount: Single;
  public
  end;

var
  frmFormSecond: TfrmFormSecond;

implementation

{$R *.fmx}

procedure TfrmFormSecond.btnCloseMeClick(Sender: TObject);
begin
  Close;
end;

procedure TfrmFormSecond.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := TCloseAction.caFree;
end;

procedure TfrmFormSecond.FormCreate(Sender: TObject);
begin
  // Self.Visible      := False;
  Self.Transparency := True;                     // start transparent!!!
  Self.BorderStyle  := TFmxFormBorderStyle.None; // no borders!
  //
  Panel1.Opacity  := 0;   // like a transparen!!!
  Timer1.Interval := 100; // 01 sec Div 100 = delay-time to show my form!
  iMyOpacityCount := 0.3; // intervale to opacity!!!
end;

procedure TfrmFormSecond.Timer1Timer(Sender: TObject);
begin
  Panel1.Opacity := Panel1.Opacity + iMyOpacityCount;
  //
  Edit1.Text := TimeToStr(now) + ', ' + Panel1.Opacity.ToString;
  //
  // Single type Use this type for low accuracy floating-point operations!!!
  // if Panel1.Opacity > 1 then ... dont disable my timer!!!
  if Panel1.Opacity > 0.999 then // 0.99 can solve problem with "accuracy" compare
  begin
    Timer1.Enabled := false;
    Edit1.Text     := 'Timer disabled!';
    //
    // Self.Transparency := False; // <---
    // Self.Visible := True;
    //
    Exit;
  end;
end;

end.

code
Для просмотра ссылки Войди или Зарегистрируйся
[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
Mobile GFX - Creating Icons and Launchers for Delphi Mobile Applications
by TGrubb
If you have ever tried to create the icons, spotlights, settings and launchers for Delphi Android and iOS applications, you have quickly realized that the process is fairly ridiculous.

There are 2 different platforms (iOS and Android), 3 different device types (iPhone, iPad, Android), and 7 different ratios (1:1, 1.33:1, etc) of icon/launcher graphic sizes all combining to require a whopping total of 28 different png files to be created (See Figure 1). Talk about taking the Rapid out of Rapid Application Development!

Для просмотра ссылки Войди или Зарегистрируйся

After doing this once, I realized that I never want to do that again. For my own sanity and yours, I have created a small little utility for quickly creating these 30 different png files and for helping fill in the Application Options page.
The utility works by allowing you to specify base image(s) for each graphic ratio, optionally defining what portion of the image to extract for each ratio, and then generating the png files. You have the option of creating iPhone, iPad, and/or Android files. In addition, the utility will even make the .optset files which Delphi uses to fill in the blanks (Click Apply… for each configuration and select the .optset file).
To use the Mobile Gfx Setup tool:
First, set up your images on the Graphics Tab

Для просмотра ссылки Войди или Зарегистрируйся
  • For each image ratio, enter or browse to an image file
  • Select the part of the image to be used for the format (shown in red)
  • Move the image selection around by Ctrl Dragging the red rectangle
Next, set up the output options from the Setup tab

Для просмотра ссылки Войди или Зарегистрируйся
  • Enter a base filename for the generated images. The tool will append the Width and Height of an image to this filename (e.g., ‘c:\junk.png’ becomes ‘c:\junk114x114.png’
  • Select which devices you want to generate images for
  • Finally, check the ‘Generate .optset file(s)’ checkbox if you want the .optset file generated which you can then later import into Delphi
Finally, generate your images from the Generate tab

Для просмотра ссылки Войди или Зарегистрируйся
  • When you go to the Generate tab, the tool will verify you have entered everything correctly
  • If validation has passed, click the Generate button to generate the images and, optionally, the .optset files (which will be called basename.android.optset and basename.ios.optset)
Finished!
If you generated the .optset file, do the following steps:
  • Load your Delphi project
  • Select Project->Options to show the project options (See Figure 1)
  • Click Application on the left to show application options
  • Change the Target configuration
  • Click the Apply… button
  • Browse to the .optset file
  • Modify the configuration and click OK!
[SHOWTOGROUPS=4,20]
I hope this is as useful to you as it is to me. Source and compiled executable: Для просмотра ссылки Войди или Зарегистрируйся.

Requests/comments/bug fixes can be sent to me at tgrubb AT RiverSoftAVG DOT com.

Happy CodeSmithing!

TGrubb

[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
Single File Data Storage (storing data-file in zip file like in SQLite way)
by coyoteelabs
Hi all, I've updated the library Single File Data Storage to work with all Delphi versions

About the library:
  • The Single File Data Storage library provides an efficient solution for an application to store many different types of data inside one file
  • able to access this data very fast and easily, without bothering about creating temporary files or streams (when requesting to read, the compressed data is decompressed on the fly directly from the source stream).

Look at the samples and in the help file to see how easy it is to use SFDS.

Features:
  • Single-file Virtual File System (read-only): SFDS files are ZIP like archive files (not really ZIP files) with enhanced functionality (see below). One or more SFDS files can be "mounted" in the application. Searching or requesting to open a stream for read will query all "mounted" files or you can just specify a single one.
  • Transparent streaming compression/decompression with full TStream compatibility.
  • Thread-safe (When reading from files): Read from multiple streams (located in the same SFDS file archive) at the same time (Just create a new clone of the stream in each thread - see demo).
  • High performance: SFDS is perfect for Games(and other applications such as backup, etc) which need to store many (usually small) files in just a small number of (big) archives. Storing data in a small number of SFDS files results in faster access time to data (When opening a SFDS file the list of streams inside is cached in memory), and also makes it harder to modify files inside.
  • Large file support (64-bit size) lets you store all the data you need in SFDS files of virtually unlimited size.
  • Supported compression types: none (stored), zlib, bzip2. New formats can easily be added.
  • Compression support is modular. Each application can chose to add only the compression it needs (if you need zlib compression/decompression simply add sfds_compressorzlib to the uses clause somewhere inside your project; add sfds_compressorbzip2 for BZip2).
  • Per stream compression option; store one stream uncompressed, another compressed with zlib, another with bzip2, etc.
  • No DLLs required.
  • No file name restrictions (including unicode file names allowed - strings are stored UTF-8 encoded, just like in .dfm files). If the file name is an empty string, then you can still access the data via file index.
  • Reading from compressed streams is just like reading from any other stream (even full seeking in any direction is allowed).
  • You can create links to streams inside SFDS files (the new entries will point to the same data).
  • Includes a list of opened reader objects, which are automatically destroyed if you forget about them (you only need to free the streams you open).
  • It has lots of routines for adding/extracting, testing (MD5 error checking) files to/from the SFDS file format.
  • It also has search routines, to easily find files inside SFDS archives (SFDS_FindFirst, SFDS_FindNext, SFDS_FindClose).
  • Supports metadata information: you can set any fields: string, number, date, boolean, binary (Metadata Editor Form included).
  • You can write/read SFDS files directly to/from any data source. Already implemented: Disk File [R/W], Memory Stream [R/W], Resource Stream [R]. Make a descendent of TSFDSCustomReader to read from any other custom source and a descendent of TSFDSCustomWriter to write to any other custom source. Once written, a SFDS file cannot have more data appended to it.
  • There are no components to install, so this library also works with the free Turbo Delphi.
  • Best of all: it's completely free (Even for commercial use).

I've made 2 versions:
  • 1st version (version 1.4.2) simply updates the library to work with the newest Delphi versions. Should still be compatible with sfds files created with original version but doesn't have unicode support. Use this one if you need to use files created in versions 1.4.1 or older.
  • 2nd version (version 1.5.0) also updates the library to support unicode (now uses string instead of ansistring). This version won't work with sfds files created with older versions (1.4.1 or older). Note that I only updated the demo .sfds files for the "Basic SFDS File Creator" demo only
[SHOWTOGROUPS=4,20]
Download v1.4.2 (no unicode support, works with older sfds files)
Для просмотра ссылки Войди или Зарегистрируйся
Download v1.5.0 (with unicode support, won't work with older sfds files)
Для просмотра ссылки Войди или Зарегистрируйся
all files together
Для просмотра ссылки Войди или Зарегистрируйся[/SHOWTOGROUPS]
 

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
How to add Android "app shortcuts" to a FMX application
by Andrea Magni
[SHOWTOGROUPS=4,20]
  • Starting with Android 7.1 (API Level 25, supported out of the box by Delphi 10.3 Rio version) there is a new functionality supported by the OS (specifically by the OS app launcher and most of alternative launchers as well): app shortcuts.

You can find all details about this Android capability at Для просмотра ссылки Войди или Зарегистрируйся.

shortcuts.png

Screenshot showing app shortcuts (from Android’s official documentation)

Why deal with app shortcuts?
Shortcuts can be very helpful when the application includes one or more main activity and the user may benefit having a specific shortcut to start your application and jump to that specific activity within your app. Also consider that most launchers (starting with the default one) will let the user have this shortcuts at hand by long-pressing the app’s icon, with an opportunity to create app-like icons on the home screen to trigger the shortcuts.

Example of popular apps with shortcuts: GMail, Google Maps, WhatsApp, Hangout, Slack and many more (and starting today, maybe yours too :)

During a one-to-one training session on FMX mobile development, one of my customers asked for this specific functionality (introduced with Android 7.1 Nougat, late 2016) to be implemented in a FMX app, so I delved a bit into this topic (that also has a sibling on the iOS side named “3D touch”, introduced in 2015 with iOS9).

In this blog post we’ll see how to add static shortcuts to your Android FMX application, through 4 simple steps. I plan to expand more on this topic (probably in Для просмотра ссылки Войди или Зарегистрируйся or during some of my mobile development workshops, held in my office in Italy or at Delphi events like Для просмотра ссылки Войди или Зарегистрируйся, scheduled for next May 8th in Koln, Germany), covering dynamic shortcut generation and the iOS side as well.

For now, we’ll start with an empty FMX app and we’ll add one static shortcut to the app.

Step 1: Edit your Manifest.xml file
Better said, edit your AndroidManifest.template.xml file, adding the following line inside the activity tag, just after the closing tag of the intent-filter element.
(...)
Код:
</intent-filter>
<meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts" />
</activity>

The AndroidManifest.template.xml file will be used by the IDE to compile the actual Manifest.xml file that will be shipped within the final APK. The app launcher of your user device will look for this piece of information in order to describe app shortcuts for your app.

Basically we are just introducing a reference to an other XML file (shortcuts.xml) we are going to create in a proper folder as we’ll see in the next step.

Step 2: Create your shortcuts.xml file
As we’ll see later, it does not really matter where on your file system, but for example you can place it in your project root folder, just aside of the AndroidManifest.template.xml that IDE should have created for you.
Код:
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
android:shortcutId="myshortcut1"
android:enabled="true"
android:icon="@drawable/andreamagni_128"
android:shortcutShortLabel="@string/my_shortcut1"
android:shortcutLongLabel="@string/my_shortcut1"
android:shortcutDisabledMessage="@string/my_shortcut1_disabled">
<intent
android:action="android.intent.action.MYACTION1"
android:targetPackage="com.embarcadero.Project1"
android:targetClass="com.embarcadero.firemonkey.FMXNativeActivity"/>
<categories android:name="android.shortcut.conversation"/>
</shortcut>
</shortcuts>

Please note:
  1. You’ll need to provide a unique (within your app) shortcutId value, a string literal (not a re;
  2. The values for the shortcutShortLabel (preferably less than 10 characters) and shortcutLongLabel (preferable less than 25 characters) are references to resource strings (we’ll see in next step of this blog post how to provide a value for these entries);
  3. there is an intent element, where you can specify the action attribute. This information will be then included in the intent information your app may inspect to determine which shortcut has been triggered;
  4. again the same intent element has a targetPackage attribute that must match the application package name (so please be sure to change this value accordingly to your Delphi project’s name);
  5. the categories element is a bit of a mistery to me so far: as far as I understood (see Для просмотра ссылки Войди или Зарегистрируйся) there is only one admitted value (conversation) and it has been introduced with API level 25 (there should be more values available in later API levels).
  6. the icon attribute has a value “@drawable/andreamagni_128”: I am going to use a 128×128 PNG file (with one of my profile pictures) as icon for our shortcut, we’ll see later how to include the actual PNG in the APK.
Step 3: create your strings.xml file
Again, it does not really matter where on your file system, but for example you can place it in your project root folder, just aside of the AndroidManifest.template.xml that IDE should have created for you and the shortcuts.xml file created at step 2.
Код:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="my_shortcut1">Andrea</string>
<string name="my_shortcut1_disabled">Shortcut is disabled</string>
</resources>

Step 4: configure Deployment
Now that we have created these two additional xml files (shortcuts.xml and strings.xml) we need to correctly include them in the final deploy (build of the APK). We can add them in the Deployment page of the IDE (Project –> Deployment) and manage their deployment for the Android platform.

Schermata-2019-02-10-alle-21.12.02.png


Please note:
  1. the platform/configuration combo box shows “Debug configuration – Android platform” (you may want to select “All configurations – Android platform” entry) before adding the two xml files and the PNG file to the deployment file list (using the second toolbutton);
  2. I’ve edited the “Remote Path” value specifying “res\values\” for the strings.xml file and “res\xml\” for the shortcuts.xml file (no quotes);
  3. the entry for the andreamagni_128.png picture has “res\drawable\” as “Remote Path” value.
That’s all… really?
No, not really. But it is all that is required to actually define (static) shortcuts for your app.
If you build&deploy this application on an Android 7.1+ device, with a shortcut-enabled launcher (my Nexus 5X with the default launcher for example) you’ll be able to long-tap on the app icon and have shortcuts displayed.

App-Shortcuts-1.png
App-shortcuts-2.png

You can even drag the shortcut on the home screen to have a separate icon on the screen to trigger your shortcut.
Here is a short video showing how to display the shortcut list and drag one of the shortcuts to the home screen in order to create a permanent icon for the shortcut.

Now you may be asking yourself how to handle shortcuts at the application level, meaning how to know if your app has been started normally or through a certain shortcut.

Handling the shortcut in the app
In order to know how your app was started (with or without a shortcut triggered), you can check the action value of the intent called by the OS to launch your app. It will contain the value specified as action attribute for the triggered shortcut (if the app has been started through a shortcut), in our case it would be “android.intent.action.MYACTION1”. The following code is a very basic example how to reach this value:
Код:
uses
Androidapi.JNI.App, Androidapi.JNI.JavaTypes,
Androidapi.Helpers;

procedure TForm1.FormCreate(Sender: TObject);
begin
Label1.Text := 'S: ' + JStringToString( TAndroidHelper.Activity.getIntent.getAction );
end;

It’s up to you then to handle the situation from an application point of view. If your app has multiple views (i.e. has a tab control on it, you may want to show a specific item, load some specific data, perform an action…).


Conclusion
App shortcut are a powerful functionality of Android operating system and can be very useful in business applications. They can improve general usability of your app as you can provide a handy and quick way to get to some functionality built-in your app.

There are a number of topics around this first/basic example I’d like to delve a bit more into but time is limited and my working schedule hard. So I hope you enjoyed this and please let me know if you have any questions about this.

Sincerely,
Andrea

[/SHOWTOGROUPS]
 

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
Introducing mORMot-JWT: a "new"” JWT implementation
JWT stands for JSON Web Tokens and it is a very popular technology used to implement custom-content tokens across REST services.
[SHOWTOGROUPS=4,20]
Для просмотра ссылки Войди или Зарегистрируйся
The JWT logo Для просмотра ссылки Войди или Зарегистрируйся

Even if it is generally much over-rated and have its own drawbacks (especially when dealing with security), it is becoming something like a de facto standard for Web and REST applications authorization/authorization mechanisms.

You can read Для просмотра ссылки Войди или Зарегистрируйся.

I have used JWT since the end of 2015 as a default implementation for authentication/authorization mechanisms in Для просмотра ссылки Войди или Зарегистрируйся. The central topic of a JWT library is of course about token signing (through HMAC SHA256, for example) and so far I used (a fork of mine of) a library named JOSE JWT that relies on Для просмотра ссылки Войди или Зарегистрируйся to implement cryptographic functions and thus forces you to distribute OpenSSL with your software.

Given deploying OpenSSL is becoming more and more a burden to match security requirements and given the Для просмотра ссылки Войди или Зарегистрируйся implemented JWT in Для просмотра ссылки Войди или Зарегистрируйся a while ago (Для просмотра ссылки Войди или Зарегистрируйся), I decided (after having discussed this a couple of times with Arnaud) to “steal” a mORMot JWT subset implementing JWT

If you have been to some of my sessions about MARS, you surely have seen me struggling with OpenSSL DLLs missing here and there… well, this is the day this will come to an end! Apart from this, there are a number of reasons this is a move forward for the MARS projects:
  1. as I said, one less external dependency for your application servers (on Windows platform);
  2. the mORMot implementation is faster (at least 5 times faster in some scenarios even I didn’t do serious benchmarking yet);
  3. the mORMot implementation has a stronger community behind and so I am more confident about feature and bugfixes;
  4. this is not the first piece of mORMot I integrate to MARS (see the dMustache integration covered by the “mustache” demo in MARS) and maybe it will not be the last (I always wanted to have MARS running on top of the mORMot’s http server http.sys implementation [as well as on top of TMS Sparkle, BTW] and I am also considering adding built-in compression for MARS using mORMot highly optimized compression utilities).
So I created the Для просмотра ссылки Войди или Зарегистрируйся on github.com with a relatively small subset of mORMot files needed to implement JWT in any Windows application (feel free to use it wherever you may need! I will soon ask jwt.io to inlcude it in the library list for Delphi). Obviously all the code is by Synopse team and I did nothing else than copying some files in the new repository, trying to get the smallest part (but not tampering too much with the original files, in order to ease upgrading to newer versions).
Here is an example of use (Для просмотра ссылки Войди или Зарегистрируйся):

Код:
uses (...)
, SynCommons, SynCrypto, SynEcc, SynLZ;
var
LJWT: TJWTAbstract;
LToken: string;
begin
LJWT := TJWTHS256.Create(StringToUTF8(ASecret), 0, [jrcIssuer, jrcSubject], [], 60);
try
LToken := UTF8ToString( LJWT.Compute(['LanguageId', 'IT', 'CurrencyId', 'EUR'], 'MyApp', 'TheUser') );
WriteLn('Token: ' + LToken);
finally
LJWT.Free;
end;
end;

Then I refactored MARS to support both JOSE and mORMot-JWT library in a manner that mORMot-JWT will be the default implementation for all Windows platforms and still keeping JOSE for non-Windows ones (mORMot does not currently support Delphi Linux compiler and ARC-enabled Delphi compilers) and also added tests to ensure the two libraries would have a coherent behavior throughout MARS.

Please upgrade your MARS projects by adding the following units inclusion IFDEF (in the Server.Ignition.pas file or wherever you are defining your TMARSEngine instance):
Код:
{$IFDEF MSWINDOWS}
, MARS.mORMotJWT.Token
{$ELSE}
, MARS.JOSEJWT.Token
{$ENDIF}

And also remember to add ‘(…)MARS/ThirdParty/mORMot/Source’ to your library path before recompiling the MARS package groups.
Enjoy!

PS: this is not the only new feature I added to MARS recently (more blog posts will come)
[/SHOWTOGROUPS]
 

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
my sample: How to Insert MP3/MP4 file or other like a Resource into your executable and Play it in MediaPlayer (FireMonkey / VCL)
NOTE1: Dont forget, in Android/iOS you need privilegies like: read/write resource in Storages (internal or external), play some, etc.. study about use of "privilegies" in your apps!
  • NOTE2: Bad pratice insert a big file in your executable!
Screen0001.png

[SHOWTOGROUPS=4,20]
Код:
unit uFormMain;

interface

uses
  System.SysUtils,
  System.Types,
  System.UITypes,
  System.Classes,
  System.Variants,
  FMX.Types,
  FMX.Controls,
  FMX.Forms,
  FMX.Graphics,
  FMX.Dialogs,
  FMX.Media,
  FMX.Controls.Presentation,
  FMX.StdCtrls,
  FMX.Layouts,
  FMX.ListBox,
  FMX.ScrollBox,
  FMX.Memo;

type
  TfrmFormMain = class(TForm)
    MediaPlayer1: TMediaPlayer;
    btnReading_MP3_on_Resources: TButton;
    mmMyLogs: TMemo;
    btn_MediaPlayer_Stop: TButton;
    procedure btnReading_MP3_on_ResourcesClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btn_MediaPlayer_StopClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmFormMain: TfrmFormMain;

implementation

{$R *.fmx}

uses
  System.IOUtils,
  FMX.DialogService;

var
  lMyPathToResouces: string;

function fncMyExceptions(lMyExcept: Exception): string;
begin
  // here, I dont worry about override my resulted ok!!!
  if lMyExcept is EResNotFound then
    result := '[my error EResNotFound class]';
  if lMyExcept is Exception then
    result := '[my error generic threat]';
  if lMyExcept is EFCreateError then
    result := '[my error EFCreateError class]';
  if lMyExcept is EMediaException then
    result := '[my error EMediaException class]';
  if lMyExcept is Exception then
    result := '[my error generic threat]' + #13#10;
  //
  result := result + #13#10 + lMyExcept.ClassName + #13#10 + lMyExcept.Message;
end;

procedure TfrmFormMain.btnReading_MP3_on_ResourcesClick(Sender: TObject);
var
  lMyStream: TResourceStream;
begin
  // SysInit.pas HInstance: HINST; { Handle of this instance }
  // { Handle of the main(.EXE) HInstance }
  //
  try
    lMyStream := nil; // avoid errors below!!!
    //
    // RT_Data = Application-defined resource (raw data)!!
    // lMyStream := TResourceStream.CreateFromID( HInstance, 0, RT_RCDATA); // only if your res was indetifyed by number
    lMyStream := TResourceStream.Create(HInstance, 'Musica_001', RT_RCDATA); // only if your res was indetifyed by "string"
  except
    on E: Exception do
    begin
      mmMyLogs.Lines.Add( fncMyExceptions(E) );
      // exit;
    end;
  end;
  //
  if not(lMyStream = nil) then
  begin
    //
    try
      // saving my resource like a MP3 file to play it!
      // NOTE: Tags stay like original file source!
      //
      // needs save in a file to play in TMediaPlayer
      // FMX.Media.pas, line 1633
      lMyStream.SaveToFile('MyResourceSaved.mp3');
      //
      try
        // use DisposeOf and nil to new project Cross-Platform, or, use FreeAndNil(lMyStream) to MSWindows only!!!
        lMyStream.DisposeOf;
        lMyStream := nil; // avoid errors below!!
        //
        if FileExists(lMyPathToResouces + 'MyResourceSaved.mp3', false) then { MSWindows and POSIX }
        begin
          MediaPlayer1.FileName := lMyPathToResouces + 'MyResourceSaved.mp3'; // EMediaException can occurr here!!!
          MediaPlayer1.Play;
        end
        else
          mmMyLogs.Lines.Add('--> ' + lMyPathToResouces + 'MyResourceSaved.mp3, Dont exist!!!');
      except
        on E: Exception do
          mmMyLogs.Lines.Add( fncMyExceptions(E) )
        // exit;
      end;
    finally
      if Assigned(lMyStream) then
      begin // FreeAndNil(lMyStream)
        lMyStream.DisposeOf;
        lMyStream := nil;
      end;
    end;
  end;
end;

procedure TfrmFormMain.btn_MediaPlayer_StopClick(Sender: TObject);
begin
  if MediaPlayer1.State = TMediaState.Playing then
  begin
    MediaPlayer1.Stop;
    //
    try
      DeleteFile(lMyPathToResouces + 'MyResourceSaved.mp3'); // MSWindows and POSIX
      //
      TDialogService.ShowMessage('Stopped and file deleted!'); // Verify: file is "playing" cannot be deleted!!!
    except
      on E: Exception do
        mmMyLogs.Lines.Add( fncMyExceptions(E) )
    end;
  end
  else
    TDialogService.ShowMessage('Nothing been played!');
end;

procedure TfrmFormMain.FormCreate(Sender: TObject);
begin
  mmMyLogs.Lines.Clear;
end;

initialization

lMyPathToResouces := ExtractFilePath(Paramstr(0)); // MSWindows old way!

// new Cross-Platform way!!!
// lMyPathToResouces := TPath.GetDocumentsPath + '\';
{ /storage/emulated/0/Documents }
// lMyPathToResouces := TPath.GetSharedDocumentsPath + '\';
{ /storage/emulated/0/Music }
// lMyPathToResouces := TPath.GetSharedMusicPath + '\';

finalization

end.
[/SHOWTOGROUPS]
 
Последнее редактирование:

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
My easy way to filling my OnCalcFields like an Array of values in DBGrid using any field on DataSet with my conditional data
1588194254060.png

NOTE: if your table had all records deleted, verify if your "initial value - your vars" should be "cleaned" too! Else, the last values will be used for next "first record"

[SHOWTOGROUPS=4,20]
Код:
object frmFormMain: TfrmFormMain
  Left = 0
  Top = 0
  Caption = 'frmFormMain'
  ClientHeight = 352
  ClientWidth = 402
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  Position = poScreenCenter
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object DBGrid1: TDBGrid
    Left = 8
    Top = 16
    Width = 385
    Height = 328
    DataSource = DataSource1
    TabOrder = 0
    TitleFont.Charset = DEFAULT_CHARSET
    TitleFont.Color = clWindowText
    TitleFont.Height = -11
    TitleFont.Name = 'Tahoma'
    TitleFont.Style = []
    Columns = <
      item
        Expanded = False
        FieldName = 'ID'
        Visible = True
      end
      item
        Expanded = False
        FieldName = 'DATA'
        Width = 150
        Visible = True
      end
      item
        Expanded = False
        FieldName = 'C1'
        Width = 50
        Visible = True
      end
      item
        Expanded = False
        FieldName = 'C2'
        Width = 50
        Visible = True
      end
      item
        Expanded = False
        FieldName = 'C3'
        Width = 50
        Visible = True
      end>
  end
  object FDMemTable1: TFDMemTable
    AfterDelete = FDMemTable1AfterDelete
    OnCalcFields = FDMemTable1CalcFields
    FieldDefs = <>
    IndexDefs = <>
    FetchOptions.AssignedValues = [evMode]
    FetchOptions.Mode = fmAll
    ResourceOptions.AssignedValues = [rvPersistent, rvSilentMode]
    ResourceOptions.Persistent = True
    ResourceOptions.SilentMode = True
    UpdateOptions.AssignedValues = [uvCheckRequired, uvAutoCommitUpdates]
    UpdateOptions.CheckRequired = False
    UpdateOptions.AutoCommitUpdates = True
    StoreDefs = True
    Left = 80
    Top = 257
    object FDMemTable1ID: TIntegerField
      DisplayWidth = 10
      FieldName = 'ID'
    end
    object FDMemTable1DATA: TStringField
      DisplayWidth = 20
      FieldName = 'DATA'
    end
    object FDMemTable1C1: TStringField
      DisplayWidth = 2
      FieldKind = fkCalculated
      FieldName = 'C1'
      Size = 1
      Calculated = True
    end
    object FDMemTable1C2: TStringField
      DisplayWidth = 2
      FieldKind = fkCalculated
      FieldName = 'C2'
      Size = 1
      Calculated = True
    end
    object FDMemTable1C3: TStringField
      DisplayWidth = 18
      FieldKind = fkCalculated
      FieldName = 'C3'
      Size = 1
      Calculated = True
    end
  end
  object FDGUIxWaitCursor1: TFDGUIxWaitCursor
    Provider = 'Forms'
    Left = 272
    Top = 192
  end
  object FDStanStorageXMLLink1: TFDStanStorageXMLLink
    Left = 128
    Top = 184
  end
  object DataSource1: TDataSource
    DataSet = FDMemTable1
    Left = 192
    Top = 256
  end
end

Код:
var
  frmFormMain: TfrmFormMain;

implementation

{$R *.dfm}

var
  // what will be writed if the "initial value" was empty? = first record, for example!
  lC1: string = '?';
  lC2: string = '?';
  lC3: string = '?';

  { NOTE:
    if your table had all records deleted, verify if your "initial value - your vars" should be "cleaned" too!
  }

procedure TfrmFormMain.FDMemTable1AfterDelete(DataSet: TDataSet);
begin
  if DataSet.RecordCount = 0 then // for example, to re-start your vars!
  begin
    lC1 := '?';
    lC2 := '?';
    lC3 := '?';
  end;
end;

procedure TfrmFormMain.FDMemTable1CalcFields(DataSet: TDataSet);
var
  lMyArrayString: TArray<string>;
  lMyTextTmp    : string;
  lMyField      : TField;
begin
  lMyTextTmp     := '';
  lMyArrayString := nil;
  lMyField       := nil;
  //
  for lMyField in DataSet.Fields do
  begin
    if (lMyField.FieldNo = -1) then // only CalcField (FieldNo = -1) will be processed!
    begin
      lMyTextTmp := DataSet.Fields.Fields[1].AsString; // Field "DATA" it's the source!
      //
      lMyArrayString := lMyTextTmp.Split([';'], TStringSplitOptions.ExcludeEmpty);
      lMyTextTmp     := '';
      //
      for lMyTextTmp in lMyArrayString do // analizing what will be write!
      begin
        if lMyTextTmp.Contains('0=') then
        begin
          DataSet.Fields.Fields[2].AsString := lMyTextTmp.Chars[2];
          lC1                               := DataSet.Fields.Fields[2].AsString;
        end;
        //
        if lMyTextTmp.Contains('1=') then
        begin
          DataSet.Fields.Fields[3].AsString := lMyTextTmp.Chars[2];
          lC2                               := DataSet.Fields.Fields[3].AsString;
        end;
        //
        if lMyTextTmp.Contains('2=') then
        begin
          DataSet.Fields.Fields[4].AsString := lMyTextTmp.Chars[2];
          lC3                               := DataSet.Fields.Fields[4].AsString;
        end;
        //
      end;
      //
      if DataSet.Fields.Fields[2].IsNull then
        DataSet.Fields.Fields[2].AsString := lC1;
      //
      if DataSet.Fields.Fields[3].IsNull then
        DataSet.Fields.Fields[3].AsString := lC2;
      //
      if DataSet.Fields.Fields[4].IsNull then
        DataSet.Fields.Fields[4].AsString := lC3;
    end;
  end;
end;

procedure TfrmFormMain.FormCreate(Sender: TObject);
begin
  // loading my fields structure and some initial value
  FDMemTable1.ResourceOptions.PersistentFileName := '..\..\MyXMLFDMemTableData.xml';
  FDMemTable1.ResourceOptions.Persistent         := True;
  //
  FDMemTable1.LoadFromFile(FDMemTable1.ResourceOptions.PersistentFileName, sfXML);
  //
  if FDMemTable1.Active then;

end;
[/SHOWTOGROUPS]
 
Последнее редактирование:
Статус
В этой теме нельзя размещать новые ответы.