closed #111 - Make grid image picker for widget eyes and mouth

This commit is contained in:
Trey t
2022-03-12 11:32:00 -06:00
parent edf6802e85
commit 055b3f4bbd
126 changed files with 1885 additions and 230 deletions

View File

@@ -15,7 +15,10 @@ struct CreateWidgetView: View {
@StateObject private var customWidget: CustomWidgetModel
@State private var mouth: CustomWidgetMouthOptions = CustomWidgetMouthOptions.defaultOption
@State private var showRightEyeImagePicker: Bool = false
@State private var showLeftEyeImagePicker: Bool = false
@State private var showMuthImagePicker: Bool = false
var widgetView: CustomWidgetView
private var randomElements: [AnyView]
@@ -41,7 +44,7 @@ struct CreateWidgetView: View {
widgetView = CustomWidgetView(customWidgetModel: customWidget)
}
func update(eye: CustomWidgetEyes, eyeOption: CustomWidgetEyeOptions) {
func update(eye: CustomWidgetEyes, eyeOption: CustomWidgeImageOptions) {
switch eye {
case .left:
customWidget.leftEye = eyeOption
@@ -59,14 +62,14 @@ struct CreateWidgetView: View {
customWidget.rightEyeColor = Color.random()
customWidget.mouthColor = Color.random()
update(eye: .left, eyeOption: CustomWidgetEyeOptions.allCases.randomElement()!)
update(eye: .right, eyeOption: CustomWidgetEyeOptions.allCases.randomElement()!)
update(mouthOption: CustomWidgetMouthOptions.allCases.randomElement()!)
update(eye: .left, eyeOption: CustomWidgeImageOptions.allCases.randomElement()!)
update(eye: .right, eyeOption: CustomWidgeImageOptions.allCases.randomElement()!)
update(mouthOption: CustomWidgeImageOptions.allCases.randomElement()!)
update(background: CustomWidgetBackGroundOptions.allCases.randomElement()!)
}
func update(mouthOption: CustomWidgetMouthOptions) {
func update(mouthOption: CustomWidgeImageOptions) {
customWidget.mouth = mouthOption
}
@@ -87,6 +90,195 @@ struct CreateWidgetView: View {
}
}
var bottomBarButtons: some View {
Group {
HStack(alignment: .center, spacing: 0) {
Button(action: {
createRandom()
}, label: {
Image(systemName: "shuffle")
.font(.title)
.foregroundColor(Color(UIColor.white))
})
.frame(minWidth: 0, maxWidth: .infinity)
.frame(height: 40)
.background(.blue)
Button(action: {
UserDefaultsStore.saveCustomWidget(widgetModel: customWidget, inUse: false)
let impactMed = UIImpactFeedbackGenerator(style: .heavy)
impactMed.impactOccurred()
dismiss()
}, label: {
Text(String(localized: "create_widget_save"))
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color(UIColor.white))
})
.frame(minWidth: 0, maxWidth: .infinity)
.frame(height: 40)
.background(.green)
Button(action: {
UserDefaultsStore.saveCustomWidget(widgetModel: customWidget, inUse: true)
let impactMed = UIImpactFeedbackGenerator(style: .heavy)
impactMed.impactOccurred()
dismiss()
}, label: {
Text(String(localized: "create_widget_use"))
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color(UIColor.white))
})
.frame(height: 40)
.frame(minWidth: 0, maxWidth: .infinity)
.background(.pink)
if customWidget.isSaved {
Button(action: {
UserDefaultsStore.deleteCustomWidget(withUUID: customWidget.uuid)
let impactMed = UIImpactFeedbackGenerator(style: .heavy)
impactMed.impactOccurred()
dismiss()
}, label: {
Image(systemName: "trash")
.font(.title)
.foregroundColor(Color(UIColor.white))
})
.frame(height: 40)
.frame(minWidth: 0, maxWidth: .infinity)
.background(.orange)
}
}
}
}
var colorOptions: some View {
Group {
VStack {
HStack(spacing: 0) {
VStack(alignment: .center) {
Text(String(localized: "create_widget_background_color"))
ColorPicker("", selection: $customWidget.bgColor)
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)
VStack(alignment: .center) {
Text(String(localized: "create_widget_inner_color"))
ColorPicker("", selection: $customWidget.innerColor)
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)
VStack(alignment: .center) {
Text(String(localized: "create_widget_face_outline_color"))
ColorPicker("", selection: $customWidget.circleStrokeColor)
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)
}
HStack(spacing: 0) {
VStack(alignment: .center) {
Text(String(localized: "create_widget_view_left_eye_color"))
ColorPicker("", selection: $customWidget.leftEyeColor)
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)
VStack(alignment: .center) {
Text(String(localized: "create_widget_view_right_eye_color"))
ColorPicker("", selection: $customWidget.rightEyeColor)
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)
VStack(alignment: .center) {
Text(String(localized: "create_widget_view_mouth_color"))
ColorPicker("", selection: $customWidget.mouthColor)
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)
}
}
.padding()
.background(
theme.currentTheme.secondaryBGColor
)
}
}
var bgImageOptions: some View {
Group {
HStack {
ForEach(CustomWidgetBackGroundOptions.selectable, id: \.self) { bg in
Image(bg.rawValue, bundle: .main)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(minWidth: 10, idealWidth: 40, maxWidth: 40,
minHeight: 10, idealHeight: 40, maxHeight: 40,
alignment: .center)
.onTapGesture {
update(background: bg)
}
}
mixBG
.onTapGesture {
update(background: .random)
}
ColorPicker("", selection: $customWidget.bgOverlayColor)
}
.padding()
.background(
theme.currentTheme.secondaryBGColor
)
}
}
var faceImageOptions: some View {
Group {
HStack(alignment: .center) {
Spacer()
VStack(alignment: .center) {
Text(String(localized: "create_widget_view_left_eye"))
.onTapGesture(perform: {
showLeftEyeImagePicker.toggle()
})
.foregroundColor(textColor)
.foregroundColor(textColor)
}
Spacer()
VStack(alignment: .center) {
Text(String(localized: "create_widget_view_right_eye"))
.onTapGesture(perform: {
showRightEyeImagePicker.toggle()
})
.foregroundColor(textColor)
}
Spacer()
VStack(alignment: .center) {
Text(String(localized: "create_widget_view_mouth"))
.onTapGesture(perform: {
showMuthImagePicker.toggle()
})
.foregroundColor(textColor)
.foregroundColor(textColor)
}
Spacer()
}
.padding()
.background(
theme.currentTheme.secondaryBGColor
)
}
}
var body: some View {
VStack(spacing: 0) {
widgetView
@@ -97,206 +289,34 @@ struct CreateWidgetView: View {
Divider().background(Color(UIColor.tertiarySystemBackground))
Group {
HStack(alignment: .center) {
Spacer()
VStack(alignment: .center) {
Menu(String(localized: "create_widget_view_left_eye")) {
ForEach(CustomWidgetEyeOptions.allCases, id: \.self) { option in
Button(action: {
update(eye: .left, eyeOption: option)
}, label: {
Label(option.rawValue, image: option.rawValue)
})
}
}
.foregroundColor(textColor)
}
Spacer()
VStack(alignment: .center) {
Menu(String(localized: "create_widget_view_right_eye")) {
ForEach(CustomWidgetEyeOptions.allCases, id: \.self) { option in
Button(action: {
update(eye: .right, eyeOption: option)
}, label: {
Label(option.rawValue, image: option.rawValue)
})
}
}
.foregroundColor(textColor)
}
Spacer()
VStack(alignment: .center) {
Menu(String(localized: "create_widget_view_mouth")) {
ForEach(CustomWidgetMouthOptions.allCases, id: \.self) { option in
Button(action: {
update(mouthOption: option)
}, label: {
Label(option.rawValue, image: option.rawValue)
})
}
}
.foregroundColor(textColor)
}
Spacer()
}
.padding()
.background(
theme.currentTheme.secondaryBGColor
)
}
faceImageOptions
Divider().background(Color(UIColor.tertiarySystemBackground))
Group {
HStack {
ForEach(CustomWidgetBackGroundOptions.selectable, id: \.self) { bg in
Image(bg.rawValue, bundle: .main)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(minWidth: 10, idealWidth: 40, maxWidth: 40,
minHeight: 10, idealHeight: 40, maxHeight: 40,
alignment: .center)
.onTapGesture {
update(background: bg)
}
}
mixBG
.onTapGesture {
update(background: .random)
}
ColorPicker("", selection: $customWidget.bgOverlayColor)
}
.padding()
.background(
theme.currentTheme.secondaryBGColor
)
}
bgImageOptions
Divider().background(Color(UIColor.tertiarySystemBackground))
Group {
VStack {
HStack(spacing: 0) {
VStack(alignment: .center) {
Text(String(localized: "create_widget_background_color"))
ColorPicker("", selection: $customWidget.bgColor)
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)
VStack(alignment: .center) {
Text(String(localized: "create_widget_inner_color"))
ColorPicker("", selection: $customWidget.innerColor)
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)
VStack(alignment: .center) {
Text(String(localized: "create_widget_face_outline_color"))
ColorPicker("", selection: $customWidget.circleStrokeColor)
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)
}
HStack(spacing: 0) {
VStack(alignment: .center) {
Text(String(localized: "create_widget_view_left_eye_color"))
ColorPicker("", selection: $customWidget.leftEyeColor)
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)
VStack(alignment: .center) {
Text(String(localized: "create_widget_view_right_eye_color"))
ColorPicker("", selection: $customWidget.rightEyeColor)
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)
VStack(alignment: .center) {
Text(String(localized: "create_widget_view_mouth_color"))
ColorPicker("", selection: $customWidget.mouthColor)
.labelsHidden()
}
.frame(minWidth: 0, maxWidth: .infinity)
}
}
.padding()
.background(
theme.currentTheme.secondaryBGColor
)
}
colorOptions
Divider().background(Color(UIColor.tertiarySystemBackground))
Group {
HStack(alignment: .center, spacing: 0) {
Button(action: {
createRandom()
}, label: {
Image(systemName: "shuffle")
.font(.title)
.foregroundColor(Color(UIColor.white))
})
.frame(minWidth: 0, maxWidth: .infinity)
.frame(height: 40)
.background(.blue)
Button(action: {
UserDefaultsStore.saveCustomWidget(widgetModel: customWidget, inUse: false)
let impactMed = UIImpactFeedbackGenerator(style: .heavy)
impactMed.impactOccurred()
dismiss()
}, label: {
Text(String(localized: "create_widget_save"))
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color(UIColor.white))
})
.frame(minWidth: 0, maxWidth: .infinity)
.frame(height: 40)
.background(.green)
Button(action: {
UserDefaultsStore.saveCustomWidget(widgetModel: customWidget, inUse: true)
let impactMed = UIImpactFeedbackGenerator(style: .heavy)
impactMed.impactOccurred()
dismiss()
}, label: {
Text(String(localized: "create_widget_use"))
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color(UIColor.white))
})
.frame(height: 40)
.frame(minWidth: 0, maxWidth: .infinity)
.background(.pink)
if customWidget.isSaved {
Button(action: {
UserDefaultsStore.deleteCustomWidget(withUUID: customWidget.uuid)
let impactMed = UIImpactFeedbackGenerator(style: .heavy)
impactMed.impactOccurred()
dismiss()
}, label: {
Image(systemName: "trash")
.font(.title)
.foregroundColor(Color(UIColor.white))
})
.frame(height: 40)
.frame(minWidth: 0, maxWidth: .infinity)
.background(.orange)
}
}
}
bottomBarButtons
}
.sheet(isPresented: $showRightEyeImagePicker) {
ImagePickerGridView(pickedImageClosure: { image in
update(eye: .right, eyeOption: image)
})
}
.sheet(isPresented: $showLeftEyeImagePicker) {
ImagePickerGridView(pickedImageClosure: { image in
update(eye: .left, eyeOption: image)
})
}
.sheet(isPresented: $showMuthImagePicker) {
ImagePickerGridView(pickedImageClosure: { image in
update(mouthOption: image)
})
}
}
}

View File

@@ -11,9 +11,9 @@ class CustomWidgetModel: ObservableObject, Codable, NSCopying {
static let numberOfBGItems = 109
static var randomWidget: CustomWidgetModel {
return CustomWidgetModel(leftEye: CustomWidgetEyeOptions.defaultOption,
rightEye: CustomWidgetEyeOptions.defaultOption,
mouth: CustomWidgetMouthOptions.defaultOption,
return CustomWidgetModel(leftEye: CustomWidgeImageOptions.defaultOption,
rightEye: CustomWidgeImageOptions.defaultOption,
mouth: CustomWidgeImageOptions.defaultOption,
background: CustomWidgetBackGroundOptions.defaultOption,
bgColor: Color.random(),
innerColor: Color.random(),
@@ -28,9 +28,9 @@ class CustomWidgetModel: ObservableObject, Codable, NSCopying {
createdDate: Date())
}
init(leftEye: CustomWidgetEyeOptions,
rightEye: CustomWidgetEyeOptions,
mouth: CustomWidgetMouthOptions,
init(leftEye: CustomWidgeImageOptions,
rightEye: CustomWidgeImageOptions,
mouth: CustomWidgeImageOptions,
background: CustomWidgetBackGroundOptions,
bgColor: Color,
innerColor: Color,
@@ -60,9 +60,9 @@ class CustomWidgetModel: ObservableObject, Codable, NSCopying {
self.createdDate = createdDate
}
@Published var leftEye: CustomWidgetEyeOptions
@Published var rightEye: CustomWidgetEyeOptions
@Published var mouth: CustomWidgetMouthOptions
@Published var leftEye: CustomWidgeImageOptions
@Published var rightEye: CustomWidgeImageOptions
@Published var mouth: CustomWidgeImageOptions
@Published var background: CustomWidgetBackGroundOptions
@Published var bgColor: Color
@@ -113,9 +113,9 @@ class CustomWidgetModel: ObservableObject, Codable, NSCopying {
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
leftEye = try container.decode(CustomWidgetEyeOptions.self, forKey: .leftEye)
rightEye = try container.decode(CustomWidgetEyeOptions.self, forKey: .rightEye)
mouth = try container.decode(CustomWidgetMouthOptions.self, forKey: .mouth)
leftEye = try container.decode(CustomWidgeImageOptions.self, forKey: .leftEye)
rightEye = try container.decode(CustomWidgeImageOptions.self, forKey: .rightEye)
mouth = try container.decode(CustomWidgeImageOptions.self, forKey: .mouth)
background = try container.decode(CustomWidgetBackGroundOptions.self, forKey: .background)
bgColor = try container.decode(Color.self, forKey: .bgColor)
@@ -197,27 +197,88 @@ enum CustomWidgetEyes: String, Codable {
case right
}
enum CustomWidgetEyeOptions: String, CaseIterable, Codable {
case fire = "fire"
case bolt = "bolt2"
case dollar = "dollar"
case bell = "bell"
case btc = "btc"
case code = "code"
case crown = "crown"
case divide = "divide"
case exclamation = "exclamation"
case fan = "fan"
case floppy = "floppy"
case x = "x"
case skull = "skull"
case covid = "covid"
case bomb = "bomb"
case skull2 = "skull2"
case poo = "poo"
static public var defaultOption: CustomWidgetEyeOptions {
CustomWidgetEyeOptions.fire
enum CustomWidgeImageOptions: String, CaseIterable, Codable {
case bolt2 = "custom_icon/bolt2"
case star_solid = "custom_icon/star-solid"
case jet_fighter_solid = "custom_icon/jet-fighter-solid"
case circle_xmark_solid = "custom_icon/circle-xmark-solid"
case frown_regular = "custom_icon/frown-regular"
case bullhorn_solid = "custom_icon/bullhorn-solid"
case caret_down_solid = "custom_icon/caret-down-solid"
case meteor_solid = "custom_icon/meteor-solid"
case eye_solid = "custom_icon/eye-solid"
case battery_half_solid = "custom_icon/battery-half-solid"
case heart_crack_solid = "custom_icon/heart-crack-solid"
case life_ring_regular = "custom_icon/life-ring-regular"
case heart_solid = "custom_icon/heart-solid"
case location_crosshairs_solid = "custom_icon/location-crosshairs-solid"
case bitcoin_brands = "custom_icon/bitcoin-brands"
case baby_solid = "custom_icon/baby-solid"
case grin_regular = "custom_icon/grin-regular"
case bell = "custom_icon/bell"
case x = "custom_icon/x"
case shuttle_space_solid = "custom_icon/shuttle-space-solid"
case floppy = "custom_icon/floppy"
case exclamation = "custom_icon/exclamation"
case chess_queen_solid = "custom_icon/chess-queen-solid"
case lightbulb_solid = "custom_icon/lightbulb-solid"
case skull_solid = "custom_icon/skull-solid"
case dice_one_solid = "custom_icon/dice-one-solid"
case arrow_up_1_9_solid = "custom_icon/arrow-up-1-9-solid"
case fan = "custom_icon/fan"
case skull = "custom_icon/skull"
case dharmachakra_solid = "custom_icon/dharmachakra-solid"
case ban_solid = "custom_icon/ban-solid"
case sad_tear_regular = "custom_icon/sad-tear-regular"
case crown = "custom_icon/crown"
case futbol_regular = "custom_icon/futbol-regular"
case fire = "custom_icon/fire"
case crosshairs_solid = "custom_icon/crosshairs-solid"
case lemon_solid = "custom_icon/lemon-solid"
case caret_right_solid = "custom_icon/caret-right-solid"
case rainbow_solid = "custom_icon/rainbow-solid"
case apple_brands = "custom_icon/apple-brands"
case missing = "custom_icon/missing"
case pizza_slice_solid = "custom_icon/pizza-slice-solid"
case empire_brands = "custom_icon/empire-brands"
case caret_up_solid = "custom_icon/caret-up-solid"
case dragon_solid = "custom_icon/dragon-solid"
case cannabis_solid = "custom_icon/cannabis-solid"
case bullseye_solid = "custom_icon/bullseye-solid"
case code_compare_solid = "custom_icon/code-compare-solid"
case battery_empty_solid = "custom_icon/battery-empty-solid"
case moon_solid = "custom_icon/moon-solid"
case android_brands = "custom_icon/android-brands"
case poo = "custom_icon/poo"
case smile_beam_regular = "custom_icon/smile-beam-regular"
case code = "custom_icon/code"
case dollar = "custom_icon/dollar"
case btc = "custom_icon/btc"
case cross_solid = "custom_icon/cross-solid"
case bomb = "custom_icon/bomb"
case battery_full_solid = "custom_icon/battery-full-solid"
case gem_solid = "custom_icon/gem-solid"
case bolt_lightning_solid = "custom_icon/bolt-lightning-solid"
case skull2 = "custom_icon/skull2"
case caret_left_solid = "custom_icon/caret-left-solid"
case fort_awesome_brands = "custom_icon/fort-awesome-brands"
case hotjar_brands = "custom_icon/hotjar-brands"
case burger_solid = "custom_icon/burger-solid"
case egg_solid = "custom_icon/egg-solid"
case meh_regular = "custom_icon/meh-regular"
case battery_three_quarters_solid = "custom_icon/battery-three-quarters-solid"
case clock_solid = "custom_icon/clock-solid"
case battery_quarter_solid = "custom_icon/battery-quarter-solid"
case fly_brands = "custom_icon/fly-brands"
case baseball_solid = "custom_icon/baseball-solid"
case divide = "custom_icon/divide"
case covid = "custom_icon/covid"
case dice_d20_solid = "custom_icon/dice-d20-solid"
case microphone_solid = "custom_icon/microphone-solid"
case peace_solid = "custom_icon/peace-solid"
static public var defaultOption: CustomWidgeImageOptions {
CustomWidgeImageOptions.fire
}
public var image: Image {

View File

@@ -0,0 +1,50 @@
//
// ImagePickerGrid.swift
// Feels (iOS)
//
// Created by Trey Tartt on 3/12/22.
//
import SwiftUI
struct ImagePickerGridView: View {
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
@Environment(\.presentationMode) var presentationMode
@State var column = Array(repeating: GridItem(.flexible(), spacing: 10), count: 7)
let pickedImageClosure: ((CustomWidgeImageOptions) -> Void)
@AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = .black
var body: some View {
VStack {
ScrollView {
LazyVGrid(columns: column,spacing: 10, content: {
ForEach(CustomWidgeImageOptions.allCases, id:\.self) { item in
Image(item.rawValue)
.resizable()
.scaledToFit()
.frame(width: 40, height: 40)
.foregroundColor(textColor)
.onTapGesture {
pickedImageClosure(item)
presentationMode.wrappedValue.dismiss()
}
}
})
}
.padding()
Spacer()
}
.background(
theme.currentTheme.bg
.edgesIgnoringSafeArea(.all)
)
}
}
struct ImagePickerGridView_Previews: PreviewProvider {
static var previews: some View {
ImagePickerGridView(pickedImageClosure: { image in
})
}
}