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

Mustafa Suleiman

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

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

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

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

    365

إجابات الأسئلة

  1. إجابة Mustafa Suleiman سؤال في تخزين البيانات في متصفح الويب باستخدام JavaScript و localStorage كانت الإجابة المقبولة   
    عليك باستخدام localStorage لحفظ القيم المدخلة في حقول الإدخال، وذلك بتعديل السكريبت لديك بالشكل التالي:
    let submit = document.getElementById('submit'); let text = document.getElementById('text'); let password = document.getElementById('password'); // عرض البيانات المحفوظة عند تحميل الصفحة window.onload = function() { let savedText = localStorage.getItem('text'); if (savedText) { text.value = savedText; } let savedPassword = localStorage.getItem('password'); if (savedPassword) { password.value = savedPassword; } }; submit.onclick = function () { if (text.value === 'محمد عماد احمد' && password.value === '10203') { alert('نعم'); // حفظ القيم في localStorage localStorage.setItem('text', text.value); localStorage.setItem('password', password.value); } else { alert('لا'); } let screenWidth = screen.availWidth; if (screenWidth > 1000) { alert('فقط الهواتف المحمولة، من فضلك'); } else { alert('الهاتف المحمول المناسب'); } }; يستخدم localStorage.setItem(key, value) لحفظ القيم في ذاكرة التخزين المحلية للمتصفح.
    وعند تحميل الصفحة، يستخدم localStorage.getItem(key) لاسترداد القيم المحفوظة وتعيينها في حقول الإدخال، وستظل القيمة محفوظة حتى بعد تحديث الصفحة.
     
  2. إجابة Mustafa Suleiman سؤال في كيفية العمل على مواقع العمل الحر كمبرمج فلاتر وتحديد السعر المناسب للساعة والمشروع كانت الإجابة المقبولة   
    إذا كنت قد تعلمت فلاتر بالفعل وتريد العمل على موقع العمل الحر، فأمامك مساحة واسعة للإختيار من بينها، ومنها مواقع مثل مستقل وخمسات وبعيد، وعلى تلك الموقع يتم العمل بتكلفة ثابتة Fixed للمشروع قابلة للزيادة والتعديل في حالة وجود ميزات إضافية لم يتم الإتفاق عليها.
    أما عن نظام الساعة، فعليك بتفقد الأسعار لمبرمجي فلاتر من حيث سعر الساعة، ثم ضع احسب متوسط السعر وضع سعر ساعة منخفض قليلاً عن المتوسط في البداية وقدم جودة عمل جيدة أعلى من المطلوب ولكن لا تفرض على نفسك ذلك أي التزم بالمطلوب وقم بتقديم أكثر منه وهناك مبدأ دائمًا أحب الإلتزام به في العمل الحر، ألا وهوUnder Promise And Over Deliver بمعنى أن الجميع يسرد أشعار للعميل وسيفعل وسيفعل وذلك خطأ.
    بل التزم بما هو مطلوب منك أو أعلى قليلاً للمنافسة في البداية، ثم وفر أكثر مما هو ممطلوب وستجد أن العميل سعيد جدًا بذلك وأيضًا لم تفرض على نفسك أي شيء.
    وبخصوص كيفية حساب الساعة فإليك بعض النقاط التي ستساعدك:
    قم بتحديد ما هي نوعية العمل التي ستقدمها؟ هل تعمل على تطوير تطبيقات بسيطة أو معقدة؟ ما هو مستوى الخبرة المطلوبة؟ إجراء بحث عن أسعار الساعة المعتادة لمبرمجي فلاتر على منصات العمل الحر، وتستطيع الاطلاع على مشاريع مماثلة والتحقق من الأسعار المقدمة من قبل المطورين الآخرين. احتسب سنوات الخبرة التي تمتلكها كمبرمج فلاتر، فستتمكن من تحقيق سعر أعلى إذا كنت تمتلك خبرة واسعة ومشاريع ناجحة في معرض أعمالك. تحديد تكاليف العمل الخاصة بك، وتشمل هذه العناصر تكاليف المعدات والبرمجيات والوقت الذي ستستغرقه في إكمال المشروع. مع الوقت سيكون لديك فكرة تقريبية عن الوقت المستغرق لإكمال مشروع معين، فقم بتحديد عدد الساعات المتوقعة للعمل على المشروع. تحديد المبلغ الذي ترغب في كسبه من العمل الحر، فيمكن أن يكون المبلغ مبنيًا على احتساب قيمة ساعة العمل الأساسية وإضافة الربح المرغوب. ولكن عدد الساعات لا يعني أبدًا التكلفة الحقيقية للمشروع، فمثلاً بعد سنوات خبرة، ستستطيع إنهاء مشروع في وقت أقل وبجودة أعلى فهل ذلك يعني أنك تتقاضى مبلغ أقل، بالطبع لا، هنا عليك إما بحساب تكلفة ثابتة للمشروع أو وضع عدد ساعات مناسب ومرضي لك.
    وأنصحك بقراءة التالي:
     
  3. إجابة Mustafa Suleiman سؤال في أشهر البوتات في Discord ووظائفها المفيدة كانت الإجابة المقبولة   
    هناك كم هائل من الوظائف التي بإمكان تلك الروبوتات القيام بها ومنها:
     إنشاء وحذف وتحرير القنوات، وتعيين الأذونات اللازمة للأعضاء.  تتبع نشاط المستخدمين ومنحهم مستويات وأدوار مخصصة بناءً على تفاعلهم في الخادم.  تشغيل الموسيقى في قنوات الصوت من مصادر مثل YouTube أو Spotify، ويمكنها التحكم في مستوى الصوت وتشغيل قوائم التشغيل. إرسال إشعارات وتذكيرات للأعضاء في الخادم، مثل تذكير بالأحداث المهمة أو مواعيد الاجتماعات.  تقديم ألعاب تفاعلية للأعضاء، مثل ألعاب الكلمات المتقاطعة أو ألعاب الأدوار البسيطة. البحث عن معلومات عبر الإنترنت وتقديمها للأعضاء، مثل الأخبار أو توقعات الطقس أو معلومات عامة.  الترحيب بالأعضاء الجدد في الخادم وتوديع الأعضاء الذين يغادرون. مراقبة النشاط في الخادم والكشف عن المخالفات والسلوك غير الملائم، وتنفيذ تدابير الأمان المطلوبة مثل حظر الأعضاء المخالفين.  تنظيم مسابقات وألعاب تفاعلية للأعضاء، مثل ألعاب الألغاز أو ألعاب الأدوار المتقدمة.  توفير الدعم الفني والإجابة على الأسئلة الشائعة للأعضاء، وتقديم التوجيه والمساعدة في استخدام الخادم.  الاتصال بمنصات أخرى مثل Twitter أو Reddit وتقديم تحديثات مباشرة للأعضاء. توفير أوامر خاصة بتخصيص واجهة الخادم، مثل تغيير الألوان والخلفيات وإضافة الرموز التعبيرية المخصصة. بالنسبة لأشهر البوتات في Discord، فهناك العديد من البوتات المشهورة ومنها:
    Dyno: بوت متعدد الاستخدامات يوفر ميزات إدارة الخادم ونظام المستويات والموسيقى والأدوار. MEE6: يوفر نظام المستويات والأدوار والموسيقى والترحيب والإشعارات والمسابقات. Tatsumaki: يقدم نظام المستويات والأدوار والألعاب والإحصائيات والترحيب والتوديع. Dank Memer: للترفيه يقدم ألعاب الكلمات والميمات والنكات والصور المضحكة. Rythm: لتشغيل الموسيقى من مصادر مثل YouTube وSpotify وSoundCloud.
  4. إجابة Mustafa Suleiman سؤال في شرح استخدام الفئة المجردة abstract class في فلاتر BLOC كانت الإجابة المقبولة   
    السبب وراء وضع الـ abstract class في بداية قائمة الـ states في فلاتر BLOC هو لتوفير واجهة مشتركة لجميع حالات الحالة (states) المحتملة التي يمكن أن يتبعها Cubit أو Bloc.
    وباستخدام الـ abstract class ، تستطيع تعريف مجموعة محددة من الحالات الأساسية التي قد يعتمدها Cubit أو Bloc دون الحاجة إلى إعادة تعريف الأساليب الأساسية في كل مرة.
    والكود في الصورة، تم به تعريف NewestBooksState كـ abstract class وتنفيذها من قبل عدة حالات محددة، مثل NewestBooksInitial و NewestBooksLoading و NewestBooksFailure و NewestBooksSuccess.
    ومن خلال استخدام abstract class، تستطيع توحيد النهج وتطبيق المنطق المشترك بين حالات الحالة المختلفة، مثل توفير قائمة الممتلكات (props) المشتركة وأي أساليب أخرى ترغب في تعريفها لجميع حالات الحالة.
    أيضًا بوجود abstract class، بإمكانك استخدام المتغيرات من نوع NewestBooksState للإشارة إلى أي حالة من حالات الحالة، مما يسهل تحديد الحالة الحالية واتخاذ الإجراءات المناسبة في الـ Cubit أو Bloc الخاص بك.
    وسأقدم لك مثالًا يوضح كيفية استخدام الفئة المجردة (abstract class) في فلاتر BLOC، ولنفترض أن لدينا Cubit لإدارة حالة قائمة أحدث الكتب في تطبيق مكتبة.
    فتستطيع كتابة الفئات المختلفة على النحو التالي:
    import 'package:equatable/equatable.dart'; abstract class NewestBooksState extends Equatable { const NewestBooksState(); @override List<Object> get props => []; } class NewestBooksInitial extends NewestBooksState {} class NewestBooksLoading extends NewestBooksState {} class NewestBooksFailure extends NewestBooksState { final String error; const NewestBooksFailure(this.error); @override List<Object> get props => [error]; } class NewestBooksSuccess extends NewestBooksState { final List<Book> books; const NewestBooksSuccess(this.books); @override List<Object> get props => [books]; } هنا لدينا الفئة المجردة NewestBooksState التي تم تنفيذها من قبل عدة حالات محددة.
    وNewestBooksState يحتوي على المنطق المشترك لجميع حالات الحالة، والذي يشمل تنفيذ props لإعطاء معرف فريد لكل حالة، وذلك لتمكين المقارنة والتعامل مع التغييرات في الحالة بشكل فعال.
    NewestBooksInitial: حالة البداية، ويمثل الحالة الأولية للقائمة. NewestBooksLoading: حالة التحميل، ويشير إلى أن القائمة تحمل البيانات حاليًا. NewestBooksFailure: حالة الفشل، ويشير إلى حدوث خطأ أثناء جلب البيانات، ويحتوي على رسالة الخطأ المحددة. NewestBooksSuccess: حالة النجاح، ويشير إلى أن البيانات تم جلبها بنجاح، ويحتوي على قائمة الكتب الأحدث. وباستخدام الفئة المجردة NewestBooksState وحالاتها المحددة، يمكنك توحيد المنطق وإدارة حالة قائمة الكتب في Cubit الخاص بك، وإصدار حالة معينة باستخدام emit داخل Cubit بناءً على المنطق والأحداث التي تحدث في التطبيق.
  5. إجابة Mustafa Suleiman سؤال في خطأ في نشر تطبيق فلاتر على ابل ستور كانت الإجابة المقبولة   
    App ID
    هو هوية فريدة تُعرف في بيئة تطوير Apple وتُستخدم لتمييز التطبيقات الخاصة بك عند توزيعها أو تحديثها. يحتوي App ID على سلسلة نصية مميزة تُعبر عن هوية التطبيق.
    عند إنشاء تطبيق جديد، يتم إنشاء App ID خاص به ويكون له تكوين معين يشمل معلومات مثل Bundle Identifier والخدمات المرتبطة بالتطبيق مثل Push Notifications وApp Groups وغيرها.
    Bundle Identifier
     مُعرّف فريد للتطبيق في إطار التطوير ويستخدم لتمييز التطبيق على نظام iOS، ويتم تعريف Bundle Identifier في مشروعك في Xcode ويتم استخدامه كمعرّف للتطبيق أثناء عملية التطوير والبناء.
    وقد يحتوي Bundle Identifier على نفس القيمة التي تستخدمها في App ID، ولكنها ليست نفس الشيء.
    باختصار، Bundle Identifier هو المعرّف الذي يتم استخدامه أثناء تطوير وبناء التطبيق في Xcode، في حين أن App ID هو المعرّف الفريد في بيئة تطوير Apple ويستخدم لتمييز التطبيق أثناء توزيعه على Apple App Store أو استخدام الخدمات المرتبطة بالتطبيق.
    لذلك تأكد من استخدام Bundle Identifier الصحيح في Xcode  و وجود App ID صحيح مقابله في حسابك على موقع مطوري Apple.
  6. إجابة Mustafa Suleiman سؤال في تفسير عدم حدوث استثناء عند استخدام Column داخل SingleChildScrollView كانت الإجابة المقبولة   
    عند وضع 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 ويمكن التمرير لعرض المحتوى الكامل.
  7. إجابة Mustafa Suleiman سؤال في نمط Repository أم نمط MVVM: الأفضل لتطوير مشاريع فلاتر؟ وما هو الفارق بينهما؟ كانت الإجابة المقبولة   
    عند العمل على مشاريع فلاتر (Flutter)، باستطاعتك استخدام أنماط مختلفة لتنظيم وإدارة الكود، وهناك نمطين شائعين في عالم فلاتر هما MVVM و Repository.
    سأوضح لك الفارق بينهما وسأشرح كل نمط على حدة
    1- MVVM (Model-View-ViewModel)

    يعتبر MVVM من أنماط التصميم الأكثر شيوعًا في تطوير تطبيقات الهواتف المحمولة بما في ذلك فلاتر، وينقسم هذا النمط إلى ثلاثة أجزاء رئيسية:
    Model: يمثل البيانات والمنطق الخاصة بالتطبيق، ويمكن أن يكون لديك مثيلات للنماذج التي تحتوي على بيانات يستخدمها التطبيق. View: تمثل واجهة المستخدم، وتعرض البيانات المنتجة من ViewModel وتتفاعل مع المستخدم. ViewModel: يعمل كوسيط بين Model و View، ويتولى استرجاع البيانات من Model وتحويلها إلى شكل مناسب للعرض على الـ View، أيضًا يحتوي على المنطق اللازم للتعامل مع استجابة المستخدم. الفكرة الرئيسية وراء MVVM هي فصل الواجهة البصرية عن البيانات والمنطق الخاصة بها، مما يتيح تبسيط عملية اختبار وصيانة التطبيق وسهولة إضافة ميزات جديدة.
    2- Repository Pattern

    يستخدم نمط Repository لإدارة استرجاع البيانات وحفظها في التطبيق، ويقدم هذا النمط واجهة وسيطة (Interface) تحدد العمليات الممكنة مع البيانات مثل الاسترجاع والحفظ والتحديث والحذف، ويقوم المستودع (Repository) الفعلي بتنفيذ هذه العمليات باستخدام مصادر البيانات المناسبة مثل قواعد البيانات أو خدمات الويب.
    وفي سياق فلاتر، يمكن أن يكون المستودع هو الجزء الذي يسترجع البيانات من قواعد البيانات أو يتصل بخدمات الويب لجلب البيانات، وبإمكانك استخدام Repository Pattern بشكل مستقل أو مع نمط آخر مثل MVVM لتوفير واجهة بين النمطين.
    أي الفكرة الأساسية وراء Repository Pattern هي تجنب تكرار كود الوصول للبيانات في مختلف أجزاء التطبيق، وتوفير واجهة واحدة للتعامل معها، بدلاً من أن يتم استدعاء وكتابة الاستعلامات المباشرة في أجزاء مختلفة من التطبيق، ويستخدم المستودع كوسيط للتفاعل مع البيانات.
    الأسلوب الأكثر احترافية
    الأمر يعتمد على نوع المشروع وحجمه وتعقيده،  فعادةً ما ينصح باستخدام نمط MVVM لأنه يفصل واجهة المستخدم عن البيانات ويسهل اختبار وصيانة التطبيق.
    أما إذا كنت تعمل على مشروع بسيط وغير معقد، فتستطيع استخدام نمط Repository بشكل مستقل، وإذا اقتضى الأمر تستطيع أيضًا استخدام كلا النمطين معًا.
     
  8. إجابة Mustafa Suleiman سؤال في كيفية الحصول على وظيفة في شركات FAANG؟ كانت الإجابة المقبولة   
    ما يؤهلك للعمل في تلك الشركات هو تعلم مجالك بإحترافية وسنوات الخبرة المطلوبة في وصف الوظيفة والأمر مختلف من وظيفة لأخرى، لكن ما يهم حقًا هو تعلم Data Structure وAlgorithms وSystem Design والـ Problem Solving.
    حيث أنه يتم إختبارك في تلك المهارات بشكل قوي، وستجد العديد من الكورسات التي تؤهلك لإجتياز تلك الإختبارات من خلال تعلم تلك المهارات بشكل قوي وعلى أسس صحيحة، لا أن تحقظ حل بعض الأسئلة الشهيرة فقط فبذلك أنت تخدع نفسك.
    وأيضًا مهارات الـ Soft skills وتستطيع البحث عنها على اليوتيوب وهي هامة جدًا في مقابلات العمل، بالإضافة إلى تعلم مهارة إنشاء CV قوي أي مهارة كيف تعرض وتسوق لنفسك بشكل مختصر وتلك مهارة هامة سواء في الـ  CV أو مقابلة العمل.
    والأمر سيسير كالتالي:
    أولاً عليك الحصول على مقابلة عمل، وإليك بعض النقاط حول ذلك:
    يحتاج المرشح للحصول على مقابلة عمل في إحدى شركات FAANG. تكون هناك الكثير من السير الذاتية التي ترسل لشركات تكنولوجيا المعلومات، ومعظمها سيئة التنسيق ولا تشتمل على تعليم في علوم الحاسوب أو خبرة. هناك بعض الطرق الفعالة لتميز سيرتك الذاتية هنا، مثل: 1. الحصول على توصية من موظف داخل الشركة، 2. وجود خبرة عمل كمبرمج، 3. حصولك على شهادة في علوم الحاسوب، و 4. تقديم سيرة ذاتية تبدو جميلة (قليل من الأخطاء الإملائية، تنسيق جيد، وربما تحتوي على عدة لغات برمجة أو شيء مشابه). والتركيز يجب أن يكون على أسهل طريقة وهي الحصول على توصية، قم ببناء شبكتك الاجتماعية وابحث عن أشخاص يعملون في تلك الشركات الكبرى الذين يمكنهم تقديم سيرتك الذاتية، وهذه خطوة جيدة لك ولهم أيضًا لأن تلك الشركات تدفع مكافآت مالية للمهندسين الذين يوصون بمزيد من المهندسين البرمجيين. بعد ذلك، قم بالتركيز على النقطة الثانية. النقطة الثانية: أداء جيد في المقابلة.
    بعد تحقيق النقطة الأولى، ستحصل على مقابلات في الشركات الخمس. لاحظ أن معدل نجاح هذه المقابلات منخفض، فعادةً ما تبدأ بامتحان تلقائي أو مكالمة هاتفية لمدة ساعة مع مهندس برمجي أو اثنين، وسيطرحون عليك سؤالًا مأخوذًا مباشرة من "Cracking the Coding Interview"، وستكتب إجابة وتقول "هذا O(N log N)" وسيشيدون بك لأنك واحد من بين خمسة أشخاص تقريبًا تجتازوا تلك الاختبارات الهاتفية وتستمرون في المراحل التالية. وللنجاح في تلك المرحلة، يجب دراسة الخوارزميات وهياكل البيانات، وحل مشاكل مماثلة لـ LeetCode، ونأمل أن يقوم أحد أصدقائك الذين قدمت لهم توصية بإجراء بعض المكالمات التجريبية للممارسة.
    وهذا النوع من الممارسة سيكون جزءًا كبيرًا من تركيزك خلال فترة العمل لمدة عامين، وهذا هو المعيار الرئيسي الذي ستقيم عليه، إلى احترافيتك أثناء المقابلة والتجهيز الجيد لها.
    بعد ذلك، ستأتي مرحلة المقابلة في المكان الفعلي (on-site interview) وستكون مشابهة للمقابلة الهاتفية باستثناء أنك ستجري خمسة مقابلات متتالية.
    وقد يكون لديك فرصة 1 من بين 6 لاجتياز هذه المرحلة، في المتوسط.
    وستساعدك الممارسة بشكل كبير. الأخبار الجيدة هي أن العملية تعتمد إلى حد كبير على الصدفة، بفرض أنك جيد جدًا في الإجابة على هذا النوع من المشكلات، فإذا ما قمت بالمقابلة في الشركات الخمس، فإن الفرص جيدة جدًا أن يتم اجتيازك في إحداها، وسوف تتحسن قدرتك على المقابلة مع الوقت.
    بالإضافة إلى ذلك، تتوفر لدى بعض هذه الشركات فرصة لإعادة المقابلة بعد ستة أشهر إلى سنة.
    لذا، فإن الفرصة لاجتياز المقابلة الأولى ضئيلة، ولكن الفرصة جيدة في الواقع لاجتياز إحدى المقابلات في النهاية، وتحتاج فقط إلى اجتياز المقابلة مرة واحدة.
    وهل أنت مرتاح في التحدث أمام عدة أشخاص؟ عليك بأن تصبح مرتاحًا من خلال إجراء مقابلات عمل والتعود عليها، وانتبه إلى أن حل مشكلة خوارزمية في المنزل شيء، وحل مشكلة خوارزمية على لوح أبيض أمام عدة أشخاص ومهنة تحقق من ستة أرقام مالية هي شيء آخر تمامًا.
    وبالطبع عليك العمل على اللغة الإنجليزية الخاصة بك، وأنصحك بمشاهدة الفيديو التالي على اليوتيوب:
    كيف تصل للشركات العالمية؟ || بودكاست مع المهندس أحمد علي - مهندس برمجيات في شركة فيسبوك. وستتعلم الكثير خلال مقابلة مدتها ساعة ونص من المعلومات المفيدة حقًا.
  9. إجابة Mustafa Suleiman سؤال في أهمية الترتيب في pseudo-classes لتنسيق الروابط في CSS كانت الإجابة المقبولة   
    أولاً سأشرح لك ما معنى كل من الـ pseudo-classes الآتية:
    وقبل ذلك لنفهم ما معنى pseudo-class في CSS، وهي تعبير يستخدم لتحديد حالة محددة أو حالة خاصة لعنصر HTML، وتسمح pseudo-classes بتطبيق أنماط وتنسيقات مختلفة للعناصر بناءً على حالتها أو عنصر معين.
    {}a:link هذا يحدد النمط الذي ستظهر به الروابط التي لم يتم النقر عليها بعد (روابط لم يتم زيارتها). {}a:visited يحدد النمط الذي ستظهر به الروابط التي تم النقر عليها مسبقًا (روابط تم زيارتها أي النقر عليها). {}a:focus تحدد النمط الذي ستظهر به الروابط عندما تكون محددة بواسطة المستخدم (جرب الضغط على Tab في الكيبورد وستجد أنه يتم التنقل بين عناصر الصفحة إلى أن تصل للروابط).
    {}a:hover يحدد النمط الذي ستظهر به الروابط عندما يتم تحريك المؤشر فوقها. {}a:active يحدد النمط الذي ستظهر به الروابط عندما يتم النقر عليها (الضغط بالفأرة دون الإفلات أي بشكل مستمر أي اللحظة التي تضغط فيها بالفأرة). والترتيب الذي يشترط في هذه القواعد هو أمر مهم لأنه يُحدد ترتيب تطبيق الأنماط وتعديلات الشكل على الروابط وفقًا لحالة الروابط وتفاعل المستخدم معها.
    ولكن ذلك ليس ضروري حيث أن التنسيق هنا يتم بناءًا على حالة العنصر وليس موقعه في الكود المكتوب، وفي حال قمت بكتابة مثلاً focus أو hover في البداية فلن يتغير شيء، حيث يطبق التنسيق بناءًا على حالة العنصر فقط.
    ولتوضيح أفضل، إليك مثالًا على كيفية استخدام هذه القواعد:
    a:link { color: blue; } a:visited { color: purple; } a:focus { color: DarkTurquoise; } a:hover { color: red; } a:active { color: green; } وستكون الروابط غير المزارة باللون الأزرق (a:link)، وعندما يتم النقر على الرابط ويتم تحويله إلى حالة مزارة، سيتغير لونه إلى اللون البنفسجي (a:visited).
    وعند التنقل بين عناصر الصفحة عند الضغط على Tab سيكون اللون هو DarkTurquoise.
    وعند تحريك المؤشر فوق الرابط، سيتغير لونه إلى اللون الأحمر (a:hover)، وعند النقر عليه، سيتغير لونه إلى اللون الأخضر (a:active) وجرب عدم الإفلات أي اضغط بشكل مستمر وستجد أن لونه أخضر.
    وإليك مثال:
    <!DOCTYPE html> <html> <head> <title>تنسيق الروابط</title> <style> a { color: blue; } a:visited { color: p; } a:focus { color: DarkTurquoise; } a:hover { color: red; } a:active { color: green; } </style> </head> <body> <h1>تنسيق الروابط</h1> <p> <a href="#">روابط الصفحة</a> <br> <a href="#">رابط آخر</a> <br> <a href="#">رابط إضافي</a> </p> </body> </html>
  10. إجابة Mustafa Suleiman سؤال في إضافة إشعارات في تطبيق Android Studio كانت الإجابة المقبولة   
    سأوضح لك الخطوات التي أشار إليك بها عدنان:
    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 في الإجابة السابقة.
     
  11. إجابة Mustafa Suleiman سؤال في سبب خطأ Base table or view already exists في مشروع لارافيل كانت الإجابة المقبولة   
    الخطأ يعني أن الجدول 'posts' موجود بالفعل في قاعدة البيانات ولا يمكن إنشاؤه مرة أخرى، وذلك أمر طبيعي يحدث عندما تحاول تشغيل عملية إنشاء جدول عن طريق التهجير والجدول بالفعل موجود في قاعدة البيانات.
    لذلك الأمر الصحيح هو التالي:
    php artisan migrate:fresh --seed فهو يستخدم في Laravel لإعادة إنشاء وتحديث قاعدة البيانات بالجداول والبيانات الأولية، و يتكون من عدة أجزاء:
    "php artisan": يشير إلى تشغيل أمر Laravel عبر واجهة سطر الأوامر. "migrate:fresh": يعني أنه سيتم إعادة إنشاء كل الجداول في قاعدة البيانات، ويتم حذف جميع الجداول الموجودة في قاعدة البيانات وإعادة إنشائها بناءًا على ملفات الترحيل (migrations) الموجودة في مشروع Laravel. "--seed": يشير إلى أنه سيتم تشغيل ملفات بزر البيانات الأولية (seeds) بعد إعادة إنشاء الجداول، وملفات البزر تستخدم لإضافة بيانات افتراضية أو تجريبية إلى قاعدة البيانات بعد إعادة إنشاء الجداول.
  12. إجابة Mustafa Suleiman سؤال في إضافة ميزة محرر النصوص في تطبيق Flutter لإضافة وتحرير النصوص وإضافة الصور والروابط كانت الإجابة المقبولة   
    في دالة onSave التي قمت بتعريفها  في المثال السابق في RichTextField، قم بتنفيذ الخطوات التالية لحفظ النص والصور والروابط في Firebase:
    استخدم Firebase Auth للتحقق من هوية المستخدم والتأكد من أنه مسجل دخوله. استخدم Firebase Firestore لإنشاء وثيقة جديدة وحفظ النص والصور والروابط في حقول مناسبة، وباستطاعتك تخزين الصور في تخزين Firebase Storage وتخزين روابطها في Firestore، وتخصيص الطريقة التي تحفظ بها البيانات في Firebase حسب طبيعة تطبيقك. مثلاً، لحفظ محتوى المحرر (النص والصور والروابط) في Firebase Firestore، من الممكن تعريف حقول كالتالي:
    حقل "نص" (Text field) لتخزين النص الذي يتم إدخاله أو تحريره. حقل "صورة" (Image field) لتخزين الصورة المحملة من المحرر. حقل "روابط" (Links field) لتخزين الروابط المدخلة.
  13. إجابة Mustafa Suleiman سؤال في حل مشكلة GitHub لا يقبل رفع أكثر من 100 ملف في المرة الواحدة كانت الإجابة المقبولة   
    السبب هو أنك لم تقم بإنشاء ملف باسم  .gitignore والذي يتجاهل كافة الملفات والمجلدات ما عدا الكود المصدري الخاص بالمشروع، أي لا يتم رفع مجلد venv مثلاً فبه البيئة الإفتراضية الخاصة بك وأيضًا المكتبات التي تم تثبيتها.
    ولذلك عليك بإنشاء ملف بالاسم التالي في مجلد المشروع:
    .gitignore ولاحظ وجود نقطة في بداية الاسم، أي ذلك الملف يتم إنشائه بجوار مجلد venv لديك ومجلد taskaty الخاص بالمشروع.
    وضع به التالي:
    ولكن يجب التوضيح نص الملف gitignore التالي خاص ببايثون، وسأقوم بإرفاق ملف خاص بمشاريع الويب في المرفقات أي التي تستخدم HTML, CSS, JS.
    ### Python ### # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ pip-wheel-metadata/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST .history/ # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coveage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ pytestdebug.log # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ doc/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # PEP 582; used by e.g. github.com/David-OConnor/pyflow __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ pythonenv* # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # pytype static type analyzer .pytype/ # profiling data .prof # Virtualenv # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ .Python [Bb]in [Ii]nclude [Ll]ib [Ll]ib64 [Ll]ocal [Ss]cripts pyvenv.cfg .venv pip-selfcheck.json ثم عليك بتنفيذ الأمر التالي:
    git rm -r --cached من أجل إزالة التعقب عن الملفات والمجلدات التي لا نريد تعقبها كما أشرنا إليها في الملف .gitignore وبعد ذلك قم بإعادة أوامر رفع المشروع وهي:
    1- قم بإضافة كل ملفات المشروع لرفعها من خلال الأمر التالي:
    git add . 2- عمل commit من خلال الأمر التالي:
    git commit -m "Upload files" 3- إضافة العنوان البعيد (remote URL) لمستودع GitHub الخاص بك مع الأمر التالي:
    git remote add origin https://github.com/moazzant226/react.git أخيرًا، استخدم الأمر التالي لرفع التحديثات إلى مستودع GitHub الخاص بك:
    git push -u origin main  
    .gitignore
  14. إجابة Mustafa Suleiman سؤال في من لم يشكر الناس لم يشكر الله كانت الإجابة المقبولة   
    ألف مبروك يا منتصر، وسنك صغير ما شاء الله عليك صراحة، واصل إجتهاد وهتحقق أكتر بكتير إن شاء الله، وركز إنك تتعلم الأساسيات كويس ومتستعجلش إنت لسة صغير وحاول تشتغل على مشاريع بعد الأساسيات ومتركزش أوي على تعلم إطارات العمل والمكتبات وتتجاهل الأساسيات.
    لأنها هي اللي هتخليك تتعلم وتستخدم أي لغة وإطار عمل أو مكتبة بسهولة بعد كدة، وتتعلم أسرع.
    حاول بناء مشروع كبير باللغات الأساسية التي تعلمتها، مثل تنفيذ تطبيق SPA باستخدام HTML, CSS, JS فقط وستتعلم الكثير من ذلك.
  15. إجابة Mustafa Suleiman سؤال في تصحيح خطأ في الكود الخاص بتحديث بيانات الطالب في PHP كانت الإجابة المقبولة   
    الكود يحتوي على خطأ واحد في عبارة SQL المستخدمة في الجملة prepare() في السطر التالي:
    $stmt2 = $con->prepare("UPDATE student SET name = ?, Email = ?password=? WHERE id =?"); حيث أن الخطأ هو عدم وجود فاصلة بين الحقول name و Email وبين الحقول Email و password، ويجب وضع فواصل بين الحقول بطريقة صحيحة
    والصحيح هو التالي:
    $stmt2 = $con->prepare("UPDATE student SET name = ?, Email = ?, password = ? WHERE id =?");
  16. إجابة Mustafa Suleiman سؤال في مشكلة ضبط موضع الصورة واسم المستخدم في مستوى الكتابة في كود HTML و CSS كانت الإجابة المقبولة   
    سأوضح لك بمثال كيف يمكن تنسيق الصورة مع النص.
    HTML:
    <div class="user-profile"> <img src="path/to/image.jpg" alt="صورة المستخدم"> <span class="username">اسم المستخدم</span> </div> CSS:
    .user-profile { display: flex; align-items: center; gap: 10px; /* المسافة بين الصورة واسم المستخدم */ } .username { font-size: 18px; /* حجم الخط لاسم المستخدم */ } قمت بإنشاء عنصر div بالصفات user-profile والذي يحتوي على الصورة واسم المستخدم.
    واستخدمت تنسيقات CSS لتطبيق display: flex على العنصر الأب user-profile لتحقيق توزيع المحتوى في مستوى واحد.
    وحددت align-items: center لمحاذاة العناصر عموديًا، و gap لتحديد المسافة بين الصورة واسم المستخدم.
    وتستطيع ضبط قيم التنسيق وفقًا لاحتياجاتك، مثل تغيير حجم الخط أو المسافة بين العناصر، وعليك بتعديل المسار path/to/image.jpg ليتناسب مع موقع الصورة.
     
  17. إجابة Mustafa Suleiman سؤال في مشكلة جلب الصور من خلال pickImage في flutter كانت الإجابة المقبولة   
    هناك بعض الأمور التي يجب مراعاتها عند استخدام pickImage في Flutter.
    أولاً، تأكد من أنك قمت بإضافة الاعتمادية الصحيحة لحزمة image_picker في ملف pubspec.yaml الخاص بمشروعك.
    ثانياً، تأكد من أنك قمت بمعالجة صورة المعاينة التي تم اختيارها بنجاح، وتستطيع استخدام مكتبة معالجة الصور مثل flutter_image_compress لضغط الصورة وتحسين أدائها.
    ثالثاً، في الكود الحالي، يتم تخزين مسار الصورة المحلية المحددة في حقل imageUrls كقيمة واحدة في قائمة الصور filteredUsers، ولكن العرض المتوقع يتطلب أن يحتوي كل عنصر في القائمة filteredUsers على قائمة من الصور المختارة، لذا يجب تعديل بعض الأجزاء في الكود.
    في دالة _captureImage، عند إضافة الصورة المحلية الجديدة إلى filteredUsers، قم بتعديل الكود لإنشاء قائمة جديدة من الصور بدلاً من تخزين الصورة المحددة بمفردها، وبإمكانك تحقيق ذلك بتغيير السطر:
    filteredUsers.add(ImageTopicModel(imageUrls: [image.path])); إلى:
    filteredUsers.add(ImageTopicModel(imageUrls: [image.path], isLocal: true)); وذلك للإ شارة أن هذه الصورة هي صورة محلية.
    ثم في دالة build، قم بتعديل جزء إنشاء عناصر الصور داخل ListView.builder كما يلي:
    return Container( height: 150, child: ListView.builder( // ... itemBuilder: (BuildContext context, int index) { // ... return Row( children: filteredUsers[index].imageUrls!.map((imageUrl) { if (filteredUsers[index].isLocal) { // عرض الصور المحلية return GestureDetector( onTap: () { print('Local image clicked! URL: $imageUrl'); // Perform any action you want when the image is clicked }, child: Padding( padding: EdgeInsets.only(right: 10.0), child: Container( height: 100, width: 100, child: Image.file( File(imageUrl), fit: BoxFit.cover, ), ), ), ); } else { // عرض الصور من الفايربيس return GestureDetector( onTap: () { print('Firebase image clicked! URL: $imageUrl'); // Perform any action you want when the image is clicked }, child: Padding( padding: EdgeInsets.only(right: 10.0), child: Container( height: 100, width: 100, child: Image.network( imageUrl, fit: BoxFit.cover, ), ), ), ); } }).toList(), ); }, ), ); وتلك التغييرات تتيح لك عرض الصور المحلية التي تم اختيارها من خلال pickImage بشكل صحيح بجانب الصور الأخرى التي تأتي من Firebase.
  18. إجابة Mustafa Suleiman سؤال في تعلم البرمجة من الصفر: الطريقة الافضل لتعلم البرمجة كانت الإجابة المقبولة   
    أنت لا تشعر بالضياع أو التشتت عزيزي، حتى من لديه خبرة كبيرة بالبرمجة إذا انقطع لفترة طويلة سينسى بالتأكيد، فالبرمجة تحتاج إلى ممارسة، فما بالك بمن درس لفترة صغيرة وانقطع بالتأكيد سيشعر بالضياع.
    وإذا كنت قد درست بشكل صحيح وبتأني وقمت بالتطبيق مرة مع المدرب ومرة بمفردك وحاولت التغيير قليلاً في المشروع لتتعلم أشياء جديدة من المشاكل التي ستواجهك، أو تستطيع مشاهدة بعض الفيديوهات ثم توقفت وقم بالتطبيق بمفردك وحاول الإضافة أو التغيير قليلاً لتتعلم.
    فلا مشكلة كل ما تحتاجه حاليًا هو مراجعة الدورة بشكل سريع أي تشغيل الفيديو على سرعة 1.5 أو 2 حسب ما يناسبك فإذا وجدت نفسك تسترجع المعلومات وتتذكر فعليك بالتطبيق على مشروع إذًا لتثبيت ما قمت بمراجعته.
    ولكن إذا وجدت نفسك لا تتذكر كم كبير من المعلومات أو تجد صعوبة في تنفيذ المشروع من البداية ولا تعرف ماذا تفعل بالكود، هنا يجب دراسة الدورة من البداية وبتأني وعدم الإنتقال من قسم إلى قسم إلا بعد التأكد أنك فهمت وطبقت بمفردك.
    ونصيحة، حاول ألا تشعر بالقلق عند تعلم البرمجة فالجميع بدأ من نفس النقطة، فأعطي نفسك بعض الوقت وإلتزم بمسار تعليمي وخلال فترة سيتحسن مستواك بشكل كبير.
    وأيضًا إذا واجهتك مشكلة قم بتقسيمها إلى أجزاء صغيرة وحاول تنفيذها ولا تنظر للمشكلة بشكل كامل، في البداية حاول التطبيق على أجزاء صغيرة ثم قم ببناء موقع كامل وستجد في الروابط التي أرفقتها لك موقع لتحديثات وتصاميم للتطبيق على ما تعلمته.
    وقد تم النقاش حول الطريقة الصحيحة لدراسة الدورات هنا بشكل مفصل:
    ولتجنب التكرار، أنصحك بقراءة النقاشات التالية فستجد بها إجابة على الكثير من الأسئلة لديك:
     
  19. إجابة Mustafa Suleiman سؤال في استخدام العنصر الزائف ":before" في CSS لا يصلح لإضافة عنصر قبل عنصر "input" والسبب في ذلك كانت الإجابة المقبولة   
    في CSS، تعتبر ":before" عنصر زائف وتستخدم لإضافة محتوى قبل عنصر محدد، بينما ":after" تستخدم لإضافة محتوى بعد عنصر محدد، وغالبًا تستخدم هاتين الخاصيتين لإضافة عناصر مرئية إلى عناصر HTML الموجودة.
    لكن في حالة عنصر الإدخال "input"، يعتبر استخدام ":before" غير صحيح ولا يعمل على نحو صحيح.، ذلك لأنه عنصر الإدخال "input" يعتبر عنصراً فارغاً لا يحتوي على محتوى داخلي.
    مما يعني أنه لا يمكنك استخدام ":before" لإضافة محتوى قبل عنصر "input" نفسه.
    وإذا كنت ترغب في إنشاء رمز البحث داخل عنصر الإدخال "input"، تستطيع استخدام العديد من الطرق لتحقيق ذلك.
    واحدة من هذه الطرق هي وضع عنصر فرعي مستقل للعنصر "input" واستخدام الخاصية "position: absolute" لتحديد موقع الرمز بالنسبة لعنصر الإدخال، كتعيين أيقونة لرمز البحث كخلفية للعنصر الفرعي وتنسيقه بواسطة CSS ليتناسب مع المظهر المطلوب.
    وسأوضح لك الكود اللازم لإنشاء رمز البحث داخل عنصر الإدخال "input" باستخدام خاصية "position: absolute":
    HTML:
    <div class="search-container"> <input type="text" class="search-input"> <span class="search-icon"></span> </div> CSS:
    .search-container { position: relative; } .search-icon { position: absolute; top: 50%; right: 10px; transform: translateY(-50%); width: 20px; height: 20px; background-image: url('path/to/search-icon.png'); background-size: cover; } .search-input { padding-right: 30px; } حيث قمت بإنشاء عنصر <div> لتكون حاوية لعنصر الإدخال "input" وعنصر الرمز "span".
    ثم بتعيين الخاصية "position: relative" للعنصر الحاوي .search-container ليمكن تحديد موقع العناصر الفرعية بالنسبة له.
    وتحديد الخاصية "position: absolute" للعنصر الفرعي .search-icon ليمكن تحديد موقعه بالنسبة للحاوية.
    ثم استخدمت الخاصيات top, right, transform لتحديد موقع الرمز في الزاوية العلوية اليمنى ووسط العنصر، قمت أيضًا بتعيين خلفية للرمز باستخدام خاصية "background-image" وتحديد حجمها باستخدام "background-size".
    أخيرًا، تعديل حجم عنصر الإدخال "input" بإضافة الحشو على الجانب الأيمن ليسمح بوجود مساحة كافية لعرض الرمز داخل العنصر.
    ولا تنسى استبدال 'path/to/search-icon.png' بمسار الصورة الخاصة بأيقونة البحث، أو تستطيع استخدام أيقونة من Font Awesome.
    وإليك مثال إذا أردت استخدام Font Awesome:
    HTML:
    <!DOCTYPE html> <html> <head> <!-- استيراد Font Awesome --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw==" crossorigin="anonymous" referrerpolicy="no-referrer" /> </head> <body> <div class="search-container"> <input type="text" class="search-input"> <span class="search-icon"><i class="fas fa-search"></i></span> </div> </body> </html> قمت بتحديد الأيقونة المستخدمة لرمز البحث باستخدام العنصر <i> ومنحها الفئات المناسبة .fas و .fa-search، حيث .fas تعني استخدام الأيقونات الخطية (Solid) و.fa-search تعني استخدام أيقونة البحث.
    CSS:
    .search-container { position: relative; } .search-icon { position: absolute; top: 50%; right: 10px; transform: translateY(-50%); width: 20px; height: 20px; color: #999; /* لتغيير لون الأيقونة */ } .search-input { padding-right: 30px; }  
  20. إجابة Mustafa Suleiman سؤال في تخزين البيانات في قاعدة بيانات Firebase وكيفية تخزين الخانات الثابتة واللغات المتعددة كانت الإجابة المقبولة   
    عندما يتعلق الأمر بتخزين البيانات في قاعدة البيانات، هناك عدة طرق يمكن اتباعها، وسأقدم لك بعض الأفكار العامة حول كيفية تخزين البيانات التي تم توضيحها في استفسارك.
    بالنسبة للخانات الثابتة، بإمكانك اتخاذ قرار بين تخزين القيم المباشرة أو استخدام المعرفات والربط ببيانات أخرى.
    ولنستخدم مثالك "اسم الكتاب: أبيض وأسود".
    تستطيع أن تقرر تخزين النص "أبيض وأسود" مباشرة كقيمة في قاعدة البيانات وجعلها حقلًا في الجدول الخاص بالمواضيع، أو باستطاعتك إنشاء جدول منفصل للكتب وتخزين تفاصيل الكتب فيه، مع إضافة حقل يحمل معرف الكتاب في جدول المواضيع للإشارة إلى الكتاب المحدد.
    بالنسبة للغات المتعددة، فإذا كنت ترغب في دعم العربية والإنجليزية في التطبيق، تستطيع تخزين اسم الكتاب باللغتين في قاعدة البيانات.
    مثلاً، إضافة حقول مثل "اسم الكتاب بالعربية" و "اسم الكتاب بالإنجليزية"، وبمثل هذا النهج، يمكن للتطبيق استخدام النص المناسب بناءً على لغة تفضيل المستخدم أو اختياراته.
    وتذكر أن الطريقة الأفضل والصحيحة لتخزين البيانات تعتمد على احتياجات تطبيقك.
    ,إذا كنت تستخدم قاعدة بيانات Firebase، فإنها توفر لك بنية لتخزين البيانات تعتمد على مفهوم الوثائق والمجموعات في قاعدة البيانات.
    حيث أن في Firebase، يتم تخزين البيانات في وثائق (Documents)، وهي هيكل تخزين قابل للتنفيذ يتكون من مجموعة من الحقول وقيمها. يمكنك أن تنظر إلى الوثيقة كإدخال مستقل في قاعدة البيانات.
    وبناءً على ما تم شرحه، تستطيع تخزين الخانات الثابتة (مثل نوع المشاركة ونوع الكتاب ورقم الإصدار) كحقول في وثيقة الموضوع، وتخزين القيم المباشرة لهذه الخانات مباشرة في حقولها بقاعدة البيانات.
    مثلاً، إنشاء وثيقة لكل موضوع وتتضمن حقولًا مثل "عنوان الموضوع" و "نوع المشاركة" و "نوع الكتاب" و "رقم الإصدار"، وتخزين القيم المدخلة من المستخدمين في هذه الحقول.
    في Firebase، بإمكانك أيضًا تخزين قيم متعددة لنفس الحقل باستخدام مفهوم المصفوفات. وبالتالي، تستطيع تخزين أسماء الكتب بالعربية والإنجليزية في نفس الحقل، مثل ["أبيض وأسود", "Black and White"].
     
  21. إجابة Mustafa Suleiman سؤال في كيفية تحويل قيمة استرداد Firestore من String إلى Map<String, dynamic> في Flutter؟ كانت الإجابة المقبولة   
    في البداية الخطأ الذي تواجهه يحدث عند استخدام String بدلاً من Map<String, dynamic>، والسبب في الخطأ هو أنَّ قيمة "ImageTopic" في الكود الخاص بك ليست في صيغة JSON صحيحة.
    حاول التأكد من أن جميع القيم الموجودة في حقل "ImageTopic" تم تخزينها بصيغة JSON صحيحة، أيضًا التأكد من أن موديل "ImageTopicModel" يتوافق مع القيم الموجودة في "ImageTopic".
    ولتحديد الخطأ بشكل أدق، تستطيع تحويل الـ Map<String, dynamic> إلى String باستخدام JSON.encode() ومن ثم استخدام print() لطباعة الناتج، وهذا يمكن أن يساعد في تحديد ما إذا كانت البيانات الموجودة في حقل "ImageTopic" تتوافق مع JSON صحيح أم لا.
    استخدم الكود التالي لتحويل الـ Map<String, dynamic> إلى String:
    final jsonString = json.encode(myMap); ولتحويل الـ String إلى Map<String, dynamic> استخدام هذا الكود:
    final myMap = json.decode(jsonString); وأيضًا حاول تغيير هذا السطر في الكود:
    List<dynamic> myArray = querySnapshot.docs.first.get('ImageTopic') ?? []; إلى هذا الشكل:
    List<dynamic> myArray = List<Map<String, dynamic>>.from(querySnapshot.docs.first.get('ImageTopic') ?? []); هذا التغيير سيحول النوع المسترجع من البيانات إلى List<Map<String, dynamic>> والذي يمكن استخدامه في الخطوة التالية من تحويل العناصر إلى قائمة من Model objects.
    وبعد ذلك، يجب تحديث تابع fromJson() في ImageTopicModel ليتعامل مع Map<String, dynamic> بدلاً من String.
    استخدام الكود التالي كنموذج للتحديث:
    factory ImageTopicModel.fromJson(Map<String, dynamic> json) { return ImageTopicModel( imageTopic: json['imageTopic'], ); }  
  22. إجابة Mustafa Suleiman سؤال في هل اكثر من تطبيق في مشروع واحد في firebase سوف يودي الي تكرار الاشعارات في كل التطبيقات ؟ كانت الإجابة المقبولة   
    إذا قمت بإنشاء مشروع واحد في Firebase للاشتراك في الخدمة المشتركة بين تطبيق المستخدم وتطبيق مقدم الخدمة، فسوق يؤدي إلى تلقي الإشعارات في كلا التطبيقين، وهذا يحدث لأن المشروع في Firebase يعتبر كمنطقة مشتركة لجميع التطبيقات المرتبطة به.
    فإذا كنت ترغب في تجنب تلقي الإشعارات في كلا التطبيقين، تستطيع اتخاذ إحدى الخيارات التالية:
    1- إنشاء مشروع مستقل في Firebase لكل تطبيق (تطبيق المستخدم وتطبيق مقدم الخدمة)، مما سيفصل الإشعارات والتكوينات بين التطبيقين ويحد من تكرار الإشعارات.
    2-  استخدام العلامات Tags في Firebase لتمييز المستخدمين ومقدمي الخدمة وإرسال الإشعارات بناءً على العلامات المحددة، عن طريق تعيين علامات مختلفة لكل تطبيق واستخدامها في عمليات إرسال الإشعارات لتحديد المستلم المناسب.
    بمعنى في تطبيق المستخدم:
    عند تسجيل المستخدم في التطبيق، يتم تعيين علامة مثل "user_app" للمستخدم باستخدام دالة setUserProperty في Firebase. عند إرسال الإشعارات إلى مستخدمي التطبيق، قم بتحديد العلامة "user_app" كجزء من المستخدمين المستهدفين. في تطبيق مقدم الخدمة:
    عند تسجيل مقدم الخدمة في التطبيق، يتم تعيين علامة مثل "provider_app" لمقدم الخدمة باستخدام دالة setUserProperty في Firebase. عند إرسال الإشعارات إلى مقدمي الخدمة، قم بتحديد العلامة "provider_app" كجزء من المستخدمين المستهدفين. عمومًا، من الأفضل تصميم تطبيق Firebase بشكل منفصل لكل تطبيق، خاصة إذا كانت التطبيقات مستقلة تمامًا ولها متطلبات واحتياجات مختلفة.
  23. إجابة Mustafa Suleiman سؤال في نصيحة لتعلم مجال تعلم الآلة بعد تعلم تطوير المواقع، أم استمر في مجال تطوير المواقع؟ كانت الإجابة المقبولة   
    لا أنصحك بالاستمرار فيما تفعله، ضع شغفك جانبًا وتعلم المهارات المطلوبة في سوق العمل المحلي لديك أو مواقع العمل الحر، وتلك نصيحة دائمًا أرددها، حيث أن الكثير يقع في ذلك الفخ، وهو السعي وراء تعلم ما يريده أو  اللغة والإطار الأشهر، وفي النهاية يصبح غير قادر على الحصول على وظيفة بسبب عدم إمتلاك المهارات المطلوبة.
    أنت في الطريق الصحيح، حيث أن مجال الويب ستتعلم منه الكثير وسيفتح لك مجالات أخرى بسبب سهولة تعلمه نسبيًا وبه مجال الواجهة الأمامية والواجهة الخلفية وتصميم واجهات المستخدم، وسيسهل عليك تعلم المجالات الأخرى مثل تطوير تطبيقات الهاتف.
    بإختصار اختر مسار تعليمي يؤهلك إلى إمتلاك المهارات اللازمة للحصول على وظيفة أو تأهيلك لتنفيذ مشاريع حقيقية للعمل على مواقع العمل الحر، بعد ذلك تعلم ما تشاء في أوقات فراغك.
    وإليك بعض النقاشات التي قد تفيدك:
    عندي حب للبرمجة ولكنني لا أستمر في تعلمها .. ماهو الحل ؟  
  24. إجابة Mustafa Suleiman سؤال في كيف أضيف شعار لمدونة بلوجر ؟ كانت الإجابة المقبولة   
    أنت بذلك تقصد FavIcon أي أيقونة المفضلة، ولإضافتها  إلى مدونتك على بلوجر، عليك بإتباع التالي:
    قم بإعداد الشعار الخاص بك بتنسيق صورة صغيرة، عادةً بحجم 16x16 بكسل أو 32x32 بكسل. يجب أن يكون الشعار بتنسيق صورة مشفرة بتنسيق ICO أو PNG.
    انتقل إلى "تخطيط المدونة" (Layout) من لوحة التحكم. انقر على "تحرير" (Edit) بجانب عنصر "رأس المدونة" (Blog Header). ستنتقل إلى صفحة تحرير عنصر رأس المدونة. ابحث عن خيار "fav icon" أو "رمز الموقع" (Site Icon). انقر على زر "اختيار ملف" (Choose File) أو "استعراض" (Browse) لتحديد ملف FavIcon الذي قمت بإعداده في الخطوة الأولى. بعد اختيار الملف، انقر على زر "حفظ" (Save) أو "تحديث" (Update) لحفظ التغييرات.
  25. إجابة Mustafa Suleiman سؤال في ما هي شروط قبول مدونة بلوجر فى جوجل ادسنس ؟ كانت الإجابة المقبولة   
    أقصر طريق للقبول بسرعة في جوجل أدسنس هو إنشاء محتوى عالي الجودة وأن يضمن موقعك تجربة جيدة للزائرين من حيث السرعة المقبولة وقالب الموقع المناسب للهاتف.
    وسألخص لك الشروط:
    1- محتوى الموقع: يجب أن يكون المحتوى الذي تريد وضع الإعلانات فيه محتوى ذو جودة عالية ومفيد للمستخدمين. ويجب أن يكون المحتوى مكتوبًا بلغة صحيحة وواضحة ويتوافق مع سياسة AdSense. كما يجب أن لا يحتوي على محتوى مخل بالآداب العامة أو ينتهك القوانين الدولية.
    2- عدد الزيارات: يجب أن يكون لديك عدد كافٍ من الزيارات اليومية للموقع. لا يوجد رقم محدد للزيارات المطلوبة، ولكن عادة ما يعتبر موقعك مؤهلاً للتقديم عندما يكون لديك عدد كبير من الزيارات الفريدة كل شهر.
    3- تصميم الموقع: يجب أن يكون تصميم الموقع جذابًا وسهل الاستخدام، ويجب أن يكون متوافقًا مع متطلبات AdSense. يجب أن يتضمن محتوى الموقع صفحات مثل "الاتصال بنا" و "سياسة الخصوصية" و "الشروط والأحكام" وغيرها.
    4- العمر: يجب أن يكون عمر موقعك على الأقل 6 أشهر، وذلك للتأكد من أن الموقع يتمتع بالاستقرار والنمو.
    5- الدول المؤهلة: يتم قبول التسجيل في برنامج AdSense في بعض الدول فقط، لذلك تحتاج إلى التحقق من ما إذا كانت دولتك مؤهلة للتقديم.
    وأهم نصيحة أقدمها لك هي  الصبر والاستمرارية حيث يمكن أن تستغرق عملية الحصول على الموافقة من Google AdSense بعض الوقت، ولا ينبغي الاستسلام في حالة الرفض الأولي، ويمكن تحسين الموقع والمحتوى وإعادة تقديم الطلب، وكذلك الاستمرار في إنشاء محتوى عالي الجودة فالأمر يتطلب وقت لتحقيق عائد.
×
×
  • أضف...