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

๐Ÿ”€ :: [#102] ํ•™์ƒํ™œ๋™ ์ถ”๊ฐ€ ํŽ˜์ด์ง€ ํผ๋ธ”๋ฆฌ์‹ฑ #116

Merged
merged 16 commits into from
Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
86a0976
:sparkles: :: [#102] InputActivityFeature / InputActivityView ํผ๋ธ”๋ฆฌ์‹ฑ
uuuunseo Dec 29, 2023
78c0434
:bug: :: ์ถฉ๋Œ ํ•ด๊ฒฐ
uuuunseo Dec 29, 2023
fe36c12
:bug: :: ์ถฉ๋Œ ํ•ด๊ฒฐ
uuuunseo Dec 29, 2023
dee40a8
:bento: :: [#102] Icons / ์„ค์ • Icon ์ถ”๊ฐ€
uuuunseo Dec 31, 2023
d8a16a4
:sparkles: :: [#102] extensions / hideKeyboard extensions ์ถ”๊ฐ€
uuuunseo Dec 31, 2023
1ddf929
:sparkles: :: [#102] ActivityFeature / InputActivityView navigate
uuuunseo Dec 31, 2023
ba9ec2a
:sparkles: :: [#102] InputActivityView / ๋ ˆ์ด์•„์›ƒ ์ˆ˜์ • ๋ฐ๋ฒ„ํŠผ ์ถ”๊ฐ€
uuuunseo Dec 31, 2023
6c2b5d7
:sparkles: :: [#102] AppComponent / inputActivityFactory ์ถ”๊ฐ€
uuuunseo Dec 31, 2023
c6f7139
:fire: :: [#102] InputActivityDependency / ํ•„์š”์—†๋Š” Import ์‚ญ์ œ
uuuunseo Dec 31, 2023
2b061f1
:green_heart: :: [#102] MainActor ์œ„์น˜ ๋ณ€๊ฒฝ
uuuunseo Jan 1, 2024
330909c
:recycle: :: [#102] InputActivityView / frame ํ•œ ์ค„๋กœ ์ˆ˜์ •
uuuunseo Jan 1, 2024
6f04423
:recycle: :: [#102] InputActivityView / Button ์ฝ”๋“œ ์ˆ˜์ •
uuuunseo Jan 7, 2024
5590217
:recycle: :: [#102] ActivityListView / Button trailing ํด๋กœ์ ธ ์‚ฌ์šฉ
uuuunseo Jan 11, 2024
3b0d2c2
:recycle: :: [#102] InputActivityView / Image ResourceSynthesizer๋กœ ๋ณ€๊ฒฝ
uuuunseo Jan 11, 2024
867aa6c
:recycle: :: [#102] InputActivityView / TextEditor Text ๋ถ€๋ถ„ binding์œผ๋กœ ๋ณ€๊ฒฝ
uuuunseo Jan 11, 2024
0310838
:recycle: :: [#102] InputActivityView / Image add -> setting์œผ๋กœ ์ˆ˜์ •
uuuunseo Jan 11, 2024
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
21 changes: 21 additions & 0 deletions App/Resources/Icon/Icons.xcassets/setting.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "setting.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 6 additions & 2 deletions App/Sources/Application/DI/AppComponent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,16 @@ public extension AppComponent {
var loginFactory: any LoginFactory {
LoginComponent(parent: self)
}

var activityListFactory: any ActivityListFactory {
ActivityListComponent(parent: self)
}

var signupFactory: any StudentSignUpFactory {
StudentSignUpComponent(parent: self)
}

var inputActivityFactory: any InputActivityFactory {
InputActivityComponent(parent: self)
}
}
159 changes: 127 additions & 32 deletions App/Sources/Application/NeedleGenerated.swift

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions App/Sources/DesignSystem/Extensions/View+hideKeyBoard.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import SwiftUI

extension View {
func hideKeyboard() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
24 changes: 23 additions & 1 deletion App/Sources/Feature/ActivityListFeature/ActivityListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ struct ActivityListView: View {
@Environment(\.dismiss) var dismiss
@StateObject var model: ActivityListModel
@StateObject var viewModel: ActivityListViewModel

private let inputActivityFactory: any InputActivityFactory

init(
inputActivityFactory: any InputActivityFactory,
model: ActivityListModel,
viewModel: ActivityListViewModel
) {
self.inputActivityFactory = inputActivityFactory
_model = StateObject(wrappedValue: model)
_viewModel = StateObject(wrappedValue: viewModel)
}

var body: some View {
NavigationView {
ScrollView {
Expand Down Expand Up @@ -38,7 +51,9 @@ struct ActivityListView: View {
.toolbar {
ToolbarItemGroup(placement: .navigationBarTrailing) {
if model.authority == .student {
Button(action: {}, label: {
Button(action: {
viewModel.inputActivityViewIsRequired()
}, label: {
Image(systemName: "plus")
.resizable()
.aspectRatio(contentMode: .fit)
Expand All @@ -48,6 +63,13 @@ struct ActivityListView: View {
}
}
}
.navigate(
to: inputActivityFactory.makeView().eraseToAnyView(),
when: Binding(
get: { viewModel.isPresentedInputActivityView },
set: { _ in viewModel.inputActivityViewIsDismissed() }
)
)
}
.onAppear {
viewModel.onAppear()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@ import Service
import SwiftUI

public protocol ActivityListDependency: Dependency {
var inputActivityFactory: any InputActivityFactory { get }
var loadUserAuthorityUseCase: any LoadUserAuthorityUseCase { get }
var queryMyStudentActivityUseCase: any QueryMyStudentActivityUseCase { get }
var queryStudentActivityListUseCase: any QueryStudentActivityListUseCase { get }
var queryStudentActivityByIdUseCase: any QueryStudentActivityByIdUseCase { get }
}

@MainActor
public final class ActivityListComponent: Component<ActivityListDependency>, ActivityListFactory {
@MainActor
public func makeView(studentID: UUID) -> some View {
let model = ActivityListModel()
return ActivityListView(
inputActivityFactory: dependency.inputActivityFactory,
model: model,
viewModel: .init(
studentID: studentID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Foundation
import Service

final class ActivityListViewModel: BaseViewModel {
@Published var isPresentedInputActivityView: Bool = false
var model: ActivityListModel
private let loadUserAuthorityUseCase: any LoadUserAuthorityUseCase
private let queryMyStudentActivityUseCase: any QueryMyStudentActivityUseCase
Expand Down Expand Up @@ -71,4 +72,12 @@ final class ActivityListViewModel: BaseViewModel {
func toastDismissed() {
self.isErrorOccurred = false
}

func inputActivityViewIsRequired() {
self.isPresentedInputActivityView = true
}

func inputActivityViewIsDismissed() {
self.isPresentedInputActivityView = false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import SwiftUI

public protocol InputActivityFactory {
associatedtype SomeView: View
func makeView() -> SomeView
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import NeedleFoundation
import Service
import SwiftUI

public protocol InputActivityDependency: Dependency {}

public final class InputActivityComponent: Component<InputActivityDependency>, InputActivityFactory {
public func makeView() -> some View {
InputActivityView(
viewModel: .init(title: .init(), activityText: .init())
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import SwiftUI

struct InputActivityView: View {
@StateObject var viewModel: InputActivityViewModel

init(viewModel: InputActivityViewModel) {
_viewModel = StateObject(wrappedValue: viewModel)
}

var body: some View {
ScrollView {
VStack(spacing: 0) {
VStack {
TextEditor(text: $viewModel.title)
.bitgouelFont(.title3)
.overlay(alignment: .topLeading) {
if viewModel.title.isEmpty {
BitgouelText(
text: "ํ™œ๋™ ์ œ๋ชฉ (100์ž ์ด๋‚ด)",
font: .title3
)
.padding(.top, 8)
.padding(.leading, 4)
.foregroundColor(.bitgouel(.greyscale(.g7)))
}
}
.onChange(of: viewModel.title, perform: { value in
if viewModel.title.count > 100 {
viewModel.title.removeLast()
}
})
}
.padding(.top, -40)
.frame(minHeight: 40, maxHeight: 120)

Divider()

VStack {
TextEditor(text: $viewModel.activityText)
.bitgouelFont(.text3)
.overlay(alignment: .topLeading) {
if viewModel.activityText.isEmpty {
BitgouelText(
text: "๋ณธ๋ฌธ ์ž…๋ ฅ (1000์ž ์ด๋‚ด)",
font: .text3
)
.padding(.top, 8)
.padding(.leading, 4)
.foregroundColor(.bitgouel(.greyscale(.g7)))
}
}
.onChange(of: viewModel.activityText, perform: { value in
if viewModel.activityText.count > 1000 {
viewModel.activityText.removeLast()
}
})
}
.padding(.top, 16)
.frame(height: 460)

Divider()

VStack(spacing: 8) {
Button {} label: {
Image("setting")

Text("ํ™œ๋™ ์„ธ๋ถ€ ์„ค์ •")
.bitgouelFont(.text3, color: .primary(.p5))
}
.padding(.vertical, 12)
.padding(.horizontal, 96)
.overlay {
RoundedRectangle(cornerRadius: 8)
.strokeBorder(Color.bitgouel(.primary(.p5)))
}

CTAButton(
text: "ํ™œ๋™ ์ถ”๊ฐ€",
style: .default
)
}
.padding(.top, 24)
.padding(.bottom, 12)
}
}
.padding(.horizontal, 28)
.onTapGesture {
hideKeyboard()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Foundation
import Service

final class InputActivityViewModel: BaseViewModel {
@Published var title: String
@Published var activityText: String

init(title: String, activityText: String) {
self.title = title
self.activityText = activityText
}
}