Commit 5e4e2e3c authored by shigemi miura's avatar shigemi miura

Merge trial-chat2 into develop

parents 0b014901 9aeb57c1
...@@ -11,9 +11,10 @@ struct ChatView: View { ...@@ -11,9 +11,10 @@ struct ChatView: View {
@EnvironmentObject private var selectedTabModel: SelectedTabModel @EnvironmentObject private var selectedTabModel: SelectedTabModel
@ObservedObject var message = SharingData.message @ObservedObject var message = SharingData.message
@State var isShowMember: Bool = false @State var isShowMember: Bool = false
var body: some View { var body: some View {
ZStack { ZStack {
if message.mode == 1{ if message.mode == true{
LinearGradient(gradient: Gradient(colors: [.chatEmargencyColor1, .chatEmargencyColor2]), startPoint: .top, endPoint: .bottom) LinearGradient(gradient: Gradient(colors: [.chatEmargencyColor1, .chatEmargencyColor2]), startPoint: .top, endPoint: .bottom)
.ignoresSafeArea() .ignoresSafeArea()
} }
...@@ -21,12 +22,14 @@ struct ChatView: View { ...@@ -21,12 +22,14 @@ struct ChatView: View {
ChatTitleView(isShowMember: $isShowMember) ChatTitleView(isShowMember: $isShowMember)
ZStack{ ZStack{
ScrollViewReader { proxy in
ScrollView(.vertical) { ScrollView(.vertical) {
VStack {
Spacer() Spacer()
.frame(height: 20) .frame(height: 20)
ForEach(message.messages, id: \.messageId) { msg in ForEach(message.messages, id: \.messageId) { msg in
if msg.fromId != String(SharingData.my.id){ if msg.from == Preferences.UserName {
//自分のメッセージ //自分のメッセージ
MyChatContentView(message: msg) MyChatContentView(message: msg)
.padding(.bottom, 24) .padding(.bottom, 24)
...@@ -37,6 +40,31 @@ struct ChatView: View { ...@@ -37,6 +40,31 @@ struct ChatView: View {
} }
} }
} }
.onAppear {
if let id = message.messages.last?.messageId {
print(debug: "ChatView:onAppear")
proxy.scrollTo(id, anchor: .center)
}
}
.onChange(of: message.messages.count) { newValue in
if let id = message.messages.last?.messageId {
withAnimation {
print(debug: "ChatView:onChange")
proxy.scrollTo(id, anchor: .center)
}
}
}
.onReceive(message.$messages) { (value) in
withAnimation {
guard !value.isEmpty else {return}
if let id = message.messages.last?.messageId {
print(debug: "ChatView:onReceive")
proxy.scrollTo(id, anchor: .center)
}
}
}
}
}
HStack { HStack {
Spacer() Spacer()
VStack{ VStack{
...@@ -56,10 +84,9 @@ struct ChatView: View { ...@@ -56,10 +84,9 @@ struct ChatView: View {
ChatMemberView() ChatMemberView()
} }
} }
}
ChatInputView() ChatInputView()
} }
}
.background(ColorSet.BackgroundPrimary.color) .background(ColorSet.BackgroundPrimary.color)
} }
} }
......
...@@ -12,26 +12,31 @@ class GetMessage { ...@@ -12,26 +12,31 @@ class GetMessage {
func start() { func start() {
print(debug: "called") print(debug: "called")
sessionGetMessage.RequestGetMessage(responseGetMessage) sessionGetMessage.RequestGetMessage { response in
} switch response {
private func responseGetMessage(result: Result<Data, APIError>) {
print(debug: "called")
switch result {
case .success(let resultData): case .success(let resultData):
let serverSession = ServerSession() let serverSession = ServerSession()
let resjson = serverSession.fromJSON(resultData: resultData, resltType: ResGetMessages.self) let resjson = serverSession.fromJSON(resultData: resultData, resltType: ResGetMessages.self)
if let res = resjson { if let res = resjson {
SharingData.message.mode = res.mode if res.mode == 1 {
SharingData.message.mode = true
} else {
SharingData.message.mode = false
}
SharingData.message.messages = [] SharingData.message.messages = []
if let msg = res.messages { if let msg = res.messages {
SharingData.message.messages = msg SharingData.message.messages = msg
} }
SharingData.message.users = []
if let users = res.users {
SharingData.message.users = users
}
} }
case .failure(let errorCode): case .failure(let errorCode):
print(debug: errorCode) print(debug: errorCode)
break break
} }
} }
}
} }
//
// Imagepicker.swift
// Sailassist
//
// Created by 三浦薫巳 on 2024/01/19.
//
import SwiftUI
struct Imagepicker : UIViewControllerRepresentable {
@Binding var show: Bool
@Binding var image: Data
var sourceType: UIImagePickerController.SourceType
func makeCoordinator() -> Imagepicker.Coodinator {
return Imagepicker.Coordinator(parent: self)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<Imagepicker>) -> UIImagePickerController {
let controller = UIImagePickerController()
controller.sourceType = sourceType
controller.delegate = context.coordinator
return controller
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<Imagepicker>) {
}
class Coodinator: NSObject,UIImagePickerControllerDelegate,UINavigationControllerDelegate {
var parent : Imagepicker
init(parent : Imagepicker){
self.parent = parent
}
//Cancel
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
self.parent.show.toggle()
}
//Use Photo
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let image = info[.originalImage] as! UIImage
let data = image.pngData()
self.parent.image = data!
self.parent.show.toggle()
}
}
}
//
// CameraView.swift
// Sailassist
//
// Created by 三浦薫巳 on 2024/01/19.
//
import SwiftUI
struct CameraView: View {
@Binding var imageData : Data
@Binding var source: UIImagePickerController.SourceType
@Binding var isActionSheet: Bool
@Binding var isImagePicker: Bool
var body: some View {
NavigationStack {
List {
}.navigationDestination(isPresented: $isImagePicker) {
Imagepicker(show: $isImagePicker, image: $imageData, sourceType: source)
}
}
.ignoresSafeArea(.all, edges: .top)
.background(Color.primary.opacity(0.06).ignoresSafeArea(.all, edges: .all))
}
}
...@@ -9,14 +9,69 @@ import SwiftUI ...@@ -9,14 +9,69 @@ import SwiftUI
struct ChatInputView: View { struct ChatInputView: View {
@EnvironmentObject private var sceneDelegate: SceneDelegate @EnvironmentObject private var sceneDelegate: SceneDelegate
@ObservedObject var sessionUploadImage: SessionUploadImage = SessionUploadImage()
@State var inputText = "" @State var inputText = ""
@State private var selectionValue = 3
@State var isCamera: Bool = false
@State var isPhoto: Bool = false
@State var isImportFile: Bool = false
@State var imageData : Data = .init(capacity:0)
@State var source:UIImagePickerController.SourceType = .photoLibrary
@State var isActionSheet = false
@State var isImagePicker = false
@FocusState var isKeyboard : Bool @FocusState var isKeyboard : Bool
var body: some View { var body: some View {
VStack(spacing: 0){ VStack(spacing: 0){
Spacer() Spacer()
Divider() Divider()
HStack(spacing: 10){ HStack(spacing: 10){
Button {
sceneDelegate.tabWindow?.isHidden = true
isCamera = true
source = .camera
isImagePicker.toggle()
} label: {
Image(systemName: "camera")
.resizable()
.frame(width: 24, height: 24)
.padding(10)
}
Menu {
Button(action: {
print("Photo Library")
sceneDelegate.tabWindow?.isHidden = true
isCamera = true
source = .photoLibrary
isImagePicker.toggle()
}) {
Label("Photo Library", systemImage: "photo.on.rectangle")
}
Button(action: {
print("Take Photo")
sceneDelegate.tabWindow?.isHidden = true
isImportFile = true
}) {
Label("Take Phot", systemImage: "camera")
}
Button(action: {
print("Choose File")
sceneDelegate.tabWindow?.isHidden = true
isCamera = true
source = .photoLibrary
isImagePicker.toggle()
}) {
Label("Choose File", systemImage: "folder")
}
} label: {
Image(systemName: "photo")
.resizable()
.frame(width: 24, height: 24)
.padding(10)
}
TextField("", text: $inputText, onEditingChanged: { isEdit in TextField("", text: $inputText, onEditingChanged: { isEdit in
sceneDelegate.tabWindow?.isHidden = isEdit sceneDelegate.tabWindow?.isHidden = isEdit
}) })
...@@ -31,7 +86,9 @@ struct ChatInputView: View { ...@@ -31,7 +86,9 @@ struct ChatInputView: View {
Button{ Button{
isKeyboard = false isKeyboard = false
let signalRService = SignalR()
signalRService.chatMessage(message: inputText)
inputText = ""
} label: { } label: {
Image("send") Image("send")
.resizable() .resizable()
...@@ -42,8 +99,47 @@ struct ChatInputView: View { ...@@ -42,8 +99,47 @@ struct ChatInputView: View {
.padding(.trailing, 11) .padding(.trailing, 11)
} }
.background(ColorSet.BackgroundSecondary.color) .background(ColorSet.BackgroundSecondary.color)
.fullScreenCover(isPresented: .constant(isImagePicker), onDismiss: {
//シートを閉じる時に実行する処理
sceneDelegate.tabWindow?.isHidden = false
if imageData.count != 0 {
let jpegData = UIImage(data: imageData)!.jpegData(compressionQuality: 1.0)
let uploadImage = ReqUploadImage(shipId: Preferences.shipId, messageId: UUID().uuidString, location: 2, from: Preferences.UserName, fromId: String(SharingData.my.id), files: jpegData!)
sessionUploadImage.RequestUploadImage(uploadImage, completion: responseUploadImage)
} }
}, content: {
CameraView(imageData: $imageData, source: $source, isActionSheet: $isActionSheet, isImagePicker: $isImagePicker)
})
.fileImporter(isPresented: $isImportFile, allowedContentTypes: [.png, .jpeg, .pdf]) { result in
switch result {
case .success(let url):
guard let imageData = try? Data(contentsOf: url) else { return }
if imageData.count != 0 {
let jpegData = UIImage(data: imageData)!.jpegData(compressionQuality: 1.0)
let uploadImage = ReqUploadImage(shipId: Preferences.shipId, messageId: UUID().uuidString, location: 2, from: Preferences.UserName, fromId: String(SharingData.my.id), files: jpegData!)
sessionUploadImage.RequestUploadImage(uploadImage, completion: responseUploadImage)
}
case .failure:
print("failure")
}
}
}
.frame(maxHeight: 55)
}
func responseUploadImage(result: Result<Data, APIError>) {
print(debug: "calld")
switch result {
case .success(let resultData):
let serverSession = ServerSession()
let resjson = serverSession.fromJSON(resultData: resultData, resltType: ResLogin.self)
case .failure(let errorCode):
print(debug: errorCode)
break
}
} }
} }
......
...@@ -8,12 +8,13 @@ ...@@ -8,12 +8,13 @@
import SwiftUI import SwiftUI
struct ChatMemberView: View { struct ChatMemberView: View {
var members = ["Yokoyama", "Nogami", "Arahira", "Enokido"] @ObservedObject var message = SharingData.message
// var members = ["Yokoyama", "Nogami", "Arahira", "Enokido"]
var body: some View { var body: some View {
VStack { VStack {
List { List {
ForEach(members, id: \.self) { member in ForEach(message.users, id: \.id) { user in
Text(member) Text(user.name)
.foregroundColor(ColorSet.BodyChat.color) .foregroundColor(ColorSet.BodyChat.color)
.font(FontStyle.SupplementText.font) .font(FontStyle.SupplementText.font)
} }
......
...@@ -9,10 +9,10 @@ import SwiftUI ...@@ -9,10 +9,10 @@ import SwiftUI
struct ChatTitleView: View { struct ChatTitleView: View {
@Binding var isShowMember: Bool @Binding var isShowMember: Bool
var body: some View { @ObservedObject var message = SharingData.message
var body: some View {
VStack { VStack {
HStack { HStack {
Button{ Button{
...@@ -25,11 +25,15 @@ struct ChatTitleView: View { ...@@ -25,11 +25,15 @@ struct ChatTitleView: View {
Spacer() Spacer()
HStack(spacing: 8) { HStack(spacing: 8) {
VStack{ VStack{
Text("JMB-Demo(0518)") Text(SharingData.my.shipName)
.font(FontStyle.TitleL.font) .font(FontStyle.TitleL.font)
Text("Yokoyama,Nogami,Arahira,Enokida")
.font(FontStyle.TitleSBold.font)
HStack {
ForEach(message.users, id: \.id) { user in
Text(user.name + ",")
.font(FontStyle.TitleS.font)
}
}
} }
.foregroundColor(ColorSet.Body.color) .foregroundColor(ColorSet.Body.color)
.frame(width: 162,height: 44) .frame(width: 162,height: 44)
......
...@@ -13,12 +13,59 @@ struct MyChatContentView: View { ...@@ -13,12 +13,59 @@ struct MyChatContentView: View {
HStack { HStack {
Spacer() Spacer()
VStack(alignment: .trailing, spacing: 6) { VStack(alignment: .trailing, spacing: 6) {
Group {
if message.message.contains("https://") { //TODO: stampIdが0
AsyncImage(url: URL(string: message.message)) { image in
image.resizable()
.frame(width: 200, height: 200)
.contextMenu {
Button(action: {
print("fight")
}) {
Text("Share...")
Image(systemName: "square.and.arrow.up")
}
Button(action: {
print("bag")
}) {
Text("Save to Photos")
Image(systemName: "square.and.arrow.down")
}
Button(action: {
print("pokemon")
}) {
Text("Copy")
Image(systemName: "doc.on.doc")
}
Button(action: {
print("run")
}) {
Text("Copy Subject")
Image(systemName: "circle.dashed.rectangle")
}
Button(action: {
print("run")
}) {
Text("Show Text")
Image(systemName: "text.viewfinder")
}
}
} placeholder: {
ProgressView()
}
} else {
Text(message.message) Text(message.message)
.font(FontStyle.DefaultText.font) .font(FontStyle.DefaultText.font)
.foregroundColor(ColorSet.BodyChat.color) .foregroundColor(ColorSet.BodyChat.color)
.padding(15) .padding(15)
.background(ColorSet.ChatBaloon.color) .background(ColorSet.ChatBaloon.color)
.cornerRadius(10, corners: [.tl, .tr, .bl]) .cornerRadius(10, corners: [.tl, .tr, .br])
}
}
HStack(spacing: 0){ HStack(spacing: 0){
Text(DateTextLib.ISO86012FormatText(message.time, format: "yyyy/MM/dd hh:mm", errFormat: "")) Text(DateTextLib.ISO86012FormatText(message.time, format: "yyyy/MM/dd hh:mm", errFormat: ""))
......
...@@ -16,12 +16,59 @@ struct OtherChatContentView: View { ...@@ -16,12 +16,59 @@ struct OtherChatContentView: View {
.font(FontStyle.EmphasisText.font) .font(FontStyle.EmphasisText.font)
.foregroundColor(ColorSet.Body.color) .foregroundColor(ColorSet.Body.color)
VStack(alignment: .leading, spacing: 10) { VStack(alignment: .leading, spacing: 10) {
Group {
if message.message.contains("https://") { //TODO: stampIdが0
AsyncImage(url: URL(string: message.message)) { image in
image.resizable()
.frame(width: 200, height: 200)
.contextMenu {
Button(action: {
print("fight")
}) {
Text("Share...")
Image(systemName: "square.and.arrow.up")
}
Button(action: {
print("bag")
}) {
Text("Save to Photos")
Image(systemName: "square.and.arrow.down")
}
Button(action: {
print("pokemon")
}) {
Text("Copy")
Image(systemName: "doc.on.doc")
}
Button(action: {
print("run")
}) {
Text("Copy Subject")
Image(systemName: "circle.dashed.rectangle")
}
Button(action: {
print("run")
}) {
Text("Show Text")
Image(systemName: "text.viewfinder")
}
}
} placeholder: {
ProgressView()
}
} else {
Text(message.message) Text(message.message)
.font(FontStyle.DefaultText.font) .font(FontStyle.DefaultText.font)
.foregroundColor(ColorSet.BodyChat.color) .foregroundColor(ColorSet.BodyChat.color)
.padding(15) .padding(15)
.background(ColorSet.ChatBaloon.color) .background(ColorSet.ChatBaloon.color)
.cornerRadius(10, corners: [.tl, .tr, .br]) .cornerRadius(10, corners: [.tl, .tr, .br])
}
}
HStack(alignment: .top){ HStack(alignment: .top){
Text(DateTextLib.ISO86012FormatText(message.time, format: "yyyy/MM/dd hh:mm", errFormat: "")) Text(DateTextLib.ISO86012FormatText(message.time, format: "yyyy/MM/dd hh:mm", errFormat: ""))
...@@ -30,6 +77,14 @@ struct OtherChatContentView: View { ...@@ -30,6 +77,14 @@ struct OtherChatContentView: View {
} }
} }
} }
.onAppear {
//既読確認
let result = message.viewer.first(where: {$0.id == String(SharingData.my.id)})
if result == nil {
let signalRService = SignalR()
signalRService.ackMessage(messageId: message.messageId)
}
}
.padding(.leading, 20) .padding(.leading, 20)
Spacer() Spacer()
} }
......
//
// ReqUploadImage.swift
// Sailassist
//
// Created by 三浦薫巳 on 2024/01/29.
//
import Foundation
struct ReqUploadImage : Codable {
var shipId: Int
var messageId: String //UUID
var location: Int //1:Shore、2:Ship
var from: String //投稿者名
var fromId: String //ユーザーID
var files: Data
}
//
// ResAckMessage.swift
// Sailassist
//
// Created by 三浦薫巳 on 2024/01/05.
//
import Foundation
struct ResAckMessage: Codable {
var shipId: Int
var messageId: String //UUID
var time: String //投稿日時
var location: Int //1:Shore、2:Ship
var fromId: String //ユーザーID
}
//
// ResChatMessage.swift
// Sailassist
//
// Created by 三浦薫巳 on 2024/01/05.
//
import Foundation
struct ResChatMessage: Codable {
var shipId: Int
var messageId: String //UUID
var type: Int //0:テキスト、1:スタンプ
var time: String //投稿日時
var location: Int //1:Shore、2:Ship
var from: String //投稿者名
var fromId: String //ユーザーID
var message: String //テキスト
var stampId: Int //スタンプ番号
}
//
// ResChatMode.swift
// Sailassist
//
// Created by 三浦薫巳 on 2024/01/05.
//
import Foundation
struct ResChatMode: Codable {
var shipId: Int
var time: String //投稿日時
var location: Int //1:Shore、2:Ship
var fromId: String //ユーザーID
var mode: Int //0:通常、1:Warning中
}
...@@ -10,16 +10,17 @@ import Foundation ...@@ -10,16 +10,17 @@ import Foundation
struct ResGetMessages: Codable { struct ResGetMessages: Codable {
var mode: Int // 0:通常 , 1:Warning中 var mode: Int // 0:通常 , 1:Warning中
var messages: [ChatMessage]? var messages: [ChatMessage]?
var users: [ChatUser]?
} }
struct ChatMessage: Codable { struct ChatMessage: Codable {
var shipId: UInt var shipId: Int
var messageId: String //各メッセージ固有ID var messageId: String //各メッセージ固有ID
var type: Int //0:テキスト , 1:スタンプ , 2:画像 var type: Int //0:テキスト , 1:スタンプ , 2:画像
var time: String //投稿日時 var time: String //投稿日時
var location: Int //1:Shore , 2:Ship var location: Int //1:Shore , 2:Ship
var from: String //投稿者名 var from: String //投稿者名
var fromId: String //ユーザーID var fromId: String? //ユーザーID
var message: String //テキスト時:テキスト , 画像時:サムネイルのUri var message: String //テキスト時:テキスト , 画像時:サムネイルのUri
var stampId: Int //スタンプ番号 0:Fire~ var stampId: Int //スタンプ番号 0:Fire~
var viewer: [Viewer] //閲覧者情報 var viewer: [Viewer] //閲覧者情報
...@@ -30,3 +31,10 @@ struct Viewer: Codable { ...@@ -30,3 +31,10 @@ struct Viewer: Codable {
var location: Int //1:Shore , 2:Ship var location: Int //1:Shore , 2:Ship
var id: String //ユーザーID var id: String //ユーザーID
} }
struct ChatUser: Codable {
var time: String //最終アクセス日時
var location: Int //1:Shore , 2:Ship
var id: String //ログイン時のデバイスID
var name: String //ユーザー名
}
...@@ -17,10 +17,12 @@ struct MapRepresentable: UIViewControllerRepresentable{ ...@@ -17,10 +17,12 @@ struct MapRepresentable: UIViewControllerRepresentable{
@ObservedObject var pushHistory = SharingData.pushHistory @ObservedObject var pushHistory = SharingData.pushHistory
@State var mapVC = MapViewController() @State var mapVC = MapViewController()
//作成したいViewControllerを返すメソッド
func makeUIViewController(context: Context) -> some UIViewController { func makeUIViewController(context: Context) -> some UIViewController {
mapVC mapVC
} }
//Viewが更新された場合に必要な処理を実装
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) { func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
let ecaArea = ecaData.ecaArea.map{ $0.1 }.filter{ $0.isRunning }.first let ecaArea = ecaData.ecaArea.map{ $0.1 }.filter{ $0.isRunning }.first
if let ecaArea = ecaArea{ if let ecaArea = ecaArea{
...@@ -29,6 +31,7 @@ struct MapRepresentable: UIViewControllerRepresentable{ ...@@ -29,6 +31,7 @@ struct MapRepresentable: UIViewControllerRepresentable{
mapVC.removeEcaLine() mapVC.removeEcaLine()
} }
//ECA領域を画面中央に表示
if let focusEcaAreaId = ecaData.focusEca, let focusEca = ecaData.ecaArea[focusEcaAreaId]{ if let focusEcaAreaId = ecaData.focusEca, let focusEca = ecaData.ecaArea[focusEcaAreaId]{
mapVC.updateCamera(location: focusEca.centerPosition, zoomlevel: focusEca.zoomLevel) mapVC.updateCamera(location: focusEca.centerPosition, zoomlevel: focusEca.zoomLevel)
mapVC.updateOneTimeEca(eca: focusEca.points) mapVC.updateOneTimeEca(eca: focusEca.points)
...@@ -38,6 +41,7 @@ struct MapRepresentable: UIViewControllerRepresentable{ ...@@ -38,6 +41,7 @@ struct MapRepresentable: UIViewControllerRepresentable{
} }
} }
//通知場所を画面中央に表示
if let focusPushHistoryId = pushHistory.focusPushHistory, let focusPushHistory = pushHistory.pushHistoryData[focusPushHistoryId]{ if let focusPushHistoryId = pushHistory.focusPushHistory, let focusPushHistory = pushHistory.pushHistoryData[focusPushHistoryId]{
if let position = focusPushHistory.position { if let position = focusPushHistory.position {
if let latitude = position.lat, let longitude = position.lon { if let latitude = position.lat, let longitude = position.lon {
......
...@@ -13,7 +13,6 @@ class GetManualUrl { ...@@ -13,7 +13,6 @@ class GetManualUrl {
func start() { func start() {
print(debug: "called") print(debug: "called")
sessionGetManualUrl.getManualUrl { response in sessionGetManualUrl.getManualUrl { response in
print(debug: "called")
switch response { switch response {
case .success(let resultData): case .success(let resultData):
print(debug: String(data: resultData, encoding: .utf8) as Any) print(debug: String(data: resultData, encoding: .utf8) as Any)
......
...@@ -221,7 +221,7 @@ struct MenuView: View { ...@@ -221,7 +221,7 @@ struct MenuView: View {
loginViewModel.isLogin = false loginViewModel.isLogin = false
sceneDelegate.tabWindow?.isHidden = true sceneDelegate.tabWindow?.isHidden = true
SharingData.message.mode = 0 SharingData.message.mode = false
SharingData.message.messages = [] SharingData.message.messages = []
SharingData.pushHistory.focusPushHistory = nil SharingData.pushHistory.focusPushHistory = nil
...@@ -231,6 +231,8 @@ struct MenuView: View { ...@@ -231,6 +231,8 @@ struct MenuView: View {
SharingData.map.legLine = [] SharingData.map.legLine = []
SharingData.map.portLine = [] SharingData.map.portLine = []
SharingData.map.starboardLine = [] SharingData.map.starboardLine = []
connection!.stop()
} }
Button("No") {} Button("No") {}
} message: { Text("Are you sure?") } } message: { Text("Are you sure?") }
......
This diff is collapsed.
...@@ -79,6 +79,50 @@ class ServerSession{ ...@@ -79,6 +79,50 @@ class ServerSession{
}).resume() }).resume()
} }
func postForm(boundary: String, _ req_url : URL, _ postdata : Data, completion: @escaping (SessionResponse) -> Void){
var req = URLRequest(url: req_url)
req.httpMethod = "POST"
req.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
req.setValue("\(postdata.count)", forHTTPHeaderField: "Content-Length")
req.httpBody = postdata
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 error != nil{
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()
}
func getJson(_ req_url : URL, completion: @escaping (SessionResponse) -> Void){ func getJson(_ req_url : URL, completion: @escaping (SessionResponse) -> Void){
var req = URLRequest(url: req_url) var req = URLRequest(url: req_url)
...@@ -164,4 +208,44 @@ class ServerSession{ ...@@ -164,4 +208,44 @@ class ServerSession{
} }
return false return false
} }
func httpBody(boundary: String, _ uploadImage : ReqUploadImage) -> Data! {
var httpBody1 = "--\(boundary)\r\n"
httpBody1 += "Content-Disposition: form-data; name=\"shipId\"\r\n"
httpBody1 += "\r\n"
httpBody1 += "\(uploadImage.shipId)\r\n"
httpBody1 += "--\(boundary)\r\n"
httpBody1 += "Content-Disposition: form-data; name=\"messageId\"\r\n"
httpBody1 += "\r\n"
httpBody1 += "\(uploadImage.messageId)\r\n"
httpBody1 += "--\(boundary)\r\n"
httpBody1 += "Content-Disposition: form-data; name=\"location\"\r\n"
httpBody1 += "\r\n"
httpBody1 += "\(uploadImage.location)\r\n"
httpBody1 += "--\(boundary)\r\n"
httpBody1 += "Content-Disposition: form-data; name=\"from\"\r\n"
httpBody1 += "\r\n"
httpBody1 += "\(uploadImage.from)\r\n"
httpBody1 += "--\(boundary)\r\n"
httpBody1 += "Content-Disposition: form-data; name=\"fromId\"\r\n"
httpBody1 += "\r\n"
httpBody1 += "\(uploadImage.fromId)\r\n"
httpBody1 += "--\(boundary)\r\n"
// httpBody1 += "Content-Disposition: form-data; name=\"files\"; filename=\"\(uploadImage.files)\"\r\n"
httpBody1 += "Content-Type: image/jpeg\r\n"
httpBody1 += "\r\n"
// var tmp = httpBody1.data(using: .utf8)!
var httpBody = Data()
httpBody.append(httpBody1.data(using: .utf8)!)
httpBody.append(uploadImage.files)
var httpBody2 = "\r\n"
httpBody2 += "--\(boundary)--\r\n"
httpBody.append(httpBody2.data(using: .utf8)!)
return httpBody
}
} }
...@@ -19,7 +19,7 @@ class SessionUploadImage : ObservableObject { ...@@ -19,7 +19,7 @@ class SessionUploadImage : ObservableObject {
/** /**
* メッセージ * メッセージ
*/ */
func RequestGetUploadImage(_ completion: @escaping ((Result<Data, APIError>)) -> Void) { func RequestUploadImage(_ uploadImage : ReqUploadImage ,completion: @escaping ((Result<Data, APIError>)) -> Void) {
print(debug: "calld") print(debug: "calld")
if Calling { if Calling {
return return
...@@ -27,19 +27,20 @@ class SessionUploadImage : ObservableObject { ...@@ -27,19 +27,20 @@ class SessionUploadImage : ObservableObject {
Calling = true Calling = true
// リクエストURLの組み立て // リクエストURLの組み立て
// リクエストURLの組み立て let url_string : String = HttpRequestType.UploadImage.rawValue
// let url_string : String = HttpRequestType.UploadImage.rawValue guard let req_url = URL(string : url_string) else {
// guard let req_url = URL(string : url_string) else { Calling = false
// Calling = false return
// return }
// }
// if let postdata = serverSession.toJSON(login) { // let boundary = "----------" + UUID().uuidString
// serverSession.postJson(req_url, postdata, completion: completion) let boundary = "----WebKitFormBoundaryZLdHZy8HNaBmUX0d"
// } if let postdata = serverSession.httpBody(boundary: boundary, uploadImage) {
// else { serverSession.postForm(boundary: boundary, req_url, postdata, completion: completion)
// Calling = false }
// return else {
// } Calling = false
return
}
} }
} }
...@@ -116,8 +116,13 @@ class SharingData{ ...@@ -116,8 +116,13 @@ class SharingData{
static var message = Message() static var message = Message()
class Message: ObservableObject { class Message: ObservableObject {
@Published var mode: Int = 0 // 0:通常 , 1:Warning中 @Published var mode: Bool = false // false:通常 , true:Warning中
@Published var messages: [ChatMessage] = [] @Published var messages: [ChatMessage] = []
@Published var users: [ChatUser] = []
func changeMode(){
self.mode.toggle()
}
} }
static var information = Information() static var information = Information()
......
//
// SignalRService.swift
// Sailassist
//
// Created by 三浦薫巳 on 2023/11/17.
//
import Foundation
import SwiftSignalRClient
public class SignalRService {
private var connection: HubConnection
private var hubConnectionDelegate: HubConnectionDelegate?
public init() {
// hubConnectionDelegate = ChatHubConnectionDelegate(app: self)
hubConnectionDelegate = ChatHubConnectionDelegate()
connection = HubConnectionBuilder(url: URL(string : HttpRequestType.SignalR.rawValue)!)
.withHubConnectionDelegate(delegate: hubConnectionDelegate!)
.withAutoReconnect()
.withLogging(minLogLevel: .error).build()
connection.on(method: "chatMessage", callback: { (shipId: Int, messageId: Int, type: Int, time: String, location: Int, from: String, fromeId: Int, message: String) in
self.handleChatMessage(message, from: from)
})
connection.on(method: "ackMessage", callback: { (shipId: Int, time: String, location: Int, fromId: Int, mode: Int) in
self.handleAckMessage(time)
})
connection.on(method: "chatMode", callback: { (shipId: Int, time: String, location: Int, fromId: String, mode: Int) in
self.handleChatMessage(fromId)
})
connection.start()
}
private func handleChatMessage(_ message: String, from user: String) {
print(debug: "called")
}
private func handleAckMessage(_ time: String) {
print(debug: "called")
}
private func handleChatMessage(_ fromId: String) {
print(debug: "called")
}
func applicationWillTerminate(_ aNotification: Notification) {
connection.stop()
}
//呼び出す
func chatMessage(_ message: String) {
var request = ReqMessage(shipId: Preferences.shipId, messageId: "aaaa")
request.type = 0 //0:テキスト, 1:スタンプ
// request.time = DateTextLib.Date2ISO8601Text(date: Date())
request.location = 2 //1:Shore , 2:Ship
request.from = Preferences.UserName //投稿者名
// request.fromeId = SharingData.my.shipName //ユーザーID
request.message = message //テキスト
// request.stampId = //スタンプ番号 0:Fire~
if message != "" {
connection.invoke(method: "ChatMessage", message) { error in
if let e = error {
print(debug: "Error:\(e)")
}
}
}
}
func ackMessage(_ message: String) {
var request = ReqAckMessage(shipId: Preferences.shipId, messageId: "aaaa")
//request.time = DateTextLib.Date2ISO8601Text(date: Date())
request.location = 2 //1:Shore , 2:Ship
// request.fromeId = SharingData.my.shipName //ユーザーID
if message != "" {
connection.invoke(method: "AckMessage", request) { error in
if let e = error {
print(debug: "Error:\(e)")
}
}
}
}
func chatMode(_ message: String) {
var request = ReqChatModeMessage(shipId: Preferences.shipId)
// request.time = DateTextLib.Date2ISO8601Text(date: Date())
request.location = 2 //1:Shore , 2:Ship
// request.fromeId = SharingData.my.shipName //ユーザーID
request.mode = 0 //0:通常 / 1:Warning中
if message != "" {
connection.invoke(method: "ChatMode", message) { error in
if let e = error {
print(debug: "Error:\(e)")
}
}
}
}
// func chatMode2(_ message: String) {
// connection.send(method: "Broadcast", "Playground user", "Testing send") { error in
// if let error = error {
// print("Send failed: \(error)")
// }
// }
// }
}
class ChatHubConnectionDelegate: HubConnectionDelegate {
// weak var app: AppDelegate?
//
// init(app: AppDelegate) {
// self.app = app
// }
func connectionDidOpen(hubConnection: HubConnection) {
print("connectionDidOpen")
// After connection established call registerUserInServer method
DispatchQueue.main.async {
// self.registerUserInServer()
}
}
func connectionDidFailToOpen(error: Error) {
print("connectionDidFailToOpen")
}
func connectionDidClose(error: Error?) {
print("connectionDidClose")
}
func connectionWillReconnect(error: Error) {
print("connectionWillReconnect")
}
func connectionDidReconnect() {
print("connectionDidReconnect")
}
}
...@@ -122,12 +122,20 @@ struct CustomTabBar: View { ...@@ -122,12 +122,20 @@ struct CustomTabBar: View {
} }
}, label: { }, label: {
VStack{ VStack{
ZStack(alignment: .bottomTrailing) {
Image(selectedTabModel.activeTab == tab ? tab.rawValue + "_selected" : tab.rawValue) Image(selectedTabModel.activeTab == tab ? tab.rawValue + "_selected" : tab.rawValue)
.font(.title2) .font(.title2)
// if tab == Tab.chat {
// Rectangle()
// .foregroundColor(.red)
// .frame(width: 12, height: 12)
// .cornerRadius(60)
// }
}
Text(tab.title) Text(tab.title)
.font(.caption) .font(.caption)
} }
.frame(maxWidth: .infinity, maxHeight: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
.contentShape(.rect) .contentShape(.rect)
...@@ -140,11 +148,9 @@ struct CustomTabBar: View { ...@@ -140,11 +148,9 @@ struct CustomTabBar: View {
.background(ColorSet.BottomNav.color) .background(ColorSet.BottomNav.color)
.alert("", isPresented: $selectedTabModel.isShowChangeEmrMode) { .alert("", isPresented: $selectedTabModel.isShowChangeEmrMode) {
Button("Yes"){ Button("Yes"){
if SharingData.message.mode == 0{ SharingData.message.changeMode()
SharingData.message.mode = 1 let signalRService = SignalR()
}else{ signalRService.chatMode(mode: SharingData.message.mode)
SharingData.message.mode = 0
}
} }
Button("No"){ Button("No"){
......
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