4 분 소요

프로젝트 : DUI (Deajeon University Introduction app)

포트폴리오 주소: https://github.com/nohhyeon/Fidecosemi.git

수행 기간: 2023.03 ~ 2023.11

수행 인원: 3명

프로젝트 목표/소개

신입생과 처음 학교를 방문한 사람들을 위해 학교의 편의시설을 쉽게 찾을 수 있도록 카테고리별로 장소를 나누고, 해당 카테고리를 누르면 마커핀을 통해 장소의 명칭과 위치를 확인할 수 있게 합니다. 또한, 마커핀을 길게 누르면 상세 정보 표시, 익명성을 보장하는 게시판 기능 제공.

개발 환경 (사용 도구/언어)

FirebaseFirebase, SwiftSwift, CocoaPodsCocoaPods, Firebase Realtime DatabaseFirebase Realtime Database, Google MapsGoogle Maps, XcodeXcode, macOSmacOS

image-20240616205527274

담당 역할

  • 프로젝트 팀장으로서 iOS 앱의 전체적인 개발 구성과 기획
  • Firebase Database를 사용하여 게시판과 Google Maps에서 마커핀 정보 출력 기능 구현

블록 다이어그램

image-20240616205535076

시연 영상

[영상 1] - 위치정보의 표시와 상단 카테고리에 따라 마커핀이 표시가 다르게 되고 마커핀 클릭시 상세 정보가 나오는 작동 화면을 보여줍니다.

[영상 2] - UUID로 게시판에 고유의 정보로 글 작성과 삭제 권환이 있는 것을 보여줍니다.

실행화면 및 상세설명, 주요 코드

image-20240616205624892

import UIKit

class Define: Any {
    // "~~~~~~" 개인정보라 가려둠
    // KEY
    static let GOOGLE_API_KEY   = "~~~~~~"
    static let MAP_ID           = "~~~~~~"
    
    // OpenWeatherMap API 엔드포인트 및 API 키
    static let apiKey = "~~~~~~"
    static let endpoint = "~~~~~~"
    static let city = "Daejeon, KR" // 날씨 정보를 얻고자 하는 도시
    
    // 구글지도 좌표계 -> WGS 84 (교내 편의시설 기본 좌표)
    static let LAT_001          = 36.336059
    static let LONG_001         = 127.459963
    
    // 구글지도 좌표계 -> WGS 84 (주변 음식점 기본 좌표)
    static let LAT_002          = 36.335088
    static let LONG_002         = 127.457517
    
    static let BOARD_REG_DATE_TYPE  = "yyyyMMddHHmmss"
    
}

image-20240616205628905

import UIKit
import Firebase
import FirebaseDatabase

class ResMapdetailViewController: UIViewController {
    
    @IBOutlet weak var contentTextView: UITextView!
    @IBOutlet weak var contentTextFied: UITextField!
    
    var ref: DatabaseReference!
    var categoryName: String = "" // 카테고리 정보
    var Atitle: String = "" //
    var cam: String = ""

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Firebase Database Reference 가져오기
        ref = Database.database().reference()
        
        // 제목 필드의 테두리 스타일 설정
        contentTextFied.layer.borderWidth = 1.0 // 테두리 두께
        contentTextFied.layer.borderColor = UIColor.gray.cgColor // 테두리 색상
        contentTextFied.layer.cornerRadius = 5.0 // 테두리 모서리 반경
        contentTextFied.isEnabled = false  // 읽기 전용

                // 내용 필드의 테두리 스타일 설정
        contentTextView.layer.borderWidth = 1.0 // 테두리 두께
        contentTextView.layer.borderColor = UIColor.gray.cgColor // 테두리 색상
        contentTextView.layer.cornerRadius = 5.0 // 테두리 모서리 반경
        contentTextView.isEditable = false // 읽기 전용
        
        // placeID가 존재하면 데이터를 가져와서 표시
          self.fetchPlaceDetails()
        
    }
    
    // Firebase에서 장소 정보 가져와 텍스트 뷰에 출력하는 함수
    func fetchPlaceDetails() {
        // Firebase 데이터베이스에서 placeID에 해당하는 장소의 정보를 가져옵니다.
        ref.child(cam).child(categoryName).child(Atitle).observe(.value) { (snapshot) in
            if let placeData = snapshot.value as? [String: Any],
               let title = placeData["title"] as? String,
               let content = placeData["content"] as? String {
                
                // 가져온 정보를 텍스트 뷰에 설정
                let Info = "\(content)"
                self.contentTextView.text = Info
                let PlaceName = "\(title)"
                self.contentTextFied.text = PlaceName
                
            }
            else { print("error")
                self.contentTextView.text = "Info가 포함되어 있지 않습니다."
                self.contentTextFied.text = "PlaceName이 포함되어 있지 않습니다."
            }
        }
    }
    

}

image-20240616205636834

import UIKit
import Foundation
import Firebase
import FirebaseDatabase

    struct ShowBoard {
    var sUID: String = ""
    var sTitle: String = ""
    var sContext: String = ""
    var sRegDate: String = ""
}

class ShowViewController: UIViewController {
    
    
    @IBOutlet weak var txViewTitle: UITextField!
    @IBOutlet weak var txViewMessage: UITextView!
    
    var ref: DatabaseReference!
    
    var boardID: String = ""
    var UUID: String = ""
    var aUID: String = ""
    
    var uuid = AppStorage.sharedInstance.getUUID()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Firebase Database Reference 가져오기
        self.ref = Database.database().reference()
        
        // 제목 필드의 테두리 스타일 설정
        txViewTitle.layer.borderWidth = 1.0 // 테두리 두께
        txViewTitle.layer.borderColor = UIColor.gray.cgColor // 테두리 색상
        txViewTitle.layer.cornerRadius = 5.0 // 테두리 모서리 반경
        txViewTitle.isEnabled = false  // 읽기 전용

        // 내용 필드의 테두리 스타일 설정
        txViewMessage.layer.borderWidth = 1.0 // 테두리 두께
        txViewMessage.layer.borderColor = UIColor.gray.cgColor // 테두리 색상
        txViewMessage.layer.cornerRadius = 5.0 // 테두리 모서리 반경
        txViewMessage.isEditable = false // 읽기 전용
        
        // Firebase 데이터 가져오기
        self.ShowFirebaseBoard(ID: boardID)
        
        // 삭제 버튼 생성
        let DeleteBarButtonItem = UIBarButtonItem(
            title: "삭제",
            style: .plain,
            target: self,
            action: #selector(DeleteBarButtonTapped)
        )
               
        // 네비게이션 바 오른쪽에 버튼 추가
        navigationItem.rightBarButtonItem = DeleteBarButtonItem
    
    }
   // Firebase에서 데이터를 가져오는 메소드 
    func ShowFirebaseBoard(ID: String) {
        self.ref.child("게시판").child(ID).observe(.value) { (snapshot) in

            print("---------")
            print("id : \(ID)")
            print("ref : \(String(describing: self.ref.child("게시판")))")

            if let data = snapshot.value as? [String: Any],
               let UID = data["UID"] as? String,
               let title = data["title"] as? String,
               let context = data["context"] as? String,
               let regDate = data["regDate"] as? String {

                var abc = ShowBoard.init()
                abc.sUID = UID
                abc.sTitle = title
                abc.sContext = context
                abc.sRegDate = regDate
                
                print("UID : \(abc.sUID)")
                print("Title : \(abc.sTitle)")
                print("Context : \(abc.sContext)")
                print("regDate : \(abc.sRegDate)")
                
                self.UUID = abc.sUID

                // UI 업데이트
                self.txViewTitle.text = abc.sTitle
                self.txViewMessage.text = abc.sContext
                
            } 
        }
    }

image-20240616205643801

image-20240616205647218


    // 최단경로
    func directionTest() {
        
        // 일본(한국은 휴전국가로 구글에서 경로 정보를 불러올 수 없어서 일본으로 테스트)
        let originLatitude = 34.03887901056528 // 시작 위도
        let originLongitude = 131.8512689120819 // 시작 경도
        let destinationLatitude = 43.1368075169225 // 도착 위도
        let destinationLongitude = 141.42493501345194 // 도착 경도
        
        let origin = "\(originLatitude),\(originLongitude)"
        let destination = "\(destinationLatitude),\(destinationLongitude)"

        
        // 구글 API로 경로 정보 불러오는기
        let directionsURL = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&key=\(Define.GOOGLE_API_KEY)"

        
        print("DirectionsURL : \(directionsURL)")
        if let url = URL(string: directionsURL) {
            URLSession.shared.dataTask(with: url) { (data, response, error) in
                if let data = data {
                    do {
                        if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
                            if let routes = json["routes"] as? [[String: Any]] {
                                if let route = routes.first,
                                   let overviewPolyline = route["overview_polyline"] as? [String: String],
                                   let points = overviewPolyline["points"] {
                                    // Decode the polyline points and create a GMSPolyline
                                    if let path = GMSPath(fromEncodedPath: points) {
                                        let polyline = GMSPolyline(path: path)
                                        polyline.strokeWidth = 3.0
                                        polyline.map = self.mapView
                                    }
                                }
                            }
                        }
                    } catch {
                        print("Error parsing JSON: \(error)")
                    }
                }
            }.resume()
        }
    }

댓글남기기