본문 바로가기
📱Mobile/🔥Flutter

[Flutter] 간단한 앱 만들기 (provider pattern, translator(google 번역), ChuckNorris(19joke json api), jsontoclass)

by 후눅스 2021. 1. 8.
반응형

 

https://pub.dev/packages/translator

 

ChuckNorris 라는 19세 농담을 던져주는 json api가 있습니다.

 

그 rest api를 사용해서 화면에 뿌려지는 간단한 어플을 만들어보도록 하겠습니다.

 

우선 JSON To Dart Class (JsonToDartClass)를 설치하여줍니다.

 

이런게 플러그인으로 있는지 몰랐는데.. 매우 좋습니다!!! 짱짱 json 형식을 dart class 로 바꾸어집니다.

원하는대로 바꾸어지지 않을 수 있지만 몇개만 추가하면되서 무조건 이 방식이 좋습니다.

 

 

 

먼저 provider, http, translator 이렇게 3가지를 추가해줍니다.

 

provider 패턴을 이용할것이고 http로 json response를 받을것이고 translator로 영어로된것을 한글로 번역할것입니다.

 

파일트리입니다.

 

저는 연습장 정도로만 쓰는 프로젝트에서 만들어서 패키지 이름이 flutter_note 입니다.

 

 

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.0
  provider: ^4.0.5+1	//추가
  http: ^0.12.0+4	//추가
  translator: ^0.1.5	//추가

dev_dependencies:
  flutter_test:
    sdk: flutter

 

 

 

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_note/providers/ChuckyProvider.dart';
import 'package:flutter_note/view/init/initializeProviderDataScreen.dart';
import 'package:provider/provider.dart';
import 'package:translator/translator.dart';

void main() async {
  run();
  // var translation = await translator.translate("hello", to: 'ko');
  // print(translation);
  // print(await "example".translate(to: 'ko'));

  // WidgetsFlutterBinding.ensureInitialized();
  // SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
  //     .then((_) {
  // run();
  // });
}

void run() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  MyApp();

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => ChuckyProvider()),
      ],
      child: MaterialApp(
        color: Colors.white,
        home: InitializeProviderDataScreen(),
      ),
    );
  }

  @override
  void dispose() {
    super.dispose();
  }
}

 

 

 

initializeProviderDataScreen.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_note/models/chuck_random.dart';
import 'package:flutter_note/providers/ChuckyProvider.dart';
import 'package:flutter_note/view/chucky/chuck_random_view.dart';
import 'package:provider/provider.dart';

class InitializeProviderDataScreen extends StatefulWidget {
  @override
  _InitializeProviderDataScreenState createState() =>
      _InitializeProviderDataScreenState();
}

class _InitializeProviderDataScreenState
    extends State<InitializeProviderDataScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: Center(
        child: _loadChuckyCategories(),
      ),
    );
  }

  Widget _loadChuckyCategories() {
    return FutureBuilder(
      future: Provider.of<ChuckyProvider>(context, listen: true)
          .fetchChuckyRandom(),
      builder: (context, snapshot) {
        switch (snapshot.connectionState) {
          case ConnectionState.none:
          case ConnectionState.active:
          case ConnectionState.waiting:
            return getChuckNorris();
          case ConnectionState.done:
            if (snapshot.hasError) {
              return Text('ConnectionState.done / snapshot.hasError',
                  textAlign: TextAlign.center);
            } else {
              return ChuckRandomView(chuckRandom: snapshot.data);
            }
        }
        return getChuckNorris();
      },
    );
  }

  Widget getChuckNorris() {
    return Container(
      width: MediaQuery.of(context).size.width,
      child: Padding(
        padding: const EdgeInsets.all(22.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            SizedBox(
              height: 240,
            ),
            Image.asset(
              'assets/images/chucknorris_logo.png',
              width: 280,
              height: 280,
            ),
            Expanded(child: SizedBox())
          ],
        ),
      ),
    );
  }
}

 

 

 

chuck_random_view.dart

import 'package:flutter/material.dart';
import 'package:flutter_note/models/chuck_random.dart';
import 'package:flutter_note/providers/ChuckyProvider.dart';
import 'package:provider/provider.dart';
import 'package:translator/translator.dart';

class ChuckRandomView extends StatefulWidget {
  ChuckRandom chuckRandom;

  ChuckRandomView({this.chuckRandom});

  @override
  _ChuckRandomViewState createState() =>
      _ChuckRandomViewState(chuckRandom: chuckRandom);
}

class _ChuckRandomViewState extends State<ChuckRandomView> {
  ChuckRandom chuckRandom;

  var chuckKO = '';

  _ChuckRandomViewState({this.chuckRandom});

  @override
  void initState() {
    super.initState();
    translateText(chuckRandom.value);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        width: MediaQuery.of(context).size.width,
        child: Padding(
          padding: const EdgeInsets.all(22.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Expanded(child: SizedBox()),
              Image.asset(
                'assets/images/chucknorris_logo.png',
                width: 280,
                height: 200,
              ),
              chuckTextWidget(chuckRandom.value),
              SizedBox(
                height: 30,
              ),
              chuckTextWidget(chuckKO),
              Expanded(child: SizedBox()),
              FlatButton(
                color: Colors.blue,
                textColor: Colors.white,
                padding: EdgeInsets.all(8.0),
                splashColor: Colors.blueAccent,
                onPressed: () async {
                  ChuckRandom fetchChuckRandom =
                      await Provider.of<ChuckyProvider>(context, listen: false)
                          .fetchChuckyRandom();
                  translateText(fetchChuckRandom.value);
                  chuckRandom = fetchChuckRandom;
                },
                child: Text(
                  "Shot",
                  style: TextStyle(fontSize: 20.0),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  translateText(text) async {
    var translation = await GoogleTranslator().translate(text, to: 'ko');
    setState(() {
      chuckKO = translation.text;
    });
  }

  Widget chuckTextWidget(text) {
    return Text(
      text,
      textAlign: TextAlign.center,
      style: TextStyle(
        color: Colors.black,
        fontSize: 16,
      ),
    );
  }
}

 

 

 

 

commons.dart

import 'dart:convert';
import 'package:http/http.dart' as http;

class Commons {
  ///jokes/random
  static const baseURL = "https://api.chucknorris.io";

  static dynamic returnResponse(http.Response response) {
    switch (response.statusCode) {
      case 200:
        var responseJson = jsonDecode(response.body.toString());
        print(responseJson);
        return responseJson;
      case 400:
        print('400 error');
        return response.body.toString();
      case 401:
      case 403:
        print('400 or 403 error');
        return response.body.toString();
      case 500:
        print('500 error');
        return response.body.toString();
      default:
        print('case default . error');
        return response.body.toString();
    }
  }
}

 

 

 

ChuckyProvider.dart

import 'dart:convert';

import 'package:flutter/cupertino.dart';
import 'package:flutter_note/models/chuck_random.dart';
import 'package:flutter_note/utils/commons.dart';
import 'package:http/http.dart' as http;
import 'package:translator/translator.dart';

class ChuckyProvider extends ChangeNotifier {
  ChuckRandom chuckRandom;
  ///jokes/random

  Future<ChuckRandom> fetchChuckyRandom() async {
    try {
      final response =
          await http.get((Commons.baseURL + '/jokes/random'), headers:{
            "Accept": "application/json",
            "content-type": "application/json",
          });
      if(response.statusCode == 200){
        chuckRandom =ChuckRandom.fromJson(Commons.returnResponse(response));
        return chuckRandom;
      } else {
        return null;
      }
    } on Exception {
      print('fetch ChuckyRandom() exception');
      return null;
    }
  }
}

 

 

 

 

ChuckRandom 클래스는 json to dart class 를 사용해서 만든것입니다!

 

아까 플러그인을 설치하였으면 상단에 Generate가 보일것입니다.

 

클릭하시고 

 

적어주면 생성됩니다

 

 

chuck_random.dart

import 'package:translator/translator.dart';

class ChuckRandom {
  final List<Object> categories;
  final String createdAt;
  final String iconUrl;
  final String id;
  final String updatedAt;
  final String url;
  final String value;

  ChuckRandom({
    this.categories,
    this.createdAt,
    this.iconUrl,
    this.id,
    this.updatedAt,
    this.url,
    this.value,
  });

  factory ChuckRandom.fromJson(Map<String, dynamic> json) {
    return ChuckRandom(
      categories: json['categories'] != null
          ? new List<String>.from(json['categories'])
          : null,
      createdAt: json['created_at'] ?? '',
      iconUrl: json['icon_url'] ?? '',
      id: json['id'] ?? '',
      updatedAt: json['updated_at'] ?? '',
      url: json['url'] ?? '',
      value: json['value'] ?? '',
    );
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['created_at'] = this.createdAt;
    data['icon_url'] = this.iconUrl;
    data['id'] = this.id;
    data['updated_at'] = this.updatedAt;
    data['url'] = this.url;
    data['value'] = this.value;
    if (this.categories != null) {
      data['categories'] = this.categories;
    }
    return data;
  }
}

 

메인화면 wating
main done (has data)

 

 

 

MultiProvider 로 ChangeNotifierProvider들을 리스트에 담아줍니다.

ChangeNofifierProvider에 create 클래스들은 모두 ChangeNotifier 를 extends 하고있습니다.

 

 

feacth 해서 내려오는 값들을 snapshot의 상태를 확인해서 hasError가 아닌경우(hasData) 화면 뿌릴 위젯을 만듭니다.

 

 

 

to: 'ko' 는 Korea 입니다. 변경가능한 언어 리스트인데 골라서 변경해줘도 됩니다!

static final _langs = {
    'auto': 'Automatic',
    'af': 'Afrikaans',
    'sq': 'Albanian',
    'am': 'Amharic',
    'ar': 'Arabic',
    'hy': 'Armenian',
    'az': 'Azerbaijani',
    'eu': 'Basque',
    'be': 'Belarusian',
    'bn': 'Bengali',
    'bs': 'Bosnian',
    'bg': 'Bulgarian',
    'ca': 'Catalan',
    'ceb': 'Cebuano',
    'ny': 'Chichewa',
    'zh-cn': 'Chinese Simplified',
    'zh-tw': 'Chinese Traditional',
    'co': 'Corsican',
    'hr': 'Croatian',
    'cs': 'Czech',
    'da': 'Danish',
    'nl': 'Dutch',
    'en': 'English',
    'eo': 'Esperanto',
    'et': 'Estonian',
    'tl': 'Filipino',
    'fi': 'Finnish',
    'fr': 'French',
    'fy': 'Frisian',
    'gl': 'Galician',
    'ka': 'Georgian',
    'de': 'German',
    'el': 'Greek',
    'gu': 'Gujarati',
    'ht': 'Haitian Creole',
    'ha': 'Hausa',
    'haw': 'Hawaiian',
    'iw': 'Hebrew',
    'hi': 'Hindi',
    'hmn': 'Hmong',
    'hu': 'Hungarian',
    'is': 'Icelandic',
    'ig': 'Igbo',
    'id': 'Indonesian',
    'ga': 'Irish',
    'it': 'Italian',
    'ja': 'Japanese',
    'jw': 'Javanese',
    'kn': 'Kannada',
    'kk': 'Kazakh',
    'km': 'Khmer',
    'ko': 'Korean',
    'ku': 'Kurdish (Kurmanji)',
    'ky': 'Kyrgyz',
    'lo': 'Lao',
    'la': 'Latin',
    'lv': 'Latvian',
    'lt': 'Lithuanian',
    'lb': 'Luxembourgish',
    'mk': 'Macedonian',
    'mg': 'Malagasy',
    'ms': 'Malay',
    'ml': 'Malayalam',
    'mt': 'Maltese',
    'mi': 'Maori',
    'mr': 'Marathi',
    'mn': 'Mongolian',
    'my': 'Myanmar (Burmese)',
    'ne': 'Nepali',
    'no': 'Norwegian',
    'ps': 'Pashto',
    'fa': 'Persian',
    'pl': 'Polish',
    'pt': 'Portuguese',
    'pa': 'Punjabi',
    'ro': 'Romanian',
    'ru': 'Russian',
    'sm': 'Samoan',
    'gd': 'Scots Gaelic',
    'sr': 'Serbian',
    'st': 'Sesotho',
    'sn': 'Shona',
    'sd': 'Sindhi',
    'si': 'Sinhala',
    'sk': 'Slovak',
    'sl': 'Slovenian',
    'so': 'Somali',
    'es': 'Spanish',
    'su': 'Sundanese',
    'sw': 'Swahili',
    'sv': 'Swedish',
    'tg': 'Tajik',
    'ta': 'Tamil',
    'te': 'Telugu',
    'th': 'Thai',
    'tr': 'Turkish',
    'uk': 'Ukrainian',
    'ur': 'Urdu',
    'uz': 'Uzbek',
    'vi': 'Vietnamese',
    'cy': 'Welsh',
    'xh': 'Xhosa',
    'yi': 'Yiddish',
    'yo': 'Yoruba',
    'zu': 'Zulu'
  };

 

 

앱에 빌드하고 나오는 말들이 재미있어서 앱에 빌드하고 심심할때 봐도 괜찮을꺼같아요!

 

구글번역이라 번역이 잘 되지는 않습니다..

반응형