Skip to content

Commit

Permalink
Merge branch 'juri' into refactor/#146-reportNavigationMVI
Browse files Browse the repository at this point in the history
  • Loading branch information
juri123123 committed Jan 27, 2025
2 parents 38ece9d + 382a4df commit 5cd1ba6
Show file tree
Hide file tree
Showing 11 changed files with 108 additions and 43 deletions.
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@
<br>



# **🍎 iOS Developer**

|이지훈</br>[@hooni0918](https://github.com/hooni0918)|최안용</br>[@ChoiAnYong](https://github.com/ChoiAnYong)|최주리</br>[@juri123123](https://github.com/juri123123)|이명진</br>[@thingineeer](https://github.com/thingineeer)|
|:---:|:---:|:---:|:---:|
|<img src = "https://github.com/user-attachments/assets/c902e0b5-2d59-4ee1-ae67-404d987342de" width ="250">|<img src = "https://github.com/user-attachments/assets/f9a78b97-09bf-4816-a6e4-a4e74deea41d" width ="250">|<img src = "https://github.com/user-attachments/assets/d84163d3-cccd-4bac-8a0f-ba3e34d79880" width ="250">|<img src = "https://github.com/user-attachments/assets/e62ef571-917f-4668-b657-321e9b1a8375" width ="250">|
|<img src = "https://github.com/user-attachments/assets/6cacd948-f678-4cf8-936a-5ceb7c2880d7" width ="250">|<img src = "https://github.com/user-attachments/assets/aef88d62-6007-410d-a6b3-a228cae59ab8" width ="250">|<img src = "https://github.com/user-attachments/assets/04e4c8f6-0acc-489e-ad91-20d8c71baf4d" width ="250">|<img src = "https://github.com/user-attachments/assets/7434cdf9-3153-4259-8a2d-82baa25282a7" width ="250">|
|`메인 지도`,`장소검색`|`등록하기`|`등록장소 리스트`, `신고하기`| `등록장소 디테일뷰`|
</br>


# **⚒️** Tech stack & Architecture
<img src="https://img.shields.io/badge/SwiftUI-2C68B5?&style=flat-square&logo=Swift&logoColor=white"/> <img src="https://img.shields.io/badge/Xcode_16-147EFB?style=flat-square&logo=Xcode&logoColor=white"/> <img src="https://img.shields.io/badge/Swift_Concurrency-FF3E00?style=flat-square&logo=Swift&logoColor=white"/>

Expand All @@ -48,6 +48,24 @@
![의존관계도](https://github.com/user-attachments/assets/aa247fb7-ce0b-4300-8753-e884c24cffcb)


# 시연영상
# SpoonMe
| 지도 | 장소검색 |
|:-:|:-:|
| <img src="https://github.com/user-attachments/assets/b6421bba-5848-4bdb-87ac-a0ec883f0b8e" width="180"/> | <img src="https://github.com/user-attachments/assets/bbdbad16-37a9-442e-9755-b61142154141" width="180"/> |

| 떠먹기 | 네이버 길찾기 |
|:-:|:-:|
| <img src="https://github.com/user-attachments/assets/06d05895-8c86-4aa4-a2c9-3631839537a8" width="180"/> | <img src="https://github.com/user-attachments/assets/619bc050-7929-4bd5-95b8-b6250bdf7ce8" width="180"/> |

| 탐색 리스트 조회 | 지도 리스트 떠먹기 | 신고하기 |
|:-:|:-:|:-:|
| <img src="https://github.com/user-attachments/assets/0b393820-b921-4e6a-9210-c2573c23bcf7" width="180"/> | <img src="https://github.com/user-attachments/assets/78e9d4f8-1741-4558-b945-b8c2333e71b2" width="180"/> | <img src="https://github.com/user-attachments/assets/a536e9cb-a797-4b3a-8426-328e34d93215" width="180"/> |

| 등록 1단계 | 등록 2단계 |
|:-:|:-:|
| <img src="https://github.com/user-attachments/assets/642e1274-a91e-460c-8b7d-6a332cc43981" width="180"/> | <img src="https://github.com/user-attachments/assets/ad0203eb-b17f-4fb9-a997-f038679d3f64" width="180"/> |

# **🌀 Library**

| library | description | version |
Expand Down
12 changes: 7 additions & 5 deletions Spoony-iOS/Spoony-iOS/Resource/Components/SpoonyTextEditor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,10 @@ extension SpoonyTextEditor {
// MARK: - customTextEditor
private var customTextEditor: some View {
let borderColor: Color = {
if errorState == .noError, isFocused {
return .main400
} else if errorState == .noError || errorState == .initial {
return .gray100
if isFocused {
return errorState == .noError || errorState == .initial ? .main400 : .error400
} else {
return .error400
return errorState == .noError || errorState == .initial ? .gray100 : .error400
}
}()

Expand Down Expand Up @@ -197,3 +195,7 @@ public enum TextEditorErrorState: Equatable {
self == .maximumInputError(style: .review) || self == .maximumInputError(style: .report)
}
}

#Preview {
SpoonyTextEditor(text: .constant(" "), style: .review, placeholder: "dk", isError: .constant(true))
}
44 changes: 28 additions & 16 deletions Spoony-iOS/Spoony-iOS/Resource/Components/SpoonyTextField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,23 +77,25 @@ extension SpoonyTextField {
.customFont(.body2m)
.foregroundStyle(.gray500)
}
.autocapitalization(.none)
.autocapitalization(.none)
.autocorrectionDisabled()
.focused($isFocused)
.customFont(.body2m)
.foregroundStyle(.gray900)
.onChange(of: text) { oldValue, newValue in
.onChange(of: text) { _, newValue in
if style != .icon {
switch checkInputError(newValue) {
let removeText = newValue.removeCharacters()

switch checkInputError(removeText) {
case .maximumInputError:
errorState = .maximumInputError
text = String(newValue.prefix(30))
text = String(removeText.prefix(30))
case .minimumInputError:
errorState = .minimumInputError
case .invalidInputError:
text = oldValue
text = removeText
case .noError, .initial:
errorState = .noError
text = removeText
}
}
}
Expand All @@ -102,7 +104,7 @@ extension SpoonyTextField {
errorState = .noError
}
}
.onChange(of: errorState) {
.onChange(of: errorState) {
switch errorState {
case .noError:
isError = false
Expand Down Expand Up @@ -174,13 +176,7 @@ extension SpoonyTextField {
// MARK: - Functions
extension SpoonyTextField {
private func checkInputError(_ input: String) -> TextFieldErrorState {
let trimmedText = text.replacingOccurrences(of: " ", with: "")
let regex = "^[a-zA-Z0-9ㄱ-ㅎㅏ-ㅣ가-힣\\x20\\p{P}\\$\\^\\+=₩|~<>¥£]*$"
let predicate = NSPredicate(format: "SELF MATCHES %@", regex)

if !predicate.evaluate(with: input) {
return .invalidInputError
}
let trimmedText = input.replacingOccurrences(of: " ", with: "")

if trimmedText.isEmpty {
return .minimumInputError
Expand Down Expand Up @@ -270,7 +266,6 @@ public enum SpoonyTextFieldStyle: Equatable {
public enum TextFieldErrorState {
case maximumInputError
case minimumInputError
case invalidInputError
case noError
case initial

Expand All @@ -280,8 +275,25 @@ public enum TextFieldErrorState {
return "글자 수 30자 이하로 입력해 주세요"
case .minimumInputError:
return "한 줄 소개는 필수예요"
case .noError, .invalidInputError, .initial:
case .noError, .initial:
return nil
}
}
}


extension String {
func removeCharacters() -> String {
return .init(
unicodeScalars.filter { scalar in
let isEmoji = scalar.properties.isEmoji || scalar.properties.isEmojiPresentation
let isControlCharacter = scalar.value == 8203 || scalar.value == 8204 || scalar.value == 8205 || scalar.value == 0x200B
let isSpecialCharacter = scalar == "*" || scalar == "#"
let isInvisibleSpace = scalar.value == 0x200B || scalar.value == 0x200C || scalar.value == 0x200D // Invisible space characters

return (!isEmoji && !isControlCharacter && !isInvisibleSpace) || scalar.properties.numericType == .decimal || isSpecialCharacter
}
.reduce(into: "") { $0 += String($1) }
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct DetailState {
var iconTextColor: String = ""
var iconBackgroundColor: String = ""
var categoryColorResponse: DetailCategoryColorResponse = .init(categoryName: "", iconUrl: "", iconTextColor: "", iconBackgroundColor: "", categoryId: 0)
var isMine: Bool = true
var isMine: Bool = false
var spoonCount: Int = 0

// 추가 상태
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,10 @@ struct DetailView: View {
.onAppear {
store.send(intent: .getInitialValue(userId: Config.userId, postId: postId))

print("1️⃣ \(store.state.successService)")
// 상태 확인 후 네비게이션 처리
if !store.state.successService {
navigationManager.pop(1)
}

print("2️⃣ \(store.state.successService)")
}
.onChange(of: store.state.toast) { _, newValue in
toastMessage = newValue
Expand Down Expand Up @@ -125,7 +122,7 @@ extension DetailView {

Spacer()

if store.state.isMine {
if !store.state.isMine {
Image(.icMenu)
.onTapGesture {
isPresented.toggle()
Expand Down Expand Up @@ -154,7 +151,7 @@ extension DetailView {
.scaledToFill()
.frame(width: 335.adjusted)
.frame(height: 335.adjustedH)
.blur(radius: store.state.isScoop ? 0 : 12)
.blur(radius: (store.state.isScoop || store.state.isMine) ? 0 : 12)
.cornerRadius(11.16)
.padding(EdgeInsets(top: 0, leading: 20.adjusted, bottom: 32.adjustedH, trailing: 20.adjusted))
} else {
Expand All @@ -165,7 +162,7 @@ extension DetailView {
.scaledToFill()
.frame(width: 278.adjusted)
.frame(height: 278.adjustedH)
.blur(radius: store.state.isScoop ? 0 : 12)
.blur(radius: (store.state.isScoop || store.state.isMine) ? 0 : 12)
.cornerRadius(11.16)
}
}
Expand All @@ -182,7 +179,7 @@ extension DetailView {
chip: store.state.categoryColorResponse.toEntity()
)

Text(store.state.description.splitZeroWidthSpace())
Text(store.state.title)
.customFont(.title1b)
.foregroundStyle(.black)

Expand All @@ -193,9 +190,16 @@ extension DetailView {
Spacer()
.frame(height: 16.adjustedH)

Text(store.state.description.splitZeroWidthSpace())
.customFont(.body2m)
.foregroundStyle(.gray900)
Text(
(store.state.isScoop || store.state.isMine)
? store.state.description.splitZeroWidthSpace()
: (store.state.description.count > 120
? "\(store.state.description.prefix(120))...".splitZeroWidthSpace()
: store.state.description.splitZeroWidthSpace())
)
.customFont(.body2m)
.frame(width: 335.adjusted)
.foregroundStyle(.black)

}
.padding(EdgeInsets(top: 0, leading: 20.adjusted, bottom: 32.adjustedH, trailing: 20.adjusted))
Expand Down Expand Up @@ -233,7 +237,7 @@ extension DetailView {

}
.padding(.horizontal, 20.adjusted)
.blur(radius: store.state.isScoop ? 0 : 8)
.blur(radius: (store.state.isScoop || store.state.isMine) ? 0 : 12)
}

private var menuInfo: some View {
Expand Down Expand Up @@ -277,9 +281,9 @@ extension DetailView {
HStack(spacing: 0) {
SpoonyButton(
style: .secondary,
size: store.state.isScoop ? .medium : .xlarge,
title: store.state.isScoop ? "길찾기" : "떠먹기",
isIcon: store.state.isScoop ? false : true,
size: (store.state.isScoop) ? .medium : .xlarge,
title: (store.state.isScoop || store.state.isMine) ? "길찾기" : "떠먹기",
isIcon: (store.state.isScoop || store.state.isMine) ? false : true,
disabled: .constant(false)
) {
print("⭐️")
Expand Down Expand Up @@ -378,5 +382,3 @@ struct Line: Shape {
return path
}
}

//
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct ExploreState {
var spoonCount: Int = 0

//TODO: 현재 위치 받아와서 바꾸기
var selectedLocation: SeoulType = .gangnam
var selectedLocation: SeoulType = .mapo
var tempLocation: SeoulType?

var selectedFilter: FilterType = .latest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import PhotosUI
struct RegisterState {
// MARK: - Register
var registerStep: RegisterStep = .start
var isLoading: Bool = false

// MARK: - InfoStepView
var placeText: String = ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,11 @@ final class RegisterStore: ObservableObject {
case .didTapPhoto(let items):
validateSelectedPhotoCount(item: items)
case .updateKeyboardHeight(let height):
state.keyboardHeight = height
Task {
await MainActor.run {
state.keyboardHeight = height
}
}
}
}
}
Expand Down Expand Up @@ -306,6 +310,9 @@ extension RegisterStore {

Task {
do {
await MainActor.run {
state.isLoading = true
}
let success = try await network.registerPost(
request: request,
imagesData: state.uploadImages.map {
Expand All @@ -314,12 +321,14 @@ extension RegisterStore {
await MainActor.run {
if success {
state.registerStep = .end
state.isLoading = false
navigationManager.dispatch(.showPopup(.registerSuccess(action: {
self.navigationManager.dispatch(.changeTab(.explore))
self.state = .init()
self.state.isToolTipPresented = false
})))
} else {
state.isLoading = false
print("Error")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ extension InfoStepView {
.padding(.bottom, store.state.keyboardHeight)
.ignoresSafeArea(.keyboard)
.onChange(of: store.state.keyboardHeight) { _, newValue in
if newValue != 0 {
if newValue != 0 && !isPlaceTextFieldFocused {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
withAnimation {
proxy.scrollTo("nextButton", anchor: .bottom)
Expand Down
12 changes: 12 additions & 0 deletions Spoony-iOS/Spoony-iOS/Source/Feature/Register/View/Register.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ struct Register: View {
}
)
}
.overlay {
if store.state.isLoading {
ProgressView()
.tint(.main400)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.white.opacity(0.1))
}
}
}
}

Expand Down Expand Up @@ -74,3 +82,7 @@ enum RegisterStep: Int {
case middle = 2
case end = 3
}

#Preview {
Register(store: .init(navigationManager: .init()))
}
9 changes: 9 additions & 0 deletions Spoony-iOS/Spoony-iOS/Source/Feature/Report/Report.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ struct Report: View {
self.postId = postId
}

let postId: Int

var body: some View {
VStack(spacing: 0) {
CustomNavigationBar(
Expand All @@ -86,6 +88,13 @@ struct Report: View {
) {
hideKeyboard()
store.dispatch(.reportPostButtonTapped(postId))
// Task {
// try await store.dispatch(.reportPostButtonTapped(postId))
// try await store.postReport(postId: postId, description: text)
// navigationManager.popup = .reportSuccess(action: {
// navigationManager.pop(2)
// })
// }
}
.padding(.top, !store.state.isError ? 12 : 20)
.padding(.bottom, 20)
Expand Down

0 comments on commit 5cd1ba6

Please sign in to comment.