Skip to content

Commit 4fb5bd9

Browse files
authored
Product detail category (#11)
1 parent 69cf699 commit 4fb5bd9

13 files changed

Lines changed: 474 additions & 368 deletions

File tree

assets/translations/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
"filter_price": "Price",
9090
"product_description": "Description",
9191
"product_characteristics": "Product properties",
92+
"product_from_same_category": "Related products",
9293
"product_property_id": "Unique ID",
9394
"product_property_name": "Name",
9495
"product_property_price": "Price",

assets/translations/ru.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
"filter_price": "Цена",
9090
"product_description": "Описание",
9191
"product_characteristics": "Характеристики товара",
92+
"product_from_same_category": "Рекомендуемые товары",
9293
"product_property_id": "Идентификатор",
9394
"product_property_name": "Наименование",
9495
"product_property_price": "Цена",

assets/translations/uk.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"tab_home": "Товари",
66
"tab_catalog": "Каталог",
77
"tab_search": "Пошук",
8-
"tab_cart": "Корзина",
8+
"tab_cart": "Кошик",
99
"tab_profile": "Профіль",
1010
"exp_show_more": "Розгорнути",
1111
"exp_show_less": "Згорнути",
@@ -89,6 +89,7 @@
8989
"filter_price": "Ціна",
9090
"product_description": "Опис",
9191
"product_characteristics": "Характеристики товару",
92+
"product_from_same_category": "Супутні товари",
9293
"product_property_id": "Ідентифікатор",
9394
"product_property_name": "Найменування",
9495
"product_property_price": "Ціна",
@@ -101,7 +102,7 @@
101102
"product_property_rating": "Рейтинг",
102103
"product_property_images": "Зображення",
103104
"product_property_undefined": "<не задано>",
104-
"cart_empty_title": "Ваша корзина порожня",
105+
"cart_empty_title": "Ваш кошик порожній",
105106
"cart_empty_subtitle": "Саме час зробити вибір!",
106107
"cart_empty_action": "За покупками!",
107108
"settings_language": "Мова",

lib/config/config.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ class WooAppConfig {
77
static const bool featureCart = true;
88
static const bool featureProfile = true;
99
static const bool featureWishList = true;
10+
static const bool featureShopMap = false;
1011
}

lib/datasource/catalog_data_source.dart

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,59 @@ import 'package:wooapp/model/product.dart';
66
import 'package:wooapp/screens/featured/featured_sort.dart';
77

88
class CatalogDataSourceImpl extends CatalogDataSource {
9-
109
final WooApiClient _api = locator<WooApiClient>();
1110

1211
@override
13-
Future<List<Category>> getCategories(int page, Sort sort) => _api.dio
14-
.get('products/categories?hide_empty=true&parent=0&per_page=${WooAppConfig.paginationLimit}&page=$page&$sort')
15-
.then((response) => (response.data as List).map((item) => Category.fromJson(item)).toList());
12+
Future<List<Category>> getCategories(
13+
int page,
14+
Sort sort,
15+
) =>
16+
_api.dio
17+
.get(
18+
'products/categories?hide_empty=true'
19+
'&parent=0'
20+
'&per_page=${WooAppConfig.paginationLimit}'
21+
'&page=$page&$sort',
22+
)
23+
.then(
24+
(response) => (response.data as List)
25+
.map((item) => Category.fromJson(item))
26+
.toList(),
27+
);
1628

1729
@override
18-
Future<List<Product>> getCatalogProducts(int category) => _api.dio
19-
.get('products?status=publish&per_page=10&page=1&category=$category')
20-
.then((response) => (response.data as List).map((item) => Product.fromJson(item)).toList());
30+
Future<List<Product>> getCatalogProducts(
31+
int category, {
32+
List<int> excludedProductIds = const [],
33+
}) =>
34+
_api.dio
35+
.get(
36+
'products?status=publish'
37+
'&per_page=10'
38+
'&page=1'
39+
'${_mapExcludedParam(excludedProductIds)}'
40+
'&category=$category',
41+
)
42+
.then(
43+
(response) => (response.data as List)
44+
.map((item) => Product.fromJson(item))
45+
.toList(),
46+
);
47+
48+
String _mapExcludedParam(List<int> excludedProductIds) {
49+
if (excludedProductIds.isEmpty) return '';
50+
var param = '&exclude=';
51+
for (var id in excludedProductIds) param += '$id,';
52+
param.trim();
53+
return param;
54+
}
2155
}
2256

2357
abstract class CatalogDataSource {
2458
Future<List<Category>> getCategories(int page, Sort sort);
2559

26-
Future<List<Product>> getCatalogProducts(int category);
60+
Future<List<Product>> getCatalogProducts(
61+
int category, {
62+
List<int> excludedProductIds,
63+
});
2764
}

lib/model/category.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ class Category {
1313
: id = json['id'],
1414
name = json['name'],
1515
slug = json['slug'],
16-
parent = json['parent'],
17-
description = json['description'],
16+
parent = json['parent'] ?? -1,
17+
description = json['description'] ?? '',
1818
image = (json['image'] != null)
1919
? WooImage.fromJson(json['image']).src
2020
: '',
21-
count = json['count'];
21+
count = json['count'] ?? 0;
2222
}

lib/model/product.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:wooapp/model/attribute.dart';
2+
import 'package:wooapp/model/category.dart';
23
import 'package:wooapp/model/dimensions.dart';
34
import 'package:wooapp/model/woo_image.dart';
45

@@ -21,6 +22,7 @@ class Product {
2122
Dimensions dimensions;
2223
List<WooImage> images;
2324
List<ProductAttribute> attributes;
25+
List<Category> categories;
2426

2527
bool get isVariable => type == 'variable';
2628
bool get hasDescription => description.isNotEmpty;
@@ -42,8 +44,9 @@ class Product {
4244
sku = json['sku'] ?? '',
4345
rating = double.tryParse(json['average_rating']) ?? 0.0,
4446
dimensions = Dimensions.fromJson(json['dimensions']),
45-
images = (json['images'] as List).map((item) => WooImage.fromJson(item)).toList(),
46-
attributes = (json['attributes'] as List).map((item) => ProductAttribute.fromJson(item)).toList();
47+
images = (json['images'] as List?)?.map((i) => WooImage.fromJson(i)).toList() ?? [],
48+
attributes = (json['attributes'] as List?)?.map((a) => ProductAttribute.fromJson(a)).toList() ?? [],
49+
categories = (json['categories'] as List?)?.map((c) => Category.fromJson(c)).toList() ?? [];
4750
}
4851

4952
class CategoryProduct {

lib/screens/category/category_screen.dart

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,21 +69,22 @@ class _CategoryScreenState extends State<CategoryScreen> {
6969
color: WooAppTheme.colorToolbarForeground,
7070
),
7171
actions: [
72-
if (widget.categoryDesc.isNotEmpty) IconButton(
73-
onPressed: () => Navigator.of(context).push(
74-
MaterialPageRoute(
75-
builder: (context) => CategoryInfoScreen(
76-
widget.categoryTitle,
77-
widget.categoryDesc,
78-
widget.categoryImage,
72+
if (widget.categoryDesc.isNotEmpty)
73+
IconButton(
74+
onPressed: () => Navigator.of(context).push(
75+
MaterialPageRoute(
76+
builder: (context) => CategoryInfoScreen(
77+
widget.categoryTitle,
78+
widget.categoryDesc,
79+
widget.categoryImage,
80+
),
7981
),
8082
),
83+
icon: Icon(
84+
Icons.info,
85+
color: WooAppTheme.colorToolbarForeground,
86+
),
8187
),
82-
icon: Icon(
83-
Icons.info,
84-
color: WooAppTheme.colorToolbarForeground,
85-
),
86-
),
8788
IconButton(
8889
onPressed: () {
8990
_scaffoldKey.currentState!.openEndDrawer();

lib/screens/product/product_view.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import 'package:wooapp/widget/shimmer.dart';
1818
import 'package:flutter_bloc/flutter_bloc.dart';
1919
import 'package:wooapp/widget/widget_add_to_cart.dart';
2020
import 'package:wooapp/widget/widget_attributes.dart';
21+
import 'package:wooapp/widget/widget_catalog_products.dart';
2122
import 'package:wooapp/widget/widget_price_product.dart';
2223
import 'package:wooapp/widget/widget_product_actions.dart';
2324
import 'package:wooapp/widget/widget_product_info.dart';
@@ -171,6 +172,24 @@ class ProductView extends StatelessWidget {
171172
),
172173
Divider(),
173174
ViewedProductsScreen(() {}),
175+
176+
177+
if (product.categories.isNotEmpty)
178+
CatalogProductsWidget(
179+
product.categories[0].id,
180+
height: 166,
181+
itemPaddingHorizontal: 12,
182+
excludedProductsIds: [product.id],
183+
shrinkOnEmpty: true,
184+
headerWidget: Column(
185+
crossAxisAlignment: CrossAxisAlignment.start,
186+
children: [
187+
Divider(),
188+
WooSectionHeading(tr('product_from_same_category')),
189+
],
190+
),
191+
),
192+
174193
SizedBox(height: 16),
175194
],
176195
),

0 commit comments

Comments
 (0)