열정 많은 개발자
, push 해야되는데 잊어버린 마감 급한 개발자 등등을 위한 1일 1커밋 강요앱
저희 CYC(Check your commit)는 크게 commit 알림 기능, 간단한 todo list를 갖고 있습니다.
강치우 | 김명현 | 이민영 | 황민채 | 황성진 |
---|---|---|---|---|
- 깃허브 OAuth를 통한 로그인 연동
- OAuth AcessToken을 바탕으로 유저 정보를 활용
- 유저 정보를 custom ProgressView, GrassView 등 활용
- 목표달성을 도와주는 챌린지 설정
- MainView에서 D-Day를 제공함으로, 목표를 가시적으로 확인
- 오늘 커밋을 위해 할일을 기록하는 TodoList
- 알람을 통해 일정시간마다 커밋 체크
앱 화면 |
---|
라이트 모드 | 다크 모드 |
---|---|
Step 1 타임라인
- 23.12.5 ~ 23.12.6
- 팀빌딩
- 아이디어 토의
- 아이디어 구현 방안 토의
Step 2 타임라인
- 23.12.06 ~ 23.12.07
- Figma를 기본 디자인 프로토타입 제작
- 각 기능별 구현 방안 토의
- 각 파트별 역할 분배
- 프로젝트 개발 시작
- 23.12.12 ~ 23.12.13
- 앱 아이콘 제작
Step 3 타임라인
- 23.12.06
- 기본 앱 구조 제작
- 커스텀 폰트, 컬러 Aseet 적용
- 23.12.07 ~ 23.12.11
- 깃허브 OAuth 로그인 구현
- OAuth 데이터를 통해 유저 정보 받아오는 부분 구현
- 23.12.07 ~ 23.12.14
- 알림기능 구현
- Todo List 구현
- 23.12.11 ~ 23.12.14
- 깃허브 API를 이용한 GrassView 구현
- 깃허브 API로 받아온 커밋일수로 D-day 계산기 구현
- 23.12.14
- 라이트 모드, 다크모드 변환 버튼 구현
API를 통해 JSON 유저 데이터가 정상적으로 불러와지지 않음
Git API
를 통해 유저 데이터가 JSON 형식으로 불러와지지 않는 문제
func getUser() {
let accessToken = KeychainSwift().get("accessToken") ?? ""
let headers: HTTPHeaders = ["Accept": "application/vnd.github.v3+json",
"Authorization": "token \(accessToken)"]
AF.request(githubApiURL+ApiPath.USER.rawValue,
method: .get,
parameters: [:],
headers: headers).responseJSON(completionHandler: { (response) in
switch response.result {
case .success(let json):
print(json as! [String: Any])
case .failure:
print("")
}
})
}
- 깃허브 유저 API 공식문서 해당 문서의 형태로 curl 을 사용하면 정상적으로 JSON 형태의 데이터가 받아와 지는 것을 확인
- API를 받아오는 과정에서 responseJSON 의 형태가 아니라 responseString 혹은 responseDecodable 으로 사용하면 정상적으로 데이터가 받아와 지는 것을 확인
- struct를 통해 User를 선언하고 responseDecodable 로 해당 데이터를 할당시키는 방법으로 활용
struct User: Decodable {
let login: String
let name: String
}
func getUser() {
let headers: HTTPHeaders = ["Accept": "application/vnd.github+json",
"Authorization": "Bearer \(access_token!)"]
AF.request("https://api.github.com/user",
method: .get, parameters: [:],
headers: headers).responseDecodable(of: User.self) { response in
switch response.result {
case .success(let user):
self.userLogin = user.login
self.userName = user.name
self.getCommitData()
case .failure(let error):
print("Error: \(error.localizedDescription)")
}
}
}
- REST API의 주소가 명확한지 확인하기위해 curl의 활용법을 알게됨.
UserDefaults의 사용
API
를 활용하기 위해서는 액세스토큰 값이 절대적으로 필요, 앱을 종료 시켜도 해당 값은 유효해야 됨- AppStorage를 사용하려 했지만 다른 뷰에서도 사용하고 참조해야 되기 때문에 사용이 어려움
class LoginModel: ObservableObject {
static let shared = LoginModel()
@Published var code: String?
@Published var access_token: String?
@Published var userLogin: String?
- UserDefaults 로 해당 변수들을 선언하고 extension을 통해 set, get 부분을 적용
- init() 부분을 통해 선언된 변수를 초기화
@Published var access_token: String? {
didSet {
UserDefaults.standard.setAccessToken(access_token ?? "")
}
}
@Published var userName: String? {
didSet {
UserDefaults.standard.setUserName(userName ?? "")
}
}
@Published var userLogin: String? {
didSet {
UserDefaults.standard.setUserLogin(userLogin ?? "")
}
}
var results: [(String, String)] = []
@Published var testCase:[String:Int] = [:]
// UserDefaults로 선언된 변수를 사용하기 위한 init 부분
init() {
self.userLogin = UserDefaults.standard.getUserLogin()
self.access_token = UserDefaults.standard.getAccessToken()
self.userName = UserDefaults.standard.getUserName()
}
// UserDefaults의 extension 부분
extension UserDefaults {
private static let userLoginKey = "userLoginKey"
func setUserLogin(_ login: String) {
set(login, forKey: UserDefaults.userLoginKey)
}
func getUserLogin() -> String? {
return string(forKey: UserDefaults.userLoginKey)
}
}
extension UserDefaults {
private static let userAcessToken = "acessToken"
func setAccessToken(_ token: String) {
set(token, forKey: UserDefaults.userAcessToken)
}
func getAccessToken() -> String? {
return string(forKey: UserDefaults.userAcessToken)
}
}
extension UserDefaults {
private static let userNickname = "userNickname"
func setUserName(_ name: String) {
set(name, forKey: UserDefaults.userNickname)
}
func getUserName() -> String? {
return string(forKey: UserDefaults.userNickname)
}
}
SwiftUI
Xcode 15.1
iOS 17.1
Language - Swift 5.5.3
알람 - UserNotification
API - Alamofire
Todo - SwiftData
GrassView - SwiftSoup
📦CYC
┣ 📂 Main
┃ ┗ 📜 MainView.swift
┣ 📂 Login
┃ ┃ ┣ 📂 extension
┃ ┃ ┗ 📜 extensionOfUserDefaults.ttf
┃ ┣ 📜 OnboardingTabView.swift
┃ ┣ 📜 LoginView.swift
┃ ┗ 📜 LoginModel.swift
┃ ┃ ┣ 📂 Font
┣ 📂 Setting
┃ ┣ 📂 PersonProfile
┃ ┃ ┣ 📂 View
┃ ┃ ┃ ┣ 📜 PersonGridView.swift
┃ ┃ ┃ ┗ 📜 AboutCYC.swift
┃ ┃ ┣ 📂 Model
┃ ┃ ┃ ┗ 📜 PersonModel.swift
┃ ┣ 📂 ViewModel
┃ ┃ ┣ 📜 LicenseViewModel.swift
┃ ┃ ┗ 📜 SettingViewModel.swift
┃ ┣ 📂 View
┃ ┃ ┣ 📜 LicenseView.swift
┃ ┃ ┣ 📜 NotificationView.swift
┃ ┃ ┗ 📜 SettingView.swift
┃ ┣ 📂 Model
┃ ┃ ┣ 📜 LicenseModel.swift
┃ ┃ ┗ 📜 SettingModel.swift
┣ 📂 Grass
┃ ┣ 📂 View
┃ ┃ ┗ 📜 CommitView.swift
┣ 📂 Todo
┃ ┣ 📂 View
┃ ┃ ┣ 📜 TodoView.swift
┃ ┃ ┗ 📜 TodoPreView.swift
┃ ┣ 📂 Model
┃ ┃ ┗ 📜 TodoModel.swift
┣ 📂 Progress
┃ ┣ 📂 View
┃ ┃ ┣ 📜 ProgressView.swift
┃ ┃ ┣ 📜 ModalView.swift
┃ ┃ ┣ 📜 ProgressBarView.swift
┃ ┃ ┣ 📜 DdayButtonView.swift
┃ ┃ ┗ 📜 ProgressTextView.swift
┣ 📂 Helper
┃ ┣ 📂 NotificationHelper
┃ ┃ ┗ 📜 LocalNotificationHelper.swift
┃ ┣ 📂 DarkLightMode
┃ ┃ ┣ 📜 DLMode.swift
┃ ┃ ┗ 📜 UIButton.swift
┃ ┣ 📂 Extensions
┃ ┃ ┣ 📜 fontExtension.swift
┃ ┃ ┣ 📜 CustomSpacing.swift
┃ ┃ ┣ 📜 colorExtension.swift
┃ ┃ ┗ 📜 DismissGesture.swift
┃ ┣ 📂 Fonts
┃ ┃ ┣ 📜 Pretendard-Black.otf
┃ ┃ ┣ 📜 Pretendard-Bold.otf
┃ ┃ ┣ 📜 Pretendard-ExtraBold.otf
┃ ┃ ┣ 📜 Pretendard-ExtraLight.otf
┃ ┃ ┣ 📜 Pretendard-Light.otf
┃ ┃ ┣ 📜 Pretendard-Medium.otf
┃ ┃ ┣ 📜 Pretendard-Regular.otf
┃ ┃ ┣ 📜 Pretendard-SemiBold.otf
┃ ┃ ┗ 📜 Pretendard-Thin.otf.swift
┣ 📜 CYCAPP.swift
┣ 📜 AppDelegate.swift
┣ 📜 StartView.swift
┗ 🖼️ Assets