Skip to content

Commit c182f8d

Browse files
committed
User interface update.
1 parent a42e0af commit c182f8d

File tree

14 files changed

+378
-266
lines changed

14 files changed

+378
-266
lines changed

ArtOfAscii.xcodeproj/project.pbxproj

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
7174D3BC23F7D0D100A09FFB /* woman.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 7174D3B023F7D0D100A09FFB /* woman.jpg */; };
3535
7174D3BD23F7D0D100A09FFB /* imagePickerList.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7174D3B123F7D0D100A09FFB /* imagePickerList.plist */; };
3636
71BA4ED823FE31BA00788A11 /* FiraCode-VF.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 71BA4ED723FE31BA00788A11 /* FiraCode-VF.ttf */; };
37+
71C37FDA24024D10002C4F81 /* RawImage+BookAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99F6648091CC93CB6693447 /* RawImage+BookAPI.swift */; };
38+
71C37FDB24024D13002C4F81 /* AsciiArtRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99F6337FA0E5673FC85EE91 /* AsciiArtRenderer.swift */; };
3739
B99F60BD727AA847C9846C2B /* IntroductionLiveViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99F6C47683919CCE440B901 /* IntroductionLiveViewController.swift */; };
3840
B99F618160CD0C4E04B0A759 /* LiveViewSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99F6D807B507CFEA417C45F /* LiveViewSupport.swift */; };
3941
B99F618E497E728524D63AF8 /* EventListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99F62ACBBE87D8546FAB866 /* EventListener.swift */; };
@@ -389,6 +391,16 @@
389391
path = PublicResources;
390392
sourceTree = "<group>";
391393
};
394+
71C37FD924024B4B002C4F81 /* Book */ = {
395+
isa = PBXGroup;
396+
children = (
397+
B99F6648091CC93CB6693447 /* RawImage+BookAPI.swift */,
398+
B99F6F739FC0DC4F69F5CB92 /* FontResourceProvider.swift */,
399+
B99F6337FA0E5673FC85EE91 /* AsciiArtRenderer.swift */,
400+
);
401+
path = Book;
402+
sourceTree = "<group>";
403+
};
392404
71C6D8DF23F975EA005333B3 /* Frameworks */ = {
393405
isa = PBXGroup;
394406
children = (
@@ -433,14 +445,15 @@
433445
B99F64119B36315AE8FAFAE3 /* Sources */ = {
434446
isa = PBXGroup;
435447
children = (
436-
B99F68A75310EEBB0FB9E53E /* Core */,
448+
B99F62ACBBE87D8546FAB866 /* EventListener.swift */,
437449
);
438450
path = Sources;
439451
sourceTree = "<group>";
440452
};
441453
B99F6565BBD6409ECA1863B0 /* Sources */ = {
442454
isa = PBXGroup;
443455
children = (
456+
71C37FD924024B4B002C4F81 /* Book */,
444457
B99F68A240FBE29591D96212 /* Core */,
445458
B99F69A4BA261552C3989CF5 /* Utils */,
446459
B99F6D23FE8B41BA5E133703 /* DataSource */,
@@ -488,17 +501,6 @@
488501
path = Core;
489502
sourceTree = "<group>";
490503
};
491-
B99F68A75310EEBB0FB9E53E /* Core */ = {
492-
isa = PBXGroup;
493-
children = (
494-
B99F62ACBBE87D8546FAB866 /* EventListener.swift */,
495-
B99F6648091CC93CB6693447 /* RawImage+BookAPI.swift */,
496-
B99F6F739FC0DC4F69F5CB92 /* FontResourceProvider.swift */,
497-
B99F6337FA0E5673FC85EE91 /* AsciiArtRenderer.swift */,
498-
);
499-
path = Core;
500-
sourceTree = "<group>";
501-
};
502504
B99F6931A885E93A1A2490B6 /* ShowcaseImageView */ = {
503505
isa = PBXGroup;
504506
children = (
@@ -790,6 +792,7 @@
790792
B99F6B218BB1EDDCF5A1BEDA /* RawImage.swift in Sources */,
791793
B99F65EBA0B2B605EAF4B0D9 /* UIColor+StateColors.swift in Sources */,
792794
B99F6661C523F8C8DE0DDEEA /* ImagePickerDataSource.swift in Sources */,
795+
71C37FDB24024D13002C4F81 /* AsciiArtRenderer.swift in Sources */,
793796
B99F6E509D271A941D4E9790 /* BaseViewController.swift in Sources */,
794797
B99F62A628D4A47F72E23E1D /* ImagePickerViewController.swift in Sources */,
795798
B99F6400E1E57AF2E5AB4976 /* ImagePickerCollectionViewCell.swift in Sources */,
@@ -805,6 +808,7 @@
805808
B99F6ED14C4977D2A3E4D777 /* AsciificationLiveViewController.swift in Sources */,
806809
B99F649C83DCDA708FA85400 /* ScaleModeButton.swift in Sources */,
807810
B99F6905CE4227EDEC115B4C /* FontResourceProvider.swift in Sources */,
811+
71C37FDA24024D10002C4F81 /* RawImage+BookAPI.swift in Sources */,
808812
B99F6A90900307C53CE347D7 /* AVCaptureVideoOrientation+UIInterfaceOrientatiion.swift in Sources */,
809813
);
810814
runOnlyForDeploymentPostprocessing = 0;

ArtOfAscii/Chapters/01-ArtOfAscii.playgroundchapter/Pages/03-GrayscaleHistogramEqualization.playgroundpage/main.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,13 @@ func applyHistogramEqualization(rawImage: RawImage) {
101101
// Add current pixel count to the cumulative pixel count.
102102
pixelCumulative += histogram[i]
103103
// Calculates the cumulative pixel frequency (CPF) as cumulative pixel count divided by total pixel count.
104-
let cumulativePixelFrequency = <#T##cumulativeFrequency##Double#>
104+
let cumulativePixelFrequency: Double = <#T##cumulativeFrequency##Double#>
105105

106106
// Map current brightness to full range according current CPF value.
107107
let equalizedBrightness = cumulativePixelFrequency * 255.0
108108
equalizationMap[i] = UInt8(equalizedBrightness.rounded())
109109
}
110-
rawImage.applyBrightnessMap(equalizationMap)
110+
rawImage.applyBrightnessLookup(equalizationMap)
111111
}
112112

113113
//#-end-editable-code

ArtOfAscii/Modules/BookAPI.playgroundmodule/Sources/Core/RawImage+BookAPI.swift renamed to ArtOfAscii/Modules/BookCore.playgroundmodule/Sources/Book/RawImage+BookAPI.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,15 @@
66
import UIKit
77
import Accelerate
88

9-
import BookCore
10-
119
public extension RawImage {
1210

13-
func applyBrightnessMap(_ mapping: [UInt8]) {
11+
func applyBrightnessLookup(_ mapping: [UInt8]) {
1412
let dataPointer = getMutableDataPointer()
1513
for i in stride(from: 0, to: format.pixelCount * 4, by: 4) {
1614
let red = dataPointer[i]
1715
let green = dataPointer[i + 1]
1816
let blue = dataPointer[i + 2]
19-
let brightness = Int((0.2126 * Float(red) + 0.7152 * Float(blue) + 0.0722 * Float(green)).rounded())
17+
let brightness = Int(((Double(red) + Double(blue) + Double(green)) / 3).rounded())
2018
let mappedBrightness = mapping[brightness]
2119
dataPointer[i] = mappedBrightness
2220
dataPointer[i + 1] = mappedBrightness

ArtOfAscii/Modules/BookCore.playgroundmodule/Sources/UserInterface/BaseViewController.swift

Lines changed: 115 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,39 @@
66
import UIKit
77
import PlaygroundSupport
88

9-
public class BaseViewController: UIViewController, PlaygroundLiveViewSafeAreaContainer,
10-
ImagePickerViewControllerDelegate, ToolBarButtonViewDelegate {
11-
12-
@IBOutlet weak var backgroundImageView: UIImageView!
13-
@IBOutlet weak var showcaseImageCoontainerView: UIView!
9+
public class BaseViewController: UIViewController,
10+
PlaygroundLiveViewSafeAreaContainer,
11+
ImagePickerViewControllerDelegate,
12+
ToolBarButtonViewDelegate,
13+
PlaygroundLiveViewMessageHandler {
14+
15+
@IBOutlet private weak var backgroundImageView: UIImageView!
16+
@IBOutlet private weak var showcaseImageContainerView: UIView!
1417
@IBOutlet weak var showcaseImageView: ShowcaseImageView!
15-
16-
@IBOutlet weak var toolBarContainerView: UIView!
18+
19+
@IBOutlet private weak var toolBarContainerView: UIView!
20+
21+
private weak var loadingIndicatorView: UIView!
1722

1823
var sourceImage: UIImage?
1924

2025
var imagePickerController: ImagePickerViewController!
21-
26+
27+
var editorConnected = false
28+
2229
public override func viewDidLoad() {
2330
super.viewDidLoad()
2431

32+
setupLogoImageView()
33+
setupToolBarBlurView()
34+
setupProcessingIndicator()
35+
2536
backgroundImageView.contentMode = .scaleAspectFill
2637
backgroundImageView.image = UIImage(named: "background-v2")
2738

2839
showcaseImageView.cornerRadius = 8.0
2940

30-
setupLogoImageView()
31-
setupToolBarBlurView()
41+
setLoadingIndicatorHidden(true, animated: false)
3242
}
3343

3444
public override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
@@ -46,24 +56,24 @@ public class BaseViewController: UIViewController, PlaygroundLiveViewSafeAreaCon
4656
}
4757
}
4858

49-
func setupLogoImageView() {
59+
private func setupLogoImageView() {
5060
let logoImageView = UIImageView()
5161
logoImageView.image = UIImage(named: "logo")
5262
logoImageView.contentMode = .scaleAspectFit
53-
63+
5464
logoImageView.translatesAutoresizingMaskIntoConstraints = false
55-
self.showcaseImageCoontainerView.insertSubview(logoImageView, belowSubview: showcaseImageView)
65+
self.showcaseImageContainerView.insertSubview(logoImageView, belowSubview: showcaseImageView)
5666

57-
logoImageView.centerXAnchor.constraint(equalTo: showcaseImageCoontainerView.centerXAnchor).isActive = true
58-
logoImageView.centerYAnchor.constraint(equalTo: showcaseImageCoontainerView.centerYAnchor).isActive = true
67+
logoImageView.centerXAnchor.constraint(equalTo: showcaseImageContainerView.centerXAnchor).isActive = true
68+
logoImageView.centerYAnchor.constraint(equalTo: showcaseImageContainerView.centerYAnchor).isActive = true
5969
logoImageView.widthAnchor.constraint(equalToConstant: 420).isActive = true
60-
logoImageView.heightAnchor.constraint(equalTo: showcaseImageCoontainerView.heightAnchor).isActive = true
70+
logoImageView.heightAnchor.constraint(equalTo: showcaseImageContainerView.heightAnchor).isActive = true
6171
}
62-
63-
func setupToolBarBlurView() {
72+
73+
private func setupToolBarBlurView() {
6474
let blurEffect = UIBlurEffect(style: .dark)
6575
let blurView = UIVisualEffectView(effect: blurEffect)
66-
76+
6777
blurView.translatesAutoresizingMaskIntoConstraints = false
6878
self.view.insertSubview(blurView, aboveSubview: self.backgroundImageView)
6979

@@ -72,11 +82,72 @@ public class BaseViewController: UIViewController, PlaygroundLiveViewSafeAreaCon
7282
blurView.topAnchor.constraint(equalTo: self.toolBarContainerView.topAnchor, constant: -12).isActive = true
7383
blurView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
7484
}
75-
85+
86+
private func setupProcessingIndicator() {
87+
let indicatorBackgroundView = UIView()
88+
89+
indicatorBackgroundView.backgroundColor = UIColor.black.withAlphaComponent(0.6)
90+
indicatorBackgroundView.translatesAutoresizingMaskIntoConstraints = false
91+
92+
self.showcaseImageContainerView.addSubview(indicatorBackgroundView)
93+
94+
indicatorBackgroundView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
95+
indicatorBackgroundView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
96+
indicatorBackgroundView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
97+
indicatorBackgroundView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
98+
99+
let indicatorContainerView = UIView()
100+
101+
indicatorContainerView.backgroundColor = .clear
102+
indicatorContainerView.translatesAutoresizingMaskIntoConstraints = false
103+
indicatorBackgroundView.addSubview(indicatorContainerView)
104+
105+
indicatorContainerView.topAnchor.constraint(equalTo: indicatorBackgroundView.topAnchor).isActive = true
106+
indicatorContainerView.leadingAnchor.constraint(equalTo: indicatorBackgroundView.leadingAnchor).isActive = true
107+
indicatorContainerView.trailingAnchor.constraint(equalTo: indicatorBackgroundView.trailingAnchor).isActive = true
108+
indicatorContainerView.bottomAnchor.constraint(equalTo: showcaseImageContainerView.bottomAnchor).isActive = true
109+
110+
let progressIndicator = UIActivityIndicatorView(style: .whiteLarge)
111+
progressIndicator.translatesAutoresizingMaskIntoConstraints = false
112+
indicatorContainerView.addSubview(progressIndicator)
113+
progressIndicator.centerXAnchor.constraint(equalTo: indicatorContainerView.centerXAnchor).isActive = true
114+
progressIndicator.centerYAnchor.constraint(equalTo: indicatorContainerView.centerYAnchor).isActive = true
115+
116+
progressIndicator.startAnimating()
117+
118+
self.loadingIndicatorView = indicatorBackgroundView
119+
}
120+
76121
func updateShowcaseImage(image: UIImage) {
77122
showcaseImageView.image = image
78123
}
79124

125+
private func setLoadingIndicatorHidden(_ hidden: Bool, animated: Bool) {
126+
if loadingIndicatorView.isHidden == hidden {
127+
return
128+
}
129+
if animated {
130+
if loadingIndicatorView.isHidden && !hidden {
131+
loadingIndicatorView.alpha = 0.0
132+
loadingIndicatorView.isHidden = false
133+
}
134+
UIView.animate(withDuration: 0.25, delay: hidden ? 0.25 : 0, animations: {
135+
self.loadingIndicatorView.alpha = hidden ? 0.0 : 1.0
136+
}, completion: { (complete) in
137+
self.loadingIndicatorView.isHidden = hidden
138+
})
139+
} else {
140+
loadingIndicatorView.isHidden = hidden
141+
}
142+
}
143+
144+
func send(_ message: PlaygroundSupport.PlaygroundValue, showLoadingView: Bool) {
145+
if editorConnected && showLoadingView {
146+
setLoadingIndicatorHidden(false, animated: true)
147+
}
148+
send(message)
149+
}
150+
80151
func didSelectImage(image: UIImage, pickerController: ImagePickerViewController) {
81152
sourceImage = image
82153
updateShowcaseImage(image: image)
@@ -86,4 +157,28 @@ public class BaseViewController: UIViewController, PlaygroundLiveViewSafeAreaCon
86157

87158
}
88159

160+
public func liveViewMessageConnectionOpened() {
161+
editorConnected = true
162+
}
163+
164+
public func liveViewMessageConnectionClosed() {
165+
editorConnected = false
166+
setLoadingIndicatorHidden(true, animated: true)
167+
}
168+
169+
public func receive(_ message: PlaygroundValue) {
170+
guard let message = EventMessage.from(playgroundValue: message) else {
171+
return
172+
}
173+
switch message {
174+
case .imageProcessingResponse(let image):
175+
setLoadingIndicatorHidden(true, animated: true)
176+
if let image = image {
177+
self.updateShowcaseImage(image: image)
178+
}
179+
default:
180+
break
181+
}
182+
}
183+
89184
}

ArtOfAscii/Modules/BookCore.playgroundmodule/Sources/UserInterface/Chapters/01-ArtOfAscii/01-Introduction/IntroductionLiveViewController.swift

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import PlaygroundSupport
88
import AVFoundation
99
import Accelerate
1010

11-
class IntroductionLiveViewController: BaseViewController {
11+
public class IntroductionLiveViewController: BaseViewController {
1212

1313
@IBOutlet private weak var sessionSetupResultLabel: UILabel!
1414

@@ -80,19 +80,19 @@ class IntroductionLiveViewController: BaseViewController {
8080
}
8181
}
8282

83-
override func viewDidLoad() {
83+
public override func viewDidLoad() {
8484
super.viewDidLoad()
8585

8686
self.imagePickerController.enableCameraRollPicking = false
8787
sessionSetupResultLabel.isHidden = true
8888
}
8989

90-
override func viewWillDisappear(_ animated: Bool) {
90+
public override func viewWillDisappear(_ animated: Bool) {
9191
stopSession()
9292
super.viewWillDisappear(animated)
9393
}
9494

95-
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
95+
public override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
9696
super.viewWillTransition(to: size, with: coordinator)
9797

9898
sessionQueue.async {
@@ -105,13 +105,27 @@ class IntroductionLiveViewController: BaseViewController {
105105
}
106106

107107
override func didSelectImage(image: UIImage, pickerController: ImagePickerViewController) {
108-
108+
109109
}
110110

111111
override func toolBarButtonTapped(buttonView: ToolBarButtonView) {
112112
buttonView.state = .normal
113113
}
114114

115+
public override func liveViewMessageConnectionOpened() {
116+
requestAuthorization()
117+
reconfigureSession()
118+
startSessionAndUpdateUI()
119+
}
120+
121+
public override func liveViewMessageConnectionClosed() {
122+
stopSession()
123+
}
124+
125+
public override func receive(_ message: PlaygroundValue) {
126+
127+
}
128+
115129
}
116130

117131
extension IntroductionLiveViewController {
@@ -256,7 +270,7 @@ extension IntroductionLiveViewController {
256270

257271
extension IntroductionLiveViewController: AVCaptureVideoDataOutputSampleBufferDelegate {
258272

259-
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
273+
public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
260274
guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
261275
return
262276
}
@@ -328,21 +342,3 @@ extension IntroductionLiveViewController: AVCaptureVideoDataOutputSampleBufferDe
328342
}
329343

330344
}
331-
332-
extension IntroductionLiveViewController: PlaygroundLiveViewMessageHandler {
333-
334-
public func liveViewMessageConnectionOpened() {
335-
requestAuthorization()
336-
reconfigureSession()
337-
startSessionAndUpdateUI()
338-
}
339-
340-
public func liveViewMessageConnectionClosed() {
341-
stopSession()
342-
}
343-
344-
public func receive(_ message: PlaygroundValue) {
345-
346-
}
347-
348-
}

0 commit comments

Comments
 (0)