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

1. نظرة عامة

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

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

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

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

ما ستُنشئه

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

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

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

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

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

2. فهم آلية العمل

تتضمّن خطوات تفعيل اختصار ديناميكي لتطبيق Voice Access ما يلي:

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

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

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

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

راجِع مرجع الأهداف المضمّنة للحصول على قائمة كاملة مصنّفة بالأهداف المضمّنة.

توفير اختصارات إلى "مساعد 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 من مستودع GitHub:

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.
  2. أضِف طرقًا ShortcutsRepository إلى محدِّد الخدمات في التطبيق.
  3. سجِّل خدمة ShortcutRepository في التطبيق الرئيسي.

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

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

نافذة Android Studio تعرض موقع فئة ShortcutsRepository

الشكل 2: نافذة "ملفات مشروع Android Studio" تعرض الموقع الجغرافي لفئة 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" من خلال الانتقال إلى التنقّل > الفئة وكتابة 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 توجيه المستخدمين مباشرةً إلى عنصر المهمة المطلوب عند بدء تفاعل IB عن طريق طرح أسئلة مثل "مرحبًا Google، أريد فتح قائمة البقالة على SampleApp".

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

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

استيراد ShortcutsRepository

علينا أولاً إتاحة خدمة 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. في قسم المكوّنات الإضافية، انتقِل إلى Marketplace (السوق) وابحث عن "مساعد Google".
  3. ثبِّت الأداة وأعِد تشغيل "استوديو Android".

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

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

  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". تشجّع الاختصارات على تعزيز تفاعل المستخدمين من خلال تسهيل إعادة تشغيل الإجراءات الأكثر استخدامًا في تطبيقك.

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

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

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

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

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

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

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

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

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

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