Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jwoo/ios render sync #1547

Merged
merged 6 commits into from Jun 7, 2018
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -7,6 +7,8 @@
objects = {

/* Begin PBXBuildFile section */
6B7B1A9B20C21CA900260731 /* SportingEvent.json in Resources */ = {isa = PBXBuildFile; fileRef = 6B7B1A9920C21CA800260731 /* SportingEvent.json */; };
6B7B1A9C20C21CA900260731 /* NotificationCard.json in Resources */ = {isa = PBXBuildFile; fileRef = 6B7B1A9A20C21CA900260731 /* NotificationCard.json */; };
6BF339D620A665E600DA5973 /* CustomTextBlockRenderer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6BF339D420A665E600DA5973 /* CustomTextBlockRenderer.mm */; };
6BF339E320A66A3F00DA5973 /* AdaptiveCards.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6BF339E220A66A3F00DA5973 /* AdaptiveCards.framework */; };
6BF339E420A66A4D00DA5973 /* AdaptiveCards.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6BF339E220A66A3F00DA5973 /* AdaptiveCards.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
Expand Down Expand Up @@ -111,6 +113,8 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
6B7B1A9920C21CA800260731 /* SportingEvent.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = SportingEvent.json; path = ../../../../samples/v1.0/Scenarios/SportingEvent.json; sourceTree = "<group>"; };
6B7B1A9A20C21CA900260731 /* NotificationCard.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = NotificationCard.json; path = ../../../../samples/v1.0/Scenarios/NotificationCard.json; sourceTree = "<group>"; };
6BF339D420A665E600DA5973 /* CustomTextBlockRenderer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CustomTextBlockRenderer.mm; sourceTree = "<group>"; };
6BF339D520A665E600DA5973 /* CustomTextBlockRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomTextBlockRenderer.h; sourceTree = "<group>"; };
6BF339E220A66A3F00DA5973 /* AdaptiveCards.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AdaptiveCards.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -309,6 +313,8 @@
F4D33E341F045B6E00941E44 /* Jsons */ = {
isa = PBXGroup;
children = (
6B7B1A9A20C21CA900260731 /* NotificationCard.json */,
6B7B1A9920C21CA800260731 /* SportingEvent.json */,
F4F44BA6204CF97100A2F24C /* CustomParsingTestUsingProgressBar.json */,
F4F44B842048CDB300A2F24C /* AdditionalProperty.json */,
F4F44B8220478E1100A2F24C /* DateTimeTestTranslation.json */,
Expand Down Expand Up @@ -481,10 +487,12 @@
F4933CC51F79852C00F6EBFD /* Action.Submit.json in Resources */,
F4933CED1F79852C00F6EBFD /* TextBlock.Weight.json in Resources */,
F4933D061F79853B00F6EBFD /* StockUpdate.json in Resources */,
6B7B1A9C20C21CA900260731 /* NotificationCard.json in Resources */,
F4933D081F79853B00F6EBFD /* WeatherLarge.json in Resources */,
F4933CCD1F79852C00F6EBFD /* ColumnSet.Spacing.json in Resources */,
F4933CC21F79852C00F6EBFD /* Action.OpenUrl.json in Resources */,
F4933CFE1F79853B00F6EBFD /* FlightItinerary.json in Resources */,
6B7B1A9B20C21CA900260731 /* SportingEvent.json in Resources */,
F4933CC81F79852C00F6EBFD /* Column.Style.json in Resources */,
F4F44B8320478E1100A2F24C /* DateTimeTestTranslation.json in Resources */,
F4933CE81F79852C00F6EBFD /* TextBlock.Markdown.json in Resources */,
Expand Down
Expand Up @@ -86,20 +86,12 @@ - (UIView *)render:(UIView<ACRIContentHoldingView> *)viewGroup
lab.numberOfLines = 1;
}

ACRContentHoldingUIView *wrappingview = [[ACRContentHoldingUIView alloc] init];

[wrappingview addSubview:lab];

[wrappingview setAlignmentForSubview:textBlockElement->GetHorizontalAlignment()];

[viewGroup addArrangedSubview:wrappingview];

wrappingview.translatesAutoresizingMaskIntoConstraints = false;
[viewGroup addArrangedSubview:lab];

wrappingview.backgroundColor = UIColor.lightGrayColor;
lab.backgroundColor = UIColor.lightGrayColor;

lab.translatesAutoresizingMaskIntoConstraints = false;

return wrappingview;
return lab;
}
@end
Expand Up @@ -218,16 +218,16 @@ - (void)update:(NSString *) jsonStr
[self.curView removeFromSuperview];

self.curView = ad;
if(_enableCustomRenderer){
[_scrView addSubview:self.curView];
UIView *view = self.curView;
view.translatesAutoresizingMaskIntoConstraints = NO;

[_scrView addSubview:self.curView];
UIView *view = self.curView;
view.translatesAutoresizingMaskIntoConstraints = NO;

[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:_scrView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0].active = YES;
[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:_scrView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0].active = YES;
[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:_scrView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0].active = YES;
[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:_scrView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0].active = YES;
}
[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:_scrView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0].active = YES;
[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:_scrView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0].active = YES;
[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:_scrView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0].active = YES;
[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:_scrView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0].active = YES;

}
}

Expand Down Expand Up @@ -291,18 +291,6 @@ - (void)didFetchHttpRequest:(NSURLRequest *)request
NSLog(@"Http Request fetched: %@", request);
}

- (void)didLoadElements
{
[_scrView addSubview:self.curView];
UIView *view = self.curView;
view.translatesAutoresizingMaskIntoConstraints = NO;

[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:_scrView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0].active = YES;
[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:_scrView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0].active = YES;
[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:_scrView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0].active = YES;
[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:_scrView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0].active = YES;
}

- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
Expand Down
Expand Up @@ -27,7 +27,7 @@ + (UIButton* )rootView:(ACRView *)rootView
CGSize contentSize = [button.titleLabel intrinsicContentSize];
[button setFrame:CGRectMake(0, 0, contentSize.width, contentSize.height)];
[button setContentEdgeInsets:UIEdgeInsetsMake(5,5,5,5)];

std::shared_ptr<AdaptiveCards::BaseActionElement> action = [acoAction element];
if([iconUrl length] != 0)
{
Expand All @@ -47,18 +47,18 @@ + (UIButton* )rootView:(ACRView *)rootView
actionsViewMap[key] = button;
}
});

if(imgView)
Copy link

@bviglietta bviglietta Jun 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imgView [](start = 11, length = 7)

If you change the dispatch to async, there's no guarantee that imgView will be set by the time you get here. #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're correct. i may have forgotten to push my latest commit.


In reply to: 193240758 [](ancestors = 193240758)

{
{
[ACRView setImageView:imgView inButton:button withConfig:config];

// remove postfix added for imageMap access
std::string id = action->GetId();
std::size_t idx = id.find_last_of('_');
action->SetId(id.substr(0, idx));
}
}

return button;
}
@end
Expand Up @@ -39,22 +39,19 @@ + (ACRUILabel *)buildLabel:(NSString *)text
lab.isFactSetLabel = YES;
lab.translatesAutoresizingMaskIntoConstraints = NO;
lab.style = style;
__block NSMutableAttributedString *content = nil;
NSMutableAttributedString *content = nil;
if(rootView){
std::shared_ptr<FactSet> fctSet = std::dynamic_pointer_cast<FactSet>(element);
NSMutableDictionary *textMap = [rootView getTextMap];
// Syncronize access to imageViewMap
dispatch_sync([rootView getSerialTextQueue], ^{
if(textMap[elementId]) { // if content is available, get it, otherwise cache label, so it can be used used later
content = textMap[elementId];
} else {
textMap[elementId] = lab;
}
});
}

if(content){
NSDictionary* data = textMap[elementId];
Copy link

@bviglietta bviglietta Jun 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

textMap[elementId] [](start = 29, length = 18)

I'm a little confused about the synchronization. Elsewhere it looks like access to this textMap is serialized on ACRView's _serial_text_queue, but here we're accessing it from a different thread without any synchronization. #Resolved

Copy link
Member Author

@jwoo-msft jwoo-msft Jun 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, the reason is that once asyncronous tasks are completed, remaining works are done in serial since the works are UI related and have to be run on main thread.


In reply to: 193501004 [](ancestors = 193501004)

NSData *htmlData = data[@"html"];
NSDictionary *options = data[@"options"];

std::shared_ptr<HostConfig> config = [acoConfig getHostConfig];
// Initializing NSMutableAttributedString for HTML rendering is very slow
content = [[NSMutableAttributedString alloc] initWithData:htmlData options:options documentAttributes:nil error:nil];
// Drop newline char
[content deleteCharactersInRange:NSMakeRange([content length] -1, 1)];
// Set paragraph style such as line break mode and alignment
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineBreakMode = textConfig.wrap ? NSLineBreakByWordWrapping:NSLineBreakByTruncatingTail;
Expand All @@ -70,7 +67,6 @@ + (ACRUILabel *)buildLabel:(NSString *)text
NSStrokeWidthAttributeName:[ACOHostConfig getTextStrokeWidthForWeight:textConfig.weight]}
range:NSMakeRange(0, content.length)];
lab.attributedText = content;

std::string ID = element->GetId();
std::size_t idx = ID.find_last_of('_');
if(std::string::npos != idx){
Expand Down
Expand Up @@ -58,51 +58,37 @@ - (UIView *)render:(UIView<ACRIContentHoldingView> *)viewGroup
constant:cgsize.height]]];
}
NSMutableDictionary *imageViewMap = [rootView getImageMap];
__block UIImage *img = nil;
// Generate key for ImageViewMap
NSString *key = [NSString stringWithCString:imgElem->GetId().c_str() encoding:[NSString defaultCStringEncoding]];
UIImage *img = nil;
// Syncronize access to imageViewMap
dispatch_sync([rootView getSerialQueue], ^{
// if image is available, get it, otherwise cache UIImageView, so it can be used once images are ready
if(imageViewMap[key] && [imageViewMap[key] isKindOfClass:[UIImage class]]) {
img = imageViewMap[key];
}
else {
imageViewMap[key] = view;
}
});
NSNumber *number = [NSNumber numberWithUnsignedLongLong:(unsigned long long)imgElem.get()];
NSString *key = [number stringValue];
img = imageViewMap[key];
view.image = img;
if(img && (img.size.width > 0) && (imgElem->GetImageSize() == ImageSize::Auto || imgElem->GetImageSize() == ImageSize::Stretch || imgElem->GetImageSize() == ImageSize::None)){
CGFloat heightToWidthRatio = img.size.height / img.size.width;
[view addConstraints:@[[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:view
attribute:NSLayoutAttributeWidth
multiplier:heightToWidthRatio
constant:0]]];
CGFloat widthToHeightRatio = img.size.width/ img.size.height;
[view addConstraints:@[[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:view
attribute:NSLayoutAttributeHeight
multiplier:widthToHeightRatio
constant:0]]];
}

if(img) {// if image is ready, proceed to add it
view.image = img;
if(imgElem->GetImageSize() == ImageSize::Auto || imgElem->GetImageSize() == ImageSize::Stretch || imgElem->GetImageSize() == ImageSize::None){
CGFloat heightToWidthRatio = img.size.height / img.size.width;
[view addConstraints:@[[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:view
attribute:NSLayoutAttributeWidth
multiplier:heightToWidthRatio
constant:0]]];
CGFloat widthToHeightRatio = img.size.width/ img.size.height;
[view addConstraints:@[[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:view
attribute:NSLayoutAttributeHeight
multiplier:widthToHeightRatio
constant:0]]];
}
view.contentMode = UIViewContentModeScaleAspectFit;
view.clipsToBounds = NO;
if(imgElem->GetImageStyle() == ImageStyle::Person) {
CALayer *imgLayer = view.layer;
[imgLayer setCornerRadius:cgsize.width/2];
[imgLayer setMasksToBounds:YES];
}
// remove postfix added for imageMap access
std::string id = imgElem->GetId();
std::size_t idx = id.find_last_of('_');
imgElem->SetId(id.substr(0, idx));
view.contentMode = UIViewContentModeScaleAspectFit;
view.clipsToBounds = NO;
if(imgElem->GetImageStyle() == ImageStyle::Person) {
CALayer *imgLayer = view.layer;
[imgLayer setCornerRadius:cgsize.width/2];
[imgLayer setMasksToBounds:YES];
}

ACRContentHoldingUIView *wrappingview = [[ACRContentHoldingUIView alloc] initWithFrame:view.frame];
Expand Down
Expand Up @@ -63,31 +63,29 @@ + (UIView *)renderWithAdaptiveCards:(std::shared_ptr<AdaptiveCard> const &)adapt
{
std::vector<std::shared_ptr<BaseCardElement>> body = adaptiveCard->GetBody();
ACRColumnView *verticalView = containingView;

if(!body.empty()) {
[rootView addTasksToConcurrentQueue:body];
// addTasksToConcurrentQueue spawns concurrent tasks, this flag indicates that
// all tasks have been added to work queues, and is needed for complete notification to work properly
rootView.seenAllElements = YES;

if(!body.empty()) {
ACRContainerStyle style = ([config getHostConfig]->adaptiveCard.allowCustomStyle)? (ACRContainerStyle)adaptiveCard->GetStyle() : ACRDefault;
style = (style == ACRNone)? ACRDefault : style;
[verticalView setStyle:style];

[rootView addTasksToConcurrentQueue:body];

[rootView waitForAsyncTasksToFinish];

[ACRRenderer render:verticalView rootView:rootView inputs:inputs withCardElems:body andHostConfig:config];

[[rootView card] setInputs:inputs];
[[rootView card] setInputs:inputs];

std::vector<std::shared_ptr<BaseActionElement>> actions = adaptiveCard->GetActions();
if(!actions.empty()) {
[rootView addActionsToConcurrentQueue:actions];
[ACRSeparator renderActionsSeparator:verticalView hostConfig:[config getHostConfig]];
// renders buttons and their associated actions
[ACRRenderer renderButton:rootView inputs:inputs superview:verticalView actionElems:actions hostConfig:config];
}
[verticalView adjustHuggingForLastElement];
}

return verticalView;
}

Expand Down