Commit a1620e01 authored by sugita mamoru's avatar sugita mamoru

Merge commit '4bc8200f' into develop

parents f1b96f97 4bc8200f
//
// GetMessage.swift
// Sailassist
//
// Created by 三浦薫巳 on 2023/11/14.
//
import Foundation
class GetMessage {
var sessionGetMessage = SessionGetMessage()
func start() {
print(debug: "called")
sessionGetMessage.RequestGetMessage(responseGetMessage)
}
private func responseGetMessage(result: Result<Data, APIError>) {
print(debug: "called")
switch result {
case .success(let resultData):
let serverSession = ServerSession()
let resjson = serverSession.fromJSON(resultData: resultData, resltType: ResGetMessages.self)
if let res = resjson {
SharingData.Message.mode = res.mode
SharingData.Message.messages = []
if let msg = res.messages {
SharingData.Message.messages = msg
}
}
case .failure(let errorCode):
print(debug: errorCode)
break
}
}
}
......@@ -8,28 +8,40 @@
import SwiftUI
struct ContentView: View {
@State var isLogin = true//ContentView.LoginCheck()
@State var isLogin = false//ContentView.LoginCheck()
@EnvironmentObject private var sceneDelegate: SceneDelegate
@StateObject var locationViewModel = LocationViewModel()
var selectedTabModel = SelectedTabModel()
var body: some View {
MainTabView()
.environmentObject(selectedTabModel)
.onAppear(){
if isLogin{
switch locationViewModel.authorizationStatus {
case .notDetermined:
RequestLocationView()
.environmentObject(locationViewModel)
case .restricted:
ErrorView(errorText: "位置情報の使用が制限されています。")
case .denied:
ErrorView(errorText: "位置情報を使用できません。")
case .authorizedAlways, .authorizedWhenInUse:
MainTabView()
.environmentObject(selectedTabModel)
.onAppear(){
if isLogin{
guard sceneDelegate.tabWindow == nil else{ return }
sceneDelegate.addTabBar(selectedTabModel)
selectedTabModel.activeTab = .task
}
}
.fullScreenCover(isPresented: .constant(!isLogin), onDismiss: {
guard sceneDelegate.tabWindow == nil else{ return }
sceneDelegate.addTabBar(selectedTabModel)
selectedTabModel.activeTab = .task
}
}
.fullScreenCover(isPresented: .constant(!isLogin), onDismiss: {
guard sceneDelegate.tabWindow == nil else{ return }
sceneDelegate.addTabBar(selectedTabModel)
selectedTabModel.activeTab = .task
}, content: {
LoginView(isLogin: $isLogin)
})
}, content: {
LoginView(isLogin: $isLogin)
})
default:
Text("Unexpected status")
}
}
}
......
//
// EcaTask.swift
// Sailassist
//
// Created by 三浦薫巳 on 2023/11/13.
//
import Foundation
class EcaTask {
var sessionShipStatus = SessionShipStatus()
var sharingData = SharingData.shared
func start() {
print(debug: "called")
sessionShipStatus.RequestShipStatus(responseShipStatus)
}
func responseShipStatus(result: Result<Data, APIError>) {
print(debug: "called")
switch result {
case .success(let resultData):
let serverSession = ServerSession()
let resjson = serverSession.fromJSON(resultData: resultData, resltType: ResShipStatus.self)
if let res = resjson {
SharingData.My.speed = res.speed
SharingData.My.course = res.course
SharingData.My.heading = res.heading
SharingData.My.server?.latitude = res.lat
SharingData.My.server?.longitude = res.lon
SharingData.My.dataTime = res.dataTime //2023-11-02T05:25:49.4362123Z
}
checkEca()
case .failure(let errorCode):
print(debug: errorCode)
break
}
}
private func checkEca() {
let runningEca = sharingData.ecaArea.first(where: {(key, value) in value.isRunning == true})
if let eca = runningEca?.value {
if let location = SharingData.My.location {
let distance = LocationCalculation.checkPolyLine(objPos: eca.points, shipPos: location)
if eca.swStart >= Float(distance) {
}
if eca.swNotice >= Float(distance) {
}
if eca.swFinish >= Float(distance) {
}
}
}
}
}
//
// ErrorView.swift
// Sailassist
//
// Created by 三浦薫巳 on 2023/11/13.
//
import SwiftUI
struct ErrorView: View {
var errorText: String
var body: some View {
Text(errorText)
}
}
struct ErrorView_Previews: PreviewProvider {
static var previews: some View {
ErrorView(errorText: "Error message")
}
}
......@@ -11,10 +11,17 @@ import Foundation
#if DEBUG
//MARK: デバッグサーバー用
enum HttpRequestType : String {
case RegisterLogin = "https://ssv-canary-web.azurewebsites.net/applogin"
case RegisterLogin = "https://ssv-canary-web.azurewebsites.net/sailassistlogin"
case SitePolicy = "https://ssv-canary-web.azurewebsites.net/sitepolicy"
case CookiePolicy = "https://ssv-canary-web.azurewebsites.net/cookiepolicy"
case PrivacyPolicy = "https://ssv-canary-web.azurewebsites.net/inapp?" //+バージョン番号
case TaskList = "https://ssv-canary-web.azurewebsites.net/api/sailassist/tasklist/XXXXX"
case EcaArea = "https://ssv-canary-web.azurewebsites.net/api/sailassist/ecaarea"
case ShipStatus = "https://ssv-canary-web.azurewebsites.net/api/sailassist/shipstatus/XXXXX"
case ShipMonitoringRoute = "https://ssv-canary-web.azurewebsites.net/api/sailassist/shipmonitoringroute/XXXXX"
case GetMessage = "https://ssv-canary-web.azurewebsites.net/api/chatdata/getmessages?shipId=XXXXX"
case SignalR = "https://ssv-canary-web.azurewebsites.net/signalr/shore"
case UploadImage = "https://ssv-canary-web.azurewebsites.net/api/chatdata/uploadimage"
}
#else
//MARK: 運用サーバー用
......
......@@ -5,6 +5,8 @@
<key>MBXAccessToken</key>
<string>pk.eyJ1Ijoiam1hcmluZWNsb3VkIiwiYSI6ImNsbmxjbGYzZjA0dG8yaW82MDgwajQ5OTQifQ.pd8YC9qK1C4YmMUbMx6ywQ</string>
<key>UIBackgroundModes</key>
<array/>
<array>
<string>location</string>
</array>
</dict>
</plist>
......@@ -8,11 +8,17 @@
import Foundation
struct ReqLogin : Codable {
var Id: String
var Password: String
var id: String
var password: String
init(Id: String, Password: String) {
self.Id = Id
self.Password = Password
self.id = Id
self.password = Password
}
}
struct QrLogin : Codable {
var id: String
var pass: String
var exp: String //有効期限
}
//
// ReqTaskList.swift
// Sailassist
//
// Created by 三浦薫巳 on 2023/11/14.
//
import Foundation
struct ReqTaskList : Codable {
var areaId: Int
var taskName: String
// var status:
}
//
// ResGetMessages.swift
// Sailassist
//
// Created by 三浦薫巳 on 2023/11/14.
//
import Foundation
struct ResGetMessages: Codable {
var mode: Int // 0:通常 , 1:Warning中
var messages: [message]?
}
struct message: Codable {
var shipId: UInt
var messageId: String //各メッセージ固有ID
var type: Int //0:テキスト , 1:スタンプ , 2:画像
var time: String //投稿日時
var location: Int //1:Shore , 2:Ship
var from: String //投稿者名
var fromId: String //ユーザーID
var message: String //テキスト時:テキスト , 画像時:サムネイルのUri
var stampId: Int //スタンプ番号 0:Fire~
var viewer: [view] //閲覧者情報
}
struct view: Codable {
var time: String //確認日時
var location: Int //1:Shore , 2:Ship
var id: Int //ユーザーID
}
......@@ -8,9 +8,9 @@
import Foundation
struct ResLogin : Codable {
var Id: Int = 0
var Name: String = ""
var CanUseCmap: Bool = false
var CanCheckActiveRouteAlert: Bool = false
var CanCheckBamAlert: Bool = false
var id: Int = 0
var shipId: Int = 0
var shipName: String = ""
var imo: Int = 0
var mmsi: Int = 0
}
//
// ResMonitoringRoute.swift
// Sailassist
//
// Created by 三浦薫巳 on 2023/11/14.
//
import Foundation
struct ResMonitoringRoute: Codable {
var wayPoints: [points]?
var legLine: [points]?
var portLine: [points]?
var starboardLine: [points]?
}
struct points: Codable {
var lat: Double?
var lon: Double?
}
//
// ResShipStatus.swift
// Sailassist
//
// Created by 三浦薫巳 on 2023/11/13.
//
import Foundation
struct ResShipStatus : Codable {
var dataTime: String = "" //2023-11-02T05:25:49.4362123Z
var speed: Double = 0.0
var course: Double = 0.0
var heading: Double = 0.0
var lat: Double = 0.0
var lon: Double = 0.0
}
//
// LocationViewModel.swift
// Sailassist
//
// Created by 三浦薫巳 on 2023/11/13.
//
import CoreLocation
class LocationViewModel: NSObject, ObservableObject, CLLocationManagerDelegate {
@Published var authorizationStatus: CLAuthorizationStatus
@Published var lastSeenLocation: CLLocation?
private let locationManager: CLLocationManager
override init() {
locationManager = CLLocationManager()
authorizationStatus = locationManager.authorizationStatus
super.init()
locationManager.delegate = self
locationManager.activityType = .automotiveNavigation
locationManager.distanceFilter = 100 //100mぐらい移動したら位置情報取得
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.allowsBackgroundLocationUpdates = true // バックグラウンド実行中も座標取得する場合、trueにする
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.startUpdatingLocation()
}
func requestPermission() {
locationManager.requestWhenInUseAuthorization()
locationManager.requestAlwaysAuthorization() // バックグラウンド実行中も座標取得する場合はこちら
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
authorizationStatus = manager.authorizationStatus
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let newLocation = locations.last {
let isLocation = filterLocation(newLocation)
if isLocation {
lastSeenLocation = locations.first
let targetCoordinate : CLLocationCoordinate2D = lastSeenLocation!.coordinate
SharingData.My.gps = targetCoordinate
}
}
}
func filterLocation(_ location: CLLocation) -> Bool {
let intervalTime = -location.timestamp.timeIntervalSinceNow
if intervalTime > 10 { //位置情報を取得してから10秒以上
return false
}
if location.horizontalAccuracy < 0 { //水平方向の位置精度
return false
}
if location.horizontalAccuracy > 100 { //水平方向の誤差が100m
return false
}
return true
}
}
......@@ -36,6 +36,7 @@ struct LoginView: View {
@State var alertType: AlertType = .loginFailure
@ObservedObject var scannerViewModel = ScannerViewModel()
@State var loginViewParam = LoginViewParam()
@State var timer :Timer?
var sessionLogin = SessionLogin()
var body: some View {
......@@ -141,10 +142,33 @@ struct LoginView: View {
print(debug: "calld")
switch result {
case .success(let resultData):
let jsonstr = String(data: resultData, encoding: .utf8)!
let serverSession = ServerSession()
let resjson = serverSession.fromJSON(resultData: resultData, resltType: ResLogin.self)
if let res = resjson {
SharingData.My.id = res.id
SharingData.My.shipId = res.shipId
SharingData.My.shipName = res.shipName
SharingData.My.imo = res.imo
SharingData.My.mmsi = res.mmsi
}
Preferences.lastLoginDate_Int64 = DateTextLib.Date2UnixTime(date: Date())
isLogin = true
timer = Timer.scheduledTimer(withTimeInterval: 60.0, repeats: true) { _ in
print(debug: "called timer")
let eca = EcaTask()
eca.start()
let message = GetMessage()
message.start()
let route = MonitoringRoute()
route.start()
}
case .failure(let errorCode):
print(debug: errorCode)
isLogin = false
isAlert = true
alertType = .loginFailure
......
......@@ -16,6 +16,7 @@ struct InputUserNameView: View {
@Binding var isAlert : Bool
@Binding var alertType: AlertType
@State private var isEmptyAlert = false
@State var timer :Timer?
let itemHPadding: Double = 16
let dialogBottomPadding: Double = 32
let textFieldHeight: Double = 40
......@@ -99,13 +100,36 @@ struct InputUserNameView: View {
case .success(let resultData):
let serverSession = ServerSession()
let resjson = serverSession.fromJSON(resultData: resultData, resltType: ResLogin.self)
if let res = resjson {
SharingData.My.id = res.id
SharingData.My.shipId = res.shipId
SharingData.My.shipName = res.shipName
SharingData.My.imo = res.imo
SharingData.My.mmsi = res.mmsi
}
Preferences.ShipId = param.shipId
Preferences.ShipPassword = param.password
Preferences.lastLoginDate_Int64 = DateTextLib.Date2UnixTime(date: Date())
timer = Timer.scheduledTimer(withTimeInterval: 60.0, repeats: true) { _ in
print(debug: "called timer")
let eca = EcaTask()
eca.start()
let message = GetMessage()
message.start()
let route = MonitoringRoute()
route.start()
}
isProgressView = false
isLogin = true
isAlert = false
case .failure(let errorCode):
print(debug: errorCode)
isProgressView = false
isLogin = false
isAlert = true
......
......@@ -19,10 +19,11 @@ class ScannerViewModel: ObservableObject {
self.lastQrCode = code
let decoder = JSONDecoder()
let jsonData = self.lastQrCode.data(using: .utf8)!
let resjson: ReqLogin = try decoder.decode(ReqLogin.self, from: jsonData)
let resjson: QrLogin = try decoder.decode(QrLogin.self, from: jsonData)
Preferences.ShipId = resjson.id
Preferences.ShipPassword = resjson.pass
Preferences.ShipId = resjson.Id
Preferences.ShipPassword = resjson.Password
Preferences.lastLoginDate_Int64 = DateTextLib.Date2UnixTime(date: Date())
} catch {
print(debug: "decodeエラー")
......
//
// MonitoringRoute.swift
// Sailassist
//
// Created by 三浦薫巳 on 2023/11/14.
//
import Foundation
import CoreLocation
class MonitoringRoute {
var sessionMonitoringRoute = SessionMonitoringRoute()
func start() {
print(debug: "called")
sessionMonitoringRoute.RequestMonitoringRoute(responseMonitoringRoute)
}
private func responseMonitoringRoute(result: Result<Data, APIError>) {
print(debug: "called")
switch result {
case .success(let resultData):
let serverSession = ServerSession()
let resjson = serverSession.fromJSON(resultData: resultData, resltType: ResMonitoringRoute.self)
if let res = resjson {
SharingData.Map.wayPoints = []
if let wayPoint = res.wayPoints {
wayPoint.forEach { waypoint in
var point: CLLocationCoordinate2D = CLLocationCoordinate2D()
point.latitude = CLLocationDegrees(waypoint.lat ?? 0.0)
point.longitude = CLLocationDegrees(waypoint.lon ?? 0.0)
SharingData.Map.wayPoints.append(point)
}
}
SharingData.Map.legLine = []
if let legLine = res.legLine {
legLine.forEach { legline in
var point: CLLocationCoordinate2D = CLLocationCoordinate2D()
point.latitude = CLLocationDegrees(legline.lat ?? 0.0)
point.longitude = CLLocationDegrees(legline.lon ?? 0.0)
SharingData.Map.legLine.append(point)
}
}
SharingData.Map.portLine = []
if let portLine = res.portLine {
portLine.forEach { portline in
var point: CLLocationCoordinate2D = CLLocationCoordinate2D()
point.latitude = CLLocationDegrees(portline.lat ?? 0.0)
point.longitude = CLLocationDegrees(portline.lon ?? 0.0)
SharingData.Map.portLine.append(point)
}
}
SharingData.Map.starboardLine = []
if let starboardLine = res.starboardLine {
starboardLine.forEach { starboardline in
var point: CLLocationCoordinate2D = CLLocationCoordinate2D()
point.latitude = CLLocationDegrees(starboardline.lat ?? 0.0)
point.longitude = CLLocationDegrees(starboardline.lon ?? 0.0)
SharingData.Map.starboardLine.append(point)
}
}
}
case .failure(let errorCode):
print(debug: errorCode)
break
}
}
}
......@@ -25,9 +25,6 @@ class Preferences{
@AppStorage(wrappedValue:"", PreferencesKey.TypeString.ShipId.rawValue) static var ShipId: String
@AppStorage(wrappedValue:"", PreferencesKey.TypeString.ShipPassword.rawValue) static var ShipPassword: String
@AppStorage(wrappedValue:"", PreferencesKey.TypeString.Mmsi.rawValue) static var Mmsi: String
@AppStorage(wrappedValue:"", PreferencesKey.TypeString.ShipName.rawValue) static var ShipName: String
@AppStorage(wrappedValue:"", PreferencesKey.TypeString.GroupName.rawValue) static var GroupName: String
@AppStorage(wrappedValue:"", PreferencesKey.TypeString.UserName.rawValue) static var UserName: String
// func getPreferences(key)
......
......@@ -14,9 +14,6 @@ class PreferencesKey{
enum TypeString: String{
case ShipId
case ShipPassword
case Mmsi
case ShipName
case GroupName
case UserName
}
......
//
// RequestLocationView.swift
// Sailassist
//
// Created by 三浦薫巳 on 2023/11/13.
//
import SwiftUI
struct RequestLocationView: View {
@EnvironmentObject var locationViewModel: LocationViewModel
var body: some View {
Button(action: {
locationViewModel.requestPermission()
}) {
Text("Allow use of location information.")
}
}
}
struct RequestLocationView_Previews: PreviewProvider {
static var previews: some View {
RequestLocationView().environmentObject(LocationViewModel())
}
}
......@@ -78,6 +78,49 @@ class ServerSession{
}).resume()
}
func getJson(_ req_url : URL, completion: @escaping ((Result<Data, APIError>)) -> Void){
var req = URLRequest(url: req_url)
req.addValue("application/json", forHTTPHeaderField: "Content-Type")
req.timeoutInterval = 20 // タイムアウト3秒 → Amedasでタイムアウトエラー20秒に変更
// サーバー送信
let session = URLSession(configuration: .default, delegate: nil, delegateQueue: OperationQueue.main)
session.dataTask(with: req, completionHandler: {(data, response, error ) in
session.finishTasksAndInvalidate()
do{
if let error = error{
let err = APIError.clientError
throw APIError.clientError
}
guard let indata = data, let inresponse = response as? HTTPURLResponse else {
throw APIError.responseError
}
if inresponse.statusCode != 200 {
throw APIError.serverError
}
//Cookieを保存
if let fields = inresponse.allHeaderFields as? [String: String], let url = inresponse.url {
for cookie in HTTPCookie.cookies(withResponseHeaderFields: fields, for: url) {
HTTPCookieStorage.shared.setCookie(cookie)
}
}
DispatchQueue.main.async {
completion(.success(indata))
}
}catch{
if error as? APIError != nil{
completion(.failure(error as! APIError))
}
else{
completion(.failure(.unknown))
}
}
}).resume()
}
// HTTPCookieStorageに特定のCookieが保存されているかを調べる
func isCookieSet(name: String, url: URL) -> Bool {
if let cookies = HTTPCookieStorage.shared.cookies(for: url) {
......
//
// SessionGetMessage.swift
// Sailassist
//
// Created by 三浦薫巳 on 2023/11/14.
//
import Foundation
import SwiftUI
class SessionGetMessage : ObservableObject {
@Published var status = false
// シングルトン宣言
static let OnlyOne = SessionGetMessage()
private var serverSession = ServerSession()
private var Calling : Bool = false // 通信中
/**
* メッセージ
*/
func RequestGetMessage(_ completion: @escaping ((Result<Data, APIError>)) -> Void) {
print(debug: "calld")
if Calling {
return
}
Calling = true
// リクエストURLの組み立て
let id = SharingData.My.shipId
if id != 0 {
var url_string : String = HttpRequestType.GetMessage.rawValue
url_string = url_string.replacingOccurrences(of: "XXXXX", with: String(id))
guard let req_url = URL(string : url_string) else {
Calling = false
return
}
serverSession.getJson(req_url, completion: completion)
}
}
}
//
// SessionMonitoringRoute.swift
// Sailassist
//
// Created by 三浦薫巳 on 2023/11/14.
//
import Foundation
import SwiftUI
class SessionMonitoringRoute : ObservableObject {
@Published var status = false
// シングルトン宣言
static let OnlyOne = SessionMonitoringRoute()
private var serverSession = ServerSession()
private var Calling : Bool = false // 通信中
/**
* Monitoring Route
*/
func RequestMonitoringRoute(_ completion: @escaping ((Result<Data, APIError>)) -> Void) {
print(debug: "calld")
if Calling {
return
}
Calling = true
// リクエストURLの組み立て
let id = SharingData.My.shipId
if id != 0 {
var url_string : String = HttpRequestType.ShipMonitoringRoute.rawValue
url_string = url_string.replacingOccurrences(of: "XXXXX", with: String(id))
guard let req_url = URL(string : url_string) else {
Calling = false
return
}
serverSession.getJson(req_url, completion: completion)
}
}
}
//
// SessionShipStatus.swift
// Sailassist
//
// Created by 三浦薫巳 on 2023/11/14.
//
import Foundation
import SwiftUI
class SessionShipStatus : ObservableObject {
@Published var status = false
// シングルトン宣言
static let OnlyOne = SessionShipStatus()
private var serverSession = ServerSession()
private var Calling : Bool = false // 通信中
/**
* 船情報
*/
func RequestShipStatus(_ completion: @escaping ((Result<Data, APIError>)) -> Void) {
print(debug: "calld")
if Calling {
return
}
Calling = true
// リクエストURLの組み立て
let id = SharingData.My.shipId
if id != 0 {
var url_string : String = HttpRequestType.ShipStatus.rawValue
url_string = url_string.replacingOccurrences(of: "XXXXX", with: String(id))
guard let req_url = URL(string : url_string) else {
Calling = false
return
}
serverSession.getJson(req_url, completion: completion)
}
}
}
//
// SessionTaskList.swift
// Sailassist
//
// Created by 三浦薫巳 on 2023/11/15.
//
import Foundation
import SwiftUI
class SessionTaskList : ObservableObject {
@Published var status = false
// シングルトン宣言
static let OnlyOne = SessionTaskList()
private var serverSession = ServerSession()
private var Calling : Bool = false // 通信中
/**
* メッセージ
*/
func RequestTaskList(_ completion: @escaping ((Result<Data, APIError>)) -> Void) {
print(debug: "calld")
if Calling {
return
}
Calling = true
// リクエストURLの組み立て
let id = SharingData.My.shipId
if id != 0 {
var url_string : String = HttpRequestType.TaskList.rawValue
url_string = url_string.replacingOccurrences(of: "XXXXX", with: String(id))
guard let req_url = URL(string : url_string) else {
Calling = false
return
}
serverSession.getJson(req_url, completion: completion)
}
}
}
......@@ -22,6 +22,41 @@ class SharingData: ObservableObject{
}
class My {
static var location: CLLocationCoordinate2D? = nil
static var gps: CLLocationCoordinate2D? = nil
static var server: CLLocationCoordinate2D? = nil
static var speed: Double = 0.0
static var course: Double = 0.0
static var heading: Double = 0.0
static var dataTime: String = "" //2023-11-02T05:25:49.4362123Z
static var id: Int = 0
static var shipId: Int = 0
static var shipName: String = ""
static var imo: Int = 0
static var mmsi: Int = 0
static func reset() {
location = nil
speed = 0.0
course = 0.0
heading = 0.0
}
}
class Map {
static var wayPoints: [CLLocationCoordinate2D] = []
static var legLine: [CLLocationCoordinate2D] = []
static var portLine: [CLLocationCoordinate2D] = []
static var starboardLine: [CLLocationCoordinate2D] = []
}
class Message {
static var mode: Int = 0 // 0:通常 , 1:Warning中
static var messages: [message] = []
}
/**
* Eca
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment