اذهب إلى المحتوى

Mustafa Suleiman

الأعضاء
  • المساهمات

    9819
  • تاريخ الانضمام

  • تاريخ آخر زيارة

  • عدد الأيام التي تصدر بها

    299

كل منشورات العضو Mustafa Suleiman

  1. تجاهلي الرسالة التالية: packages are looking for funding run `npm fund` for details حيث أنه يخبرك بتنفيذ الأمر npm fund، وسيتم عرض قائمة بجميع الوحدات والحزم التي قمت بتثبيتها والتي تم إنشاؤها بواسطة شركات أو منظمات تحتاج إلى دعم مالي لمشاريعها في مجال تقنية المعلومات. وستظهر لك قائمة بصفحات الويب التي يمكنك من خلالها إرسال الأموال لهذه الشركات أو المنظمات. وتستطيعي تعطيل ظهور تلك الرسالة عن طريق الأمر التالي: npm config set fund false --global وبخصوص parcel من الأفضل استخدام parcel بشكل محلي داخل المشروع وليس global، لذلك عليك بحذف النسخة التي قمتي بتحميلها بشكل global بالأمر التالي: npm un parcel -g بعد ذلك تثبيت الحزمة بالشكل التالي: npm install --save-dev parcel وتستطيعي تشغيل المشروع من خلال الأمر التالي مباشرًة: npx parcel src/index.html ولاحظي أنه يتم تشغيل الملف index.html في مجلد src. والأفضل استخدام السكريبت في ملف package.json بالشكل التالي: { "name": "my-project", "source": "src/index.html", "scripts": { "start": "parcel", "build": "parcel build" }, "devDependencies": { "parcel": "latest" } } ولاحظي أنه في source تم تحديد الملف الرئيسي للمشروع، وتستطيعي تشغيل المشروع الآن عن طريق الأمر npm start. وتستطيعي قراءة الشرح الخاص بـ Parcel من المستند الرسمي: https://parceljs.org/getting-started/webapp/
  2. عندما يتعلق الأمر بتخزين البيانات في قاعدة البيانات، هناك عدة طرق يمكن اتباعها، وسأقدم لك بعض الأفكار العامة حول كيفية تخزين البيانات التي تم توضيحها في استفسارك. بالنسبة للخانات الثابتة، بإمكانك اتخاذ قرار بين تخزين القيم المباشرة أو استخدام المعرفات والربط ببيانات أخرى. ولنستخدم مثالك "اسم الكتاب: أبيض وأسود". تستطيع أن تقرر تخزين النص "أبيض وأسود" مباشرة كقيمة في قاعدة البيانات وجعلها حقلًا في الجدول الخاص بالمواضيع، أو باستطاعتك إنشاء جدول منفصل للكتب وتخزين تفاصيل الكتب فيه، مع إضافة حقل يحمل معرف الكتاب في جدول المواضيع للإشارة إلى الكتاب المحدد. بالنسبة للغات المتعددة، فإذا كنت ترغب في دعم العربية والإنجليزية في التطبيق، تستطيع تخزين اسم الكتاب باللغتين في قاعدة البيانات. مثلاً، إضافة حقول مثل "اسم الكتاب بالعربية" و "اسم الكتاب بالإنجليزية"، وبمثل هذا النهج، يمكن للتطبيق استخدام النص المناسب بناءً على لغة تفضيل المستخدم أو اختياراته. وتذكر أن الطريقة الأفضل والصحيحة لتخزين البيانات تعتمد على احتياجات تطبيقك. ,إذا كنت تستخدم قاعدة بيانات Firebase، فإنها توفر لك بنية لتخزين البيانات تعتمد على مفهوم الوثائق والمجموعات في قاعدة البيانات. حيث أن في Firebase، يتم تخزين البيانات في وثائق (Documents)، وهي هيكل تخزين قابل للتنفيذ يتكون من مجموعة من الحقول وقيمها. يمكنك أن تنظر إلى الوثيقة كإدخال مستقل في قاعدة البيانات. وبناءً على ما تم شرحه، تستطيع تخزين الخانات الثابتة (مثل نوع المشاركة ونوع الكتاب ورقم الإصدار) كحقول في وثيقة الموضوع، وتخزين القيم المباشرة لهذه الخانات مباشرة في حقولها بقاعدة البيانات. مثلاً، إنشاء وثيقة لكل موضوع وتتضمن حقولًا مثل "عنوان الموضوع" و "نوع المشاركة" و "نوع الكتاب" و "رقم الإصدار"، وتخزين القيم المدخلة من المستخدمين في هذه الحقول. في Firebase، بإمكانك أيضًا تخزين قيم متعددة لنفس الحقل باستخدام مفهوم المصفوفات. وبالتالي، تستطيع تخزين أسماء الكتب بالعربية والإنجليزية في نفس الحقل، مثل ["أبيض وأسود", "Black and White"].
  3. الدالة الأولى: function increase(num) { num++; console.log(num); } تستقبل معامل واحد يُسمى num، وداخل الدالة، يتم استخدام المعامل المؤقت ++ لزيادة قيمة num بمقدار واحد. ثم طباعة القيمة المحدثة لـ num، في هذه الحالة، سيتم زيادة قيمة num من 1 إلى 2، وبعد ذلك ستُطبع القيمة 2. الدالة الثانية: function increase(number) { return number++; } الدالة أيضًا تستقبل معامل واحد يُسمى number، داخل الدالة، يستخدم المعامل المؤقت ++ لزيادة قيمة number بمقدار واحد. ومع ذلك، يتم إرجاع القيمة الأصلية لـ number (قبل زيادتها)، حيث ستُرجع الدالة قيمة 1 (القيمة الأصلية لـ number) وليس القيمة المحدثة (2). ولكن ما السبب؟ السبب يكمن في المعامل ++، فهو معامل يُستخدم لزيادة قيمة متغير بمقدار واحد. وهناك فرق بين استخدام ++ قبل اسم المتغير وبعده. فإذا استخدمته قبل اسم المتغير ويعرف باسم pre-increment: ++num ستتم زيادة قيمة المتغير ومن ثم يتم استخدام القيمة المحدثة. أما إذا استخدمته بعد اسم المتغير، ويعرف باسم post-increment: num++، فسيتم استخدام القيمة الأصلية للمتغير ومن ثم يتم زيادة قيمته. مثال لتوضيح الاستخدام: let num = 1; console.log(++num); // ستُطبع القيمة 2 (تم زيادة القيمة قبل الاستخدام) console.log(num++); // ستُطبع القيمة 2 (ت بمعنى أنك لو أردت أن يتم إرجاع قيمة 2 من الدالة الثانية وليس 1 عليك تعديل المعامل ليصبح قبل المتغير بالشكل التالي: function increase(number) { return ++number; }
  4. للاستفادة من التاريخ الهجري في لغة JavaScript، تستطيع استخدام المكتبة المعروفة باسم "Hijri.js"، وهي مكتبة JavaScript مفتوحة المصدر تتيح لك التعامل مع التواريخ الهجرية، يمكنك تنزيل المكتبة من مستودع GitHub الخاص بها. ولتثبيت المكتبة باستخدام مدير حزم npm، استخدم الأمر التالي: npm install hijri.js بعد تثبيت المكتبة، قم باستيرادها في مشروعك بالشكل التالي: const HijriDate = require('hijri.js'); // مثال على كيفية إنشاء تاريخ هجري جديد const hijriDate = new HijriDate(); console.log(hijriDate.toString()); // يقوم بطباعة التاريخ الهجري الحالي // يمكنك أيضًا تعيين تاريخ هجري محدد const specificDate = new HijriDate(1443, 9, 1); console.log(specificDate.toString()); // يقوم بطباعة التاريخ الهجري المحدد بالنسبة لـ React Native، لا يوجد مكتبة محددة للتعامل مع التواريخ الهجرية في React Native بشكل مدمج، لذلك عليك بالإعتماد على مكتبة جافاسكريبت مثل Hijri.js المذكورة أعلاه في مشروع React Native بنفس الطريقة الموضحة في الأمثلة. وهناك أيضًا مكتبة moment-hijri لعرض التاريخ الهجري وهي إضافة لمكتبة moment.js الخاصة بالتواريخ. وهنا شرح استخدامها، وهي بسيطة: https://github.com/xsoh/moment-hijri استخدام التاريخ الهجري في جافا سكريبت بدون مكتبة سأشرح لك كيف يمكن القيام بذلك، لكن من الأسهل استخدام مكتبة جاهزة، وسنعتمد على الدوال والعمليات المتاحة في JavaScript للتعامل مع التواريخ وبعض الحسابات الرياضية يدويًا. // تحويل التاريخ الميلادي إلى هجري function convertToHijri(gregorianDate) { const dateObj = new Date(gregorianDate); const year = dateObj.getFullYear(); const month = dateObj.getMonth() + 1; const day = dateObj.getDate(); // الحساب المبسط للتاريخ الهجري const jd = Math.floor((11 * year + 3) / 30) + 354 * year + 30 * month - Math.floor((month - 1) / 2) + day + 1948440 - 385; const yearHijri = Math.floor((11 * jd + 3) / 30); const monthHijri = Math.floor(12 * (jd - Math.floor((30 * yearHijri + 3) / 11)) + 6) / 354; const dayHijri = jd - Math.floor((30 * yearHijri + 3 * monthHijri - 1) / 11); return { year: yearHijri, month: monthHijri, day: dayHijri }; } // مثال لاستخدام الدالة const gregorianDate = '2023-05-22'; const hijriDate = convertToHijri(gregorianDate); console.log(hijriDate); تحتوي الدالة convertToHijri في المثال أعلاه على خوارزمية بسيطة لتحويل التاريخ الميلادي إلى التاريخ الهجري. تستخدم الدالة Date المدمجة في JavaScript لإنشاء كائن تاريخ ميلادي من التاريخ الذي تريد تحويله. ثم يتم استخدام المعادلات المحسوبة يدويًا لتحويل التاريخ الميلادي إلى التاريخ الهجري. وإرجاع النتيجة في شكل كائن يحتوي على السنة الهجرية والشهر واليوم. ويرجى ملاحظة أن هذا مثال بسيط ولا يعتبر دقيقًا بنسبة 100٪ بالنسبة للحسابات المعقدة للتاريخ الهجري، حيث يوجد عدد من القواعد والتعقيدات في حساب التاريخ الهجري التقليدي التي لم تتم مراعاتها في هذا المثال. لذلك من الأفضل استخدام مكتبة خارجية إذا كنت تحتاج إلى دقة ومرونة أكثر في التعامل مع التاريخ الهجري.
  5. إذا قمت بإنشاء مشروع واحد في Firebase للاشتراك في الخدمة المشتركة بين تطبيق المستخدم وتطبيق مقدم الخدمة، فسوق يؤدي إلى تلقي الإشعارات في كلا التطبيقين، وهذا يحدث لأن المشروع في Firebase يعتبر كمنطقة مشتركة لجميع التطبيقات المرتبطة به. فإذا كنت ترغب في تجنب تلقي الإشعارات في كلا التطبيقين، تستطيع اتخاذ إحدى الخيارات التالية: 1- إنشاء مشروع مستقل في Firebase لكل تطبيق (تطبيق المستخدم وتطبيق مقدم الخدمة)، مما سيفصل الإشعارات والتكوينات بين التطبيقين ويحد من تكرار الإشعارات. 2- استخدام العلامات Tags في Firebase لتمييز المستخدمين ومقدمي الخدمة وإرسال الإشعارات بناءً على العلامات المحددة، عن طريق تعيين علامات مختلفة لكل تطبيق واستخدامها في عمليات إرسال الإشعارات لتحديد المستلم المناسب. بمعنى في تطبيق المستخدم: عند تسجيل المستخدم في التطبيق، يتم تعيين علامة مثل "user_app" للمستخدم باستخدام دالة setUserProperty في Firebase. عند إرسال الإشعارات إلى مستخدمي التطبيق، قم بتحديد العلامة "user_app" كجزء من المستخدمين المستهدفين. في تطبيق مقدم الخدمة: عند تسجيل مقدم الخدمة في التطبيق، يتم تعيين علامة مثل "provider_app" لمقدم الخدمة باستخدام دالة setUserProperty في Firebase. عند إرسال الإشعارات إلى مقدمي الخدمة، قم بتحديد العلامة "provider_app" كجزء من المستخدمين المستهدفين. عمومًا، من الأفضل تصميم تطبيق Firebase بشكل منفصل لكل تطبيق، خاصة إذا كانت التطبيقات مستقلة تمامًا ولها متطلبات واحتياجات مختلفة.
  6. برمجة الروبوتات وتعلم الآلة هما مفاهيم مترابطة ولكن لهما اختلافات واضحةK إليك الفرق بينهما: برمجة الروبوتات: تشير إلى عملية كتابة الشفرات البرمجية التي تتحكم في سلوك الروبوتات. تركز على تحديد تعليمات محددة للروبوت لأداء مهام محددة. يتم برمجة الروبوت بواسطة المطور بشكل صريح، حيث يتم تحديد كل خطوة يجب على الروبوت اتخاذها. تعلم الآلة: يشير إلى قدرة النظم الآلية على استخلاص الأنماط والمعرفة من البيانات وتحسين أداءها تلقائيًا عن طريق الخبرة. يهدف إلى تطوير نماذج أو خوارزميات قادرة على التعلم من البيانات واتخاذ قرارات بناءً على هذا التعلم. يعتمد على تدريب النماذج باستخدام مجموعة واسعة من البيانات لتحقيق القدرة على التعلم والتكيف. ببساطة، برمجة الروبوتات تتعامل بشكل مباشر مع برمجة سلوك الروبوت وتوجيهه بتعليمات محددة، في حين أن تعلم الآلة يركز على تطوير نماذج أو خوارزميات تستفيد من البيانات والتجارب لتعلم وتحسين أداء النظام الآلي.
  7. تستطيع استخدام كلمة مرور مختلفة لكل قاعدة بيانات على حدى في MongoDB، وذلك بتكرار الخطوات التي أشار إليك بها محمد، لإنشاء مستخدم وتعيين كلمة مرور جديدة لكل قاعدة بيانات ترغب في استخدامها. أيضًا بإمكانك استخدام نفس المستخدم وكلمة المرور لعدة قواعد بيانات إذا كنت ترغب في ذلك. وسأشرح لك الكود: use اسم_قاعدة_البيانات db.createUser({ user: "اسم_المستخدم", pwd: "كلمة_المرور", roles: [ { role: "اسم_الدور", db: "اسم_قاعدة_البيانات" } ] }) 1- use اسم_قاعدة_البيانات: هذا الأمر يستخدم للتبديل إلى قاعدة البيانات التي ترغب في إنشاء مستخدم لها، واستبدل "اسم_قاعدة_البيانات" بالاسم الذي ترغب في استخدامه لقاعدة البيانات. 2- db.createUser(): يستخدم لإنشاء مستخدم جديد وتعيين كلمة مرور له. وعليك باستبدال "اسم_المستخدم" و"كلمة_المرور" بالقيم الخاصة بالمستخدم الذي ترغب في إنشائه. 3- roles: [ { role: "اسم_الدور", db: "اسم_قاعدة_البيانات" } ]: في هذا الجزء من الكود، يتم تحديد الدور (role) الذي يحدد الصلاحيات والامتيازات التي يمتلكها المستخدم. وعليك استبدال "اسم_الدور" بدور MongoDB المناسب لاحتياجاتك، مثلاً استخدام "readWrite" لمنح المستخدم صلاحيات القراءة والكتابة. وإليك بعض الأمثلة للأدوار الشائعة ووصفها: read: يمنح المستخدم صلاحية القراءة فقط للمجموعات والمجموعات الفرعية. readWrite: يمنح المستخدم صلاحية القراءة والكتابة للمجموعات والمجموعات الفرعية. dbAdmin: يمنح المستخدم صلاحية الإدارة لقاعدة البيانات المحددة، بما في ذلك إنشاء وحذف المجموعات وإجراء العمليات الإدارية الأخرى. userAdmin: يمنح المستخدم صلاحية إدارة المستخدمين في قاعدة البيانات، مثل إنشاء وحذف المستخدمين وتعديل الأذونات. dbOwner: يمنح المستخدم جميع صلاحيات القراءة والكتابة والإدارة في قاعدة البيانات، بما في ذلك إنشاء وحذف المجموعات وإجراء العمليات الإدارية وإدارة المستخدمين. وتذكر أنه يمكنك تعيين عدة أدوار للمستخدم عن طريق تكرار الكود المذكور في قوسين مربعين ضمن roles. مثال: roles: [ { role: "readWrite", db: "اسم_قاعدة_البيانات" }, { role: "dbAdmin", db: "اسم_قاعدة_البيانات" } ] ويجب الإنتباه إلى أنه عليك إمتلاك صلاحية كافية لإنشاء المستخدم وتعيين كلمة المرور، حيث ستحتاج إلى تشغيل هذه الأوامر باستخدام مستخدم يحمل صلاحية الإدارة (مثل المستخدم الأولي "admin") لكي تتمكن من إنشاء المستخدم بنجاح.
  8. مساحة عرض الصورة على موقع مستقل هي 128 في 128 بكسل والنسخة المصغرة منها هي 36 في 36 بكسل، أي للحصول على أفضل عرض للصورة، من الأفضل رفع صورة مربعة بأي مقاس على الموقع. ويجب أن تكون الصورة إحترافية وليست صورة سيلفي أو ليست صورة شخصية لك. أما إذا كنت تتسائل من أجل تصميم حجم مشابه لها في تصميمك، فعليك بإختيار الحجم المناسب الذي يتناسب مع باقي مكونات التصميم، وأيضًا عرض الصورة بشكل واضح.
  9. عند وضع Column داخل SingleChildScrollView، بإمكان لـ Column أن يتمدد بشكل لا محدود في الاتجاه الرأسي داخل SingleChildScrollView. وبالتالي، لن يتم رمي استثناء عند تمرير المحتوى. وهناك بعض التناقض في الشروط التي يتم فيها رمي استثناء عند استخدام Expanded داخل SingleChildScrollView. في الواقع، إذا وضعت Expanded داخل SingleChildScrollView، ستحدث استثناءات لأن Expanded يحاول التمدد لاستغلال المساحة المتبقية، في حين يسمح SingleChildScrollView بالتمدد غير المحدود. ففي حالة وضع Column بداخل SingleChildScrollView، يتم تطبيق تمدد Column على العناصر الموجودة داخلها فقط، وليس على الـ SingleChildScrollView نفسه. ببساطة، SingleChildScrollView يعمل على إظهار المحتوى الذي يتجاوز المساحة المتاحة على الشاشة بواسطة التمرير، في حين يتمدد Column فقط بناءً على المحتوى الذي يحتويه. وإليك مثالًا بسيطًا يوضح استخدام Column داخل SingleChildScrollView بدون حدوث استثناء: import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Example', home: Scaffold( appBar: AppBar( title: Text('Example'), ), body: SingleChildScrollView( child: Column( children: [ Container( height: 200, // ارتفاع ثابت للمثال color: Colors.blue, ), Container( height: 200, color: Colors.green, ), Container( height: 200, color: Colors.red, ), // يمكنك إضافة المزيد من العناصر هنا ], ), ), ), ); } } تم وضع Column داخل SingleChildScrollView وتحديد ارتفاع ثابت لكل عنصر في Column، بغض النظر عن عدد العناصر، ستظهر جميعها داخل SingleChildScrollView ويمكن التمرير لعرض المحتوى الكامل.
  10. كلاهما مطلوبان في سوق العمل، والأمر يتوقف على سوق العمل لديك، عليك بالبحث على مواقع مثل LinkedIn وIndeed وبعيد أو أي موقع آخر شهير للوظائف في بلدك، فمثلاً في مصر يوجد Wuzzuf. ولا تأخذ كلامي بنسبة 100% على أنه الصحيح عليك بالبحث لتتخذ قرارك، وعامًة في العالم العربي المطلوب بكثرة بالنسبة للمبتدأين في مجال البرمجة هو PHP وإطار لارافيل وورد بريس، وأيضًا إطار .NET المعتمد على لغة C# وغالبًا يتم استخدام Angular بالنسبة للواجهة الأمامية عند استخدام .NET وذلك ليس شرط بالطبع حيث تستطيع إنشاء واجهة أمامية بدون Angular. أما الـ MERN Stack فستجد فرص بلا شك، لكن عادة ما يتم طلب خبرة سنة حيث أن React وNode.js يعتمدوا على الكثير من المكتبات الأخرى لذلك أنت بحاجة إلى خبرة حقيقية من خلال بناء مشاريع ومواجهة الأخطاء الشائعة والتعود عليها، حتى يتم قبولك في وظيفة. وهناك بعض الشركات التي توفر فرص عمل بخبرة بسيطة أي لا يشترط خبرة سنة في حال كنت مطور MERN أي مطور Full stack، وبالطبع يجب وجود مشاريع حقيقية وليست مجرد نماذج بسيطة بمعرض أعمالك باي حال من الأحوال. وهناك دورة تطوير التطبيقات باستخدام لغة JavaScript توفر لك التطبيق على مشاريع لوضعها بمعرض أعمالك، وهي خاصة بمسار MERN. وأيضًا هناك دورة تطوير تطبيقات الويب باستخدام لغة PHP وإطار لارافيل وورد بريس. أي أنه عليك بالبحث عن متطلبات الوظائف الخاصة بمستوى Junior أو Entry level أو خبرة سنة وقرر على ذلك الأساس. فإذا كان لديك الوقت ولست على عجلة للحصول على وظيفة، فقم بتعلم مسار MERN، والعكس صحيح بالنسبة PHP. وإذا أردت التخصص في الواجهة الأمامية فقط فعليك بتعلم Angular إذا أردت التوظيف بشكل سريع، والعكس صحيح بالنسبة لـ React. أما إذا أردت العمل على مواقع العمل الحر فيجب عليك أن تكون مطور Full stack، وبالنسبة للمواقع العربية فعليك تعلم PHP ولارافيل وورد بريس. وأكرر، يجب أن تقوم بالبحث عن الوظائف المتاحة في سوق العمل المحلي لديك وتقرر على هذا الأساس.
  11. عند وضع Column widget داخل SingleChildScrollView، فإنه لا يحدث استثناء (exception) لأن SingleChildScrollView يسمح بالتمدد (expansion) غير محدود في الاتجاه الرأسي، بغض النظر عن عدد عناصر Column. SingleChildScrollView يعمل على إظهار كل عناصر القائمة بطريقة يمكن التمرير (scrollable) حتى وإن كانت أكثر من المساحة المتاحة على الشاشة. وعندما يكون لديك عنصر واحد فقط في SingleChildScrollView، ويمكن لـ Column أن يتمدد (expand) بشكل غير محدود في الاتجاه الرأسي ليتناسب مع حجم محتواه. أما بالنسبة لاستخدام Expanded داخل SingleChildScrollView، فالمشكلة تكمن في أن Expanded يحاول التمدد بنسبة معينة مقابل المساحة المتبقية، ولكن بسبب وجود SingleChildScrollView الذي يسمح بالتمدد غير المحدود، يكون هناك صراع بين الـ Expanded و SingleChildScrollView في التمدد، وهذا ما يتسبب في رمي استثناء (exception). وإذا أردت استخدام Column داخل SingleChildScrollView وتجنب الاستثناء، تستطيع استخدام واجهة ConstrainedBox لتحديد حجم ثابت لـ Column، بحيث لا يحاول التمدد بشكل غير مناسب. مثال للتوضيح: import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Example', home: Scaffold( appBar: AppBar( title: Text('Example'), ), body: SingleChildScrollView( child: ConstrainedBox( constraints: BoxConstraints(), // قيود خالية، لا تحدد أي قيود على الحجم child: Column( children: [ // عناصر القائمة هنا // يمكنك وضع قائمة طويلة هنا دون حدوث استثناء ], ), ), ), ), ); } }
  12. في البداية أنا لا أنصحك بالإنتقال من Vite إلى Laravel Mix وتم توضيح سبب ذلك في النقاش التالي: سأشرح لك طريقة الإنتقال من استخدام Vite إلى Laravel mix بشكل صحيح: أولاً عليك بحذف Vite من المشروع وذك عن طريق حذف أي حزم متعلقة بـ Vite في ملف package.json مثل التالي: "laravel-vite-plugin": "^0.7.5", و "vite": "^4.0.0" وأيضًا حذف ملف vite.config.js وملف package-lock.json ومجلد node_modules. والآن قم بالتالي: 1- تثبيت Laravel Mix باستخدام npm عن طريق الأمر التالي في مجلد المشروع: npm install laravel-mix --save-dev 2- بعد التثبيت، ستحتاج إلى إنشاء ملف webpack.mix.js في جذر مشروع Laravel حيث سيحتوي على تكوينات Laravel Mix. في ملف webpack.mix.js، يمكنك تحديد مدخلات ومخرجات ملفات CSS و JavaScript. مثلاً، إذا كان لديك ملف app.css و app.js تحت مجلد resources/assets/css و resources/assets/js على التوالي، سيكون شكل الكود كالتالي: const mix = require('laravel-mix'); mix.js('resources/assets/js/app.js', 'public/js') .sass('resources/assets/css/app.scss', 'public/css'); في المثال، سيتم دمج ملف app.js وتحويله إلى ملف JavaScript واحد في المسار public/js وكذلك ملف app.scss سيتم دمجه وتحويله إلى ملف CSS واحد في المسار public/css. وبإمكانك تكوين المزيد من المدخلات والمخرجات حسب احتياجات مشروعك. وللمزيد عن طريقة الاستخدام قم بقراءة المستند الرسمي من هنا: https://laravel-mix.com/docs/6.0/installation أو قراءة الدليل العربي من موسوعة حسوب: https://wiki.hsoub.com/Laravel/mix 3- بعد تكوين webpack.mix.js، تستطيع تشغيل Laravel Mix باستخدام الأمر التالي: npx mix وسيبدأ Laravel Mix في دمج وتحويل الملفات وفقًا للتكوينات المحددة. وإذا كنت ترغب في تشغيل Mix على مدار الوقت أثناء التطوير، فاستخدم الأمر التالي بدلاً من الأمر السابق: npx mix watch سيبدأ Mix في الاستماع إلى أي تغييرات في الملفات وتنفيذ المهام المطلوبة تلقائيًا. أو تستطيع استخدام السكريبتات في ملف package.json لاستخدامها بدلاً من الأوامر السابقة كالتالي: "scripts": { "dev": "npm run development", "development": "mix", "watch": "mix watch", "watch-poll": "mix watch -- --watch-options-poll=1000", "hot": "mix watch --hot", "prod": "npm run production", "production": "mix --production" }, ولتشغيل Mix على مدار الوقت أثناء التطوير، فاستخدم الأمر npm run watch. وبخصوص رسالة الخطأ التي تظهر لك، فهى تعني أن ملف webpack.mix.js يتم التعامل معه كملف ES Module، وذلك لأن ملف package.json الأساسي في مشروعك يحتوي على "type": "module". حاول القيام بالتالي: 1- تغيير اسم الملف webpack.mix.js لينتهي بامتداد .cjs بدلاً من .js، أي تغيير اسم الملف إلى مثلاً webpack.mix.cjs. 2- تغيير رمز الاستيراد في ملف webpack.config.js من require() إلى استخدام import() الديناميكي. حيث يعمل import() مع جميع CommonJS modules، وبالتالي تستطيع استخدامه في ملف webpack.config.js، أي استبدال السطر 11 في ملف webpack.config.js بالتالي: const { mix } = import('laravel-mix'); بعد ذلك، عليك بتعديل قيمة "type" في ملف package.json إلى "commonjs" بدلاً من "module". أي تغيير السطر الذي يحتوي على "type": "module" في ملف package.json إلى التالي: "type": "commonjs"
  13. بالنسبة للسؤال الأول: تستطيع إزالة الخاصية height من الـ Container في Flutter، وإذا قمت بإزالة height أو قمت بتعيينها إلى null، فسيتم تحجيم الـ Container تلقائيًا بناءً على حجم المحتوى الذي يحتوي عليه، ولن يتسبب ذلك في رمي استثناء (Exception). بالنسبة للسؤال الثاني: بإمكانك استخدام Expanded داخل SingleChildScrollView دون تحديد ارتفاع محدد، حيث أن Expanded يقوم بتمدد العنصر الفرعي ليمتلئ بالمساحة المتاحة المتبقية داخل SingleChildScrollView. وسيعتمد ذلك على المحتوى الذي يتم تضمينه داخل Expanded وأيضًا على التركيب العام لواجهتك. إذا تم توفير محتوى يتطلب مساحة إضافية، فقد يؤدي استخدام Expanded دون تحديد ارتفاع محدد إلى زيادة الارتفاع وبالتالي إمكانية التمرير داخل SingleChildScrollView. ولكن يجب ملاحظة أنه في بعض الحالات، قد يكون من الأفضل تحديد ارتفاع محدد لـ SingleChildScrollView بدلاً من الاعتماد على Expanded فقط، خاصة إذا كان لديك محتوى كبير يمكن أن يتجاوز المساحة المتاحة ويسبب مشكلة في التمرير. وتطبيقًا على الكود الخاص بك، إليك نسخة محدثة حيث تم إزالة الـ height من الـ Container واستخدام Expanded داخل SingleChildScrollView: SingleChildScrollView( child: Column( children: [ Text('Widget 1'), Text('Widget 2'), // Add your widgets inside the Column // ... ], ), ) حيث تم إزالة Container وتم استخدام SingleChildScrollView مباشرة مع Column، وباستطاعتك وضع أي عدد من الودجتس (Widgets) داخل Column وستتمكن من التمرير إذا كانت المساحة المتاحة غير كافية لعرض جميع الودجتس في الشاشة بشكل كامل. وستقوم Expanded بتمدد المساحة داخل SingleChildScrollView لسد الفراغ المتاح بعد وضع الودجتس داخل Column. لاحظ أنه في بعض الحالات قد تحتاج إلى إضافة خاصية physics لـ SingleChildScrollView لتمكين التمرير بشكل صحيح، وذلك حسب المتطلبات الخاصة بتطبيقك.
  14. رسالة الخطأ تعني أن FirebaseOptions لا يمكن أن تكون قيمة null عند إنشاء التطبيق الافتراضي. حاول إتباع التالي لحل المشكلة: 1- تأكد من أنك قمت بإضافة ملف google-services.json الخاص بـ Firebase إلى مجلد الجذر في مشروع Flutter الخاص بك. 2- تأكد من أنك قمت بإضافة جميع حزم Firebase اللازمة إلى ملف pubspec.yaml في مشروعك، وتستطيع التأكد من وجود الحزم اللازمة وإصداراتها الصحيحة في ملف pubspec.yaml، ثم قم بتشغيل الأمر flutter pub get لتثبيتها. 3- تأكد من أن تكوين Firebase الخاص بك صحيح في مشروع Flutter، من خلال فتح ملف android/app/build.gradle وتأكد من وجود التكوينات التالية: apply plugin: 'com.google.gms.google-services' dependencies { implementation platform('com.google.firebase:firebase-bom:32.0.0') // ... } 4- تحقق من أنه تم تثبيت مكون Google Services الصحيح في مشروعك فيجب وجود السطر التالي في ملف android/build.gradle: classpath 'com.google.gms:google-services:4.3.15' 5- تأكد من استدعاء دالة main() باستخدام الكلمة المفتاحية async واستخدام await قبل دالة Firebase.initializeApp() لضمان تهيئة Firebase بنجاح قبل تشغيل التطبيق.
  15. الشرح بمثال أفضل طريقة للتوضيح، وإذا فرضنا أن لديك الكلاس التالي في JavaScript: class MyClass { constructor() { this.property = "Hello, World!"; } sayHello() { console.log(this.property); } } وتريد تطبيقه على عنصر HTML، تستطيع استخدام الأكواد التالية: // تعريف العنصر الذي ترغب في تطبيق الكلاس عليه const myElement = document.getElementById("myElement"); // تطبيق الكلاس على العنصر const myObject = new MyClass(); myElement.classList.add("myClass"); // استدعاء الوظائف في الكلاس myObject.sayHello(); والآن في HTML، قم بإنشاء العنصر الذي ترغب في تطبيق الكلاس عليه: <div id="myElement"></div> وبالطبع يجب تضمين ملف الجافاسكريبت في HTML من خلال التالي: <script type="text/javascript" src="yourJavascript.js"></script> وعليك بتعديل اسم الملف في خاصية src. ,إذا قمت بذلك بشكل صحيح، فيجب أن يتم طباعة "Hello, World!" في وحدة التحكم (console) وأن يكون العنصر في HTML يحتوي على الكلاس "myClass".
  16. @محمد عبدالله18 الكود في header.php سليم ولا يحتوي على أي خطأ واضح يمكن أن يؤدي إلى تجاوز الوقت الأقصى للتنفيذ، وقد يكون السبب الحقيقي للمشكلة في ملفات أخرى أو في الطريقة التي يتم تنفيذها، وأنت ذكرت أنه عند حذف ملف ناف بار يتم حل المشكلة فعليك بتفقد ما الخطأ في الملف والكود. وهناك طريقة يمكنك استخدامها لتحديد السبب الحقيقي وراء خطأ تجاوز الوقت الأقصى، من خلال تعطيل تنفيذ الكود تدريجيًا في header.php والتأكد من أن كل جزء يعمل بشكل صحيح دون تجاوز الوقت الأقصى. تستطيع القيام بذلك باختبار التعليمات البرمجية الواحدة تلو الأخرى بتعليقها باستخدام علامة التعليق // أو /* */. <link rel="stylesheet" href="<?php echo $css?>bootstrap.rtl.min.css"> <link rel="stylesheet" href="<?php echo $css?>bootstrap.min.css"> <link rel="stylesheet" href="<?php echo $css?>all.min.css"> <link rel="stylesheet" href="<?php echo $css?>backend.css"> ثم أعد تشغيل المشروع ووتحقق مما إذا كانت المشكلة مستمرة. إذا توقفت المشكلة، فهذا يشير إلى أن الخطأ قد يكون في أحد هذه الأجزاء المعلقة، فقم بإلغاء التعليق لكل جزء على حدة وأعد التحقق من المشكلة بعد كل جزء لتحديد أي جزء يسبب تجاوز الوقت الأقصى. إذا استمرت المشكلة بعد تعليق جميع الأجزاء، فإن السبب قد يكون في أجزاء أخرى من المشروع مثل ملف ناف بار، وليس في header.php نفسه. أو هناك كود معقد أو استعلام قاعدة بيانات يستغرق وقتًا طويلًا للتنفيذ في أحد الملفات الأخرى التي تم تضمينها في init.php أو في صفحة dashboard.php. تستطيع مراجعة هذه الملفات للتحقق من وجود أي تعليمات برمجية تستغرق وقتًا طويلًا أو تسبب حلقة تكرارية غير محدودة. وربما هناك خطأ في رمز الصفحة الرئيسية index.php الخاص بك بعد إضافة شريط التنقل (Navigation Bar) باستخدام Bootstrap. فقد يتم تحميل الأكواد المشتركة مرتين، مرة واحدة في ملف header.php ومرة أخرى في ملف init.php، مما يسبب تكرار تحميل الأكواد وتأثيرًا سلبيًا على أداء الموقع وزيادة وقت التنفيذ. تستطيع إزالة إحدى الأكواد المكررة في الملفات، مثلاً إزالة السطر التالي من ملف init.php: include $tpl . 'navbar.php';
  17. من خلال الكود، لاحظت أنه هناك مشكلة صغيرة في تعريف العنوان الذي يتم استخدامه في توجيه الطلبات. يجب أن يكون عنوان الطريق كما يلي: Route::get('show/{id}', function($id) { $post = DB::table('posts')->find($id); return view('posts.show', compact('post')); }); لاحظ أنني قمت بتغيير {$id} إلى {id} في تعريف الطريق، حيث يجب أن يكون لديك واحد فقط $ قبل اسم المتغير في الطريق. تحتاج أيضًا إلى التأكد من وجود قيم في قاعدة البيانات تتطابق مع المعرّفات التي تحاول الوصول إليها في الرابط، فإذا كنت تحاول الوصول إلى /show/1، فيجب أن يكون هناك سجل في جدول "posts" يحمل معرّف 1. تأكد من أن هناك سجلات موجودة في قاعدة البيانات وأن المعرّفات التي تحاول الوصول إليها تتطابق مع هذه السجلات، وأيضًا تنفيذ الأمر الذي أخبرك به محمد. وإذا لم تكن هذه هي المشكلة، فيرجى تقديم المزيد من التفاصيل حول الخطوات التي قمت بها ورسالة الخطأ التي تحصل عليها.
  18. إذا كان السؤال متعلق بدورة PHP فأرجو منك طرح السؤال أسفل فيديو الدورة المتعلق بالسؤال، وطرح الأسئلة العامة هنا. ومن خلال رسالة الخطأ يظهر أن المشكلة تحدث في ملف header.php الذي يتم تضمينه في init.php. حيث يحدث خطأ في الوقت الأقصى المسموح لتنفيذ البرنامج، وذلك يشير إلى أن هناك عملية تستغرق وقتًا طويلًا للتنفيذ قبل أن يحدث خطأ التجاوز. و هناك أسباب محتملة لحدوث ذلك، مثلاً تعليمة معقدة في header.php تستغرق وقتًا طويلًا للتنفيذ، أو هناك حلقة تكرارية تستمر إلى ما لا نهاية، أو ربما يتم استدعاء ملف آخر يتسبب في تعليمة تكرارية. جرب تعليق السطور في header.php بشكل تدريجي واختبار الكود بعد كل خط لمعرفة أين تحدث المشكلة بالضبط، وقد تحتاج أيضًا إلى مراجعة ملفات أخرى مرتبطة بهذا المشروع للتحقق من أنها لا تسبب أي تضاربات أو مشاكل في التنفيذ. أو يمكنك مشاركة الكود في ملف header.php لتفقد المشكلة.
  19. أرجو منك طرح السؤال أسفل فيديو الدورة الخاص به في المرة القادمة. الأمر الذي استخدمته لإنشاء venv ليس كاملًا، حيث يتطلب استخدام أمر venv واحد على الأقل بعده، في الخطأ الذي تلقيته، يشير إلى أنه تم توفير ENV_DIR كواحد من الوسائط المطلوبة، ولكنها لم تتم تحديدها بشكل صحيح. فبدلاً من كتابة "python3 -m venv" فقط، يجب تحديد مسار المجلد الذي ترغب في إنشاء البيئة الافتراضية فيه. مثال: python3 -m venv venv حيث أن venv الأخيرة هي اسم المجلد الخاص بالبيئة الإفتراضية، وتستطيع تغيير الاسم كما تريد والاسم الشائع هو venv. وبعد إنشاء بيئة العمل الافتراضية باستخدام venv، عليك باتباع الخطوات التالية: 1- تفعيل بيئة العمل: venv\Scripts\activate ولاحظ أنه في أول الأمر تم كتابة اسم المجلد الخاص بالبيئة الإفتراضية. 2- تثبيت الحزم اللازمة: بعد تفعيل بيئة العمل، تستطيع تثبيت الحزم المطلوبة باستخدام مدير الحزم الخاص بـ Python (pip). مثلاً تثبيت حزمة Flask، استخدم الأمر التالي: pip install flask وعليك تثبيت باقي الحزم الأخرى اللازمة للمشروع، وأيضًا ضبط متغيرات البيئة كما سيتم شرحها لك في الدورة.
  20. معنى الرسالة أن هناك خطأ في ملف pubspec.yaml الخاص بمشروعك، والرسالة تشير إلى خطأ في السطر 61 في عمود 4، و يفترض أن يكون لديك مفتاح صحيح في هذا السطر وفقًا لصيغة YAML، لذلك حاول اتبع الخطوات التالية: قم بفتح ملف pubspec.yaml في محرر النصوص الخاص بك. انتقل إلى السطر 61 وتحقق من وجود أي أخطاء في النحو أو التنسيق. تأكد من أن المفتاح الموجود في هذا السطر صحيح ومكتوب بشكل صحيح وأنه ليس هناك أخطاء في التنسيق مثل تقديمه بطريقة صحيحة. بعد إجراء التعديلات المطلوبة، يجب أن تتمكن من تنفيذ flutter pub get بنجاح دون وجود أخطاء. وسأشرح لك الأمر بمثال عن كيفية حدوث خطأ مشابه في ملف pubspec.yaml: ... 60 dependencies: 61 assets: 62 - assets/images/ 63 - assets/fonts/ ... الخطأ في المثال هو أن العنصر "assets" يفتقد رمز النقطة الرأسية (colon) بعد كلمة "assets"، ويجب أن يكون الملف pubspec.yaml بهذا الشكل الصحيح: ... 60 dependencies: 61 assets: 62 - assets/images/ 63 - assets/fonts/ ... تأكد من إضافة النقطة الرأسية بعد "assets" وترتيب الهمزة والساكنة بشكل صحيح للمفتاح والقيمة الموجودة في القائمة، بعد ذلك، يجب أن تتمكن من تنفيذ flutter pub get بنجاح.
  21. سأوضح لك الخطوات التي أشار إليك بها عدنان: 1- إنشاء ملف XML لتصميم إشعارك، باستخدام عنصر RelativeLayout أو LinearLayout لتحديد تخطيط الإشعار الخاص بك وتضمين العناصر المختلفة مثل الصورة والنص. مثال: <!-- notification.xml --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/notification_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/notification_icon" /> <TextView android:id="@+id/notification_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/notification_icon" android:text="عنوان الإشعار" /> <TextView android:id="@+id/notification_message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/notification_title" android:layout_toRightOf="@id/notification_icon" android:text="رسالة الإشعار" /> </RelativeLayout> 2- في فئة النشاط (Activity) أو الخدمة (Service) التي ترغب في استخدام الإشعار، أنشئ كائنًا من فئة NotificationCompat.Builder لبناء الإشعار. مثال: // في الأعلى من الفئة، قم بإضافة استيرادات التالية: // import androidx.core.app.NotificationCompat; // import androidx.core.app.NotificationManagerCompat; public class MyActivity extends AppCompatActivity { // ... private static final String CHANNEL_ID = "my_channel_id"; // قم بتعيين قيمة فريدة لهذا المعرف private void showNotification() { // بناء الإشعار NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.notification_icon) .setContentTitle("عنوان الإشعار") .setContentText("رسالة الإشعار") .setPriority(NotificationCompat.PRIORITY_DEFAULT); // قم بإنشاء النقرة النائبة (PendingIntent) للتعامل مع نقرة المستخدم على الإشعار (اختياري) Intent intent = new Intent(this, MyActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0); builder.setContentIntent(pendingIntent); // إنشاء الإشعار NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); notificationManager.notify(notificationId, builder.build()); } // ... } 3- إنشاء قناة الإشعار (Notification Channel) في طراز الأندرويد الذي يدعم قنوات الإشعارات (Android 8.0 أو أعلى). مثال: public class MyApplication extends Application { private static final String CHANNEL_ID = "my_channel_id"; // يجب أن يتطابق مع القيمة المستخدمة في الخطوة السابقة @Override public void onCreate() { super.onCreate(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // إنشاء قناة الإشعار CharSequence name = "اسم القناة"; String description = "وصف القناة"; int importance = NotificationManager.IMPORTANCE_DEFAULT; NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance); channel.setDescription(description); // تهيئة إعدادات قناة الإشعار NotificationManager notificationManager = getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(channel); } } } 4. تنفيذ دالة showNotification() عند الحاجة لعرض الإشعار. بمجرد تنفيذ دالة showNotification()، ستقوم ببناء الإشعار وعرضه للمستخدم، وتستطيع استدعاء هذه الدالة من أي مكان في تطبيقك وفي أي سياق مناسب. مثلاً استدعاء showNotification() عندما يتم اكتشاف حدث جديد في التطبيق، مثل وصول رسالة جديدة أو تحديث مهم، أيضًا استدعائها من داخل خدمة (Service) لعرض إشعارات دورية أو قائمة بالتحديثات الجديدة. مثال على استدعاء showNotification(): public class MyActivity extends AppCompatActivity { // ... private void checkForNewMessages() { // افحص على وجود رسائل جديدة // إذا تم العثور على رسالة جديدة، عرض إشعار if (hasNewMessages()) { showNotification(); } } // ... } تأكد من تعيين القيم المناسبة لكائن NotificationCompat.Builder في دالة showNotification() واستخدم الأساليب المناسبة لتخصيص الإشعار حسب احتياجات تطبيقك. من الهام جدًا أن تتذكر أنه بدءًا من Android 8.0 (API level 26)، يجب عليك إنشاء قناة إشعارات (Notification Channel) وتعيينها لكائن NotificationCompat.Builder حتى يتم عرض الإشعار بنجاح. وتأكد من استدعاء الدالة createNotificationChannel() في الوقت المناسب، كما تم شرحه في الخطوة 3 في الإجابة السابقة.
  22. رسالة الخطأ في الملف App.js تعني أن هناك مشكلة في تعريف المتغير 'Text'، حيث أنه غير معرف. وعليك أولاً بكتابة المكون بشكل صحيح، عن طريق تمرير props كمعامل في المكون كالتالي: import React from 'react'; function Text(props) { return <p>{props.text}</p>; } export default Text; ثم يمكنك استيراد المكون "Text" في ملف App.js واستخدامه كما تريد: import React from 'react'; import Text from './Text'; function App() { return ( <div> <Text text="مرحبًا بك" /> </div> ); } export default App; ولاحظ أنني قمت بتمرير text كـ prop بقيمة مرحبًا بك للمكون Text. ,تأكد من وضع ملف "Text.js" في نفس المجلد الذي يحتوي على ملف "App.js"، أو قم بتعديل المسار المناسب في حالة وجودهما في مجلدين منفصلين، أي استورده بشكل صحيح.
  23. في مجال البرمجة لا غنى عن مستوى مقبول من اللغة الإنجليزية، ففي العمل اليومي ستتعرض للغة الإنجليزية بلا شك، سواء عند البحث عن مشكلة تريد حل لها على المواقع الأجنبية، أو قراءة المستندات الخاصة بالمكتبات وإطار العمل الذي تستخدمه من أجل معرفة كيفية استخدام ميزة معينة في المشروع أو من أجل حل مشكلة تواجهك. وأيضًا في الإيميلات والتراسلات بين فريق العمل قد يتم استخدام اللغة الإنجليزية بها، لذلك أنت بحاجة إلى مستوى مقبول من حيث القراءة والاستماع والكتابة وقد يتم التغاضي عن التحدث. أي يجب إمتلاك ما تستطيع به تسيير أمور عملك اليومي بدون مشاكل، وإلا سيتم إختيار شخص آخر يمتلك مهارات تواصل جيدة فبيئة العمل لا تعني كتابة الكود فقط. وربما تجد شركات تستخدم لا تحتاج إلى لغة إنجليزية في بيئة العمل، لكن ذلك أمر نادر تلك الأيام حيث يجب إمتلاك مستوى مقبول كما ذكرت، وتستطيع دراسة اللغة الإنجليزية من قناة طليق أو ذي أمريكان إنجليش على اليوتيوب أو من خلال تطبيق الهاتف. وقد تم التطرق إلى سؤالك بالتفصيل في النقاش التالي:
  24. بالنسبة لسؤالك الأول: فتطبيقات تسجيل المكالمات المتوفرة على Google Play تعمل بطرق مختلفة وتختلف في سياساتها وقدراتها، وأغلبها يقوم بتنفيذ العملية على جهازك الخاص، وليس على خوادم المطور الخارجية. وغالبًا ما يتم تخزين ملفات تسجيل المكالمات على جهازك أو في سحابة التخزين الشخصية التي تحددها (مثل Google Drive أو Dropbox)، وليس عند مطور التطبيق. بالتالي، فإن الأرقام والتفاصيل الشخصية المتعلقة بالمكالمة تكون محفوظة فقط على جهازك وليست متاحة للمطور. ومع ذلك، يجب أن تتأكد من قراءة سياسة الخصوصية وشروط الاستخدام لكل تطبيق تسجيل المكالمات قبل استخدامه. قد توجد بعض التطبيقات التي تجمع وتخزن المكالمات على خوادم المطور، ولذا يجب أن تتأكد من الإعدادات والسياسات الخاصة بالتطبيق لمعرفة كيفية معاملة بياناتك الشخصية. وبالنسبة لسؤالك الثاني: في حالة كان هناك خاصية التخزين السحابي ومزامنة التسجيلات الخاصة بك، فتستطيع تحميل التطبيق والدخول بحسابك وستجد المكالمات التي تم تسجيلها سابقًا. أما إذا كان يتم التخزين على حسابك في Google Drive فعليك بتفقد المجلد هناك وستجد المكالمات المسجلة. أما إذا كان يتم التخزين على جهازك وحذفت التطبيق، فهناك إحتمالان، الأول أن مجلد المكالمات المسجلة قد تم حذفه ولن تستطيع استرجاعه حيث أن ذلك حدث منذ فترة بناءًا على كلامك. والإحتمال الثاني أن مجلد المكالمات المسجلة مازال موجود وعليك بتفقد الملفات الصوتية لديك للتأكد من ذلك.
  25. المشكلة تحدث عندما تحاول تحويل قيمة من نوع int إلى نوع String في السطر التالي: controller.itemsId.toString() ويتوقع البرنامج أن يكون itemsId من نوع String وليس int. لذلك عليك بتحويل itemsId إلى String قبل تمريره إلى paniercontroller، وتستطيع استخدام الدالة toString() لتحقيق ذلك. وهناك عدة طرق لفعل ذلك، ومنها: controller.paniercontroller.add(controller.itemsId.toString()); من المهم أيضًا التحقق مما إذا كانت القيمة controller.itemsId صحيحة وغير فارغة، فقم بالتحقق من صحة القيمة قبل تحويلها إلى سلسلة نصية باستخدام شرط مثل هذا: IconButton( onPressed: () { if (controller.itemsId != null) { controller.paniercontroller.add( controller.itemsId.toString() ); } }, icon: Icon(Icons.add) ),
×
×
  • أضف...