mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-09 22:36:01 +05:45
402 lines
14 KiB
Objective-C
402 lines
14 KiB
Objective-C
// 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 currently 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
|