Skip to content

Profile image generator. #108

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

Draft
wants to merge 20 commits into
base: development
Choose a base branch
from
Draft
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
108 changes: 64 additions & 44 deletions Project SF.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions Project SF/Models/ImageStore.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// ImageStore.swift
// Project SF
//
// Created by Roman Esin on 18.07.2020.
//

import UIKit

// TODO: Finish this thing...
@propertyWrapper
struct ImageStore {
var key: String
var storage = UserDefaults.standard

var wrappedValue: UIImage? {
get {
guard let data = storage.value(forKey: key) as? Data else { return nil }
return UIImage(data: data)
}
set { storage.setValue(newValue?.pngData(), forKey: key) }
}

init(_ key: String, wrappedValue: UIImage) {
self.key = key
self.wrappedValue = wrappedValue
}
}
81 changes: 81 additions & 0 deletions Project SF/Models/Pixel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//
// Pixel.swift
// Project SF
//
// Created by Roman Esin on 16.07.2020.
//

import SwiftUI

// swiftlint:disable identifier_name
struct Pixel {
var a: UInt8
var r: UInt8
var g: UInt8
var b: UInt8
}

class PixelImage {
var width: Int
var height: Int
var pixels: [Pixel]

static func random(width: Int, height: Int) -> PixelImage {
var pixels: [Pixel] = []
for _ in 0..<(width * height) {
pixels.append(Pixel(a: 255,
r: .random(in: 0...255),
g: .random(in: 0...255),
b: .random(in: 0...255)))
}
return PixelImage(width: width, height: height, pixels: pixels)
}

/// Returns random symmetrixal `PixelImage` with given size.
/// - Parameters:
/// - width: Width of the image.
/// - height: Height of the image.
/// - Returns: Random symmetrixal `PixelImage` with given size.
static func randomSymmetrical(color: Color, width: Int, height: Int) -> PixelImage {
var pixels: [Pixel] = []
let clear = Pixel(a: 0,
r: 0,
g: 0,
b: 0)

let uiColor = UIColor(color)
var a: CGFloat = 0
var r: CGFloat = 0
var g: CGFloat = 0
var b: CGFloat = 0
uiColor.getRed(&r, green: &g, blue: &b, alpha: &a)

let color = Pixel(a: 255,
r: UInt8(r * 255),
g: UInt8(g * 255),
b: UInt8(b * 255))

var slice: [Pixel] = []
let num = width % 2
for _ in 0..<height {
loop: for j in 0..<width {
if j - num == width / 2 {
pixels.append(contentsOf: slice[..<(slice.count - num)].reversed())
slice = []
break loop
} else {
let color = Bool.random() ? clear : color
pixels.append(color)
slice.append(color)
}
}
}
return PixelImage(width: width, height: height, pixels: pixels)
}

init(width: Int, height: Int, pixels: [Pixel]) {
self.width = width
self.height = height
self.pixels = pixels
}
}
36 changes: 36 additions & 0 deletions Project SF/Utilities/Extensions/UIImage+PixelData.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// UIImage+PixelData.swift
// Project SF
//
// Created by Roman Esin on 16.07.2020.
//

import UIKit

extension UIImage {
convenience init?(pixelImage: PixelImage) {
let width = pixelImage.width
let height = pixelImage.height
let pixels = pixelImage.pixels

guard width > 0 && height > 0, pixels.count == width * height else { return nil }
var data = pixels
guard let providerRef = CGDataProvider(data: Data(bytes: &data,
count: data.count * MemoryLayout<Pixel>.size) as CFData)
else { return nil }
guard let cgim = CGImage(
width: width,
height: height,
bitsPerComponent: 8,
bitsPerPixel: 32,
bytesPerRow: width * MemoryLayout<Pixel>.size,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue),
provider: providerRef,
decode: nil,
shouldInterpolate: false,
intent: .defaultIntent)
else { return nil }
self.init(cgImage: cgim)
}
}
28 changes: 28 additions & 0 deletions Project SF/Views/NavigationBarLabel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,34 @@ struct NavigationLabel<Destination: View>: View {
}
}

struct NavigationBarButton: View {

let title: String?
let systemName: String
let action: () -> Void

var body: some View {
Button(
action: action,
label: {
if let title = title {
Label(title, systemImage: systemName)
.font(.title2)
} else {
Image(systemName: systemName)
.font(.title2)
}
}
)
}

init(title: String? = nil, systemName: String, action: @escaping () -> Void) {
self.title = title
self.systemName = systemName
self.action = action
}
}

struct NavigationButton: View {

let title: String? = nil
Expand Down
2 changes: 1 addition & 1 deletion Project SF/Views/Tabs/Competitions/CompetitionCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ struct CompetitionCell: View {
struct CompetitionCell_Previews: PreviewProvider {

static var previews: some View {
var competitions: [Competition] = [
let competitions: [Competition] = [
Competition(
name: "Competition1",
startDate: Date() - 100000,
Expand Down
12 changes: 11 additions & 1 deletion Project SF/Views/Tabs/Competitions/CompetitionDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ struct CompetitionDetailView: View {

struct CompetitionDetailView_Previews: PreviewProvider {
static var previews: some View {
CompetitionDetailView(competition: Competition(name: "Competition Name", startDate: Date(), endDate: Date() + 123))
CompetitionDetailView(competition: Competition(
name: "Competition2",
startDate: Date(),
endDate: Date() + 1000000,
creatingUser: CompetingPerson(name: "Me", points: 5500),
people: [
CompetingPerson(name: "Person1", points: 5000),
CompetingPerson(name: "Person2", points: 200),
CompetingPerson(name: "Person3", points: 500)
]
))
}
}
72 changes: 72 additions & 0 deletions Project SF/Views/Tabs/Profile/Settings/ProfileImageCreator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//
// ProfileImageCreator.swift
// Project SF
//
// Created by Roman Esin on 16.07.2020.
//

import SwiftUI

struct ProfileImageCreator: View {

@Environment(\.presentationMode) var presentationMode
@Binding var image: UIImage?
@Binding var color: Color

var body: some View {
NavigationView {
VStack {
if let image = image {
Image(uiImage: image)
.interpolation(.none)
.renderingMode(.template)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 200, height: 200)
.clipShape(Circle())
.foregroundColor(color)

GroupBox {
ColorPicker("Select foreground color", selection: $color, supportsOpacity: false)
}
.padding(.top)
}
RoundedButton("Generate image") {
withAnimation {
image = UIImage(pixelImage: .randomSymmetrical(color: .white, width: 7, height: 7))
}
}
.padding(.top)
}
.padding(.horizontal)
.navigationTitle("Profile Image Creator")
}
.onDisappear {
if image == nil {
color = .clear
}
}
}

init(_ image: Binding<UIImage?>, color: Binding<Color>) {
DispatchQueue.main.async {
var shouldRemoveImage = false
if color.wrappedValue == .clear {
color.wrappedValue = .black
shouldRemoveImage = true
}
if image.wrappedValue != nil && shouldRemoveImage {
image.wrappedValue = nil
}
}
_image = image
_color = color
}
}

struct ProfileImageCreator_Previews: PreviewProvider {
static var previews: some View {
ProfileImageCreator(.constant(UIImage(pixelImage: .randomSymmetrical(color: .red, width: 10, height: 10))),
color: .constant(Color.red))
}
}
62 changes: 49 additions & 13 deletions Project SF/Views/Tabs/Profile/Settings/ProfileSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,45 @@ struct ProfileSettings: View {
@StateObject var keyboard = KeyboardManager()

@State var profilePicture: UIImage?
@State var showImageSelectionView = false
@State var color = Color.clear

@State var showSheet = false
@State var selectedSheet = 0
@State var showSelectAlert = false

var body: some View {
// This VStack and empty text is required to fix the navigation title glitching out on scroll
// so ScrollView isn't the topmost view.
NavScrollView {
Button(action: {
showImageSelectionView = true
}, label: {
// profilePicture = UIImage(pixelImage: .randomSymmetrical(width: 6, height: 6))
showSelectAlert = true
}) {
if profilePicture == nil {
Image(systemName: "person.crop.circle.badge.plus")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 100, height: 100)
} else {
Image(uiImage: profilePicture!)
.renderingMode(.original)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 100, height: 100)
.clipShape(Circle())
if color != .clear {
Image(uiImage: profilePicture!)
.interpolation(.none)
.renderingMode(.template)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 100, height: 100)
.clipShape(Circle())
.foregroundColor(color)
} else {
Image(uiImage: profilePicture!)
.renderingMode(.original)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 100, height: 100)
.clipShape(Circle())
}
}
})
.padding(.bottom)
}

TextField("Name", text: $name)
.font(.headline)
Expand Down Expand Up @@ -86,8 +101,29 @@ struct ProfileSettings: View {
}
.padding(.horizontal)
.navigationTitle("Profile")
.sheet(isPresented: $showImageSelectionView) {
ImageSelectionView(image: $profilePicture)
.actionSheet(isPresented: $showSelectAlert) {
ActionSheet(title: Text("Select profile image"),
message: nil,
buttons: [
.default(Text("Open profile image creator"), action: {
selectedSheet = 0
showSheet = true
}), .default(Text("Select from image gallery"), action: {
selectedSheet = 1
showSheet = true
}), .cancel()])
}
.onChange(of: showSheet, perform: { showSheet in
if !showSheet && selectedSheet == 1 {
color = .clear
}
})
.sheet(isPresented: $showSheet) {
if selectedSheet == 0 {
ProfileImageCreator($profilePicture, color: $color)
} else {
ImageSelectionView(image: $profilePicture)
}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions Project SF/Views/Tabs/Profile/Settings/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ struct AboutFooter: View {
}

struct SettingsView: View {

@Environment(\.presentationMode) var presentationMode

var body: some View {
List {
Section(header: Text("General")) {
Expand Down