Commit a2e1336e authored by shigemi miura's avatar shigemi miura

Merge update-mapbox-version into develop

parents aa7356fa dabd9d58
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>
......
......@@ -2,11 +2,84 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeBrowsingHistory</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeUserID</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<true/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeName</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeOther</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypePreciseLocation</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
</array>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>E174.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
</array>
</dict>
......
......@@ -32,16 +32,6 @@
020B98692ADD221E0029DE4C /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 020B98682ADD221D0029DE4C /* Preferences.swift */; };
020B986C2ADD3E810029DE4C /* InTextLib.swift in Sources */ = {isa = PBXBuildFile; fileRef = 020B986B2ADD3E810029DE4C /* InTextLib.swift */; };
020B986E2ADD3E8D0029DE4C /* DateTextLib.swift in Sources */ = {isa = PBXBuildFile; fileRef = 020B986D2ADD3E8D0029DE4C /* DateTextLib.swift */; };
022789002AE1FE4600A87787 /* MapboxCommon.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 022788F92AE1FE3D00A87787 /* MapboxCommon.xcframework */; };
022789012AE1FE4600A87787 /* MapboxCommon.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 022788F92AE1FE3D00A87787 /* MapboxCommon.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
022789022AE1FE4700A87787 /* MapboxCoreMaps.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 022788F82AE1FE3D00A87787 /* MapboxCoreMaps.xcframework */; };
022789032AE1FE4700A87787 /* MapboxCoreMaps.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 022788F82AE1FE3D00A87787 /* MapboxCoreMaps.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
022789042AE1FE4900A87787 /* MapboxMaps.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 022788FA2AE1FE3D00A87787 /* MapboxMaps.xcframework */; };
022789052AE1FE4900A87787 /* MapboxMaps.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 022788FA2AE1FE3D00A87787 /* MapboxMaps.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
022789062AE1FE4B00A87787 /* MapboxMobileEvents.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 022788F62AE1FE3C00A87787 /* MapboxMobileEvents.xcframework */; };
022789072AE1FE4B00A87787 /* MapboxMobileEvents.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 022788F62AE1FE3C00A87787 /* MapboxMobileEvents.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
022789082AE1FE4C00A87787 /* Turf.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 022788F72AE1FE3C00A87787 /* Turf.xcframework */; };
022789092AE1FE4C00A87787 /* Turf.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 022788F72AE1FE3C00A87787 /* Turf.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
0227890C2AE22E0B00A87787 /* SharingData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0227890B2AE22E0B00A87787 /* SharingData.swift */; };
022A98202AF8B8960079C55A /* LocationCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022A981F2AF8B8960079C55A /* LocationCalculation.swift */; };
023DB8282B1429E400B351CF /* NotificationContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023DB8272B1429E400B351CF /* NotificationContentView.swift */; };
......@@ -58,6 +48,7 @@
02A1DE2F2AFB4AA0005BCF55 /* ChatInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02A1DE2E2AFB4AA0005BCF55 /* ChatInputView.swift */; };
02A1DE312AFB61D8005BCF55 /* MyChatContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02A1DE302AFB61D8005BCF55 /* MyChatContentView.swift */; };
02A1DE332AFB654A005BCF55 /* CustomCornerRadius.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02A1DE322AFB654A005BCF55 /* CustomCornerRadius.swift */; };
02C38B902C9ABBF400D3B1E9 /* MapboxMaps in Frameworks */ = {isa = PBXBuildFile; productRef = 02C38B8F2C9ABBF400D3B1E9 /* MapboxMaps */; };
02C3E5CE2AFCA04700AF7837 /* OtherChatContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C3E5CD2AFCA04700AF7837 /* OtherChatContentView.swift */; };
02C3E5D12AFCC16800AF7837 /* ChatTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C3E5D02AFCC16800AF7837 /* ChatTitleView.swift */; };
02C3E6092AFDF30000AF7837 /* ChatMemberView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C3E6082AFDF30000AF7837 /* ChatMemberView.swift */; };
......@@ -120,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 */; };
......@@ -171,11 +164,6 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
022789032AE1FE4700A87787 /* MapboxCoreMaps.xcframework in Embed Frameworks */,
022789072AE1FE4B00A87787 /* MapboxMobileEvents.xcframework in Embed Frameworks */,
022789012AE1FE4600A87787 /* MapboxCommon.xcframework in Embed Frameworks */,
022789092AE1FE4C00A87787 /* Turf.xcframework in Embed Frameworks */,
022789052AE1FE4900A87787 /* MapboxMaps.xcframework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
......@@ -211,11 +199,6 @@
020B98682ADD221D0029DE4C /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
020B986B2ADD3E810029DE4C /* InTextLib.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InTextLib.swift; sourceTree = "<group>"; };
020B986D2ADD3E8D0029DE4C /* DateTextLib.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateTextLib.swift; sourceTree = "<group>"; };
022788F62AE1FE3C00A87787 /* MapboxMobileEvents.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = MapboxMobileEvents.xcframework; sourceTree = "<group>"; };
022788F72AE1FE3C00A87787 /* Turf.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Turf.xcframework; sourceTree = "<group>"; };
022788F82AE1FE3D00A87787 /* MapboxCoreMaps.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = MapboxCoreMaps.xcframework; sourceTree = "<group>"; };
022788F92AE1FE3D00A87787 /* MapboxCommon.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = MapboxCommon.xcframework; sourceTree = "<group>"; };
022788FA2AE1FE3D00A87787 /* MapboxMaps.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = MapboxMaps.xcframework; sourceTree = "<group>"; };
0227890B2AE22E0B00A87787 /* SharingData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingData.swift; sourceTree = "<group>"; };
022A981F2AF8B8960079C55A /* LocationCalculation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LocationCalculation.swift; path = Sailassist/Location/LocationCalculation.swift; sourceTree = SOURCE_ROOT; };
023DB8272B1429E400B351CF /* NotificationContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = NotificationContentView.swift; path = Sailassist/Alert/View/NotificationContentView.swift; sourceTree = SOURCE_ROOT; };
......@@ -303,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; };
......@@ -334,11 +319,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
022789022AE1FE4700A87787 /* MapboxCoreMaps.xcframework in Frameworks */,
022789002AE1FE4600A87787 /* MapboxCommon.xcframework in Frameworks */,
022789042AE1FE4900A87787 /* MapboxMaps.xcframework in Frameworks */,
022789082AE1FE4C00A87787 /* Turf.xcframework in Frameworks */,
022789062AE1FE4B00A87787 /* MapboxMobileEvents.xcframework in Frameworks */,
02C38B902C9ABBF400D3B1E9 /* MapboxMaps in Frameworks */,
D6BEB5D3598C619546873CFC /* Pods_Sailassist.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
......@@ -366,7 +347,6 @@
children = (
D594825E2BC4C5DD0032A473 /* PrivacyInfo.xcprivacy */,
D53ACA752B0AECF8008DCB18 /* Sailassist.entitlements */,
02CE4DCE2ADFBA16002E79BC /* Fremeworks */,
020B98122AD8C3140029DE4C /* SailAssist */,
020B98232AD8C31A0029DE4C /* SailAssistTests */,
020B982D2AD8C31A0029DE4C /* SailAssistUITests */,
......@@ -463,7 +443,7 @@
020B983E2AD8C3500029DE4C /* Tab */ = {
isa = PBXGroup;
children = (
02C3E5CF2AFCC15700AF7837 /* View */,
D5AAB69C2E7A5E8F0027CD90 /* AlertModifiers.swift */,
02CE4DC92ADF9D2E002E79BC /* ViewModel */,
020B98582AD92A4C0029DE4C /* MainTabView.swift */,
);
......@@ -641,6 +621,7 @@
02A1DE2D2AFB497B005BCF55 /* View */ = {
isa = PBXGroup;
children = (
D5A4C2522E7AB46B00642D7D /* SpeechRecognizer.swift */,
02C3E5D02AFCC16800AF7837 /* ChatTitleView.swift */,
02A1DE2E2AFB4AA0005BCF55 /* ChatInputView.swift */,
02A1DE302AFB61D8005BCF55 /* MyChatContentView.swift */,
......@@ -654,13 +635,6 @@
path = View;
sourceTree = "<group>";
};
02C3E5CF2AFCC15700AF7837 /* View */ = {
isa = PBXGroup;
children = (
);
path = View;
sourceTree = "<group>";
};
02CE4D7D2ADE4297002E79BC /* View */ = {
isa = PBXGroup;
children = (
......@@ -695,18 +669,6 @@
path = ViewModel;
sourceTree = "<group>";
};
02CE4DCE2ADFBA16002E79BC /* Fremeworks */ = {
isa = PBXGroup;
children = (
022788F92AE1FE3D00A87787 /* MapboxCommon.xcframework */,
022788F82AE1FE3D00A87787 /* MapboxCoreMaps.xcframework */,
022788FA2AE1FE3D00A87787 /* MapboxMaps.xcframework */,
022788F62AE1FE3C00A87787 /* MapboxMobileEvents.xcframework */,
022788F72AE1FE3C00A87787 /* Turf.xcframework */,
);
path = Fremeworks;
sourceTree = "<group>";
};
5C62E7AC977110B4B727E3F3 /* Frameworks */ = {
isa = PBXGroup;
children = (
......@@ -843,6 +805,9 @@
dependencies = (
);
name = Sailassist;
packageProductDependencies = (
02C38B8F2C9ABBF400D3B1E9 /* MapboxMaps */,
);
productName = forShip;
productReference = 020B98102AD8C3140029DE4C /* Sail Assist.app */;
productType = "com.apple.product-type.application";
......@@ -916,6 +881,9 @@
Base,
);
mainGroup = 020B98072AD8C3140029DE4C;
packageReferences = (
02C38B8E2C9ABBF400D3B1E9 /* XCRemoteSwiftPackageReference "mapbox-maps-ios" */,
);
productRefGroup = 020B98112AD8C3140029DE4C /* Products */;
projectDirPath = "";
projectRoot = "";
......@@ -988,10 +956,14 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Sailassist/Pods-Sailassist-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Sailassist/Pods-Sailassist-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Sailassist/Pods-Sailassist-frameworks.sh\"\n";
......@@ -1129,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 */,
......@@ -1307,7 +1281,7 @@
CODE_SIGN_ENTITLEMENTS = Sailassist/Sailassist.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 56;
CURRENT_PROJECT_VERSION = 62;
DEVELOPMENT_ASSET_PATHS = "\"Sailassist/Preview Content\"";
DEVELOPMENT_TEAM = D2DC7QNNJ8;
ENABLE_PREVIEWS = YES;
......@@ -1325,12 +1299,15 @@
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UIRequiresFullScreen = YES;
INFOPLIST_KEY_UIStatusBarStyle = "";
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.5;
MARKETING_VERSION = 1.0.3;
OTHER_SWIFT_FLAGS = "-D CANARY -D COCOAPODS";
PRODUCT_BUNDLE_IDENTIFIER = com.jrc.sailassist.canary;
......@@ -1353,7 +1330,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Sailassist/Sailassist.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 56;
CURRENT_PROJECT_VERSION = 62;
DEVELOPMENT_ASSET_PATHS = "\"Sailassist/Preview Content\"";
DEVELOPMENT_TEAM = D2DC7QNNJ8;
ENABLE_PREVIEWS = YES;
......@@ -1368,12 +1345,15 @@
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UIRequiresFullScreen = YES;
INFOPLIST_KEY_UIStatusBarStyle = "";
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.5;
MARKETING_VERSION = 1.0.3;
OTHER_SWIFT_FLAGS = "-D COCOAPODS";
PRODUCT_BUNDLE_IDENTIFIER = com.jrc.sailassist;
......@@ -1536,7 +1516,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Sailassist/Sailassist.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 56;
CURRENT_PROJECT_VERSION = 62;
DEVELOPMENT_ASSET_PATHS = "\"Sailassist/Preview Content\"";
DEVELOPMENT_TEAM = D2DC7QNNJ8;
ENABLE_PREVIEWS = YES;
......@@ -1554,12 +1534,15 @@
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UIRequiresFullScreen = YES;
INFOPLIST_KEY_UIStatusBarStyle = "";
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.5;
MARKETING_VERSION = 1.0.3;
OTHER_SWIFT_FLAGS = "-D QC -D COCOAPODS";
PRODUCT_BUNDLE_IDENTIFIER = com.jrc.sailassist.qc;
......@@ -1656,6 +1639,25 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
02C38B8E2C9ABBF400D3B1E9 /* XCRemoteSwiftPackageReference "mapbox-maps-ios" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/mapbox/mapbox-maps-ios.git";
requirement = {
kind = upToNextMinorVersion;
minimumVersion = 10.18.2;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
02C38B8F2C9ABBF400D3B1E9 /* MapboxMaps */ = {
isa = XCSwiftPackageProductDependency;
package = 02C38B8E2C9ABBF400D3B1E9 /* XCRemoteSwiftPackageReference "mapbox-maps-ios" */;
productName = MapboxMaps;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 020B98082AD8C3140029DE4C /* Project object */;
}
{
"originHash" : "c48d77ebe93e854e8e2b4bbddf1d5fe4977e5a87efa4e14ea29c90b3e5919e31",
"pins" : [
{
"identity" : "mapbox-common-ios",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mapbox/mapbox-common-ios.git",
"state" : {
"revision" : "c2aa7022afdcf5a070ace4e3b608562101a04690",
"version" : "23.10.1"
}
},
{
"identity" : "mapbox-core-maps-ios",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mapbox/mapbox-core-maps-ios.git",
"state" : {
"revision" : "51f776b11bcff34ced88fcf14e4ed9c568257232",
"version" : "10.18.0"
}
},
{
"identity" : "mapbox-maps-ios",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mapbox/mapbox-maps-ios.git",
"state" : {
"revision" : "8ef49bb140bbd5d51917f1e69d4c3949a176c009",
"version" : "10.18.2"
}
},
{
"identity" : "turf-swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mapbox/turf-swift.git",
"state" : {
"revision" : "213050191cfcb3d5aa76e1fa90c6ff1e182a42ca",
"version" : "2.8.0"
}
}
],
"version" : 3
}
......@@ -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]?
......
......@@ -22,7 +22,7 @@ struct MapInformation: View {
.cornerRadius(3)
}
.padding(.top, 100)
.padding(.trailing, 200)
.padding(.trailing, positionLocation())
VStack {
ForEach(ngaData.ngaArea.map{ $0.1 }.filter{ $0.passingCnt > 0 }, id: \.name) { nga in
Text("Entering NGA \(nga.name)")
......@@ -44,6 +44,15 @@ struct MapInformation: View {
}
return location
}
func positionLocation() -> CGFloat {
var yPos: CGFloat = 200
if UIDevice.current.userInterfaceIdiom == .pad {
yPos = 900
}
return yPos
}
}
#Preview {
......
......@@ -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")
}
......@@ -454,15 +476,36 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, ObservableObject {
let tabWindow = PassThroughWindow(windowScene: scene)
tabWindow.rootViewController = tabBarController
tabWindow.isHidden = false
self.tabWindow = tabWindow
}
}
class PassThroughWindow: UIWindow{
// override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
// guard let view = super.hitTest(point, with: event) else { return nil}
// return rootViewController?.view == view ? nil : view
// }
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard let view = super.hitTest(point, with: event) else { return nil}
return rootViewController?.view == view ? nil : view
let view = super.hitTest(point, with: event)
if let view = view {
print("Hit test view: \(view), at point: \(point)")
print("View hierarchy: \(type(of: view)) -> \(view.superview)")
} else {
print("Hit test view: nil, at point: \(point)")
}
// rootViewController?.view がヒットしても、子ビューがある場合は透過しない
if rootViewController?.view == view {
// 子ビューが存在する場合はタッチイベントを処理
if rootViewController?.view.subviews.contains(where: { $0.frame.contains(point) }) == true {
return view
}
print("Background was hit, passing through")
return nil
}
return view
}
}
......
......@@ -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.")
}
}
}
......@@ -12,53 +12,56 @@ enum Tab: String, CaseIterable{
case chat = "tab_chat"
case alert = "tab_notification"
case menu = "tab_menu"
var title: String{
""
switch self {
case .map: return "Map"
case .chat: return "Chat"
case .alert: return "Alert"
case .menu: return "Menu"
}
}
}
struct MainTabView: View {
@EnvironmentObject var selectedTabModel: SelectedTabModel
@EnvironmentObject private var sceneDelegate: SceneDelegate
@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
// EcaCoordinatesTable().setEcaData()
var isTabShow: Bool {
sceneDelegate.tabWindow != nil
}
var isTaskSel: Bool {
selectedTabModel.activeTab == .map
}
var body: some View {
if UIDevice.current.userInterfaceIdiom == .phone {
@State var isTabShow: Bool = sceneDelegate.tabWindow != nil
@State var isTaskSel: Bool = selectedTabModel.activeTab == .map
Group {
if UIDevice.current.userInterfaceIdiom == .phone {
phoneView
} else {
padView
}
}
.onAppear {
SharingData.location.focusOwnShip = true
configureTabBarAppearance()
}
}
TabView(selection: $selectedTabModel.activeTab){
private var phoneView: some View {
ZStack(alignment: .bottom) {
TabView(selection: $selectedTabModel.activeTab) {
mapTab
if SharingData.my.isCommunication {
ChatView()
.tag(Tab.chat)
ChatView().tag(Tab.chat)
}
ZStack {
MapRepresentable()
MapInformation()
}
.ignoresSafeArea()
.tag(Tab.map)
NotificationView()
.tag(Tab.alert)
MenuView(isSignout: $isSignout)
.tag(Tab.menu)
NotificationView().tag(Tab.alert)
MenuView(isSignout: $isSignout).tag(Tab.menu)
}
.hideNativeTabBar()
// .sheet(isPresented: .constant(isTaskSel && isTabShow && SharingData.my.isFuelSwitchTask), content: {
.sheet(isPresented: .constant(isTaskSel && isTabShow), content: {
.sheet(isPresented: .constant(isTaskSel && isTabShow)) {
MenuTaskView()
.zIndex(0)
.presentationDragIndicator(.hidden)
......@@ -67,41 +70,93 @@ struct MainTabView: View {
.presentationBackgroundInteraction(.enabled(upThrough: .medium))
.presentationBackground(ColorSet.BackgroundSecondary.color)
.interactiveDismissDisabled()
})
} else if UIDevice.current.userInterfaceIdiom == .pad {
@State var isPopover: Bool = selectedTabModel.isPoppver
}
}
}
TabView(selection: $selectedTabModel.activeTab){
private var padView: some View {
ZStack(alignment: .bottom) {
TabView(selection: $selectedTabModel.activeTab) {
mapTab.padding(.bottom, 50)
if SharingData.my.isCommunication {
ChatView()
.tag(Tab.chat)
ChatView().padding(.bottom, 50).tag(Tab.chat)
}
NotificationView().padding(.bottom, 50).tag(Tab.alert)
MenuView(isSignout: $isSignout).padding(.bottom, 50).tag(Tab.menu)
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
}
}
ZStack {
MapRepresentable()
MapInformation()
}
.ignoresSafeArea()
.tag(Tab.map)
@ViewBuilder
private var mapTab: some View {
ZStack {
MapRepresentable()
MapInformation()
}
.ignoresSafeArea(edges: .top)
.tag(Tab.map)
}
NotificationView()
.tag(Tab.alert)
private func configureTabBarAppearance() {
let appearance = UITabBarAppearance()
appearance.backgroundColor = .clear
UITabBar.appearance().scrollEdgeAppearance = appearance
UITabBar.appearance().standardAppearance = appearance
}
}
MenuView(isSignout: $isSignout)
.tag(Tab.menu)
}
.hideNativeTabBar()
// .popover(isPresented: .constant(isPopover && SharingData.my.isFuelSwitchTask), attachmentAnchor: .point(.bottom)) {
.popover(isPresented: .constant(isPopover), attachmentAnchor: .point(.bottom)) {
MenuTaskView()
.presentationCompactAdaptation(.popover)
.zIndex(0)
.frame(minWidth: 500, maxHeight: 500)
.aspectRatio(contentMode: .fit)
.presentationCornerRadius(15)
.presentationBackgroundInteraction(.enabled(upThrough: .medium))
.presentationBackground(ColorSet.BackgroundSecondary.color)
.interactiveDismissDisabled()
class MenuWindowManager {
static let shared = MenuWindowManager()
private var window: UIWindow?
func showMenuView<Content: View>(_ content: Content, frame: CGRect) {
guard window == nil else { return }
let hostingController = UIHostingController(rootView: content)
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
var rFrame = frame
rFrame.size.height -= 20
let newWindow = UIWindow(windowScene: windowScene)
newWindow.rootViewController = hostingController
newWindow.windowLevel = .alert + 1
newWindow.backgroundColor = UIColor.clear
newWindow.makeKeyAndVisible()
newWindow.alpha = 0.8
newWindow.frame = rFrame
newWindow.layer.cornerRadius = 15
newWindow.layer.masksToBounds = true
self.window = newWindow
}
}
func hideMenuView() {
guard let window = window else { return }
window.isHidden = true
window.rootViewController = nil
window.removeFromSuperview()
self.window = nil
}
}
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)
)
}
}
}
......@@ -118,105 +173,59 @@ struct CustomTabBar: View {
@ObservedObject var pushHistory = SharingData.pushHistory
@State var isSignalrRestert = false
@State var isMenuTaskViewVisible = false
var body: some View {
VStack(spacing: 0){
Divider()
HStack(spacing: 0){
ForEach(Tab.allCases, id: \.rawValue) { tab in
Button(action: {
selectedTabModel.activeTab = tab
if tab == .map {
selectedTabModel.isPoppver.toggle()
//iPhoneは船に移動 iPadはMenu表示
if UIDevice.current.userInterfaceIdiom == .phone {
location.focusOwnShip = true
}
} else if tab == .chat {
let message = GetMessage()
message.start()
message.readNotification()
message.checkUnreadMessages()
selectedTabModel.isPoppver = false
} else {
selectedTabModel.isPoppver = false
}
}, label: {
VStack{
ZStack(alignment: .bottomTrailing) {
if !SharingData.my.isCommunication && tab == Tab.chat {
Image("tab_chat_Invalid")
.font(.title2)
} else {
Image(selectedTabModel.activeTab == tab ? tab.rawValue + "_selected" : tab.rawValue)
.font(.title2)
}
//チャット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)
)
}
VStack{
ZStack(alignment: .bottomTrailing) {
if !SharingData.my.isCommunication && tab == Tab.chat {
Image("tab_chat_Invalid")
.font(.title2)
.onTapGesture {
handleTabSelection(tab)
print("Image for \(tab.rawValue) tapped")
}
}
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)
)
}
} else {
Image(selectedTabModel.activeTab == tab ? tab.rawValue + "_selected" : tab.rawValue)
.font(.title2)
.onTapGesture {
handleTabSelection(tab)
print("Image for \(tab.rawValue) tapped")
}
}
}
Text(tab.title)
.font(.caption)
//チャットTab上の既読マーク
if tab == Tab.chat {
NotificationBadge(count: message.viewCnt, font: FontStyle.VersionText.font)
.id(message.viewCnt)
}
if tab == Tab.alert {
NotificationBadge(count: pushHistory.viewCnt, font: FontStyle.VersionText.font)
.id(pushHistory.viewCnt)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.contentShape(.rect)
})
Text(tab.title)
.font(.caption)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.contentShape(Rectangle())
}
}
.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()
......@@ -226,42 +235,81 @@ 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
}))
.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
}))
}
/**
* タブが選択されたときの処理
*/
private func handleTabSelection(_ tab: Tab) {
selectedTabModel.activeTab = tab
if tab == .map {
selectedTabModel.isPoppver.toggle()
// iPhoneは船に移動、iPadはMenu表示
if UIDevice.current.userInterfaceIdiom == .phone {
location.focusOwnShip = true
} else {
if isMenuTaskViewVisible {
MenuWindowManager.shared.hideMenuView()
} else {
mapFunctionsView()
}
UIApplication.shared.open(settingsURL, options: [:], completionHandler: nil)
isMenuTaskViewVisible.toggle()
}
} 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)!)
} else if tab == .chat {
let message = GetMessage()
message.start()
message.readNotification()
message.checkUnreadMessages()
selectedTabModel.isPoppver = false
if UIDevice.current.userInterfaceIdiom == .pad {
MenuWindowManager.shared.hideMenuView()
isMenuTaskViewVisible = false
}
} 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
}
} else {
selectedTabModel.isPoppver = false
if UIDevice.current.userInterfaceIdiom == .pad {
MenuWindowManager.shared.hideMenuView()
isMenuTaskViewVisible = false
}
} message: {
Text("The mode did not change.")
}
}
private func mapFunctionsView() {
let screenBounds = UIScreen.main.bounds
let screenHeight = screenBounds.height
let menuTaskViewWidth: CGFloat = 400
let menuTaskViewOffset: CGFloat = 80
let menuTaskViewX: CGFloat = 10
// メニューの縦サイズを画面の高さに応じて計算
let menuTaskViewHeight = max(200, screenHeight * 0.8)
// メニューのY座標を計算(画面の下部に配置)
let menuTaskViewY = screenHeight - menuTaskViewHeight - menuTaskViewOffset
MenuWindowManager.shared.showMenuView(
MenuTaskView()
.frame(width: menuTaskViewWidth, height: menuTaskViewHeight)
.background(ColorSet.BackgroundSecondary.color)
.cornerRadius(15),
frame: CGRect(x: menuTaskViewX, y: menuTaskViewY, width: menuTaskViewWidth, height: menuTaskViewHeight)
)
}
/**
* Warninngモードレスポンス
*/
......
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