Commit d2befa8b authored by shigemi miura's avatar shigemi miura

チャット複数行対応

parent f4d8fe36
......@@ -91,6 +91,7 @@
D55135202B15B030007B66B1 /* SetEcaArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = D551351F2B15B030007B66B1 /* SetEcaArea.swift */; };
D55135222B15C062007B66B1 /* GetEcaList.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55135212B15C062007B66B1 /* GetEcaList.swift */; };
D55135242B15C3BF007B66B1 /* DeleteEcaArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55135232B15C3BF007B66B1 /* DeleteEcaArea.swift */; };
D55186132E7E9158004CD8BD /* ImageQualityPreset.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55186122E7E914C004CD8BD /* ImageQualityPreset.swift */; };
D5598B782C435A5C00611AE0 /* ChatUrlImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5598B772C435A5C00611AE0 /* ChatUrlImageView.swift */; };
D5598B7A2C435C4500611AE0 /* ChatUrlRawImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5598B792C435C4500611AE0 /* ChatUrlRawImageView.swift */; };
D57905FE2C1C069000AF797C /* SetNgaArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = D57905FD2C1C069000AF797C /* SetNgaArea.swift */; };
......@@ -266,6 +267,7 @@
D551351F2B15B030007B66B1 /* SetEcaArea.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SetEcaArea.swift; path = Sailassist/ECA/SetEcaArea.swift; sourceTree = SOURCE_ROOT; };
D55135212B15C062007B66B1 /* GetEcaList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = GetEcaList.swift; path = Sailassist/ECA/GetEcaList.swift; sourceTree = SOURCE_ROOT; };
D55135232B15C3BF007B66B1 /* DeleteEcaArea.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DeleteEcaArea.swift; path = Sailassist/ECA/DeleteEcaArea.swift; sourceTree = SOURCE_ROOT; };
D55186122E7E914C004CD8BD /* ImageQualityPreset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageQualityPreset.swift; sourceTree = "<group>"; };
D5598B772C435A5C00611AE0 /* ChatUrlImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ChatUrlImageView.swift; path = Sailassist/Chat/View/ChatUrlImageView.swift; sourceTree = SOURCE_ROOT; };
D5598B792C435C4500611AE0 /* ChatUrlRawImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ChatUrlRawImageView.swift; path = Sailassist/Chat/View/ChatUrlRawImageView.swift; sourceTree = SOURCE_ROOT; };
D57905FD2C1C069000AF797C /* SetNgaArea.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetNgaArea.swift; sourceTree = "<group>"; };
......@@ -504,6 +506,7 @@
020B985F2ADD14970029DE4C /* Chat */ = {
isa = PBXGroup;
children = (
D55186122E7E914C004CD8BD /* ImageQualityPreset.swift */,
020B98622ADD14E40029DE4C /* ChatView.swift */,
02A1DE2D2AFB497B005BCF55 /* View */,
D5258CA42B036F0700365276 /* GetMessage.swift */,
......@@ -1040,6 +1043,7 @@
D57906022C1C0CFB00AF797C /* ReqNgaList.swift in Sources */,
020B98162AD8C3150029DE4C /* ContentView.swift in Sources */,
020B98632ADD14E50029DE4C /* ChatView.swift in Sources */,
D55186132E7E9158004CD8BD /* ImageQualityPreset.swift in Sources */,
02CE4DDA2ADFBA72002E79BC /* MapRepresentable.swift in Sources */,
020B985E2ADCFF130029DE4C /* PreferencesKey.swift in Sources */,
0227890C2AE22E0B00A87787 /* SharingData.swift in Sources */,
......@@ -1281,7 +1285,7 @@
CODE_SIGN_ENTITLEMENTS = Sailassist/Sailassist.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 62;
CURRENT_PROJECT_VERSION = 63;
DEVELOPMENT_ASSET_PATHS = "\"Sailassist/Preview Content\"";
DEVELOPMENT_TEAM = D2DC7QNNJ8;
ENABLE_PREVIEWS = YES;
......@@ -1330,7 +1334,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Sailassist/Sailassist.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 62;
CURRENT_PROJECT_VERSION = 63;
DEVELOPMENT_ASSET_PATHS = "\"Sailassist/Preview Content\"";
DEVELOPMENT_TEAM = D2DC7QNNJ8;
ENABLE_PREVIEWS = YES;
......@@ -1516,7 +1520,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Sailassist/Sailassist.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 62;
CURRENT_PROJECT_VERSION = 63;
DEVELOPMENT_ASSET_PATHS = "\"Sailassist/Preview Content\"";
DEVELOPMENT_TEAM = D2DC7QNNJ8;
ENABLE_PREVIEWS = YES;
......
......@@ -27,9 +27,6 @@ struct ChatView: View {
ScrollViewReader { proxy in
ScrollView(.vertical) {
VStack {
Spacer()
.frame(height: 20)
ForEach(message.messages, id: \.messageId) { msg in
if msg.message != nil {
if msg.from == Preferences.UserName {
......@@ -47,6 +44,7 @@ struct ChatView: View {
}
}
}
.padding(.top)
.onAppear {
guard !message.messages.isEmpty,
let id = message.messages.last?.messageId else { return }
......@@ -83,6 +81,16 @@ struct ChatView: View {
}
}
}
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardDidShowNotification)) { _ in
Task {
try await Task.sleep(for: .seconds(0.1))
withAnimation {
if let id = message.messages.last?.messageId {
proxy.scrollTo(id, anchor: .bottom)
}
}
}
}
}
}
HStack {
......
import CoreGraphics
import UIKit
enum ImageQualityPreset {
case low, middle, high
var compressionQuality: CGFloat {
switch self {
case .low: return 0.3
case .middle: return 0.6
case .high: return 1.0
}
}
var targetSize: CGSize {
switch self {
case .low: return CGSize(width: 640, height: 480)
case .middle: return CGSize(width: 1280, height: 960)
case .high: return CGSize(width: 1920, height: 1440)
}
}
}
extension UIImage {
func resized(to targetSize: CGSize) -> UIImage {
let renderer = UIGraphicsImageRenderer(size: targetSize)
return renderer.image { _ in
self.draw(in: CGRect(origin: .zero, size: targetSize))
}
}
}
......@@ -4,48 +4,56 @@
//
// Created by 三浦薫巳 on 2024/01/19.
//
import SwiftUI
struct Imagepicker : UIViewControllerRepresentable {
@Binding var show: Bool
@Binding var image: Data
var sourceType: UIImagePickerController.SourceType
var preset: ImageQualityPreset
func makeCoordinator() -> Imagepicker.Coodinator {
return Imagepicker.Coordinator(parent: self)
func makeCoordinator() -> Coordinator {
return Coordinator(parent: self)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<Imagepicker>) -> UIImagePickerController {
let controller = UIImagePickerController()
controller.sourceType = sourceType
controller.delegate = context.coordinator
// controller.mediaTypes = ["public.image", "public.movie"]
// controller.videoQuality = .type640x480
return controller
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<Imagepicker>) {
}
class Coodinator: NSObject,UIImagePickerControllerDelegate,UINavigationControllerDelegate {
class Coordinator: NSObject,UIImagePickerControllerDelegate,UINavigationControllerDelegate {
var parent : Imagepicker
init(parent : Imagepicker){
self.parent = parent
}
//Cancel
//MARK: - Cancel
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
self.parent.show.toggle()
}
//Use Photo
//MARK: - Use Photo
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let image = info[.originalImage] as! UIImage
if let data = image.jpegData(compressionQuality: 1.0) {
self.parent.image = data
if let image = info[.originalImage] as? UIImage {
let resizedImage = image.resized(to: parent.preset.targetSize)
if let data = resizedImage.jpegData(compressionQuality: parent.preset.compressionQuality) {
parent.image = data
}
self.parent.show.toggle()
} else if let videoURL = info[.mediaURL] as? URL {
// 動画ファイルの処理(例: Dataに変換して保存)
if let videoData = try? Data(contentsOf: videoURL) {
parent.image = videoData
}
}
parent.show.toggle()
}
}
}
......@@ -18,7 +18,7 @@ struct CameraView: View {
NavigationStack {
List {
}.navigationDestination(isPresented: $isImagePicker) {
Imagepicker(show: $isImagePicker, image: $imageData, sourceType: source)
Imagepicker(show: $isImagePicker, image: $imageData, sourceType: source, preset: .high)
}
}
.ignoresSafeArea(.all, edges: .top)
......
......@@ -25,6 +25,7 @@ struct ChatInputView: View {
@State private var failedUploadImage: ReqUploadImage? = nil
@State private var isRetryDialogPresented = false
@State private var isRecording = false
@State private var textViewHeight: CGFloat = 40
@FocusState private var isKeyboardFocused: Bool
@Binding var isFocus: Bool
......@@ -75,35 +76,51 @@ struct ChatInputView: View {
}
//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)
}
// 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("Enter your message", text: $inputText, onEditingChanged: { isEditing in
sceneDelegate.tabWindow?.isHidden = isEditing
isFocus = true
})
TextEditor(text: $inputText)
.focused($isKeyboardFocused)
.font(FontStyle.SupplementText.font)
.font(FontStyle.DefaultText.font)
.scrollContentBackground(Visibility.hidden)
.foregroundColor(ColorSet.BodyChat.color)
.padding(10)
.background(ColorSet.ChatForm.color)
.background(ColorSet.ChatBaloon.color)
.cornerRadius(5)
.padding(.vertical, 10)
.padding(.leading, 10)
.frame(height: textViewHeight)
.onAppear {
recalculateHeight()
}
.onChange(of: inputText) { _ in
recalculateHeight()
}
.overlay(alignment: .topLeading) {
if inputText.isEmpty {
Text("Enter your message")
.font(FontStyle.DefaultText.font)
.foregroundColor(ColorSet.BodyNotice.color)
.background(ColorSet.ChatBaloon.color)
.padding(10)
}
}
.padding(EdgeInsets(top: 2, leading: 10, bottom: 3, trailing: 0))
.onChange(of: isKeyboardFocused) { isFocused in
sceneDelegate.tabWindow?.isHidden = isFocused
isFocus = isFocused
}
//MARK: - 送信ボタン
Button {
......@@ -276,6 +293,16 @@ struct ChatInputView: View {
}
}
}
//MARK: - テキスト高さ
private func recalculateHeight() {
let textView = UITextView()
textView.text = inputText
textView.font = UIFont.preferredFont(forTextStyle: .body)
let fixedWidth = UIScreen.main.bounds.width - 40 // 適宜調整
let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
textViewHeight = max(newSize.height, 40) // 最低高さを40に設定
}
}
#Preview {
......
......@@ -23,7 +23,7 @@ struct MyChatContentView: View {
.foregroundColor(ColorSet.BodyChat.color)
.padding(15)
.background(ColorSet.ChatBaloon.color)
.border(Color.red.gradient.opacity(0.8), width: (message.mode == 1 ? 2 : 0))
.border(Color.red.gradient.opacity(0.8), width: (message.mode == ChatMode.warningProgress.rawValue ? 2 : 0))
.clipShape(
.rect(
topLeadingRadius: 10,
......
......@@ -28,7 +28,7 @@ struct OtherChatContentView: View {
.foregroundColor(ColorSet.BodyChat.color)
.padding(15)
.background(ColorSet.ChatBaloon.color)
.border(Color.red.gradient.opacity(0.8), width: (message.mode == 1 ? 2 : 0))
.border(Color.red.gradient.opacity(0.8), width: (message.mode == ChatMode.warningProgress.rawValue ? 2 : 0))
.clipShape(
.rect(
topLeadingRadius: 10,
......
......@@ -23,7 +23,7 @@ struct MapRepresentable: UIViewControllerRepresentable {
mapVC
}
//Viewが更新された場合に必要な処理を実装
//MARK: - Viewが更新された場合に必要な処理を実装
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
let ecaArea = ecaData.ecaArea.map{ $0.1 }.filter{ $0.isRunning }.first
if let ecaArea = ecaArea {
......@@ -32,7 +32,7 @@ struct MapRepresentable: UIViewControllerRepresentable {
mapVC.removeEcaLine()
}
//ECA領域を画面中央に表示
//MARK: - ECA領域を画面中央に表示
if let focusEcaAreaId = ecaData.focusEca, let focusEca = ecaData.ecaArea[focusEcaAreaId] {
mapVC.updateCamera(location: focusEca.centerPosition, zoomlevel: focusEca.zoomLevel)
mapVC.updateOneTimeEca(eca: focusEca.points)
......@@ -42,7 +42,7 @@ struct MapRepresentable: UIViewControllerRepresentable {
}
}
//NGA領域を画面中央に表示
//MARK: - NGA領域を画面中央に表示
if let AreaId = ngaData.focusNga, let uuid = NSUUID(uuidString: AreaId) {
if let focusNga = ngaData.ngaArea[uuid as UUID] {
if focusNga.points.count > 0 {
......@@ -52,7 +52,7 @@ struct MapRepresentable: UIViewControllerRepresentable {
}
}
//通知場所を画面中央に表示
//MARK: - 通知場所を画面中央に表示
if let focusPushHistoryId = pushHistory.focusPushHistory, let focusPushHistory = pushHistory.pushHistoryData[focusPushHistoryId] {
if let position = focusPushHistory.position {
if let latitude = position.lat, let longitude = position.lon {
......@@ -61,9 +61,9 @@ struct MapRepresentable: UIViewControllerRepresentable {
}
}
//自船を画面中央に表示
//MARK: - 自船を画面中央に表示
if location.focusOwnShip {
mapVC.updateCamera(location: location.location, zoomlevel: nil)
mapVC.updateCamera(location: location.location, zoomlevel: 10.0)
}
if let mylocation = location.location {
......@@ -124,7 +124,7 @@ class MapViewController : UIViewController {
self.addLayers()
}
//地図上クリック
//MARK: - 地図上クリック
let singleTap = UITapGestureRecognizer(target: self, action: #selector(handleMapTap(sender:)))
singleTap.numberOfTapsRequired = 1
singleTap.numberOfTouchesRequired = 1
......@@ -134,7 +134,7 @@ class MapViewController : UIViewController {
// }
mapView.addGestureRecognizer(singleTap)
//地図上長押し
//MARK: - 地図上長押し
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleMapLongPress(sender:)))
for recognizer in mapView.gestureRecognizers! where recognizer is UILongPressGestureRecognizer {
longPress.require(toFail: recognizer)
......@@ -1011,11 +1011,13 @@ class MapViewController : UIViewController {
* カメラ
*/
func updateCamera(location: CLLocationCoordinate2D?, zoomlevel: CGFloat?){
DispatchQueue.main.async {
if let level = zoomlevel {
self.mapView.camera.ease(to: CameraOptions(center: location, zoom: level), duration: 1)
} else {
self.mapView.camera.ease(to: CameraOptions(center: location), duration: 1)
}
}
if SharingData.eca.focusEca != nil {
SharingData.eca.focusEca = nil
}
......
......@@ -209,7 +209,7 @@ class AppDelegate: NSObject, UIApplicationDelegate ,MSNotificationHubDelegate, M
private func handleChatMode(message: ResChatMode) {
print(debug: "called")
if message.mode == 1 {
if message.mode == ChatMode.warningProgress.rawValue {
self.msg.mode = true
} else {
self.msg.mode = false
......
......@@ -199,7 +199,7 @@ struct CustomTabBar: View {
}
}
//チャットTab上の既読マーク
//MARK: - チャットTab上の既読マーク
if tab == Tab.chat {
NotificationBadge(count: message.viewCnt, font: FontStyle.VersionText.font)
.id(message.viewCnt)
......
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