Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/workflows/pull_request_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@ jobs:
cache: true

- name: Install dependencies
run: flutter pub get

run: |
flutter pub get
cd example && flutter pub get

- name: Clean Gradle cache
working-directory: ./example/android
run: rm -rf ~/.gradle/caches/

- name: Run Android tests
working-directory: ./example/android
run: ./gradlew testDebugUnitTest -x :url_launcher_android:testDebugUnitTest
Expand Down
2 changes: 1 addition & 1 deletion example/android/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pluginManagement {
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.9.1" apply false
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
}

include(":app")
3 changes: 2 additions & 1 deletion ios/Classes/SwiftVirtusizeFlutterPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ extension SwiftVirtusizeFlutterPlugin: VirtusizeFlutterProductEventHandler {
storeProduct: VirtusizeServerProduct,
bestUserProduct: VirtusizeServerProduct?,
recommendationText: String,
willFit: Bool?) {
willFit: Bool
) {
DispatchQueue.main.async { [self] in
self.flutterChannel?.invokeMethod(
VirtusizeFlutterMethod.onProduct,
Expand Down
2 changes: 1 addition & 1 deletion ios/virtusize_flutter_sdk.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ This SDK helps clients to integrate Virtusize’s size and fit service into thei
s.resources = 'Resources/**/*.json'
s.resource_bundle = { 'virtusize_flutter_sdk' => ['Resources/**/*.json'] }
s.dependency 'Flutter'
s.dependency 'Virtusize', '~> 2.12.25'
s.dependency 'Virtusize', '~> 2.12.26'
s.static_framework = true

s.platform = :ios, '14.0'
Expand Down
82 changes: 51 additions & 31 deletions lib/src/widgets/virtusize_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ import '../main.dart';
import '../models/product_data_check.dart';
import '../models/recommendation.dart';

class VirtusizeWidget extends StatefulWidget {
class VirtusizeWidgetBuilder extends StatefulWidget {
final VirtusizeClientProduct product;
final Container child;
final ValueChanged<VirtusizeWidgetEvent> onVirtusizeEventChanged;
VirtusizeWidget({

final Widget Function(BuildContext context, VirtusizeWidgetState) builder;

VirtusizeWidgetBuilder({
required this.product,
required this.child,
required this.onVirtusizeEventChanged,
required this.builder,
}) : super(key: ValueKey('button_${product.externalProductId}'));

@override
State<StatefulWidget> createState() => _VirtusizeWidgetState();
State<StatefulWidget> createState() => _VirtusizeWidgetBuilderState();
}

class _VirtusizeWidgetState extends State<VirtusizeWidget> {
class _VirtusizeWidgetBuilderState extends State<VirtusizeWidgetBuilder> {
late final StreamSubscription<ProductDataCheck> _pdcSubscription;
late final StreamSubscription<String> _errorSubscription;
late final StreamSubscription<Recommendation> _recSubscription;
Expand All @@ -31,6 +31,8 @@ class _VirtusizeWidgetState extends State<VirtusizeWidget> {
bool _isAllowedForStore = false;
Timer? _productDataCheckTimeout;

VirtusizeWidgetState _eventState = VirtusizeWidgetLoading();

@override
void initState() {
super.initState();
Expand All @@ -44,11 +46,15 @@ class _VirtusizeWidgetState extends State<VirtusizeWidget> {
_productDataCheckTimeout?.cancel();

setState(() {
_isValidProduct = productDataCheck.isValidProduct;
_eventState = VirtusizeWidgetLoading();

_isValidProduct = productDataCheck.isValidProduct;
_isAllowedForStore = productDataCheck.isAllowedForStore();
});

widget.onVirtusizeEventChanged(LoadingChanged(true));
if(!_isValidProduct) {
_eventState = VirtusizeWidgetError(error: 'Invalid product: ${productDataCheck.externalProductId}');
}
});
});

_recSubscription = IVirtusizeSDK.instance.recStream.listen((
Expand All @@ -58,8 +64,7 @@ class _VirtusizeWidgetState extends State<VirtusizeWidget> {
recommendation.externalProductID) {
return;
}
widget.onVirtusizeEventChanged(LoadingChanged(false));
getRecommendedSize(recommendation.text);
onVirtusizeWidgetCompleted(recommendation.text);
});

_errorSubscription = IVirtusizeSDK.instance.productErrorStream.listen((
Expand All @@ -68,9 +73,10 @@ class _VirtusizeWidgetState extends State<VirtusizeWidget> {
if (widget.product.externalProductId != externalProductId) {
return;
}
widget.onVirtusizeEventChanged(LoadingChanged(false));
widget.onVirtusizeEventChanged(ErrorOccurred());

setState(() {
_eventState = VirtusizeWidgetError(error: 'Product error: $externalProductId');
});
});

// Start timeout timer for product data check
Expand All @@ -82,14 +88,16 @@ class _VirtusizeWidgetState extends State<VirtusizeWidget> {

_productDataCheckTimeout = Timer(Duration(seconds: 10), () {
if (!mounted) return;
if (!_isValidProduct) {
setState(() {});
if (_eventState is VirtusizeWidgetLoading) {
setState(() {
_eventState = VirtusizeWidgetError(error: 'Product data check timed out');
});
}
});
}

@override
void didUpdateWidget(VirtusizeWidget oldWidget) {
void didUpdateWidget(VirtusizeWidgetBuilder oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.product.externalProductId != widget.product.externalProductId) {
setState(() {
Expand All @@ -110,23 +118,35 @@ class _VirtusizeWidgetState extends State<VirtusizeWidget> {

@override
Widget build(BuildContext context) {
// Show the view only when the product is confirmed valid
if (_isValidProduct && _isAllowedForStore) {
return GestureDetector(
onTap: _openVirtusizeWebview,
child: widget.child,
);

switch(_eventState){
case VirtusizeWidgetCompleted():{
//Return empty container if store is not allowed to use this widget class
if(!_isAllowedForStore){
return Container();
}

return GestureDetector(
onTap: _openVirtusizeWebview,
child: widget.builder(context, _eventState),
);
}
default:
return widget.builder(context, _eventState);
}
return Container();
}

void getRecommendedSize(String recText) {
void onVirtusizeWidgetCompleted(String recText) {
List<String> recTextArray = recText.split("<br>");
if (recTextArray.length == 2) {
widget.onVirtusizeEventChanged(RecommendedSizeChanged(recTextArray.first, recTextArray.last));
} else {
widget.onVirtusizeEventChanged(RecommendedSizeChanged(recText, ""));
}
setState(() {
if (recTextArray.length == 2) {
_eventState = VirtusizeWidgetCompleted(
recommendedText: recTextArray.first, recommendedSize: recTextArray.last);
} else {
_eventState = VirtusizeWidgetCompleted(
recommendedText: recText, recommendedSize: '');
}
});
}

Future<void> _openVirtusizeWebview() async {
Expand Down
21 changes: 10 additions & 11 deletions lib/src/widgets/virtusize_widget_event.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
sealed class VirtusizeWidgetEvent {}
sealed class VirtusizeWidgetState {}

class RecommendedSizeChanged extends VirtusizeWidgetEvent {
final String size;
final String text;
class VirtusizeWidgetCompleted extends VirtusizeWidgetState {
final String recommendedText;
final String recommendedSize;

RecommendedSizeChanged(this.text, this.size);
VirtusizeWidgetCompleted({required this.recommendedText,required this.recommendedSize});
}

class LoadingChanged extends VirtusizeWidgetEvent {
final bool isLoading;

LoadingChanged(this.isLoading);
class VirtusizeWidgetLoading extends VirtusizeWidgetState {
VirtusizeWidgetLoading();
}

class ErrorOccurred extends VirtusizeWidgetEvent {
ErrorOccurred();
class VirtusizeWidgetError extends VirtusizeWidgetState {
final Object error;
VirtusizeWidgetError({required this.error});
}
Loading