
قصة فكرة بسيطة… وتنفيذ لم يكن بسيطًا أبدًا
منذ بداية العمل على [https://github.com/adelpro/open-mushaf-native](Open Mushaf) وأنا أحاول قدر الإمكان أن تكون كل ميزة تُضاف نابعة من استخدام حقيقي، لا من “قائمة أفكار جميلة”. الفكرة هذه المرة جاءت من ملاحظة يومية جدًا:
نفتح هواتفنا عشرات المرات في اليوم، لكن لا نفتح التطبيق في كل مرة. ومع ذلك، علاقتنا مع القرآن تحتاج حضورًا دائمًا، حتى في اللحظات السريعة.
من هنا بدأت فكرة الـ Widget.
الفكرة
أردت Widget بسيطًا، يوضع على الشاشة الرئيسية، ويقوم بشيء واحد فقط لكن بإتقان:
- يذكّر المستخدم بورده الحالي
- يبيّن السورة والمصحف الحاليين
- يعرض التقدم بشكل بصري واضح
- يجيب عن سؤال واحد بسرعة: أين وصلت؟
دون فتح التطبيق.
دون أي خطوات إضافية.
شيء عملي، مباشر، ومفيد فعلًا.
مِيزة صغيرة، لكنها من النوع الذي يصنع فارقًا حقيقيًا في الاستمرارية.
وهذه الإضافة كانت طبيعية جدًا لتطبيق مفتوح المصدر مثل
Open Mushaf Native.
البحث عن الأداة المناسبة
أصعب جزء في البداية لم يكن البرمجة، بل إيجاد أداة:
- تعمل مع Expo
- لا تكسر إعدادات المشروع الحالية
- متوافقة مع React Native الحديث
- ويمكن البناء عليها مستقبلًا (حتى لـ iOS)
بعد بحث وتجربة أكثر من خِيار، وصلت إلى:
sAleksovski/react-native-android-widget
المكتبة بدت ممتازة من حيث الفكرة والتنفيذ، لكن للأسف لم تعمل مع إعداداتي الحالية:
- Android Native 0.19
- Expo SDK 54
التواصل مع المطوّر
بدل البحث عن حلول ملتوية، فتحت Issue مباشرة:
Issue #134
وهنا واحدة من أجمل نِقَاط العمل على المشاريع المفتوحة المصدر:
المطوّر تفاعل، وفهم المشكلة، وأصدر نسخة جديدة من المكتبة لمحاولة حلها.
ظننت أن الأمور انتهت هنا… لكن لا.
React Compiler يدخل على الخط
بعد التحديث، ظهرت مشكلة جديدة:
المكتبة غير متوافقة مع React Compiler الجديد.
بعد بحث وتجارب، وصلت لحل بسيط لكن غير متوقّع:
إضافة هذا السطر أعلى ملف الـ widget:
'use no memo';
بهذا الشكل، يتم استثناء الملف من التحويل، لأن الكود مبني على native logic ولا يحتاج React Compiler أصلًا.
حل صغير، لكنه أنقذ الموقف بالكامل.
بداية التنفيذ الفعلي
تطوير Widget في React Native مختلف تمامًا عن تطوير شاشة عادية.
أنت لا تتعامل فقط مع UI، بل مع طبقة أقرب للنظام نفسه.
في هذه المرحلة كنت أتعامل مع:
- إعدادات native
- نقاط دخول مختلفة عن التطبيق
- Expo plugins
- lifecycle خاص بالـ widget
تعديل app.json
أول خطوة كانت تعديل app.json وإضافة plugin الخاص بالـ widget مع الإعدادات الكاملة، بما فيها صورة المعاينة:
[
"react-native-android-widget",
{
"widgets": [
{
"name": "OpenMushaf",
"label": "Open Mushaf Widget",
"minWidth": "320dp",
"minHeight": "120dp",
"targetCellWidth": 5,
"targetCellHeight": 2,
"description": "Open Mushaf Widget",
"previewImage": "./assets/widgets/widget-preview.png",
"resizeMode": "horizontal | vertical",
"updatePeriodMillis": 1800000
}
]
}
]
تغيير نقطة الدخول
بعد ذلك، كان عليّ تغيير نقطة الدخول في package.json:
"main": "index.ts"
إنشاء ملف index.ts
ثم إنشاء ملف index.ts في جذر المشروع، وهو المسؤول عن ربط التطبيق بالـ widget:
import '@expo/metro-runtime';
import { App } from 'expo-router/build/qualified-entry';
import { renderRootComponent } from 'expo-router/build/renderRootComponent';
import { registerWidgetTaskHandler } from 'react-native-android-widget';
import { widgetTaskHandler } from './widgets/widget-task-handler';
renderRootComponent(App);
registerWidgetTaskHandler(widgetTaskHandler);
هيكلة ملفات الـ Widget
أنشأت مجلد widgets وفيه ملفان أساسيان:
التحدي الحقيقي: التصميم
المساحة صغيرة جدًا، والمعلومات كثيرة نسبيًا.
هنا كان لا بد من قرارات حاسمة:
- ما الذي يجب أن يُرى أولًا؟
- كيف أرتّب المعلومات بصريًا؟
- كيف أجعل الـ widget جذابًا دون تعقيد؟
- وكيف أضمن أن البيانات دائمًا متزامنة مع التطبيق؟
القرارات التي اتخذتها
استخدام حلقة تقدم واضحة مع ألوان متباينة ونسبة مئوية
النظرة الأولى يجب أن تخبرك فورًا: هل أنت متقدم أم لا
تدرّج في أحجام الخطوط
المهم كبير، والباقي داعم له
أيقونة بسيطة
لكسر جمود النص فقط، دون أي مبالغة
الاعتماد على نفس البيانات المستخدمة في التطبيق
نفس المصدر، نفس الحالة، دون أي تكرار أو منطق إضافي، إعادة استعمال نفس الكود للتطبيق
النتيجة
Widget صغير.
هادئ.
لكن حاضر دائمًا.
كل مرة تفتح فيها هاتفك، ترى:
أين وصلت، وماذا تبقى في الورد اليومي.
وهذا بالضبط ما كنت أريده.
ليس مِيزة ضخمة، ولا شيء مبهر تقنيًا،
بل أداة بسيطة تساعد على الاستمرار.
الخلاصة
إضافة Widget لم تكن تجرِبة سهلة:
- إعدادات native
- Expo
- React Compiler
- قرارات تصميم صعبة
لكنها كانت تجرِبة غنيّة وممتعة،
وتؤكد مرة أخرى أن أبسط الأفكار، عندما تُنفّذ بعناية،
قد تكون أكثرها أثرًا.
والأهم من كل ذلك:
القرآن يستحق أن يكون أقرب… دائمًا.
يمكنكم الاطلاع على الكود على هذا الرابط: https://github.com/adelpro/open-mushaf-native/tree/feqture/android-widget-v2