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

Mustafa Suleiman

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

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

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

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

    315

أجوبة بواسطة Mustafa Suleiman

  1. بتاريخ الآن قال Osama Kha:

    هل من الصحيح وضع النوع string بالنسبة للسعر على سبيل المثال ممكن وضع xxبدل من 01وهذا غير منطقي

    لا، من الأفضل عدم استخدام النوع string لحفظ السعر. لأن السعر يجب أن يكون رقماً، وليس نصاً. إذا تم حفظ السعر كنص، فسيكون من الصعب إجراء عمليات حسابية عليه، مثل الجمع والطرح والقسمة والضرب.

    كما أن استخدام النوع string سيسبب مشاكل أخرى، مثل الصعوبة في البحث والترتيب حسب السعر. على سبيل المثال، إذا كان السعر مخزناً كنص، فلا يمكن ترتيب البيانات حسب السعر بالترتيب الصحيح.

    لذلك، الأفضل استخدام أنواع البيانات المخصصة للأرقام، مثل الأنواع المذكورة في الإجابة التي وضعتها لك، بحيث يكون من السهل القيام بالعمليات الحسابية والترتيب والبحث.

    • أعجبني 1
  2. في Laravel، يمكنك استخدام خاصية length لتحديد الحجم الذي تريد استخدامه لحقل integer. ولكن، هناك بعض الاختلافات بين أحجام الأعداد المسموح بها للأنواع المختلفة من الحقول.

    • tinyInteger  يستخدم لتعريف عمود رقمي صغير يمكنه تخزين القيم بين -128 و +127، ويحتوي على 1 بايت فقط (8 بت).
    • integer فهو يستخدم لتعريف عمود رقمي أكبر يمكنه تخزين القيم بين -2147483648 و +2147483647، ويحتوي على 4 بايتات (32 بت).

    بالتالي، إذا كان العدد الذي تريد تخزينه في العمود صغيرًا، يمكنك استخدام tinyInteger لتوفير مساحة في قاعدة البيانات، وإذا كان العدد كبيرًا، فيمكن استخدام integer. يجب ملاحظة أنه في حالة عدم تحديد عدد الأرقام في العمود، فإن Laravel سيستخدم الإعدادات الافتراضية لقاعدة البيانات التي يتم استخدامها.

    يمكن استخدام

    $table->string('price', 2) 

    لتحديد حجم الحقل، لكن هذا يعتمد على نوع البيانات التي تريد تخزينها في هذا الحقل.

    عادةً ما يتم استخدام الأنواع الرقمية مثل tinyInteger و integer لتخزين الأرقام الصحيحة، مثل الأسعار والكميات والعمر وما إلى ذلك. وعند استخدام أنواع الأرقام الصحيحة، من المفترض أن يكون لديك قيمة رقمية تريد تخزينها، وليس قيمة نصية.

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

    لذلك، يمكن استخدام string لتخزين الأرقام الصحيحة ذات الطول الصغير مثل price ، ولكن يتم استخدام الأنواع الرقمية مثل tinyInteger و integer للأرقام الصحيحة ذات الطول الكبير.

    إذا كنت تريد استخدام حقل tinyInteger، يمكنك تحديد الطول بالتالي:

    $table->tinyInteger('price', 4);

    تمثل القيمة الثانية الحد الأقصى لعدد الأرقام المسموح بها في هذا الحقل.

    إذا كنت تريد استخدام حقل integer، يمكنك تحديد الطول بالتالي:

    $table->integer('price', 11);

    تمثل القيمة الثانية الحد الأقصى لعدد الأرقام المسموح بها في هذا الحقل.

    ومع ذلك، يجب الانتباه إلى أن هذه القيم لا تحدد الحد الأقصى للأعداد التي يمكن حفظها في الحقل. بدلاً من ذلك، فإنها تحدد العدد الأقصى للأرقام التي يمكن عرضها عند عرض الحقل في أدوات الإدارة مثل phpMyAdmin.

    لحفظ أي رقم في الحقل، يجب التأكد من أن الرقم لا يتجاوز الحد الأقصى للحقل.

    علاوة على ذلك، يمكن تخصيص الخاصية unsigned لجعل الحقل موجباً فقط. يتم ذلك بإضافة unsigned() في نهاية تعريف الحقل، على النحو التالي:

    $table->integer('price', 11)->unsigned();

    وبمجرد تحديد الحجم الصحيح للحقل، يمكن استخدامه بشكل عادي في التطبيق Laravel الخاص بك.

    • أعجبني 1
  3. في المرات القادمة أرجو منك طرح السؤال أسفل الفيديو الخاص به في الدورة.

    المشكلة هي أنه لا يوجد دالة display() في الكائن Taskcontroller، وبالتالي يتعذر على برنامج Python العثور على هذه الدالة أثناء تشغيل الأمر.

    لحل هذه المشكلة، يجب إضافة دالة display() إلى الكائن Taskcontroller. يمكن القيام بذلك عن طريق إضافة الكود التالي داخل الكائن:

    class Taskcontroller:
        # ...
    
        def display(self):
            tasks = self.model.get_all_tasks()
            if tasks:
                self.view.show_all_tasks(tasks)
            else:
                self.view.show_empty_task_list_message()

    هذا الكود ينشئ دالة display() التي تقوم بجلب جميع المهام باستخدام دالة get_all_tasks() من النموذج وتعرضها باستخدام دالة show_all_tasks() من العرض. إذا لم تكن هناك مهام، سيتم عرض رسالة خاصة بذلك باستخدام دالة show_empty_task_list_message().

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

     

  4. يمكن تخزين القيم التي لا تحتاج إلى ترجمة بشكل عادي في العمود نفسه دون استخدام JSON. أما بالنسبة للأعمدة التي تحتاج إلى ترجمة، فيمكن استخدام JSON لتخزين النص المترجم لكل لغة في مفتاح يمثل اسم اللغة.

    على سبيل المثال، يمكن إنشاء عمود "product_name" و "product_description" في الجدول الخاص بالمنتجات في قاعدة البيانات. يمكن تخزين النص المترجم لكل لغة باستخدام JSON على النحو التالي:

    {
      "ar": "اسم المنتج",
      "en": "Product Name"
    }

    يمكن تحديد القيمة المخزنة باستخدام العنصر الفرعي "ar" للغة العربية والعنصر الفرعي "en" للغة الإنجليزية.

    لعرض القيم في تطبيقك، يمكنك استخدام حزمة "spatie/laravel-translatable" في Laravel لترجمة النصوص بسهولة. يمكنك استخدام الوظيفة "translatable()" لتحديد الأعمدة التي تحتوي على النص المترجم واستخدام الدالة "translate()" للوصول إلى النص المترجم للغة المحددة. على سبيل المثال:

    $product = Product::find(1);
    
    // الحصول على اسم المنتج بلغة معينة
    $productName = $product->translate('ar')->product_name;

    يمكنك أيضًا استخدام الوظيفة "locale()" للتحقق من اللغة الحالية المستخدمة في التطبيق وعرض النص المترجم باللغة المناسبة تلقائيًا.

    $product = Product::find(1);
    
    // الحصول على اسم المنتج باللغة الحالية في التطبيق
    $productName = $product->translate(app()->getLocale())->product_name;

    يمكن استخدام هذا النهج لعرض الوصف المترجم للمنتجات أيضًا.

    وسأشرح لك المزيد

    وتخزين البيانات المتعلقة باللغات في قاعدة البيانات يمكن أن يكون تحديًا في تطبيقات الويب متعددة اللغات. إذا كان لديك عمودين فقط في جدول قاعدة البيانات واحد يتعلق بالاسم والآخر بالوصف، وتريد ترجمة قيمهما للغات المختلفة، فيمكن استخدام حزمة "spatie/laravel-translatable" في Laravel.

    قبل البدء في الاستخدام، يجب تثبيت الحزمة باستخدام مدير الحزم composer، باستخدام الأمر التالي:

    composer require spatie/laravel-translatable

    يمكن تحويل العمود الذي يحتوي على الاسم والعمود الذي يحتوي على الوصف إلى حقول قابلة للترجمة باستخدام خاصية "translatable" من الحزمة، على النحو التالي:

    use Spatie\Translatable\HasTranslations;
    
    class Product extends Model
    {
        use HasTranslations;
    
        public $translatable = ['product_name', 'product_description'];
    
        // ...
    }

    تم تحويل العمودين "product_name" و "product_description" إلى حقول قابلة للترجمة باستخدام الخاصية "translatable".

    بعد ذلك، يمكن إدخال البيانات المتعلقة بالترجمة في قاعدة البيانات باستخدام تنسيق JSON المعتمد من Laravel، كما أوضحته في إجابتي السابقة. يمكن الوصول إلى قيمة الحقل المترجم باستخدام الدالة "translate()"، على النحو التالي:

    $product = Product::find(1);
    
    // الحصول على اسم المنتج بلغة معينة
    $productName = $product->translate('ar')->product_name;
    
    // الحصول على وصف المنتج بلغة معينة
    $productDescription = $product->translate('ar')->product_description;

    إذا كنت تريد عرض النص المترجم للغة المحددة في تطبيقك، يمكن استخدام الدالة "locale()" للتحقق من اللغة الحالية للمستخدم وعرض النص المترجم باللغة المناسبة، على النحو التالي:

    $product = Product::find(1);
    
    //
    • شكرًا 1
  5. يمكن حل هذه المشكلة باستخدام الخطافات فقط، بإضافة حالة إضافية لتعقب حالة الكرسي إذا كان قيمته true أو false وفي الحالة الأولى يتم تغيير لون الكرسي إلى اللون المختلف، وإذا تم النقر على الكرسي مرة أخرى والحالة الثانية تصبح صحيحة، يتم إزالة اللون المختلف.

    يمكن تنفيذ هذا الحل على النحو التالي:

    const [isSelected, setIsSelected] = useState(false);
    
    const handleClick = () => {
      setIsSelected(!isSelected);
    };
    
    const seatClasses = classNames('seat', {
      selected: isSelected
    });
    
    return (
      <div
        className={seatClasses}
        onClick={handleClick}
      >
        Seat
      </div>
    );

    في هذا المثال، نستخدم "classnames" لتحقيق تحكم أفضل في فئات الكراسي وتغييرها بين "seat" و "seat selected" بناءً على الحالة الحالية لـ "isSelected".

     

  6. هناك تعارض بين الإصدارات المستخدمة في package.json، ولذلك عندما يتم التثبيت تتوقف العملية.

    ولحل تلك المشكلة أشرت إليك باستخدام التالي:

    يتم استخدام:

    npm install --force @craco/craco

    عادةً عندما يحدث خطأ في تثبيت الحزمة باستخدام npm install العادي. وعند استخدام --force ، يتم تجاهل أي أخطاء وتمرير تركيب الحزمة بشكل صارم دون مراجعة أي اعتمادات أو مشكلات تثبيت أخرى.

    وإذا استمرت المشكلة استخدم الأمر التالي:

    npm install --legacy-peer-deps @craco/craco

    ونستخدمه عندما تكون هناك مشكلات في التثبيت المتعلقة بتعارضات اعتمادات النداء الزوجي.

    تعارضات اعتمادات النداء الزوجي (Peer Dependency conflicts) هي مشكلات تحدث عندما تحتوي حزمة معينة على تبعيات (dependencies) متضاربة مع تبعيات أخرى للحزم المراد تثبيتها.

    وهذا يحدث عندما تتطلب حزمة ما تثبيت حزمة تعتمد عليها بشكل مباشر ولكن يوجد نسخة من هذه الحزمة مثبتة بالفعل في مشروع الـ Node.js الذي يتم تثبيت الحزمة فيه. ولذلك ، فإن حل تعارضات الاعتمادات الزوجية يتطلب حلاً للتبعيات المتضاربة وذلك بتحديد أي من الحزم يجب أن تكون مثبتة بأي إصدارات.

  7. مرحبًا أخي احمد، 
    يبدوا أنك منزعح من أمرًا ما وأقدر ذلك، لكن هل يمكنك إيضاح المزيد عن سؤالك؟

    بمعنى هل تتحدث عن أحد دورات أكاديمية حسوب؟ أم أمرًا آخر؟ وإذا كان حديثك عن دورة ما في حسوب، فما هي تلك الدورة وما الذي تجد صعوبة في فهمه؟.

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

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

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

  8. يمكن توسيط عنصر div باستخدام العديد من الطرق المختلفة في CSS. ومن بين هذه الطرق:

    1- استخدام margin: auto

    يمكن توسيط العنصر div بوضع margin: auto له. يجب على العنصر div أن يكون له عرض محدد ويجب أن يكون محيطه الخارجي مفعلًا.

    مثال:

    HTML:

    <div class="container">
      <p>Hello, World!</p>
    </div>

    CSS:

    .container {
      width: 50%;
      margin: auto;
    }

    2- استخدام flexbox

    يمكن استخدام Flexbox لتوسيط عنصر div. يجب على العنصر الرئيسي (parent element) أن يكون له display: flex ويجب أن يستخدم justify-content: center و align-items: center.

    مثال:

    HTML:

    <div class="container">
      <p>Hello, World!</p>
    </div>

    CSS:

    .container {
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
    }

    3- استخدام grid

    يمكن استخدام CSS grid لتوسيط عنصر div. يجب على العنصر الرئيسي (parent element) أن يكون له display: grid ويجب على العنصر الفرعي (child element) أن يكون له grid-column و grid-row محدد.

    مثال:

    HTML:

    <div class="container">
      <p>Hello, World!</p>
    </div>

    CSS:

    .container {
      display: grid;
      place-items: center;
      height: 100vh;
    }
    
    .container p {
      grid-column: 1 / -1;
      grid-row: 1 / -1;
      text-align: center;
    }

    يجب تحديد height للعنصر الرئيسي في حال استخدام Flexbox أو Grid، حتى يتم توسيط العنصر الفرعي بشكل صحيح. يمكن استخدام قيمة نسبية مثل vh لضمان أن الارتفاع يمتد عبر جميع شاشات العرض بشكل صحيح.

     

    • أعجبني 1
  9. لتمديد الصورة باستخدام CSS يمكن استخدام الخواص التالية:

    • width: تحديد عرض الصورة.
    • height: تحديد ارتفاع الصورة.
    • max-width: تحديد أقصى عرض مسموح به للصورة.
    • max-height: تحديد أقصى ارتفاع مسموح به للصورة.
    • min-width: تحديد أدنى عرض مسموح به للصورة.
    • min-height: تحديد أدنى ارتفاع مسموح به للصورة.
    • object-fit: تحديد كيفية تمدد الصورة في العنصر الأب (contain أو cover أو fill أو none أو scale-down).

    مثال:

    img {
      width: 800px;
      height: 600px;
      max-width: 100%;
      object-fit: contain;
    }

    في هذا المثال ، تم تحديد عرض الصورة وارتفاعها وأقصى عرض مسموح به للصورة ، بالإضافة إلى تحديد كيفية تمدد الصورة في العنصر الأب باستخدام خاصية object-fit. يمكن استخدام الخصائص الأخرى المذكورة أعلاه بنفس الطريقة.

    يمكن استخدام خاصية transform في CSS لتحويل الصورة بشكل أفقي أو رأسي أو للتحكم في حجمها ودورانها وموقعها. تشمل بعض القيم الشائعة لخاصية transform:

    • rotate: لدوران الصورة.
    • scale: لتحجيم الصورة.
    • translate: لتحريك الصورة.
    • skew: لإمالة الصورة.

    مثال:

    img {
      width: 800px;
      height: 600px;
      transform: rotate(45deg) scale(1.5);
    }

    في هذا المثال ، تم تحديد عرض الصورة وارتفاعها ، وتم دورانها 45 درجة وتكبير حجمها بنسبة 1.5 باستخدام خاصية transform. يمكن استخدام القيم الأخرى للخاصية transform لتعديل الصورة بأي شكل تريده.

    • أعجبني 1
  10. يمكن التعديل على العنصر الذي تم إنشاؤه باستخدام DOM من خلال CSS.

    عند إنشاء عنصر باستخدام DOM ، يتم تحديد خصائصه الأساسية مثل نوع العنصر والفئات والمعرفات والنص الذي يتضمنه العنصر. يمكننا أيضًا تحديد خصائص أخرى مثل النص الداخلي للعنصر ، أو الخصائص المرتبطة بالحدث.

    لتعديل العنصر الذي تم إنشاؤه باستخدام DOM بواسطة CSS ، يمكننا استخدام معرف العنصر أو فئته أو أي مجموعة أخرى من المحددات التي تستخدمها CSS.

    على سبيل المثال ، إذا كان لدينا عنصر "div" تم إنشاؤه باستخدام DOM ، يمكننا تغيير لون خلفيته باستخدام الكود التالي:

    let divElement = document.createElement("div");
    divElement.style.backgroundColor = "red";

    يمكننا الآن تغيير لون الخلفية لعنصر "div" باستخدام CSS ببساطة:

    div {
      background-color: blue;
    }

    يمكننا أيضًا استخدام معرف العنصر في CSS:

    let divElement = document.createElement("div");
    divElement.id = "myDiv";

    وبعد ذلك يمكننا تعديل العنصر باستخدام معرفه في CSS:

    #myDiv {
      background-color: blue;
    }

    السؤال الثاني:

    سبب وضع الأكواد داخل JS وليس HTML ، فهناك العديد من الأسباب التي يمكن أن تجعل هذا الأمر مفيدًا. ومن بين هذه الأسباب:

    1- الحفاظ على تنظيم الشفرة: عندما يكون لديناعدد كبير من أسطر الكود ونقوم بوضعه داخل الصفحة HTML ، فقد يصعب تنظيم هذا الكود ويصعب العثور على الأخطاء فيما بعد.

    2- تحسين أداء الصفحة: يمكن أن يؤدي وضع الأكواد في ملف JavaScript إلى تحسين أداء الصفحة بشكل كبير. عندما يتم تحميل الصفحة ، يتم تنفيذ الأكواد التي تم وضعها في ملف JavaScript بشكل مستقل عن الصفحة ، وهذا يتيح للصفحة أن تحمل بسرعة أكبر. وبالإضافة إلى ذلك ، يمكن استخدام ملف JavaScript لتحميل الأكواد التي تحتاجها الصفحة فقط ، بدلاً من تحميل جميع الأكواد في كل مرة يتم فيها تحميل الصفحة.

    3- سهولة الصيانة: عندما يتم وضع الأكواد في ملف JavaScript ، يمكن للمطورين تحديث الأكواد بشكل أسهل وأكثر سرعة من خلال تعديل ملف JavaScript الواحد بدلاً من العديد من صفحات HTML المختلفة.

    4- قابلية إعادة الاستخدام: يمكن إعادة استخدام الأكواد التي تم وضعها في ملف JavaScript في الصفحات المختلفة ، مما يسهل ويسرع عملية التطوير.

    للتعرف على الفرق بين وضع الأكواد داخل HTML ووضعها داخل JavaScript ، يمكن أن نلقي نظرة على المثال التالي:

    HTML:

    <div id="myDiv"></div>
    <script>
    document.getElementById("myDiv").innerHTML = "Hello World!";
    </script>

    JavaScript:

    <div id="myDiv"></div>
    <script src="script.js"></script>

    وفي ملف script.js:

    document.getElementById("myDiv").innerHTML = "Hello World!";

    كما نلاحظ ، في المثال الثاني تم وضع الأكواد داخل ملف JavaScript وتم استدعاءها في الصفحة HTML بواسطة عنصر "script" ، مما يسهل إعادة استخدام الأكواد في الصفحات المختلفة ويسهل الصيانة ويحسن أداء الصفحة.

     

    • أعجبني 1
  11. بالإضافة إلى قام أحمد بذكره، هناك العديد من المواقع  التي توفر إلهامًا لتصميم واجهات المستخدم، ومن بينها:

    1- UI Movement: يوفر هذا الموقع تجربة استخدام ممتعة، حيث يتيح للمستخدمين تصفح تصاميم واجهات المستخدم المختلفة بطريقة سهلة وممتعة.

    2- SiteInspire: يحتوي على مجموعة من التصاميم الجذابة والإبداعية للمواقع الإلكترونية، ويتميز بتصفح سلس وبديهي.

    3- Land-book: يعرض تصاميم مميزة وجذابة للمواقع الإلكترونية، ويتميز بتنظيم التصاميم حسب الفئات مثل التجارية والتكنولوجيا والمنظمات غير الربحية، ويمكن للمستخدمين الاطلاع على معلومات حول التصميم والموقع.

    4- CollectUI: يحتوي على مجموعة من التحديات اليومية لمصممي واجهات المستخدم، حيث يتم تقديم تحدي جديد كل يوم يشمل تصميم عنصر واجهة مستخدم، ويمكن للمستخدمين الاطلاع على التصاميم المقدمة من قبل المشاركين في التحديات.

    Landingfolio: يقدم قوالب مختلفة لتصميم صفحات الهبوط (Landing Pages) التي تستخدم عادةً لتسويق منتجات أو خدمات معينة.

    5- One Page Love: يقدم تصاميم لمواقع تتألف من صفحة واحدة فقط، والتي يمكن استخدامها لإطلاق منتجات أو خدمات معينة أو لإظهار معلومات بسيطة عن الشركة أو المؤسسة.

    6- CalltoIdea: يحتوي على مجموعة من التصاميم الإبداعية للمواقع الإلكترونية التي يمكن استخدامها في تصميم مواقع الشركات والمؤسسات والمدونات والأسواق الإلكترونية وغيرها.

    7- Muzli: موقع يهدف إلى تزويد المصممين بتصاميم مستوحاة من الإبداع والابتكار، ويقدم محتوى تحفيزي ويتيح للمستخدمين استعراض التصاميم والأفكار الجديدة في مختلف مجالات التصميم.

    8- Designspiration: يعد منصة لمصممي الويب والمبتدئين والمحترفين، ويحتوي على مجموعة من التصاميم والأفكار المبتكرة والجذابة، ويسمح للمستخدمين بتصفح محتوى متنوع يشمل العديد من المجالات والمواضيع.

    9- Lapa Ninja: يوفر مجموعة واسعة من التصاميم الجاهزة والمصممة بشكل احترافي للمواقع والتطبيقات، كما يوفر مقالات مفيدة وأدوات تصميمية مجانية، ويعد موقعًا شاملاً للمصممين.

  12. الصورة التي تم رفعها هي سبب المشكلة لديك، فكما يبدوا أنك تستخدم تلك الصورة في الـ Footer ولو لاحظت فهى مائلة بالأساس، من الأفضل استخدام صور منفصلة وترتيبها داخل كود html ثم تنسيها بالـ CSS، او يمكنك استعدال الصورة من خلال برامج تعديل الصور، أو ضبط إمالة الصورة بالـ CSS من خلال الخاصية transform: rotate(20deg);

    • أعجبني 1
  13. يمكنك استخدام الطريقة الآتية لتعيين عدد الحروف في عمود integer في Laravel:

    $table->tinyInteger('price')->unsigned();
    

    سينشئ هذا الأمر عمودًا integer صغيرًا (tiny integer) غير موقع (unsigned) مع حد أقصى للقيمة 255، وهو أقل بكثير من 999. ولكن يمكنك تغيير الحد الأقصى للقيمة عن طريق تعيين عدد الأرقام الكلية التي تريدها بدلاً من 3 أرقام عند استخدام الدالة.

    يمكنك أيضًا استخدام الأمر التالي لتعيين حد أقصى للقيمة 999:

    $table->unsignedSmallInteger('price');
    

    سينشئ هذا الأمر عمودًا integer صغيرًا (small integer) غير موقع (unsigned) مع حد أقصى للقيمة 65535، ولكن يمكنك تغيير الحد الأقصى للقيمة عند الحاجة.

  14.  يمكن القيام بذلك باستخدام Amazon S3 CLI(Command Line Interface) والخطوات التالية توضح كيفية القيام بذلك:

    1- تثبيت Amazon S3 CLI: قم بتثبيت Amazon S3 CLI على جهاز الكمبيوتر الخاص بك. يمكنك القيام بذلك باستخدام مثبت pip بالطريقة التالية، ويجب تثبيت بايثون لتتمكني من استخدام مدير الحزم pip.

    pip install awscli

    2- تكوين الأمان والوصول: قم بتسجيل الدخول إلى حسابك على Amazon S3 من خلال CLI باستخدام الأمر التالي:

    aws configure

    ثم يُطلب منك إدخال مفتاح الوصول (Access Key) ومفتاح الحماية (Secret Key) والإقليم الخاص بـ Amazon S3 الذي تريد الاتصال به.

    3- تنزيل الملفات من S3 bucket: استخدم الأمر التالي لتنزيل الملفات من Amazon S3 bucket:

    aws s3 cp s3://<bucket-name>/<path-to-file> <local-path>

    حيث <bucket-name> هو اسم البوكيت و <path-to-file> هو المسار الذي يحتوي على الملفات التي تريد تنزيلها و <local-path> هو المسار المحلي على جهاز الكمبيوتر الذي تريد حفظ الملفات فيه.

    4- ضغط الملفات على الهارد ديسك:

    يمكنك ضغط الملفات باستخدام أدوات ضغط الملفات مثل WinRAR أو 7-Zip. بعد تثبيت أحد هذه الأدوات، يمكنك النقر بزر الماوس الأيمن على الملف أو المجلد الذي تريد ضغطه واختيار "Add to archive" ثم اختيار نوع الضغط المطلوب وتحديد المسار الذي تريد حفظ الملف المضغوط فيه.

  15. المشكلة في الكود هي استخدام دالة splice بشكل غير صحيح، حيث أن الدالة تأخذ مؤشر البداية وعدد العناصر التي يجب حذفها من المصفوفة، ولكن في هذه الحالة يتم استخدام e.target.classList.contains('selected') كمؤشر بداية لحذف العنصر المختار، وهذا خاطئ لأن e.target.classList.contains('selected') ليست مؤشرًا بل قيمة بوليانية.

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

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

    لحل هذه المشكلة يجب استخدام seats.filter() بدلاً من splice() لإزالة العنصر المختار وإعادة القيم الجديدة للمصفوفة seats. كما يجب إصلاح الجزء المسؤول عن إضافة الكرسي المختار بحيث يتم حذف الكرسي من المصفوفة إذا كان قد تم اختياره مسبقًا.

    والأفضل أن يكون الكود  على النحو التالي فهو مختصر:

    const [seats, setSeats] = useState([]);
    
    const handleSeats = (e) => {
      e.target.classList.toggle('selected');
      const selectedSeats = document.querySelectorAll('.selected:not(.occupied)');
      const selectedSeatsIds = Array.from(selectedSeats).map(seat => seat.id);
      setSeats(selectedSeatsIds);
    }
    

    وهنا، تم استخدام querySelectorAll للعثور على كل العناصر التي تحتوي على الكلاس .selected وليس العناصر التي يتم احتلالها، ثم تم استخدام map لإرجاع مصفوفة الهويات الخاصة بالعناصر المحددة فقط. ثم تم تعيين هذه المصفوفة إلى حالة seats.

  16. بتاريخ 12 دقائق مضت قال Ahmed Hamed7:

    انا حاطط الصوره فى     background-image: url(images/footer-bg.png);

    والصوره فى div اسمو footer-image  وفى footer-social-icon

    وفى footer-stor

    كلو موجود فى الكود

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

  17. بتاريخ 22 دقائق مضت قال Ahmed Hamed7:

    وفى برضو حاحه الصوره اصلا فيها حتت زياده فى الجنب مش عارف بتتظبط ازاى برضو

     

    أرجو منك إضافة الأكواد بالنسخ واللصق، ضع كود HTML الخاص بالـ Footer و كود CSS أيضًا.

  18. يمكن أن يكون السبب في عدم تعيين ارتفاع الـ container الخاص بالـ footer بشكل صحيح، مما يؤدي إلى تغيير توزيع المحتوى. يمكن حل المشكلة عن طريق تحديد ارتفاع الـ container بشكل صحيح، ويمكن القيام بذلك باستخدام الخاصية "height" مع CSS، مثلاً:

    .footer {
      height: 100px;
    }

    ويمكن تعديل قيمة 100px وفقًا لاحتياجات التصميم. كما يجب التأكد من استخدام الأدوات المناسبة لتحليل التصميم والتأكد من تطابق النتائج مع التصميم الأصلي.

    بعض الأسباب الأخرى التي يمكن أن تؤدي إلى عدم توافق التصميم مع الواجهة النهائية على الموقع تشمل:

    • استخدام العرض والارتفاع بنسبة مئوية بدلاً من القيم الثابتة.
    • استخدام خصائص CSS مثل transform و rotate و translate بشكل غير صحيح.
    • عدم تحديد وحدات القياس بشكل صحيح، مثل استخدام البكسل بدلاً من النسبة المئوية.
    • استخدام العناصر المطلقة (absolute) بشكل غير صحيح، مما يؤدي إلى عدم وضوح الموقع على الشاشات المختلفة.
    • استخدام القيم الافتراضية للخصائص في CSS دون تعديلها وفقًا لاحتياجات التصميم.

    ومن الصعب الجزم بسبب المشكلة، إلا بعض رؤية الكود الخاص بالـ Footer ويجب أن يكود كود HTML و CSS.

    • أعجبني 1
  19. قبل تعلم TailwindCSS عليك بمعرفة ماهى الميزات والقيود الخاص بتلك المكتبة وأيضًا مقارنتها بالبدائل مثل Bootstrap و StyledComponents، ومتى يتم استخدامها.

    Tailwind CSS

    تتميز مكتبة Tailwind CSS بالتالي:

    • توفر مجموعة كبيرة ومتنوعة من الأنماط والألوان الرئيسية المعرفة مسبقًا.
    • يمكنك تخصيص الأنماط بشكل كبير ومعرفة مسبقًا ما هي الفئات المتوفرة من خلال العرض الأساسي للمكتبة.
    • تستخدم بنية "Atomic CSS" التي تسمح لك بإنشاء الأنماط بسرعة وسهولة عن طريق الجمع بين الفئات الأساسية المتوفرة لتشكيل تراكيب جديدة.
    • تدعم ميزة "Dark Mode" التي تمكنك من تغيير الألوان تلقائيًا عندما تتغير الخلفية.
    • تدعم RTL ولكن بشكل محدود وهناك إضافات خارجية لذلك.

    إليك بعض الأكواد البسيطة باستخدام Tailwind CSS:

    <div class="container mx-auto p-4">
      <h1 class="text-4xl font-bold">مرحبًا بالعالم</h1>
      <p class="mt-4">أنا نص مثالي باستخدام Tailwind CSS</p>
      <button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded mt-4">اضغط هنا</button>
    </div>

    Bootstrap

    تتميز مكتبة Bootstrap بالتالي:

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

    مثال:

    <div class="container p-4">
      <h1 class="text-primary display-4">مرحبًا بالعالم</h1>
      <p class="mt-4">أنا نص مثالي باستخدام Bootstrap</p>
      <button class="btn btn-primary mt-4">اضغط هنا</button>
    </div>

     

    Styled Components

    تتميز مكتبة Styled Components بالتالي:

    • توفر أسلوبًا مختلفًا للتعامل مع CSS وتستخدم قوة JavaScript لإنشاء عناصر UI.
    • تسمح بتعريف المكونات باستخدام العلامات المشتقة باستخدام القوالب، مما يجعل من السهل إنشاء مكونات مخصصة وقابلة لإعادة الاستخدام.
    • تسمح للمطورين بإنشاء ستايلات قابلة للتغيير والقابلة للتوسع بشكل سهل، مما يتيح إمكانية إجراء التعديلات بسهولة في جميع الأجزاء المتعلقة بالتصميم.
    • تتميز بقدرتها على التعامل مع الحالات الحدودية وتسهيل التحويل بين المكونات. لا توفر الكثير من الميزات المدمجة مثل Bootstrap ولكن يمكن استخدام المكتبات الخارجية معها بسهولة.

    مثال:

    import styled from 'styled-components';
    
    const Container = styled.div`
      padding: 1rem;
    `;
    
    const Title = styled.h1`
      font-size: 4rem;
      font-weight: bold;
      color: #0077ff;
    `;
    
    const Paragraph = styled.p`
      margin-top: 1rem;
    `;
    
    const Button = styled.button`
      background-color: #0077ff;
      color: #fff;
      font-weight: bold;
      padding: 0.5rem 1rem;
      border-radius: 0.25rem;
      margin-top: 1rem;
      &:hover {
        background-color: #0051a8;
      }
    `;
    
    function App() {
      return (
        <Container>
          <Title>مرحبًا بالعالم</Title>
          <Paragraph>أنا نص مثالي باستخدام Styled Components</Paragraph>
          <Button>اضغط هنا</Button>
        </Container>
      );
    }

    تلاحظ أن Styled Components تستخدم JavaScript لإنشاء المكونات في حين أن Bootstrap يستخدم الكلاسات لتحديد المظهر.

    ما الأفضل بينهم ومتى يكون من الأفضل استخدام أيًا منهم؟

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

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

    Styled Components، بالمقابل، تعتمد على JavaScript وتقنية CSS-in-JS، مما يتيح للمطورين تصميم وتخصيص المكونات باستخدام JavaScript وCSS معًا، ويسمح للمستخدمين بتحسين أداء التطبيق والتحكم في الأنماط والأنماط الشخصية بشكل أفضل.

    لذا، يعتمد الاختيار بين TailwindCSS وBootstrap وStyled Components على الحاجة والغرض من المشروع والأولويات المطلوبة، فإذا كنت تحتاج إلى تسريع تطوير تطبيقات الويب الخاصة بك وتخصيصها بسهولة، فقد يكون TailwindCSS الخيار الأفضل. وإذا كنت تبحث عن مكتبة تصميم مكونات جاهزة ووظيفية، فقد يكون Bootstrap الخيار الأفضل، وإذا كنت تريد تصميم مكونات مخصصة باستخدام JavaScript و CSS معًا، فقد يكون Styled Components الخيار الأفضل.

  20. بالإضافة إلى ما تم ذكره، هناك أمر هام يجب معرفته وهو لماذا تم الاستغناء عن var وإعتماد let و const بدلاً منها:

    var:

    تم استخدام var في السابق لتعريف المتغيرات قبل إضافة let و const في ES6. يمكن استخدام var في أي مكان داخل النطاق الوظيفي الذي تم تعريفه فيه، وإذا تم استخدام var داخل الكتلة block، فإن نطاقه ينتهي عند نهاية الكتلة الحالية. يمكن إعادة تعريف المتغيرات المعرفة ب var داخل نفس النطاق، ويتم تعويض القيمة المخزنة في المتغيرات المعرفة ب var في حالة الارتفاع (hoisting)، وهو سلوك يؤدي إلى رفع تعريف المتغيرات إلى الجزء العلوي من النطاق الحالي.

    let:

    تم إضافة let في ES6 وهي تماثل var في كونها تستخدم لتعريف المتغيرات، ولكنها تتمتع بسلوك أفضل في بعض الحالات. يتم تعريف نطاق let داخل الكتلة، ولا يمكن إعادة تعريف المتغيرات المعرفة ب let داخل نفس النطاق، ولا يتم تعويض القيمة المخزنة في المتغيرات المعرفة ب let قبل تعريفها. يتم استخدام let بشكل أكبر في حالات تحتاج فيها إلى النطاق الحالي دون إعادة تعريف المتغيرات.

    const:

    تم إضافة const أيضًا في ES6 وهي تستخدم لتعريف المتغيرات ثابتة القيمة (constant)، أي أن القيمة المخزنة فيها لا يمكن تغييرها. يتم تعريف نطاق const داخل الكتلة، ويجب تعيين القيمة المخزنة في المتغيرات المعرفة ب const عند التعريف ولا يمكن تغييرها لاحقًا. يتم استخدام const عادة عندما يكون من الضروري تعريف قيم ثابتة وغير قابلة للتغيير، مثل القيم الثابتة مثل قيمة عدد ثابت مثل الرقم الثابت PI (3.14) أو قيمة ثابتة مثل عنوان URL الذي يستخدمه التطبيق.

    بشكل عام، يتم استخدام var عندما تكون هناك حاجة لتعريف متغيرات على مستوى الدالة أو الملف، ويتم استخدام let و const في حالة الحاجة إلى تعريف متغيرات على مستوى الكتلة. ويتم استخدام const في حالة الحاجة إلى تعريف متغيرات ثابتة القيمة.

    وتم استبدال var ب let و const في ES6 لتحسين توضيح ونطاق الحياة للمتغيرات. فباستخدام let و const، يتم تقييد نطاق المتغيرات بمدى الكتلة والتأكد من عدم تعريفها بشكل عشوائي في أي مكان آخر في البرنامج، بينما var يتم تعريف المتغيرات بمدى الدالة أو الملف، مما يمكن أحيانًا من تعريفها دون قصد في أي مكان في البرنامج.

    باختصار

    1- متى يتم استخدام var و let:

    يتم استخدام var في حالات النطاق العام (global scope) أو النطاق الداخلي للدالة (function scope)، بينما يتم استخدام let في حالات النطاق الداخلي للكتل (block scope)، مثل اللوحات التالية:

    // نطاق العام (global scope)
    var a = 10;
    
    function myFunction() {
      // نطاق الدالة (function scope)
      var b = 20;
      
      if (true) {
        // نطاق الكتل (block scope)
        let c = 30;
      }
    }

    2- لماذا تم استبدال var ب let و const:

    تم استبدال var بـ let و const لتفادي المشاكل التي قد تحدث بسبب نطاق الدالة العام وتبسيط العمل على المطورين. على سبيل المثال، قد يحدث خطأ في استخدام var عند تعريف متغير مرتين في نفس النطاق، حيث يتم تغيير قيمة المتغير الأول. ومن خلال استخدام let و const، يتم حل هذه المشكلة وتسهيل الكود. كما أن استخدام const يحد من خطأ البرمجة في تغيير قيمة المتغير عن طريق الخطأ.

    مثال:

    // مثال استخدام var
    var x = 5;
    var x = 10;
    console.log(x); // النتيجة 10
    
    // مثال استخدام let
    let y = 5;
    y = 10;
    console.log(y); // النتيجة 10
    
    // مثال استخدام const
    const z = 5;
    z = 10; // سيتم إلقاء خطأ في الكود
    console.log(z);

    https://io.hsoub.com/javascript/44681-المتغيرات-في-جافاسكربت-بعد-es6

    https://io.hsoub.com/javascript/45102-رفع-المتغيرات-في-جافا-سكريبت-javascript-variables-hoisting

  21. بالإضافة إلى الخطوات التي أشار إليها Kais، يجب إصلاح الأخطاء في ملفات المشروع التي لديك لتجنب ظهور أخطاء أخرى.

    وأرجو منك إكمال بقية النقاش حول السؤال هنا لتجنب حل المشكلة من قبل أكثر من شخص، وفي المرات القادمة ضع السؤال أسفل الدرس.

    وإليك ملف app.py بعد التعديل وإصلاح الأخطاء التالية:

    • استخدام Taskcontroller بدلاً من TaskController.
    • إزالة المسافات الإضافية للوسيطات - مثل "title " بدلاً من "           title".
    • استخدام "type = str" لجميع الوسيطات، بدلاً من استخدام "type = str" لبعضها فقط.
    • إضافة "action = 'store_true'" لخيار "--done" بدلاً من استخدام "type = str".
    • تغيير الخيار "-a" إلى "--all" في الأمر "list".
    • تغيير الخيار "-a" إلى "-n" في الأمر "remove".
    • تحديد الخيار "task" كـ "type = int" في الأمر "check".
    from argparse import ArgumentParser
    from Taskcontroller import TaskController
    from argparse import Namespace
    
    
    def main():
        controller = TaskController('tasks.txt')
    
        parser = ArgumentParser(description='Simple CLI Task Manager')
        subparsers = parser.add_subparsers()
    
        add_task = subparsers.add_parser('add', help='add the given task')
        add_task.add_argument('title', help='title of the task', type=str)
        add_task.add_argument('-d', '--description', help='short description of the task', type=str, default=None)
        add_task.add_argument('-s', '--start_date', help='date start of the task', type=str, default=None)
        add_task.add_argument('-e', '--end_date', help='date end of the task', type=str, default=None)
        add_task.add_argument('--done', help='check whether the task is done or not', action="store_true")
        add_task.set_defaults(func=controller.add_task)
    
        list_task = subparsers.add_parser("list", help='list of unfinished task')
        list_task.add_argument('-a', '--all', help='lists of all tasks', action="store_true")
        list_task.set_defaults(func=controller.display)
    
        check_task = subparsers.add_parser("check", help='check the given task')
        check_task.add_argument('-t', '--task', help='number of task to be done', type=int)
        check_task.set_defaults(func=controller.check_task)
    
        remove_task = subparsers.add_parser("remove", help='remove of  task')
        remove_task.add_argument('-n', '--number', help='the task will be removed(numbers)', type=int)
        remove_task.set_defaults(func=controller.remove_task)
    
        reset_task = subparsers.add_parser("reset", help='remove all  tasks')
        reset_task.set_defaults(func=controller.reset_task)
    
        args = parser.parse_args()
        args.func(args)
    
    
    if __name__ == '__main__':
        main()

    وهذا هو ملف Task.py بعد إصلاح الأخطاء التالية:

    تم تصحيح اسم الوسيط dsecription إلى description لكي يتوافق مع اسم المتغير المعرف في الدالة __init__، وتم إضافة مسافات بعد علامة فاصلة في دالة __str__ لتوضيح النص بشكل أفضل.

    class Task:
        def __init__(self, title, description=None, start_date=None, end_date=None, done=False):
            self.title = title
            self.description = description
            self.start_date = start_date
            self.end_date = end_date
            self.done = done
    
        def __str__(self):
            return f'{self.title}, {self.description}, {self.start_date}, {self.end_date}, {self.done}'

    ملف Taskcontroller.py بعد إصلاح الأخطاء التالية: 

    1. استخدام متغيرات غير معرفة في الدوال: تم استخدام متغيرات غير معرفة في دالة list_alltasks()، والتي قام المبرمج بتسميتها بـ finished_tasks بدلاً من unfinished_tasks التي تم تعريفها في الدالة.
    2. خطأ في تعريف الدوال: تم تعريف دالة check_task() ولم يتم استخدام البارامتر args الموجود في تعريفها داخل الدالة، بل تم استخدام self.args بدلاً من ذلك.
    3. خطأ في اسم الدالة: تم تعريف دالة list_tasks() ولم يتم استخدام الاسم الصحيح للدالة، حيث استخدم اسم all_tasks بدلاً من unfinished_tasks الذي تم تعريفها.
    4. استخدام دالة غير موجودة: تم استخدام دالة list_all_tasks() بدلاً من list_alltasks() في الدالة remove_task().
    5. استخدام self.args بدلاً من args: تم استخدام self.args بدلاً من args في الدالة check_task().
    6. استخدام نوع البيانات الخاطئ: تم استخدام دالة date.fromisofromat() و date.formisoformat() بدلاً من date.fromisoformat() و date.isoformat() في الدالة due_date().
    7. خطأ في استخدام الدالة print_table(): تم استخدام الدالة print_table() بدون استخدام البارامتر tasks في الدالة display().
    8. استخدام tasks بدلاً من task: تم استخدام tasks بدلاً من task في الدالة remove_task()، والتي تم تعريفها كمتغير لحذف مهمة واحدة، وبالتالي أدت إلى القيام بحذف جميع المهام في الملف.
    9. عدم إدخال البيانات بالشكل الصحيح في الملف: تم حفظ البيانات في الملف في صورة سلسلة محولة، بدلاً من استخدام أي شكل من أشكال تخزين البيانات الهيكلية (على سبيل المثال، JSON أو CSV).
    10. عدم استخدام argparse بشكل صحيح: تم استخدام argparse للتعرف على المدخلات المستخدمة، ولكن تحديد الخيارات والوسائط التي تم استخدامها من خلال الأرقام الثابتة، وليس باستخدام الخيارات الاسمية. وهذا يعني أن أي تغيير في ترتيب الخيارات يؤثر على طريقة عمل البرنامج.
    11. عدم التحقق من صحة المدخلات: لم يتم التحقق من صحة المدخلات المستخدمة، مثل التحقق من تنسيق التاريخ المدخل أو القيم المدخلة للخيارات.
    12. تعقيد المنطق المستخدم في البرنامج: تم استخدام مجموعة متنوعة من الأساليب لإنجاز المهام المطلوبة، مما يصعب فهم كيفية عمل البرنامج وتصحيح الأخطاء في حالة وجودها.
    13. عدم استخدام معايير جيدة لتسمية المتغيرات: تم استخدام أسماء متغيرات غير واضحة، مما يصعب فهم دور كل متغير في البرنامج.
    14. الاعتماد على العوامل الخارجية: تم الاعتماد على وجود ملفات خارجية لتخزين البيانات، وهذا يعني أن أي تغييرات في تنسيق الملف يمكن أن تؤثر على طريقة عمل البرنامج.
    15. عدم وجود مستوى جيد من التعليقات: لم يتم إضافة تعليقات كافية لشرح وظيفة الأكواد المستخدمة، مما يجعل صعوبة فهم وتصحيح الأخطاء في البرنامج.
    from Task import Task
    from datetime import date
    from tabulate import tabulate
    from argparse import Namespace
    
    class TaskController:
        def __init__(self, file_name):
            self.file_name = file_name
    
        def add_task(self, args):
            # 1 start date
            if not args.start_date:
                now = date.today().isoformat()
                args.start_date = now
    
            # 2 define task
            task = (args.title, args.description, args.start_date, args.end_date, args.done)
    
            # 3 open file and save info
            with open(self.file_name, 'a') as file:
                file.write(", ".join(str(x) for x in task) + "\n")
    
        def list_tasks(self):
            unfinished_tasks = []
            with open(self.file_name, 'r') as file:
                for line in file:
                    title, description, start_date, end_date, done = line.strip().split(", ")
                    end_date = None if end_date == 'None' else end_date
                    done = False if done.strip() == 'False' else True
                    if done:
                        continue
                    unfinished_tasks.append({'title': title, 'description': description, 'start_date': start_date, 'end_date': end_date})
            return unfinished_tasks
    
        def list_all_tasks(self):
            all_tasks = []
            with open(self.file_name, 'r') as file:
                for line in file:
                    title, description, start_date, end_date, done = line.strip().split(", ")
                    end_date = None if end_date == 'None' else end_date
                    done = False if done.strip() == 'False' else True
                    all_tasks.append({'title': title, 'description': description, 'start_date': start_date, 'end_date': end_date, 'done': done})
            return all_tasks
    
        def due_date(self, start, end):
            start_date = date.fromisoformat(start)
            end_date = date.fromisoformat(end)
            due_date = end_date - start_date
            return f'{due_date.days} days left.'
    
        def print_table(self, tasks):
            formatted_tasks = []
            for number, task in enumerate(tasks, 1):
                if task['start_date'] and task['end_date']:
                    due_date = self.due_date(task['start_date'], task['end_date'])
                else:
                    due_date = 'Open'
                formatted_tasks.append({'no.': number, **task, 'due_date': due_date})
            print(tabulate(formatted_tasks, headers='keys'))
    
        def display(self, args):
            all_tasks = self.list_all_tasks()
            unfinished_tasks = self.list_tasks()
    
            if not all_tasks:
                print('There are no tasks. To add a task, use: add <task>')
                return
            if args.all:
                self.print_table(all_tasks)
            else:
                if unfinished_tasks:
                    self.print_table(unfinished_tasks)
                else:
                    print('All tasks have been completed!')
    
        def check_task(self, args):
            index = args.task
            tasks = self.list_all_tasks()
            if index <= 0 or index > len(tasks):
                print(f'Task number ({index}) does not exist!')
                return
            tasks[index - 1]['done'] = True
            with open(self.file_name, 'w') as file:
                for task in tasks:
                    self.add_task(Namespace(**task))
    
       def remove_task(self, args):
            tasks = self.list_alltasks()
            if args.task:
                index = args.task
            else:
                index = len(tasks) - 1
            if index <= 0 or index > len(tasks):
                print(f'Task number ({index}) does not exist!')
                return
            tasks.pop(index - 1)
            with open(self.file_name, 'w') as file:
                for task in tasks:
                    self.add_task(Namespace(**task))
    
    def reset_task(self):
        with open(self.file_name, 'w') as file:
            file.write('')
            print('All tasks have been deleted!')
  22. بتاريخ 1 ساعة قال Aama Aama:

    نتيجة flutter doctorimage.thumb.png.4b9d3d304eb2ed1aebc8f73305f2714f.png

     

    الخطأ الذي يظهر عند تشغيل التطبيق:

    Launching lib\main.dart on sdk gphone64 x86 64 in debug mode...
    Running Gradle task 'assembleDebug'...

    FAILURE: Build failed with an exception.

    * What went wrong:
    Could not open settings generic class cache for settings file 'C:\Flutter-development\flutter-apps\first_app\android\settings.gradle' (C:\Users\aama6\.gradle\caches\7.5\scripts\3d075fs9hjp81ny0sgym4v09w).
    > BUG! exception in phase 'semantic analysis' in source unit '_BuildScript_' Unsupported class file major version 63

    * Try:
    > Run with --stacktrace option to get the stack trace.
    > Run with --info or --debug option to get more log output.
    > Run with --scan to get full insights.

    * Get more help at https://help.gradle.org

    BUILD FAILED in 5s
    Exception: Gradle task assembleDebug failed with exit code 1

    يمكن اتباع الخطوات التالية لحل المشكلة:

    1- لحل مشكلة [!] Android Studio (version 2022.1) ✗ Unable to find bundled Java version التي ظهرت في flutter doctor.

    أولاً السبب يعود إلى إصدار تحديثات لـ Flutter و Android Studio بشكل منتظم ، وتحديثات برمجية أخرى غير متوافقة يمكن أن تسبب مشاكل.

    تم توثيق هذه المشكلة في رابط المشكلة الحالية في Github: https://github.com/flutter/flutter/issues/118502. والحل البديل المؤقت هو إنشاء اختصار (symlink) لمجلد JRE الذي يأتي مع Android Studio. ويوضح الموضوع الآخر في Github (https://github.com/flutter/flutter/issues/106674) أنه تم إصدار تغيير معيب ، ولم يتم تضمينه بعد في الإصدار الثابت الحالي ، لذلك يجب استخدام حل المؤقت إلى حين تحديث Android Studio كالتالي:

    mklink /J "C:\Program Files\Android\Android Studio\jre" "C:\Program Files\Android\Android Studio\jbr"

     

    هذا الأمر يقوم بإنشاء رابط رمزي بإسم "jre" في مسار "C:\Program Files\Android\Android Studio" يشير إلى المجلد "jbr". يمكن تغيير المسار حسب مسار تثبيت برنامج Android Studio على جهاز الكمبيوتر الخاص بك.

    2- إذا استمرت المشكلة قم بالتالي: التأكد من تثبيت Java Development Kit (JDK) بشكل صحيح وإضافتها إلى المتغيرات البيئية PATH، ولتجنب مشاكل java مع flutter يجب عليك تثبيت الإصدار Java 11.

    2- تحديث Gradle إلى الإصدار الأحدث، يمكن القيام بذلك بتشغيل الأمر التالي:

    flutter upgrade --force

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

    cd android: هذا الأمر يتيح لنا التنقل إلى مجلد android في مشروع Flutter الذي نعمل عليه.

    gradlew clean: هذا الأمر يستخدم لحذف أي ملفات مؤقتة أو ملفات بناء سابقة في مشروع Android. تمامًا كما تقوم بتنظيف الفضاء الخاص بالمشروع قبل إنشاء مشروع جديد في Android Studio.

    cd ..: هذا الأمر يسمح لنا بالعودة إلى الدليل الأعلى من مجلد android الذي قمنا بالتنقل إليه في الخطوة الأولى.

    flutter run: هذا الأمر يتيح لنا تشغيل تطبيق Flutter الخاص بنا. عند تنفيذ هذا الأمر، سيتم تشغيل تطبيق Flutter الخاص بك وتحميله على الهاتف المحمول أو المحاكي الذي يتم استخدامه في تطوير التطبيقات.

    cd android
    gradlew clean
    cd ..
    flutter run

    4- ربما يوجد خطأ مع إصدار Gradle الحالي الذي يعمل عليه المشروع، يمكن تغيير الإصدار إلى إصدار أقدم أو أحدث بتحديث ملف android/build.gradle. يجب تغيير الإصدار في كل من build.gradle و gradle-wrapper.properties:

    buildscript {
        repositories {
            google()
            jcenter()
        }
    
        dependencies {
            classpath 'com.android.tools.build:gradle:4.1.0' // تغيير هذا الرقم إلى الإصدار المطلوب
        }
    }
    
    ...
    
    dependencies {
        implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
        implementation 'com.android.support:multidex:1.0.3'
    }
    
    ...
    
    distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip // تغيير هذا الرقم إلى الإصدار المطلوب

    5- بعد التعديل، قم بحفظ الملفات وإعادة بناء التطبيق بتشغيل الأمر التالي:

    flutter run
  23. إذا كانت المشكلة ليست في ذلك، ربما تكون المشكلة في اسم العرض الذي تحاولي الاستدعاء منه الـ autocomplete.

    يتعين عليك التحقق من الاسم الصحيح لعرض الـ autocomplete الخاص بالمركز والذي يجب استخدامه في تعريف URLconf لتوجيه الطلبات إليه.

    بالإضافة إلى ذلك، تأكدي من تضمين مسار URL الصحيح لـ autocomplete في ملفات تعريف URLconf الخاصة بتطبيق Django الخاص بك. يجب أن يحتوي هذا المسار على اسم العرض الصحيح وعلى وظيفة العرض التي ستعيد البيانات المطلوبة لـ autocomplete.

    على سبيل المثال، إذا كان اسم العرض الخاص بالـ autocomplete هو "center-autocomplete"، فإن المسار الخاص به في ملف URLconf يجب أن يكون مشابهًا للتالي:

    path('center-autocomplete/', views.CenterAutocomplete.as_view(), name='center-autocomplete'),

    وبعد ذلك، يمكنك استدعاء الـ autocomplete عن طريق تمرير اسم العرض الصحيح إلى الوسم الخاص بـ autocomplete في ملف HTML الخاص بك. على سبيل المثال:

    {% url 'center-autocomplete' %}

    هذا ينبغي أن يعيد اسم العرض الصحيح للـ autocomplete والذي يمكن استخدامه لإجراء طلبات autocomplete بشكل صحيح.

  24. إذا أردت إنشاء slider مماثل للصورة في سؤالك، يمكنك استخدام الكود التالي مه شرح التفاصيل الخاصة به.

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

    <div class="slider">
      <div class="slide active">
        <img src="image1.jpg" alt="Slide 1">
      </div>
      <div class="slide">
        <img src="image2.jpg" alt="Slide 2">
      </div>
      <div class="slide">
        <img src="image3.jpg" alt="Slide 3">
      </div>
      <button class="prev-btn">Prev</button>
      <button class="next-btn">Next</button>
    </div>

    يجب علينا إنشاء عناصر div داخل عنصر الشريحة. العنصر الأول هو الصورة التي سيتم عرضها في الشريحة. يجب أن يكون لدينا أيضًا عنصر آخر يحتوي على عناصر نصية مثل العنوان والوصف. يمكنك تخصيص هذه العناصر بشكل كامل وفقًا لتصميمك.

    الآن ، يجب علينا استخدام CSS لتصميم الشرائح وإظهارها بشكل جيد. يمكننا استخدام position و display و z-index لإظهار الشرائح في المكان المناسب على الصفحة.

    .slider {
      position: relative;
      width: 100%;
      height: 500px;
      overflow: hidden;
    }
    
    .slide {
      position: absolute;
      width: 100%;
      height: 100%;
      opacity: 0;
      transition: opacity 0.5s ease-in-out;
    }
    
    .slide.active {
      opacity: 1;
    }
    
    .slide img {
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
    
    .prev-btn,
    .next-btn {
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      width: 50px;
      height: 50px;
      background-color: #000;
      color: #fff;
      border: none;
      cursor: pointer;
    }
    
    .prev-btn {
      left: 20px;
    }
    
    .next-btn {
      right: 20px;
    }

    تم تعيين position: relative على العنصر الرئيسي للمتزلج لأننا سنستخدم position: absolute على العناصر الفرعية لتحديد مكانها. تم تعيين العرض والارتفاع على العنصر الرئيسي للتحكم في حجم المتزلج على الصفحة.

    تم تعيين position: absolute و top: 0 و left: 0 على الشرائح لأننا نريد عرضها في المكان الصحيح في المتزلج. تم تعيين opacity إلى 0 لكي يتم إخفاء جميع الشرائح غير النشطة.

    تم تعيين transition على opacity لإضافة تأثير تحويل عند تغيير الشريحة. تم تعيين z-index إلى -1 لجعل جميع الشرائح مخفية خلف العنصر النشط.

    عندما تصبح الشريحة نشطة ، يتم تعيين z-index إلى 1 لجعلها تظهر فوق الشرائح الأخرى. تم تعيين object-fit: cover على الصورة لجعلها تملأ المساحة المتاحة بالشريحة بشكل كامل.

    تم تعيين position: absolute و bottom: 0 و left: 0 و width: 100٪ على العنصر النصي لجعله يظهر في الجزء السفلي من الشريحة. تم تعيين خصائص النص (font-size و margin) لتخصيص النص وفقًا لتصميمك.

    أخيرًا ، سنستخدم JavaScript لتغيير الشريحة النشطة بعد فترة زمنية معينة.

    const slides = document.querySelectorAll('.slide');
    const prevBtn = document.querySelector('.prev-btn');
    const nextBtn = document.querySelector('.next-btn');
    let currentSlide = 0;
    
    // Show the first slide
    slides[currentSlide].classList.add('active');
    
    function prevSlide() {
      slides[currentSlide].classList.remove('active');
      currentSlide = (currentSlide - 1 + slides.length) % slides.length;
      slides[currentSlide].classList.add('active');
    }
    
    function nextSlide() {
      slides[currentSlide].classList.remove('active');
      currentSlide = (currentSlide + 1) % slides.length;
      slides[currentSlide].classList.add('active');
    }
    
    prevBtn.addEventListener('click', prevSlide);
    nextBtn.addEventListener('click', nextSlide);

    كود JavaScript، يقوم بتحديد الشرائح (slides) وأزرار التحكم (previous و next)، ثم يعطي الوظيفة (function) للزر السابق (previous) والتالي (next) للتحكم في الشرائح.

    في البداية، يتم تحديد الشرائح عن طريق استخدام document.querySelectorAll()، الذي يبحث عن جميع العناصر التي تحتوي على الكلاس (class) المعطى، في هذه الحالة هو .slide، ويتم حفظها في متغير slides باستخدام const.

    ثم يتم تحديد الأزرار عن طريق استخدام document.querySelector()، الذي يبحث عن أول عنصر يحتوي على الكلاس المعطى، في هذه الحالة هم .prev-btn و .next-btn، ويتم حفظهما في متغيرات prevBtn و nextBtn باستخدام const.

    ثم يتم تعيين الوظيفة (function) لكل زر بواسطة .addEventListener()، الذي يقوم بتحديد الحدث (event) الذي يتم الاستماع إليه، في هذه الحالة هو click، والوظيفة التي يتم تشغيلها عند حدوث هذا الحدث.

    لتحديد الشريحة الحالية وإظهارها، يتم تعيين متغير currentSlide إلى القيمة 0، ويتم إظهار الشريحة الأولى باستخدام .classList.add() وإضافة الكلاس active.

    لتبديل الشرائح بواسطة الأزرار، يتم إنشاء وظائف (functions) prevSlide() و nextSlide() التي تزيل الكلاس active من الشريحة الحالية وتحديد الشريحة التي ستظهر، بحيث يتم تطبيق العملية الحسابية (currentSlide - 1 + slides.length) % slides.length للحصول على الشريح

    • أعجبني 1
×
×
  • أضف...