| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- // Copyright 2020 Google LLC
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #import "PerfTraceView.h"
- #import "PerfTraceView+Accessibility.h"
- @interface PerfTraceView ()
- // Views in the view hierarchy.
- /** A label for the trace name. */
- @property(nonatomic) UILabel *nameLabel;
- /** A button that will stop the currently running trace. */
- @property(nonatomic) UIButton *stopTraceButton;
- /** A button to start a new stage on the currently running trace. */
- @property(nonatomic) UIButton *stageButton;
- /** A button to increment a metric on the currently running trace. */
- @property(nonatomic) UIButton *metricOneButton;
- /** A button to increment a second metric on the currently running trace. */
- @property(nonatomic) UIButton *metricTwoButton;
- /** A button to add a custom attribute to the currrently running trace. */
- @property(nonatomic) UIButton *customAttributeButton;
- /** A label for the current stage state. */
- @property(nonatomic) UILabel *recentStageLabel;
- // State preserving properties.
- /** The current trace. */
- @property(nonatomic, readwrite, copy) FIRTrace *trace;
- /** The current stage number. */
- @property(nonatomic, assign) NSInteger stageNumber;
- /** The current value of metric one. */
- @property(nonatomic, assign) NSInteger metricOneValue;
- /** The current value of metric two. */
- @property(nonatomic, assign) NSInteger metricTwoValue;
- /** The current custom attribute counter used for their names. */
- @property(nonatomic, assign) NSInteger customAttributeCounter;
- /** The current custom attribute value to be added to the trade. */
- @property(nonatomic) NSString *customAttributeValue;
- /** The timestamp of when the trace started for UI labeling purposes. */
- @property(nonatomic) NSDate *traceDate;
- // Helper properties.
- @property(nonatomic) NSLayoutConstraint *bottomConstraint;
- /**
- * Picks a custom attribute value from a constant list of values and sets the property.
- * It also auto increments the custom attribute name and updates the button's title.
- */
- - (void)chooseCustomAttribute;
- @end
- @implementation PerfTraceView
- #pragma mark - Initialization
- - (instancetype)initWithFrame:(CGRect)frame {
- NSAssert(NO, @"Not a valid initializer.");
- return nil;
- }
- - (instancetype)initWithCoder:(NSCoder *)coder {
- NSAssert(NO, @"Not a valid initializer.");
- return nil;
- }
- - (instancetype)initWithTrace:(FIRTrace *)trace frame:(CGRect)frame {
- self = [super initWithFrame:frame];
- if (self) {
- _trace = trace;
- _traceDate = [NSDate date];
- }
- return self;
- }
- - (void)updateConstraints {
- [super updateConstraints];
- if (self.constraints.count == 0) {
- [self constrainViews];
- }
- }
- - (void)didMoveToSuperview {
- [super didMoveToSuperview];
- if (self.superview != nil && self.subviews.count == 0) {
- [self createViewTree];
- [_metricOneButton setTitle:@"metric1 - 0" forState:UIControlStateNormal];
- [_metricTwoButton setTitle:@"metric2 - 0" forState:UIControlStateNormal];
- _nameLabel.text = _trace.name;
- [self chooseCustomAttribute];
- }
- }
- #pragma mark - Control methods
- - (void)stopTrace:(UIButton *)button {
- self.nameLabel.text = [NSString stringWithFormat:@"%@ - %0.2fs", self.trace.name,
- (-1 * [self.traceDate timeIntervalSinceNow])];
- [self.delegate perfTraceViewTraceStopped:self];
- self.trace = nil;
- [self disableActions];
- }
- /** @brief: Disables all the actionable elements on the view. */
- - (void)disableActions {
- self.stopTraceButton.enabled = NO;
- self.metricOneButton.enabled = NO;
- self.metricTwoButton.enabled = NO;
- self.stageButton.enabled = NO;
- }
- /**
- * Creates new Stage in the trace and adds it to the visual list of stages created.
- *
- * @param button Button that initiated the request.
- */
- - (void)createStage:(UIButton *)button {
- NSString *stageName = [NSString stringWithFormat:@"Stage%zd", self.stageNumber];
- NSString *stageNameLabelText = [NSString
- stringWithFormat:@"%@ - %0.2fs", stageName, (-1 * [self.traceDate timeIntervalSinceNow])];
- UILabel *currentLabel = self.recentStageLabel;
- self.recentStageLabel = [self newStageLabel];
- self.recentStageLabel.text = stageNameLabelText;
- [self addSubview:self.recentStageLabel];
- // Stage feature is currently disabled.
- // [self.trace startStageNamed:stageName];
- if (currentLabel) {
- [NSLayoutConstraint activateConstraints:@[
- [self.recentStageLabel.topAnchor constraintEqualToAnchor:currentLabel.bottomAnchor
- constant:10.0f],
- [self.recentStageLabel.leftAnchor constraintEqualToAnchor:currentLabel.leftAnchor],
- ]];
- } else {
- [NSLayoutConstraint activateConstraints:@[
- [self.recentStageLabel.topAnchor
- constraintEqualToAnchor:self.customAttributeButton.bottomAnchor
- constant:10.0f],
- [self.recentStageLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
- ]];
- }
- if (self.bottomConstraint) {
- [self removeConstraint:self.bottomConstraint];
- }
- self.bottomConstraint =
- [self.bottomAnchor constraintGreaterThanOrEqualToAnchor:self.recentStageLabel.bottomAnchor
- constant:5.0f];
- [self addConstraint:self.bottomConstraint];
- self.stageNumber++;
- }
- /**
- * Action for incrementing metric one.
- *
- * @param button The button object where the action took place.
- */
- - (void)incrementMetricOne:(UIButton *)button {
- self.metricOneValue++;
- [self.trace incrementMetric:@"metric1" byInt:1];
- NSString *stringValue = [NSString stringWithFormat:@"metric1 - %zd", self.metricOneValue];
- [self.metricOneButton setTitle:stringValue forState:UIControlStateNormal];
- }
- /**
- * Action for incrementing metric two.
- *
- * @param button The button object where the action took place.
- */
- - (void)incrementMetricTwo:(UIButton *)button {
- self.metricTwoValue++;
- [self.trace incrementMetric:@"metric2" byInt:1];
- NSString *stringValue = [NSString stringWithFormat:@"metric2 - %zd", self.metricTwoValue];
- [self.metricTwoButton setTitle:stringValue forState:UIControlStateNormal];
- }
- /**
- * Action for adding a custom attribute onto the trace.
- *
- * @param button The button object where the action took place.
- */
- - (void)addCustomAttribute:(UIButton *)button {
- NSString *attrName = [NSString stringWithFormat:@"attr%d", (int)_customAttributeCounter];
- [self.trace setValue:_customAttributeValue forAttribute:attrName];
- ++_customAttributeCounter;
- [self chooseCustomAttribute];
- }
- #pragma mark - View hierarchy
- /** @brief Creates the view hierarchy for the PerfTraceView. */
- - (void)createViewTree {
- [self addSubview:self.nameLabel];
- [self addSubview:self.stopTraceButton];
- [self addSubview:self.stageButton];
- [self addSubview:self.metricOneButton];
- [self addSubview:self.metricTwoButton];
- [self addSubview:self.customAttributeButton];
- }
- /** @brief Constrains for the views inside PerfTraceView. */
- - (void)constrainViews {
- [NSLayoutConstraint activateConstraints:@[
- [self.nameLabel.topAnchor constraintEqualToAnchor:self.topAnchor constant:5.0f],
- [self.nameLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
- // Position adding a stage button and stop trace button.
- [self.stopTraceButton.topAnchor constraintEqualToAnchor:self.nameLabel.bottomAnchor
- constant:10.0f],
- [self.stageButton.centerYAnchor constraintEqualToAnchor:self.stopTraceButton.centerYAnchor],
- [self.stopTraceButton.widthAnchor constraintEqualToAnchor:self.stageButton.widthAnchor],
- [self.stageButton.leftAnchor constraintEqualToAnchor:self.stopTraceButton.rightAnchor
- constant:50.0f],
- [self.stopTraceButton.rightAnchor constraintEqualToAnchor:self.centerXAnchor constant:-25.0f],
- // Position metric button below stage button.
- [self.metricOneButton.topAnchor constraintEqualToAnchor:self.stageButton.bottomAnchor
- constant:5.0f],
- [self.metricTwoButton.centerYAnchor constraintEqualToAnchor:self.metricOneButton.centerYAnchor],
- [self.metricOneButton.widthAnchor constraintEqualToAnchor:self.metricTwoButton.widthAnchor],
- [self.metricTwoButton.leftAnchor constraintEqualToAnchor:self.metricOneButton.rightAnchor
- constant:50.0f],
- [self.metricOneButton.rightAnchor constraintEqualToAnchor:self.centerXAnchor constant:-25.0f],
- // Position Custom Attribute button below metric buttons.
- [self.customAttributeButton.topAnchor constraintEqualToAnchor:self.metricOneButton.bottomAnchor
- constant:5.0f],
- [self.customAttributeButton.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
- // Bottom constraint is required to determine height.
- [self.bottomAnchor constraintGreaterThanOrEqualToAnchor:self.customAttributeButton.bottomAnchor
- constant:10.0f],
- ]];
- }
- #pragma mark - Lazy creation of views.
- - (UILabel *)nameLabel {
- if (!_nameLabel) {
- _nameLabel = [[UILabel alloc] init];
- _nameLabel.translatesAutoresizingMaskIntoConstraints = NO;
- }
- return _nameLabel;
- }
- - (UILabel *)newStageLabel {
- UILabel *label = [[UILabel alloc] init];
- label.translatesAutoresizingMaskIntoConstraints = NO;
- return label;
- }
- - (UIButton *)stopTraceButton {
- if (!_stopTraceButton) {
- _stopTraceButton = [self newButton];
- AccessibilityItem *item = [[self class] stopAccessibilityItemWithTraceName:self.trace.name];
- _stopTraceButton.accessibilityLabel = item.accessibilityLabel;
- _stopTraceButton.accessibilityIdentifier = item.accessibilityID;
- [_stopTraceButton setTitle:@"Stop trace" forState:UIControlStateNormal];
- [_stopTraceButton addTarget:self
- action:@selector(stopTrace:)
- forControlEvents:UIControlEventTouchUpInside];
- }
- return _stopTraceButton;
- }
- - (UIButton *)stageButton {
- if (!_stageButton) {
- _stageButton = [self newButton];
- AccessibilityItem *item = [[self class] stageAccessibilityItemWithTraceName:self.trace.name];
- _stageButton.accessibilityLabel = item.accessibilityLabel;
- _stageButton.accessibilityIdentifier = item.accessibilityID;
- [_stageButton setTitle:@"Stage" forState:UIControlStateNormal];
- [_stageButton addTarget:self
- action:@selector(createStage:)
- forControlEvents:UIControlEventTouchUpInside];
- }
- return _stageButton;
- }
- - (UIButton *)metricOneButton {
- if (!_metricOneButton) {
- _metricOneButton = [self newButton];
- AccessibilityItem *item =
- [[self class] metricOneAccessibilityItemWithTraceName:self.trace.name];
- _metricOneButton.accessibilityLabel = item.accessibilityLabel;
- _metricOneButton.accessibilityIdentifier = item.accessibilityID;
- [_metricOneButton setTitle:@"Metric 1" forState:UIControlStateNormal];
- [_metricOneButton addTarget:self
- action:@selector(incrementMetricOne:)
- forControlEvents:UIControlEventTouchUpInside];
- }
- return _metricOneButton;
- }
- - (UIButton *)metricTwoButton {
- if (!_metricTwoButton) {
- _metricTwoButton = [self newButton];
- AccessibilityItem *item =
- [[self class] metricTwoAccessibilityItemWithTraceName:self.trace.name];
- _metricTwoButton.accessibilityLabel = item.accessibilityLabel;
- _metricTwoButton.accessibilityIdentifier = item.accessibilityID;
- [_metricTwoButton setTitle:@"Metric 2" forState:UIControlStateNormal];
- [_metricTwoButton addTarget:self
- action:@selector(incrementMetricTwo:)
- forControlEvents:UIControlEventTouchUpInside];
- }
- return _metricTwoButton;
- }
- - (UIButton *)customAttributeButton {
- if (!_customAttributeButton) {
- _customAttributeButton = [self newButton];
- AccessibilityItem *item =
- [[self class] customAttributeAccessibilityItemWithTraceName:self.trace.name];
- _customAttributeButton.accessibilityLabel = item.accessibilityLabel;
- _customAttributeButton.accessibilityIdentifier = item.accessibilityID;
- [_customAttributeButton addTarget:self
- action:@selector(addCustomAttribute:)
- forControlEvents:UIControlEventTouchUpInside];
- }
- return _customAttributeButton;
- }
- #pragma mark - View utility functions
- /**
- * Creates a new button with default UI properties.
- *
- * @return button The button that was created.
- */
- - (UIButton *)newButton {
- UIButton *button = [[UIButton alloc] init];
- button.translatesAutoresizingMaskIntoConstraints = NO;
- [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
- [button setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled];
- button.titleLabel.font = [UIFont systemFontOfSize:12.0];
- button.contentEdgeInsets = UIEdgeInsetsMake(10.0f, 20.0f, 10.0f, 20.0f);
- button.layer.cornerRadius = 3.0f;
- button.layer.borderColor = [[UIColor blackColor] CGColor];
- button.layer.borderWidth = 1.0f;
- return button;
- }
- - (void)chooseCustomAttribute {
- NSArray<NSString *> *const values = @[
- @"apple", @"pear", @"plum", @"orange", @"purple", @"red", @"blue", @"1", @"2", @"3", @"4", @"5",
- @"6", @"7", @"8", @"9", @"0"
- ];
- _customAttributeValue = values[arc4random_uniform((uint32_t)values.count)];
- NSString *buttonTitle;
- buttonTitle = [NSString stringWithFormat:@"Add Attribute: attr%d with Value: %@",
- (int)_customAttributeCounter, _customAttributeValue];
- [_customAttributeButton setTitle:buttonTitle forState:UIControlStateNormal];
- }
- @end
|