Skip to content

Commit

Permalink
Improve UI
Browse files Browse the repository at this point in the history
Do screen updates on the next frame, animate resizing in sync with keyboard, remove status bar, transparent background for the terminal
  • Loading branch information
tbodt committed Nov 9, 2017
1 parent 42cacc1 commit 5477fdc
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 16 deletions.
2 changes: 1 addition & 1 deletion app/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<gestureRecognizers/>
<constraints>
<constraint firstAttribute="trailing" secondItem="FQi-r8-odu" secondAttribute="trailing" id="EeQ-tO-BY6"/>
Expand Down
15 changes: 15 additions & 0 deletions app/DelayedUITask.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// DelayedUITask.h
// iSH
//
// Created by Theodore Dubois on 11/8/17.
//

#import <Foundation/Foundation.h>

@interface DelayedUITask : NSObject

- (instancetype)initWithTarget:(id)target action:(SEL)action;
- (void)schedule;

@end
35 changes: 35 additions & 0 deletions app/DelayedUITask.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// DelayedUITask.m
// iSH
//
// Created by Theodore Dubois on 11/8/17.
//

#import "DelayedUITask.h"

@interface DelayedUITask ()

@property id target;
@property SEL action;
@property NSTimer *timer;

@end

@implementation DelayedUITask

- (instancetype)initWithTarget:(id)target action:(SEL)action {
if (self = [super init]) {
self.target = target;
self.action = action;
}
return self;
}

- (void)schedule {
if (!self.timer.valid) {
self.timer = [NSTimer timerWithTimeInterval:1.0/60 target:self.target selector:self.action userInfo:nil repeats:NO];
[NSRunLoop.mainRunLoop addTimer:self.timer forMode:NSDefaultRunLoopMode];
}
}

@end
2 changes: 2 additions & 0 deletions app/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
<array>
<string>armv7</string>
</array>
<key>UIStatusBarHidden</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
Expand Down
31 changes: 21 additions & 10 deletions app/Terminal.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

#import "Terminal.h"
#import "DelayedUITask.h"
#include "fs/tty.h"

@interface Terminal () <WKScriptMessageHandler>
Expand All @@ -14,6 +15,9 @@ @interface Terminal () <WKScriptMessageHandler>
@property struct tty *tty;
@property NSMutableData *pendingData;

@property DelayedUITask *refreshTask;
@property DelayedUITask *scrollToBottomTask;

@end

@implementation Terminal
Expand All @@ -25,6 +29,9 @@ - (instancetype)init {
return terminal;
if (self = [super init]) {
self.pendingData = [NSMutableData new];
self.refreshTask = [[DelayedUITask alloc] initWithTarget:self action:@selector(refresh)];
self.scrollToBottomTask = [[DelayedUITask alloc] initWithTarget:self action:@selector(scrollToBottom)];

WKWebViewConfiguration *config = [WKWebViewConfiguration new];
[config.userContentController addScriptMessageHandler:self name:@"log"];
self.webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:config];
Expand All @@ -45,36 +52,40 @@ - (void)userContentController:(WKUserContentController *)userContentController d
- (size_t)write:(const void *)buf length:(size_t)len {
@synchronized (self) {
[self.pendingData appendData:[NSData dataWithBytes:buf length:len]];
[self performSelectorOnMainThread:@selector(sendPendingOutput) withObject:nil waitUntilDone:NO];
[self.refreshTask schedule];
}
return len;
}

- (void)sendInput:(const char *)buf length:(size_t)len {
tty_input(self.tty, buf, len);
[self.scrollToBottomTask schedule];
}

- (void)scrollToBottom {
[self.webView evaluateJavaScript:@"term.scrollToBottom()" completionHandler:nil];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if (object == self.webView && [keyPath isEqualToString:@"loading"] && !self.webView.loading) {
[self sendPendingOutput];
[self.refreshTask schedule];
[self.webView removeObserver:self forKeyPath:@"loading"];
}
}

- (void)sendPendingOutput {
- (void)refresh {
if (self.webView.loading)
return;

NSString *str;
@synchronized (self) {
if (self.webView.loading)
return;
if (self.pendingData.length == 0)
return;
str = [[NSString alloc] initWithData:self.pendingData encoding:NSUTF8StringEncoding];
self.pendingData = [NSMutableData new];
}
NSError *err;

NSError *err = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:@[str] options:0 error:&err];
if (err != nil)
NSLog(@"%@", err);
NSAssert(err == nil, @"JSON serialization failed, wtf");
NSString *jsToEvaluate = [NSString stringWithFormat:@"term.write(%@[0])", [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]];
[self.webView evaluateJavaScript:jsToEvaluate completionHandler:nil];
}
Expand Down
2 changes: 2 additions & 0 deletions app/TerminalView.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ - (void)setTerminal:(Terminal *)terminal {
WKWebView *webView = terminal.webView;
[webView.configuration.userContentController addScriptMessageHandler:self name:@"focus"];
webView.frame = self.frame;
self.opaque = webView.opaque = NO;
webView.backgroundColor = UIColor.clearColor;
[self addSubview:webView];
webView.translatesAutoresizingMaskIntoConstraints = NO;
[webView.topAnchor constraintEqualToAnchor:self.topAnchor].active = YES;
Expand Down
32 changes: 27 additions & 5 deletions app/TerminalViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ - (void)viewDidLoad {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(keyboardDidSomething:)
name:UIKeyboardDidShowNotification
name:UIKeyboardWillShowNotification
object:nil];
[center addObserver:self
selector:@selector(keyboardDidSomething:)
Expand All @@ -42,11 +42,33 @@ - (void)viewDidLoad {
object:nil];
}

- (BOOL)prefersStatusBarHidden {
return YES;
}

- (void)keyboardDidSomething:(NSNotification *)notification {
NSValue *frame = notification.userInfo[UIKeyboardFrameEndUserInfoKey];
self.bottomConstraint.constant = -frame.CGRectValue.size.height;
NSLog(@"bottom constant = %f", self.bottomConstraint.constant);
[self.termView setNeedsUpdateConstraints];
if (self.termView.needsUpdateConstraints) {
// initial layout hasn't happened yet, so animation is going to look really bad
return;
}

CGFloat pad = 0;
if ([notification.name isEqualToString:UIKeyboardWillShowNotification]) {
NSValue *frame = notification.userInfo[UIKeyboardFrameEndUserInfoKey];
pad = frame.CGRectValue.size.height;
}
NSLog(@"pad = %f", pad);
self.bottomConstraint.constant = -pad;
[self.view setNeedsUpdateConstraints];
NSNumber *interval = notification.userInfo[UIKeyboardAnimationDurationUserInfoKey];
NSNumber *curve = notification.userInfo[UIKeyboardAnimationCurveUserInfoKey];
[UIView animateWithDuration:interval.doubleValue
delay:0
options:curve.integerValue << 16
animations:^{
[self.view layoutIfNeeded];
}
completion:nil];
}

- (void)ishExited:(NSNotification *)notification {
Expand Down
4 changes: 4 additions & 0 deletions xtermjs/term.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ html, body, #terminal {
margin: 0;
}

body {
background: transparent;
}

#terminal {
padding: 0 5px;
}
Expand Down

0 comments on commit 5477fdc

Please sign in to comment.