Skip to content

Commit 4586218

Browse files
Implement a Virtusize Widget
1 parent cb1c01f commit 4586218

9 files changed

Lines changed: 224 additions & 3 deletions

File tree

android/src/main/kotlin/com/virtusize/virtusize_flutter_sdk/VirtusizeFlutterConstants.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ internal object VirtusizeFlutterKey {
4242
const val SHOW_USER_PRODUCT_IMAGE = "showUserProductImage"
4343
const val IS_VALID_PRODUCT = "isValidProduct"
4444
const val SHOW_PRIVACY_POLICY = "showPrivacyPolicy"
45+
const val STORE_NAME = "storeName"
4546
}
4647

4748
internal object VirtusizeEventKey {

android/src/main/kotlin/com/virtusize/virtusize_flutter_sdk/VirtusizeFlutterPlugin.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class VirtusizeFlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
3939
mutableMapOf(
4040
VirtusizeFlutterKey.EXTERNAL_PRODUCT_ID to productWithPCDData.externalId,
4141
VirtusizeFlutterKey.IS_VALID_PRODUCT to (productWithPCDData.productCheckData?.data?.validProduct ?: false),
42+
VirtusizeFlutterKey.STORE_NAME to (productWithPCDData.productCheckData?.data?.storeName ?: ""),
4243
)
4344
)
4445
}

example/lib/screens/home_screen.dart

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ class _HomeScreenState extends State<HomeScreen> {
1515
/// Declare a global [VirtusizeClientProduct] variable, which will be passed to the `Virtusize` widgets in order to bind the product info
1616
late VirtusizeClientProduct _product;
1717

18+
String _virtusizeWidget = "Virtusize Widget Test";
19+
20+
1821
@override
1922
void initState() {
2023
super.initState();
@@ -69,6 +72,7 @@ class _HomeScreenState extends State<HomeScreen> {
6972
child: ListView(
7073
shrinkWrap: true,
7174
children: [
75+
7276
Center(
7377
child:
7478
/// A [VirtusizeButton] widget with the default VirtusizeStyle
@@ -161,6 +165,26 @@ class _HomeScreenState extends State<HomeScreen> {
161165
child: Text("Go to next product page"),
162166
),
163167
),
168+
Container(height: 16),
169+
Center(
170+
child: VirtusizeWidget(
171+
product: _product,
172+
onVirtusizeEventChanged: handleVirtusizeWidgetEvent,
173+
child: Container(
174+
padding: EdgeInsets.all(8.0),
175+
decoration: BoxDecoration(
176+
gradient: const LinearGradient(
177+
colors: [
178+
Color(0xFF6A5AE0),
179+
Color(0xFFB967FF),
180+
],
181+
),
182+
borderRadius: BorderRadius.circular(12),
183+
),
184+
child: Text(_virtusizeWidget),
185+
),
186+
),
187+
),
164188
],
165189
),
166190
),
@@ -208,4 +232,24 @@ class _HomeScreenState extends State<HomeScreen> {
208232
},
209233
);
210234
}
235+
236+
void handleVirtusizeWidgetEvent(VirtusizeWidgetEvent event) {
237+
switch (event) {
238+
case RecommendedSizeChanged(:final text, :final size):
239+
print("Recommended size: $size");
240+
setState(() {
241+
if(size.isNotEmpty){
242+
_virtusizeWidget = "your size is $size";
243+
} else {
244+
_virtusizeWidget = text;
245+
}
246+
});
247+
248+
case LoadingChanged(:final isLoading):
249+
print("Loading: $isLoading");
250+
251+
case ErrorOccurred():
252+
print("Error");
253+
}
254+
}
211255
}

lib/src/main.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,10 @@ class VirtusizeSDK {
6363
call.arguments[FlutterVirtusizeKey.externalProductId];
6464
final isValidProduct =
6565
call.arguments[FlutterVirtusizeKey.isValidProduct];
66+
final storeName =
67+
call.arguments[FlutterVirtusizeKey.storeName];
6668
IVirtusizeSDK.instance._pdcController.add(
67-
ProductDataCheck(externalId, isValidProduct),
69+
ProductDataCheck(externalId, isValidProduct, storeName),
6870
);
6971
},
7072
FlutterVirtusizeMethod.onProductError: (call) {

lib/src/models/product_data_check.dart

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,19 @@ class ProductDataCheck {
55
/// A boolean to tell whether it's a valid product in the Virtusize server
66
final bool isValidProduct;
77

8-
ProductDataCheck(this.externalProductId, this.isValidProduct);
8+
/// A string to represent the store name
9+
final String storeName;
10+
11+
ProductDataCheck(this.externalProductId, this.isValidProduct, this.storeName);
912

1013
@override
1114
String toString() {
12-
return '{externalProductId: $externalProductId, isValidProduct: $isValidProduct}';
15+
return '{externalProductId: $externalProductId, isValidProduct: $isValidProduct, storeName: $storeName}';
1316
}
17+
18+
bool canBuildVirtusizeWidget() => _Stores.values.any((store) => store.name == storeName);
19+
}
20+
21+
enum _Stores{
22+
snkrdunk
1423
}

lib/src/utils/virtusize_constants.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,5 @@ class FlutterVirtusizeKey {
4343
static const String showUserProductImage = "showUserProductImage";
4444
static const String isValidProduct = "isValidProduct";
4545
static const String showPrivacyPolicy = "showPrivacyPolicy";
46+
static const String storeName = "storeName";
4647
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import 'dart:async';
2+
3+
import 'package:flutter/material.dart';
4+
import 'package:virtusize_flutter_sdk/src/widgets/virtusize_widget_event.dart';
5+
6+
import '../../virtusize_flutter_sdk.dart';
7+
import '../main.dart';
8+
import '../models/product_data_check.dart';
9+
import '../models/recommendation.dart';
10+
import '../res/vs_text.dart';
11+
12+
class VirtusizeWidget extends StatefulWidget {
13+
final VirtusizeClientProduct product;
14+
final Container child;
15+
final ValueChanged<VirtusizeWidgetEvent> onVirtusizeEventChanged;
16+
VirtusizeWidget({
17+
required this.product,
18+
required this.child,
19+
required this.onVirtusizeEventChanged,
20+
}) : super(key: ValueKey('button_${product.externalProductId}'));
21+
22+
@override
23+
State<StatefulWidget> createState() => _VirtusizeWidgetState();
24+
}
25+
26+
class _VirtusizeWidgetState extends State<VirtusizeWidget> {
27+
late final StreamSubscription<VSText> _vsTextSubscription;
28+
late final StreamSubscription<ProductDataCheck> _pdcSubscription;
29+
late final StreamSubscription<String> _errorSubscription;
30+
late final StreamSubscription<Recommendation> _recSubscription;
31+
32+
VSText _vsText = IVirtusizeSDK.instance.vsText;
33+
bool _isValidProduct = false;
34+
bool _canBuildWidget = false;
35+
Timer? _productDataCheckTimeout;
36+
37+
@override
38+
void initState() {
39+
super.initState();
40+
41+
_vsTextSubscription = IVirtusizeSDK.instance.vsTextStream.listen((vsText) {
42+
setState(() {
43+
_vsText = vsText;
44+
});
45+
});
46+
47+
_pdcSubscription = IVirtusizeSDK.instance.pdcStream.listen((
48+
productDataCheck,
49+
) {
50+
if (widget.product.externalProductId != productDataCheck.externalProductId) {
51+
return;
52+
}
53+
_productDataCheckTimeout?.cancel();
54+
55+
setState(() {
56+
_isValidProduct = productDataCheck.isValidProduct;
57+
_canBuildWidget = productDataCheck.canBuildVirtusizeWidget();
58+
});
59+
60+
widget.onVirtusizeEventChanged(LoadingChanged(true));
61+
});
62+
63+
_recSubscription = IVirtusizeSDK.instance.recStream.listen((
64+
recommendation,
65+
) {
66+
if (widget.product.externalProductId !=
67+
recommendation.externalProductID) {
68+
return;
69+
}
70+
widget.onVirtusizeEventChanged(LoadingChanged(false));
71+
getRecommendedSize(recommendation.text);
72+
});
73+
74+
_errorSubscription = IVirtusizeSDK.instance.productErrorStream.listen((
75+
externalProductId,
76+
) {
77+
if (widget.product.externalProductId != externalProductId) {
78+
return;
79+
}
80+
widget.onVirtusizeEventChanged(LoadingChanged(false));
81+
widget.onVirtusizeEventChanged(ErrorOccurred());
82+
83+
});
84+
85+
// Start timeout timer for product data check
86+
_startProductDataCheckTimeout();
87+
}
88+
89+
void _startProductDataCheckTimeout() {
90+
_productDataCheckTimeout?.cancel();
91+
92+
_productDataCheckTimeout = Timer(Duration(seconds: 10), () {
93+
if (!mounted) return;
94+
if (!_isValidProduct) {
95+
setState(() {});
96+
}
97+
});
98+
}
99+
100+
@override
101+
void didUpdateWidget(VirtusizeWidget oldWidget) {
102+
super.didUpdateWidget(oldWidget);
103+
if (oldWidget.product.externalProductId != widget.product.externalProductId) {
104+
setState(() {
105+
_isValidProduct = false;
106+
});
107+
_startProductDataCheckTimeout();
108+
}
109+
}
110+
111+
@override
112+
void dispose() {
113+
_vsTextSubscription.cancel();
114+
_pdcSubscription.cancel();
115+
_productDataCheckTimeout?.cancel();
116+
super.dispose();
117+
}
118+
119+
@override
120+
Widget build(BuildContext context) {
121+
// Show the view only when the product is confirmed valid
122+
if (_isValidProduct && _canBuildWidget) {
123+
return GestureDetector(
124+
onTap: _openVirtusizeWebview,
125+
child: widget.child,
126+
);
127+
}
128+
return Container();
129+
}
130+
131+
void getRecommendedSize(String recText) {
132+
List<String> recTextArray = recText.split("<br>");
133+
if (recTextArray.length == 2) {
134+
widget.onVirtusizeEventChanged(RecommendedSizeChanged(recTextArray.first, recTextArray.last));
135+
} else {
136+
widget.onVirtusizeEventChanged(RecommendedSizeChanged(recText, ""));
137+
}
138+
}
139+
140+
Future<void> _openVirtusizeWebview() async {
141+
await VirtusizeSDK.instance.openVirtusizeWebView(widget.product);
142+
}
143+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
sealed class VirtusizeWidgetEvent {}
2+
3+
class RecommendedSizeChanged extends VirtusizeWidgetEvent {
4+
final String size;
5+
final String text;
6+
7+
RecommendedSizeChanged(this.text, this.size);
8+
}
9+
10+
class LoadingChanged extends VirtusizeWidgetEvent {
11+
final bool isLoading;
12+
13+
LoadingChanged(this.isLoading);
14+
}
15+
16+
class ErrorOccurred extends VirtusizeWidgetEvent {
17+
ErrorOccurred();
18+
}

lib/virtusize_flutter_sdk.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ export 'src/models/virtusize_enums.dart';
66
export 'src/models/virtusize_order.dart';
77
export 'src/models/virtusize_order_item.dart';
88
export 'src/widgets/virtusize_button.dart';
9+
export 'src/widgets/virtusize_widget.dart';
10+
export 'src/widgets/virtusize_widget_event.dart';
911
export 'src/widgets/virtusize_inpage_standard.dart';
1012
export 'src/widgets/virtusize_inpage_mini.dart';
1113
export 'src/utils/virtusize_message_listener.dart';

0 commit comments

Comments
 (0)