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

cloudinary setup #20

Open
wants to merge 1 commit into
base: main
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
Binary file modified .DS_Store
Binary file not shown.
70 changes: 70 additions & 0 deletions ImagePicker.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//
// ImagePicker.swift
//
// Created by Dan Gullis on 19/02/2024.
//

//ObservableObject: A protocol that allows SwiftUI to observe changes to a class's properties. When a property marked with @Published changes, any views observing the object will be notified and re-rendered with the new data.

//@Published: A property wrapper that marks a property as observable. When the value of a @Published property changes, it notifies any views that are observing the object to update their state.

//@StateObject: A property wrapper used in SwiftUI to create and manage a reference to an observable object. It ensures that the object it wraps remains alive for use in the view where it is declared and in any views that share it. This is particularly important for objects that conform to the ObservableObject protocol.

//The use of ObservableObject, @StateObject, and @Published in SwiftUI allows for a reactive programming model where the UI automatically updates in response to changes in the underlying data model.

// this class uses SwiftUI and PhotosUI framework to select images form the user photo library
// uses cloudinary framework to upload selected image to cloudinary account

import SwiftUI
import PhotosUI
import Cloudinary

class ImagePicker: ObservableObject {
// variable to store image data once its loaded
@Published var imageData: Data?
// varible to represent the selected item - when this changes the didset block is executed
@Published var imageSelection: PhotosPickerItem? {
didSet {
if let imageSelection {
Task {
try await loadTransferable(from: imageSelection)
}
}
}
}
// asynchronous function loads image data from selected photoPickerItem
// if sucessful assigns image data to imageData variable
func loadTransferable(from imageSelection: PhotosPickerItem?) async throws {
do {
if let imageData = try await imageSelection?.loadTransferable(type: Data.self) {
self.imageData = imageData
}
} catch {
print(error.localizedDescription)
imageData=nil
}
}

// uploads image data to cloudinary returns public ID of image on completion
func uploadToCloudinary(data: Data, completion: @escaping (String?) -> Void){
let config = CLDConfiguration(cloudName: "dbhtb2iqe", secure: true)
let cloudinary = CLDCloudinary(configuration: config)
let uploader = cloudinary.createUploader()

let uploadParams = CLDUploadRequestParams().setFolder("acebook-mobile")

uploader.upload(data: data, uploadPreset: "acebook-user-image", params: uploadParams, completionHandler: {result, error in
if let error = error {
print("upload error \(error)")
completion(nil)
} else if let result = result, let imagePublicId = result.publicId {
completion(imagePublicId)
} else {
completion(nil)
}

})

}

}
43 changes: 43 additions & 0 deletions MobileAcebook.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
AE5D85E32AC9AFD2009680C6 /* MockAuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE5D85E22AC9AFD2009680C6 /* MockAuthenticationService.swift */; };
AE5D85E62AC9B077009680C6 /* AuthenticationServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE5D85E52AC9B077009680C6 /* AuthenticationServiceProtocol.swift */; };
AE5D85E82AC9B29A009680C6 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE5D85E72AC9B29A009680C6 /* User.swift */; };
F390892E2B83ABEA000D4C06 /* Cloudinary in Frameworks */ = {isa = PBXBuildFile; productRef = F390892D2B83ABEA000D4C06 /* Cloudinary */; };
F39089572B84B5C3000D4C06 /* UserPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39089562B84B5C3000D4C06 /* UserPageView.swift */; };
F39089592B84B5D9000D4C06 /* ImagePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39089582B84B5D9000D4C06 /* ImagePicker.swift */; };
F390895B2B84CCEF000D4C06 /* CloudinaryConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = F390895A2B84CCEF000D4C06 /* CloudinaryConfig.swift */; };
F390895D2B84CDCB000D4C06 /* CloudinaryImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F390895C2B84CDCB000D4C06 /* CloudinaryImageView.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -54,13 +59,18 @@
AE5D85E22AC9AFD2009680C6 /* MockAuthenticationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAuthenticationService.swift; sourceTree = "<group>"; };
AE5D85E52AC9B077009680C6 /* AuthenticationServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationServiceProtocol.swift; sourceTree = "<group>"; };
AE5D85E72AC9B29A009680C6 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
F39089562B84B5C3000D4C06 /* UserPageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserPageView.swift; sourceTree = "<group>"; };
F39089582B84B5D9000D4C06 /* ImagePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePicker.swift; sourceTree = "<group>"; };
F390895A2B84CCEF000D4C06 /* CloudinaryConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudinaryConfig.swift; sourceTree = "<group>"; };
F390895C2B84CDCB000D4C06 /* CloudinaryImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudinaryImageView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
AE5D85A92AC8A221009680C6 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F390892E2B83ABEA000D4C06 /* Cloudinary in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -84,6 +94,7 @@
AE5D85A32AC8A221009680C6 = {
isa = PBXGroup;
children = (
F39089582B84B5D9000D4C06 /* ImagePicker.swift */,
AE5D85AE2AC8A221009680C6 /* MobileAcebook */,
AE5D85BF2AC8A224009680C6 /* MobileAcebookTests */,
AE5D85C92AC8A224009680C6 /* MobileAcebookUITests */,
Expand Down Expand Up @@ -111,6 +122,9 @@
AE5D85B32AC8A224009680C6 /* Assets.xcassets */,
AE5D85B52AC8A224009680C6 /* Preview Content */,
AE5D85D92AC8A337009680C6 /* WelcomePageView.swift */,
F390895A2B84CCEF000D4C06 /* CloudinaryConfig.swift */,
F39089562B84B5C3000D4C06 /* UserPageView.swift */,
F390895C2B84CDCB000D4C06 /* CloudinaryImageView.swift */,
);
path = MobileAcebook;
sourceTree = "<group>";
Expand Down Expand Up @@ -190,6 +204,9 @@
dependencies = (
);
name = MobileAcebook;
packageProductDependencies = (
F390892D2B83ABEA000D4C06 /* Cloudinary */,
);
productName = MobileAcebook;
productReference = AE5D85AC2AC8A221009680C6 /* MobileAcebook.app */;
productType = "com.apple.product-type.application";
Expand Down Expand Up @@ -262,6 +279,9 @@
Base,
);
mainGroup = AE5D85A32AC8A221009680C6;
packageReferences = (
F390892C2B83ABEA000D4C06 /* XCRemoteSwiftPackageReference "cloudinary_ios" */,
);
productRefGroup = AE5D85AD2AC8A221009680C6 /* Products */;
projectDirPath = "";
projectRoot = "";
Expand Down Expand Up @@ -305,9 +325,13 @@
buildActionMask = 2147483647;
files = (
AE5D85E12AC9AFA9009680C6 /* AuthenticationService.swift in Sources */,
F390895B2B84CCEF000D4C06 /* CloudinaryConfig.swift in Sources */,
AE5D85E62AC9B077009680C6 /* AuthenticationServiceProtocol.swift in Sources */,
F39089572B84B5C3000D4C06 /* UserPageView.swift in Sources */,
AE5D85B02AC8A221009680C6 /* MobileAcebookApp.swift in Sources */,
F39089592B84B5D9000D4C06 /* ImagePicker.swift in Sources */,
AE5D85E82AC9B29A009680C6 /* User.swift in Sources */,
F390895D2B84CDCB000D4C06 /* CloudinaryImageView.swift in Sources */,
AE5D85DA2AC8A337009680C6 /* WelcomePageView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -629,6 +653,25 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
F390892C2B83ABEA000D4C06 /* XCRemoteSwiftPackageReference "cloudinary_ios" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/cloudinary/cloudinary_ios.git";
requirement = {
branch = master;
kind = branch;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
F390892D2B83ABEA000D4C06 /* Cloudinary */ = {
isa = XCSwiftPackageProductDependency;
package = F390892C2B83ABEA000D4C06 /* XCRemoteSwiftPackageReference "cloudinary_ios" */;
productName = Cloudinary;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = AE5D85A42AC8A221009680C6 /* Project object */;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"pins" : [
{
"identity" : "cloudinary_ios",
"kind" : "remoteSourceControl",
"location" : "https://github.com/cloudinary/cloudinary_ios.git",
"state" : {
"branch" : "master",
"revision" : "26d2c43324c623d2495a6c127d1a8da1549370ce"
}
}
],
"version" : 2
}
17 changes: 17 additions & 0 deletions MobileAcebook/CloudinaryConfig.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// CloudinaryConfig.swift
// MobileAcebook
//
// Created by Dan Gullis on 20/02/2024.
//

import Cloudinary

struct CloudinaryConfig {
static let cloudName = "dbhtb2iqe"
static let secure = true

static var configuration: CLDConfiguration {
return CLDConfiguration(cloudName: cloudName, secure: secure)
}
}
34 changes: 34 additions & 0 deletions MobileAcebook/CloudinaryImageView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// CloudinaryImageView.swift
// MobileAcebook
//
// Created by Dan Gullis on 20/02/2024.
//

import SwiftUI
import Cloudinary

func cloudinaryImageView(cloudinary: CLDCloudinary, imagePath: String) -> some View {
VStack {
if let cloudinaryURL = cloudinary.createUrl().generate(imagePath) {
if let url = URL(string: cloudinaryURL) {
AsyncImage(url: url) { image in
image
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 100, height: 100)
.clipped()
.clipShape(Circle())

} placeholder: {
ProgressView() // Show a progress view while the image is loading
}
} else {
// Placeholder view if the URL is not valid
Text("Invalid URL")
}
} else {
Text("Image not found")
}
}
}
40 changes: 40 additions & 0 deletions MobileAcebook/UserPageView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// UserPageView.swift
// MobileAcebook
//
// Created by Dan Gullis on 20/02/2024.
//

import SwiftUI
import Cloudinary


struct UserPageView: View {
let cloudinary = CLDCloudinary(configuration: CloudinaryConfig.configuration)

var body: some View {
NavigationView{
VStack {
HStack {
// replace image path with publicId of user image from sign up
cloudinaryImageView(cloudinary: cloudinary, imagePath: "acebook-mobile/Screenshot_2024-02-20_at_11.23.41_qd0jaw")

Text("username")
}

Spacer ()
}
}
}

}



struct UserPageView_Previews: PreviewProvider {
static var previews: some View {
UserPageView()
}
}


81 changes: 52 additions & 29 deletions MobileAcebook/WelcomePageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,64 @@
//

import SwiftUI
import PhotosUI
import Cloudinary


struct WelcomePageView: View {
@StateObject var imagePicker = ImagePicker()
@State private var uploadedImagePublicId: String?
var body: some View {
ZStack {
VStack {
Spacer()

Text("Welcome to Acebook!")
.font(.largeTitle)
.padding(.bottom, 20)
.accessibilityIdentifier("welcomeText")

Spacer()

Image("makers-logo")
.resizable()
.scaledToFit()
.frame(width: 200, height: 200)
.accessibilityIdentifier("makers-logo")

Spacer()

Button("Sign Up") {
// TODO: sign up logic
NavigationView {
ZStack {
VStack {
Spacer()

Text("Welcome to Acebook!")
.font(.largeTitle)
.padding(.bottom, 20)
.accessibilityIdentifier("welcomeText")

Spacer()

Image("makers-logo")
.resizable()
.scaledToFit()
.frame(width: 200, height: 200)
.accessibilityIdentifier("makers-logo")

Spacer()

Button("Sign Up") {
// TODO: sign up logic
}
.accessibilityIdentifier("signUpButton")


NavigationLink("user page", destination: UserPageView())

PhotosPicker(selection: $imagePicker.imageSelection) {
Text("upload a photo")
}
.onChange(of: imagePicker.imageData) { imageData in
// This block is executed when image data is set in the ImagePicker
// You can update the uploadedImagePublicId here
if let imageData = imageData {
imagePicker.uploadToCloudinary(data: imageData) { imagePublicId in
uploadedImagePublicId = imagePublicId
}
}
}
Spacer()

}
.accessibilityIdentifier("signUpButton")

Spacer()
}
}
}
}

struct WelcomePageView_Previews: PreviewProvider {
static var previews: some View {
WelcomePageView()
struct WelcomePageView_Previews: PreviewProvider {
static var previews: some View {
WelcomePageView()
}
}
}