Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: wire cells upload images & videos previews - WPB-15844 #2513

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
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
6 changes: 6 additions & 0 deletions .github/workflows/test_pr_changes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ jobs:
WireAuthentication:
- 'WireAuthentication/**'
- 'wire-ios-mono.xcworkspace/xcshareddata/xcschemes/WireAuthenticationAll.xcscheme'
WireCells:
- 'WireCells/**'
- 'wire-ios-mono.xcworkspace/xcshareddata/xcschemes/WireCellsAll.xcscheme'
WireDebug:
- 'WireDebug/**'
- 'wire-ios-mono.xcworkspace/xcshareddata/xcschemes/WireDebugAll.xcscheme'
WireDomain:
- 'WireDomain/**'
WireLogging:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
<false/>
</dict>
</plist>
54 changes: 44 additions & 10 deletions WireCells/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,82 @@

import PackageDescription

let WireTestingPackage = Target.Dependency.product(name: "WireTestingPackage", package: "WireFoundation")

let package = Package(
name: "WireCells",
platforms: [.iOS(.v16), .macOS(.v12)],
products: [
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: "WireCellsAPI",
targets: ["API"]
targets: ["WireCellsAPI"]
),
.library(
name: "WireCellsBindings",
targets: ["Bindings"]
targets: ["WireCellsBindings"]
),
.library(
name: "WireCellsUI",
targets: ["WireCellsUI"]
),
],
dependencies: [
.package(url: "https://github.com/pydio/cells-sdk-swift.git", branch: "v5-dev"),
.package(url: "https://github.com/awslabs/aws-sdk-swift.git", from: "1.0.0")
.package(url: "https://github.com/pydio/cells-sdk-swift.git", branch: "v0.1.1-alpha02"),
.package(url: "https://github.com/awslabs/aws-sdk-swift.git", from: "1.0.0"),
.package(name: "WireFoundation", path: "../WireFoundation"),
.package(name: "WireUI", path: "../WireUI")
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "API",
name: "WireCellsAPI",
dependencies: [
.product(name: "CellsSDK", package: "cells-sdk-swift")
]
),
.target(name: "Bindings"),
.target(name: "WireCellsBindings"),
.target(
name: "Implementation",
name: "WireCellsImplementation",
dependencies: [
"API",
"WireCellsAPI",
.product(name: "AWSS3", package: "aws-sdk-swift"),
.product(name: "CellsSDK", package: "cells-sdk-swift")
]
),
.target(
name: "WireCellsUI",
dependencies: [
.product(name: "WireDesign", package: "WireUI")
]
),
.testTarget(
name: "WireCellsTests",
dependencies: [
"API",
"Implementation"
"WireCellsAPI",
"WireCellsImplementation"
]
),
.testTarget(
name: "WireCellsUITests",
dependencies: [
"WireCellsUI"
]
),
]
)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to have the upcoming features enabled, like other packages do, see WireFoundation please.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This package builds with the 6.0 toolchain, so those are not upcoming features and are already enabled for this package.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made the changes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we should update WireAuthentication/Package.swift in a separate PR

for target in package.targets {
    if target.isTest {
        target.dependencies += [WireTestingPackage]
    }
    target.swiftSettings = (target.swiftSettings ?? []) + [
        // TODO: [WPB-15967] Enable `ExistentialAny` upcoming feature
        .enableUpcomingFeature("GlobalConcurrency"),
        .enableExperimentalFeature("StrictConcurrency"),
        .unsafeFlags(["-enable-bare-slash-regex"]) // For regex literals
    ]
}

for target in package.targets {
if target.isTest {
target.dependencies += [WireTestingPackage]
}
}

for target in package.targets {
target.swiftSettings = (target.swiftSettings ?? []) + [
.enableUpcomingFeature("InternalImportsByDefault"),
.enableUpcomingFeature("FullTypedThrows"),
.enableUpcomingFeature("ExistentialAny")
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@
//

public enum WireCellsFileQueryError: Error {
case genericError(Error)
case genericError(any Error)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@

public enum WireCellsFileUploadError: Error {
case fileTooLarge(fileSize: Int, maxSize: Int)
case genericError(Error)
case genericError(any Error)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// along with this program. If not, see http://www.gnu.org/licenses/.
//

import Foundation
public import Foundation

public struct WireCellsFileUploadInfo: Identifiable, Sendable {
public let data: Data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
// along with this program. If not, see http://www.gnu.org/licenses/.
//

@preconcurrency import CellsSDK
import Foundation
@preconcurrency public import CellsSDK

public protocol WireCellsService {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// along with this program. If not, see http://www.gnu.org/licenses/.
//

import Foundation
public import Foundation

public struct WireCellsUploadedFile: Sendable {
/// The path of the uploaded file on the server
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,8 @@
// along with this program. If not, see http://www.gnu.org/licenses/.
//

class WireCellsAssembly {}
public class WireCellsAssembly {
public init() {
print("Init")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@
// along with this program. If not, see http://www.gnu.org/licenses/.
//

package import Foundation
package import WireCellsAPI
package import CellsSDK

import AWSClientRuntime
@preconcurrency import AWSS3
import AWSSDKIdentity
@preconcurrency import CellsSDK
import ClientRuntime
import Foundation
import Smithy
import WireCellsAPI

package class WireCellsServiceImplementation: WireCellsService {

Expand Down Expand Up @@ -114,14 +115,14 @@ package class WireCellsServiceImplementation: WireCellsService {
}

private func _listFiles(atPath path: String) async throws(WireCellsFileQueryError) -> [RestNode] {
let request = RestLookupRequest()
var request = RestLookupRequest()
let locator = RestNodeLocator(path: path)
request.locators = RestNodeLocators(many: [locator])
let requestBuilder = NodeServiceAPI.lookupWithRequestBuilder(body: request, apiConfiguration: cellsApiConfig)

do {
let response: Response<RestNodeCollection> = try await requestBuilder.execute()
return response.body.nodes
return response.body.nodes ?? []
Comment on lines -117 to +125
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were build errors which I fixed, please verify @El-Fitz

Copy link
Contributor Author

@El-Fitz El-Fitz Feb 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, probably due to the change in the dependency version. They moved from a class to a struct. Thank you.

} catch {
throw .genericError(error)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//
// Wire
// Copyright (C) 2025 Wire Swiss GmbH
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.
//

import SwiftUI
import WireDesign

struct CircularIconButtonStyle: ButtonStyle {
private enum Constants {
static let backgroundColor: Color = BaseColorPalette.Neutrals.white.color
static let iconColor: Color = BaseColorPalette.Neutrals.black.color
static let strokeColor: Color = BaseColorPalette.Grays.gray40.color
static let strokeWidth: CGFloat = 1
}

let padding: CGFloat

func makeBody(configuration: Configuration) -> some View {
configuration
.label
.foregroundStyle(Constants.backgroundColor)
.overlay(Circle().stroke(Constants.strokeColor, lineWidth: Constants.strokeWidth).padding(padding))
.background(Circle().fill(Constants.iconColor).padding(padding))
// Optionally, apply a slight visual change when pressed
.opacity(configuration.isPressed ? 0.6 : 1.0)
}
}

#Preview {
Button(action: {
print("Tapped")
}, label: {
Image(systemName: "xmark.circle.fill")
.font(.system(size: 24))
.buttonStyle(CircularIconButtonStyle(padding: 2))
})
.foregroundStyle(.white)
.frame(width: 35, height: 35)
.padding(20)
.background(Color.gray)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//
// Wire
// Copyright (C) 2025 Wire Swiss GmbH
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.
//

import SwiftUI
import WireDesign

struct DeleteItemButtonViewModifier: ViewModifier {
private enum Constants {
static let iconFontSize: CGFloat = 24
static let padding: CGFloat = 2
static let buttonSize: CGFloat = 35
static let offset: CGFloat = 17.5
}

let onRemove: @Sendable () -> Void

init(onRemove: @escaping @Sendable () -> Void) {
self.onRemove = onRemove
}

func body(content: Content) -> some View {
content
.overlay(alignment: .topTrailing) {
Button(action: {
onRemove()
}, label: {
Image(systemName: "xmark.circle.fill")
.font(.system(size: Constants.iconFontSize))
})
.buttonStyle(CircularIconButtonStyle(padding: Constants.padding))
.frame(
width: Constants.buttonSize,
height: Constants.buttonSize
)
.offset(
x: Constants.offset,
y: -Constants.offset
)
}
}
}

extension View {
func deleteItemButton(onRemove: @escaping @Sendable () -> Void) -> some View {
modifier(DeleteItemButtonViewModifier(onRemove: onRemove))
}
}

#Preview {
RoundedRectangle(cornerRadius: 10)
.fill(.gray)
.deleteItemButton(onRemove: {})
.frame(width: 200, height: 200)
}
49 changes: 49 additions & 0 deletions WireCells/Sources/WireCellsUI/Components/LocalImagePreview.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// Wire
// Copyright (C) 2025 Wire Swiss GmbH
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.
//

import SwiftUI

struct LocalImagePreview: View {
private enum Constants {
static let cornerRadius: CGFloat = 10
}

let image: Image

var body: some View {
GeometryReader { geometry in
image
.resizable()
.scaledToFill()
// Image won't clip to the container's frame.
.frame(width: geometry.size.width, height: geometry.size.height)
.clipShape(RoundedRectangle(cornerRadius: Constants.cornerRadius, style: .circular))
}
}
}

#Preview {
VStack {
LocalImagePreview(image: Image("square-placeholder", bundle: .module))
.foregroundStyle(.black)
.frame(width: 200, height: 200)
.background(.white)
}
.padding()
.background(.gray)
}
Loading
Loading