코드코도

[코독하구만 2] 6주차 - Flutter : Shop App 3 본문

Act/2021_여름_모각코_개인

[코독하구만 2] 6주차 - Flutter : Shop App 3

고도고도 고도고도 2021. 8. 10. 23:28
728x90

https://codekodo.tistory.com/91

 

[코독하구만 2] 5주차 - Flutter : Shop App

https://codekodo.tistory.com/88 [코독하구만 2] 4주차 - Flutter : Shop App Udemy 강의가 어느덧 50퍼를 넘겼다. 중간에 어려운 부분도 몇 개 있었지만 이제 어느정도 혼자서 구축할 수 있을 것 같다. 사실 그..

codekodo.tistory.com

지금까지는 Local에서 진행했는데 Firebase를 이용하여 Server에서 데이터를 가져오도록 코드를 수정했다.

우선 일종의 Controller 역할을 수행하는 Provider로 모든 데이터를 변경했다.

 

예를 들어 서버에 저장된 상품을 가져올 수 있도록 구현했다.

import 'package:flutter/material.dart';
import '/models/http_exception.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'product.dart';

class Products with ChangeNotifier {
  List<Product> _items = [
    // Product(
    //   id: 'p1',
    //   title: '농심 배흥동 비빔면, 32개입',
    //   description: '엄청 시원한 비빔면 존맛탱임!',
    //   price: 19020,
    //   imageUrl:
    //       'https://thumbnail8.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/255828096400583-70f3975f-3357-4101-bf29-d1dbc7bf94d8.jpg',
    // ),
    // Product(
    //   id: 'p2',
    //   title: '농심 짬뽕건면, 32개입',
    //   description: '이것이 짬뽕인가 짜장인가 모르겠네',
    //   price: 20300,
    //   imageUrl:
    //       'https://thumbnail6.coupangcdn.com/thumbnails/remote/230x230ex/image/rs_quotation_api/xlezetna/983616a9d6cb4879b8ec897b0f190912.jpg',
    // ),
    // Product(
    //   id: 'p3',
    //   title: '신라면 블랙 두부김치, 4개입',
    //   description: '히트상품 신라면 블랙의 후속작!',
    //   price: 3800,
    //   imageUrl:
    //       'https://thumbnail7.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/2020/11/16/18/8/c199d767-22d4-4d94-9df7-8757f5db3d34.jpg',
    // ),
    // Product(
    //   id: 'p4',
    //   title: '아몬드브리즈 뉴트리 식이섬유',
    //   description: '다이어트 드가자',
    //   price: 15480,
    //   imageUrl:
    //       'https://thumbnail6.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/2020/10/22/17/8/e705de8a-ec4c-4cfd-a38f-42afc47215df.jpg',
    // ),
    // Product(
    //   id: 'p5',
    //   title: '프레시지 더큰 햄가득 부대전골',
    //   description: '집에서 해먹는 간편 부대찌개!',
    //   price: 10900,
    //   imageUrl:
    //       'https://thumbnail8.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/2020/06/18/12/9/9f4cd406-34aa-4e3e-ba20-2c5ebeff0234.jpg',
    // ),
    // Product(
    //   id: 'p6',
    //   title: '미트포유 옛날 삼겹살',
    //   description: '다이어트 나가자',
    //   price: 14900,
    //   imageUrl:
    //       'https://thumbnail6.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/2020/10/21/16/3/88432c7e-584a-4748-9db2-9760f8080ac3.jpg',
    // ),
    // Product(
    //     id: 'p7',
    //     title: '판토텐산 B5',
    //     description: '여드름 전용인가?',
    //     price: 9330,
    //     imageUrl:
    //         'https://thumbnail6.coupangcdn.com/thumbnails/remote/230x230ex/image/vendor_inventory/images/2019/03/20/13/1/57ecf457-bb41-4ba8-9b65-63597c024cee.jpg'),
    // Product(
    //     id: 'p8',
    //     title: '퀴멸의 칼날 히노카미',
    //     description: '귀칼 유행이라며',
    //     price: 125000,
    //     imageUrl:
    //         'https://thumbnail6.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/2021/07/13/10/4/12387f17-6f35-488c-876f-8296bd727d7c.jpg'),
    // Product(
    //   id: 'p9',
    //   title: '홈플래닛 스마트 체지방 측정기',
    //   description: '다이어트 드가자',
    //   price: 13660,
    //   imageUrl:
    //       'https://thumbnail9.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/519187041074607-0c17571c-5e95-469e-a940-99b2883aa25b.jpg',
    // ),
    // Product(
    //     id: 'p10',
    //     title: '샤오미 LCD 드로잉 테이블',
    //     description: '그림이 너무 좋아',
    //     price: 22950,
    //     imageUrl:
    //         'https://thumbnail7.coupangcdn.com/thumbnails/remote/230x230ex/image/retail/images/2020/11/04/10/5/8b59da3d-c676-4529-986d-6969690a6733.jpg'),
    // Product(
    //     id: 'p11',
    //     title: '닌텐도 스위치 퍼펙트 슈퍼볼',
    //     description: '곧 품절예상!',
    //     price: 38000,
    //     imageUrl:
    //         'https://thumbnail7.coupangcdn.com/thumbnails/remote/300x300ex/image/retail/images/2021/07/14/10/8/311f8e83-9b5f-4fbb-9bda-50c74560bc08.jpg'),
    // Product(
    //     id: 'p12',
    //     title: 'Apple 정품 USB-C 케이블',
    //     description: '정품 케이블',
    //     price: 19500,
    //     imageUrl:
    //         'https://thumbnail10.coupangcdn.com/thumbnails/remote/300x300ex/image/retail/images/330677074620956-bc96f542-d67b-45d7-91ae-f91d39b59f5b.jpg'),
    // Product(
    //     id: 'p13',
    //     title: '애플워치 SE, GPS',
    //     description: '2021년 최신형',
    //     price: 345900,
    //     imageUrl:
    //         'https://thumbnail7.coupangcdn.com/thumbnails/remote/300x300ex/image/retail/images/7696374737960-06c26f91-d1ad-45c8-bf34-39ee275d068a.jpg'),
  ];

  List<Product> get items {
    return [..._items];
  }

  List<Product> get favoriteItems {
    return _items.where((productItem) => productItem.isFavorite).toList();
  }

  Product findById(String id) {
    return _items.firstWhere((element) => element.id == id);
  }

  final String autoToken;

  Products(this.autoToken, this._items);

// void showFavoritesOnly() {
//   _showFavoritesOnly = true;
//   notifyListeners();
// }
//
// void showAll() {
//   _showFavoritesOnly = false;
//   notifyListeners();
// }
//
  Future<void> fetchAndSetProducts() async {
    final url =
        'https://myfourthflutterapp-default-rtdb.firebaseio.com/products.json?auth=$autoToken';
    try {
      final response = await http.get(url);
      final extractData = json.decode(response.body) as Map<String, dynamic>;
      final List<Product> loadedProducts = [];
      if (extractData == null) {
        return;
      }
      extractData.forEach((key, value) {
        loadedProducts.add(Product(
          id: key,
          title: value['title'],
          description: value['description'],
          price: value['price'],
          isFavorite: value['isFavorite'],
          imageUrl: value['imageUrl'],
        ));
      });
      _items = loadedProducts;
      notifyListeners();
    } catch (error) {
      throw (error);
    }
  }

  Future<void> addProduct(Product product) async {
    final url =
        'https://myfourthflutterapp-default-rtdb.firebaseio.com/products.json?auth=$autoToken';
    try {
      final response = await http.post(
        url,
        body: json.encode({
          'title': product.title,
          'price': product.price,
          'description': product.description,
          'imageUrl': product.imageUrl,
          'isFavorite': product.isFavorite,
        }),
      );
      final newProduct = Product(
        id: json.decode(response.body)['name'],
        title: product.title,
        price: product.price,
        description: product.description,
        imageUrl: product.imageUrl,
      );
      _items.add(newProduct);
      notifyListeners();
    } catch (error) {
      throw error;
    }
  }

  Future<void> updateProduct(String id, Product newProduct) async {
    final prodIndex = _items.indexWhere((prod) => prod.id == id);
    if (prodIndex >= 0) {
      final url =
          'https://myfourthflutterapp-default-rtdb.firebaseio.com/products/$id.json?auth=$autoToken';
      await http.patch(url,
          body: json.encode({
            'title': newProduct.title,
            'description': newProduct.description,
            'price': newProduct.price,
            'imageUrl': newProduct.imageUrl,
          }));

      _items[prodIndex] = newProduct;
      notifyListeners();
    } else {
      print('...');
    }
  }

  Future<void> deleteProduct(String id) async {
    final url =
        'https://myfourthflutterapp-default-rtdb.firebaseio.com/products/$id.json?auth=$autoToken';
    final existingProductIndex = _items.indexWhere((prod) => prod.id == id);
    var existingProduct = _items[existingProductIndex];
    final response = await http.delete(url);
    _items.removeAt(existingProductIndex);
    notifyListeners();
    if (response.statusCode >= 400) {
      _items.insert(existingProductIndex, existingProduct);
      notifyListeners();
      throw HttpException('상품을 삭제할 수 없습니다.');
    }
    existingProduct = null;
  }
}

주석 부분은 기존에 사용하던 더미 데이터이다.

fetchAndSetProducts는 상품 목록을 가져오는 메소드로써 http 통신의 get 방식을 이용하여

json 형태의 데이터를 가져온다.

이후 파싱을 통해 리스트형태로 저장한다.

 

addProduct는 상품을 추가하는 메소드이다.

이번엔 post 방식을 이용하여 json의 body에 추가할 상품 데이터 정보를 넣어서 보낸다.

 

updateProduct는 기존에 있던 상품의 정보를 수정하는 메소드이다.

patch 방식을 이용해서 데이터를 수정한다.

 

deleteProduct는 상품을 제거하는 메소드로 delete 방식을 이용해서 서버에 저장된 상품을 제거한다.

 

실제 실시간 데이터베이스를 보면 정상적으로 저장되어 있는 것을 볼 수 있다.

 

소스코드는 아래 링크를 통해 접속하면 확인할 수 있다.

https://github.com/k906506/2021-Summer-Flutter-Study/tree/master/myfourthflutterapp

 

GitHub - k906506/2021-Summer-Flutter-Study: Studying hybrid app development using Dart and Flutter in summer vacation Mogakko

Studying hybrid app development using Dart and Flutter in summer vacation Mogakko 👾 - GitHub - k906506/2021-Summer-Flutter-Study: Studying hybrid app development using Dart and Flutter in summer va...

github.com

 

728x90
0 Comments
댓글쓰기 폼