Last active
June 18, 2022 07:56
-
-
Save koboolean/0eb66bad1f4c3043a256ff44d7b6c976 to your computer and use it in GitHub Desktop.
flutter by book_store
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Book { | |
String title; | |
String subtitle; | |
String thumbnail; | |
String previewLink; | |
Book({ | |
required this.title, | |
required this.subtitle, | |
required this.thumbnail, | |
required this.previewLink, | |
}); | |
// Map<String, dynamic>을 전달받아 Book 클래스 인스턴스를 반환하는 함수 | |
// factory 키워드를 붙여서 생성자로 사용 | |
factory Book.fromJson(Map<String, dynamic> volumeInfo) { | |
return Book( | |
// title이 없는 경우 빈 문자열 할당 | |
title: volumeInfo["title"] ?? "", | |
// subtitle이 없는 경우 빈 문자열 할당 | |
subtitle: volumeInfo["subtitle"] ?? "", | |
// imageLisks 또는 thumbnail이 없을 때 빈 이미지 추가 | |
thumbnail: volumeInfo["imageLinks"]?["thumbnail"] ?? "https://i.ibb.co/2ypYwdr/no-photo.png", | |
// previewLink가 없는 경우 빈 문자열 할당 | |
previewLink: volumeInfo["previewLink"] ?? "", | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:dio/dio.dart'; | |
import 'package:flutter/material.dart'; | |
import 'book.dart'; | |
class BookService extends ChangeNotifier { | |
// 책 목록 | |
List<Book> bookList = []; | |
/// 검색어로 책 정보 불러오기 | |
void getBookList(String q) async { | |
bookList.clear(); // 기존에 들어있는 데이터 초기화 | |
// API 호출 | |
Response res = await Dio().get( | |
"https://www.googleapis.com/books/v1/volumes?q=$q&startIndex=0&maxResults=40", | |
); | |
List items = res.data["items"]; // items 접근 | |
for (Map<String, dynamic> item in items) { | |
Map<String, dynamic> volumeInfo = item["volumeInfo"]; // volumeInfo 접근 | |
Book book = Book.fromJson(volumeInfo); // Map -> Book | |
bookList.add(book); // Book 추가 | |
} | |
// 화면 갱신 | |
notifyListeners(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:book_store/book_service.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:provider/provider.dart'; | |
import 'package:url_launcher/url_launcher.dart'; | |
import 'book.dart'; | |
class HomePage extends StatelessWidget { | |
HomePage({Key? key}) : super(key: key); | |
/// 검색어를 가져올 수 있도록 TextField와 연결해 줍니다. | |
final TextEditingController searchController = TextEditingController(); | |
/// 검색 함수 | |
/// 엔터를 누르거나 돋보기 아이콘을 누를 때 호출 | |
void search(BookService bookService) { | |
String keyword = searchController.text; | |
if (keyword.isNotEmpty) { | |
bookService.getBookList(keyword); | |
} | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Consumer<BookService>( | |
builder: (context, bookService, child) { | |
return Scaffold( | |
appBar: AppBar( | |
backgroundColor: Colors.white, | |
centerTitle: false, | |
title: Text( | |
"Book Store", | |
style: TextStyle( | |
fontSize: 24, | |
fontWeight: FontWeight.bold, | |
color: Colors.black, | |
), | |
), | |
actions: [ | |
Container( | |
alignment: Alignment.bottomCenter, | |
padding: const EdgeInsets.only(right: 12), | |
child: Text( | |
"total ${bookService.bookList.length}", | |
style: TextStyle( | |
color: Colors.black, | |
fontSize: 16, | |
), | |
), | |
), | |
], | |
/// AppBar의 Bottom은 항상 PreferredSize 위젯으로 시작해야합니다. | |
bottom: PreferredSize( | |
preferredSize: Size(double.infinity, 72), | |
child: Padding( | |
padding: const EdgeInsets.all(8.0), | |
child: TextField( | |
controller: searchController, | |
decoration: InputDecoration( | |
hintText: "원하시는 책을 검색해주세요.", | |
// 테두리 | |
border: OutlineInputBorder( | |
borderSide: BorderSide(color: Colors.black), | |
), | |
/// 돋보기 아이콘 | |
suffixIcon: IconButton( | |
icon: Icon(Icons.search), | |
onPressed: () { | |
// 돋보기 아이콘 클릭 | |
search(bookService); | |
}, | |
), | |
), | |
onSubmitted: (v) { | |
// 엔터를 누르는 경우 | |
search(bookService); | |
}, | |
), | |
), | |
), | |
), | |
body: bookService.bookList.isEmpty | |
// bookList가 비어있는 경우 | |
? Center( | |
child: Text( | |
"검색어를 입력해 주세요", | |
style: TextStyle( | |
fontSize: 21, | |
color: Colors.grey, | |
), | |
), | |
) | |
// bookList 보여주기 | |
: ListView.builder( | |
itemCount: bookService.bookList.length, | |
itemBuilder: (context, index) { | |
Book book = bookService.bookList[index]; | |
return ListTile( | |
leading: Image.network( | |
book.thumbnail, | |
width: 80, | |
height: 80, | |
fit: BoxFit.cover, | |
), | |
title: Text(book.title), | |
subtitle: Text(book.subtitle), | |
onTap: () { | |
// 클릭시 previewLink 띄우기 | |
launchUrl(Uri.parse(book.previewLink)); | |
}, | |
); | |
}, | |
), | |
); | |
}, | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:book_store/book_service.dart'; | |
import 'package:book_store/home_page.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:provider/provider.dart'; | |
void main() { | |
runApp( | |
MultiProvider( | |
providers: [ | |
ChangeNotifierProvider(create: (context) => BookService()), | |
], | |
child: const MyApp(), | |
), | |
); | |
} | |
class MyApp extends StatelessWidget { | |
const MyApp({Key? key}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
debugShowCheckedModeBanner: false, | |
home: HomePage(), | |
); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment