Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
## XX.XX.XX
* The feedback widgets now have fullscreen and transparent backgrounds for a cleaner look.
* Added a config method to disable server config in the initialization "disableSDKBehaviorSettings()".

## 25.4.1
Expand Down
2 changes: 2 additions & 0 deletions CountlyCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ void CountlyPrint(NSString *stringToPrint);
- (BOOL)hasStarted_;

- (NSURLSession *)URLSession;

- (CGSize)getWindowSize;
@end


Expand Down
41 changes: 41 additions & 0 deletions CountlyCommon.m
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,47 @@ - (NSURLSession *)URLSession
}
}

- (CGSize)getWindowSize {
#if (TARGET_OS_IOS)
UIWindow *window = nil;

if (@available(iOS 13.0, *)) {
for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) {
if ([scene isKindOfClass:[UIWindowScene class]]) {
window = ((UIWindowScene *)scene).windows.firstObject;
break;
}
}
} else {
window = [[UIApplication sharedApplication].delegate window];
}

if (!window) return CGSizeZero;

UIEdgeInsets safeArea = UIEdgeInsetsZero;
CGFloat screenScale = [UIScreen mainScreen].scale;
if (@available(iOS 11.0, *)) {
safeArea = window.safeAreaInsets;
safeArea.left /= screenScale;
safeArea.bottom /= screenScale;
safeArea.right /= screenScale;
}

UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
BOOL isLandscape = UIInterfaceOrientationIsLandscape(orientation);

CGSize size = CGSizeMake(window.bounds.size.width, window.bounds.size.height);

if(!isLandscape){
size.width -= safeArea.left + safeArea.right;
size.height -= safeArea.top + safeArea.bottom;
}

return size;
#endif
return CGSizeZero;
}

@end


Expand Down
115 changes: 38 additions & 77 deletions CountlyContentBuilderInternal.m
Original file line number Diff line number Diff line change
Expand Up @@ -191,47 +191,9 @@ - (NSURLRequest *)fetchContentsRequest
return request;
}

- (CGSize)getWindowSize {
UIWindow *window = nil;

if (@available(iOS 13.0, *)) {
for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) {
if ([scene isKindOfClass:[UIWindowScene class]]) {
window = ((UIWindowScene *)scene).windows.firstObject;
break;
}
}
} else {
window = [[UIApplication sharedApplication].delegate window];
}

if (!window) return CGSizeZero;

UIEdgeInsets safeArea = UIEdgeInsetsZero;
CGFloat screenScale = [UIScreen mainScreen].scale;
if (@available(iOS 11.0, *)) {
safeArea = window.safeAreaInsets;
safeArea.left /= screenScale;
safeArea.bottom /= screenScale;
safeArea.right /= screenScale;
}

UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
BOOL isLandscape = UIInterfaceOrientationIsLandscape(orientation);

CGSize size = CGSizeMake(window.bounds.size.width, window.bounds.size.height);

if(!isLandscape){
size.width -= safeArea.left + safeArea.right;
size.height -= safeArea.top + safeArea.bottom;
}

return size;
}

- (NSString *)resolutionJson {
//TODO: check why area is not clickable and safearea things
CGSize size = [self getWindowSize];
CGSize size = [CountlyCommon.sharedInstance getWindowSize];

UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
BOOL isLandscape = UIInterfaceOrientationIsLandscape(orientation);
Expand Down Expand Up @@ -261,45 +223,44 @@ - (void)showContentWithHtmlPath:(NSString *)urlString placementCoordinates:(NSDi


dispatch_async(dispatch_get_main_queue(), ^ {
// Detect screen orientation
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
BOOL isLandscape = UIInterfaceOrientationIsLandscape(orientation);
// Detect screen orientation
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
BOOL isLandscape = UIInterfaceOrientationIsLandscape(orientation);

// Get the appropriate coordinates based on the orientation
NSDictionary *coordinates = isLandscape ? placementCoordinates[@"l"] : placementCoordinates[@"p"];


// Get the appropriate coordinates based on the orientation
NSDictionary *coordinates = isLandscape ? placementCoordinates[@"l"] : placementCoordinates[@"p"];

CGFloat x = [coordinates[@"x"] floatValue];
CGFloat y = [coordinates[@"y"] floatValue];
CGFloat width = [coordinates[@"w"] floatValue];
CGFloat height = [coordinates[@"h"] floatValue];

CGRect frame = CGRectMake(x, y, width, height);

// Log the URL and the frame
CLY_LOG_I(@"%s, Showing content from URL: %@", __FUNCTION__, url);
CLY_LOG_I(@"%s, Placement frame: %@", __FUNCTION__, NSStringFromCGRect(frame));

CountlyWebViewManager* webViewManager = CountlyWebViewManager.new;
[webViewManager createWebViewWithURL:url frame:frame appearBlock:^
{
CLY_LOG_I(@"%s, Webview appeared", __FUNCTION__);
self->_isCurrentlyContentShown = YES;
[self clearContentState];
} dismissBlock:^
{
CLY_LOG_I(@"%s, Webview dismissed", __FUNCTION__);
self->_isCurrentlyContentShown = NO;
self->_minuteTimer = [NSTimer scheduledTimerWithTimeInterval:self->_zoneTimerInterval
target:self
selector:@selector(enterContentZone)
userInfo:nil
repeats:NO];
if(self.contentCallback) {
self.contentCallback(CLOSED, NSDictionary.new);
}
}];
CGFloat x = [coordinates[@"x"] floatValue];
CGFloat y = [coordinates[@"y"] floatValue];
CGFloat width = [coordinates[@"w"] floatValue];
CGFloat height = [coordinates[@"h"] floatValue];

CGRect frame = CGRectMake(x, y, width, height);

// Log the URL and the frame
CLY_LOG_I(@"%s, Showing content from URL: %@", __FUNCTION__, url);
CLY_LOG_I(@"%s, Placement frame: %@", __FUNCTION__, NSStringFromCGRect(frame));

CountlyWebViewManager* webViewManager = CountlyWebViewManager.new;
[webViewManager createWebViewWithURL:url frame:frame appearBlock:^
{
CLY_LOG_I(@"%s, Webview appeared", __FUNCTION__);
self->_isCurrentlyContentShown = YES;
[self clearContentState];
} dismissBlock:^
{
CLY_LOG_I(@"%s, Webview dismissed", __FUNCTION__);
self->_isCurrentlyContentShown = NO;
self->_minuteTimer = [NSTimer scheduledTimerWithTimeInterval:self->_zoneTimerInterval
target:self
selector:@selector(enterContentZone)
userInfo:nil
repeats:NO];
if(self.contentCallback) {
self.contentCallback(CLOSED, NSDictionary.new);
}
}];
});
}
#endif
@end
@end
66 changes: 59 additions & 7 deletions CountlyFeedbackWidget.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Please visit www.count.ly for more information.

#import "CountlyCommon.h"
#import "CountlyWebViewManager.h"
#if (TARGET_OS_IOS)
#import <WebKit/WebKit.h>
#endif
Expand All @@ -24,8 +25,13 @@ @interface CountlyFeedbackWidget ()
@property (nonatomic) CLYFeedbackWidgetType type;
@property (nonatomic) NSString* ID;
@property (nonatomic) NSString* name;
@property (nonatomic) NSString* widgetVersion;
@property (nonatomic) NSArray<NSString*>* tags;
@property (nonatomic) NSDictionary* data;
@property (nonatomic) WidgetCallback widgetCallback;
#if (TARGET_OS_IOS)
@property (nonatomic) CLYInternalViewController* webVC;
#endif
@end


Expand All @@ -39,6 +45,7 @@ + (CountlyFeedbackWidget *)createWithDictionary:(NSDictionary *)dictionary
feedback.type = dictionary[@"type"];
feedback.name = dictionary[@"name"];
feedback.tags = dictionary[@"tg"];
feedback.widgetVersion = dictionary[@"wv"];
return feedback;
}

Expand All @@ -52,25 +59,64 @@ - (void)present
- (void)presentWithAppearBlock:(void(^ __nullable)(void))appearBlock andDismissBlock:(void(^ __nullable)(void))dismissBlock
{
CLY_LOG_I(@"%s %@ %@", __FUNCTION__, appearBlock, dismissBlock);
[self presentWithCallback:^(WidgetState widgetState) {
id widgetCallback = ^(WidgetState widgetState) {
if(appearBlock && widgetState == WIDGET_APPEARED) {
appearBlock();
}

if(dismissBlock && widgetState == WIDGET_CLOSED) {
dismissBlock();
}
}];
};

[self presentWithCallback:widgetCallback];
}

- (void)presentWidget_new:(WidgetCallback) widgetCallback;
{
CLY_LOG_I(@"%s %@", __FUNCTION__, widgetCallback);
if (!CountlyConsentManager.sharedInstance.consentForFeedback)
return;

CGSize size = [CountlyCommon.sharedInstance getWindowSize];

dispatch_async(dispatch_get_main_queue(), ^ {
CGRect frame = CGRectMake(0.0, 0.0, size.width, size.height);

// Log the URL and the frame
CLY_LOG_I(@"%s, Placement frame: %@", __FUNCTION__, NSStringFromCGRect(frame));

CountlyWebViewManager* webViewManager = CountlyWebViewManager.new;
[webViewManager createWebViewWithURL:[self generateWidgetURL] frame:frame appearBlock:^
{
CLY_LOG_I(@"%s, Webview appeared", __FUNCTION__);
if(widgetCallback)
widgetCallback(WIDGET_APPEARED);
} dismissBlock:^
{
CLY_LOG_I(@"%s, Webview dismissed", __FUNCTION__);
if (widgetCallback)
widgetCallback(WIDGET_CLOSED);
[self recordReservedEventForDismissing];
}];
});
}

- (void)presentWithCallback:(WidgetCallback) widgetCallback;
{
CLY_LOG_I(@"%s %@", __FUNCTION__, widgetCallback);
if (!CountlyConsentManager.sharedInstance.consentForFeedback)
return;

if (self.widgetVersion && ![self.widgetVersion isKindOfClass:[NSNull class]]) {
[self presentWidget_new:widgetCallback];
return;
}

__block CLYInternalViewController* webVC = CLYInternalViewController.new;
webVC.view.backgroundColor = [UIColor.blackColor colorWithAlphaComponent:0.4];
webVC.modalPresentationStyle = UIModalPresentationCustom;

// Configure WKWebView with non-persistent data store
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
configuration.websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
Expand All @@ -79,11 +125,13 @@ - (void)presentWithCallback:(WidgetCallback) widgetCallback;
webView.layer.shadowOpacity = 0.5;
webView.layer.shadowOffset = CGSizeMake(0.0f, 5.0f);
webView.layer.masksToBounds = NO;

webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[webVC.view addSubview:webView];
webVC.webView = webView;
NSURLRequest* request = [self displayRequest];
NSURLRequest* request = [NSURLRequest requestWithURL:[self generateWidgetURL]];
[webView loadRequest:request];

CLYButton* dismissButton = [CLYButton dismissAlertButton];
dismissButton.onClick = ^(id sender)
{
Expand Down Expand Up @@ -193,7 +241,7 @@ - (NSURLRequest *)dataRequest
}
}

- (NSURLRequest *)displayRequest {
- (NSURL *)generateWidgetURL {
// Create the base URL with endpoint and feedback type
NSMutableString *URL = [NSMutableString stringWithFormat:@"%@%@/%@",
CountlyConnectionManager.sharedInstance.host,
Expand Down Expand Up @@ -227,7 +275,12 @@ - (NSURLRequest *)displayRequest {
[URL appendFormat:@"?%@", queryString];

// Create custom parameters
NSDictionary *customParams = @{@"tc": @"1"};
NSMutableDictionary *customParams = [@{@"tc": @"1"} mutableCopy];

if (self.widgetVersion && ![self.widgetVersion isKindOfClass:[NSNull class]]) {
customParams[@"rw"] = @"1";
customParams[@"xb"] = @"1";
}

// Create JSON data from custom parameters
NSError *error;
Expand All @@ -241,8 +294,7 @@ - (NSURLRequest *)displayRequest {
[URL appendFormat:@"&custom=%@", customString.cly_URLEscaped];
}

// Create and return the NSURLRequest
return [NSURLRequest requestWithURL:[NSURL URLWithString:URL]];
return [NSURL URLWithString:URL];
}


Expand Down
Loading
Loading