Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions desktopApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ compose.desktop {
nativeDistributions {
targetFormats(TargetFormat.Pkg)
packageName = "Flare"
packageVersion = "1.0.0"
packageVersion = "1.0.1"
macOS {
val file = project.file("signing.properties")
val hasSigningProps = file.exists()
packageBuildVersion = System.getenv("BUILD_NUMBER") ?: "24"
packageBuildVersion = System.getenv("BUILD_NUMBER") ?: "26"
bundleID = "dev.dimension.flare"
minimumSystemVersion = "14.0"
appStore = hasSigningProps
Expand Down
17 changes: 17 additions & 0 deletions iosApp/Flare.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
0646B2622E7151A700535A3E /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 0646B2612E7151A700535A3E /* Kingfisher */; };
068F7CD12E75405A00B5FB40 /* MarkdownUI in Frameworks */ = {isa = PBXBuildFile; productRef = 068F7CD02E75405A00B5FB40 /* MarkdownUI */; };
06C7FC172E7D474900A0D01A /* LazyPager in Frameworks */ = {isa = PBXBuildFile; productRef = 06C7FC162E7D474900A0D01A /* LazyPager */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand Down Expand Up @@ -41,6 +42,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
06C7FC172E7D474900A0D01A /* LazyPager in Frameworks */,
068F7CD12E75405A00B5FB40 /* MarkdownUI in Frameworks */,
0646B2622E7151A700535A3E /* Kingfisher in Frameworks */,
);
Expand Down Expand Up @@ -89,6 +91,7 @@
packageProductDependencies = (
0646B2612E7151A700535A3E /* Kingfisher */,
068F7CD02E75405A00B5FB40 /* MarkdownUI */,
06C7FC162E7D474900A0D01A /* LazyPager */,
);
productName = flare;
productReference = 06E433FE2E6A9A2600CD0826 /* Flare.app */;
Expand Down Expand Up @@ -122,6 +125,7 @@
0646B2602E7151A700535A3E /* XCRemoteSwiftPackageReference "Kingfisher" */,
068F7CCF2E75405A00B5FB40 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */,
06791BD42E7AA40000FF2050 /* XCRemoteSwiftPackageReference "SwiftLintPlugins" */,
06C7FC152E7D474900A0D01A /* XCRemoteSwiftPackageReference "LazyPager" */,
);
preferredProjectObjectVersion = 77;
productRefGroup = 06E433FF2E6A9A2600CD0826 /* Products */;
Expand Down Expand Up @@ -431,6 +435,14 @@
version = 2.4.1;
};
};
06C7FC152E7D474900A0D01A /* XCRemoteSwiftPackageReference "LazyPager" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/gh123man/LazyPager";
requirement = {
kind = exactVersion;
version = 1.1.13;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
Expand All @@ -449,6 +461,11 @@
package = 068F7CCF2E75405A00B5FB40 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */;
productName = MarkdownUI;
};
06C7FC162E7D474900A0D01A /* LazyPager */ = {
isa = XCSwiftPackageProductDependency;
package = 06C7FC152E7D474900A0D01A /* XCRemoteSwiftPackageReference "LazyPager" */;
productName = LazyPager;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 06E433F62E6A9A2600CD0826 /* Project object */;
Expand Down
12 changes: 12 additions & 0 deletions iosApp/flare/Assets.xcassets/fa-eye-slash.symbolset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"symbols" : [
{
"filename" : "fa-eye-slash.svg",
"idiom" : "universal"
}
]
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions iosApp/flare/Assets.xcassets/fa-eye.symbolset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"symbols" : [
{
"filename" : "fa-eye.svg",
"idiom" : "universal"
}
]
}
84 changes: 84 additions & 0 deletions iosApp/flare/Assets.xcassets/fa-eye.symbolset/fa-eye.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions iosApp/flare/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,9 @@
}
}
},
"sensitive_button_show" : {
"comment" : "Button to show sensitive media"
},
"settings_title" : {
"localizations" : {
"en" : {
Expand Down
55 changes: 36 additions & 19 deletions iosApp/flare/UI/Component/MediaView.swift
Original file line number Diff line number Diff line change
@@ -1,32 +1,44 @@
import SwiftUI
import TipKit
import KotlinSharedUI

struct MediaView: View {
let data: UiMedia
@State private var showAlt: Bool = false
var body: some View {
switch onEnum(of: data) {
case .image(let image):
NetworkImage(data: image.previewUrl)
.overlay(alignment: .bottomTrailing) {
if let alt = image.description_ {
Text("ALT")
.padding(8)
.background(.black, in: .rect(cornerRadius: 16))
.foregroundStyle(.white)
.padding()
.frame(alignment: .bottomTrailing)
Button {
showAlt.toggle()
} label: {
Text("ALT")
}
.popover(isPresented: $showAlt) {
Text(alt)
.padding()
}
.padding()
.buttonStyle(.glass)
}
}
case .video(let video):
NetworkImage(data: video.thumbnailUrl)
.overlay(alignment: .bottomTrailing) {
if let alt = video.description_ {
Text("ALT")
.padding(8)
.background(.black, in: .rect(cornerRadius: 16))
.foregroundStyle(.white)
.padding()
.frame(alignment: .bottomTrailing)
Button {
showAlt.toggle()
} label: {
Text("ALT")
}
.popover(isPresented: $showAlt) {
Text(alt)
.padding()
}
.padding()
.buttonStyle(.glass)
}
}
.overlay(alignment: .bottomLeading) {
Expand All @@ -38,17 +50,22 @@ struct MediaView: View {
.frame(alignment: .bottomLeading)
}
case .gif(let gif):
NetworkImage(data: gif.previewUrl)
NetworkImage(data: gif.url)
.overlay(
alignment: .bottomTrailing
) {
if let alt = gif.description_ {
Text("ALT")
.padding(8)
.background(.black, in: .rect(cornerRadius: 16))
.foregroundStyle(.white)
.padding()
.frame(alignment: .bottomTrailing)
Button {
showAlt.toggle()
} label: {
Text("ALT")
}
.popover(isPresented: $showAlt) {
Text(alt)
.padding()
}
.buttonStyle(.glass)
.padding()
}
}
case .audio(let audio):
Expand Down
27 changes: 21 additions & 6 deletions iosApp/flare/UI/Component/NetworkImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,25 @@ import Kingfisher

struct NetworkImage: View {
let data: URL?
let placeholder: URL?
var body: some View {
KFImage
KFAnimatedImage
.url(data)
.loadTransition(.blurReplace)
.placeholder {
Rectangle()
.fill(.placeholder)
.redacted(reason: .placeholder)
if let placeholder {
NetworkImage(data: placeholder)
} else {
Rectangle()
.fill(.placeholder)
.redacted(reason: .placeholder)
}
}
.resizable()
.if(placeholder == nil, if: { image in
image.loadTransition(.blurReplace)
}, else: { image in
image
})
// .resizable()
.scaledToFill()
}
}
Expand All @@ -21,4 +30,10 @@ extension NetworkImage {
init(data: String) {
self.init(data: .init(string: data))
}
init(data: String, placeholder: String) {
self.init(data: .init(string: data), placeholder: .init(string: placeholder))
}
init(data: URL?) {
self.init(data: data, placeholder: nil)
}
}
11 changes: 7 additions & 4 deletions iosApp/flare/UI/Component/Status/StatusActionView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ struct StatusActionsView: View {
HStack {
ForEach(0..<data.count) { index in
let item = data[index]
if index == data.count - 1 {
Spacer()
}
StatusActionView(data: item, useText: false, isFixedWidth: index != data.count - 1)
.if(index == data.count - 1) { view in
view.frame(maxWidth: .infinity, alignment: .trailing)
} else: { view in
view
}

}
}
.labelIconToTitleSpacing(4)
Expand Down Expand Up @@ -130,7 +133,7 @@ extension StatusActionItem {
switch colorized.color {
case .contentColor: Color(.label)
case .error: Color(.systemRed)
case .primaryColor: Color.primary
case .primaryColor: Color.accentColor
case .red: Color(.systemRed)
}
} else {
Expand Down
58 changes: 58 additions & 0 deletions iosApp/flare/UI/Component/Status/StatusMediaView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,69 @@ import KotlinSharedUI

struct StatusMediaView: View {
let data: [any UiMedia]
let sensitive: Bool
@State private var isBlur: Bool
@State private var showFullScreen: Bool = false
@State private var selectedItem: (any UiMedia)?

var body: some View {
AdaptiveMosaic(data, spacing: 4, singleMode: .force16x9) { item in
MediaView(data: item)
.onTapGesture {
if !sensitive || !isBlur {
// Only allow tap if not sensitive or already unblurred
selectedItem = item
showFullScreen = true
}
}
}
.fullScreenCover(isPresented: $showFullScreen, onDismiss: {
showFullScreen = false
}, content: {
StatusMediaScreen(data: data, selectedIndex: data.firstIndex(where: { $0.url == selectedItem?.url }) ?? 0)
})
.blur(radius: isBlur ? 20 : 0)
.overlay(
alignment: isBlur ? .center : .topLeading
) {
if sensitive {
if isBlur {
Button {
withAnimation {
isBlur = false
}
} label: {
Label {
Text("sensitive_button_show", comment: "Button to show sensitive media")
} icon: {
Image("fa-eye")
}
}
.buttonStyle(.glassProminent)
.padding()
} else {
Button {
withAnimation {
isBlur = true
}
} label: {
Image("fa-eye-slash")
}
.buttonStyle(.glass)
.padding()
}
} else {
EmptyView()
}
}
.clipShape(.rect(cornerRadius: 16))
}
}

extension StatusMediaView {
init(data: [any UiMedia], sensitive: Bool) {
self.data = data
self.sensitive = sensitive
self._isBlur = State(initialValue: sensitive)
}
}
6 changes: 4 additions & 2 deletions iosApp/flare/UI/Component/Status/StatusView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ struct StatusView: View {
Text("mastodon_item_show_more")
}
}
.buttonStyle(.glassProminent)
}

if expand || data.contentWarning == nil || data.contentWarning?.isEmpty == true {
Expand All @@ -106,13 +107,14 @@ struct StatusView: View {
.if(isDetail) { richText in
richText
} else: { richText in
richText.lineLimit(5)
richText
.lineLimit(5)
}

}
}
if !data.images.isEmpty {
StatusMediaView(data: data.images)
StatusMediaView(data: data.images, sensitive: data.sensitive)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}

Expand Down
10 changes: 9 additions & 1 deletion iosApp/flare/UI/Component/TimelinePagingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import KotlinSharedUI

struct TimelinePagingView: View {
let data: PagingState<UiTimeline>
let detailStatusKey: MicroBlogKey?
var body: some View {
switch onEnum(of: data) {
case .empty: EmptyView()
Expand All @@ -17,7 +18,7 @@ struct TimelinePagingView: View {
ForEach(TimelineCollection(data: success)) { data in
if let item = data.data {
ListCardView(index: data.index, totalCount: Int(success.itemCount)) {
TimelineView(data: item)
TimelineView(data: item, detailStatusKey: detailStatusKey)
.padding()
.onAppear {
_ = success.get(index: Int32(data.index))
Expand All @@ -37,6 +38,13 @@ struct TimelinePagingView: View {
}
}

extension TimelinePagingView {
init(data: PagingState<UiTimeline>) {
self.data = data
self.detailStatusKey = nil
}
}

struct TimelineData: Identifiable {
let id: String
let data: UiTimeline?
Expand Down
Loading