Skip to content

Commit

Permalink
Merge pull request #49 from 2024-Saphy/feat/SAPHY-33-product-favlist
Browse files Browse the repository at this point in the history
[FEAT] : Product API integration
  • Loading branch information
boroboro01 authored Oct 6, 2024
2 parents ac77dca + f13452a commit 5dc1309
Show file tree
Hide file tree
Showing 18 changed files with 582 additions and 434 deletions.
Binary file added assets/images/ALL.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/LAPTOP.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/PHONE.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/TABLET.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/headphone-3d.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/wearable-3d.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions devtools_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:
122 changes: 113 additions & 9 deletions lib/screens/main/main_screen.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import 'dart:async';

import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:saphy/models/product.dart';
import 'package:saphy/screens/products/item_list_page.dart';
import 'package:saphy/utils/colors.dart';
import 'package:saphy/utils/textstyles.dart';
import 'package:saphy/widgets/carousel.dart';
Expand All @@ -16,7 +17,6 @@ class MainScreen extends StatefulWidget {
}

class _MainScreenState extends State<MainScreen> {
final int productLength = 6;
late Future<List<Product>> _products;

@override
Expand All @@ -28,8 +28,7 @@ class _MainScreenState extends State<MainScreen> {
Future<List<Product>> getProducts() async {
final dio = Dio();
try {
final response =
await dio.get('https://saphy.site/api/items/all?type=ALL');
final response = await dio.get('https://saphy.site/api/items?size=20');
if (response.statusCode == 200) {
final data = response.data as Map<String, dynamic>;
if (data['results'] != null) {
Expand All @@ -44,29 +43,86 @@ class _MainScreenState extends State<MainScreen> {
throw Exception('Failed to load products');
}
} catch (e) {
print('Error: ${e.toString()}'); // 오류 메시지 확인
print('Error: ${e.toString()}');
return [];
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: false,
title: const Padding(
padding: EdgeInsets.symmetric(horizontal: 10.0),
child: SizedBox(
height: 25,
child: Image(
image: AssetImage('assets/images/SaphyLogoSmallWhite.png')),
),
),
backgroundColor: Colors.transparent, //appBar 투명색
elevation: 0.0,
actions: [
IconButton(
onPressed: () {},
icon: const Icon(
Icons.notifications_outlined,
color: white,
)),
const SizedBox(
width: 10,
)
],
),
extendBodyBehindAppBar: true,
backgroundColor: altWhite,
body: CustomScrollView(
slivers: [
const SliverToBoxAdapter(
child: Carousel(),
),
const SliverToBoxAdapter(
child: SizedBox(
height: 20,
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(20),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SizedBox(
height: 90,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
categoryButton("전체", "ALL"),
const SizedBox(
width: 20,
),
categoryButton("스마트폰", "PHONE"),
const SizedBox(
width: 20,
),
categoryButton("태블릿", "TABLET"),
const SizedBox(
width: 20,
),
categoryButton("노트북", "LAPTOP"),
const SizedBox(
width: 20,
),
categoryButton("음향기기", "headphone-3d"),
const SizedBox(
width: 20,
),
categoryButton("웨어러블", "wearable-3d"),
],
),
),
),
),
),
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 30.0),
child: Text("최근 확인한 상품", style: titleText()),
child: Text("전체 상품", style: titleText()),
),
),
SliverPadding(
Expand Down Expand Up @@ -112,4 +168,52 @@ class _MainScreenState extends State<MainScreen> {
),
);
}

InkWell categoryButton(String category, String url) {
return InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ItemListPage(
name: category,
url: url,
),
),
);
},
child: Container(
height: 90,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: white,
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 13.0, vertical: 8),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 40,
width: 40,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/$url.png'),
fit: BoxFit.cover,
)),
),
Text(
category,
style: const TextStyle(
fontFamily: "Pretendard",
fontSize: 15,
color: black,
fontWeight: FontWeight.w500),
),
],
),
),
),
);
}
}
202 changes: 202 additions & 0 deletions lib/screens/products/item_list_page.dart
Original file line number Diff line number Diff line change
@@ -1 +1,203 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:saphy/utils/colors.dart';
import 'package:saphy/utils/textstyles.dart';
import 'package:saphy/widgets/product_card.dart';
import 'package:dio/dio.dart';
import 'package:saphy/models/product.dart';

class ItemListPage extends StatefulWidget {
final String name, url;
const ItemListPage({super.key, required this.url, required this.name});

@override
State<ItemListPage> createState() => _ItemListPageState();
}

class _ItemListPageState extends State<ItemListPage> {
late Future<List<Product>> _products;
int cnt = 0;

@override
void initState() {
super.initState();
_products = getProducts();
countProducts();
}

Future<void> countProducts() async {
List<Product> products = await getProducts();
setState(() {
cnt = products.length;
});
}

Future<List<Product>> getProducts() async {
final dio = Dio();
try {
final response = await dio
.get('https://saphy.site/api/items?deviceType=${widget.url}&size=20');
if (response.statusCode == 200) {
final data = response.data as Map<String, dynamic>;
if (data['results'] != null) {
List<Product> products = (data['results'] as List)
.map((item) => Product.fromJson(item))
.toList();
return products;
} else {
throw Exception('No results found in the response');
}
} else {
throw Exception('Failed to load products');
}
} catch (e) {
return [];
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xfff4f4f4),
appBar: _appBar(),
body: CustomScrollView(
slivers: [
_buildHeader(),
const SliverToBoxAdapter(
child: SizedBox(height: 10),
),
_buildSorter(),
_buildProductGrid(),
],
),
);
}

AppBar _appBar() {
return AppBar(
automaticallyImplyLeading: false,
backgroundColor: altWhite,
title: Padding(
padding: const EdgeInsets.only(top: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
icon: const Icon(
Icons.arrow_back_ios,
size: 25,
),
onPressed: () {
Navigator.pop(context);
},
),
IconButton(
icon: const Icon(
Icons.search,
size: 25,
),
onPressed: () {},
),
],
),
),
);
}

SliverToBoxAdapter _buildHeader() {
return SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 30.0,
),
child: Text(
widget.name,
style: titleText(),
),
),
);
}

SliverPadding _buildSorter() {
return SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 30),
sliver: SliverToBoxAdapter(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'상품 $cnt',
style: subTitleText(),
),
IconButton(
icon: const Icon(Icons.sort_outlined),
onPressed: () {},
),
],
),
),
);
}

SliverPadding _buildProductGrid() {
return SliverPadding(
padding: const EdgeInsets.only(bottom: 50, right: 20, left: 20, top: 10),
sliver: SliverToBoxAdapter(
child: Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.spaceBetween,
spacing: 15,
runSpacing: 15,
children: [
FutureBuilder(
future: _products,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error.toString()}');
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
return const Center(child: Text('상품이 없습니다'));
} else {
final products = snapshot.data!;
return Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.spaceBetween,
spacing: 15,
runSpacing: 15,
children: products
.map((product) => ProductCard(product: product))
.toList(),
);
}
})
],
),
),
);
}

Container buildFilterButton(String label) {
return Container(
height: 45,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
border: Border.all(color: gray300, width: 1),
color: white,
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 13.0, vertical: 8),
child: Center(
child: Text(
label,
style: const TextStyle(
fontFamily: "Pretendard",
fontSize: 15,
fontWeight: FontWeight.bold),
),
),
),
);
}
}
Loading

0 comments on commit 5dc1309

Please sign in to comment.