Improve UI

Do screen updates on the next frame, animate resizing in sync with keyboard, remove status bar, transparent background for the terminal
This commit is contained in:
Theodore Dubois
2017-11-08 17:25:04 -08:00
parent 42cacc1add
commit 5477fdc1e6
8 changed files with 107 additions and 16 deletions
+1 -1
View File
@@ -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"/>
+15
View File
@@ -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
View File
@@ -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
View File
@@ -28,6 +28,8 @@
<array>
<string>armv7</string>
</array>
<key>UIStatusBarHidden</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
+21 -10
View File
@@ -6,6 +6,7 @@
//
#import "Terminal.h"
#import "DelayedUITask.h"
#include "fs/tty.h"
@interface Terminal () <WKScriptMessageHandler>
@@ -14,6 +15,9 @@
@property struct tty *tty;
@property NSMutableData *pendingData;
@property DelayedUITask *refreshTask;
@property DelayedUITask *scrollToBottomTask;
@end
@implementation Terminal
@@ -25,6 +29,9 @@ static Terminal *terminal = nil;
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];
@@ -45,36 +52,40 @@ static Terminal *terminal = nil;
- (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];
}
+2
View File
@@ -21,6 +21,8 @@
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;
+27 -5
View File
@@ -29,7 +29,7 @@
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(keyboardDidSomething:)
name:UIKeyboardDidShowNotification
name:UIKeyboardWillShowNotification
object:nil];
[center addObserver:self
selector:@selector(keyboardDidSomething:)
@@ -42,11 +42,33 @@
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 {
+4
View File
@@ -5,6 +5,10 @@ html, body, #terminal {
margin: 0;
}
body {
background: transparent;
}
#terminal {
padding: 0 5px;
}