[] 더보기 페이지 그리기 완료

This commit is contained in:
Seonkyu_Kim 2025-02-13 16:05:37 +09:00
parent 4f16512073
commit cb9e906d7c
20 changed files with 502 additions and 80 deletions

View File

@ -35,7 +35,7 @@ struct CircleBtnView: View {
.foregroundStyle(state.foreColor)
.frame(width: state.width/2, height: state.height/2)
}
if let title = state.title, let font = state.font {
if let title = state.text, let font = state.font {
Text("\(title)")
.font(font)
.lineLimit(1)

View File

@ -15,7 +15,7 @@ struct SimpleBtnView: View {
var body: some View {
if let state = vm.btnStates[id] {
if let title = state.title, let font = state.font {
if let title = state.text, let font = state.font {
Text("\(title)")
.font(font)
.lineLimit(1)

View File

@ -51,8 +51,13 @@ struct IntroView: View {
case .finished: break
}
} receiveValue: { version in
let compareForce = compareVersion(version.force_ver, currentVersion())
let compareChoice = compareVersion(version.final_ver, currentVersion())
@UserDefault(key:"currentVer", defaultValue: "0.0.0") var currentVer
@UserDefault(key:"finalVer", defaultValue: "0.0.0") var finalVer
currentVer = currentVersion()
finalVer = version.final_ver
let compareForce = compareVersion(version.force_ver, currentVer)//currentVersion())
let compareChoice = compareVersion(version.final_ver, currentVer)//currentVersion())
if compareForce == .bigger {
appVM.alertData = SetAlertData().setForceUpdate(
@ -65,7 +70,10 @@ struct IntroView: View {
)
appVM.showAlert.toggle()
} else {
//
naviState.set(act: .RESET, path: .Login)
}
}
.store(in: &cancellables)
@ -121,10 +129,3 @@ struct IntroView: View {
return ver.components(separatedBy: ["."]).map {Int($0) ?? 0}
}
}
//#Preview {
// IntroView(path: $NavigationPath())
//}

View File

@ -8,8 +8,14 @@
import SwiftUI
struct HomeView: View {
@StateObject private var topVM = TopViewModel()
@State private var scrollOffset: CGPoint = .zero
@State private var topViewState: Bool = false
//MARK: -
@State private var myType: UserType = .Student
var body: some View {
VStack(spacing: 0) {
ZStack {
@ -63,7 +69,7 @@ struct HomeView: View {
if topViewState {
VStack(spacing: 0) {
TopView(titleName: "Name")
TopView(topVM: topVM)
.transition(.move(edge: .top))
.animation(.easeInOut, value: scrollOffset)
Spacer(minLength: 1)
@ -72,6 +78,18 @@ struct HomeView: View {
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.onAppear {
topVM.titleName = "Name"
if myType == .Student {
topVM.setLeftBtn(Image(.Icon.face), size: CGPoint(x: 40, y: 40), action: leftAct)
} else {
topVM.setLeftBtn(text: "\(myType.rawValue)", font: .nps(font: .bold, size: 24),
size: CGPoint(x: 40, y: 40), action: leftAct)
}
topVM.setRightBtn(Image(.Icon.notificationSET), size: CGPoint(x: 40, y: 40), action: rightAct)
topVM.btnVM.setImage(for: topVM.rightBtnID, newImage: Image(.Icon.notificationSET))
}
.onChange(of: scrollOffset.y) { oldValue, newValue in
if newValue > 200 && topViewState == false {
topViewState = true
@ -80,6 +98,14 @@ struct HomeView: View {
}
}
}
func leftAct() {
printLog("왼쪽 버튼 클릭")
}
func rightAct() {
printLog("오른쪽 버튼 클릭")
}
}
struct EmptyBoxView: View {

View File

@ -8,7 +8,33 @@
import SwiftUI
struct ManagementView: View {
@StateObject private var topVM = TopViewModel()
@State private var scrollOffset: CGPoint = .zero
var body: some View {
Text("학습 관리")
VStack(spacing: 0) {
TopView(topVM: topVM)
OffsetObservableScrollView(showsIndicators: false, scrollOffset: $scrollOffset) { proxy in
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.onAppear {
topVM.titleName = ""
topVM.setLeftBtn(size: CGPoint(x: 40, y: 40), action: leftAct)
topVM.setRightBtn(size: CGPoint(x: 40, y: 40), action: rightAct)
}
}
func leftAct() {
printLog("왼쪽 버튼 클릭")
}
func rightAct() {
printLog("오른쪽 버튼 클릭")
}
}

View File

@ -8,7 +8,33 @@
import SwiftUI
struct ChattingView: View {
@StateObject private var topVM = TopViewModel()
@State private var scrollOffset: CGPoint = .zero
var body: some View {
Text("채팅")
VStack(spacing: 0) {
TopView(topVM: topVM)
OffsetObservableScrollView(showsIndicators: false, scrollOffset: $scrollOffset) { proxy in
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.onAppear {
topVM.titleName = ""
topVM.setLeftBtn(size: CGPoint(x: 40, y: 40), action: leftAct)
topVM.setRightBtn(size: CGPoint(x: 40, y: 40), action: rightAct)
}
}
func leftAct() {
printLog("왼쪽 버튼 클릭")
}
func rightAct() {
printLog("오른쪽 버튼 클릭")
}
}

View File

@ -8,7 +8,34 @@
import SwiftUI
struct CalendarView: View {
@StateObject private var topVM = TopViewModel()
@State private var scrollOffset: CGPoint = .zero
var body: some View {
Text("일정")
VStack(spacing: 0) {
TopView(topVM: topVM)
OffsetObservableScrollView(showsIndicators: false, scrollOffset: $scrollOffset) { proxy in
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.onAppear {
topVM.titleName = ""
topVM.setLeftBtn(size: CGPoint(x: 40, y: 40), action: leftAct)
topVM.setRightBtn(size: CGPoint(x: 40, y: 40), action: rightAct)
}
}
func leftAct() {
printLog("왼쪽 버튼 클릭")
}
func rightAct() {
printLog("오른쪽 버튼 클릭")
}
}

View File

@ -0,0 +1,34 @@
//
// AppInfoView.swift
// AcaMate
//
// Created by TAnine on 2/13/25.
//
import SwiftUI
struct AppInfoView: View {
@UserDefault(key:"currentVer", defaultValue: "0.0.0") var currentVer
@UserDefault(key:"finalVer", defaultValue: "0.0.0") var finalVer
var body: some View {
EtcBoxView(title: "앱 정보"){
HStack(spacing: 0) {
Image(.Logo.pageIcon)
.resizable()
.frame(width: 40, height: 40, alignment: .center)
.padding(.trailing, 12)
Text("설치 버전: \(currentVer)")
.font(.nps(font: .bold, size: 20))
.foregroundStyle(Color(.Text.detail))
Spacer(minLength: 1)
if currentVer == finalVer {
Text("최신버전입니다.")
.font(.nps(size: 12))
.foregroundStyle(Color(.Normal.light))
}
}
.padding([.top,.bottom],12)
}
}
}

View File

@ -0,0 +1,45 @@
//
// CsCenterView.swift
// AcaMate
//
// Created by TAnine on 2/13/25.
//
import SwiftUI
struct CsCenterView: View {
var body: some View {
EtcBoxView(title: "고객 센터") {
VStack(spacing: 0){
EtcCellView(title: "공지사항") {
// MARK: TO-DO
//
printLog("공지사항 이동")
}
DashedDivider()
EtcCellView(title: "1:1 문의") {
// MARK: TO-DO
// 1:1
printLog("1:1 문의 이동")
}
DashedDivider()
EtcCellView(title: "자주 묻는 질문") {
// MARK: TO-DO
//
printLog("자주 묻는 질문 이동")
}
DashedDivider()
EtcCellView(title: "학원 정보") {
// MARK: TO-DO
//
printLog("학원 정보 이동")
}
}
}
}
}

View File

@ -0,0 +1,63 @@
//
// EtcBoxView.swift
// AcaMate
//
// Created by TAnine on 2/13/25.
//
import SwiftUI
struct EtcBoxView<Content: View>: View {
let title: String
@ViewBuilder let content: Content
var body: some View {
VStack(spacing: 24) {
Text("\(title)")
.font(.nps(font: .bold, size: 24))
.foregroundStyle(Color(.Text.detail))
.frame(maxWidth: .infinity, alignment: .leading)
content
.padding([.leading,.trailing],24)
.background {
RoundedRectangle(cornerRadius: 8)
.foregroundStyle(Color(.Other.cell))
}
}
}
}
struct EtcCellView: View {
@StateObject var btnVM = ButtonViewModel()
let nextBtnID = UUID()
let title: String
let action: VOID_TO_VOID
var body: some View {
HStack(spacing: 0) {
Text("\(title)")
.font(.nps(font: .bold, size: 20))
.foregroundStyle(Color(.Text.detail))
Spacer(minLength: 1)
SimpleBtnView(vm: btnVM, id: nextBtnID)
.padding([.top,.bottom],24)
}
.onAppear {
btnVM.setSize(for: nextBtnID, newWidth: 24, newHeight: 24)
btnVM.setImage(for: nextBtnID, newImage: Image(.Icon.right))
btnVM.setAction(for: nextBtnID, newAction: action)
}
}
}
struct DashedDivider: View {
var body: some View {
Rectangle()
.stroke(style: StrokeStyle(lineWidth: 1, dash: [5, 3]))
.foregroundColor(Color.Disable.normal)
.frame(height: 1)
}
}

View File

@ -8,8 +8,44 @@
import SwiftUI
struct EtcView: View {
@StateObject private var topVM = TopViewModel()
@State private var scrollOffset: CGPoint = .zero
var body: some View {
Text("더보기")
VStack(spacing: 0) {
TopView(topVM: topVM)
OffsetObservableScrollView(showsIndicators: false, scrollOffset: $scrollOffset) { proxy in
VStack(spacing: 24) {
UserInfoView(userData: SummaryUser(profile: Image(.Icon.face), name: "이름", userID: "abcdefg", email: "abcdefg@gmail.com"))
UserSettingView()
CsCenterView()
TsCsView()
AppInfoView()
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(24)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.onAppear {
topVM.titleName = ""
topVM.setLeftBtn(size: CGPoint(x: 40, y: 40), action: leftAct)
topVM.setRightBtn(size: CGPoint(x: 40, y: 40), action: rightAct)
}
}
func leftAct() {
printLog("왼쪽 버튼 클릭")
}
func rightAct() {
printLog("오른쪽 버튼 클릭")
}
}

View File

@ -0,0 +1,29 @@
//
// TsCsView.swift
// AcaMate
//
// Created by TAnine on 2/13/25.
//
import SwiftUI
struct TsCsView: View {
var body: some View {
EtcBoxView(title: "약관"){
VStack(spacing: 0) {
EtcCellView(title: "이용약관") {
// MARK: TO-DO
//
printLog("이용약관 이동")
}
DashedDivider()
EtcCellView(title: "개인정보 처리방침") {
// MARK: TO-DO
//
printLog("개인정보 처리방침 이동")
}
}
}
}
}
//

View File

@ -0,0 +1,68 @@
//
// UserInfoView.swift
// AcaMate
//
// Created by TAnine on 2/13/25.
//
import SwiftUI
struct UserInfoView: View {
@StateObject var btnVM = ButtonViewModel()
@State var notifyBtnID = UUID()
@State var userData: SummaryUser
var body: some View {
VStack(spacing: 8 ) {
HStack(spacing: 12) {
userData.profile.resizable()
.frame(width: 30, height: 30, alignment: .center)
Text("\(userData.name)")
.font(.nps(font: .bold, size: 20))
.foregroundStyle(Color(.Text.detail))
Spacer(minLength: 1)
VStack(alignment: .center, spacing: 0) {
SimpleBtnView(vm: btnVM, id: notifyBtnID)
Text("알림설정")
.font(.nps(font: .bold, size: 8))
.foregroundStyle(Color(.Text.detail))
}
}
VStack(spacing: 10) {
HStack(spacing: 0) {
Text("ID")
.font(.nps(font: .bold, size: 16))
.foregroundStyle(Color(.Text.detail))
Spacer(minLength: 1)
Text("\(userData.userID)")
.font(.nps(font: .bold, size: 16))
.foregroundStyle(Color(.Text.detail))
}
HStack(spacing: 0) {
Text("E-mail")
.font(.nps(font: .bold, size: 16))
.foregroundStyle(Color(.Text.detail))
Spacer(minLength: 1)
Text("\(userData.email)")
.font(.nps(font: .bold, size: 16))
.lineLimit(1)
.minimumScaleFactor(0.5)
.truncationMode(.tail)
.foregroundStyle(Color(.Text.detail))
}
}
.padding(10)
}
.padding(12)
.background {
RoundedRectangle(cornerRadius: 8)
.foregroundStyle(Color(.Other.cell))
}
.onAppear {
btnVM.setImage(for: notifyBtnID, newImage: Image(.Icon.notificationSET))
btnVM.setSize(for: notifyBtnID, newWidth: 24, newHeight: 24)
}
}
}

View File

@ -0,0 +1,31 @@
//
// UserSettingView.swift
// AcaMate
//
// Created by TAnine on 2/13/25.
//
import SwiftUI
struct UserSettingView: View {
var body: some View {
EtcBoxView(title: "설정") {
VStack(spacing: 0){
EtcCellView(title: "정보 변경") {
// MARK: TO-DO
//
printLog("정보 변경 이동")
}
DashedDivider()
EtcCellView(title: "계정 관리") {
// MARK: TO-DO
//
printLog("계정 관리 이동")
}
}
}
}
}

View File

@ -8,37 +8,36 @@
import SwiftUI
struct TopView: View {
@StateObject var btnVM = ButtonViewModel()
@State var titleName: String = ""
@State private var leftBtnID = UUID()
@State private var rightBtnID = UUID()
//MARK: -
var myType: UserType = .Student
@ObservedObject var topVM: TopViewModel
var body: some View {
HStack(alignment: .center, spacing: 0) {
SimpleBtnView(vm: btnVM, id: leftBtnID)
HStack(alignment: .center, spacing: 12) {
SimpleBtnView(vm: topVM.btnVM, id: topVM.leftBtnID)
.background {
if let state = btnVM.btnStates[leftBtnID], state.image == nil {
if let state = topVM.btnVM.btnStates[topVM.leftBtnID], state.image == nil, state.text != nil {
Circle()
.strokeBorder(Color(.Second.normal) ,lineWidth: 4)
.frame(width: 40, height: 40)
.frame(width: state.width, height: state.height)
}
}
.padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 12))
.padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 0))
Text("\(titleName)")
Text("\(topVM.titleName)")
.foregroundStyle(Color(.Text.detail))
.font(.nps(font: .bold, size: 20))
Spacer()
SimpleBtnView(vm: btnVM, id: rightBtnID)
.padding(EdgeInsets(top: 12, leading: 12, bottom: 12, trailing: 24))
.frame(height: 40)
.padding(EdgeInsets(top: 12, leading: 12, bottom: 12, trailing: 12))
Spacer(minLength: 1)
SimpleBtnView(vm: topVM.btnVM, id: topVM.rightBtnID)
.background {
if let state = topVM.btnVM.btnStates[topVM.rightBtnID], state.image == nil, state.text != nil {
Circle()
.strokeBorder(Color(.Second.normal) ,lineWidth: 4)
.frame(width: state.width, height: state.height)
}
}
.padding(EdgeInsets(top: 12, leading: 0, bottom: 12, trailing: 24))
}
.background {
Rectangle()
@ -47,48 +46,9 @@ struct TopView: View {
}
.frame(maxWidth: .infinity)
.onAppear {
btnVM.btnStates[leftBtnID] = ButtonState()
btnVM.btnStates[rightBtnID] = ButtonState()
btnVM.setSize(for: leftBtnID, newWidth: 40, newHeight: 40)
btnVM.setSize(for: rightBtnID, newWidth: 40, newHeight: 40)
if self.myType == .Student {
btnVM.setImage(for: leftBtnID, newImage: Image(.Icon.face))
} else {
btnVM.setText(for: leftBtnID,
newText: "\(myType.rawValue)",
newFont: .nps(font: .bold, size: 24))
}
btnVM.setImage(for: rightBtnID, newImage: Image(.Icon.notificationSET))
}
}
}
}
//struct TypeIcon: View {
// var myType: UserType
//
// var body: some View {
// if self.myType == .Student {
// SimpleBtnView(image: Image(.Icon.face), title: nil, font: nil, width: 40, height: 40)
// } else {
// SimpleBtnView(image: nil, title: "\(self.myType.rawValue)", font: .nps(font: .bold, size: 24), width: 40, height: 40)
// .doAction {
// printLog("CHECK!!!")
// }
// .setTextColor(.red)
// .setIsUsable(false)
// }
// }
//}
//#Preview {
// TopView(titleName: "Name")
//}

View File

@ -10,7 +10,7 @@ import SwiftUI
struct ButtonState {
var image: Image? = nil
var title: String? = nil
var text: String? = nil
var font: Font? = nil
var width: CGFloat = 0

View File

@ -5,7 +5,7 @@
// Created by TAnine on 2/5/25.
//
import Foundation
import SwiftUI
enum UserType: String {
case Student = "S"
@ -15,3 +15,10 @@ enum UserType: String {
case Employee = "E"
case ETC = "V"
}
struct SummaryUser {
var profile: Image
var name: String
var userID: String
var email: String
}

View File

@ -21,7 +21,7 @@ class ButtonViewModel: ObservableObject {
func setText(for id: UUID, newText: String?, newFont: Font?) {
var state = btnStates[id] ?? ButtonState()
state.title = newText
state.text = newText
state.font = newFont
btnStates[id] = state

View File

@ -0,0 +1,43 @@
//
// TopViewModel.swift
// AcaMate
//
// Created by TAnine on 2/13/25.
//
import SwiftUI
class TopViewModel: ObservableObject {
@Published var btnVM = ButtonViewModel()
@Published var titleName: String = ""
let leftBtnID = UUID()
let rightBtnID = UUID()
init() {
btnVM.btnStates[leftBtnID] = ButtonState()
btnVM.btnStates[rightBtnID] = ButtonState()
}
func setLeftBtn(_ image: Image? = nil, text: String? = nil, font: Font? = nil, size: CGPoint, action: @escaping VOID_TO_VOID) {
btnVM.setSize(for: leftBtnID, newWidth: size.x, newHeight: size.y)
if text != nil {
btnVM.setText(for: leftBtnID, newText: text, newFont: font)
} else if let image = image {
btnVM.setImage(for: leftBtnID, newImage: image)
}
btnVM.setAction(for: leftBtnID, newAction: action)
}
func setRightBtn(_ image: Image? = nil, text: String? = nil, font: Font? = nil, size: CGPoint, action: @escaping VOID_TO_VOID) {
btnVM.setSize(for: rightBtnID, newWidth: size.x, newHeight: size.y)
if text != nil {
btnVM.setText(for: rightBtnID, newText: text, newFont: font)
} else if let image = image {
btnVM.setImage(for: rightBtnID, newImage: image)
}
btnVM.setAction(for: rightBtnID, newAction: action)
}
}