[Flutter] 스나이퍼팩토리 Flutter 중급과정 (7)

GONG·2023년 4월 30일
0
post-thumbnail

Json Serialization 연습

Dictionary

  • https://api.dictionaryapi.dev/v2/entries/en/{검색어}
  • {검색어}의 발음기호와 뜻을 알려주는 API로, 많은 데이터를 포함하고 있다.
    [
      {
        "word": "apple",
        "phonetic": "/ˈæp.əl/",
        "phonetics": [
          {
            "text": "/ˈæp.əl/",
            "audio": "https://api.dictionaryapi.dev/media/pronunciations/en/apple-uk.mp3",
            "sourceUrl": "https://commons.wikimedia.org/w/index.php?curid=9014262",
            "license": {
              "name": "BY 3.0 US",
              "url": "https://creativecommons.org/licenses/by/3.0/us"
            }
          },
          {
            "text": "/ˈæp.əl/",
            "audio": "https://api.dictionaryapi.dev/media/pronunciations/en/apple-us.mp3",
            "sourceUrl": "https://commons.wikimedia.org/w/index.php?curid=718877",
            "license": {
              "name": "BY-SA 3.0",
              "url": "https://creativecommons.org/licenses/by-sa/3.0"
            }
          }             
        ],
        "meanings": [
          {
            "partOfSpeech": "noun",
            "definitions": [
              {
                "definition": "A common, round fruit produced by the tree Malus domestica, cultivated in temperate climates.",
                "synonyms": [ ],
                "antonyms": [ ]
              },
              {
                "definition": "Any of various tree-borne fruits or vegetables especially considered as resembling an apple; also (with qualifying words) used to form the names of other specific fruits such as custard apple, rose apple, thorn apple etc.",
                "synonyms": [ ],
                "antonyms": [ ]
              },
              {
                "definition": "The fruit of the Tree of Knowledge, eaten by Adam and Eve according to post-Biblical Christian tradition; the forbidden fruit.",
                "synonyms": [ ],
                "antonyms": [ ]
              },
              {
                "definition": "A tree of the genus Malus, especially one cultivated for its edible fruit; the apple tree.",
                "synonyms": [ ],
                "antonyms": [ ]
              },
              {
                "definition": "The wood of the apple tree.",
                "synonyms": [ ],
                "antonyms": [ ]
              },
              {
                "definition": "(in the plural) Short for apples and pears, slang for stairs.",
                "synonyms": [ ],
                "antonyms": [ ]
              },
              {
                "definition": "The ball in baseball.",
                "synonyms": [ ],
                "antonyms": [ ]
              },
              {
                "definition": "When smiling, the round, fleshy part of the cheeks between the eyes and the corners of the mouth.",
                "synonyms": [ ],
                "antonyms": [ ]
              },
              {
                "definition": "A Native American or red-skinned person who acts and/or thinks like a white (Caucasian) person.",
                "synonyms": [ ],
                "antonyms": [ ]
              },
              {
                "definition": "(ice hockey slang) An assist.",
                "synonyms": [ ],
                "antonyms": [ ]
              }
            ],
            "synonyms": [ ],
            "antonyms": [ ]
          },
          {
            "partOfSpeech": "verb",
            "definitions": [
              {
                "definition": "To become apple-like.",
                "synonyms": [ ],
                "antonyms": [ ]
              },
              {
                "definition": "To form buds.",
                "synonyms": [ ],
                "antonyms": [ ]
              }
            ],
            "synonyms": [ ],
            "antonyms": [ ]
          }
        ],
        "license": {
          "name": "CC BY-SA 3.0",
          "url": "https://creativecommons.org/licenses/by-sa/3.0"
        },
        "sourceUrls": [
          "https://en.wiktionary.org/wiki/apple"
        ]
      }
    ]
  • json 데이터 받아와서 Dict 인스턴스 만들어보기
    import 'package:dio/dio.dart';
    
    class Dict {
      String word;
      String? phonetic;
      List<Phonetic> phonetics;
      List<Meaning> meanings;
      License license;
      List<String> sourceUrls;
    
      Dict({
        required this.word,
        required this.phonetic,
        required this.phonetics,
        required this.meanings,
        required this.license,
        required this.sourceUrls,
      });
    
      factory Dict.fromMap(Map<String, dynamic> map) {
        return Dict(
          word: map['word'],
          phonetic: map['phonetic'],
          phonetics: List<Phonetic>.from(map['phonetics'].map((e) => Phonetic.fromMap(e))),
          meanings: List<Meaning>.from(map['meanings'].map((e) => Meaning.fromMap(e))),
          license: License.fromMap(map['license']),
          sourceUrls: List<String>.from(map['sourceUrls']),
        );
      }
    }
    
    class License {
      String name;
      String url;
    
      License({
        required this.name,
        required this.url,
      });
    
      factory License.fromMap(Map<String, dynamic> map) {
        return License(
          name: map['name'],
          url: map['url'],
        );
      }
    }
    
    class Phonetic {
      String? text;
      String audio;
      String? sourceUrl;
      License? license;
    
      Phonetic({
        required this.text,
        required this.audio,
        required this.sourceUrl,
        required this.license,
      });
    
      factory Phonetic.fromMap(Map<String, dynamic> map) {
        return Phonetic(
          text: map['text'],
          audio: map['audio'],
          sourceUrl: map['sourceUrl'],
          license: map['license'] != null ? License.fromMap(map['license']) : null,
        );
      }
    }
    
    class Meaning {
      String partOfSpeech;
      List<Definition> definitions;
    
      Meaning({
        required this.partOfSpeech,
        required this.definitions,
      });
    
      factory Meaning.fromMap(Map<String, dynamic> map) {
        return Meaning(
          partOfSpeech: map['partOfSpeech'],
          definitions: List<Definition>.from(map['definitions'].map((e) => Definition.fromMap(e))),
        );
      }
    }
    
    class Definition {
      String definition;
      List<String> synonyms;
      List<String> antonyms;
      String? example;
    
      Definition({
        required this.definition,
        required this.synonyms,
        required this.antonyms,
        required this.example,
      });
    
      factory Definition.fromMap(Map<String, dynamic> map) {
        return Definition(
          definition: map['definition'],
          synonyms: List<String>.from(map['synonyms']),
          antonyms: List<String>.from(map['antonyms']),
          example: map['example'],
        );
      }
    }
    
    void main() async {
      Dio dio = Dio();
      String search = 'run';
      String url = 'https://api.dictionaryapi.dev/api/v2/entries/en/$search';
      var res = await dio.get(url);
      var dict = Dict.fromMap(res.data.first);
      print(dict);
    }

과제

딕셔너리 앱 만들기

다음의 공개된 API를 분석하고, 클래스를 활용하여 적용 후
딕셔너리 앱을 다음과 같이 만드시오.

  • 반드시 Dict 클래스를 만들고 Serialization을 진행할 수 있도록 하시오.
    • 필요한 요소만을 클래스에 적용하는 것은 허용되지만,
      최대한 많은 데이터를 가져올 수 있도록 한다.
  • 이 때, 만약 검색어가 존재하지 않는 단어로 서버에서 정상적인 응답을 못받았을 경우는 아무 것도 출력되지 않도록 한다.
  • 검색어를 입력하고 엔터를 누르면 (TextField의 onSubmitted) 주어진 API를 통해 검색하도록 한다.
    • 이 때, 결과는 아래에 커스텀 위젯을 최대한 활용하여 보여줄 수 있도록한다.
    • 커스텀 위젯은 최대한 분할되어 있을수록 좋다.
      • 예) MeaningCard..
  • 다음의 제공되는 코드를 사용할 수 있다.
    • lib/page/main_page.dart
      // 추가 코드를 작성할 것. 본 소스는 디자인만 작성되어 있으며
      // 이 기본 틀을 통하여 과제에 필요한 소스코드를 추가적으로 구현할 것.
      import 'package:flutter/material.dart';
      
      class MainPage extends StatefulWidget {
        const MainPage({super.key});
      
        
        State<MainPage> createState() => _MainPageState();
      }
      
      class _MainPageState extends State<MainPage> {
        
        Widget build(BuildContext context) {
          return Scaffold(
            appBar: AppBar(
              title: const Text('Dictionary App'),
              elevation: 0,
              centerTitle: false,
            ),
            body: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Row(
                    children: [
                      Expanded(
                        child: Padding(
                          padding: const EdgeInsets.all(16),
                          child: TextField(
                            decoration: const InputDecoration(
                              hintText: "Search",
                              suffixIcon: Icon(Icons.search),
                              enabledBorder: OutlineInputBorder(
                                borderSide: BorderSide(color: Colors.white),
                              ),
                              focusedBorder: OutlineInputBorder(
                                borderSide: BorderSide(color: Colors.white),
                              ),
                            ),
                            onSubmitted: (value) {},
      
                          ),
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            ),
          );
        }
      }

코드

  • main.dart
    import 'package:flutter/material.dart';
    
    import 'page/main_page.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      
      Widget build(BuildContext context) {
        return MaterialApp(
          home: MainPage(),
        );
      }
    }

model

  • dict.dart
    import 'phonetic.dart';
    import 'meaning.dart';
    import 'license.dart';
    
    class Dict {
      String word;
      String? phonetic;
      List<Phonetic> phonetics;
      List<Meaning> meanings;
      License license;
      List<String> sourceUrls;
    
      Dict({
        required this.word,
        required this.phonetic,
        required this.phonetics,
        required this.meanings,
        required this.license,
        required this.sourceUrls,
      });
    
      factory Dict.fromMap(Map<String, dynamic> map) {
        return Dict(
          word: map['word'],
          phonetic: map['phonetic'],
          phonetics: List<Phonetic>.from(map['phonetics'].map((e) => Phonetic.fromMap(e))),
          meanings: List<Meaning>.from(map['meanings'].map((e) => Meaning.fromMap(e))),
          license: License.fromMap(map['license']),
          sourceUrls: List<String>.from(map['sourceUrls']),
        );
      }
    }
  • phonetic.dart
    import 'license.dart';
    
    class Phonetic {
      String? text;
      String audio;
      String? sourceUrl;
      License? license;
    
      Phonetic({
        required this.text,
        required this.audio,
        required this.sourceUrl,
        required this.license,
      });
    
      factory Phonetic.fromMap(Map<String, dynamic> map) {
        return Phonetic(
          text: map['text'],
          audio: map['audio'],
          sourceUrl: map['sourceUrl'],
          license: map['license'] != null ? License.fromMap(map['license']) : null,
        );
      }
    }
  • meaning.dart
    import 'definition.dart';
    
    class Meaning {
      String partOfSpeech;
      List<Definition> definitions;
      List<String> synonyms;
      List<String> antonyms;
    
      Meaning({
        required this.partOfSpeech,
        required this.definitions,
        required this.synonyms,
        required this.antonyms,
      });
      
      factory Meaning.fromMap(Map<String, dynamic> map) {
        return Meaning(
          partOfSpeech: map['partOfSpeech'], 
          definitions: List<Definition>.from(map['definitions'].map((e) => Definition.fromMap(e))),
          synonyms: List<String>.from(map['synonyms']),
          antonyms: List<String>.from(map['antonyms']),
        );
      }
    }
  • definition.dart
    class Definition {
      String definition;
      List<String> synonyms;
      List<String> antonyms;
      String? example;
    
      Definition({
        required this.definition,
        required this.synonyms,
        required this.antonyms,
        required this.example,
      });
    
      factory Definition.fromMap(Map<String, dynamic> map) {
        return Definition(
          definition: map['definition'],
          synonyms: List<String>.from(map['synonyms']),
          antonyms: List<String>.from(map['antonyms']),
          example: map['example'],
        );
      }
    }
  • license.dart
    class License {
      String name;
      String url;
    
      License({required this.name, required this.url});
    
      factory License.fromMap(Map<String, dynamic> map) {
        return License(name: map['name'], url: map['url']);
      }
    }

page

  • main_page.dart
    import 'dart:developer';
    
    import 'package:dio/dio.dart';
    import 'package:first_app/homework/week6/day28/widget/meaning_card.dart';
    import 'package:flutter/material.dart';
    
    import '../model/dict.dart';
    
    class MainPage extends StatefulWidget {
      const MainPage({super.key});
    
      
      State<MainPage> createState() => _MainPageState();
    }
    
    class _MainPageState extends State<MainPage> {
      Dict? _word;
    
      getData(String word) async {
        Dio dio = Dio();
        String url = 'https://api.dictionaryapi.dev/api/v2/entries/en/$word';
    
        try {
          var res = await dio.get(url);
          if (res.statusCode == 200) {
            _word = Dict.fromMap(res.data.first);
          }
        } on DioError {
          _word = null;
        }
        print(_word);
        setState(() { });
      }
    
      
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('Dictionary App'),
            elevation: 0,
            centerTitle: false,
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Row(
                  children: [
                    Expanded(
                      child: Padding(
                        padding: const EdgeInsets.all(16),
                        child: TextField(
                          decoration: const InputDecoration(
                            hintText: "Search",
                            suffixIcon: Icon(Icons.search),
                            enabledBorder: OutlineInputBorder(
                              borderSide: BorderSide(color: Colors.white),
                            ),
                            focusedBorder: OutlineInputBorder(
                              borderSide: BorderSide(color: Colors.white),
                            ),
                          ),
                          onSubmitted: (value) {
                            getData(value);
                          },
                        ),
                      ),
                    ),
                  ],
                ),
                if (_word != null) MeaningCard(word: _word!)
              ],
            ),
          ),
        );
      }
    }

widget

  • meaning_card.dart
    import 'package:flutter/material.dart';
    
    import '../model/dict.dart';
    
    class MeaningCard extends StatelessWidget {
      const MeaningCard({Key? key, required this.word}) : super(key: key);
    
      final Dict word;
    
      
      Widget build(BuildContext context) {
        return Expanded(
          child: Container(
            width: double.infinity,
            height: double.infinity,
            color: Colors.white10,
            child: SingleChildScrollView(
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(word.word, style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
                    for (var meaning in word.meanings)
                      Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text(meaning.partOfSpeech, style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
                            SizedBox(height: 8),
                            Text('- Synonyms:'),
                            for (var synonym in meaning.synonyms) Text(synonym),
                            SizedBox(height: 8),
                            Text('- Definitions:'),
                            for (var definition in meaning.definitions) Text(definition.definition),
                            SizedBox(height: 8),
                            Text('- Antonyms:'),
                            for (var antonym in meaning.antonyms) Text(antonym),
                            Divider(),
                          ],
                        ),
                      ),
                  ],
                ),
              ),
            ),
          ),
        );
      }
    }


28일차 끝!!!

드디어 밀린 과제를 다 끝냇습니다................................

과연 주간평가 과제는 밀릴까요~~ 안밀릴까요~~~

정답은.................................................................................................................

밀렷다~!

입니다...............


열심히해서제출하겟습니다..............

profile
우와재밋다

0개의 댓글