name27 / flutter

0 stars 0 forks source link

계속 quote 데이터 받아오기, quote 데이터 10개 받아와 tag 검색 #97

Open name27 opened 1 year ago

name27 commented 1 year ago

image image image image

main.dart

import 'package:flutter/material.dart';
import 'package:my_app/page/main_page.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark(),
      debugShowCheckedModeBanner: false,
      home: MainPage(),
    );
  }
}

main_page.dart

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:my_app/model/quote_data.dart';
import 'package:my_app/page/search_page.dart';
import 'package:my_app/widget/quoteCard.dart';

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

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  List<QuoteData?> quoteData = [];
  Future<List> readQuote() async {
    Dio dio = Dio();
    var url = 'https://favqs.com/api/qotd';
    var res = await dio.get(url);
    if (res.statusCode == 200) {
      quoteData.add(QuoteData.fromMap(res.data));
      print(quoteData.length);
      quoteData;
      return quoteData;
    }
    return [];
  }

  @override
  void initState() {
    super.initState();
    int x = 0;
    while (x < 7) {
      readQuote();
      x++;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
          image: DecorationImage(
              image: NetworkImage(
                  'https://fastly.picsum.photos/id/197/400/600.jpg?hmac=mGEc8MdTwY4Ny3KkvCDqtNTF2SpHBxD8PwIGDm28BNY'),
              fit: BoxFit.cover,
              opacity: 0.5)),
      child: Scaffold(
        backgroundColor: Colors.transparent,
        extendBodyBehindAppBar: true,
        appBar: AppBar(
          backgroundColor: Colors.transparent,
          elevation: 0,
          actions: [
            IconButton(
                onPressed: () {
                  if (quoteData != null) {
                    Navigator.push(
                        context,
                        MaterialPageRoute(
                          builder: (context) =>
                              SearchPage(quoteData: quoteData),
                        ));
                  }
                },
                icon: FaIcon(FontAwesomeIcons.search))
          ],
        ),
        body: Center(
            child: FutureBuilder(
          future: readQuote(),
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return PageView.builder(
                  onPageChanged: (index) => readQuote(),
                  itemBuilder: (context, index) => QuoteCard(
                        quoteData: snapshot.data![index],
                      ));
            }
            return CircularProgressIndicator();
          },
        )),
      ),
    );
  }
}

search_page.dart

import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:my_app/page/tag_page.dart';

class SearchPage extends StatefulWidget {
  const SearchPage({super.key, required this.quoteData});
  final List<dynamic> quoteData;

  @override
  State<SearchPage> createState() => _SearchPageState();
}

var _inputController = TextEditingController();
List<String> searchList = [];
List<int> _searchIndex = [];

class _SearchPageState extends State<SearchPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.transparent,
        elevation: 0,
        title: TextField(
          onSubmitted: (value) {
            searchList.insert(0, value);
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (context) => TagPage(
                          tag: value,
                        )));
            setState(() {});
          },
          controller: _inputController,
          decoration: InputDecoration(
            hintText: 'Tag Search..',
            enabledBorder: OutlineInputBorder(
              borderSide: BorderSide(
                color: Colors.transparent,
                width: 0.3,
              ),
            ),
          ),
        ),
        actions: [
          IconButton(
              onPressed: () {
                _inputController.text = "";
                setState(() {});
              },
              icon: FaIcon(FontAwesomeIcons.close)),
          IconButton(
              onPressed: () {
                searchList.insert(0, _inputController.text);
                Navigator.push(
                    context,
                    MaterialPageRoute(
                        builder: (context) => TagPage(
                              tag: _inputController.text,
                            )));
                setState(() {});
              },
              icon: FaIcon(FontAwesomeIcons.search)),
        ],
      ),
      body: searchList.isEmpty
          ? SizedBox()
          : Padding(
              padding: const EdgeInsets.all(8.0),
              child: Wrap(
                runSpacing: 3,
                spacing: 5,
                children: searchList
                    .map((e) => Chip(
                          labelPadding: EdgeInsets.all(0),
                          label: TextButton(
                              onPressed: () {
                                _inputController.text = e;
                                Navigator.push(
                                    context,
                                    MaterialPageRoute(
                                        builder: (context) => TagPage(
                                              tag: _inputController.text,
                                            )));
                                setState(() {});
                              },
                              child: Text(
                                e,
                                style: TextStyle(
                                    color: Colors.white, fontSize: 16),
                              )),
                          onDeleted: () {
                            searchList.remove(e);
                            setState(() {});
                          },
                        ))
                    .toList(),
              ),
            ),
    );
  }
}

tag_page.dart

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:my_app/model/quote_data.dart';
import 'package:my_app/widget/quoteCard.dart';

class TagPage extends StatefulWidget {
  const TagPage({
    super.key,
    required this.tag,
  });
  final String tag;

  @override
  State<TagPage> createState() => _TagPageState();
}

class _TagPageState extends State<TagPage> {
  List<QuoteData> quoteData = [];
  QuoteData? tagData;
  ValueNotifier<int> i = ValueNotifier<int>(0);
  Future<QuoteData?> readQuote() async {
    for (i.value = 10; i.value > 0; i.value--) {
      Dio dio = Dio();
      var url = 'https://favqs.com/api/qotd';
      var res = await dio.get(url);
      if (res.statusCode == 200) {
        if (res.data['quote']['tags'].contains(widget.tag)) {
          var data = QuoteData.fromMap(res.data);
          return data;
        }
      }
    }
    return null;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
          image: DecorationImage(
              image: NetworkImage(
                  'https://fastly.picsum.photos/id/338/400/600.jpg?hmac=jBPWPvkVzsfyawbDduGKmTO_lR0mq_j3R-2KngcnnPI'),
              fit: BoxFit.cover,
              opacity: 0.5)),
      child: Scaffold(
          extendBodyBehindAppBar: true,
          backgroundColor: Colors.transparent,
          appBar: AppBar(
            title: Text(widget.tag),
            backgroundColor: Colors.transparent,
            elevation: 0,
            centerTitle: true,
          ),
          body: FutureBuilder(
            future: readQuote(),
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return QuoteCard(quoteData: snapshot.data!);
              }
              if (snapshot.connectionState == ConnectionState.done) {
                return Center(
                  child: Text('다시 검색하세요'),
                );
              }
              return Center(
                  child: ValueListenableBuilder(
                      valueListenable: i,
                      builder: (context, value, child) => Text('${i.value}')));
            },
          )),
    );
  }
}

quoteCard.dart

import 'package:animate_do/animate_do.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:my_app/model/quote_data.dart';

class QuoteCard extends StatelessWidget {
  const QuoteCard({super.key, required this.quoteData});
  final QuoteData quoteData;

  @override
  Widget build(BuildContext context) {
    return FadeIn(
      duration: Duration(milliseconds: 800),
      child: Center(
        child: Padding(
          padding: const EdgeInsets.all(12.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Text(
                quoteData.quote.body,
                textAlign: TextAlign.center,
                style: TextStyle(
                  fontWeight: FontWeight.w600,
                  fontSize: 21,
                  wordSpacing: 1.5,
                ),
              ),
              SizedBox(
                height: 8,
              ),
              Text(quoteData.quote.author),
              SizedBox(
                height: 12,
              ),
              Wrap(
                alignment: WrapAlignment.center,
                spacing: 5,
                runSpacing: 3,
                children: [
                  if (quoteData.quote.tags != null)
                    for (var tags in quoteData.quote.tags)
                      Chip(
                        label: Text('# ${tags}'),
                        backgroundColor: Colors.black26,
                      )
                ],
              )
            ],
          ),
        ),
      ),
    );
  }
}

quote_date.dart

import 'package:my_app/model/quote.dart';

class QuoteData {
  String? qotdDate;
  Quote quote;

  QuoteData({required this.qotdDate, required this.quote});

  factory QuoteData.fromMap(Map<String, dynamic> map){
    return QuoteData(qotdDate: map['qotdDate'], quote: Quote.fromMap(map['quote']));
  }
}

quote.dart

class Quote {
  int id;
  bool dialogue;
  String? source;
  String? context;
  bool private;
  List<String> tags;
  String url;
  int? favoritesCount;
  int? upvotesCount;
  int? downvotesCount;
  String author;
  String? authorPermalink;
  String body;

  Quote(
      {required this.id,
      required this.dialogue,
      required this.source,
      required this.context,
      required this.private,
      required this.tags,
      required this.url,
      required this.favoritesCount,
      required this.upvotesCount,
      required this.downvotesCount,
      required this.author,
      required this.authorPermalink,
      required this.body});

  factory Quote.fromMap(Map<String, dynamic> map){
    return Quote(
    id: map['id'],
    dialogue: map['dialogue'],
    source: map['source'],
    context: map['context'],
    private: map['private'],
    tags: List<String>.from(map['tags']),
    url: map['url'],
    favoritesCount: map['favoritesCount'],
    upvotesCount: map['upvotesCount'],
    downvotesCount: map['downvotesCount'],
    author: map['author'], 
    authorPermalink: map['authorPermalink'],
    body: map['body']);
  }
}
name27 commented 1 year ago

1.

헤맸던 내용 페이지 뷰 넘길때마다 새로운 데이터를 가져오고 싶었으나 어떻게 할지 모름

해결 과정 페이지뷰 onPageChanged로 데이터 받아오는 함수를 실행해서 데이터를 가져옴 (맞는 방법 같진 않음)

2.

헤맸던 내용 페이지를 넘길때마다 새로운 데이터를 가져오는데 3번째 페이지부터 에러가 뜸

해결 과정 initState 함수를 통해 먼저 7개 생성 (맞는 방법같진 않음)

3.

헤맸던 내용 태그 검색 시 해당 태그가 들어있는 quote 데이터로 페이지뷰를 보여주고 싶으나 안됨

해결 과정 메인 페이지에서 quote 데이터를 받아와서 검색하는게 아니라 태그페이지에서 새로 받아와서 해결 하지만 워낙 태그 종류가 많아서 로딩이 오래걸림 검색을 10로 제한하여 해결