MDC-102 Flutter: मटीरियल स्ट्रक्चर और लेआउट

1. परिचय

logo_components_color_2x_web_96dp.png

मटीरियल कॉम्पोनेंट (एमडीसी), मटीरियल डिज़ाइन लागू करने में डेवलपर की मदद करते हैं. Google में इंजीनियरों और UX डिज़ाइनर की टीम ने बनाया है. एमडीसी में दर्जनों खूबसूरत और काम करने वाले यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट हैं. यह Android, iOS, वेब और Flutter.material.io/प्रॉडक्ट के लिए उपलब्ध है

कोडलैब MDC-101 में, आपने लॉगिन पेज बनाने के लिए दो मटीरियल कॉम्पोनेंट इस्तेमाल किए: टेक्स्ट फ़ील्ड और इंक रिपल वाले बटन. आइए, अब नेविगेशन, स्ट्रक्चर, और डेटा जोड़कर इस बुनियाद के बारे में और जानें.

आपको क्या बनाना होगा

इस कोडलैब में, Shरीन नाम के ऐप्लिकेशन की होम स्क्रीन बनाई जा सकती है. यह एक ई-कॉमर्स ऐप्लिकेशन है जो कपड़े और घर का सामान बेचता है. इसमें ये चीज़ें शामिल होंगी:

  • सबसे ऊपर मौजूद ऐप्लिकेशन बार
  • प्रॉडक्ट की ग्रिड वाली लिस्ट

Android

iOS

ई-कॉमर्स ऐप्लिकेशन, जिसके ऊपर ऐप्लिकेशन बार और ग्रिड दिख रहे हैं

ई-कॉमर्स ऐप्लिकेशन, जिसके ऊपर ऐप्लिकेशन बार और ग्रिड दिख रहे हैं

इस कोडलैब में मौजूद मटीरियल Flutter कॉम्पोनेंट और सबसिस्टम

  • सबसे ऊपर मौजूद ऐप्लिकेशन बार
  • ग्रिड
  • कार्ड

Flutter डेवलपमेंट के साथ अपने अनुभव के आधार पर आप क्या रेटिंग देंगे?

शुरुआती इंटरमीडिएट कुशल

2. Flutter डेवलपमेंट एनवायरमेंट को सेट अप करें

इस लैब को पूरा करने के लिए, आपको सॉफ़्टवेयर के दो हिस्सों की ज़रूरत होगी—Flutter SDK टूल और एडिटर.

इनमें से किसी भी डिवाइस का इस्तेमाल करके, कोडलैब चलाया जा सकता है:

  • आपके कंप्यूटर से कनेक्ट किया गया Android या iOS डिवाइस होना चाहिए और वह डेवलपर मोड पर सेट होना चाहिए.
  • iOS सिम्युलेटर (Xcode टूल इंस्टॉल करना ज़रूरी है).
  • Android Emulator (Android Studio में सेटअप करना ज़रूरी है).
  • ब्राउज़र (डीबग करने के लिए Chrome ज़रूरी है).
  • Windows, Linux या macOS डेस्कटॉप ऐप्लिकेशन के तौर पर. आपको उस प्लैटफ़ॉर्म पर गेम बनाना होगा जहां आपको इसे डिप्लॉय करना है. इसलिए, अगर आपको Windows डेस्कटॉप ऐप्लिकेशन डेवलप करना है, तो आपको सही बिल्ड चेन ऐक्सेस करने के लिए Windows पर डेवलप करना होगा. ऑपरेटिंग सिस्टम से जुड़ी कुछ खास शर्तें हैं, जिनके बारे में docs.flutter.dev/desktop पर जानकारी दी गई है.

3. कोडलैब स्टार्टर ऐप्लिकेशन डाउनलोड करें

क्या MDC-101 से आगे बढ़ना है?

अगर आपने MDC-101 पूरा कर लिया है, तो आपका कोड इस कोडलैब के लिए तैयार होना चाहिए. सीधे चरण पर जाएं: सबसे ऊपर मौजूद ऐप्लिकेशन बार जोड़ें.

शुरुआत से कर रहे हैं?

स्टार्टर कोडलैब ऐप्लिकेशन डाउनलोड करें

स्टार्टर ऐप्लिकेशन, material-components-flutter-codelabs-102-starter_and_101-complete/mdc_100_series डायरेक्ट्री में मौजूद है.

...या GitHub से इसका क्लोन बनाएं

GitHub से इस कोडलैब का क्लोन बनाने के लिए, ये निर्देश चलाएं:

git clone https://github.com/material-components/material-components-flutter-codelabs.git
cd material-components-flutter-codelabs/mdc_100_series
git checkout 102-starter_and_101-complete

प्रोजेक्ट खोलें और ऐप्लिकेशन चलाएं

  1. अपनी पसंद के एडिटर में प्रोजेक्ट खोलें.
  2. "ऐप्लिकेशन चलाएं" के निर्देशों का पालन करें शुरू करें: टेस्ट ड्राइव में.

हो गया! आपको अपने डिवाइस पर एमडीसी-101 कोडलैब से श्राइन का लॉगिन पेज दिखेगा.

Android

iOS

उपयोगकर्ता नाम और पासवर्ड फ़ील्ड, रद्द करें और अगले बटन के साथ लॉगिन पेज

उपयोगकर्ता नाम और पासवर्ड फ़ील्ड, रद्द करें और अगले बटन के साथ लॉगिन पेज

अब लॉगिन स्क्रीन ठीक लग रही है, इसलिए ऐप्लिकेशन को अपने-आप कुछ प्रॉडक्ट से भर देते हैं.

4. सबसे ऊपर मौजूद ऐप्लिकेशन बार जोड़ें

फ़िलहाल, अगर आप "आगे बढ़ें" पर क्लिक करते हैं इस बटन पर क्लिक करने से, आपको होम स्क्रीन पर "आपने कर दिखाया!" दिखेगा. बहुत बढ़िया! हालांकि, अब हमारे उपयोगकर्ता को कोई कार्रवाई करने या ऐप्लिकेशन में अपनी जगह की जानकारी नहीं है. आपकी मदद के लिए, नेविगेशन का इस्तेमाल करें.

मटीरियल डिज़ाइन में नेविगेशन पैटर्न मौजूद हैं, ताकि उन्हें बेहतर तरीके से इस्तेमाल किया जा सके. सबसे ज़्यादा दिखने वाले कॉम्पोनेंट में से एक कॉम्पोनेंट, सबसे ऊपर मौजूद ऐप्लिकेशन बार होता है.

उपयोगकर्ताओं को नेविगेशन और दूसरी कार्रवाइयों का क्विक ऐक्सेस देने के लिए, सबसे ऊपर मौजूद ऐप्लिकेशन बार जोड़ें.

AppBar विजेट जोड़ना

home.dart में, स्केल में एक AppBar जोड़ें और हाइलाइट किए गए const को हटाएं:

return const Scaffold(
  // TODO: Add app bar (102)
  appBar: AppBar(
    // TODO: Add buttons and title (102)
  ),

स्कैफ़ोल्ड के appBar: फ़ील्ड में AppBar को जोड़ने से, हमें बिना किसी शुल्क के एक बेहतरीन लेआउट मिलता है. इससे AppBar को पेज में सबसे ऊपर और नीचे वाले हिस्से में ही रखा जाता है.

टेक्स्ट विजेट जोड़ें

home.dart में, AppBar में कोई टाइटल जोड़ें:

// TODO: Add app bar (102)
  appBar: AppBar(
    // TODO: Add buttons and title (102)
    title: const Text('SHRINE'),
    // TODO: Add trailing buttons (102)

अपना प्रोजेक्ट सेव करें.

Android

iOS

ऐसा ऐप्लिकेशन बार जिसके टाइटल के तौर पर श्राइन है

ऐसा ऐप्लिकेशन बार जिसके टाइटल के तौर पर श्राइन है

कई ऐप्लिकेशन बार में टाइटल के आगे एक बटन होता है. अपने ऐप्लिकेशन में मेन्यू आइकॉन जोड़ें.

पहले आइकॉन का आइकॉन जोड़ें

home.dart में ही रहते हुए, AppBar के leading: फ़ील्ड के लिए आइकॉनबटन सेट करें. (शुरुआत से पीछे के क्रम की नकल करने के लिए इसे title: फ़ील्ड से पहले रखें):

    // TODO: Add buttons and title (102)
    leading: IconButton(
      icon: const Icon(
        Icons.menu,
        semanticLabel: 'menu',
      ),
      onPressed: () {
        print('Menu button');
      },
    ),

अपना प्रोजेक्ट सेव करें.

Android

iOS

ऐप्लिकेशन बार, जिसमें श्राइन का टाइटल है और हैमबर्गर मेन्यू आइकॉन

ऐप्लिकेशन बार, जिसमें श्राइन का टाइटल है और हैमबर्गर मेन्यू आइकॉन

मेन्यू आइकॉन (जिसे "हैमबर्गर" भी कहा जाता है) ठीक वहां दिखता है जहां आपने इसकी उम्मीद की थी.

टाइटल के आखिर में बटन भी जोड़े जा सकते हैं. Flutter में इन्हें "कार्रवाइयां" कहा जाता है.

कार्रवाइयां जोड़ें

और दो आइकनबटन्स के लिए जगह है.

उन्हें टाइटल के बाद AppBar इंस्टेंस में जोड़ें:

// TODO: Add trailing buttons (102)
actions: <Widget>[
  IconButton(
    icon: const Icon(
      Icons.search,
      semanticLabel: 'search',
    ),
    onPressed: () {
      print('Search button');
    },
  ),
  IconButton(
    icon: const Icon(
      Icons.tune,
      semanticLabel: 'filter',
    ),
    onPressed: () {
      print('Filter button');
    },
  ),
],

अपना प्रोजेक्ट सेव करें. आपकी होम स्क्रीन इस तरह दिखेगी:

Android

iOS

एक ऐप बार, जिसमें श्राइन का टाइटल है और हैमबर्गर मेन्यू का आइकॉन है. इसके बाद, खोज करने के साथ-साथ, पसंद के मुताबिक आइकॉन बनाने की सुविधा भी है

एक ऐप बार, जिसमें श्राइन का टाइटल है और हैमबर्गर मेन्यू का आइकॉन है. इसके बाद, खोज करने के साथ-साथ, पसंद के मुताबिक आइकॉन बनाने की सुविधा भी है

अब ऐप्लिकेशन में लीडिंग बटन, टाइटल, और दाईं ओर दो कार्रवाइयाँ मौजूद हैं. ऐप्लिकेशन बार एक ऐसे हल्के शैडो का इस्तेमाल करके चढ़ाई भी दिखाता है जिससे पता चलता है कि यह लेयर, कॉन्टेंट से अलग किसी लेयर पर है.

5. ग्रिड में कार्ड जोड़ना

अब हमारे ऐप्लिकेशन का स्ट्रक्चर तैयार हो गया है, तो चलिए कार्ड में कॉन्टेंट जोड़कर उसे व्यवस्थित करते हैं.

GridView जोड़ना

आइए, सबसे ऊपर ऐप्लिकेशन बार के नीचे एक कार्ड जोड़कर शुरुआत करते हैं. सिर्फ़ कार्ड विजेट के पास खुद को दिखाने के लिए इतनी जानकारी नहीं है कि हम उसे कहां देख सकते हैं. इसलिए, हम इसे GridView विजेट में इनकैप्सुलेट करना चाहेंगे.

स्कैफ़ोल्ड की बॉडी में सेंटर को ग्रिड व्यू से बदलें:

// TODO: Add a grid view (102)
body: GridView.count(
  crossAxisCount: 2,
  padding: const EdgeInsets.all(16.0),
  childAspectRatio: 8.0 / 9.0,
  // TODO: Build a grid of cards (102)
  children: <Widget>[Card()],
),

चलिए, इस कोड को अनपैक करते हैं. GridView count() कंस्ट्रक्टर को शुरू करता है, क्योंकि इसमें जितने आइटम दिखते हैं उन्हें गिना जा सकता है, न कि अनलिमिटेड. हालांकि, इसका लेआउट तय करने के लिए और जानकारी की ज़रूरत है.

crossAxisCount: बताता है कि कितने आइटम हैं. हमें दो कॉलम चाहिए.

padding: फ़ील्ड, GridView के चारों तरफ़ स्पेस देता है. बेशक, आपको पेज के पीछे या सबसे नीचे की ओर पैडिंग नहीं दिख सकती, क्योंकि फ़िलहाल उनके बगल में कोई GridView चिल्ड्रेन मौजूद नहीं है.

childAspectRatio: फ़ील्ड आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) के हिसाब से, आइटम के साइज़ की पहचान करता है.

डिफ़ॉल्ट रूप से, GridView ऐसी टाइल बनाता है जो एक जैसे साइज़ की होती हैं.

हमारे पास एक कार्ड है, लेकिन वह खाली है. अपने कार्ड में चाइल्ड विजेट जोड़ें.

कॉन्टेंट का लेआउट बनाना

कार्ड में किसी इमेज, शीर्षक, और दूसरे टेक्स्ट के लिए क्षेत्र होने चाहिए.

GridView के चिल्ड्रेन अपडेट करें:

// TODO: Build a grid of cards (102)
children: <Widget>[
  Card(
    clipBehavior: Clip.antiAlias,
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        AspectRatio(
          aspectRatio: 18.0 / 11.0,
          child: Image.asset('assets/diamond.png'),
        ),
        Padding(
          padding: const EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Text('Title'),
              const SizedBox(height: 8.0),
              Text('Secondary Text'),
            ],
          ),
        ),
      ],
    ),
  )
],

यह कोड, चाइल्ड विजेट को वर्टिकल तौर पर लेआउट करने के लिए इस्तेमाल किया जाने वाला कॉलम विजेट जोड़ता है.

crossAxisAlignment: field से CrossAxisAlignment.start का पता चलता है, जिसका मतलब है कि "टेक्स्ट को सबसे आगे के किनारे पर अलाइन करें."

AspectRatio विजेट की मदद से, यह तय किया जाता है कि इमेज को कौनसा आकार मिलेगा. इससे कोई फ़र्क़ नहीं पड़ता कि किस तरह की इमेज दी गई है.

पैडिंग टेक्स्ट को साइड से थोड़ा अंदर लाती है.

दो Text विजेट के बीच में 8 पॉइंट खाली होते हैं. इन्हें वर्टिकल तौर पर रखा जाता है (SizedBox). हम उन्हें पैडिंग के अंदर रखने के लिए एक और कॉलम बनाते हैं.

अपना प्रोजेक्ट सेव करें.

Android

iOS

इमेज, टाइटल, और दूसरे टेक्स्ट वाला एक आइटम

इमेज, टाइटल, और दूसरे टेक्स्ट वाला एक आइटम

इस झलक में, आपको कार्ड के किनारे से इनसेट दिखेगा. इसके कोने गोल हैं और एक परछाई (जो कार्ड की ऊंचाई दिखाती है) है. पूरे आकार को "कंटेनर" कहा जाता है मटीरियल में. (कंटेनर नाम के असल विजेट क्लास से अलग है.)

आम तौर पर, कार्ड किसी संग्रह में दूसरे कार्ड के साथ दिखाए जाते हैं. चलिए, इन्हें ग्रिड में कलेक्शन के तौर पर दिखाते हैं.

6. कार्ड का कलेक्शन बनाना

जब किसी स्क्रीन में एक से ज़्यादा कार्ड मौजूद होते हैं, तो उन्हें एक या उससे ज़्यादा कलेक्शन में एक साथ रखा जाता है. किसी कलेक्शन में दिखने वाले कार्ड एक जैसे होते हैं. इसका मतलब है कि कार्ड, एक-दूसरे के बराबर ऊंचाई पर होते हैं. ऐसा तब होता है, जब कार्ड को ऊपर या नीचे खींचकर छोड़ा जाता है. हालांकि, हम यहां ऐसा नहीं करेंगे.

कार्ड को कलेक्शन में जोड़ना

फ़िलहाल, हमारा कार्ड GridView के children: फ़ील्ड के हिसाब से बनाया गया है. इसमें ज़्यादा संख्या में नेस्ट किए गए कोड हैं, जिन्हें पढ़ना मुश्किल हो सकता है. चलिए, इसे ऐसे फ़ंक्शन के तौर पर एक्सट्रैक्ट करते हैं जो जितने चाहें उतने खाली कार्ड जनरेट करके, कार्ड की सूची दिखाता है.

build() फ़ंक्शन के ऊपर एक नया निजी फ़ंक्शन बनाएं (ध्यान रखें कि अंडरस्कोर से शुरू होने वाले फ़ंक्शन निजी एपीआई होते हैं):

// TODO: Make a collection of cards (102)
List<Card> _buildGridCards(int count) {
  List<Card> cards = List.generate(
    count,
    (int index) {
      return Card(
        clipBehavior: Clip.antiAlias,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            AspectRatio(
              aspectRatio: 18.0 / 11.0,
              child: Image.asset('assets/diamond.png'),
            ),
            Padding(
              padding: const EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: const <Widget>[
                  Text('Title'),
                  SizedBox(height: 8.0),
                  Text('Secondary Text'),
                ],
              ),
            ),
          ],
        ),
      );
    },
  );
  return cards;
}

जनरेट किए गए कार्ड, GridView के children फ़ील्ड में असाइन करें. ग्रिडव्यू में शामिल सभी चीज़ों को इस नए कोड से बदलना न भूलें:

// TODO: Add a grid view (102)
body: GridView.count(
  crossAxisCount: 2,
  padding: const EdgeInsets.all(16.0),
  childAspectRatio: 8.0 / 9.0,
  children: _buildGridCards(10) // Replace
),

अपना प्रोजेक्ट सेव करें.

Android

iOS

आइटम का ग्रिड, जिसमें इमेज, टाइटल, और सेकंडरी टेक्स्ट शामिल हैं

आइटम का ग्रिड, जिसमें इमेज, टाइटल, और सेकंडरी टेक्स्ट शामिल हैं

कार्ड वहां मौजूद हैं, लेकिन वे अभी तक कुछ नहीं दिखा रहे हैं. प्रॉडक्ट डेटा जोड़ें.

प्रॉडक्ट डेटा जोड़ना

इस ऐप्लिकेशन में इमेज, नाम, और कीमतों के साथ कुछ प्रॉडक्ट मौजूद हैं. चलिए, इसे कार्ड में पहले से मौजूद विजेट में जोड़ देते हैं

इसके बाद, home.dart में, एक नया पैकेज और कुछ ऐसी फ़ाइलें इंपोर्ट करें जो हमने डेटा मॉडल के लिए उपलब्ध कराई हैं:

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

import 'model/product.dart';
import 'model/products_repository.dart';

आखिर में, प्रॉडक्ट की जानकारी फ़ेच करने के लिए, _buildGridCards() को बदलें और उस डेटा को कार्ड में इस्तेमाल करें:

// TODO: Make a collection of cards (102)

// Replace this entire method
List<Card> _buildGridCards(BuildContext context) {
  List<Product> products = ProductsRepository.loadProducts(Category.all);

  if (products.isEmpty) {
    return const <Card>[];
  }

  final ThemeData theme = Theme.of(context);
  final NumberFormat formatter = NumberFormat.simpleCurrency(
      locale: Localizations.localeOf(context).toString());

  return products.map((product) {
    return Card(
      clipBehavior: Clip.antiAlias,
      // TODO: Adjust card heights (103)
      child: Column(
        // TODO: Center items on the card (103)
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          AspectRatio(
            aspectRatio: 18 / 11,
            child: Image.asset(
              product.assetName,
              package: product.assetPackage,
             // TODO: Adjust the box size (102)
            ),
          ),
          Expanded(
            child: Padding(
              padding: const EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
              child: Column(
               // TODO: Align labels to the bottom and center (103)
               crossAxisAlignment: CrossAxisAlignment.start,
                // TODO: Change innermost Column (103)
                children: <Widget>[
                 // TODO: Handle overflowing labels (103)
                 Text(
                    product.name,
                    style: theme.textTheme.titleLarge,
                    maxLines: 1,
                  ),
                  const SizedBox(height: 8.0),
                  Text(
                    formatter.format(product.price),
                    style: theme.textTheme.titleSmall,
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }).toList();
}

ध्यान दें: फ़िलहाल, कंपाइल और रन नहीं किया जाएगा. हमने एक और बदलाव किया है.

साथ ही, कंपाइल करने से पहले BuildContext को _buildGridCards() में पास करने के लिए build() फ़ंक्शन को बदलें:

// TODO: Add a grid view (102)
body: GridView.count(
  crossAxisCount: 2,
  padding: const EdgeInsets.all(16.0),
  childAspectRatio: 8.0 / 9.0,
  children: _buildGridCards(context) // Changed code
),

ऐप्लिकेशन को रीस्टार्ट करें.

Android

iOS

इमेज, प्रॉडक्ट के टाइटल, और कीमत के साथ आइटम का ग्रिड

इमेज, प्रॉडक्ट के टाइटल, और कीमत के साथ आइटम का ग्रिड

यह देखा जा सकता है कि हम आपके कार्ड के बीच में वर्टिकल स्पेस नहीं जोड़ते. ऐसा इसलिए, क्योंकि डिफ़ॉल्ट रूप से उनके ऊपर और नीचे 4 पॉइंट मार्जिन होते हैं.

अपना प्रोजेक्ट सेव करें.

प्रॉडक्ट डेटा दिखता है, लेकिन इमेज के आस-पास ज़्यादा जगह होती है. इमेज डिफ़ॉल्ट रूप से .scaleDown के BoxFit के साथ बनाई जाती हैं (इस मामले में). चलिए उसे .fitWidth में बदलते हैं, ताकि वे थोड़ा ज़ूम इन करें और खाली सफ़ेद जगह हटा दें.

इमेज में BoxFit.fitWidth वैल्यू के साथ fit: फ़ील्ड जोड़ें:

  // TODO: Adjust the box size (102)
  fit: BoxFit.fitWidth,

Android

iOS

आइटम का ग्रिड दिख रहा है. इसमें काटी गई इमेज, प्रॉडक्ट का टाइटल, और कीमत दिख रही है

हमारे प्रॉडक्ट अब ऐप्लिकेशन में सही तरीके से दिख रहे हैं!

7. बधाई हो!

हमारे ऐप्लिकेशन में एक बुनियादी फ़्लो है, जो लोगों को लॉगिन स्क्रीन से होम स्क्रीन पर ले जाता है, जहां प्रॉडक्ट देखे जा सकते हैं. कोड की कुछ लाइनों में ही, हमने सबसे ऊपर मौजूद ऐप्लिकेशन बार (टाइटल और तीन बटन के साथ) और कार्ड (अपने ऐप्लिकेशन का कॉन्टेंट पेश करने के लिए) जोड़ा है. हमारी होम स्क्रीन अब सामान्य और सुविधाजनक तरीके से काम कर रही है. साथ ही, इसका बुनियादी स्ट्रक्चर और कार्रवाई करने लायक कॉन्टेंट है.

अगले चरण

सबसे ऊपर मौजूद ऐप्लिकेशन बार, कार्ड, टेक्स्ट फ़ील्ड, और बटन की मदद से, अब हमने Material Flutter लाइब्रेरी के चार मुख्य कॉम्पोनेंट का इस्तेमाल किया है! मटीरियल कॉम्पोनेंट विजेट की सूची पर जाकर ज़्यादा जानकारी पाई जा सकती है.

हालांकि, यह पूरी तरह से काम कर रहा है, लेकिन हमारा ऐप्लिकेशन फ़िलहाल किसी खास ब्रैंड या नज़रिए के बारे में नहीं बताता. MDC-103: मटीरियल डिज़ाइन थीमिंग में रंग, आकार, ऊंचाई, और टाइप में, हम चमकीले और मॉर्डन ब्रैंड दिखाने के लिए इन कॉम्पोनेंट की स्टाइल को पसंद के मुताबिक बनाएंगे.

मैंने सही समय और मेहनत में इस कोडलैब को पूरा कर लिया

पूरी तरह सहमत सहमत कोई फ़र्क़ नहीं पड़ता असहमत पूरी तरह असहमत

मुझे आने वाले समय में मटीरियल कॉम्पोनेंट इस्तेमाल करते रहना है

पूरी तरह सहमत सहमत कोई फ़र्क़ नहीं पड़ता असहमत पूरी तरह असहमत