Home > Back-end >  How do I create a function that changes data on page so I don't have to create multiple differe
How do I create a function that changes data on page so I don't have to create multiple differe

Time:01-10

I have to create multiple files for different stalls but it seems so wrong and I know there's a better way but I just don't know how. Is there a way to create something like a page builder that will let me create multiple pages with different information from a single file. The difficult part is to make the onTap function of the images send the user to the stall_page of the selected stall. I tried doing this by making a view attribute in which I create a page and manually import the page route. But that involves creating a stall_info and stall_page for every single stall.

Instead of creating stall1_page, stall2_page and so on, can I create a generic stall function that will use the same page but just change the data? I know that's LITERALLY the point of object oriented programming languages but I'm really new to them as you'll tell my previous stupid questions.

This is the homescreen dashboard

class GridDashboard extends StatelessWidget {
  Item item1 = Item(
    title: 'Tray blazers',
    subtitle: 'Open',
    event: 'by Chef Tracy',
    img: 'assets/images/tray_blazers-cr.png',
    view: stallPage,
  );

  Item item2 = Item(
    title: 'Papa Rimz',
    subtitle: 'Open',
    event: '',
    img: 'assets/images/papa_rimz.png',
    view: papaRimzPage,
  );

  Item item3 = Item(
    title: 'W SAUCE',
    subtitle: 'Open',
    event: '',
    img: 'assets/images/w_sauce-removebg.png',
    view: wSaucePage,
  );

  Item item4 = Item(
    title: 'African Kitchen',
    subtitle: 'Open',
    event: '',
    img: 'assets/images/cherry-kitchen.png',
    view: africanKitchenPage,
  );

  Item item5 = Item(
    title: 'Suya Craze',
    subtitle: 'Open',
    event: '',
    img: 'assets/images/suya_craze.png',
    view: suyaCrazePage,
  );

  Item item6 = Item(
    title: 'Zulkys cafe',
    subtitle: 'Open',
    event: '',
    img: 'assets/images/zulkys-removeb.png',
    view: zulkysCafePage,
  );

  Item item7 = Item(
    title: 'Street food',
    subtitle: 'Open',
    event: '',
    img: 'assets/images/street_food--removebg-.png',
    view: streetFoodPage,
  );
  @override
  Widget build(BuildContext context) {
    List<Item> myList = [
      item1,
      item2,
      item3,
      item4,
      item5,
      item6,
      item7,
    ];

    return Flexible(
      child: GridView.count(
        childAspectRatio: 1.0,
        padding: const EdgeInsets.only(left: 16, right: 16),
        crossAxisCount: 2,
        crossAxisSpacing: 18,
        mainAxisSpacing: 18,
        children: myList.map(
          (data) {
            return Container(
              decoration: BoxDecoration(
                color: const Color(0xff453658),
                borderRadius: BorderRadius.circular(10),
              ),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  GestureDetector(
                    onTap: () {
                      Navigator.of(context).pushNamed(data.view);
                    },
                    child: Image.asset(
                      data.img,
                      width: 90, //double.infinity
                    ),
                  ),
                  const SizedBox(height: 14),
                  Text(
                    data.title,
                    style: const TextStyle(
                      fontWeight: FontWeight.w600,
                      fontSize: 13,
                      color: Colors.white,
                    ),
                  ),
                  const SizedBox(height: 8),
                  Text(
                    data.subtitle,
                    style: const TextStyle(
                      fontWeight: FontWeight.w600,
                      fontSize: 10,
                      color: Colors.white38,
                    ),
                  ),
                  const SizedBox(height: 8),
                  // Text(
                  //   data.event,
                  //   style: const TextStyle(
                  //     fontWeight: FontWeight.w600,
                  //     fontSize: 11,
                  //     color: Colors.white70,
                  //   ),
                  // ),
                ],
              ),
            );
          },
        ).toList(),
      ),
    );
  }
}

class Item {
  String title;
  String subtitle;
  String event;
  String img;
  String view;
  Item({
    required this.title,
    required this.subtitle,
    required this.event,
    required this.img,
    required this.view,
  });
}

This is my stall_page:

class StallPage extends StatefulWidget {
  const StallPage({super.key});

  @override
  State<StallPage> createState() => _StallPageState();
}

class _StallPageState extends State<StallPage> {
  var selected = 0;
  final pageController = PageController();
  final stall = Stall.generateRestaurant1();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xff392850), //kBackground,
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          CustomAppBar(
            Icons.arrow_back_ios_outlined,
            Icons.search_outlined,
            leftCallback: () => Navigator.of(context).pop(),
          ),
          StallInfo(), //
          FoodList(
            selected,
            (int index) {
              setState(() {
                selected = index;
              });
              pageController.jumpToPage(index);
            },
            stall,
          ),
          Expanded(
            child: FoodListView(
              selected,
              (int index) {
                setState(() {
                  selected = index;
                });
              },
              pageController,
              stall,
            ),
          ),
          Container(
            padding: EdgeInsets.symmetric(horizontal: 25),
            height: 60,
            child: SmoothPageIndicator(
              controller: pageController,
              count: stall.menu.length,
              effect: CustomizableEffect(
                dotDecoration: DotDecoration(
                  width: 8,
                  height: 8,
                  color: Colors.grey.withOpacity(0.5),
                  borderRadius: BorderRadius.circular(8),
                ),
                activeDotDecoration: DotDecoration(
                  width: 10,
                  height: 10,
                  color: kBackground,
                  borderRadius: BorderRadius.circular(10),
                  dotBorder: const DotBorder(
                    color: kPrimaryColor,
                    padding: 2,
                    width: 2,
                  ),
                ),
              ),
              onDotClicked: (index) => pageController.jumpToPage(index),
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        backgroundColor: kPrimaryColor,
        elevation: 2,
        child: const Icon(
          Icons.shopping_cart_outlined,
          color: Colors.black,
          size: 30,
        ),
      ),
    );
  }
}

This is my stall_info

class StallInfo extends StatelessWidget {
  final stall = Stall.generateRestaurant1();
  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.only(top: 40),
      padding: const EdgeInsets.symmetric(horizontal: 25),
      child: Column(
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    stall.name,
                    style: const TextStyle(
                      fontSize: 25,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  const SizedBox(height: 10),
                  Row(
                    children: [
                      Container(
                          padding: const EdgeInsets.all(5),
                          decoration: BoxDecoration(
                            color: Colors.blueGrey.withOpacity(0.4),
                            borderRadius: BorderRadius.circular(5),
                          ),
                          child: Text(
                            stall.label,
                            style: const TextStyle(
                              color: Colors.white,
                            ),
                          )),
                      const SizedBox(
                        width: 10,
                      ),
                    ],
                  )
                ],
              ),
              ClipRRect(
                borderRadius: BorderRadius.circular(50),
                child: Image.asset(
                  stall.logoUrl,
                  width: 80,
                ),
              ),
            ],
          ),
          const SizedBox(
            height: 5,
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text(
                stall.desc,
                style: const TextStyle(fontSize: 16),
              ),
              Row(
                children: [
                  const Icon(
                    Icons.star_outline,
                    color: Colors.amber,
                  ),
                  Text(
                    '${stall.score}',
                    style: const TextStyle(
                      fontSize: 18,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  const SizedBox(width: 15),
                ],
              )
            ],
          )
        ],
      ),
    );
  }
}

And this is stall

class Stall {
  String name;
  String label;
  String logoUrl;
  String desc;
  num score;
  Map<String, List<Food>> menu;
  Stall(
    this.name,
    this.label,
    this.logoUrl,
    this.desc,
    this.score,
    this.menu,
  );
  static Stall generateRestaurant1() {
    return Stall(
      'Tray blazers',
      'Restaurant',
      'assets/images/tray_blazers.jpg',
      'Tray Blazers by Chef Tracy',
      4.5,
      {
        'Recommended': Food.generateRecommendedFoods1(),
        'Popular': Food.generatePopularFoods1(),
        'Smoothie': [],
        'Rice': [],
      },
    );
  }
}

CodePudding user response:

If I understand the question correctly, you want to open the StallPage but show different values on the page depending on which image (pertaining to a given 'Stall') was selected on the previous page? I.e. clicking on item2 should open the StallPage with the restaurant title "Papa Rimz" etc.?

In that case, you can pass the argument to your new route builder via the onTap() function as a constructor parameter instead of calling Stall.generateRestaurant1() with hardcoded values in a given dart file.

StallInfo

Instead of getting your stall data inside the build method, you simply accept it as a required parameter for your widget. Now you have access to the data (title, ...) anywhere inside here.

class StallInfo extends StatelessWidget {
  // Contains the stall object with its name, label, menu etc.
  final Stall stall;

  StallInfo({super.key, required this.stall});

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.only(top: 40),
      padding: const EdgeInsets.symmetric(horizontal: 25),
      child: Column(
        ...
      ),
    );
  }
}

HomeScreen

I'm a bit confused as to what the item list in your your home screen is for. Are these food items in a restaurant? Because if so, I think it would be much easier to save them inside the stall as a list of items and then use that list here:

List<Stall> _stalls = [...];

I'd like to note here that you hardcoded all the items by name and then, in your build method, added them to a list. Since you don't need their names anywhere, it would be just a little bit better to move the List<Stall> myList outside the build method and simply assign the objects directly (that is, before you add a real database):

class GridDashboard extends StatelessWidget {

    List<Stall> _stalls = [
       Stall('Tray blazers', ...),
       Stall('Papa Rimz', ...),
    ];

    @override
    Widget build(BuildContext context) {
     // do something with your stalls, onTap, pass the element directly
      ....
      children: _stalls.map(
       (data) {
         return GestureDetector(
           onTap: (){
              Navigator.of(context).push(MaterialPageRoute(
                builder: (context) => StallPage(stall: data)
               ));
           }
         );
       }),
    } 


}

If you use a builder function for your GridView (which you should if there can be a lot of stalls), in the onTap() you can instead call:

Navigator.of(context).push(MaterialPageRoute(
    builder: (context) => StallPage(stall: _stalls.elementAt(index))
));

StallPage

This page will look something like this

class StallPage extends StatefulWidget {

  final Stall stall; // Take in the stall you passed from your home screen

  const StallPage({super.key, required this.stall});

  @override
  State<StallPage> createState() => _StallPageState();
}

class _StallPageState extends State<StallPage> {
  var selected = 0;
  final pageController = PageController();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
       ...
       StallInfo(stall: widget.stall), // This is how you can access the values passed inside a StatefulWidget
       ...
    );
  }
}
 
  • Related