iOS Showcase

FREE DOWNLOAD

Click image for more screenshots.

Introduction


With this showcase demo, we wanted to demonstrate the power of both TMS iCL and TMS FMX Cloud Pack products for creating iOS applications. We refer to the power in terms of achieving a 100% true native iOS look and feel, using RAD methodology for developing the application, almost codeless access to a wide range of cloud services, access the iOS device hardware and finally getting the most performance out of the application. In this demo, we show how to use the native tab bar, toolbar, tableview, imagepicker and more. We show how to get access to files in the root and documents folder of the iOS application and how to consume multiple cloud services such as Facebook, Twitter, Google Drive, Instagram and best of all, with only a few lines of code.



Loading images / thumbnails


When deploying the demo, a set of images will be loaded from the root directory and for each image a thumbnail is shown in the list. When clicking on the item in the list, the corresponding full size image is displayed and ready to be uploaded to the authenticated services. Additionally, an image can be taken with the camera after clicking the camera icon button in the toolbar. The images are added to a TMSFMXNativeUITableView. The TMSFMXNativeUITableView has a section and section items collection. These are collections that can be used at designtime and runtime and expose Delphi properties such as a Text, Description, BitmapFile and BitmapSize property. The BitmapFile and BitmapSize properties are used to generate a thumbnail from the image that is added to the list. The TMSFMXNativeUITableView automatically takes care of this. The code below demonstrates how to load files from the root and documents directory and how to add them to the TMSFMXNativeUITableView component.
//Returns the Documents directory the iOS application
function GetDocumentsDirectory: String;
var
  paths: NSArray;
begin
  Result := '';
  paths := TNSArray.Wrap(NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, True));
  if paths.count > 0 then
    Result := UTF8ToString(TNSString.Wrap(paths.objectAtIndex(0)).UTF8String);
end;
//Returns the Root directory the iOS application
function GetRootDirectory: String;
begin
  Result := ExtractFilePath(Paramstr(0));
end;
//Initializes the list of images from the Root and Documents directory
procedure TForm1.InitImageList;
var
  doc: String;
  app: String;
begin
  TMSFMXNativeUITableView1.BeginUpdate;
  doc := GetDocumentsDirectory;
  AddImagesFromFolder(doc, ['.JPG','.JPEG','.PNG']);
  app := GetRootDirectory;
  AddImagesFromFolder(app, ['.JPG']);
  TMSFMXNativeUITableView1.Sections[0].Items.Sort(True, smDescending);
  TMSFMXNativeUITableView1.EndUpdate;
  SelectItem(0);
end;
    
//Adds images from a specified folder based on an array of file extensions.
procedure TForm1.AddImagesFromFolder(AFolder: String; AFileExtensions: array of string);
var
  arr: NSArray;
  I: Integer;
  fn, ext: String;
  it: TTMSFMXNativeUITableViewItem;
begin
  arr := TNSFileManager.Wrap(TNSFileManager.OCClass.defaultManager).contentsOfDirectoryAtPath(NSStr(AFolder), nil);
  for I := 0 to arr.count - 1 do
  begin
    fn := AFolder + '/' + UTF8ToString(TNSString.Wrap(arr.objectAtIndex(i)).UTF8String);
    ext := ExtractFileExt(fn);
    if MatchStr(ext.ToUpper, AFileExtensions) then
    begin
      it := TMSFMXNativeUITableView1.Sections[0].Items.Add;
      it.BitmapFile := fn;
      it.BitmapSize := 32;
      it.Text := ExtractFileName(it.BitmapFile);
    end;
  end;
end;
    

Authentication with multiple services


In order to access the different cloud services, it is needed to signup with these services first and register the application. Via this registration procedure, you obtain your unique application key and secret that is used to initialize the various TMS Cloud Pack components.In case the cloud service component could get access to the cloud service (i.e. by means of getting an access token) the token is persisted in a file so it can be reused without going through a new authentication/authorization phase. In the demo app, an INI file in the documents folder is used for persisting. The previously obtained tokens are loaded with the call TCloudService.LoadTokens. The next step is to test the validity of the token and this is done with the call TCloudService.TestTokens. A visual indicator on the screen indicates this validity of the token. When the token is not valid, following code is used to start a new authentication/authorization:

Click image for more screenshots.

//Initialize the application key and secret for each service
procedure TForm1.InitAppKeys;
begin
  TMSFMXCloudFaceBook1.App.Key := FacebookAppkey;
  TMSFMXCloudFaceBook1.App.Secret := FacebookAppSecret;
  TMSFMXCloudFaceBook1.PersistTokens.Key := GetDocumentsDirectory + '/facebook.ini';
  TMSFMXCloudFaceBook1.PersistTokens.Section := 'tokens';
  TMSFMXCloudFaceBook1.LoadTokens;
  TMSFMXCloudFaceBook1.Tag := integer(csFacebook);

  TMSFMXCloudTwitter1.App.Key := TwitterAppkey;
  TMSFMXCloudTwitter1.App.Secret := TwitterAppSecret;
  TMSFMXCloudTwitter1.PersistTokens.Key := GetDocumentsDirectory + '/twitter.ini';
  TMSFMXCloudTwitter1.PersistTokens.Section := 'tokens';
  TMSFMXCloudTwitter1.LoadTokens;
  TMSFMXCloudTwitter1.Tag := integer(csTwitter);

  TMSFMXCloudDropBox1.App.Key := DropBoxAppkey;
  TMSFMXCloudDropBox1.App.Secret := DropBoxAppSecret;
  TMSFMXCloudDropBox1.PersistTokens.Key := GetDocumentsDirectory + '/dropbox.ini';
  TMSFMXCloudDropBox1.PersistTokens.Section := 'tokens';
  TMSFMXCloudDropBox1.LoadTokens;
  TMSFMXCloudDropBox1.Tag := integer(csDropBox);

  TMSFMXCloudGDrive1.App.Key := GoogleAppKey;
  TMSFMXCloudGDrive1.App.Secret := GoogleAppSecret;
  TMSFMXCloudGDrive1.PersistTokens.Key := GetDocumentsDirectory + '/gdrive.ini';
  TMSFMXCloudGDrive1.PersistTokens.Section := 'tokens';
  TMSFMXCloudGDrive1.LoadTokens;
  TMSFMXCloudGDrive1.Tag := integer(csGDrive);

  TMSFMXCloudFlickr1.App.Key := FlickrAppKey;
  TMSFMXCloudFlickr1.App.Secret := FlickrAppSecret;
  TMSFMXCloudFlickr1.PersistTokens.Key := GetDocumentsDirectory + '/flickr.ini';
  TMSFMXCloudFlickr1.PersistTokens.Section := 'tokens';
  TMSFMXCloudFlickr1.LoadTokens;
  TMSFMXCloudFlickr1.Tag := integer(csFlickr);
end;
	
//Initializes the status by showing an Ok or Error image next to each service.
procedure TForm937.InitStatus(cs: TCloudServices);
begin
  if csFacebook in cs then
  begin
    svcOKFacebook.Visible := TMSFMXCloudFaceBook1.TestTokens;
    svcErrFacebook.Visible := not svcOKFacebook.Visible;
  end;
  if csTwitter in cs then
  begin
    svcOKTwitter.Visible := TMSFMXCloudTwitter1.TestTokens;
    svcErrTwitter.Visible := not svcOKTwitter.Visible;
  end;
  if csDropBox in cs then
  begin
    svcOKDropBox.Visible := TMSFMXCloudDropBox1.TestTokens;
    svcErrDropBox.Visible := not svcOKDropBox.Visible;
  end;
  if csGDrive in cs then
  begin
    svcOKGDrive.Visible := TMSFMXCloudGDrive1.TestTokens;
    svcErrGDrive.Visible := not svcOKGDrive.Visible;
  end;
  if csFlickr in cs then
  begin
    svcOKFlickr.Visible := TMSFMXCloudFlickr1.TestTokens;
    svcErrFlickr.Visible := not svcOKFlickr.Visible;
  end;
end;
	
If the TCloudService.TestTokens fails, the service is not authenticated, which means that the tokens are no longer valid, or the service hasn't provided authentication tokens yet. The TCloudService.DoAuth call shows a native iOS UIWebBrowser component with the authentication page of the service. After login / authentication, the OnReceivedAccessToken event is called, allowing the application to persist the received authentication token and secret. When the application restarts, the above process is repeated and the TCloudService.TestTokens will succeed allowing the application to start uploading images.
//Connects to a specific service
procedure TForm1.ConnectService(cs: TCloudService; ServiceName: string);
var
  cb: TTMSFMXCloudBase;
  vw: TTMSFMXNativeUIImageView;
begin
  case cs of
  csFacebook: cb := TMSFMXCloudFaceBook1;
  csTwitter: cb := TMSFMXCloudTwitter1;
  csDropBox: cb := TMSFMXCloudDropBox1;
  csFlickr: cb := TMSFMXCloudFlickr1;
  csGDrive: cb := TMSFMXCloudGDrive1;
  end;

  case cs of
  csFacebook: vw := svcOKFacebook;
  csTwitter: vw := svcOKTwitter;
  csDropBox: vw := svcOKDropBox;
  csFlickr: vw := svcOKFlickr;
  csGDrive: vw := svcOKGDrive;
  end;

  if vw.Visible then
  begin
    if MessageDlg(ServiceName +' already authorized, do you want to unauthorize ?', TMsgDlgType.mtInformation, 
	  [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0) = mrYes then
    begin
      cb.ClearTokens;
      InitStatus([cs]);
    end;
    Exit;
  end
  else
    cb.DoAuth;
end;
	

Changing appearance

Each component in the TMS iCL set has a default appearance, which is the native appearance that comes with the iOS SDK. The appearance might be different depending on the SDK and kind of device. The iOS showcase demonstrates how to change the appearance of your application with a few lines of code. The application appearance can be changed to have an Ocean look through a popup after clicking the Style button in the toolbar. The TMSFMXNativeUITableView component has an OnGetItemAppearance event that is called for each item. The Ocean style applies banding in the TMSFMXNativeUITableView and the code to accomplish this is demonstrated below:
//The TMSFMXNativeUITableView customizes its appearance through the OnGetItemAppearance event.
procedure TForm1.TMSFMXNativeUITableView1GetItemAppearance(Sender: TObject;
  ASection, ARow: Integer;
  var AAppearance: TTMSFMXNativeUITableViewItemAppearance);
begin
  if FStyle = 1 then
  begin
    if Odd(ARow) then
      AAppearance.BackGroundColor := $FFEFFFFE;

    AAppearance.SelectedBackGroundColor := $FF2AC6BD;
  end;
end;