Commit dabd9d58 authored by shigemi miura's avatar shigemi miura

画像送信関連修正

parent 8af9e919
PODS:
- AzureNotificationHubs-iOS (3.1.5)
- SwiftSignalRClient (1.0.0)
- SwiftSignalRClient (1.1.0)
DEPENDENCIES:
- AzureNotificationHubs-iOS
......@@ -13,7 +13,7 @@ SPEC REPOS:
SPEC CHECKSUMS:
AzureNotificationHubs-iOS: e5de62f44d7915a5cc3c5194ddc57cf2ee78873e
SwiftSignalRClient: f9a23a0407d490a799cc1a3c8835b8611128d76c
SwiftSignalRClient: 2fa651ea18d47c5aaa135f0c8cf959239c845999
PODFILE CHECKSUM: bbdabe3b255c91674ba1766a3ec70d307854a5a9
......
PODS:
- AzureNotificationHubs-iOS (3.1.5)
- SwiftSignalRClient (1.0.0)
- SwiftSignalRClient (1.1.0)
DEPENDENCIES:
- AzureNotificationHubs-iOS
......@@ -13,7 +13,7 @@ SPEC REPOS:
SPEC CHECKSUMS:
AzureNotificationHubs-iOS: e5de62f44d7915a5cc3c5194ddc57cf2ee78873e
SwiftSignalRClient: f9a23a0407d490a799cc1a3c8835b8611128d76c
SwiftSignalRClient: 2fa651ea18d47c5aaa135f0c8cf959239c845999
PODFILE CHECKSUM: bbdabe3b255c91674ba1766a3ec70d307854a5a9
......
......@@ -16,7 +16,6 @@
dependencies = (
);
name = "AzureNotificationHubs-iOS";
productName = "AzureNotificationHubs-iOS";
};
/* End PBXAggregateTarget section */
......@@ -122,7 +121,7 @@
99743ABC5876BBF855E5EE7D4D9BBFBC /* HubConnection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HubConnection.swift; path = Sources/SignalRClient/HubConnection.swift; sourceTree = "<group>"; };
998C647A59261C90EA8DF5F841F81ED8 /* Pods-Sailassist-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-Sailassist-umbrella.h"; sourceTree = "<group>"; };
9A23C67D0548DF810D1712CBE602461B /* LongPollingTransport.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LongPollingTransport.swift; path = Sources/SignalRClient/LongPollingTransport.swift; sourceTree = "<group>"; };
9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
9F9AF6D4F29B01D2A9287D1F02E85155 /* JSONHubProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = JSONHubProtocol.swift; path = Sources/SignalRClient/JSONHubProtocol.swift; sourceTree = "<group>"; };
A347F728F5AAA8B41DAFE3AD233425B1 /* SwiftSignalRClient-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "SwiftSignalRClient-Info.plist"; sourceTree = "<group>"; };
B1C92344570F3702174B6CD251E58E9E /* Pods-SailAssistTests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-SailAssistTests-acknowledgements.plist"; sourceTree = "<group>"; };
......@@ -132,7 +131,7 @@
B718183D31FC6004F71844FA616C449A /* HandshakeProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HandshakeProtocol.swift; path = Sources/SignalRClient/HandshakeProtocol.swift; sourceTree = "<group>"; };
C0A0244A30A292024A7AB96104039BFB /* HubConnectionExtensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HubConnectionExtensions.swift; path = Sources/SignalRClient/HubConnectionExtensions.swift; sourceTree = "<group>"; };
C99CC2D377D211487E80F9DC15293987 /* NegotiationResponse.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NegotiationResponse.swift; path = Sources/SignalRClient/NegotiationResponse.swift; sourceTree = "<group>"; };
CA2C16F20715BBB5C1E288B9406F6303 /* WindowsAzureMessaging.xcframework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.xcframework; name = WindowsAzureMessaging.xcframework; path = "WindowsAzureMessaging-SDK-Apple/WindowsAzureMessaging.xcframework"; sourceTree = "<group>"; };
CA2C16F20715BBB5C1E288B9406F6303 /* WindowsAzureMessaging.xcframework */ = {isa = PBXFileReference; includeInIndex = 1; name = WindowsAzureMessaging.xcframework; path = "WindowsAzureMessaging-SDK-Apple/WindowsAzureMessaging.xcframework"; sourceTree = "<group>"; };
CB2414C9D8D9290C1D5F4211D6FC4E26 /* Logger.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Logger.swift; path = Sources/SignalRClient/Logger.swift; sourceTree = "<group>"; };
D1D56B5309D1F749EC584E7F5D901428 /* HubConnectionDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HubConnectionDelegate.swift; path = Sources/SignalRClient/HubConnectionDelegate.swift; sourceTree = "<group>"; };
D282F486E6C5E74D2F27BF5ED45ADD47 /* Pods-SailAssistTests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-SailAssistTests-umbrella.h"; sourceTree = "<group>"; };
......@@ -144,7 +143,7 @@
DFFD42573E1097252DD74B9B8686713D /* ServerInvocationHandler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ServerInvocationHandler.swift; path = Sources/SignalRClient/ServerInvocationHandler.swift; sourceTree = "<group>"; };
E04B4C3FF284BC409C8436B3C844044C /* SwiftSignalRClient-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SwiftSignalRClient-prefix.pch"; sourceTree = "<group>"; };
E347DFCE3670A0953EA7E9880C7723D0 /* SignalRError.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SignalRError.swift; path = Sources/SignalRClient/SignalRError.swift; sourceTree = "<group>"; };
E7AFB048F72A32D1AB967A9164E20741 /* SwiftSignalRClient.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftSignalRClient.framework; sourceTree = BUILT_PRODUCTS_DIR; };
E7AFB048F72A32D1AB967A9164E20741 /* SwiftSignalRClient */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = SwiftSignalRClient; path = SwiftSignalRClient.framework; sourceTree = BUILT_PRODUCTS_DIR; };
F04040FA4924616899E5F9CD0D5FEF94 /* HttpConnection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HttpConnection.swift; path = Sources/SignalRClient/HttpConnection.swift; sourceTree = "<group>"; };
F371DF14209E4C63D0D1BFF890B0E44D /* Pods-SailAssistTests */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "Pods-SailAssistTests"; path = Pods_SailAssistTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
FAD4FBDFB36028046481AC609256BC25 /* Connection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Connection.swift; path = Sources/SignalRClient/Connection.swift; sourceTree = "<group>"; };
......@@ -288,7 +287,7 @@
children = (
32C8F03288ABF8CB2E1A04518F1394B9 /* Pods-Sailassist */,
F371DF14209E4C63D0D1BFF890B0E44D /* Pods-SailAssistTests */,
E7AFB048F72A32D1AB967A9164E20741 /* SwiftSignalRClient.framework */,
E7AFB048F72A32D1AB967A9164E20741 /* SwiftSignalRClient */,
);
name = Products;
sourceTree = "<group>";
......@@ -328,6 +327,7 @@
09BBFD81D450AA2C354BDC78D4AF50E6 /* WebsocketsTransport.swift */,
C80DDBE8FD00464F8F959003EF78F8BF /* Support Files */,
);
name = SwiftSignalRClient;
path = SwiftSignalRClient;
sourceTree = "<group>";
};
......@@ -346,6 +346,7 @@
1187AA037CB2DE219A69DE3350C6828B /* Frameworks */,
6AAA309192D5B46A98CB622F6E79D3D7 /* Support Files */,
);
name = "AzureNotificationHubs-iOS";
path = "AzureNotificationHubs-iOS";
sourceTree = "<group>";
};
......@@ -433,7 +434,7 @@
);
name = SwiftSignalRClient;
productName = SwiftSignalRClient;
productReference = E7AFB048F72A32D1AB967A9164E20741 /* SwiftSignalRClient.framework */;
productReference = E7AFB048F72A32D1AB967A9164E20741 /* SwiftSignalRClient */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
......@@ -671,7 +672,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
......@@ -697,7 +698,7 @@
GCC_PREFIX_HEADER = "Target Support Files/SwiftSignalRClient/SwiftSignalRClient-prefix.pch";
INFOPLIST_FILE = "Target Support Files/SwiftSignalRClient/SwiftSignalRClient-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
......@@ -856,7 +857,7 @@
GCC_PREFIX_HEADER = "Target Support Files/SwiftSignalRClient/SwiftSignalRClient-prefix.pch";
INFOPLIST_FILE = "Target Support Files/SwiftSignalRClient/SwiftSignalRClient-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
......@@ -928,7 +929,7 @@
GCC_PREFIX_HEADER = "Target Support Files/SwiftSignalRClient/SwiftSignalRClient-prefix.pch";
INFOPLIST_FILE = "Target Support Files/SwiftSignalRClient/SwiftSignalRClient-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
......@@ -953,7 +954,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
......@@ -1045,7 +1046,7 @@
GCC_PREFIX_HEADER = "Target Support Files/SwiftSignalRClient/SwiftSignalRClient-prefix.pch";
INFOPLIST_FILE = "Target Support Files/SwiftSignalRClient/SwiftSignalRClient-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
......@@ -1109,7 +1110,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
......@@ -1276,7 +1277,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
......
......@@ -116,10 +116,5 @@ There are several sample projects in the `Examples` folder. They include:
**"Failed to bind to address http://0.0.0.0:5000: address already in use."**. This is due to Apple now advertising an 'AirPlay Receiver' on that port.
This port can be freed by disabling the receiver: Navigate to _System Preferences > Sharing_ and uncheck _AirPlay Receiver_.
## Disclaimer
I am providing code in the repository to you under an open source license. Because this is my personal repository, the license you receive to my code is from me
and not my employer (Facebook)
## Hits
[![HitCount](http://hits.dwyl.com/moozzyk/Signalr-Client-Swift.svg)](http://hits.dwyl.com/moozzyk/Signalr-Client-Swift)
......@@ -47,7 +47,14 @@ public class HttpConnectionOptions {
The timeout value for individual requests, in seconds.
*/
public var requestTimeout: TimeInterval = 120
/**
The maximum number of bytes to buffer before the receive call fails with an error.
This value includes the sum of all bytes from continuation frames. Receive calls will fail once the task reaches this limit. (URLSessionWebSocketTask)
*/
public var maximumWebsocketMessageSize: Int?
public var authenticationChallengeHandler: ((_ session: URLSession, _ challenge: URLAuthenticationChallenge, _ completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> Void)?
/**
......
......@@ -171,6 +171,7 @@ public class HubConnectionBuilder {
httpConnectionOptionsCopy.skipNegotiation = httpConnectionOptions.skipNegotiation
}
httpConnectionOptionsCopy.requestTimeout = httpConnectionOptions.requestTimeout
httpConnectionOptionsCopy.maximumWebsocketMessageSize = httpConnectionOptions.maximumWebsocketMessageSize
httpConnectionOptionsCopy.callbackQueue = httpConnectionOptions.callbackQueue
httpConnectionOptionsCopy.authenticationChallengeHandler = httpConnectionOptions.authenticationChallengeHandler
return HttpConnection(url: url, options: httpConnectionOptionsCopy, transportFactory: transportFactory, logger: logger)
......
......@@ -35,7 +35,10 @@ public class WebsocketsTransport: NSObject, Transport, URLSessionWebSocketDelega
setAccessToken(accessTokenProvider: options.accessTokenProvider, request: &request)
urlSession = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue())
webSocketTask = urlSession!.webSocketTask(with: request)
if let maximumWebsocketMessageSize = options.maximumWebsocketMessageSize {
webSocketTask?.maximumMessageSize = maximumWebsocketMessageSize
}
webSocketTask!.resume()
}
......
......@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<string>1.1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
......
......@@ -111,6 +111,8 @@
D59908C62B19EA70000E13DD /* ResPushHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59908C52B19EA70000E13DD /* ResPushHistory.swift */; };
D59908C82B1ABD43000E13DD /* SessionPushHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59908C72B1ABD43000E13DD /* SessionPushHistory.swift */; };
D59908CA2B1AC381000E13DD /* GetPushHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59908C92B1AC381000E13DD /* GetPushHistory.swift */; };
D5A4C2532E7AB48700642D7D /* SpeechRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A4C2522E7AB46B00642D7D /* SpeechRecognizer.swift */; };
D5AAB69D2E7A5E8F0027CD90 /* AlertModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5AAB69C2E7A5E8F0027CD90 /* AlertModifiers.swift */; };
D5AE351A2AEBA66A00059889 /* ReqLogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5AE35182AEBA66A00059889 /* ReqLogin.swift */; };
D5AE351B2AEBA66A00059889 /* ResLogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5AE35192AEBA66A00059889 /* ResLogin.swift */; };
D5AE351D2AEBA6FC00059889 /* SessionLogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5AE351C2AEBA6FC00059889 /* SessionLogin.swift */; };
......@@ -284,6 +286,8 @@
D59908C52B19EA70000E13DD /* ResPushHistory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ResPushHistory.swift; path = Sailassist/Json/ResPushHistory.swift; sourceTree = SOURCE_ROOT; };
D59908C72B1ABD43000E13DD /* SessionPushHistory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SessionPushHistory.swift; path = Sailassist/ServerSession/SessionPushHistory.swift; sourceTree = SOURCE_ROOT; };
D59908C92B1AC381000E13DD /* GetPushHistory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = GetPushHistory.swift; path = Sailassist/Alert/GetPushHistory.swift; sourceTree = SOURCE_ROOT; };
D5A4C2522E7AB46B00642D7D /* SpeechRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpeechRecognizer.swift; sourceTree = "<group>"; };
D5AAB69C2E7A5E8F0027CD90 /* AlertModifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertModifiers.swift; sourceTree = "<group>"; };
D5AE35182AEBA66A00059889 /* ReqLogin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ReqLogin.swift; path = Sailassist/Json/ReqLogin.swift; sourceTree = SOURCE_ROOT; };
D5AE35192AEBA66A00059889 /* ResLogin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ResLogin.swift; path = Sailassist/Json/ResLogin.swift; sourceTree = SOURCE_ROOT; };
D5AE351C2AEBA6FC00059889 /* SessionLogin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SessionLogin.swift; path = Sailassist/ServerSession/SessionLogin.swift; sourceTree = SOURCE_ROOT; };
......@@ -439,7 +443,7 @@
020B983E2AD8C3500029DE4C /* Tab */ = {
isa = PBXGroup;
children = (
02C3E5CF2AFCC15700AF7837 /* View */,
D5AAB69C2E7A5E8F0027CD90 /* AlertModifiers.swift */,
02CE4DC92ADF9D2E002E79BC /* ViewModel */,
020B98582AD92A4C0029DE4C /* MainTabView.swift */,
);
......@@ -617,6 +621,7 @@
02A1DE2D2AFB497B005BCF55 /* View */ = {
isa = PBXGroup;
children = (
D5A4C2522E7AB46B00642D7D /* SpeechRecognizer.swift */,
02C3E5D02AFCC16800AF7837 /* ChatTitleView.swift */,
02A1DE2E2AFB4AA0005BCF55 /* ChatInputView.swift */,
02A1DE302AFB61D8005BCF55 /* MyChatContentView.swift */,
......@@ -630,13 +635,6 @@
path = View;
sourceTree = "<group>";
};
02C3E5CF2AFCC15700AF7837 /* View */ = {
isa = PBXGroup;
children = (
);
path = View;
sourceTree = "<group>";
};
02CE4D7D2ADE4297002E79BC /* View */ = {
isa = PBXGroup;
children = (
......@@ -1103,7 +1101,9 @@
D5258CA32B036CC500365276 /* SessionGetMessage.swift in Sources */,
D52C2C082B9195A8003B286C /* MenuInformationView.swift in Sources */,
D5258C992B0334BF00365276 /* SessionShipStatus.swift in Sources */,
D5AAB69D2E7A5E8F0027CD90 /* AlertModifiers.swift in Sources */,
02CE4D872ADF62A7002E79BC /* EcaListView.swift in Sources */,
D5A4C2532E7AB48700642D7D /* SpeechRecognizer.swift in Sources */,
D5E008762B2ADD5900C4070A /* MenuManualRADARView.swift in Sources */,
D59908C62B19EA70000E13DD /* ResPushHistory.swift in Sources */,
D58EF2472B9044C800FB784C /* ResInformation.swift in Sources */,
......@@ -1281,7 +1281,7 @@
CODE_SIGN_ENTITLEMENTS = Sailassist/Sailassist.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 58;
CURRENT_PROJECT_VERSION = 62;
DEVELOPMENT_ASSET_PATHS = "\"Sailassist/Preview Content\"";
DEVELOPMENT_TEAM = D2DC7QNNJ8;
ENABLE_PREVIEWS = YES;
......@@ -1330,7 +1330,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Sailassist/Sailassist.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 58;
CURRENT_PROJECT_VERSION = 62;
DEVELOPMENT_ASSET_PATHS = "\"Sailassist/Preview Content\"";
DEVELOPMENT_TEAM = D2DC7QNNJ8;
ENABLE_PREVIEWS = YES;
......@@ -1516,7 +1516,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Sailassist/Sailassist.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 58;
CURRENT_PROJECT_VERSION = 62;
DEVELOPMENT_ASSET_PATHS = "\"Sailassist/Preview Content\"";
DEVELOPMENT_TEAM = D2DC7QNNJ8;
ENABLE_PREVIEWS = YES;
......
......@@ -15,7 +15,7 @@ struct NotificationView: View {
TitleView()
ScrollView {
ForEach(pushHist.pushHistoryData.map{ $1 }.sorted{ $0.id ?? 0 > $1.id ?? 0 }, id: \.id){ data in
ForEach(pushHist.pushHistoryData.map{ $1 }.filter { $0.id != nil }.sorted{ ($0.id ?? 0) > ($1.id ?? 0) }, id: \.id){ data in
NotificationContentView(pushData: data)
.onTapGesture {
if let position = data.position {
......@@ -38,12 +38,10 @@ struct NotificationView: View {
.onAppear {
let pushCount = pushHist.viewCnt
print(debug: "\(pushCount)")
pushHist.viewCnt = 0
DispatchQueue.main.async {
pushHist.viewCnt = 0
}
}
// .onChange(of: pushHist.pushHistoryData.count) { newValue in
// let pushCount = pushHist.viewCnt
// print(debug: "\(pushCount)")
// }
}
struct TitleView: View {
......
......@@ -14,7 +14,7 @@ struct NotificationContentView: View {
var body: some View {
VStack(alignment: .leading, spacing: 4){
HStack(spacing: 10) {
Text(pushData.time ?? "2023-07-13T08::17:40Z")
Text(pushData.time ?? "2023-07-13T08:17:40Z")
.foregroundColor(ColorSet.BodyDescriptiion.color)
.font(FontStyle.SupplementText2.font)
......
......@@ -16,7 +16,7 @@ struct ChatView: View {
var body: some View {
ZStack {
if message.mode == true {
if message.mode {
LinearGradient(gradient: Gradient(colors: [.chatEmargencyColor1, .chatEmargencyColor2]), startPoint: .top, endPoint: .bottom)
.ignoresSafeArea()
}
......@@ -48,8 +48,10 @@ struct ChatView: View {
}
}
.onAppear {
if let id = message.messages.last?.messageId {
proxy.scrollTo(id, anchor: .bottom)
guard !message.messages.isEmpty,
let id = message.messages.last?.messageId else { return }
proxy.scrollTo(id, anchor: .bottom)
DispatchQueue.main.async {
message.viewCnt = 0
}
}
......@@ -118,7 +120,7 @@ struct AlertChatMessage: View {
var message : ChatMessage
var body: some View {
if message.mode == 1 {
if message.mode == ChatMode.warningProgress.rawValue {
HStack() {
Rectangle()
.fill(ColorSet.ChatDate.color)
......
......@@ -56,7 +56,7 @@ class GetMessage {
}
}
SharingData.message.viewCnt = msgCnt - viewCnt //未読数
// SharingData.message.viewCnt = msgCnt - viewCnt //未読数
}
/**
......
//
// ChatInputView.swift
// Sailassist
//
// Created by Mamoru Sugita on 2023/11/08.
//
import SwiftUI
import Speech
enum MediaInputType {
case none
case camera
case photoLibrary
case fileImport
}
struct ChatInputView: View {
@EnvironmentObject private var sceneDelegate: SceneDelegate
@ObservedObject var sessionUploadImage: SessionUploadImage = SessionUploadImage()
@ObservedObject var msg = SharingData.message
@State var inputText = ""
@State private var isChatAlert: Bool = false
@State private var isPhotAlert: Bool = false
@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
@State var isSignalrRestert = false
@ObservedObject var sessionUploadImage = SessionUploadImage()
@StateObject private var speechRecognizer = SpeechRecognizer()
@State private var inputText = ""
@State private var isChatAlert = false
@State private var imageData: Data = .init(capacity: 0)
@State private var mediaInputType: MediaInputType = .none
@State private var isImagePickerPresented = false
@State private var isFileImporterPresented = false
@State private var source: UIImagePickerController.SourceType = .photoLibrary
@State private var isSignalrRestart = false
@State private var isUploadingDialogPresented = false
@State private var failedUploadImage: ReqUploadImage? = nil
@State private var isRetryDialogPresented = false
@State private var isRecording = false
@FocusState private var isKeyboardFocused: Bool
@Binding var isFocus: Bool
var body: some View {
VStack(spacing: 0){
VStack(spacing: 0) {
Spacer()
Divider()
HStack(spacing: 10){
HStack(spacing: 10) {
// MARK: - カメラボタン
Button {
sceneDelegate.tabWindow?.isHidden = true
isCamera = true
mediaInputType = .camera
source = .camera
isImagePicker.toggle()
isImagePickerPresented = true
} label: {
Image(systemName: "camera")
.resizable()
.frame(width: 24, height: 24)
.padding(10)
.frame(width: 20, height: 20)
.padding(5)
}
//MARK: - メディア選択メニュー
Menu {
Button(action: {
print("Photo Library")
Button {
sceneDelegate.tabWindow?.isHidden = true
isCamera = true
mediaInputType = .photoLibrary
source = .photoLibrary
isImagePicker.toggle()
}) {
isImagePickerPresented = true
} label: {
Label("Photo Library", systemImage: "photo.on.rectangle")
}
Button(action: {
print("Take Photo")
sceneDelegate.tabWindow?.isHidden = true
isImportFile = true
}) {
Label("Take Photo", systemImage: "camera")
}
Button(action: {
print("Choose File")
Button {
sceneDelegate.tabWindow?.isHidden = true
isCamera = true
source = .photoLibrary
isImagePicker.toggle()
}) {
mediaInputType = .fileImport
isFileImporterPresented = true
} label: {
Label("Choose File", systemImage: "folder")
}
} label: {
Image(systemName: "photo")
.resizable()
.frame(width: 24, height: 24)
.padding(10)
.frame(width: 20, height: 20)
.padding(5)
}
TextField("", text: $inputText, onEditingChanged: { isEdit in
sceneDelegate.tabWindow?.isHidden = isEdit
//MARK: - 音声入力ボタン
// Button {
// isRecording.toggle()
// if isRecording {
// speechRecognizer.transcribedText = ""
// speechRecognizer.startRecording()
// } else {
// speechRecognizer.stopRecording()
// inputText = speechRecognizer.transcribedText
// }
// } label: {
// Image(systemName: isRecording ? "mic.fill" : "mic")
// .resizable()
// .frame(width: 20, height: 20)
// .padding(5)
// }
//MARK: - テキスト入力
TextField("", text: $inputText, onEditingChanged: { isEditing in
sceneDelegate.tabWindow?.isHidden = isEditing
isFocus = true
})
.focused($isKeyboard)
.focused($isKeyboardFocused)
.font(FontStyle.SupplementText.font)
.foregroundColor(ColorSet.BodyChat.color)
.padding(10)
.background(ColorSet.ChatForm.color)
.cornerRadius(5)
.padding(.vertical, 10)
.padding(.leading, 20)
.padding(.leading, 10)
Button{
//MARK: - 送信ボタン
Button {
sendChatMessage()
} label: {
Image("send")
.resizable()
.frame(width: 24, height: 24)
.padding(10)
.frame(width: 20, height: 20)
.padding(5)
.opacity(inputText.isEmpty ? 0.5 : 1.0)
}
.padding(.vertical, 6)
......@@ -104,115 +118,160 @@ struct ChatInputView: View {
.disabled(inputText.isEmpty)
}
.background(ColorSet.BackgroundSecondary.color)
.fullScreenCover(isPresented: .constant(isImagePicker), onDismiss: {
//シートを閉じる時に実行する処理
// MARK: - 画像ピッカー
.fullScreenCover(isPresented: $isImagePickerPresented, onDismiss: {
sceneDelegate.tabWindow?.isHidden = false
isKeyboard = false
isKeyboardFocused = false
if let image = UIImage(data: imageData),
let jpegData = image.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
)
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)
sendChatImage(uploadImage)
}
}, content: {
CameraView(imageData: $imageData, source: $source, isActionSheet: $isActionSheet, isImagePicker: $isImagePicker)
})
.fileImporter(isPresented: $isImportFile, allowedContentTypes: [.png, .jpeg, .pdf]) { result in
}) {
CameraView(imageData: $imageData, source: $source, isActionSheet: .constant(false), isImagePicker: $isImagePickerPresented)
}
//MARK: - File Importer
.fileImporter(isPresented: $isFileImporterPresented, allowedContentTypes: [.png, .jpeg, .pdf]) { result in
switch result {
case .success(let url):
guard let imageData = try? Data(contentsOf: url) else { return }
guard let data = try? Data(contentsOf: url),
let image = UIImage(data: data),
let jpegData = image.jpegData(compressionQuality: 1.0) 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)
}
let uploadImage = ReqUploadImage(
shipId: Preferences.shipId,
messageId: UUID().uuidString,
location: 2,
from: Preferences.UserName,
fromId: String(SharingData.my.id),
files: jpegData
)
sendChatImage(uploadImage)
case .failure:
print("failure")
print("File import failed")
}
}
.onChange(of: isFocus) { focus in
if focus == false {
isKeyboard = false
if !focus {
isKeyboardFocused = false
}
}
.onReceive(speechRecognizer.$transcribedText) { newText in
if isRecording {
inputText = newText
}
}
}
.frame(maxHeight: 55)
.alert("Error", isPresented: $isChatAlert) {
Button("OK") {
if self.isSignalrRestert {
let signalRService = SignalR()
signalRService.startConnection()
self.isSignalrRestert = false
if isSignalrRestart {
SignalR().startConnection()
isSignalrRestart = false
}
}
} message: {
Text("The message could not be sent.")
}
.alert("Error", isPresented: $isPhotAlert) {
Button("OK") {}
.alert("Uploading...", isPresented: $isUploadingDialogPresented) {
ProgressView(value: sessionUploadImage.progress)
.progressViewStyle(LinearProgressViewStyle())
.padding()
Button("Cancel") {
sessionUploadImage.cancelUpload()
isUploadingDialogPresented = false
}
}
.alert("Upload failed", isPresented: $isRetryDialogPresented) {
Button("retry") {
if let imageToRetry = failedUploadImage {
sendChatImage(imageToRetry)
}
}
Button("Cancel", role: .cancel) {
failedUploadImage = nil
isRetryDialogPresented = false
}
} message: {
Text("The Image could not be sent.")
Text("Image upload failed. Would you like to try again?")
}
}
/**
* イメージレスポンス
*/
func responseUploadImage(result: Result<Data, APIError>) {
print(debug: "calld")
switch result {
case .success(let resultData):
let serverSession = ServerSession()
let _ = serverSession.fromJSON(resultData: resultData, resltType: ResLogin.self)
case .failure(let errorCode):
print(debug: errorCode)
isPhotAlert = true
break
// MARK: - Send Chat Image
func sendChatImage(_ uploadImage: ReqUploadImage) {
Task {
do {
isUploadingDialogPresented = true
let response = try await sessionUploadImage.requestUploadImage(uploadImage)
print("Upload success: \(response)")
let serverSession = ServerSession()
_ = serverSession.fromJSON(resultData: response, resltType: ResLogin.self)
sessionUploadImage.progress = 0.0 // 完了後リセット
isUploadingDialogPresented = false
} catch {
print("Upload failed: \(error)")
sessionUploadImage.progress = 0.0 // エラー時もリセット
isUploadingDialogPresented = false
failedUploadImage = uploadImage
isRetryDialogPresented = true
}
}
}
/**
* チャット送信
*/
// MARK: - Send Chat Message
func sendChatMessage() {
if !SharingData.message.sendInf {
let signalRService = SignalR()
signalRService.chatMessage(message: inputText, completion: responseChatMessage)
SharingData.message.sendInf = true
guard !SharingData.message.sendInf else { return }
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
restartChatMessage()
}
isRecording = false
SignalR().chatMessage(message: inputText, completion: responseChatMessage)
SharingData.message.sendInf = true
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
restartChatMessage()
}
}
/**
* チャットレスポンス
*/
// MARK: - Chat Response
func responseChatMessage(error: Error?) {
SharingData.message.sendInf = false
if let e = error {
print(debug: "chat error \(e)")
if let error = error {
print("Chat error: \(error)")
isChatAlert = true
} else {
isKeyboard = false
isKeyboardFocused = false
inputText = ""
}
}
/**
* チャットレスポンスが無かった場合
*/
// MARK: - Restart Chat if No Response
func restartChatMessage() {
if SharingData.message.sendInf {
let signalRService = SignalR()
signalRService.stopConnection()
Thread.sleep(forTimeInterval: 1.0)
self.isSignalrRestert = true
SignalR().stopConnection()
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
isSignalrRestart = true
}
}
}
}
......
......@@ -69,15 +69,12 @@ struct MyChatContentView: View {
var shipViewer = 0
var companyViewr = 0
for viewer in message.viewer {
//船のIDは全て同じ
// if viewer.id != String(SharingData.my.id) {
if viewer.location == 1 {
companyViewr += 1
} else {
shipViewer += 1
}
if viewer.location == 1 {
companyViewr += 1
} else {
shipViewer += 1
}
// }
}
return (shipViewer, companyViewr)
}
}
......
import Foundation
import Speech
import AVFoundation
class SpeechRecognizer: ObservableObject {
private var audioEngine = AVAudioEngine()
private var request = SFSpeechAudioBufferRecognitionRequest()
private var recognizer = SFSpeechRecognizer(locale: Locale(identifier: "ja-JP"))
private var task: SFSpeechRecognitionTask?
@Published var transcribedText = ""
func startRecording() {
SFSpeechRecognizer.requestAuthorization { authStatus in
guard authStatus == .authorized else { return }
let node = self.audioEngine.inputNode
let recordingFormat = node.outputFormat(forBus: 0)
node.removeTap(onBus: 0)
node.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { buffer, _ in
self.request.append(buffer)
}
self.audioEngine.prepare()
try? self.audioEngine.start()
self.task = self.recognizer?.recognitionTask(with: self.request) { result, error in
if let result = result {
DispatchQueue.main.async {
self.transcribedText = result.bestTranscription.formattedString
}
}
}
}
}
func stopRecording() {
audioEngine.stop()
request.endAudio()
task?.cancel()
audioEngine.inputNode.removeTap(onBus: 0)
}
}
......@@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSSpeechRecognitionUsageDescription</key>
<string>Uses voice recognition</string>
<key>NSMicrophoneUsageDescription</key>
<string>Use a microphone</string>
<key>MBXAccessToken</key>
<string>pk.eyJ1Ijoiam1hcmluZWNsb3VkIiwiYSI6ImNsbmxjbGYzZjA0dG8yaW82MDgwajQ5OTQifQ.pd8YC9qK1C4YmMUbMx6ywQ</string>
<key>UIBackgroundModes</key>
......
......@@ -7,6 +7,11 @@
import Foundation
enum ChatMode: Int {
case normal = 0
case warningProgress = 1
}
struct ResGetMessages: Codable {
var mode: Int // 0:通常 , 1:Warning中
var messages: [ChatMessage]?
......
......@@ -110,7 +110,7 @@ class AppDelegate: NSObject, UIApplicationDelegate ,MSNotificationHubDelegate, M
Preferences.DeviceId = UUID().uuidString
}
//SignalR初期化
//MARK: - SignalR初期化
hubConnectionDelegate = ChatHubConnectionDelegate(app: self)
connection = HubConnectionBuilder(url: URL(string : HttpRequestType.SignalR.rawValue)!)
.withHubConnectionDelegate(delegate: hubConnectionDelegate!)
......@@ -121,10 +121,16 @@ class AppDelegate: NSObject, UIApplicationDelegate ,MSNotificationHubDelegate, M
.build()
if let r_connection = connection {
//Chat
r_connection.on(method: "ChatMessage", callback: { (message: ResChatMessage) in
self.handleChatMessage(message: message)
})
//Photo / Image
r_connection.on(method: "chatMessage", callback: { (message: ResChatMessage) in
self.handleChatMessage(message: message)
})
r_connection.on(method: "AckMessage", callback: { (message: ResAckMessage) in
self.handleAckMessage(message: message)
})
......@@ -158,6 +164,7 @@ class AppDelegate: NSObject, UIApplicationDelegate ,MSNotificationHubDelegate, M
// Push通知を受信した時(サイレントプッシュ)
func notificationHub(_ notificationHub: MSNotificationHub, didReceivePushNotification notification: MSNotificationHubMessage) {
print(debug: "called")
// let title = notification.title ?? ""
// let body = notification.body ?? ""
let userInfo = notification.userInfo
......@@ -181,11 +188,13 @@ class AppDelegate: NSObject, UIApplicationDelegate ,MSNotificationHubDelegate, M
}
private func handleChatMessage(message: ResChatMessage) {
print(debug: "called")
let ownMsg = ChatMessage(shipId: message.shipId, messageId: message.messageId, type: message.type, time: message.time, location: message.location, from: message.from, fromId: message.fromId, mode: message.mode, message: message.message, stampId: message.stampId, viewer: [])
self.msg.messages.append(ownMsg)
}
private func handleAckMessage(message: ResAckMessage) {
print(debug: "called")
let msgIndex = self.msg.messages.firstIndex(where: {$0.messageId == message.messageId})
if let index = msgIndex {
if let fromId = message.fromId {
......@@ -199,6 +208,7 @@ class AppDelegate: NSObject, UIApplicationDelegate ,MSNotificationHubDelegate, M
}
private func handleChatMode(message: ResChatMode) {
print(debug: "called")
if message.mode == 1 {
self.msg.mode = true
} else {
......@@ -352,27 +362,39 @@ extension AppDelegate: UNUserNotificationCenterDelegate {
//送信先名称が同一の場合は通知を出さない
if subtitle == Preferences.UserName {
return
} else {
DispatchQueue.main.async {
SharingData.message.viewCnt += 1
}
}
case "sailassist":
print(debug: "sailassist")
SharingData.pushHistory.viewCnt += 1
let getPushHistory = GetPushHistory()
getPushHistory.start()
DispatchQueue.main.async {
print(debug: "sailassist")
SharingData.pushHistory.viewCnt += 1
let getPushHistory = GetPushHistory()
getPushHistory.start()
}
case "bam":
print(debug: "bam")
SharingData.pushHistory.viewCnt += 1
let getPushHistory = GetPushHistory()
getPushHistory.start()
DispatchQueue.main.async {
print(debug: "bam")
SharingData.pushHistory.viewCnt += 1
let getPushHistory = GetPushHistory()
getPushHistory.start()
}
case "route":
print(debug: "route")
SharingData.pushHistory.viewCnt += 1
let getPushHistory = GetPushHistory()
getPushHistory.start()
DispatchQueue.main.async {
print(debug: "route")
SharingData.pushHistory.viewCnt += 1
let getPushHistory = GetPushHistory()
getPushHistory.start()
}
case "emergency":
print(debug: "emergency")
SharingData.pushHistory.viewCnt += 1
let getPushHistory = GetPushHistory()
getPushHistory.start()
DispatchQueue.main.async {
print(debug: "emergency")
SharingData.pushHistory.viewCnt += 1
let getPushHistory = GetPushHistory()
getPushHistory.start()
}
default:
print(debug: "default")
}
......
......@@ -14,4 +14,6 @@ enum APIError: Error{
case decodeError
case encodeError
case unknown
case invalidURL
case busy
}
......@@ -51,7 +51,7 @@ class ServerSession{
do{
if error != nil{
// print(debug: "clientError: \(error)")
print(debug: "clientError: \(String(describing: error))")
throw APIError.clientError
}
guard let indata = data, let inresponse = response as? HTTPURLResponse else {
......
......@@ -9,76 +9,107 @@ import Foundation
import SwiftUI
class SessionUploadImage : ObservableObject {
@Published var status = false
// シングルトン宣言
static let OnlyOne = SessionUploadImage()
@Published var progress: Double = 0.0
@Published var isUploading: Bool = false
static let OnlyOne = SessionUploadImage() // シングルトン宣言
private var serverSession = ServerSession()
private var Calling : Bool = false // 通信中
private var uploadTask: URLSessionUploadTask?
func cancelUpload() {
uploadTask?.cancel()
isUploading = false
progress = 0.0
}
/**
* メッセージ
*/
func RequestUploadImage(_ uploadImage : ReqUploadImage ,completion: @escaping ((Result<Data, APIError>)) -> Void) {
func requestUploadImage(_ uploadImage: ReqUploadImage) async throws -> Data {
print(debug: "calld")
if Calling {
return
guard !Calling else {
throw APIError.busy
}
Calling = true
defer { Calling = false }
// リクエストURLの組み立て
let url_string : String = HttpRequestType.UploadImage.rawValue
guard let req_url = URL(string : url_string) else {
Calling = false
return
guard let req_url = URL(string: HttpRequestType.UploadImage.rawValue) else {
throw APIError.invalidURL
}
let imageFileName = "itemp.jpg"
let boundary = "----------\(UUID().uuidString)"
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 += "\(String(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=\"\(imageFileName)\"\r\n"
httpBody1 += "Content-Type: image/jpeg\r\n"
httpBody1 += "\r\n"
var httpBody = Data()
httpBody.append(httpBody1.data(using: .utf8)!)
func appendFormField(name: String, value: String) {
httpBody.append("--\(boundary)\r\n".data(using: .utf8)!)
httpBody.append("Content-Disposition: form-data; name=\"\(name)\"\r\n\r\n".data(using: .utf8)!)
httpBody.append("\(value)\r\n".data(using: .utf8)!)
}
appendFormField(name: "ShipId", value: String(uploadImage.shipId))
appendFormField(name: "MessageId", value: uploadImage.messageId)
appendFormField(name: "Location", value: String(uploadImage.location))
appendFormField(name: "From", value: uploadImage.from)
appendFormField(name: "FromId", value: uploadImage.fromId)
httpBody.append("--\(boundary)\r\n".data(using: .utf8)!)
httpBody.append("Content-Disposition: form-data; name=\"files\"; filename=\"\(imageFileName)\"\r\n".data(using: .utf8)!)
httpBody.append("Content-Type: image/jpeg\r\n\r\n".data(using: .utf8)!)
httpBody.append(uploadImage.files)
httpBody.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
var request = URLRequest(url: req_url)
request.httpMethod = "POST"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let session = URLSession(configuration: .default, delegate: UploadProgressDelegate(parent: self), delegateQueue: nil)
isUploading = true
uploadTask = session.uploadTask(with: request, from: httpBody)
uploadTask?.resume()
let (data, response) = try await session.upload(for: request, from: httpBody)
isUploading = false
progress = 0.0
var httpBody2 = "\r\n"
httpBody2 += "--\(boundary)--\r\n"
guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
throw APIError.serverError
}
return data
}
httpBody.append(httpBody2.data(using: .utf8)!)
// let str: String = String(decoding: httpBody, as: UTF8.self)
serverSession.postForm(boundary: boundary, req_url, httpBody, completion: completion)
func postFormAsync(boundary: String, url: URL, body: Data) async throws -> Data {
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
request.httpBody = body
let (data, response) = try await URLSession.shared.data(for: request)
// if let postdata = serverSession.httpBody(boundary: boundary, uploadImage) {
// serverSession.postForm(boundary: boundary, req_url, postdata, completion: completion)
// }
// else {
// Calling = false
// return
// }
guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
throw APIError.serverError
}
return data
}
class UploadProgressDelegate: NSObject, URLSessionTaskDelegate {
weak var parent: SessionUploadImage?
init(parent: SessionUploadImage) {
self.parent = parent
}
func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64,
totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
DispatchQueue.main.async {
self.parent?.progress = Double(totalBytesSent) / Double(totalBytesExpectedToSend)
}
}
}
}
import SwiftUI
// MARK: - ChangeModeAlertModifier
struct ChangeModeAlertModifier: ViewModifier {
@Binding var isPresented: Bool
let currentMode: Bool
let onConfirm: () -> Void
func body(content: Content) -> some View {
content.alert("", isPresented: $isPresented) {
Button("Yes") {
onConfirm()
}
Button("No") {}
} message: {
Text("Do you change an warning mode?")
}
}
}
// MARK: - LocationAlertModifier
struct LocationAlertModifier: ViewModifier {
@Binding var isPresented: Bool
func body(content: Content) -> some View {
content.alert("Location", isPresented: $isPresented) {
Button("Cancel") {}
Button("Setting") {
guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else {
return
}
UIApplication.shared.open(settingsURL, options: [:], completionHandler: nil)
}
} message: {
Text("To use ECA, set the permission to use location information to ALWAYS.")
}
}
}
// MARK: - UpdateAlertModifier
struct UpdateAlertModifier: ViewModifier {
@Binding var isPresented: Bool
let appStoreURL: URL
func body(content: Content) -> some View {
content.alert("Update", isPresented: $isPresented) {
Button("Go to app page") {
UIApplication.shared.open(appStoreURL, options: [:], completionHandler: nil)
}
} message: {
Text("A new version of this app is available.")
}
}
}
// MARK: - WarningModeAlertModifier
struct WarningModeAlertModifier: ViewModifier {
@Binding var isPresented: Bool
@Binding var isSignalrRestert: Bool
let onConfirm: () -> Void
func body(content: Content) -> some View {
content.alert("Error", isPresented: $isPresented) {
Button("OK") {
onConfirm()
isSignalrRestert = false
}
} message: {
Text("The mode did not change.")
}
}
}
......@@ -29,79 +29,80 @@ struct MainTabView: View {
@ObservedObject var location = SharingData.location
@State var isSignout = false
init() {
let appearance: UITabBarAppearance = UITabBarAppearance()
appearance.backgroundColor = .clear
UITabBar.appearance().scrollEdgeAppearance = appearance
UITabBar.appearance().standardAppearance = appearance
SharingData.location.focusOwnShip = true
var isTabShow: Bool {
sceneDelegate.tabWindow != nil
}
var body: some View {
if UIDevice.current.userInterfaceIdiom == .phone {
@State var isTabShow: Bool = sceneDelegate.tabWindow != nil
@State var isTaskSel: Bool = selectedTabModel.activeTab == .map
ZStack(alignment: .bottom) {
TabView(selection: $selectedTabModel.activeTab){
ZStack {
MapRepresentable()
MapInformation()
}
.ignoresSafeArea()
.tag(Tab.map)
if SharingData.my.isCommunication {
ChatView()
.tag(Tab.chat)
}
var isTaskSel: Bool {
selectedTabModel.activeTab == .map
}
NotificationView()
.tag(Tab.alert)
var body: some View {
Group {
if UIDevice.current.userInterfaceIdiom == .phone {
phoneView
} else {
padView
}
}
.onAppear {
SharingData.location.focusOwnShip = true
configureTabBarAppearance()
}
}
MenuView(isSignout: $isSignout)
.tag(Tab.menu)
private var phoneView: some View {
ZStack(alignment: .bottom) {
TabView(selection: $selectedTabModel.activeTab) {
mapTab
if SharingData.my.isCommunication {
ChatView().tag(Tab.chat)
}
// .hideNativeTabBar()
.sheet(isPresented: .constant(isTaskSel && isTabShow), content: {
MenuTaskView()
.zIndex(0)
.presentationDragIndicator(.hidden)
.presentationDetents([.height(150), .medium, .fraction(0.99)]) //Seetの高さを設定する
.presentationCornerRadius(15)
.presentationBackgroundInteraction(.enabled(upThrough: .medium))
.presentationBackground(ColorSet.BackgroundSecondary.color)
.interactiveDismissDisabled() //Seetを閉じられなくする
})
NotificationView().tag(Tab.alert)
MenuView(isSignout: $isSignout).tag(Tab.menu)
}
} else if UIDevice.current.userInterfaceIdiom == .pad {
ZStack(alignment: .bottom) {
TabView(selection: $selectedTabModel.activeTab) {
ZStack {
MapRepresentable()
MapInformation()
}
.ignoresSafeArea(edges: .top) // 上部の安全領域を無視
.padding(.bottom, 50) // タブバーの高さ分を調整
.tag(Tab.map)
if SharingData.my.isCommunication {
ChatView()
.padding(.bottom, 50)
.tag(Tab.chat)
}
NotificationView()
.padding(.bottom, 50)
.tag(Tab.alert)
.sheet(isPresented: .constant(isTaskSel && isTabShow)) {
MenuTaskView()
.zIndex(0)
.presentationDragIndicator(.hidden)
.presentationDetents([.height(150), .medium, .fraction(0.99)])
.presentationCornerRadius(15)
.presentationBackgroundInteraction(.enabled(upThrough: .medium))
.presentationBackground(ColorSet.BackgroundSecondary.color)
.interactiveDismissDisabled()
}
}
}
MenuView(isSignout: $isSignout)
.padding(.bottom, 50)
.tag(Tab.menu)
private var padView: some View {
ZStack(alignment: .bottom) {
TabView(selection: $selectedTabModel.activeTab) {
mapTab.padding(.bottom, 50)
if SharingData.my.isCommunication {
ChatView().padding(.bottom, 50).tag(Tab.chat)
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
NotificationView().padding(.bottom, 50).tag(Tab.alert)
MenuView(isSignout: $isSignout).padding(.bottom, 50).tag(Tab.menu)
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
}
}
@ViewBuilder
private var mapTab: some View {
ZStack {
MapRepresentable()
MapInformation()
}
.ignoresSafeArea(edges: .top)
.tag(Tab.map)
}
private func configureTabBarAppearance() {
let appearance = UITabBarAppearance()
appearance.backgroundColor = .clear
UITabBar.appearance().scrollEdgeAppearance = appearance
UITabBar.appearance().standardAppearance = appearance
}
}
......@@ -142,6 +143,25 @@ class MenuWindowManager {
}
}
struct NotificationBadge: View {
let count: Int
let font: Font
var body: some View {
Group {
if count > 0 {
Ellipse()
.fill(Color.red)
.frame(width: 12, height: 12)
.overlay(
Text(count < 10 ? "\(count)" : "-")
.font(font)
.foregroundColor(.white)
)
}
}
}
}
struct CustomTabBar: View {
@EnvironmentObject private var selectedTabModel: SelectedTabModel
@State private var isModeAlert: Bool = false
......@@ -181,51 +201,14 @@ struct CustomTabBar: View {
//チャットTab上の既読マーク
if tab == Tab.chat {
if message.viewCnt != 0 {
if message.viewCnt < 10 {
Ellipse()
.fill(Color.red)
.frame(width: 12, height: 12)
.overlay(
Text(String(message.viewCnt))
.font(FontStyle.VersionText.font)
.foregroundColor(.white)
)
} else {
Ellipse()
.fill(Color.red)
.frame(width: 12, height: 12)
.overlay(
Text("-")
.font(FontStyle.VersionText.font)
.foregroundColor(.white)
)
}
}
NotificationBadge(count: message.viewCnt, font: FontStyle.VersionText.font)
.id(message.viewCnt)
}
if tab == Tab.alert {
if pushHistory.viewCnt != 0 {
if pushHistory.viewCnt < 10 {
Ellipse()
.fill(Color.red)
.frame(width: 12, height: 12)
.overlay(
Text(String(pushHistory.viewCnt))
.font(FontStyle.VersionText.font)
.foregroundColor(.white)
)
} else {
Ellipse()
.fill(Color.red)
.frame(width: 12, height: 12)
.overlay(
Text("-")
.font(FontStyle.VersionText.font)
.foregroundColor(.white)
)
}
}
NotificationBadge(count: pushHistory.viewCnt, font: FontStyle.VersionText.font)
.id(pushHistory.viewCnt)
}
}
......@@ -239,8 +222,10 @@ struct CustomTabBar: View {
.frame(height: 50)
}
.background(ColorSet.BottomNav.color)
.alert("", isPresented: $selectedTabModel.isShowChangeEmrMode) {
Button("Yes") {
.modifier(ChangeModeAlertModifier(
isPresented: $selectedTabModel.isShowChangeEmrMode,
currentMode: message.mode,
onConfirm: {
var chatMode = message.mode
chatMode.toggle()
let signalRService = SignalR()
......@@ -250,40 +235,15 @@ struct CustomTabBar: View {
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
restartChatMode()
}
}
Button("No") {}
} message: {
Text("Do you change an warning mode?")
}
.alert("Location", isPresented: $selectedTabModel.isLocationAlert) {
Button("Cancel") {}
Button("Setting") {
guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else {
return
}
UIApplication.shared.open(settingsURL, options: [:], completionHandler: nil)
}
} message: {
Text("To use ECA,set the permission to use location information to ALWAYS.")
}
.alert("Update", isPresented: $my.isUpDate) {
Button("Go to app page"){
openURL(URL(string: HttpRequestType.AppStore.rawValue)!)
}
} message: {
Text("A new version of this app is available.")
}
.alert("Error", isPresented: $isModeAlert) {
Button("OK") {
if self.isSignalrRestert {
let signalRService = SignalR()
signalRService.startConnection()
isSignalrRestert = false
}
}
} message: {
Text("The mode did not change.")
}
}))
.modifier(LocationAlertModifier(isPresented: $selectedTabModel.isLocationAlert))
.modifier(UpdateAlertModifier(isPresented: $my.isUpDate, appStoreURL: URL(string: HttpRequestType.AppStore.rawValue)!))
.modifier(WarningModeAlertModifier(isPresented: $isModeAlert, isSignalrRestert: $isSignalrRestert,
onConfirm: {
let signalRService = SignalR()
signalRService.startConnection()
isSignalrRestert = 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