توسيع نطاق الاختصارات الديناميكية إلى "مساعد Google" باستخدام ميزة "مهامّ في التطبيقات"

1. نظرة عامة

في الدرس التطبيقي السابق حول الترميز، استخدمت اختصارات ثابتة لتنفيذ أهداف مضمَّنة (BII) شائعة الاستخدام في نموذج تطبيق. يستخدم مطوّرو تطبيقات Android خدمة "مهامّ في التطبيقات" لتوسيع نطاق وظائف التطبيقات لتشمل "مساعد Google".

يتم تجميع الاختصارات الثابتة مع تطبيق ولا يمكن تحديثها إلا من خلال طرح إصدارات جديدة من التطبيق. يتم تفعيل الوظائف الصوتية للعناصر الديناميكية في أحد التطبيقات، مثل المحتوى الذي ينشئه المستخدمون، باستخدام الاختصارات الديناميكية. تدفع التطبيقات اختصارات ديناميكية بعد أن ينفذ المستخدمون إجراءات ذات صلة، مثل إنشاء ملاحظة جديدة في تطبيق تتبع المهام. يتيح لك تطبيق "مهامّ في التطبيقات" تفعيل هذه الاختصارات الصوتية من خلال ربطها بالأداة BII، ما يتيح للمستخدمين الوصول إلى المحتوى الخاص بهم من خلال "مساعد Google" بقول عبارات مثل "Ok Google، أريد فتح قائمة البقالة على ExampleApp".

ثلاث شاشات تقدّمية تعرض "مساعد Google" وهو يطلق اختصارًا ديناميكيًا.

الشكل 1. ثلاث شاشات تقدّمية تعرض مهمة أنشأها المستخدم، بينما يطلق "مساعد Google" اختصارًا ديناميكيًا إلى عنصر المهمة هذا.

ما الذي ستقوم ببنائه

في هذا الدرس التطبيقي حول الترميز، سيتم تفعيل الاختصارات الديناميكية للصوت في نموذج قائمة مهام على Android، ما يتيح للمستخدمين توجيه طلب إلى "مساعد Google" لفتح عناصر قائمة المهام التي ينشئونها في التطبيق. ويمكنك تحقيق ذلك باستخدام أنماط بنية Android، وتحديدًا أنماط المستودع ومحدِّد موقع الخدمة وViewModel.

المتطلبات الأساسية

يستند هذا الدرس التطبيقي إلى مفاهيم "مهامّ في التطبيقات" التي تم تناولها في الدرس التطبيقي السابق حول الترميز، وخاصةً معرّفات BII والاختصارات الثابتة. إذا كنت مستخدمًا جديدًا لخدمة "مهامّ في التطبيقات"، ننصحك بإكمال هذا الدرس التطبيقي قبل المتابعة.

بالإضافة إلى ذلك، يُرجى التأكّد من ضبط الإعدادات التالية في بيئة التطوير قبل المتابعة:

  • وحدة طرفية لتشغيل أوامر واجهة الأوامر مع تثبيت git
  • يشير إلى أحدث إصدار ثابت من استوديو Android.
  • جهاز Android فعلي أو افتراضي مزود بإمكانية الاتصال بالإنترنت.
  • حساب Google تم تسجيل الدخول منه إلى "استوديو Android" وتطبيق Google وتطبيق "مساعد Google"

2. التعرّف على طريقة العمل

يتضمن تمكين اختصار ديناميكي للوصول الصوتي باستخدام الخطوات التالية:

  • ربط اختصار ديناميكي بـ BII مؤهل
  • تفعيل "مساعد Google" من نقل الاختصارات من خلال إضافة مكتبة دمج "اختصارات Google"
  • الدفع اختصارًا عندما يُكمل المستخدم المهمة ذات الصلة داخل التطبيق

اختصارات الربط

لإتاحة الوصول إلى الاختصار الديناميكي من "مساعد Google"، يجب ربطه بخدمة BII ذات الصلة. عند تشغيل دالة BII مع اختصار، يطابق "مساعد Google" المَعلمات في طلب المستخدم مع الكلمات الرئيسية المحدَّدة في الاختصار المرتبط. على سبيل المثال:

  • يمكن أن يسمح الاختصار المرتبط بالرمز GET_THING BII للمستخدمين بطلب محتوى معيّن داخل التطبيق من "مساعد Google" مباشرةً. * "Ok Google، أريد فتح قائمة البقالة على ExampleApp".
  • قد يسمح الاختصار المرتبط بالوحدة ORDER_MENU_ITEM BII للمستخدمين بإعادة تشغيل الطلبات السابقة. * "Ok Google، أريد طلب خدماتي المعتادة من ExampleApp".

يمكنك الرجوع إلى مرجع الأغراض المضمَّنة للحصول على قائمة كاملة مصنَّفة بمعرّفات BII.

تقديم اختصارات لخدمة "مساعد Google"

بعد ربط اختصاراتك بـ BII، ستتمثل الخطوة التالية في تفعيل "مساعد Google" من نقل هذه الاختصارات من خلال إضافة مكتبة تكامل اختصارات Google إلى مشروعك. عند استخدام هذه المكتبة، سيطّلع "مساعد Google" على كل اختصار يطرحه تطبيقك، ما يتيح للمستخدمين تشغيل هذه الاختصارات من خلال استخدام عبارة تشغيل الاختصار في "مساعد Google".

3- إعداد بيئة التطوير

يستخدم هذا الدرس التطبيقي حول الترميز نموذجًا لتطبيق قائمة مهام مصمّمًا لنظام التشغيل Android. باستخدام هذا التطبيق، يمكن للمستخدمين إضافة عناصر إلى القوائم والبحث عن عناصر قائمة المهام حسب الفئة وفلترة المهام حسب حالة الإكمال. يمكنك تنزيل نموذج التطبيق وإعداده من خلال إكمال هذا القسم.

تنزيل ملفاتك الأساسية

شغّل الأمر التالي لاستنساخ نموذج مستودع GitHub للتطبيق:

git clone https://github.com/actions-on-google/app-actions-dynamic-shortcuts.git

بعد استنساخ المستودع، اتّبِع الخطوات التالية لفتحه في "استوديو Android":

  1. في مربّع الحوار مرحبًا بك في "استوديو Android"، انقر على استيراد مشروع.
  2. اختَر المجلد الذي استنسخت المستودع فيه.

وبدلاً من ذلك، يمكنك عرض إصدار من نموذج التطبيق الذي يمثّل الدرس التطبيقي المكتمل حول الترميز من خلال استنساخ فرع codelab-complete من مستودع جيت هب الخاص به:

git clone https://github.com/actions-on-google/app-actions-dynamic-shortcuts.git --branch codelab-complete

تعديل رقم تعريف تطبيق Android

يؤدي تعديل معرّف التطبيق الخاص بالتطبيق إلى التعرّف على التطبيق بشكلٍ فريد على الجهاز الاختباري وتجنُّب ظهور "اسم حزمة مكرّر". إذا تم تحميل التطبيق على Play Console. لتعديل معرّف التطبيق، افتح app/build.gradle:

android {
...
  defaultConfig {
    applicationId "com.MYUNIQUENAME.android.fitactions"
    ...
  }
}

استبدال "MYUNIQUENAME" في الحقل applicationId إلى معلومات فريدة لك.

إضافة تبعيات واجهة برمجة التطبيقات للاختصارات

أضِف مكتبات Jetpack التالية إلى ملف موارد app/build.gradle:

app/build.gradle

dependencies {
   ...
   // Shortcuts library
   implementation "androidx.core:core:1.6.0"
   implementation 'androidx.core:core-google-shortcuts:1.0.1'
   ...
}

اختبار التطبيق على جهازك

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

  1. في "استوديو Android"، اختَر "تشغيل" > شغِّل التطبيق أو انقر على تشغيلتشغيل رمز التطبيق في "استوديو Android" في شريط الأدوات.
  2. في مربّع الحوار اختيار هدف النشر، اختَر جهازًا وانقر على حسنًا. إصدار نظام التشغيل المقترَح هو Android 10 (المستوى 30 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، على الرغم من أنّ ميزة "مهامّ في التطبيقات" تعمل على الأجهزة حتى Android 5 (المستوى 21 من واجهة برمجة التطبيقات).
  3. اضغط مع الاستمرار على زر الشاشة الرئيسية لإعداد "مساعد Google" والتأكّد من أنّه يعمل. عليك تسجيل الدخول إلى "مساعد Google" على جهازك، إذا لم يسبق لك إجراء ذلك.

لمزيد من المعلومات حول أجهزة Android الافتراضية، يُرجى الاطّلاع على مقالة إنشاء الأجهزة الافتراضية وإدارتها.

استكشف التطبيق بإيجاز لمعرفة ما يمكنه فعله. يؤدي النقر على أيقونة علامة الجمع إلى إنشاء عنصر مهمة جديد، وتسمح لك عناصر القائمة في أعلى اليسار بالبحث عن عناصر المهام وتصفيتها حسب حالة الإكمال.

4. إنشاء فئة لمستودع الاختصارات

ستطلب العديد من الصفوف في نموذج التطبيق الخاص بنا واجهة برمجة التطبيقات ShortcutManagerCompat لإرسال الاختصارات الديناميكية وإدارتها. لتقليل تكرار التعليمات البرمجية، ستقوم بتنفيذ مستودع لتمكين فئات مشروعك من إدارة الاختصارات الديناميكية بسهولة.

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

  1. أنشِئ فئة ShortcutsRepository لاستخراج بيانات ShortcutManagerCompat API.
  2. إضافة طرق ShortcutsRepository إلى محدِّد مواقع الخدمات في التطبيق
  3. تسجيل خدمة ShortcutRepository في التطبيق الرئيسي

إنشاء المستودع

أنشِئ فئة Kotlin جديدة باسم ShortcutsRepository في حزمة com.example.android.architecture.blueprints.todoapp.data.source. يمكنك العثور على هذه الحزمة منظمة في المجلد app/src/main/java. ستستخدم هذه الفئة لتنفيذ واجهة توفّر مجموعة محدودة من الطرق التي تغطي حالة استخدام الدرس التطبيقي حول الترميز.

نافذة "استوديو Android" تعرض موقع فئة ShortcutsRepository

الشكل 2. نافذة "ملفات المشاريع" في "استوديو Android" تعرض موقع الفئة ShortcutsRepository

ألصق الرمز التالي في الفئة الجديدة:

package com.example.android.architecture.blueprints.todoapp.data.source

import android.content.Context
import android.content.Intent
import androidx.annotation.WorkerThread
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import com.example.android.architecture.blueprints.todoapp.data.Task
import com.example.android.architecture.blueprints.todoapp.tasks.TasksActivity

private const val GET_THING_KEY = "q"

/**
* ShortcutsRepository provides an interface for managing dynamic shortcuts.
*/
class ShortcutsRepository(val context: Context) {

   private val appContext = context.applicationContext

   /**
    * Pushes a dynamic shortcut. The task ID is used as the shortcut ID.
    * The task's title and description are used as shortcut's short and long labels.
    * The resulting shortcut corresponds to the GET_THING capability with task's
    * title used as BII's "name" argument.
    *
    * @param task Task object for which to create a shortcut.
    */
   @WorkerThread
   fun pushShortcut(task: Task) {
      // TODO
   }

   private fun createShortcutCompat(task: Task): ShortcutInfoCompat {
      //...
   }

   /**
    *  Updates a dynamic shortcut for the provided task. If the shortcut
    *  associated with this task doesn't exist, this method throws an error.
    *  This operation may take a few seconds to complete.
    *
    * @param tasks list of tasks to update.
    */
   @WorkerThread
   fun updateShortcuts(tasks: List<Task>) {
       //...
   }

   /**
    * Removes shortcuts if IDs are known.
    *
    * @param ids list of shortcut IDs
    */
   @WorkerThread
   fun removeShortcutsById(ids: List<String>) {
       //...
   }

   /**
    * Removes shortcuts associated with the tasks.
    *
    * @param tasks list of tasks to remove.
    */
   @WorkerThread
   fun removeShortcuts(tasks: List<Task>) {
       //...
   }
}

بعد ذلك، عليك تعديل الطريقة pushShortcut لطلب بيانات من ShortcutManagerCompat API. عدِّل الفئة ShortcutsRepository باستخدام الرمز التالي:

ShortcutsRepository.kt

/**
* Pushes a dynamic shortcut for the task. The task's ID is used as a shortcut
* ID. The task's title and description are used as shortcut's short and long
* labels. The created shortcut corresponds to GET_THING capability with task's
* title used as BII's "name" argument.
*
* @param task Task object for which to create a shortcut.
*/


@WorkerThread
fun pushShortcut(task: Task) {
   ShortcutManagerCompat.pushDynamicShortcut(appContext, createShortcutCompat(task))
}

في نموذج الرمز السابق، أرسلنا appContext إلى واجهة برمجة التطبيقات. هذا موقع إلكتروني للفئة يتضمّن سياق التطبيق. من المهم استخدام سياق التطبيق (بدلاً من سياق النشاط) لتجنُّب تسرُّب الذاكرة، نظرًا لأنه قد يتم الاحتفاظ بالسياق لفترة أطول من دورة حياة نشاط المضيف.

بالإضافة إلى ذلك، تتطلّب واجهة برمجة التطبيقات أن نمرر كائن ShortcutInfoCompat لكائن "Task". في نموذج الرمز السابق، يتم تنفيذ ذلك من خلال استدعاء الطريقة الخاصة createShortcutCompat، والتي سنعدّلها لإنشاء عنصر ShortcutInfoCompat وإرجاعه. لتنفيذ هذا الإجراء، يجب تعديل الخلاصة createShortcutCompat باستخدام الرمز التالي:

ShortcutsRepository.kt

private fun createShortcutCompat(task: Task): ShortcutInfoCompat {
   val intent = Intent(appContext, TasksActivity::class.java)
   intent.action = Intent.ACTION_VIEW
   // Filtering is set based on currentTitle.
   intent.putExtra(GET_THING_KEY, task.title)

   // A unique ID is required to avoid overwriting an existing shortcut.
   return ShortcutInfoCompat.Builder(appContext, task.id)
           .setShortLabel(task.title)
           .setLongLabel(task.title)
           // Call addCapabilityBinding() to link this shortcut to a BII. Enables user to invoke a shortcut using its title in Assistant.
           .addCapabilityBinding(
                   "actions.intent.GET_THING", "thing.name", listOf(task.title))
           .setIntent(intent)
           .setLongLived(false)
       .build()
}

تتعامل الأجزاء المتبقية من الدوال في هذا الصف مع تحديث الاختصارات الديناميكية وحذفها. قم بتمكين هذه الدوال عن طريق تحديثها بالتعليمة البرمجية التالية:

ShortcutsRepository.kt

/**
* Updates a Dynamic Shortcut for the task. If the shortcut associated with this task
* doesn't exist, throws an error. This operation may take a few seconds to complete.
*
* @param tasks list of tasks to update.
*/
@WorkerThread
fun updateShortcuts(tasks: List<Task>) {
   val scs = tasks.map { createShortcutCompat(it) }
   ShortcutManagerCompat.updateShortcuts(appContext, scs)
}

/**
* Removes shortcuts if IDs are known.
* @param ids list of shortcut IDs
*/
@WorkerThread
fun removeShortcutsById(ids: List<String>) {
   ShortcutManagerCompat.removeDynamicShortcuts(appContext, ids)
}

/**
* Removes shortcuts associated with the tasks.
*
* @param tasks list of tasks to remove.
*/
@WorkerThread
fun removeShortcuts(tasks: List<Task>) {
   ShortcutManagerCompat.removeDynamicShortcuts (appContext,
           tasks.map { it.id })
}

إضافة فئة إلى أداة البحث عن أماكن الخدمة

بعد إنشاء الفئة ShortcutsRepository، تتمثل الخطوة التالية في إتاحة العناصر التي تم إنشاء نسخة مثيل لها في هذه الفئة لبقية التطبيق. يدير هذا التطبيق تبعيات الفئة من خلال تنفيذ نمط أداة البحث عن أماكن الخدمة. افتح فئة محدّد موقع الخدمة باستخدام متصفّح الفئات في "استوديو Android" من خلال الانتقال إلى التنقّل > Class واكتب "ServiceLocator". انقر على ملف Kotlin الناتج لفتحه في بيئة التطوير المتكاملة (IDE).

في أعلى ServiceLocator.kt، الصِق الرمز التالي لاستيراد الحِزمتَين ShortcutsRepository وSuppressLint:

ServiceLocator.kt

package com.example.android.architecture.blueprints.todoapp

// ...Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository
import android.annotation.SuppressLint

أضِف طرق وأعضاء خدمة ShortcutRepository من خلال لصق الرمز التالي في نص ServiceLocator.kt:

ServiceLocator.kt

object ServiceLocator {

   // ...
   // Only the code immediately below this comment needs to be copied and pasted
   // into the body of ServiceLocator.kt:

   @SuppressLint("StaticFieldLeak")
   @Volatile
   var shortcutsRepository: ShortcutsRepository? = null


   private fun createShortcutsRepository(context: Context): ShortcutsRepository {
       val newRepo = ShortcutsRepository(context.applicationContext)
       shortcutsRepository = newRepo
       return newRepo
   }

   fun provideShortcutsRepository(context: Context): ShortcutsRepository {
       synchronized(this) {
           return shortcutsRepository ?: shortcutsRepository ?: createShortcutsRepository(context)
       }
   }
 }

تسجيل خدمة الاختصارات

الخطوة الأخيرة هي تسجيل خدمة ShortcutsRepository الجديدة في التطبيق. في "استوديو Android"، افتح TodoApplication.kt وانسخ الرمز التالي بالقرب من أعلى الملف:

TodoApplication.kt

package com.example.android.architecture.blueprints.todoapp
/// ... Other import statements

import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository

بعد ذلك، سجِّل الخدمة من خلال إضافة الرمز التالي إلى نص الفئة:

TodoApplication.kt

//...
class TodoApplication : Application() {

   //...

   val shortcutsRepository: ShortcutsRepository
       get() = ServiceLocator.provideShortcutsRepository(this)

   //...
}

أنشئ التطبيق وتأكَّد من استمرار تشغيله.

5- دفع اختصار جديد

بعد إنشاء خدمة الاختصارات، ستكون جاهزًا لبدء إرسال الاختصارات. بما أنّ المستخدمين يُنشئون محتوى (عناصر المهام) في هذا التطبيق ويتوقّعون أن يتمكّنوا من الرجوع إليها لاحقًا، سنفعّل الوصول الصوتي إلى هذا المحتوى من خلال إرسال اختصار ديناميكي يرتبط بـ GET_THING BII في كل مرة ينشئ فيها المستخدم مهمة جديدة. يتيح ذلك لخدمة "مساعد Google" توجيه المستخدمين مباشرةً إلى عنصر المَهمّة المطلوب عند تشغيل BII، وذلك من خلال توجيه طلبات مثل "Ok Google، أريد فتح قائمة البقالة على SampleApp".

يمكنك تفعيل هذه الوظيفة في نموذج التطبيق من خلال إكمال الخطوات التالية:

  1. جارٍ استيراد خدمة ShortcutsRepository إلى الفئة AddEditTaskViewModel، المسؤولة عن إدارة عناصر قائمة المهام.
  2. دفع اختصار ديناميكي عندما ينشئ المستخدم مهمة جديدة

استيراد مستودع الاختصارات

نحتاج أولاً إلى إتاحة خدمة "ShortcutsRepository" لـ "AddEditTaskViewModel". لتحقيق ذلك، عليك استيراد الخدمة إلى ViewModelFactory، وهي فئة المصنع التي يستخدمها التطبيق لإنشاء مثيل لكائنات ViewModel، بما في ذلك AddEditTaskViewModel.

افتح متصفّح الصف في "استوديو Android" من خلال الانتقال إلى التنقّل > Class واكتب "ViewModelfactor" إلى البيانات". انقر على ملف Kotlin الناتج لفتحه في بيئة التطوير المتكاملة (IDE).

في أعلى ViewModelFactory.kt، الصِق الرمز التالي لاستيراد الحِزمتَين ShortcutsRepository وSuppressLint:

ViewModelFactory.kt

package com.example.android.architecture.blueprints.todoapp

// ...Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository

بعد ذلك، استبدِل نص ViewModelFactory بالرمز التالي:

ViewModelFactory.kt

/**
 * Factory for all ViewModels.
 */
@Suppress("UNCHECKED_CAST")
class ViewModelFactory constructor(
    private val tasksRepository: TasksRepository,
    private val shortcutsRepository: ShortcutsRepository,
    owner: SavedStateRegistryOwner,
    defaultArgs: Bundle? = null
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {

    override fun <T : ViewModel> create(
        key: String,
        modelClass: Class<T>,
        handle: SavedStateHandle
    ) = with(modelClass) {
        when {
            isAssignableFrom(StatisticsViewModel::class.java) ->
                StatisticsViewModel(tasksRepository)
            isAssignableFrom(TaskDetailViewModel::class.java) ->
                TaskDetailViewModel(tasksRepository)
            isAssignableFrom(AddEditTaskViewModel::class.java) ->
                AddEditTaskViewModel(tasksRepository, shortcutsRepository)
            isAssignableFrom(TasksViewModel::class.java) ->
                TasksViewModel(tasksRepository, handle)
            else ->
                throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
        }
    } as T
}

يمكنك إكمال تغييرات ViewModelFactory بالانتقال إلى طبقة أعلى وتمرير ShortcutsRepository إلى الدالة الإنشائية للمصنع. افتح متصفح الملفات في "استوديو Android" من خلال الانتقال إلى التنقّل > ملف وكتابة "FragmentExt.kt". انقر على ملف Kotlin الناتج في الحزمة util لفتحه في بيئة التطوير المتكاملة (IDE).

استبدل نص FragmentExt.kt بالرمز التالي:

fun Fragment.getViewModelFactory(): ViewModelFactory {
   val taskRepository = (requireContext().applicationContext as TodoApplication).taskRepository
   val shortcutsRepository = (requireContext().applicationContext as TodoApplication).shortcutsRepository
   return ViewModelFactory(taskRepository, shortcutsRepository, this)
}

دفع اختصار

مع توفُّر فئة التجريد ShortcutsRepository لنماذج الصفوف البالغ عددها ViewModel في التطبيق، يمكنك تعديل AddEditTaskViewModel، وهي فئة ViewModel المسؤولة عن إنشاء الملاحظات، لإصدار اختصار ديناميكي في كل مرة ينشئ فيها المستخدم ملاحظة جديدة.

في "استوديو Android"، افتح متصفّح الصف واكتب "AddEditTaskViewModel". انقر على ملف Kotlin الناتج لفتحه في بيئة التطوير المتكاملة (IDE).

أولاً، يجب إضافة حزمة ShortcutsRepository إلى هذه الفئة باستخدام عبارة الاستيراد التالية:

package com.example.android.architecture.blueprints.todoapp.addedittask

//Other import statements
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository

بعد ذلك، أضِف السمة الخاصة بالفئة shortcutsRepository من خلال تعديل الدالة الإنشائية للفئة باستخدام الرمز التالي:

AddEditTaskViewModel.kt

//...

/**
* ViewModel for the Add/Edit screen.
*/
class AddEditTaskViewModel(
   private val tasksRepository: TasksRepository,
   private val shortcutsRepository: ShortcutsRepository
) : ViewModel() {

    //...

بعد إضافة الفئة ShortcutsRepository، أنشِئ دالة جديدة "pushShortcut()" لاستدعاء هذه الفئة. الصق الدالة الخاصة التالية في نص AddEditTaskViewModel:

AddEditTaskViewModel.kt

//...
private fun pushShortcut(newTask: Task) = viewModelScope.launch {
   shortcutsRepository.pushShortcut(newTask)
}

أخيرًا، اضغط على اختصار ديناميكي جديد عند إنشاء مهمة. استبدِل محتوى الدالة saveTask() بالرمز التالي:

AddEditTaskViewModel.kt

fun saveTask() {
    val currentTitle = title.value
    val currentDescription = description.value

    if (currentTitle == null || currentDescription == null) {
        _snackbarText.value = Event(R.string.empty_task_message)
        return
    }
    if (Task(currentTitle, currentDescription).isEmpty) {
        _snackbarText.value = Event(R.string.empty_task_message)
        return
    }

    val currentTaskId = taskId
    if (isNewTask || currentTaskId == null) {
        val task = Task(currentTitle, currentDescription)
        createTask(task)
        pushShortcut(task)
    } else {
        val task = Task(currentTitle, currentDescription, taskCompleted, currentTaskId)
        updateTask(task)
    }
}

اختبار الرمز

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

إنشاء معاينة

يتيح إنشاء معاينة باستخدام مكوّن "مساعد Google" الإضافي ظهور الاختصارات الديناميكية في "مساعد Google" على جهاز الاختبار.

تثبيت المكوّن الإضافي للاختبار

إذا لم يكن لديك مكوّن "مساعد Google" الإضافي، يمكنك تثبيته باتّباع الخطوات التالية في "استوديو Android":

  1. انتقِل إلى **ملف >. الإعدادات (استوديو Android > الإعدادات المفضّلة على نظام التشغيل MacOS).
  2. في قسم Plugins (المكوّنات الإضافية)، انتقِل إلى Marketplace وابحث عن "مساعد Google".
  3. ثبِّت الأداة وأعِد تشغيل "استوديو Android".

إنشاء المعاينة

يمكنك إنشاء معاينة باتّباع الخطوات التالية في "استوديو Android":

  1. انقر على الأدوات >. مساعد Google > "أداة اختبار إجراءات التطبيقات".
  2. في المربّع اسم التطبيق، حدِّد اسمًا مثل "قائمة المهام".
  3. انقر على إنشاء معاينة. راجِع سياسات خدمة "مهامّ في التطبيقات" وبنود الخدمة واقبلها إذا طُلِب منك ذلك.

لوحة إنشاء معاينة أداة اختبار &quot;مهامّ في التطبيقات&quot;

الشكل 3. جزء إنشاء معاينة أداة اختبار "إجراءات التطبيقات"

أثناء الاختبار، ستظهر الاختصارات الديناميكية التي ترسلها إلى "مساعد Google" في "مساعد Google" وتكون منظّمة حسب اسم التطبيق الذي قدّمته للمعاينة.

إرسال اختصار وفحصه

أعِد تشغيل نموذج التطبيق على جهازك الاختباري ونفِّذ الخطوات التالية :

  1. إنشاء مهمة جديدة بعنوان "بدء الدرس التطبيقي حول الترميز"
  2. افتح تطبيق "مساعد Google" وقُل "اختصاراتي" أو اكتبها.
  3. انقر على علامة التبويب استكشاف. من المفترض أن يظهر لك اختصار النموذج.
  4. انقر على الاختصار لاستدعاءه. من المفترض أن يظهر لك تشغيل التطبيق باسم الاختصار تمت تعبئته تلقائيًا في مربّع الفلتر، ما يسهِّل العثور على عنصر المهمة المطلوب.

6- (اختياري) تعديل اختصار وحذفه

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

تعديل اختصار

يمكنك تعديل AddEditTaskViewModel لتعديل اختصار ديناميكي عندما يغيّر المستخدم تفاصيل عنصر مهمة. أولاً، يجب تحديث نص الفئة باستخدام الرمز التالي لإضافة دالة تحديث تستخدم فئة المستودع:

AddEditTaskViewModel.kt

private fun updateShortcut(newTask: Task) = viewModelScope.launch {
   shortcutsRepository.updateShortcuts(listOf(newTask))
}

بعد ذلك، عدِّل الدالة saveTask() لاستدعاء طريقتنا الجديدة كلما تم تعديل مهمة حالية.

AddEditTaskViewModel.kt

// Called when clicking on fab.
fun saveTask() {
   // ...
   // Note: the shortcuts are created/updated in a worker thread.
   if (isNewTask || currentTaskId == null) {
       //...
   } else {
       //...
       updateShortcut(task)
   }
}

اختبِر الرمز من خلال إعادة تشغيل التطبيق واتّباع الخطوات التالية:

  1. أعِد تسمية عنوان عنصر المهمة الحالي ليصبح "إنهاء الدرس التطبيقي حول الترميز".
  2. يمكنك فتح "مساعد Google" من خلال قول "Ok Google، اختصاراتي".
  3. انقر على علامة التبويب استكشاف. من المفترض أن يظهر لك تصنيف قصير معدَّل لاختصار الاختبار.

إزالة اختصار

يجب إزالة نماذج اختصارات التطبيقات عندما يحذف أحد المستخدمين مهمة. في نموذج التطبيق، يتوفّر منطق حذف المهام في صف واحد (TaskDetailViewModel). قبل تحديث هذا الصف، يجب تحديث ViewModelFactory مرة أخرى لتمرير shortcutsRepository إلى TaskDetailViewModel.

افتح ViewModelFactory واستبدِل محتوى طريقة الدالة الإنشائية بالتعليمة البرمجية التالية:

//...
class ViewModelFactory constructor(
       private val tasksRepository: TasksRepository,
       private val shortcutsRepository: ShortcutsRepository,
       owner: SavedStateRegistryOwner,
       defaultArgs: Bundle? = null
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {

   override fun <T : ViewModel> create(
           key: String,
           modelClass: Class<T>,
           handle: SavedStateHandle
   ) = with(modelClass) {
       when {
           isAssignableFrom(StatisticsViewModel::class.java) ->
               StatisticsViewModel(tasksRepository)
           isAssignableFrom(TaskDetailViewModel::class.java) ->
               TaskDetailViewModel(tasksRepository, shortcutsRepository)
           isAssignableFrom(AddEditTaskViewModel::class.java) ->
               AddEditTaskViewModel(tasksRepository, shortcutsRepository)
           isAssignableFrom(TasksViewModel::class.java) ->
               TasksViewModel(tasksRepository, handle)
           else ->
               throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
       }
   } as T
}

بعد ذلك، افتح TaskDetailViewModel. عليك استيراد وحدة ShortcutsRepository والإعلان عن متغيّر مثيل لها باستخدام الرمز التالي:

TaskDetailViewModel.kt

package com.example.android.architecture.blueprints.todoapp.taskdetail

...
import com.example.android.architecture.blueprints.todoapp.data.source.ShortcutsRepository


/**
* ViewModel for the Details screen.
*/
class TaskDetailViewModel(
       //...
       private val shortcutsRepository: ShortcutsRepository
   ) : ViewModel() {
...
}

أخيرًا، عدِّل الدالة deleteTask() لطلب shortcutsRepository لإزالة اختصار استنادًا إلى رقم تعريفها عندما يتم حذف مهمة تتضمّن taskId مقابل:

TaskDetailViewModel.kt

fun deleteTask() = viewModelScope.launch {
   _taskId.value?.let {
       //...
       shortcutsRepository.removeShortcutsById(listOf(it))
   }
}

لاختبار الرمز، يُرجى إعادة تشغيل التطبيق واتّباع الخطوات التالية:

  1. احذف مهمة الاختبار.
  2. أعِد تسمية عنوان عنصر المهمة الحالي ليصبح "إنهاء الدرس التطبيقي حول الترميز".
  3. يمكنك فتح "مساعد Google" من خلال قول "Ok Google، اختصاراتي".
  4. انقر على علامة التبويب استكشاف. تأكَّد من أنّ اختصار الاختبار لم يعُد يظهر.

7. الخطوات التالية

تهانينا! بفضل مساعدتك، يمكن لمستخدمي نموذج التطبيق العودة بسهولة إلى الملاحظات التي ينشئونها، وذلك من خلال توجيه طلب إلى "مساعد Google" مثلاً، "Ok Google، أريد فتح قائمة البقالة على ExampleApp". تشجّع الاختصارات على تعزيز تفاعل المستخدمين من خلال تسهيل إعادة تشغيل الإجراءات الأكثر استخدامًا في تطبيقك.

النقاط التي تناولناها

في هذا الدرس التطبيقي حول الترميز، تعلمتَ كيفية:

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

الخطوات التالية

من هنا، يمكنك محاولة إجراء مزيد من التحسينات على تطبيق "قائمة المهام". للرجوع إلى المشروع النهائي، يُرجى الاطّلاع على -فرع repo-complete-متوافق مع الترميز على GitHub.

في ما يلي بعض الاقتراحات لمزيد من المعلومات حول توسيع نطاق هذا التطبيق باستخدام ميزة "مهامّ في التطبيقات":

لمواصلة رحلتك في "المهام مع مساعد Google"، يُرجى الاطّلاع على المراجع التالية:

يمكنك متابعتنا على Twitter @ActionsOnGoogle لمعرفة أحدث الإشعارات، كما يمكنك نشر تغريدة على #appActions لمشاركة ما أنجزته.

استطلاع لجمع الملاحظات

أخيرًا، يُرجى ملء هذا الاستطلاع لتقديم ملاحظاتك حول تجربتك في هذا الدرس التطبيقي حول الترميز.