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.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.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;
//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 appearanceEach 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;