Add coloured icons to show what review state a photo is in
- ID
32918c6- date
2023-06-08 14:29:55+00:00- author
Alex Chan <alex@alexwlchan.net>- parent
ae1b773- message
Add coloured icons to show what review state a photo is in- changed files
6 files, 132 additions, 48 deletionsBlinkReviewer/BlinkReviewer/Model/ReviewState.swiftBlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swiftBlinkReviewer/BlinkReviewer/Views/AlbumInfo.swiftBlinkReviewer/BlinkReviewer/Views/SwiftUIView.swiftBlinkReviewer/BlinkReviewer/Views/ThumbnailImage.swiftBlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift
Changed files
BlinkReviewer/BlinkReviewer/Model/ReviewState.swift (0) → BlinkReviewer/BlinkReviewer/Model/ReviewState.swift (822)
diff --git a/BlinkReviewer/BlinkReviewer/Model/ReviewState.swift b/BlinkReviewer/BlinkReviewer/Model/ReviewState.swift
new file mode 100644
index 0000000..0806639
--- /dev/null
+++ b/BlinkReviewer/BlinkReviewer/Model/ReviewState.swift
@@ -0,0 +1,40 @@
+//
+// ReviewState.swift
+// BlinkReviewer
+//
+// Created by Alex Chan on 08/06/2023.
+//
+
+import Foundation
+import SwiftUI
+
+enum ReviewState {
+ case Approved
+ case Rejected
+ case NeedsAction
+
+ func color() -> Color {
+ switch(self) {
+ case .Approved:
+ return .green
+
+ case .Rejected:
+ return .red
+
+ case .NeedsAction:
+ return .blue
+ }
+ }
+
+ func icon() -> Image {
+ switch(self) {
+ case .Approved:
+ return Image(systemName: "checkmark.circle.fill")
+ case .Rejected:
+ return Image(systemName: "trash.circle.fill")
+ case .NeedsAction:
+ return Image(systemName: "info.circle.fill")
+ }
+ }
+}
+
BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift (2426) → BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift (2934)
diff --git a/BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift b/BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift
index 80ba71a..97722b5 100644
--- a/BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift
+++ b/BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift
@@ -35,6 +35,25 @@ extension PHAsset {
return result
}
+ func state() -> ReviewState? {
+ var result: ReviewState? = nil
+
+ self.albums().forEach { album in
+ switch (album.localizedTitle) {
+ case "Approved":
+ result = .Approved
+ case "Rejected":
+ result = .Rejected
+ case "Needs Action":
+ result = .NeedsAction
+ default:
+ break
+ }
+ }
+
+ return result
+ }
+
private func getImageForSize(size: CGSize) -> NSImage {
// This implementation is based on code in a Stack Overflow answer
// by Francois Nadeau: https://stackoverflow.com/a/48755517/1558022
BlinkReviewer/BlinkReviewer/Views/AlbumInfo.swift (1023) → BlinkReviewer/BlinkReviewer/Views/AlbumInfo.swift (1068)
diff --git a/BlinkReviewer/BlinkReviewer/Views/AlbumInfo.swift b/BlinkReviewer/BlinkReviewer/Views/AlbumInfo.swift
index 31b06d3..1e4a1be 100644
--- a/BlinkReviewer/BlinkReviewer/Views/AlbumInfo.swift
+++ b/BlinkReviewer/BlinkReviewer/Views/AlbumInfo.swift
@@ -29,6 +29,7 @@ struct AlbumInfo: View {
.padding(5)
.background(.white.opacity(0.9))
.cornerRadius(7.0)
+ .shadow(radius: 2.0)
}
}
}.padding()
BlinkReviewer/BlinkReviewer/Views/SwiftUIView.swift (0) → BlinkReviewer/BlinkReviewer/Views/SwiftUIView.swift (354)
diff --git a/BlinkReviewer/BlinkReviewer/Views/SwiftUIView.swift b/BlinkReviewer/BlinkReviewer/Views/SwiftUIView.swift
new file mode 100644
index 0000000..c6aa691
--- /dev/null
+++ b/BlinkReviewer/BlinkReviewer/Views/SwiftUIView.swift
@@ -0,0 +1,20 @@
+//
+// SwiftUIView.swift
+// BlinkReviewer
+//
+// Created by Alex Chan on 08/06/2023.
+//
+
+import SwiftUI
+
+struct SwiftUIView: View {
+ var body: some View {
+ Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
+ }
+}
+
+struct SwiftUIView_Previews: PreviewProvider {
+ static var previews: some View {
+ SwiftUIView()
+ }
+}
BlinkReviewer/BlinkReviewer/Views/ThumbnailImage.swift (3039) → BlinkReviewer/BlinkReviewer/Views/ThumbnailImage.swift (3314)
diff --git a/BlinkReviewer/BlinkReviewer/Views/ThumbnailImage.swift b/BlinkReviewer/BlinkReviewer/Views/ThumbnailImage.swift
index 64dfb7e..d812e45 100644
--- a/BlinkReviewer/BlinkReviewer/Views/ThumbnailImage.swift
+++ b/BlinkReviewer/BlinkReviewer/Views/ThumbnailImage.swift
@@ -8,62 +8,26 @@
import SwiftUI
import Photos
-enum ReviewState {
- case Approved
- case Rejected
- case NeedsAction
-}
-
/// Renders a square thumbnail for an image.
///
/// The image will be expanded to fill the square, and may be clipped
/// if the original aspect ratio isn't square.
struct ThumbnailImage: View {
- var asset: PHAsset
+ var thumbnail: NSImage
+ var state: ReviewState?
+ var isFavorite: Bool
var isSelected: Bool
var size: CGFloat {
isSelected ? 70.0 : 50.0
}
- var state: ReviewState? {
- var result: ReviewState? = nil
-
- asset.albums().forEach { album in
- switch (album.localizedTitle) {
- case "Approved":
- result = .Approved
- case "Rejected":
- result = .Rejected
- case "Needs Action":
- result = .NeedsAction
- default:
- break
- }
- }
-
- return result
- }
-
- var stateColor: Color {
- switch (state) {
- case .Approved:
- return .green
- case .Rejected:
- return .red
- case .NeedsAction:
- return .blue
- default:
- return .gray.opacity(0.5)
- }
- }
-
var cornerRadius: CGFloat {
return isSelected ? 7.0 : 5.0
}
var body: some View {
- Image(nsImage: asset.getThumbnail())
+ Image(nsImage: thumbnail)
.resizable()
// Note: it's taken several attempts to get this working correctly;
// it behaves differently in the running app to the SwiftUI preview.
@@ -77,14 +41,17 @@ struct ThumbnailImage: View {
.scaledToFill()
.frame(width: size, height: size, alignment: .center)
.clipped()
- .cornerRadius(cornerRadius)
.overlay(
// https://www.appcoda.com/swiftui-border/
RoundedRectangle(cornerRadius: cornerRadius)
- .stroke(stateColor, lineWidth: state != nil ? 3.0 : 1.0)
+ .stroke(
+ state?.color() ?? .gray.opacity(0.7),
+ lineWidth: state != nil ? 3.0 : 1.0
+ )
)
+ .cornerRadius(cornerRadius)
.overlay(alignment: Alignment(horizontal: .leading, vertical: .bottom)) {
- if (asset.isFavorite) {
+ if (isFavorite) {
Image(systemName: "heart.fill")
.foregroundColor(.white)
.padding(2)
@@ -92,11 +59,46 @@ struct ThumbnailImage: View {
}
}
.overlay(alignment: Alignment(horizontal: .leading, vertical: .top)) {
- if (state != nil) {
- Image(systemName: "checkmark.circle.fill").foregroundColor(stateColor).accentColor(.white).padding(2).font(.title2)
-// "info.circle.fill"
-// "trash.circle.fill
+ if let thisState = state {
+ thisState.icon()
+ .foregroundStyle(.white, thisState.color())
+ .symbolRenderingMode(.palette)
+ .padding(2)
+ .font(.title2)
+ .shadow(radius: 2.0)
}
}
}
}
+
+struct ThumbnailImage_Previews: PreviewProvider {
+ static var previews: some View {
+ ThumbnailImage(
+ thumbnail: NSImage(named: "IMG_5934")!,
+ state: .Approved,
+ isFavorite: true,
+ isSelected: true
+ ).previewDisplayName("approved, favorite")
+
+ ThumbnailImage(
+ thumbnail: NSImage(named: "IMG_5934")!,
+ state: .Rejected,
+ isFavorite: false,
+ isSelected: false
+ ).previewDisplayName("rejected")
+
+ ThumbnailImage(
+ thumbnail: NSImage(named: "IMG_5934")!,
+ state: .NeedsAction,
+ isFavorite: false,
+ isSelected: false
+ ).previewDisplayName("needs action")
+
+ ThumbnailImage(
+ thumbnail: NSImage(named: "IMG_5934")!,
+ state: nil,
+ isFavorite: false,
+ isSelected: false
+ ).previewDisplayName("no state")
+ }
+}
BlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift (2810) → BlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift (2937)
diff --git a/BlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift b/BlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift
index cec0cdb..6bacfef 100644
--- a/BlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift
+++ b/BlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift
@@ -32,7 +32,9 @@ struct ThumbnailList: View {
// the thumbnails every time you change position.
ForEach(Array(displayAssets().enumerated()), id: \.element.localIdentifier) { index, asset in
ThumbnailImage(
- asset: asset,
+ thumbnail: asset.getThumbnail(),
+ state: asset.state(),
+ isFavorite: asset.isFavorite,
isSelected: displayAssets()[displaySelectedAssetIndex()].localIdentifier == asset.localIdentifier
).onTapGesture {
selectedAssetIndex = assets.count - 1 - index