مساحة اعلانية

آخر المواضيع

IOS SDK والعمل مع "تقويمات جوجل"



فى هذا البرنامج التعليمي سوف تتعلم كيفية بناء تطبيق سوف يتفاعل مع خدمات ويب بواسطة تقويمات جوجل Google Calendar بإستخدام OAuth 2.0 . أقرأ معي !
من حيث توقفنا ..

فى أخر مقال لي, اظهرت لك كيفية تنفيذ بروتوكول O Auth 2.0 من أجل الوصول إلي خدمات Google  . بنهاية هذا البرنامج التعليمي سنبني فئة تعمل بكامل طاقتها للوصول إلى خدمات Google بواسطة OAuth 2.0 .

فى هذا البرنامج التعليمي أنا ذاهب إلي وضع هذه الفئة فى العمل عن طريق  تنفيذ تطبيق تجريبي .على وجه التحديد, أنا ذاهب لأظهر لك كيفية التفاعل مع خدمة ويب جوجل التقويمية Google Calander web service .
نظرة عامة على المشروع :

هذا التطبيق الذى سوف نقوم ببناءة فى هذا البرنامج التعليمي هو ليسمح للمستخدمين بالإتصال بحساب جوجل الخاص بهم وتنزيل التقويمات الخاصة بهم وإنشاء حدث جديد بوصف وتاريخ ووقت . سيتم نشر هذا الحدث الي التقويم الذي يحدد المستخدم المحدد 

وفيما يتعلق بهيكل التطبيق الخاص بنا, سيكون العرض الأساسي هو عرض الجداول التي تحتوي على ثلاثة أقسام لإعداد البيانات التالية .
- وصف الحدث.وقت الحدث وتاريخه.- تقويم الهدف.
وبقدر ما يتعلق بوصف الحدث, سوف يظهر لنا خانة الكتابة textfield فى الخلية عندما يقوم المستخدم بتعديل الوصف, وسوف تذهب بعيد عندما ينتهي من فعل ذلك . لسهولة الإستخدام سوف تظهر طريقة عرض " الملحقات الإدخال" وكل الوقت يتم عرضه فى خانة الكتابة textfield .
لتعيين أو تغيير الوقت والتاريخ للحدث, سيكون هناك أستخدام أخر (ليس وحدة تحكم العرض).سيتضمن هذا العرض منتقي التاريخ, الذي سيجعل المستخدم قادر على اختيار التاريخ .

 الحدث يمكن أن يكون حدث لكل الأيام, حيث لا يوجد وقت محدد يحتاج إلى التعيين . فى هذه الحالة,سيتم إستخدام زر لتعيين محتوى منتقي التاريخ.للأحداث التي وقعت فى وقت محدد, يقوم منتقي التاريخ Data Picker بعرض الوقت والتاريخ. لأحداث الأيام بالكامل, فقط التاريخ هو ما سيظهر لنا .هذا العرض يحتوي على منتقي التاريخ Data picker (وشريط الأدوات بازرار فى شريط البار) ستضاف بطريقة عرض فرعية ل وحدة عرض التحكم عندما يقوم المستخدم بالإنتقال فى الجداول بالقسم الثاني فى لوحة عرض الجداول .

واخيرا, سيكون قسم التقويم calendar متعدد الوظائف.عندما لا يزال المستخدم غير مسجل الدخول على حساب جوجل Google Account , صف واحد فقط سيكون موجود فى القسم مع رسالة تطالب المستخدم بتحميل التقويمات الخاصة به .عندما يقوم المستخدم بتحديده, سوف توضع عملية التأكيد او الترخيص داخل العمل .مرة واحده فقط عندما يتم الحصول على الرمز المميز للوصول, API تصنع للحصول على التقويمات الخاصة بك من قائمة جوجل.بعد أن اخذت قائمة التقويم, أول تقويم فى القائمة سوف يقوم بإزالة رسالة السماح فى الصف ويصبح التقويم المحدد بشكل إفتراضي.

بالإضافة إلي كل ما سبق , ستظل قائمة شريط أدوات Toolbar ظاهرة تحت عرض الجداول وسوف تحتوي على اثنين من الأزرار . زر واحد سيكون لنشر الحدث على التقويم المحدد . وسيتم إستخدام الزر الثاني لتسجيل الخروج.

دعونا نبدأ

1- إنشاء مشروع جديد

قم بتشغيل Xcode  وأنشىء مشروع جديد . قم بأختيار "تطبيق محدد واحد" وأنقر فوق التالي.

فى حقل أسم المنتج أضف قيمة تجريبية ل GoogleCalandarPostDemo . بالتأكيد يمكنك أختيار أسم أخر كما تريد . ايضا تأكد من التحقق من الخيار " Automatic Reference Couting " وقم بإلغاء تحديد أى شىء أخر .بعد ذلك استمر .

وأخيرا, حدد مجلدا لتخزين المشروع وانقر فوق إنشاء .

الخطوة الثانية :
الأن أنت بحاجة لإضافة ملفات الفئة التي تم تنفيذها فى البرنامج التعليمي السابق.هذه الفئة ستكون الألية التي ستقوم بالقيام بكل عمل وراء الكوالبيس .لذا, إذا كان لديك ملفات المشروعات للبرنامج التعليمي السابق أحصل على هذه أيضا

GoogleO Auth.h
GoogleO Auth.m

إذا لم يكن لديك مشاريع البرنامج التعليمي السابق, يمكنك تحميلة والحصول عليه من هنا
2- بناء الواجهه :
سوف نستخدم " interface Builder " لإعداد الواجهه , أنت قريب جدا لمعرفة ال subviews سوف نضيفها بسبب أننا نريد إنشاء التطبيق التجريبي بأكبر درجة من الوظائف المتعددة . هذا عبارة عن سلسلة من الخطوات التي تصف كل طريقة عرض فرعية ويجب عليك إضافتها جنبا إلي جنب لكل واحده :

   1- قم بفتح ملف ViewController.xib لتكوين الواجهه وإضافة جميع subviews  اللازمة. أولا وقبل كل شىء  قم بتعيين الحجم الخاص بطريقة العرض . من Utilities Pane>Attributes inspector>Simulated Metrics وهنا نقوم بإعطاء المشروع فرصة العمل الصحيح على iphones قبل 5 .
  
    2- قم بتغيير لون الخلفية إلي الأبيض
    3- قم بسحب وإفلات UIToolbar subview فى طريقة العرض. ضعه فى الجزء السفلي من الشاشة .
    4- أضف البنود التالية على شريط الأدوات order left to right)) .
    - عنصر Bar Button مع Title:Signout عنوان تسجيل الخروج.
    - عنصر زر شريط مساحة مرنة Flexible Space Bar Button
    - عنصر زر بعنوان ووظيفه Bar Button item with TitleL:Post
    5- إضافة طريقة عرض  UlTableView subview فرعية والسماح لها بشغل كل المساحة المتوفرة على اليسار فى العرض .
   6- قم بتعيين الخاصيتين التالييتين لطريقة عرض الجداول .
   · نمط التجميع Style:Grouped
   · الخلفية لون واضح Background::Clear Color

 يجب أن تحصل على النتيجة التالية فى هذة النقطة :

بعد ذلك, أننا بحاجة إلي عرض أخر يحتوي على عرض منتقي التاريخ data picker. هنا الخطوات :

      1- إضافة طريقة عرض جديده خارج طريقة العرض الإفتراضية وتعيي حجمة ( كما فعلت من قبل) . أيضا , قم بتعيين الإرتفاع 460 .
   2- تعيين لون الخلفية بطريقة العرض إلي التمرير عرض الخلفية مزخرفة.
   3- قم بإضافة طريقة العرض UldatePicker بشكل فرعي وقم بتوسيطها وفقا للمركز الخاص بطريقة العرض.
   4- إضافة طريقة عرض ال UlToolBar فرعية فى الجزء السفلي من طريقة العرض.
   5- أضف الشريط التالي وقائمة الأدوات التالية الي شريط الأدوات .
  · ازرار القوائم بعنوان إلغاء Bar Button Item with title:Cancel
  ·  عنصر زر شريط المساحة المرن
  ·  عنصر زر شريط الأدوات بحدث كل الأيام Title:All-day event
  ·  عنصر زر شريط المساحة المرن Flexible Space Bar Button
  ·  عصر زر الأدوات ب عنوان:حسنا Title: Okay
أخيرا، أضف subviews التالية خارج العرض بشكل افتراضي وعرض المراقب 
المالي، سوف ننشأه فى العرض الثاني فقط:

  1. Subview AUIToolBar. سيكون "لعرض ملحقات الإدخال"الخاصه   ب textfield والذي سيتم استخدامه لتحرير وصف الحدث. أضف العناصر التالية لشريط الأدوات : 
  • شريط عنصر زر بعنوان: إلغاء
  • عنصر زر شريط مساحة مرنة
  • شريط عنصر زر بعنوان: حسنا
2- A UlActivitycator View والخصائص التالية :
  • النمط أبيض كبير Style: Larg White
  • الخلفية: لونها أسود Background: Black color
3- إعداد خصائص IBOutle t و IBAction .

الخطوة الأولي :
نحن بحاجة إلي بعض خصائص IB Outlet المتصل ب subviews لدينا, حيث يمكننا تعديل التعليمات البرمجية. للأتصال بخاصية IB Outlet ل subview وكذلك لإنشاء طريقة عرض فرعية و إنشاء إسلوب IBAction, أنت بحاجة الي ViewController.h سيظهر لنا فى المحرر المساعد. اذا, أنقر على الزر الأوسط لأدوات المحرر Xcode للسماح لها بالظهور. تأكد من أنه يتم عرض محتويات الملف VieController هناك .

سوف أريك كيفية إنشاء خاصية IBOutlet لعرض الجدول فقط Table View. استخدم نفس الطريقة لإنشاء خصائص subview سوف أخبرك عن الأشياء التالية .

أما فى جزء "المخطط التفصيلي للمستند" أو طريقة العرض المباشرة , قم بما يلي :
1- أنقر بزر الماوس أو أنقر على كونترول Control-Click فى طريقة عرض الجدول
2-فى القائمة السوداء المنبثقه, أنقر علي الدائرة بجانب الخيار "New Referncing Outlet"
3- أسحب وأفلت( فى نفس الوقت الخط الأزرق سوف يتبع الماوس) فى نافذة المحرر المساعد Assistant Editor  .

فى النافذة الجديدة التي تظهر, قم بإضافة tb IPostData كأسم للخاصية ولا تلمس أي خيارات أخري.أضغط على زر الإتصال أو أضغط على زر العودة إلي لوحة المفاتيح .

إليك قائمة بجميع subviews التي نحن بحاجة لها لإنشاء اتصالات ال IBOutlet,بأسمائهم .تأكد من أنك تتبع نفس الطريقة السابقة وسيكون كل شىء على ما يرام .
· وظيفة زر شريط العناصر barItemPost
· تسجيل الخروج زر شريط الأدوات : bar itemRevokeAccess
· إدخال " ملحق عرض شريط الأدوات وحده " toolbar InputAccessoryView
· عرض حاوية منتقي التاريخ : viewDataPicker
·  منتقي التاريخ : dpDataPicker
· زر أدوات البار لكل الأيام : barItemToggleDatePicker
· عرض مؤشر النشاط : activityIndicatorView
المرحلة الثانية :
كما ترون, اضفنا بعض أزرار عناصر الشريط, داخل عرضنا .نطلب منهم الرد على taps لدينا , حيث أننا بحاجة إلي إنشاء أساليب IBAction ليحدث ذلك .

إنشاء أسلوب IBAction هو نفسه تقريبا كما بينته سابقا .
    أما " المخطط التفصيلي للمستند " أو لطريقة عرض  مباشرة , أنقر بالزر الأيمن أو أنقر فوق Control على شريط البار الخاص بالأدوات .
     فى القائمة السوداء المنبثقة,تحت زر الإرسال أنقر علي الدائرة المقابلة لـ الأختيارات وابقى زر الماوس لأسفل.
    سحب وإسقاط فى نافذة المحرر المساعد Assistant Editor .


فى نافذة جديدة, أضف الوظيفة فى حقل الأسم وأترك كل شىء كما هو . أنقر فوق إتصال, أو أضغط على زر العودة فى لوحة المفاتيح.

الأن, أتبع نفس النمط وقم بإنشاء الأسلوب IBAction لـ subviews .
   1-تسجيل الخروج من شريط العناصر : revokeAccess
   2- موافقة شريط العناصر لعرض ملحقات الإدخال acceptEditingEvent
   3- ألغي شريط  العنااصر على شريط الأدوات الخاص بعرض الملحقات cancelEditingEvent
   4- موافقة زر العناصر على شريط " الأدوات الخاص بمنتقي الوقت acceptSelectedData
   5- إلغاء شريط العناصر علي شريط " الأدوات الخاص ب عرض منتقي  الوقت cancelPickingData
   6- شريط العناصر لكل الأيام على شريط الأدوات toggleDataPicker
   بعد إضافة كافة الخصائص IBOutlet وجميع أساليب IBAction الملف viewController.h الخاص بك يجب أن يكون بهذا الشكل التالي :
 @interface ViewController : UIViewController@property (weak, nonatomic) IBOutlet UITableView *tblPostData;@property (weak, nonatomic) IBOutlet UIBarButtonItem *barItemPost;@property (weak, nonatomic) IBOutlet UIBarButtonItem *barItemRevokeAccess;@property (strong, nonatomic) IBOutlet UIToolbar *toolbarInputAccessoryView;@property (strong, nonatomic) IBOutlet UIView *viewDatePicker;@property (weak, nonatomic) IBOutlet UIDatePicker *dpDatePicker;@property (weak, nonatomic) IBOutlet UIBarButtonItem *barItemToggleDatePicker;@property (strong, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicatorView;  - (IBAction)post:(id)sender;- (IBAction)revokeAccess:(id)sender;- (IBAction)acceptEditingEvent:(id)sender;- (IBAction)cancelEditingEvent:(id)sender;- (IBAction)acceptSelectedDate:(id)sender;- (IBAction)cancelPickingDate:(id)sender;- (IBAction)toggleDatePicker:(id)sender; @end
   4- أعتماد البروتوكولات :

الخطوة الأولي ..

والأن بعد أن تم إعداد الواجهه وتكوينها وخصائص IBOutlet جنبا إلي جنب مع الأسلوب IBAction التي أنشئت وأتصلت . حان الوقت للبدء فى كتابة بعض التعليمات البرمجية . فى السابق لقد أضفنا رأس GoogleOAuth وملفات التنفيذ لكن هذا لا يكفي لجعل الفئة تعمل . نحن ايضا بحاجة لأستيراد  فئة عرض التحكم view controller و اعتماد البروتوكول .

قم بفتح ملف ViewController.h وقم بأستيراد الملف GoogleOAuth.h فى أعلي الملف .
#import <UIKit/UIKit.h>#import "GoogleOAuth.h"
الخطوة الثانية :  

بالإضافة الي بروتوكولات فئة GoogleOAuth.h, نحن بحاجة إلي أعتماد ما يلي أيضا :
·  UlTableViewDelegate:the delegate of the table view المندوب من طريقة عرض الجدول
·  UlTable ViewData source:thedatasource of the table view. مصدر البيانات فى طريقة عرض الجدول
·ULTextFieldDelegate:  والذي سيتم تحريره لوصف الحدث

لذا, بينما لا يزال داخل الملف ViewController.h الملف يتم تغيير عبارة @interface مثل هذا :
@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate, GoogleOAuthDelegate> 
   5- تعريف الخصائص الخاصة & الأساليب

الخطوة الأولي : 

هناك بعض الخصائص وبعض الأساليب. التي ينبغي إعلانها فى قسم خاص للفئة المطلوبة لجعل كل شىء يعمل على نحو سلس, هذه الخصائص غالبا تقوم بتخزين معلومات التطبيق, لكن بعض الإشارات البسيطة تستخدم أيضا للإشارة إلى حالة البرنامج .

الكود القادم يعرض أجزاء التعليمات وجميع بيانات الأعضاء الخاصة, يجب عليك أضافتة للمشروع الخاص بك (نسخهم ولصقهم إذا كنت تريد) التعليقات تشرح كل شىء . لا تنسوا أننا نعمل الأن فى ملف View Controller.m
 @interface ViewController () // The string that contains the event description.// Its value is set every time the event description gets edited and its// value is displayed on the table view.@property (nonatomic, strong) NSString *strEvent; // The string that contains the date of the event.// This is the value that is displayed on the table view.@property (nonatomic, strong) NSString *strEventDate; // This string is composed right before posting the event on the calendar.// It's actually the quick-add string and contains the date data as well.@property (nonatomic, strong) NSString *strEventTextToPost; // The selected event date from the date picker.@property (nonatomic, strong) NSDate *dtEvent; // The textfield that is appeared on the table view for editing the event description.@property (nonatomic, strong) UITextField *txtEvent; // This array is one of the most important properties, as it contains// all the calendars as NSDictionary objects.@property (nonatomic, strong) NSMutableArray *arrGoogleCalendars; // This dictionary contains the currently selected calendar.// It's the one that appears on the table view when the calendar list// is collapsed.@property (nonatomic, strong) NSDictionary *dictCurrentCalendar; // A GoogleOAuth object that handles everything regarding the Google.@property (nonatomic, strong) GoogleOAuth *googleOAuth; // This flag indicates whether the event description is being edited or not.@property (nonatomic) BOOL isEditingEvent; // It indicates whether the event is a full-day one.@property (nonatomic) BOOL isFullDayEvent; // It simply indicates whether the calendar list is expanded or not on the table view.@property (nonatomic) BOOL isCalendarListExpanded; @end
أضف تعريف الأسلوب بعد الخصائص وقبل @End 

الخطوة الثانية : 

بعد أن أعلنا عن كل هذه الخصائص, دعونا نفعل بعض التهيئة. وسيتم ذلك علي viewDidLoad:method لاحظ أن فى هذا الأسلوب  أيضا قمنا بتعيينه كمندوب ومصدر للبيانات فى طريقة عرض الجدول .
 - (void)viewDidLoad{    [super viewDidLoad];         // Set self as the delegate and datasource of the table view.    [_tblPostData setDelegate:self];    [_tblPostData setDataSource:self];         // Set the initial values of the following private properties.    _strEvent = @"";    _strEventDate = @"Pick a date...";    _isEditingEvent = NO;    _isFullDayEvent = NO;    _isCalendarListExpanded = NO;         // Initialize the googleOAuth object.    // Pay attention so as to initialize it with the initWithFrame: method, not just init.    _googleOAuth = [[GoogleOAuth alloc] initWithFrame:self.view.frame];    // Set self as the delegate.    [_googleOAuth setGOAuthDelegate:self];
    6- يعرض الجدول مصدر البيانات و أسلوب المندوب .

 دعونا نستمر بكتابة بعض datasource  وتفويض الأساليب المتصلة بطريقة عرض الجدول, فى الوقت الحاضر, سنقوم بإضافة بعض التعليمات البرمجية القياسية فقط سوف نتحرك اليها , دعونا نمى قدما . كما قلت فى البداية, هناك ستكون ثلاثة أقسام فى طريقة عرض الجدول :
 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{    return 3;}
كل مقطع سوف يحتوي على صف واحد. لثلاثة أجزاء, سيكون لدينا العديد من الصفوف كدعم للتقويمات. بإستخدام هذا الأسلوب, يمكنك أن تري كيف يتم إستخدام علامة isCalandarListExpanded_ للمرة الأولي
 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{        if (section != 2) {        return 1;    }    else{        // Depending on whether the calendars are listed in the table view,        // the respective section will have either one row, or as many as the calendars are.        if (!_isCalendarListExpanded) {            return 1;        }        else{            return [_arrGoogleCalendars count];        }    }}
دعونا نضيف بعض العناوين, بغية جعل التطبيق التجريبي لدينا أكثر وصفية . ليس هناك شىء صعب هنا :
 -(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{    // Set the footer title depending on the section value.    NSString *footerTitle = @"";    if (section == 0) {        footerTitle = @"Event short description";    }    else if (section == 1){        footerTitle = @"Event date";    }    else{        footerTitle = @"Google Calendar";    }         return footerTitle;}
قم بتعيين أرتفاع لكل خلية :
 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{    return 50.0;}
 فيما يتعلق بالأسلوب tableView:cellForRowAtIndexPath: datasource, سيجعلنا هذا نقوم ببناءة خطوة بخطوة. بينما نقوم بإضافة وظائف أكثر للتطبيق, دعونا نكتب فقط الأساسيات :
 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    static NSString *CellIdentifier = @"Cell";    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier];         if (cell == nil) {        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];                 [cell setSelectionStyle:UITableViewCellSelectionStyleGray];        [cell setAccessoryType:UITableViewCellAccessoryNone];              // Set a font for the cell textLabel.        [[cell textLabel] setFont:[UIFont fontWithName:@"Trebuchet MS" size:15.0]];    }             return cell;}
وأخيرا, لدينا أسلوب مندوب واحد فقط delegate method  كالمعروف tableView:didSelectRowAtIndexPath: تماما مثل سابقتها , وهذا ايضا يجعلنا نبنيها خطوة بخطوة الأن, هي فقط تقوم بإزالة التحديد من كل صف من الصفوف التى يتم استغلالها فقط .
 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{    // At first, remove the selection from the tapped cell.    [[_tblPostData cellForRowAtIndexPath:indexPath] setSelected:NO];}
    7- التعديل على وصف الحدث
    الخطوة الأولي :

حتي الأن, قلت مرات عديدة أن textfield سوف تظهر على عرض الجداول فى كل مرة نريد تغيير وصف الحدث . ومع ذلك عدما لا نقوم بتحرير , textfield ينبغى أن لا تظهر . سوف نقوم بتحديث وصف الحدث وجعل textfield تذهب بعيدا .

قل أن نأتي على هذا السلوك فى الحياة, قد يكون من الأفضل تنفيذ الأسلوب الخاص الذي قد أعلنا عنه. setupEventTextfield فى هذا الأسلوب سوف نقوم بالمهام التالية :

  • سوف نقوم بتهيئة textfield بوضع خاصية الإطار لعرض محتوي الخليه وأيضا لتعيين النمط.
  • سوف نقوم بتعيين محتويات السلسلة strEvent كنص .
  • هل تتذكر شريط الأدوات الذي قمنا بإضافتة مفردا فى واجهة البناء فى وقت سابق 
  • نحن سوف نضعه كإدخال تبعي . يعرض من textfield .سوف نقوم بتعيين self كمندوب حتى نستطيع التعامل مع المفتاح Return من لوحة المفاتيح.
دعونا نري ذلك :
-(void)setupEventTextfield{    // Initialize the textfield by setting the following properties.    // Add or remove properties depending on your demand.    if (!_txtEvent) {        _txtEvent = [[UITextField alloc] initWithFrame:CGRectMake(10.0, 10.0,                                                                  [[_tblPostData cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]] contentView].frame.size.width - 20.0,                                                                  30.0)];        [_txtEvent setBorderStyle:UITextBorderStyleRoundedRect];        [_txtEvent setText:_strEvent];        [_txtEvent setInputAccessoryView:_toolbarInputAccessoryView];        [_txtEvent setDelegate:self];    }}

الخطوة الثانية :

الأن هذا الأسلوب على استعداد ويمكننا أن نستدعية فى أى وقت  نريد تهيئة textfield, دعونا نري كيف يمكننا تنفيذ السلوك , ونتوقع طريقة عرض الجدول. أننر نريد عرض textfield فى كل مرة نقوم بالضغط على صفوف القسم الأول, لذلك دعونا نفعل ذلك .

داخل  tableView:didSelectRowAtIndexPath: سوف نتحقق إذا كان الحدث يتم تحريره حاليا . أذا لا سنقوم بإستدعاء الأساليب المنفذة سابقا لتهيئة textfield, سوف نقوم بتغيير حالة العلامة التى تشر إلي ما كان يتم تحرير الحدث أم لا وسوف نعرض لوحة المفاتيح .
 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{    // At first, remove the selection from the tapped cell.    [[_tblPostData cellForRowAtIndexPath:indexPath] setSelected:NO];         if ([indexPath section] == 0) {        // If the row of the first section is tapped, check whether the event description is being edited or not.        // If not, then setup and show the textfield on the cell.        if (!_isEditingEvent) {            [self setupEventTextfield];        }        else{            return;        }                 // Change the value of the isEditingEvent flag.        _isEditingEvent = !_isEditingEvent;        // Reload the selected row.        [_tblPostData reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]                            withRowAnimation:UITableViewRowAnimationAutomatic];                 // If the textfield has been added as a subview to the cell,        // then make it the first responder and show the keyboard.        if (_isEditingEvent) {            [_txtEvent becomeFirstResponder];        }    }    }
الخطوة الثالثة :

الأن دعونا نقوم بتحديث tableView:cellForRowAtIndexPath: حيث أنه يعكس حالة المقطع الأول فى أى وقت من الأوقات :
 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    ...    ...    ...    if ([indexPath section] == 0) {        if (!_isEditingEvent) {            // If currently the event description is not being edited then just show            // the value of the strEvent string and let the cell contain a disclosure indicator accessory view.            // Also, set the gray as the selection style.            [[cell textLabel] setText:_strEvent];            [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];            [cell setSelectionStyle:UITableViewCellSelectionStyleGray];        }        else{            // If the event description is being edited, then empty the textLabel text so as to avoid            // having text behind the textfield.            // Add the textfield as a subview to the cell's content view and turn the selection style to none.            [[cell textLabel] setText:@""];            [[cell contentView] addSubview:_txtEvent];            [cell setSelectionStyle:UITableViewCellSelectionStyleNone];        }    }}
عظيم إذا قمت بتشغيل التطبيق الأن, ستلاحظ أن textfield تظهر فى عرض الجداول الخاصة بالقسم الأول . ومع ذلك لا يمكنك جعل textfield تتلاشي وتحافظ على القيمة التي تم تحريرها . لماذا ؟ لأننا بحاجة الي تنفيذ أساليب العرض التبعي ذات الصلة ب  زر شريط العناصر IBAction .

الخطوة الرابعة :

دعونا نبدأ بأسلوب acceptEditingEvent:iBAction سوف نبقي على وصف الحدث  فى هذا الأسلوب سوف نبقي على وصف الحدث المكتوب على السلسلة strEvent, سنقوم بتغيير القيمة isEditingEvent للأعلام, سوف نجعل لوحة المفاتيح تختفي, وسنقوم بتحديث طريقة عرض الجدول هنا :
- (IBAction)acceptEditingEvent:(id)sender {    // If the strEvent property is already initialized then set its value to nil    // as it's going to be re-allocated right after.    if (_strEvent) {        _strEvent = nil;    }         // Keep the text entered in the textfield.    _strEvent = [[NSString alloc] initWithString:[_txtEvent text]];     // Indicate that no longer the event description is being edited.    _isEditingEvent = NO;         // Resign the first responder and make the textfield nil.    [_txtEvent resignFirstResponder];    [_txtEvent removeFromSuperview];    _txtEvent = nil;     // Reload the row of the first section of the table view.    [_tblPostData reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]]                        withRowAnimation:UITableViewRowAnimationAutomatic];}

cancelEditingEvent: مماثل
 - (IBAction)cancelEditingEvent:(id)sender {    // Indicate that no longer the event description is being edited.    _isEditingEvent = NO;         // Resign the first responder.    [_txtEvent resignFirstResponder];    [_txtEvent removeFromSuperview];    _txtEvent = nil;         // Reload the first row of the first section of the table view.    [_tblPostData reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]]                        withRowAnimation:UITableViewRowAnimationAutomatic];}
الخطوة الخامسة : 

كي تكون كامل تماما من ناحية كل ما يتعلق ب textfield وتحرير وصف الحدث بشكل عام, لدينا شىء واحد أخر نريد القيام به. الا وهي أننا يجب أن نتعامل مع زر العودة إلي لوحة المفاتيح Return Button وجعله يعمل تماما مثل acceptEditing:IBAction:IBAction , ولهذا السبب سننفذ أسلوب التفويض التالي :
 -(BOOL)textFieldShouldReturn:(UITextField *)textField{    // In case the Return button on the keyboard is tapped, call the acceptEditingEvent: method    // to handle it.    [self acceptEditingEvent:nil];    return YES;}
كما تري نحن ببسأطة أجرينا مكالمة إلي الأسلوب IBAction لا أكثر ولا أقل, نحن الأن  100 بالمئة أكملنا  تحرير الحدث والتلاعب ب textfield  .

    8- اختيار موعد الحدث :
    الخطوة الأولي

جزء واحد من التطبيق التجريبي لدينا كامل. دعونا نمضي قدما الأن ودعونا نطبق ميزة الأنتقاء للتاريخ المستقبلي . وفى هذه الحالة, ما نريده عندما ضغطنا على صف الفرع الثاني من عرض الجداول, لإظهار محتوي منتقي التاريخ data picker ومن خلالة أخترنا وحددنا التاريخ, وبعد ذلك نريد تاريخ المنتقاة ليتم عرضه في عرض الجداول كذلك ينبغي إيلاء عناية خاصة لأنه يمكن تعيين حدث لوقت محدد, ولكن يمكن أيضا أن يكون حدث لكل الأيام . مما يعنى أن اختيار وقت ليس له نقطة محدده على الإطلاق, سنري كل هذا فى القادم .

دعونا نبدأ بعرض حاوية منتقي التاريخ data picker لـ self.views . إنها مجرد مسألة سطر واحد فقط , والتى ينبغي أن تكون مكتوبة فى tableView:didSelectRowAtindexPath: لتفويض الأسلوب ’ تحت أي محتوي أخر له حتى الأن .
 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{    ...    ...    else if ([indexPath section] == 1){        // If the row of the second section is tapped, just show the view that contains the date picker.        [self.view addSubview:_viewDatePicker];    }}
الخطوة الثانية

حسنا, هذا هو الجزء السهل . إذا قمت بتشغيل التطبيق الأن وضغط على الصف فى القسم الثاني, سيتم عرض حاوية منتقي التاريخ على الشاشة, ستلاحظ أنه من الأفتراضي. كل من الوقت والتاريخ يتم تمثيلهم فى المنتقي . هذا لطيب جدا إذا كنا نريد تعيين وقت محدد لحدث معين ومع ذلك , ينبغي الا ندع الوقت يظهر فى منتقي التاريخ إذا تحدثنا عن حدث لكل الأيام . ولذلك نحن بحاجة إلي تنفيذ أسلوب toggleDataPicker:IBAction .

أن طريقة هذا الأسلوب فى العمل بسيطة إلي حد ما . اعتمادا على المحتويات فى منتقي التاريخ الحالي, سوف نقوم بتعيين طريقة عملها ونقوم أيضا بتغيير عنوان كل شريط لزر العنصر. لا تنسي أن هناك علامة كذلك . للمتغير isFullDayEvent , التي ينبغي أن تتغير تبعا لذلك التالي هو للتنفيذ :
- (IBAction)toggleDatePicker:(id)sender {    if ([_dpDatePicker datePickerMode] == UIDatePickerModeDateAndTime) {        // If the date picker currently shows both date and time, then set it to show only date        // and change the title of the barItemToggleDatePicker item.        // In this case the user selects to make a full-day event.        [_dpDatePicker setDatePickerMode:UIDatePickerModeDate];        [_barItemToggleDatePicker setTitle:@"Specific time"];    }    else{        // Otherwise, if only date is shown on the date picker, set it to show time too.        // The event is no longer a full-day one.        [_dpDatePicker setDatePickerMode:UIDatePickerModeDateAndTime];        [_barItemToggleDatePicker setTitle:@"All-day event"];    }         // Change the flag that indicates whether is a full-day event or not.    _isFullDayEvent = !_isFullDayEvent;}
أعطها محاولة أخري أنقر أو (أضغط فوق جهاز المحاكاة simulator ) في كل أيام الحدث على شريط الادوات . لاحظ كيف تحصل على تغيير محتويات منتقي التاريخ , جنبا إلي جانب عنوان الزر .

الخطوة الثالثة :

نحن نعرف الأن متي يتم تعيين حدث لكل الأيام , ولكن لا نزال غير قادرين على الإحتفاظ بالتاريخ المحدد وجعله يظهر في طريقة عرض الجدول . وبالمثل لا يمكنناحتي الأن إلغاء إنتقاء التاريخ والعودة إلى وجهة نظرنا .

لذا دعونا نعمل علي كل أساليب IBAction  الأن .

في أسلوب acceptSelectedDate:IBAction نحن نحتاج إلي القيام أربعة أشياء : (1) الحفاظ على التاريخ المحدد كسلسلة, (2) تخزين التاريخ كمشروع NSDate (3) إزالة طريقة العرض من superview , واخيرا (4) إعادة تحميل جداولنا لإظهار التاريخ المحدد .
- (IBAction)acceptSelectedDate:(id)sender {    // Keep the selected date as a NSDate object.    _dtEvent = [_dpDatePicker date];    // Also, convert it to a string properly formatted depending on whether the event is a full-day one or not    // by calling the getStringFromDate: method.    _strEventDate = [[NSString alloc] initWithString:[self getStringFromDate:[_dpDatePicker date]]];         // Remove the view with the date picker from the self.view.    [_viewDatePicker removeFromSuperview];         // Reload the row of the second section of the table view to reflect the selected date.    [_tblPostData reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:1]]                        withRowAnimation:UITableViewRowAnimationAutomatic];}
في أسلوب cancelPickingDate:IBAction نحتاج فقط إلي إزالة طريقة عرض حاوية منتقي التاريخ من superview.
 - (IBAction)cancelPickingDate:(id)sender {    // Just remove the view with the date picker from the superview.    [_viewDatePicker removeFromSuperview];}
الخطوة الرابعة :

فى أسلوب acceptSelectedDate قمنا بدعوة getStringFromDate: كأسلوب خاص. والذي أعلنا عنه لكن لم يتم ينفذ حتي الأن . الان حان الوقت للعمل بهذا الأسلوب قبل أن أقدم الكود , ينبغي إجراء مراقبة .

والغرض من getStringFromDate  هو أسلوب الحصول على التاريخ الذى قدمناه (التاريخ المحدد فى مثالنا) ولإعادة التاريخ ك سلسلة وتنسيقة بالطريقة التي نريدها , ومع ذلك هناك نوعين من تنسيقات السلسلة نحن بحاجة اليها يرجع إلي ما إذا كان الحدث هو حدث يوم كامل أو إذا كان تاريخ الحدث وقت محدد . نحن نريد هذه المرة أن يكون حاضرا فى السلسلة . وخذا يعنى أنه سيكون لدينا شرط فى أسلوبنا سيحدد ماذا سيكون شكل سلسلة الإنتاج لذا , بعد أن جعلنا كل شىء واضح . أدخل التعليمية البرمجية التالية :
-(NSString *)getStringFromDate:(NSDate *)date{    // Create a NSDateFormatter object to handle the date.    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];         if (!_isFullDayEvent) {        // If it's not a full-day event, then set the date format in a way that contains the time too.        [formatter setDateFormat:@"EEE, MMM dd, yyyy, HH:mm"];    }    else{        // Otherwise keep just the date.        [formatter setDateFormat:@"EEE, MMM dd, yyyy"];    }         // Return the formatted date as a string value.    return [formatter stringFromDate:date];}
ما ورد أعلاه سوف يعطينا شيئا مثل " الأثنين 12 أغسطس 2013, 17:32

لمزيد من المعلومات حول التاريخ والرموز المستخدمة هنا وأي رموز أخرى موجودة, ألقى نظره عاملة على "أنماط تنسيق التاريخ".

ملاحظة : ضع فى الأعتبار أنه يجب تغيير رمز التاريخ في النظام للتطبيق الحقيقي ليتطابق ويمثل تاريخ بلدك .

الخطوة الخامسة :

حتي الان جيد جدا : شىء واحد فقط بقي لنقوم به . إضافة بعض التعليمات البرمجيه في tableView:cellForRowAtindexPath: حيث سيتم عرض التاريخ المحدد تحت كافة محتويات الأساليب الأخري, إضافة إلي أجزاء التعليمات البرمجية المتكرره تاليا :
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    ...    ...    ...    else if ([indexPath section] == 1){        // In the event date cell just show the strEventDate string which either prompts the user        // to pick a date, or contains the selected date as a string.        // Also, add a disclosure indicator view.        [[cell textLabel] setText:_strEventDate];        [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];    }     return cell;}
   9- إذن التطبيق
   إذا قمت مسبقا بتشغيل التطبيق, أو إذا كنت تفعل ذلك الأن, ستلاحظ أن الصف فى الجزء الثالث من عرض الجدول يحتوي على تنزيل التقويمات .. رسالة . بطبيعة الحال لا شىء يحدث عنما تضغط على هذا الأسلوب . ما نود القيام به هو إن نجعل API  يستدعي Google  ويطلب المعلومات التى نحن بحاجة إليها . ولكن, قبل ذلك يجب علينا أن نأذن لأنفسنا خدمة جوجل والحصول على الرمز المميز الذي نستخدمة لتبادل اليبانات . فى الواقع , كل هذا سوف يتم بواسطة فئة Google:Outh التى جلبناها مبكرا . كل ما علينا فعلة هو القيام بتقديم هذه الفئة Client ID , وسر العميل Client Secret والنطاق, لذا دعونا نقوم بزيارة موقع مطوري جوجل والحصول على كافة القيم التى نحن بحاجة إليها .

الخطوة الأولي

 الذهاب إلي موقع Google  المطور . أنقر فوق زر "تسجيل الدخول" الموجود على الجانب الأيمن العلوي من صفحة الويب لتسجيل الدخول .



بعد أن سجلت الدخول , قم بالتمرير إلي أسفل الصفحة حتي تقوم بتحديد موقع رمز وحدة التحكم Consol API .



أنقر فوقها , وسوف تنتقل إلي لوحة التحكم الخاصة بك, حيث يمكنك التعامل مع جميع المشاريع الخاص بك, إذا كان يجب أن تقوم بإنشاء مشروع الأن. خلاف ذلك حدد المشروع الذي قمت بإنشاءه من الدروس السابقة فى هذه السلسلة . من القائمة على الجانب الأيسر من صفحة الويب, أنقر فوق خيار Access API .

سيتم عرض تفاصيل حول المشروع الحالي على الجانب الأيمن من الصفحة هناك, يمكنك تعقب client id و client secret value التى سوف تحتاج اليها , احفظهم, ودعونا نمضي قدما .


بعد ذلك نحن بحاجة إلي إعلام Google بأننا نريد أن نستخدم خدمة التقويمات calendars للقيام بذلك. أنقر فوق خيار الحدمات فى القائمة الجانبية على الأيسر من صفحة الويب . سوف تظهر قائمة بجميع الخدمات المقدمه . حدد موقع العنصر Calandar API . وأنقر فوق الزر إيقاف التشغيل لتمكين الخدمة المحددة للمشروع الحالي.

الخطوة الثانية :

ما لم نقع علية حتى الأن , هو نطاق القيمة من أجل الحصول على معلومات التقويم أنا بحاجه فقط إلي تذكيرك, API هو طلب التطبيق للوصول الي النطاق  لتحديد موقع ما تريده, إستخدم محرك البحث Google المطور . ثم أنتقل إلى الصفحة الرئيسية لموقع المطول جوجل وابحث عن المصطلح Google Calendar API . فى صفحة النتائج أنقر فوق النتيجة الأولي .

لنأخذ نظرة حولنا, إذا كنت تريك استكشاف وأستخدام القوائم  لهذا البرنامج التعليمي , يجب عليك أن تذهب إلى Reference>Calendar List>List . يتم تحميل صفحة ويب جديدة , التي تحتوي على معلومات حول إستدعاء قوائم التقويم API . والعثور على منطقة الإذن بالقرب من الجزء السفلي من الصفحة . يمكنك العثور على نطاق نحن بحاجة إلية  https://www.googleapis.com/auth/calendar


الخطوة الثالثة : 

عليكم كيف يمكنك تمكين خدمة Google وأفضل طريقة للعثور على ما تحتاجة من موقع ويب المطور الأن , ونحن يمكن أن نبقي بناء التطبيق .

الأن أن لدينا إمكانية الوصول إلي جميع البيانات التي نحتاجها من Google دعونا نعود إلي التطبيق لدينا ومعرفة كيفية إستخدام المعلومات . بإلحاق التعليمية البرمجية التالية لمشروعنا .

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    ...
    ...
    ...
    else if ([indexPath section] == 2){
        if (_arrGoogleCalendars == nil || [_arrGoogleCalendars count] == 0) {
            // If the arrGoogleCalendars array is nil or contains nothing, then the calendars should be
            // downloaded from Google.
            // So, show the activity indicator view and authorize the user by calling the the next
            // method of our custom-made class.        
            [self showOrHideActivityIndicatorView];
            [_googleOAuth authorizeUserWithClienID:@"YOUR_CLIENT_ID"
                                   andClientSecret:@"YOUR_CLIENT_SECRET"
                                     andParentView:self.view
                                         andScopes:[NSArray arrayWithObject:@"https://www.googleapis.com/auth/calendar"]];
        }
}
سنلاحظ أن أعلاه نحن نعرض مؤشر العرض , وكذلك نفعل هذا لأننا لا نعرف كم من الوقت سوف يستغرق للحصول على الترخيص. لا تنسي تعيين القيم الخاصة بك ل client id و client secret .


عند أستخدام التطبيق للمرة الاولي, سوف تظهر لك طريقة عرض مضمون الويب . يجب إدخال بيانات إعتمادك وتسجيل الدخول إلي الحساب Google  الخاص بك للسماح للتطبيق للوصول إلي التقويم الخاص بك إذا كان كل شىء يسير على مايرام , سوف يؤذن لك دون مشكلة .

االخطوة العاشرة : قم بتحميل بيانات التقويم Calender

االخطوة الأولي :

عند هذه النقطة , نحن بحاجة إلي تنفيذ بعض الأساليب لمندوب GoogleOAuth دعونا نبدأ بطريقة authorizationWasSuccessful, حيث أننا سوف نتعامل مع تصاريح ناجحة بإستدعاء API للحصول على قائمة التقويم .

ومع ذلك , نحن بحاجة إلي سلسلة عناوين URL API إذا كنا نريد المضي قدما . إنتقل إلي صفحة قائمة التقويم السليم فى حساب Google المطور الخاص بك . فى الجزء العلوي من الصفحة ستجد عنوان url الخاضص بك جنبا إلي جنب بإسلوب HTTP التي يجب إستخدامه .

الأن يمكن أن ننفذ أسلوب التفويض :
-(void)authorizationWasSuccessful{    // If user authorization is successful, then make an API call to get the calendar list.    // For more infomation about this API call, visit:    // https://developers.google.com/google-apps/calendar/v3/reference/calendarList/list    [_googleOAuth callAPI:@"https://www.googleapis.com/calendar/v3/users/me/calendarList"           withHttpMethod:httpMethod_GET       postParameterNames:nil      postParameterValues:nil];}
المرحلة الثانية :

إذا كان كل شىء يعمل وفقا للخطة
سيتم إستدعاء الإسلوب المفوض responseFromServiceWasReceived:andResponseJSONAsData:  سيتم إستدعاء الإسلوب المفوض من قبل فئة GoogleOAuth .  نحن مسئولون للتحقق إذا إستجابت جوجل مع النتائج المرجوة, ومن ثم للحفاظ على البيانات التى نحن نهتم بها فقط .

دعونا نناقش بعض الأشياء عن ما هي محتويات الإستجابة وكيف نحن ذاهبون إلي إدارة البيانات . ما ينبغي أن نفعله أولا تحويل بيانات الإستجابة JSON إلي كائن NSDictionary إذا كنت الكائن NSLog , سنري طريقة تشكل البيانات التي يتم إرجاعها كما فى المثال التالي :
{etag = "\"AaJWGrGt8CrZSonQa3iAA4QAo_s/oZDiRXBvAIXr3JkNwKQRZZfQzQ4\"";    items =     (                { … }        { … }        { … }    );    kind = "calendar#calendarList";}
داخل كل قوس متعرج كتلة تحتوي على مجموعة من المعلومات المتعلقة بكل تقويم قمت بإنشاءة فى "Google Celander يساوي كائن عنصر صفيف يحتوي على قواميس الكائنات . وبعبارة أخري نحن نستخرج العنصر الكائن NSArray وسوف نعالج كل كائن لوحدة ككائن NSDictionary

دعونا نعود إلي المسار مرة أخري , متي يمكننا الحصول على تفاصيل كل تقويم سوف نبقى القيم التي نريدها لأغراض فى هذا المثال كمثال حقيقي , نحن ذاهبون إلي إنشاء قيمة المفتاح مع هذة القيم مع الهدف المتمثل فى خلق NSDictionaries الذي سيتم تخزينة فى الصفيف arrGoogleCalendars . هذا الصفيف هو قائمة التقويم للتطبيق لدينا . أيضا , سيتم تهيئة القاموس dictCurrentCalendar مع محتويات الجدول الزمني الأول من القائمة . متي تم ذلك سوف يصبح تمكين العناصر هو وظيفة تسجيل الخروج. ونحن أيضا سوف نخفي عرض مؤشر النشاط وتحديث الجدول لإظهار التقويم المحدد .

هذا هو الرمز :
-(void)responseFromServiceWasReceived:(NSString *)responseJSONAsString andResponseJSONAsData:(NSData *)responseJSONAsData{    NSError *error;         if ([responseJSONAsString rangeOfString:@"calendarList"].location != NSNotFound) {        // If the response from Google contains the "calendarList" literal, then the calendar list        // has been downloaded.                 // Get the JSON data as a dictionary.        NSDictionary *calendarInfoDict = [NSJSONSerialization JSONObjectWithData:responseJSONAsData options:NSJSONReadingMutableContainers error:&error];                 if (error) {            // This is the case that an error occured during converting JSON data to dictionary.            // Simply log the error description.            NSLog(@"%@", [error localizedDescription]);        }        else{            // Get the calendars info as an array.            NSArray *calendarsInfo = [calendarInfoDict objectForKey:@"items"];             // If the arrGoogleCalendars array is nil then initialize it so to store each calendar as a NSDictionary object.            if (_arrGoogleCalendars == nil) {                _arrGoogleCalendars = [[NSMutableArray alloc] init];            }                         // Make a loop and get the next data of each calendar.            for (int i=0; i<[calendarsInfo count]; i++) {                // Store each calendar in a temporary dictionary.                NSDictionary *currentCalDict = [calendarsInfo objectAtIndex:i];                                                                  // Create an array which contains only the desired data.                NSArray *values = [NSArray arrayWithObjects:[currentCalDict objectForKey:@"id"],                                   [currentCalDict objectForKey:@"summary"],                                   nil];                // Create an array with keys regarding the values on the previous array.                NSArray *keys = [NSArray arrayWithObjects:@"id", @"summary", nil];                                 // Add key-value pairs in a dictionary and then add this dictionary into the arrGoogleCalendars array.                [_arrGoogleCalendars addObject:                 [[NSMutableDictionary alloc] initWithObjects:values forKeys:keys]];            }                         // Set the first calendar as the selected one.            _dictCurrentCalendar = [[NSDictionary alloc] initWithDictionary:[_arrGoogleCalendars objectAtIndex:0]];                         // Enable the post and the sign out bar button items.            [_barItemPost setEnabled:YES];            [_barItemRevokeAccess setEnabled:YES];                         // Stop the activity indicator view.            [self showOrHideActivityIndicatorView];                         // Reload the table view section.            [_tblPostData reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:2]]                                withRowAnimation:UITableViewRowAnimationAutomatic];        }    }}
الخطوة الثالثة :

الأن بعد أن قمنا بكل ما سبق, نحن نريد أن ننتقل إلي calendar name  لنحصل على القائمة كاملة . وقد يسمح لنا بتحديد تقويم أخر . سيتم ذلك في أسلوب  tableView:didSelectRowAtIndexPath: إضافة إلى التعليمات البرمجية المتكررة التالية :
 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{        ...        ...        ...        else{            // In this case the calendars exist in the arrGoogleCalendars array.            if (_isCalendarListExpanded) {                // If the calendar list is shown on the table view, then the tapped one shoule become the selected calendar.                // Re-initialize the dictCurrentCalendar dictionary so it contains the information regarding the selected one.                _dictCurrentCalendar = nil;                _dictCurrentCalendar = [[NSDictionary alloc] initWithDictionary:[_arrGoogleCalendars objectAtIndex:[indexPath row]]];            }                         // Change the value of the isCalendarListExpanded which indicates whether only the selected calendar is shown, or the            // whole list.            _isCalendarListExpanded = !_isCalendarListExpanded;             // Finally, reload the section.            [_tblPostData reloadSections:[NSIndexSet indexSetWithIndex:2]                        withRowAnimation:UITableViewRowAnimationAutomatic];        }    }     }
الخطوة الرابعة :  

وأخيرا, نحن بحاجة إلي تحديث tableView:cellForRowAtIndexPath: لعرض كل ما قمنا به. ألحق البرمجية التعليمية التالية :
 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    ...    ...    ...    else if ([indexPath section] == 2){        // This is the case where either the selected calendar is shown, or a list with all of them.        if (!_isCalendarListExpanded) {            // If the calendar list is not expanded and only the selected calendar is shown,            // then if the arrGoogleCalendars array is nil or it doesn't have any contents at all prompt            // the user to download them now.            // Otherwise show the summary (title) of the selected calendar along with a disclosure indicator.            if (![_arrGoogleCalendars count] || [_arrGoogleCalendars count] == 0) {                [[cell textLabel] setText:@"Download calendars..."];            }            else{                [[cell textLabel] setText:[_dictCurrentCalendar objectForKey:@"summary"]];            }                         [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];        }        else{            // This is the case where all the calendars should be listed.            // Note that each calendar is represented as a NSDictionary which is read from the            // arrGoogleCalendars array.            // If the calendar that is shown in the current cell is the already selected one,            // then add the checkmark accessory type to the cell, otherwise set the accessory type to none.            NSDictionary *tempDict = [_arrGoogleCalendars objectAtIndex:[indexPath row]];            [[cell textLabel] setText:[tempDict objectForKey:@"summary"]];                         if ([tempDict isEqual:_dictCurrentCalendar]) {                [cell setAccessoryType:UITableViewCellAccessoryCheckmark];            }            else{                [cell setAccessoryType:UITableViewCellAccessoryNone];            }        }    }         return cell;}
هذا كل شىء شاهد التقويم الخاص بك على جهاز المحاكاة Simulator والألتفاف لفترة من الوقت بتوسيع قائمة التقويم Google Calendar والقوائم المحددة !

11-نشر الجدول الزمني للأحداث

الخطوة 1

دعونا نرى كيف سنتمكن من إضافة حدث إلي التقويم المحدد أول شىء ما تفعلة هو التأكد من أنك قمت بتعيين وصف الحدث وتاريخ الحدث . للتحقق من هذا , وسوف نتحقق من القيم وسنعرض تنبية إذا كان هناك شىء خاطىء.

عملنا الأن. سيعقد فيما بعد لأسلوب IBAction :
- (IBAction)post:(id)sender {    // Before posting the event, check if the event description is empty or a date has not been selected.    if ([_strEvent isEqualToString:@""]) {        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@""                                                        message:@"Please enter an event description."                                                       delegate:self                                              cancelButtonTitle:nil                                              otherButtonTitles:@"Okay", nil];        [alert show];        return;    }         if ([_strEventDate isEqualToString:@"Pick a date..."]) {        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@""                                                        message:@"Please select a date for the event."                                                       delegate:self                                              cancelButtonTitle:nil                                              otherButtonTitles:@"Okay", nil];        [alert show];        return;    }     ...}
سوف تلاحظ ببساطة أننا تحققنا ما إذا كانت سلسلة وصف الحدث مساوية لسلسلة الفراغ إذا كانت تساوي القيمة الأولي لسلسلة تاريخ الحدث .

الخطوة الثانية

كما ذكرت سابقا , ما نقوم به فعلا فى هذا المشروع هو تطبيق ميزة الإضافة السريعة التي تدعمها Google Calender ومع ذلك نحن بحاجة إلي معرفة تنسيق سلسلة الأحداث لأان هناك بعض القواعد التي يمكن تطبيقها . على سبيل المثال , هناك طريقة خاصة أن تاريخ الحدث والوقت يجب أن يتم إلحاقهم فى نهاية سلسلة وصف الحدث , حتي يعرف جوجل التاريخ والوقت بدقة للحدث, وبطبيعة الحال إذا قمت بإستخدام ميزة الإضافة السريعة بالتأكيد ستعرف ما أتحدث أنا عنه .

والحمد لله, جوجل توفر التعليمات والأمثلة فيما يتعلق بهذة المسألة . علينا فقط أن نزور وثائق الإضافة السريعه. قم بزيارة الموقع وتعرف بنفسك على هذه الميزة .

فى حالتنا , إذا كان لدينا حدثا ليوم كامل ببساطة سنقوم بإضافة التاريخ بإستخدام خطوط مائلة فى نهاية سلسلة وصف الحدث على سبيل المثال, هذا حدث 12/08/2013 إذا لم يكن لدينا حدثا ليوم كامل , سوف نقوم بإضافة الوقت ايضا بإستخدامه بين الوقت والتاريخ على سبيل المثال 12/08/2013  الساعة 21:40

بالإضافة إلي ذلك , نحن بحاجة إلي معرفة عنوان URL  ل أننا نريد إستدعاء API مثما نحن فعلنا فى قائمة التقويم . يجب علينا أن نجد ميزة الإضافة السريعة QUICK-ADD المتعلقة بالمعلومات فى وثائق Google Calendar API , إذا كنت غير مهتم بالبحث عنه الأن , هذا هو المكان حيث يمكنك العثور علية . ويجب علينا أن نبحث عن المعلومات التالية

  • الطلب هذا هو عنوان url الخاص ب API التى نريد أن نستدعيه, كما ورد فى الجزء العلوي من الصفحة .ولاحظ أيضا أننا بحاجة إلي إستخدام أسلوب POST HTTP .
  • معلمات Post : هذه هى المعلمات التي نحن بحاجة إليها لإرسالها بأسلوب POST . هناك أثنين params إلزامية , معرف التقويم الذى نريد أن نضيف الحدث والنص (طبعا المنسقة كما أشرت سابقا ) أو الحدث والتاريخ كما أشرت ايضا سابقا
  • الإذن :  هذا هو النطاق الذي ينبغي أن يكون التصريخ الخاص بنا . فى هذه الحالة النطاقات المساوية لنطاق قائمة التقويم, على كل حال لسنا بحاجة للكلام حول هذا الموضوع . مع ذلك إذا كان قيمتة مختلفه ينبغي علينا إدراجة فى نطاق الصفيف أثناء الحصول على إذن .

لذ , دعونا نذهب مرة أخري للإنتهاء من الأمور التى لدينا . قم بتحديث التعليمات البرمجية الخاصة بنا كما يلي  :
- (IBAction)post:(id)sender {    ...    ...    ...     // Create the URL string of API needed to quick-add the event into the Google calendar.    // Note that we specify the id of the selected calendar.    NSString *apiURLString = [NSString stringWithFormat:@"https://www.googleapis.com/calendar/v3/calendars/%@/events/quickAdd",                              [_dictCurrentCalendar objectForKey:@"id"]];     // Build the event text string, composed by the event description and the date (and time) that should happen.    // Break the selected date into its components.    NSDateComponents *dateComponents = [[NSDateComponents alloc] init];    dateComponents = [[NSCalendar currentCalendar] components:NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit                                                     fromDate:_dtEvent];         if (_isFullDayEvent) {        // If a full-day event was selected (meaning without specific time), then add at the end of the string just the date.        _strEventTextToPost = [NSString stringWithFormat:@"%@ %d/%d/%d", _strEvent, [dateComponents month], [dateComponents day], [dateComponents year]];    }    else{        // Otherwise, append both the date and the time that the event should happen.        _strEventTextToPost = [NSString stringWithFormat:@"%@ %d/%d/%d at %d.%d", _strEvent, [dateComponents month], [dateComponents day], [dateComponents year], [dateComponents hour], [dateComponents minute]];    }     // Show the activity indicator view.    [self showOrHideActivityIndicatorView];         // Call the API and post the event on the selected Google calendar.    // Visit https://developers.google.com/google-apps/calendar/v3/reference/events/quickAdd for more information about the quick-add event API call.    [_googleOAuth callAPI:apiURLString           withHttpMethod:httpMethod_POST       postParameterNames:[NSArray arrayWithObjects:@"calendarId", @"text", nil]      postParameterValues:[NSArray arrayWithObjects:[_dictCurrentCalendar objectForKey:@"id"], _strEventTextToPost, nil]];}
إذا قمت بتشغيل التطبيق الأن أنقر على زر الوظيفة , سيتم نشر الحدث يمكنك التحقق من هذا إذا حددت خانة الأختيار للتقويم الخاص بك من مستعرض الويب . مع ذلك يمكننا التعامل مع الإستجابة من جوجل Google , نحن غير قادرين على معرفة إذا كان هذا الحدث تم إضافتة بنجاح أم لا .

الخطوة الثالثة

فى كل وقت يتم ترحيل الحدث , جوجل تقوم بإنشاء كائن لكل منها الذي يحتوي على العديد من الخصائص والبيانات . بعد إضافتة بنجاح , يستجيب جوجل مع هذه البيانات , حيث يمكن أن يكون لدينا أى معلومات نحن بحاجة إليها فيما يتعلق بهذا الحدث الذي تم إنشاءوه حديثا وفى حالتنا , نحن لن نفعل شيئا غير عادي . سوف نعرض ببساط طريقة عرض التنبيهات التى سوف تحتوي على القيم التالية , حتى ونحن متأكدون من أن هذا الحدث تم بنجاح.

  • المعرف : كل حدث جديد يحصل على قيمة معرف فريدة من نوعها , والتى سنقوم بعرضها فى طريقة عرض التنبية
  • تاريخ الإنشاء: التاريخ الذي تم إنشاء الحدث فية
  • الملخص : وصف الحدث نفسة

وبطبيعة الحال , فى التطبيق الحقيقي يجب التعامل مع بيانات الحدث بطريقة مختلفة دائما دائما يعتبر التطبيق بحاجة إليها .

نحن ذاهبون للعمل في أسلوب responseFromServiceWasReceived:andResponseJSONAsData: مرة ثانية . لاحظ أن البيانات JSON تم تحويلها مرة أخري إلي كائن NSDictionary .
-(void)responseFromServiceWasReceived:(NSString *)responseJSONAsString andResponseJSONAsData:(NSData *)responseJSONAsData{    NSError *error;    ...    ...    ...        else if ([responseJSONAsString rangeOfString:@"calendar#event"].location != NSNotFound){        // If the Google response contains the "calendar#event" literal then the event has been added to the selected calendar        // and Google returns data related to the new event.                 // Get the response JSON as a dictionary.        NSDictionary *eventInfoDict = [NSJSONSerialization JSONObjectWithData:responseJSONAsData options:NSJSONReadingMutableContainers error:&error];                 if (error) {            // This is the case that an error occured during converting JSON data to dictionary.            // Simply log the error description.            NSLog(@"%@", [error localizedDescription]);            return;        }         // An alert view with some information regarding the just added event will be shown.        // Keep only the information that will be shown to the alert view.        // Look at the https://developers.google.com/google-apps/calendar/v3/reference/events#resource for a complete list of the        // data fields that Google returns.        NSString *eventID = [eventInfoDict objectForKey:@"id"];        NSString *created = [eventInfoDict objectForKey:@"created"];        NSString *summary = [eventInfoDict objectForKey:@"summary"];                 // Build the alert message.        NSString *alertMessage = [NSString stringWithFormat:@"ID: %@\n\nCreated:%@\n\nSummary:%@", eventID, created, summary];                 // Stop the activity indicator view.        [self showOrHideActivityIndicatorView];                 // Show the alert view.        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"New event"                                                        message:alertMessage                                                       delegate:self                                              cancelButtonTitle:nil                                              otherButtonTitles:@"Great", nil];        [alert show];    }}
الأن فى كل مرة تقوم بإضافة حدث جديد يتم عرض طريقة التنبيه التي تحتوي على معلومات الحدث .

12 – تسجيل الخروج

تسجيل الخروج من حساب Google  هو  الخيار الذي ينبغى دائما أن يقدم إلي المستخدمين , على الرغم من أنه قد أوصي بإبقائهم على اتصال لسرعة الوصول إلى خدمات الإنترنت . للتطبيق الخاص بنا , هذا هو الخطب الكود التالي لإضافة أسلوب revokeAccess: IBAction method.
- (IBAction)revokeAccess:(id)sender {    // Revoke the access token.    [_googleOAuth revokeAccessToken];}

أنها مجرد مسألة واحدة سطر واحد من التعليمات البرمجية , التى سنقوم بإضافتها على أسلوب  revokeAccess:IBAction .الأسلوب revokeAccessToken سيقوم  بإرسال إستدعاء  الي accessTokenWasRevoked لتفويض الأسلوب لإبلاغ الفئات لدينا أنه تم إلغاء الرمز المميز للوصول Access Token , والذهاب إلى تنفيذها بعد .

13- الأساليب التبعية

الخطوة الأولي :

حتى الأن . قمنا فقط بإستخدام أساليب الفئة GoogleOAuth و authorizationWasSuccessful و respnseFromServiceWasReceived:andResponseJSONASData: هناك ثلاثة أخرون منهم ينبغي أن ننفذ أسلوب التفويف للتعامل مع إبطال الوصول , ومندوب أخر لمعالجة أى أخطاء قد تحدث , والأسلوب النهائي للتعامل مع أية رسائل خطا قد تكون موجودة فى إجابات جوجل .

فيما يتعلق بإلغاء الوصول , سيتعين علينا القيام بأمور ثلاثة فقط أولا , نحن بحاجة إلي إزالة كافة التقويمات من مجموعة arrGoogleCalendars بعد ذلك , نحن بحاجة إلى تعطيل الوظيفة وزر تسجيل الخروج وأخيرأ , نحن بحاجة إلي تحديث طريقة عرض الجدول والإحتفاظ بها حتي الأن .
-(void)accessTokenWasRevoked{    // Remove all calendars from the array.    [_arrGoogleCalendars removeAllObjects];    _arrGoogleCalendars = nil;         // Disable the post and sign out bar button items.    [_barItemPost setEnabled:NO];    [_barItemRevokeAccess setEnabled:NO];         // Reload the Google calendars section.    [_tblPostData reloadSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationAutomatic];}
للخطئين التاليين سنتعامل بأسلوب التفويض , لن نفعل الكثر , نحن ببساطة سنقوم بتسجيل رسائل إعلام للخطا . فمن الواضح أنه فى التطبيق الحقيقي سيكون لديك خبرة فى التعامل مع الأخطاء بطريقة مناسبة ومعرفة الحلول التى تتعامل معها حالات غير متوقعة الأن , هنا لدينا تطبيقات stub implementations :
-(void)errorOccuredWithShortDescription:(NSString *)errorShortDescription andErrorDetails:(NSString *)errorDetails{    // Just log the error messages.    NSLog(@"%@", errorShortDescription);    NSLog(@"%@", errorDetails);} -(void)errorInResponseWithBody:(NSString *)errorMessage{    // Just log the error message.    NSLog(@"%@", errorMessage);}
الخطوة الثانية

أثناء تنفيذ المشروع , قمنا بعمل دعوات قليلة الي showOrHideActivityindicatorView والذي تم إستدعاءة لكن لن يتم بناؤة. دعونا نتعامل معه الأن .
-(void)showOrHideActivityIndicatorView{    // If the activity indicator view is not currently animating (spinning),    // then set its view center equal to self view's center, add it as a subview and start animating.    // Otherwise stop animating and remove it from the superview.    if (![_activityIndicatorView isAnimating]) {        [_activityIndicatorView setCenter:self.view.center];        [self.view addSubview:_activityIndicatorView];        [_activityIndicatorView startAnimating];    }    else{        [_activityIndicatorView stopAnimating];        [_activityIndicatorView removeFromSuperview];    } }
هذا هو أخر شىء  كان علينا أن نفعله وأخيرا , تم الإنتهاء من التطبيق لدينا . وتجربة جميع وظائف الدعم

الإستنتاج

فى هذا البرنامج التعليمي أظهرت كيفية التعامل مع التقويمات جوجل Google Calender بإستخدام OAuth 2.0  حينما كان هناك الكثير من الأعما فى خدمة التطبيق الخاصة بالويب, أرجو أن تجد الجهد المبذول فى ذلك ليكون جدير بالإهتمام ! شكرا لقراءتك هذا المقال , لا تتردد فى ترك أى أسئلة أو تعليقات وذلك فى قسم التعليقات بالأسفل

الكــاتــب

    • مشاركة

ليست هناك تعليقات:

جميع الحقوق محفوظة لــ الشبح للمعلوميات 2019 ©