Commit 7f096f00 authored by shigemi miura's avatar shigemi miura

チャット機能

parent fbbb1ea7
...@@ -47,8 +47,8 @@ struct ChatView: View { ...@@ -47,8 +47,8 @@ struct ChatView: View {
} }
} }
.onChange(of: message.messages.count) { newValue in .onChange(of: message.messages.count) { newValue in
if let id = message.messages.last?.messageId {
withAnimation { withAnimation {
if let id = message.messages.last?.messageId {
print(debug: "ChatView:onChange") print(debug: "ChatView:onChange")
proxy.scrollTo(id, anchor: .center) proxy.scrollTo(id, anchor: .center)
} }
...@@ -94,3 +94,4 @@ struct ChatView: View { ...@@ -94,3 +94,4 @@ struct ChatView: View {
#Preview { #Preview {
ChatView() ChatView()
} }
...@@ -27,23 +27,7 @@ class GetMessage { ...@@ -27,23 +27,7 @@ class GetMessage {
if let msg = res.messages { if let msg = res.messages {
//既読マーク確認 //既読マーク確認
SharingData.message.messages = msg SharingData.message.messages = msg
var msgCnt = 0 //受信メッセージ数 self.checkUnreadMessages()
var viewCnt = 0 //既読メッセージ数
for message in SharingData.message.messages {
// print(debug: "message \(message)")
if message.fromId != Preferences.UserName {
msgCnt = msgCnt + 1
}
//SSV Mobileで既読
for view in message.viewer {
if view.location == 1 {
viewCnt = viewCnt + 1
}
}
}
// if msgCnt != viewCnt {
// SharingData.message.viewCnt = msgCnt - viewCnt
// }
} }
SharingData.message.users = [] SharingData.message.users = []
if let users = res.users { if let users = res.users {
...@@ -56,5 +40,49 @@ class GetMessage { ...@@ -56,5 +40,49 @@ class GetMessage {
} }
} }
} }
/**
* 未読数の確認
*/
func checkUnreadMessages() {
var msgCnt = 0 //SSV Mobileからの受信メッセージ数
var viewCnt = 0 //Sail Assistでの既読メッセージ数
for message in SharingData.message.messages {
//SSV Mobileからの受信メッセージ
if message.location == 1 {
msgCnt = msgCnt + 1
if ((message.viewer.first(where: {$0.location == 2})) != nil){
viewCnt = viewCnt + 1
}
}
}
SharingData.message.viewCnt = msgCnt - viewCnt //未読数
}
/**
* 既読通知
*/
func readNotification() {
for message in SharingData.message.messages {
//Sail Assist側で既読が無い場合(既読確認)
var unRead = true
if ((message.viewer.first(where: {$0.location == 2})) != nil){
unRead = false //既読状態
}
if unRead {
let signalRService = SignalR()
signalRService.ackMessage(messageId: message.messageId)
let msgIndex = SharingData.message.messages.firstIndex(where: {$0.messageId == message.messageId})
if let index = msgIndex {
let viewer = Viewer(time: DateTextLib.Date2ISO8601Text(Date()), location: 2, id: "")
SharingData.message.messages[index].viewer.append(viewer)
}
}
}
}
} }
...@@ -15,48 +15,22 @@ struct MyChatContentView: View { ...@@ -15,48 +15,22 @@ struct MyChatContentView: View {
VStack(alignment: .trailing, spacing: 6) { VStack(alignment: .trailing, spacing: 6) {
Group { Group {
if message.message.contains("https://") { //TODO: stampIdが0 if message.message.contains("https://") { //TODO: stampIdが0
AsyncImage(url: URL(string: message.message)) { image in AsyncImage(url: URL(string: message.message)) { phase in
image.resizable() if let image = phase.image {
.frame(width: 200, height: 200) image
.contextMenu { .resizable(resizingMode: .stretch)
Button(action: { .aspectRatio(contentMode: .fit)
print("fight") .frame(width: 250)
}) { } else if phase.error != nil {
Text("Share...") Color.gray.opacity(0.2)
Image(systemName: "square.and.arrow.up") .overlay(Image(systemName: "rectangle.slash"))
} } else {
Color.gray.opacity(0.2)
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() ProgressView()
} }
}
.cornerRadius(16)
.frame(height: 250)
} else { } else {
Text(message.message) Text(message.message)
.font(FontStyle.DefaultText.font) .font(FontStyle.DefaultText.font)
......
...@@ -18,48 +18,22 @@ struct OtherChatContentView: View { ...@@ -18,48 +18,22 @@ struct OtherChatContentView: View {
VStack(alignment: .leading, spacing: 10) { VStack(alignment: .leading, spacing: 10) {
Group { Group {
if message.message.contains("https://") { //TODO: stampIdが0 if message.message.contains("https://") { //TODO: stampIdが0
AsyncImage(url: URL(string: message.message)) { image in AsyncImage(url: URL(string: message.message)) { phase in
image.resizable() if let image = phase.image {
.frame(width: 200, height: 200) image
.contextMenu { .resizable(resizingMode: .stretch)
Button(action: { .aspectRatio(contentMode: .fit)
print("fight") .frame(width: 250)
}) { } else if phase.error != nil {
Text("Share...") Color.gray.opacity(0.2)
Image(systemName: "square.and.arrow.up") .overlay(Image(systemName: "rectangle.slash"))
} } else {
Color.gray.opacity(0.2)
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() ProgressView()
} }
}
.cornerRadius(16)
.frame(height: 250)
} else { } else {
Text(message.message) Text(message.message)
.font(FontStyle.DefaultText.font) .font(FontStyle.DefaultText.font)
...@@ -70,21 +44,13 @@ struct OtherChatContentView: View { ...@@ -70,21 +44,13 @@ struct OtherChatContentView: View {
} }
} }
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: ""))
.font(FontStyle.DateText.font) .font(FontStyle.DateText.font)
.foregroundColor(ColorSet.ChatDate.color) .foregroundColor(ColorSet.ChatDate.color)
} }
} }
} }
.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()
} }
......
...@@ -23,7 +23,7 @@ struct ChatMessage: Codable { ...@@ -23,7 +23,7 @@ struct ChatMessage: Codable {
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] = [] //閲覧者情報
} }
struct Viewer: Codable { struct Viewer: Codable {
......
...@@ -207,14 +207,14 @@ struct LoginView: View { ...@@ -207,14 +207,14 @@ struct LoginView: View {
Preferences.lastLoginDate_Int64 = DateTextLib.Date2UnixTime(date: Date()) Preferences.lastLoginDate_Int64 = DateTextLib.Date2UnixTime(date: Date())
isLogin = true isLogin = true
let message = GetMessage()
message.start()
timer = Timer.scheduledTimer(withTimeInterval: TimerInterval, repeats: true) { _ in timer = Timer.scheduledTimer(withTimeInterval: TimerInterval, repeats: true) { _ in
print(debug: "called timer") print(debug: "called timer")
let eca = EcaTask() let eca = EcaTask()
eca.start() eca.start()
let message = GetMessage()
message.start()
let route = MonitoringRoute() let route = MonitoringRoute()
route.start() route.start()
......
...@@ -113,14 +113,14 @@ struct InputUserNameView: View { ...@@ -113,14 +113,14 @@ struct InputUserNameView: View {
Preferences.Password = param.password Preferences.Password = param.password
Preferences.lastLoginDate_Int64 = DateTextLib.Date2UnixTime(date: Date()) Preferences.lastLoginDate_Int64 = DateTextLib.Date2UnixTime(date: Date())
let message = GetMessage()
message.start()
timer = Timer.scheduledTimer(withTimeInterval: 60.0, repeats: true) { _ in timer = Timer.scheduledTimer(withTimeInterval: 60.0, repeats: true) { _ in
print(debug: "called timer") print(debug: "called timer")
let eca = EcaTask() let eca = EcaTask()
eca.start() eca.start()
let message = GetMessage()
message.start()
let route = MonitoringRoute() let route = MonitoringRoute()
route.start() route.start()
......
...@@ -77,6 +77,7 @@ class NotificationTags: NSObject { ...@@ -77,6 +77,7 @@ class NotificationTags: NSObject {
var connection: HubConnection? var connection: HubConnection?
class AppDelegate: NSObject, UIApplicationDelegate ,MSNotificationHubDelegate, MSInstallationLifecycleDelegate { class AppDelegate: NSObject, UIApplicationDelegate ,MSNotificationHubDelegate, MSInstallationLifecycleDelegate {
@ObservedObject var msg = SharingData.message
private var hubConnectionDelegate: HubConnectionDelegate? private var hubConnectionDelegate: HubConnectionDelegate?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
...@@ -117,16 +118,16 @@ class AppDelegate: NSObject, UIApplicationDelegate ,MSNotificationHubDelegate, M ...@@ -117,16 +118,16 @@ class AppDelegate: NSObject, UIApplicationDelegate ,MSNotificationHubDelegate, M
if let r_connection = connection { if let r_connection = connection {
r_connection.stop() r_connection.stop()
r_connection.on(method: "chatMessage", callback: { (message: ResChatMessage) in r_connection.on(method: "ChatMessage", callback: { (message: ResChatMessage) in
self.handleChatMessage(message: message) self.handleChatMessage(message: message)
}) })
r_connection.on(method: "ackMessage", callback: { (message: ResAckMessage) in r_connection.on(method: "AckMessage", callback: { (message: ResAckMessage) in
self.handleAckMessage(message: message) self.handleAckMessage(message: message)
}) })
r_connection.on(method: "chatMode", callback: { (message: ResChatMode) in r_connection.on(method: "ChatMode", callback: { (message: ResChatMode) in
self.handleChatMessage(message: message) self.handleChatMode(message: message)
}) })
r_connection.start() r_connection.start()
...@@ -168,27 +169,42 @@ class AppDelegate: NSObject, UIApplicationDelegate ,MSNotificationHubDelegate, M ...@@ -168,27 +169,42 @@ class AppDelegate: NSObject, UIApplicationDelegate ,MSNotificationHubDelegate, M
// APNs 登録成功時に呼ばれる // APNs 登録成功時に呼ばれる
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let token = deviceToken.map { String(format: "%.2hhx", $0) }.joined() let token = deviceToken.map { String(format: "%.2hhx", $0) }.joined()
print("デバイストークン : \(token)") print(debug: "デバイストークン : \(token)")
} }
// APNs 登録失敗時に呼ばれる // APNs 登録失敗時に呼ばれる
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("APNs 登録に失敗しました : \(error.localizedDescription)") print(debug: "APNs 登録に失敗しました : \(error.localizedDescription)")
} }
private func handleChatMessage(message: ResChatMessage) { private func handleChatMessage(message: ResChatMessage) {
print(debug: "called") print(debug: "test:called")
// print(debug: "called \(ResMessage)") let ownMsg = ChatMessage(shipId: message.shipId, messageId: message.messageId, type: message.type, time: message.time, location: message.location, from: message.from, message: message.message, stampId: message.stampId, viewer: [])
self.msg.messages.append(ownMsg)
let message = GetMessage()
message.checkUnreadMessages()
} }
private func handleAckMessage(message: ResAckMessage) { private func handleAckMessage(message: ResAckMessage) {
print(debug: "called") print(debug: "test:called")
// print(debug: "called \(ResAckMessage)") let msgIndex = self.msg.messages.firstIndex(where: {$0.messageId == message.messageId})
if let index = msgIndex {
let viewer = Viewer(time: message.time, location: message.location, id: message.fromId)
self.msg.messages[index].viewer.append(viewer)
} }
private func handleChatMessage(message: ResChatMode) { let message = GetMessage()
print(debug: "called") message.checkUnreadMessages()
// print(debug: "called \(ResChatMode)") }
private func handleChatMode(message: ResChatMode) {
print(debug: "test:called")
if message.mode == 1 {
self.msg.mode = true
} else {
self.msg.mode = false
}
} }
//アプリ終了時 //アプリ終了時
...@@ -203,7 +219,8 @@ class SignalR: NSObject { ...@@ -203,7 +219,8 @@ class SignalR: NSObject {
@ObservedObject var msg = SharingData.message @ObservedObject var msg = SharingData.message
func chatMessage(message: String) { func chatMessage(message: String) {
var request = ReqMessage(shipId: Preferences.shipId, messageId: UUID().uuidString) print(debug: "test:called")
var request = ReqMessage(shipId: Preferences.shipId, messageId: UUID().uuidString.lowercased())
request.type = 0 //0:テキスト, 1:スタンプ request.type = 0 //0:テキスト, 1:スタンプ
request.time = DateTextLib.Date2ISO8601Text(Date()) request.time = DateTextLib.Date2ISO8601Text(Date())
request.location = 2 //1:Shore , 2:Ship request.location = 2 //1:Shore , 2:Ship
...@@ -217,14 +234,14 @@ class SignalR: NSObject { ...@@ -217,14 +234,14 @@ class SignalR: NSObject {
if let e = error { if let e = error {
print(debug: "Error:\(e)") print(debug: "Error:\(e)")
} }
let viewer = Viewer(time: "", location: 0, id: "") let ownMsg = ChatMessage(shipId: request.shipId, messageId: request.messageId, type: request.type, time: request.time, location: request.location, from: request.from, message: request.message, stampId: request.stampId, viewer: [])
let ownMsg = ChatMessage(shipId: request.shipId, messageId: request.messageId, type: request.type, time: request.time, location: request.location, from: request.from, message: request.message, stampId: request.stampId, viewer: [viewer])
self.msg.messages.append(ownMsg) self.msg.messages.append(ownMsg)
} }
} }
} }
func ackMessage(messageId: String) { func ackMessage(messageId: String) {
print(debug: "test:called")
var request = ReqAckMessage(shipId: Preferences.shipId, messageId: messageId) var request = ReqAckMessage(shipId: Preferences.shipId, messageId: messageId)
request.time = DateTextLib.Date2ISO8601Text(Date()) request.time = DateTextLib.Date2ISO8601Text(Date())
request.location = 2 //1:Shore , 2:Ship request.location = 2 //1:Shore , 2:Ship
...@@ -308,13 +325,16 @@ extension AppDelegate: UNUserNotificationCenterDelegate { ...@@ -308,13 +325,16 @@ extension AppDelegate: UNUserNotificationCenterDelegate {
completionHandler([[.banner, .badge, .sound]]) completionHandler([[.banner, .badge, .sound]])
return return
} }
let subtitle = arrAlert["subtitle"] as? String ?? "" //送信内容 let subtitle = arrAlert["subtitle"] as? String ?? "" //送信先名称
let strTitle = arrAlert["title"] as? String ?? "" //船名 let strTitle = arrAlert["title"] as? String ?? "" //船名
let strBody = arrAlert["body"] as? String ?? "" //送信先名称 let strBody = arrAlert["body"] as? String ?? "" //送信内容
print(debug: "called \(subtitle) \(strTitle) \(strBody)") print(debug: "called \(subtitle) \(strTitle) \(strBody)")
let message = GetMessage()
message.start() //送信先名称が同一の場合は通知を出さない
if subtitle == Preferences.UserName {
return
}
case "sailassist": case "sailassist":
print(debug: "sailassist") print(debug: "sailassist")
let getPushHistory = GetPushHistory() let getPushHistory = GetPushHistory()
...@@ -362,8 +382,8 @@ extension AppDelegate: UNUserNotificationCenterDelegate { ...@@ -362,8 +382,8 @@ extension AppDelegate: UNUserNotificationCenterDelegate {
let strBody = arrAlert["body"] as? String ?? "" //送信先名称 let strBody = arrAlert["body"] as? String ?? "" //送信先名称
print(debug: "called \(subtitle) \(strTitle) \(strBody)") print(debug: "called \(subtitle) \(strTitle) \(strBody)")
let message = GetMessage() // let message = GetMessage()
message.start() // message.start()
case "sailassist": case "sailassist":
print(debug: "sailassist") print(debug: "sailassist")
let getPushHistory = GetPushHistory() let getPushHistory = GetPushHistory()
......
...@@ -8,9 +8,7 @@ ...@@ -8,9 +8,7 @@
import SwiftUI import SwiftUI
enum Tab: String, CaseIterable{ enum Tab: String, CaseIterable{
#if CANARY
case chat = "tab_chat" case chat = "tab_chat"
#endif
case task = "tab_task" case task = "tab_task"
case alert = "tab_notification" case alert = "tab_notification"
case menu = "tab_menu" case menu = "tab_menu"
...@@ -40,10 +38,9 @@ struct MainTabView: View { ...@@ -40,10 +38,9 @@ struct MainTabView: View {
@State var isTaskSel: Bool = selectedTabModel.activeTab == .task @State var isTaskSel: Bool = selectedTabModel.activeTab == .task
TabView(selection: $selectedTabModel.activeTab){ TabView(selection: $selectedTabModel.activeTab){
#if CANARY
ChatView() ChatView()
.tag(Tab.chat) .tag(Tab.chat)
#endif
MapRepresentable() MapRepresentable()
.ignoresSafeArea() .ignoresSafeArea()
.tag(Tab.task) .tag(Tab.task)
...@@ -117,6 +114,12 @@ struct CustomTabBar: View { ...@@ -117,6 +114,12 @@ struct CustomTabBar: View {
if tab == .task { if tab == .task {
selectedTabModel.isPoppver.toggle() selectedTabModel.isPoppver.toggle()
location.focusOwnShip = true location.focusOwnShip = true
} else if tab == .chat {
let message = GetMessage()
message.readNotification()
message.checkUnreadMessages()
selectedTabModel.isPoppver = false
} else { } else {
selectedTabModel.isPoppver = false selectedTabModel.isPoppver = false
} }
......
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