unit Main;

interface

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

type
  TFormMain = class(TForm)
    ButtonStartStop: TButton;
    CameraComponent: TCameraComponent;
    Memo: TMemo;
    ImageViewer: TImageViewer;
    procedure ButtonStartStopClick(Sender: TObject);
    procedure CameraComponentSampleBufferReady(Sender: TObject;
      const ATime: TMediaTime);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    BarcodeDecoder: TBarcodeDecoder;
    WasRealignContent: Boolean;
    procedure Start;
    procedure Stop;
  public
    { Public declarations }
  end;

var
  FormMain: TFormMain;

implementation

{$if CompilerVersion >= 33}
  {$define D103PLUS} // Delphi 10.3 or higher
{$endif}

{$if CompilerVersion >= 35}
  {$define D11PLUS} // Delphi 11 or higher
{$endif}

{$ifdef D103PLUS}
uses System.Permissions, Androidapi.JNI.JavaTypes, Androidapi.JNI.Os, Androidapi.Helpers;
{$else}
uses System.IOUtils;
{$endif D103PLUS}

{$R *.fmx}

procedure TFormMain.FormCreate(Sender: TObject);
begin
  BarcodeDecoder := TBarcodeDecoder.Create;

{$ifdef D103PLUS}
  PermissionsService.RequestPermissions([
    JStringToString(TJManifest_permission.JavaClass.CAMERA)],

  {$ifdef D11PLUS}
    procedure(const APermissions: TClassicStringDynArray; const AGrantResults: TClassicPermissionStatusDynArray)
  {$else}
    procedure(const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>)
  {$endif D11PLUS}
    begin
      ButtonStartStop.Enabled := (Length(AGrantResults) = 1)
        and (AGrantResults[0] = TPermissionStatus.Granted);
    end,

  {$ifdef D11PLUS}
    procedure(const APermissions: TClassicStringDynArray; const APostRationaleProc: TProc)
  {$else}
    procedure(const APermissions: TArray<string>; const APostRationaleProc: TProc)
  {$endif D11PLUS}
    begin
      APostRationaleProc;
    end);
{$endif D103PLUS}
end;

procedure TFormMain.FormDestroy(Sender: TObject);
begin
  BarcodeDecoder.Free;
end;

procedure TFormMain.CameraComponentSampleBufferReady(Sender: TObject; const ATime: TMediaTime);
var
  Results: TDecodeResults;
  I: Integer;
begin
  try
    CameraComponent.SampleBufferToBitmap(ImageViewer.Bitmap, True);
    Results := BarcodeDecoder.Decode(ImageViewer.Bitmap);

    if Length(Results) > 0 then
      Memo.Lines.Clear;

    for I := 0 to Length(Results) - 1 do
    begin
      Memo.Lines.Append(Results[I].FormatName + ': ' + Results[I].Text);
      Memo.GoToTextEnd;
    end;

    // TImageViewer workaround
    if not WasRealignContent then
    begin
      ImageViewer.RealignContent;
      WasRealignContent := True;
    end;
  except
    on E: Exception do
    begin
      Memo.Lines.Clear;
      Memo.Lines.Append(E.Message);
    end;
  end;
end;

procedure TFormMain.Start;
begin
  CameraComponent.Active := True;
  ButtonStartStop.Text := 'Stop';
end;

procedure TFormMain.Stop;
begin
  CameraComponent.Active := False;
  ButtonStartStop.Text := 'Start';
end;

procedure TFormMain.ButtonStartStopClick(Sender: TObject);
begin
  try
    if not CameraComponent.Active then
      Start
    else
      Stop
  except
    on E: Exception do
    begin
      Stop;
      raise
    end;
  end
end;

end.
