diff --git a/iOS/SonarKit/FlipperDiagnosticsViewController.h b/iOS/SonarKit/FlipperDiagnosticsViewController.h index 58854c43c..cc11595fe 100644 --- a/iOS/SonarKit/FlipperDiagnosticsViewController.h +++ b/iOS/SonarKit/FlipperDiagnosticsViewController.h @@ -10,9 +10,17 @@ #include "FlipperStateUpdateListener.h" #import +@interface StateTableDataSource : NSObject +@property (strong, nonatomic) NSArray *elements; +@end + @interface FlipperDiagnosticsViewController : UIViewController -@property(strong, nonatomic) UIScrollView *scrollView; +@property(strong, nonatomic) StateTableDataSource *tableDataSource; @property(strong, nonatomic) UILabel *stateLabel; +@property(strong, nonatomic) UITableView *stateTable; +@property(strong, nonatomic) UIScrollView *scrollView; +@property(strong, nonatomic) UILabel *logLabel; + - (void)onUpdate; @end diff --git a/iOS/SonarKit/FlipperDiagnosticsViewController.m b/iOS/SonarKit/FlipperDiagnosticsViewController.m index 0d0c3ff48..ae79c05ee 100644 --- a/iOS/SonarKit/FlipperDiagnosticsViewController.m +++ b/iOS/SonarKit/FlipperDiagnosticsViewController.m @@ -3,22 +3,54 @@ #import "FlipperDiagnosticsViewController.h" #import "SonarClient.h" +#define STATE_VIEW_HEIGHT 300 + +static NSString *const kSKCellIdentifier = @"FlipperDiagnosticStateTableStableCellIdentifier"; + +@implementation StateTableDataSource +- (instancetype)initWithElements:(NSArray *)elements { + self = [super init]; + if (self) { + _elements = elements; + } + return self; +} + +- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + NSInteger row = indexPath.row; + + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kSKCellIdentifier forIndexPath:indexPath]; + cell.textLabel.font = [UIFont fontWithName:@"Arial" size:10]; + cell.textLabel.text = [self.elements[row][@"state"] stringByAppendingString:self.elements[row][@"name"]]; + return cell; +} + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return [self.elements count]; +} + +@end + @implementation FlipperDiagnosticsViewController - (void)viewDidLoad { [super viewDidLoad]; - UILabel *text = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)]; - text.text = @"Flipper Diagnostics"; - [self.view addSubview:text]; + self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, STATE_VIEW_HEIGHT, self.view.frame.size.width, self.view.frame.size.height - 100 - STATE_VIEW_HEIGHT)]; + self.logLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.scrollView.frame.size.height)]; + self.logLabel.numberOfLines = 0; + self.logLabel.font = [UIFont fontWithName:@"Arial" size:10]; + [self.scrollView addSubview:self.logLabel]; - self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 50, self.view.frame.size.width, self.view.frame.size.height - 100)]; - self.stateLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 1000)]; + self.stateTable = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, STATE_VIEW_HEIGHT)]; + [self.stateTable registerClass:[UITableViewCell class] forCellReuseIdentifier:kSKCellIdentifier]; + self.stateTable.rowHeight = 14; + self.tableDataSource = [[StateTableDataSource alloc] initWithElements:[[SonarClient sharedClient] getStateElements]]; + self.stateTable.dataSource = self.tableDataSource; - self.stateLabel.numberOfLines = 0; - self.stateLabel.text = [[SonarClient sharedClient] getState]; - [self.scrollView addSubview:self.stateLabel]; - self.scrollView.contentSize = self.stateLabel.frame.size; + [self updateLogView]; + + [self.view addSubview:self.stateTable]; [self.view addSubview:self.scrollView]; self.view.backgroundColor = [UIColor whiteColor]; } @@ -26,17 +58,27 @@ - (void)onUpdate { FlipperDiagnosticsViewController __weak *weakSelf = self; dispatch_async(dispatch_get_main_queue(), ^{ - FlipperDiagnosticsViewController *strongSelf = weakSelf; - if (!strongSelf) { - return; - } - NSString *state = [[SonarClient sharedClient] getState]; - strongSelf.stateLabel.text = state; - [strongSelf.stateLabel sizeToFit]; - strongSelf.scrollView.contentSize = strongSelf.stateLabel.frame.size; + [weakSelf updateStateTable]; + [weakSelf updateLogView]; }); } +- (void)updateStateTable { + self.tableDataSource.elements = [[SonarClient sharedClient] getStateElements]; + [self.stateTable reloadData]; +} + +- (void)updateLogView { + NSString *state = [[SonarClient sharedClient] getState]; + self.logLabel.text = state; + [self.logLabel sizeToFit]; + self.scrollView.contentSize = self.logLabel.frame.size; + + // Scroll to bottom + CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height); + [self.scrollView setContentOffset:bottomOffset animated:YES]; +} + - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; id weakSelf = self; diff --git a/iOS/SonarKit/SonarClient.h b/iOS/SonarKit/SonarClient.h index d44da890b..790359595 100644 --- a/iOS/SonarKit/SonarClient.h +++ b/iOS/SonarKit/SonarClient.h @@ -5,8 +5,9 @@ * file in the root directory of this source tree. * */ -#import +#ifdef FB_SONARKIT_ENABLED +#import #import "SonarPlugin.h" #import "FlipperStateUpdateListener.h" @@ -47,10 +48,15 @@ Stop the connection to the Sonar desktop. - (void)stop; /** -Get the current state of the sonar client +Get the log of state changes from the sonar client */ - (NSString *)getState; +/** + Get the current summarized state of the sonar client + */ +- (NSArray *)getStateElements; + /** Subscribe a ViewController to state update change notifications */ @@ -61,3 +67,5 @@ Subscribe a ViewController to state update change notifications + (instancetype)new NS_UNAVAILABLE; @end + +#endif diff --git a/iOS/SonarKit/SonarClient.mm b/iOS/SonarKit/SonarClient.mm index e5bf17e6f..8ff766cce 100644 --- a/iOS/SonarKit/SonarClient.mm +++ b/iOS/SonarKit/SonarClient.mm @@ -127,6 +127,37 @@ using WrapperPlugin = facebook::sonar::SonarCppWrapperPlugin; return @(_cppClient->getState().c_str()); } +- (NSArray *)getStateElements { + NSMutableArray*> *const array = [NSMutableArray array]; + + for (facebook::sonar::StateElement element: _cppClient->getStateElements()) { + facebook::sonar::State state = element.state_; + NSString *stateString; + switch (state) { + case facebook::sonar::in_progress: + stateString = @"⏳ "; + break; + + case facebook::sonar::success: + stateString = @"✅ "; + break; + + case facebook::sonar::failed: + stateString = @"❌ "; + break; + + default: + stateString = @"❓ "; + break; + } + [array addObject:@{ + @"name": [NSString stringWithUTF8String:element.name_.c_str()], + @"state": stateString + }]; + } + return array; +} + - (void)subscribeForUpdates:(id)controller { auto stateListener = std::make_shared(controller); _cppClient->setStateListener(stateListener);