diff --git a/NEChatUIKit/NEChatUIKit.podspec b/NEChatUIKit/NEChatUIKit.podspec index 66d202af..ded0738e 100644 --- a/NEChatUIKit/NEChatUIKit.podspec +++ b/NEChatUIKit/NEChatUIKit.podspec @@ -1,12 +1,12 @@ # # Be sure to run `pod spec lint NEChatUIKit.podspec' to ensure this is a -# valid spec and to remove all comments including this before submitting the spec. +# valid spec and to remove all comments including this before submitting the s. # -# To learn more about Podspec attributes see https://guides.cocoapods.org/syntax/podspec.html +# To learn more about Podspec attributes see https://guides.cocoapods.org/syntax/pods.html # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ # -Pod::Spec.new do |spec| +Pod::Spec.new do |s| # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # # @@ -15,47 +15,40 @@ Pod::Spec.new do |spec| # summary should be tweet-length, and the description more in depth. # - spec.name = 'NEChatUIKit' - spec.version = '9.5.0' - spec.summary = 'Chat Module of IM.' + s.name = 'NEChatUIKit' + s.version = '9.6.0' + s.summary = 'Chat Module of IM.' # This description is used to generate tags and improve search results. # * Think: What does it do? Why did you write it? What is the focus? # * Try to keep it short, snappy and to the point. # * Write the description between the DESC delimiters below. # * Finally, don't worry about the indent, CocoaPods strips it! - spec.description = <<-DESC + s.description = <<-DESC TODO: Add long description of the pod here. DESC - spec.homepage = 'http://netease.im' - spec.license = { :'type' => 'Copyright', :'text' => ' Copyright 2022 Netease '} - spec.author = 'yunxin engineering department' - spec.source = { :git => 'ssh://git@g.hz.netease.com:22222/yunxin-app/xkit-ios.git', :tag => spec.version.to_s } + s.homepage = 'http://netease.im' + s.license = { :'type' => 'Copyright', :'text' => ' Copyright 2022 Netease '} + s.author = 'yunxin engineering department' + s.source = { :git => 'ssh://git@g.hz.netease.com:22222/yunxin-app/xkit-ios.git', :tag => s.version.to_s } - spec.ios.deployment_target = '9.0' - spec.swift_version = '5.0' + s.ios.deployment_target = '10.0' + s.swift_version = '5.0' - spec.source_files = 'NEChatUIKit/Classes/**/*' - spec.pod_target_xcconfig = { + s.source_files = 'NEChatUIKit/Classes/**/*' + s.pod_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64', 'BUILD_LIBRARY_FOR_DISTRIBUTION' => 'YES' } -# spec.resource_bundles = { -# 'NEChatUIKit' => ['NEChatUIKit/Assets/*.png'] -# } -# spec.static_framework = true - - spec.resource = 'NEChatUIKit/Assets/**/*' - spec.dependency 'NEChatKit' - spec.dependency 'NECommonUIKit' - spec.dependency 'MJRefresh' - spec.dependency 'NIMSDK_LITE' - spec.dependency 'YXAlog' - spec.dependency 'UITextView+Placeholder' - spec.dependency 'SDWebImageWebPCoder' - spec.dependency 'SDWebImageSVGKitPlugin' - - + s.resource = 'NEChatUIKit/Assets/**/*' + s.dependency 'NEChatKit' + s.dependency 'NECommonUIKit' + s.dependency 'NECommonKit' + s.dependency 'MJRefresh' + s.dependency 'UITextView+Placeholder' + s.dependency 'SDWebImageWebPCoder' + s.dependency 'SDWebImageSVGKitPlugin' + s.dependency 'lottie-ios','2.5.3' end diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_receive_fun.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_receive_fun.imageset/Contents.json new file mode 100644 index 00000000..ec0a34fc --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_receive_fun.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "chat_message_receive_fun@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "chat_message_receive_fun@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_receive_fun.imageset/chat_message_receive_fun@2x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_receive_fun.imageset/chat_message_receive_fun@2x.png new file mode 100644 index 00000000..187ebd49 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_receive_fun.imageset/chat_message_receive_fun@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_receive_fun.imageset/chat_message_receive_fun@3x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_receive_fun.imageset/chat_message_receive_fun@3x.png new file mode 100644 index 00000000..b62c652d Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_receive_fun.imageset/chat_message_receive_fun@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_send_fun.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_send_fun.imageset/Contents.json new file mode 100644 index 00000000..ec0a34fc --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_send_fun.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "chat_message_receive_fun@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "chat_message_receive_fun@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_send_fun.imageset/chat_message_receive_fun@2x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_send_fun.imageset/chat_message_receive_fun@2x.png new file mode 100644 index 00000000..da2f8e1c Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_send_fun.imageset/chat_message_receive_fun@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_send_fun.imageset/chat_message_receive_fun@3x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_send_fun.imageset/chat_message_receive_fun@3x.png new file mode 100644 index 00000000..8a58d52b Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/chat_message_send_fun.imageset/chat_message_receive_fun@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_change_record.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_change_record.imageset/Contents.json new file mode 100644 index 00000000..a573e3d1 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_change_record.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "funChatRecord@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "funChatRecord@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_change_record.imageset/funChatRecord@2x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_change_record.imageset/funChatRecord@2x.png new file mode 100644 index 00000000..d68ca271 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_change_record.imageset/funChatRecord@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_change_record.imageset/funChatRecord@3x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_change_record.imageset/funChatRecord@3x.png new file mode 100644 index 00000000..4a5bddca Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_change_record.imageset/funChatRecord@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/memberPlaceholder.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_keyboard.imageset/Contents.json similarity index 77% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/memberPlaceholder.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_keyboard.imageset/Contents.json index 221d581f..55c86429 100644 --- a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/memberPlaceholder.imageset/Contents.json +++ b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_keyboard.imageset/Contents.json @@ -5,12 +5,12 @@ "scale" : "1x" }, { - "filename" : "Frame 1016@2x.png", + "filename" : "Group 1804@2x.png", "idiom" : "universal", "scale" : "2x" }, { - "filename" : "Frame 1016@3x.png", + "filename" : "Group 1804@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_keyboard.imageset/Group 1804@2x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_keyboard.imageset/Group 1804@2x.png new file mode 100644 index 00000000..40f68335 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_keyboard.imageset/Group 1804@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_keyboard.imageset/Group 1804@3x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_keyboard.imageset/Group 1804@3x.png new file mode 100644 index 00000000..1563e141 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_keyboard.imageset/Group 1804@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/video_record.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_photo.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/video_record.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_photo.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_photo.imageset/Vector@2x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_photo.imageset/Vector@2x.png new file mode 100644 index 00000000..d287ef1c Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_photo.imageset/Vector@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_photo.imageset/Vector@3x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_photo.imageset/Vector@3x.png new file mode 100644 index 00000000..f0b0e9ad Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_photo.imageset/Vector@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_read_all.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_reply_clear.imageset/Contents.json similarity index 77% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_read_all.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_reply_clear.imageset/Contents.json index 28cf3ffe..6a4d508b 100644 --- a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_read_all.imageset/Contents.json +++ b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_reply_clear.imageset/Contents.json @@ -5,12 +5,12 @@ "scale" : "1x" }, { - "filename" : "Group 156@2x.png", + "filename" : "Vector@2x.png", "idiom" : "universal", "scale" : "2x" }, { - "filename" : "Group 156@3x.png", + "filename" : "Vector@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_reply_clear.imageset/Vector@2x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_reply_clear.imageset/Vector@2x.png new file mode 100644 index 00000000..1432a5fc Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_reply_clear.imageset/Vector@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_reply_clear.imageset/Vector@3x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_reply_clear.imageset/Vector@3x.png new file mode 100644 index 00000000..6ea36fbd Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_reply_clear.imageset/Vector@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/audio_play.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_show_emoj.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/audio_play.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_show_emoj.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_show_emoj.imageset/Frame@2x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_show_emoj.imageset/Frame@2x.png new file mode 100644 index 00000000..412fb711 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_show_emoj.imageset/Frame@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_show_emoj.imageset/Frame@3x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_show_emoj.imageset/Frame@3x.png new file mode 100644 index 00000000..a66452bb Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_show_emoj.imageset/Frame@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/close.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_show_more.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/close.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_show_more.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_show_more.imageset/Frame@2x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_show_more.imageset/Frame@2x.png new file mode 100644 index 00000000..c4e3ecaa Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_show_more.imageset/Frame@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_show_more.imageset/Frame@3x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_show_more.imageset/Frame@3x.png new file mode 100644 index 00000000..2910310d Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_input_show_more.imageset/Frame@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_photo.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_photo.imageset/Contents.json new file mode 100644 index 00000000..d2d43ef2 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_photo.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "fun_chat_photo@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "fun_chat_photo@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_photo.imageset/fun_chat_photo@2x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_photo.imageset/fun_chat_photo@2x.png new file mode 100644 index 00000000..4020340b Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_photo.imageset/fun_chat_photo@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_photo.imageset/fun_chat_photo@3x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_photo.imageset/fun_chat_photo@3x.png new file mode 100644 index 00000000..6094d4b5 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_photo.imageset/fun_chat_photo@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_dark.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_dark.imageset/Contents.json new file mode 100644 index 00000000..a39edf7b --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_dark.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Group 1895@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Group 1895@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_dark.imageset/Group 1895@2x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_dark.imageset/Group 1895@2x.png new file mode 100644 index 00000000..1b21d7a5 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_dark.imageset/Group 1895@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_dark.imageset/Group 1895@3x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_dark.imageset/Group 1895@3x.png new file mode 100644 index 00000000..fdbe7bda Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_dark.imageset/Group 1895@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_light.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_light.imageset/Contents.json new file mode 100644 index 00000000..4e45e065 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_light.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Group 1894@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Group 1894@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_light.imageset/Group 1894@2x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_light.imageset/Group 1894@2x.png new file mode 100644 index 00000000..d16e2e5c Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_light.imageset/Group 1894@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_light.imageset/Group 1894@3x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_light.imageset/Group 1894@3x.png new file mode 100644 index 00000000..1a9c4b56 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_close_light.imageset/Group 1894@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_inner.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_inner.imageset/Contents.json new file mode 100644 index 00000000..975a6973 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_inner.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Group 1891@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Group 1891@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_inner.imageset/Group 1891@2x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_inner.imageset/Group 1891@2x.png new file mode 100644 index 00000000..34e06a76 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_inner.imageset/Group 1891@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_inner.imageset/Group 1891@3x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_inner.imageset/Group 1891@3x.png new file mode 100644 index 00000000..eb10afbf Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_inner.imageset/Group 1891@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_outter.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_outter.imageset/Contents.json new file mode 100644 index 00000000..b632c621 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_outter.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Group 1893@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Group 1893@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_outter.imageset/Group 1893@2x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_outter.imageset/Group 1893@2x.png new file mode 100644 index 00000000..213f1da3 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_outter.imageset/Group 1893@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_outter.imageset/Group 1893@3x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_outter.imageset/Group 1893@3x.png new file mode 100644 index 00000000..ebb06a70 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Chat/fun_chat_record_gesture_outter.imageset/Group 1893@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Members/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Members/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowUp.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Members/fun_all.imageset/Contents.json similarity index 77% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowUp.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Members/fun_all.imageset/Contents.json index c7958429..e1f2e0d4 100644 --- a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowUp.imageset/Contents.json +++ b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Members/fun_all.imageset/Contents.json @@ -5,12 +5,12 @@ "scale" : "1x" }, { - "filename" : "Frame 214@2x.png", + "filename" : "fun_all@2x.png", "idiom" : "universal", "scale" : "2x" }, { - "filename" : "Frame 214@3x.png", + "filename" : "fun_all@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Members/fun_all.imageset/fun_all@2x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Members/fun_all.imageset/fun_all@2x.png new file mode 100644 index 00000000..ab14debf Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Members/fun_all.imageset/fun_all@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Members/fun_all.imageset/fun_all@3x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Members/fun_all.imageset/fun_all@3x.png new file mode 100644 index 00000000..bf330415 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/Members/fun_all.imageset/fun_all@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_pin_message_audio_bg.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_pin_message_audio_bg.imageset/Contents.json new file mode 100644 index 00000000..d102c969 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_pin_message_audio_bg.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "左气泡@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "左气泡@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_pin_message_audio_bg.imageset/\345\267\246\346\260\224\346\263\241@2x.png" "b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_pin_message_audio_bg.imageset/\345\267\246\346\260\224\346\263\241@2x.png" new file mode 100644 index 00000000..f40e2719 Binary files /dev/null and "b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_pin_message_audio_bg.imageset/\345\267\246\346\260\224\346\263\241@2x.png" differ diff --git "a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_pin_message_audio_bg.imageset/\345\267\246\346\260\224\346\263\241@3x.png" "b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_pin_message_audio_bg.imageset/\345\267\246\346\260\224\346\263\241@3x.png" new file mode 100644 index 00000000..8ab8f1cc Binary files /dev/null and "b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_pin_message_audio_bg.imageset/\345\267\246\346\260\224\346\263\241@3x.png" differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_setting_add.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_setting_add.imageset/Contents.json new file mode 100644 index 00000000..fe71594f --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_setting_add.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "funSettingAdd@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "funSettingAdd@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_setting_add.imageset/funSettingAdd@2x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_setting_add.imageset/funSettingAdd@2x.png new file mode 100644 index 00000000..dd8cf483 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_setting_add.imageset/funSettingAdd@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_setting_add.imageset/funSettingAdd@3x.png b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_setting_add.imageset/funSettingAdd@3x.png new file mode 100644 index 00000000..5f81645b Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/FunChatUIKit.xcassets/fun_setting_add.imageset/funSettingAdd@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/add.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/add.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/add.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/add.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/add.imageset/Frame@2x-4.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/add.imageset/Frame@2x-4.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/add.imageset/Frame@2x-4.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/add.imageset/Frame@2x-4.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/add.imageset/Frame@3x-4.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/add.imageset/Frame@3x-4.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/add.imageset/Frame@3x-4.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/add.imageset/Frame@3x-4.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/add_selected.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/add_selected.imageset/Contents.json new file mode 100644 index 00000000..03210129 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/add_selected.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "add_selected@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "add_selected@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/add_selected.imageset/add_selected@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/add_selected.imageset/add_selected@2x.png new file mode 100644 index 00000000..513304d9 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/add_selected.imageset/add_selected@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/add_selected.imageset/add_selected@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/add_selected.imageset/add_selected@3x.png new file mode 100644 index 00000000..55e87912 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/add_selected.imageset/add_selected@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_1.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/audio_play.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_1.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/audio_play.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/audio_play.imageset/Frame@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/audio_play.imageset/Frame@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/audio_play.imageset/Frame@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/audio_play.imageset/Frame@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/audio_play.imageset/Frame@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/audio_play.imageset/Frame@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/audio_play.imageset/Frame@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/audio_play.imageset/Frame@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_file.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_file.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_file.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_file.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_file.imageset/chat_file@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_file.imageset/chat_file@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_file.imageset/chat_file@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_file.imageset/chat_file@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_file.imageset/chat_file@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_file.imageset/chat_file@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_file.imageset/chat_file@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_file.imageset/chat_file@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_location.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_location.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_location.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_location.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_location.imageset/chat_location@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_location.imageset/chat_location@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_location.imageset/chat_location@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_location.imageset/chat_location@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_location.imageset/chat_location@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_location.imageset/chat_location@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_location.imageset/chat_location@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_location.imageset/chat_location@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_read_all.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_read_all.imageset/Contents.json new file mode 100644 index 00000000..65915e63 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_read_all.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "chat_read_all@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "chat_read_all@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_read_all.imageset/chat_read_all@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_read_all.imageset/chat_read_all@2x.png new file mode 100644 index 00000000..c3523c70 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_read_all.imageset/chat_read_all@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_read_all.imageset/chat_read_all@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_read_all.imageset/chat_read_all@3x.png new file mode 100644 index 00000000..a8cc2fc2 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_read_all.imageset/chat_read_all@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_rtc.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_rtc.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_rtc.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_rtc.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_rtc.imageset/chat_rtc@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_rtc.imageset/chat_rtc@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_rtc.imageset/chat_rtc@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_rtc.imageset/chat_rtc@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_rtc.imageset/chat_rtc@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_rtc.imageset/chat_rtc@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_rtc.imageset/chat_rtc@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_rtc.imageset/chat_rtc@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_takePicture.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_takePicture.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_takePicture.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_takePicture.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_takePicture.imageset/chat_takePicture@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_takePicture.imageset/chat_takePicture@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_takePicture.imageset/chat_takePicture@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_takePicture.imageset/chat_takePicture@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_takePicture.imageset/chat_takePicture@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_takePicture.imageset/chat_takePicture@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_takePicture.imageset/chat_takePicture@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_takePicture.imageset/chat_takePicture@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_unread.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_unread.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_unread.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_unread.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_unread.imageset/Ellipse 17@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_unread.imageset/Ellipse 17@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_unread.imageset/Ellipse 17@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_unread.imageset/Ellipse 17@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_unread.imageset/Ellipse 17@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_unread.imageset/Ellipse 17@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_unread.imageset/Ellipse 17@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_unread.imageset/Ellipse 17@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_video.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_video.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_video.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_video.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_video.imageset/chat_video@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_video.imageset/chat_video@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_video.imageset/chat_video@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_video.imageset/chat_video@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_video.imageset/chat_video@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_video.imageset/chat_video@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_video.imageset/chat_video@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/chat_video.imageset/chat_video@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/mic.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/close.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/mic.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/close.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/close.imageset/Frame@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/close.imageset/Frame@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/close.imageset/Frame@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/close.imageset/Frame@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/close.imageset/Frame@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/close.imageset/Frame@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/close.imageset/Frame@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/close.imageset/Frame@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/emoji.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/emoji.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/emoji.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/emoji.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/emoji.imageset/Frame@2x-1.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/emoji.imageset/Frame@2x-1.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/emoji.imageset/Frame@2x-1.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/emoji.imageset/Frame@2x-1.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/emoji.imageset/Frame@3x-1.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/emoji.imageset/Frame@3x-1.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/emoji.imageset/Frame@3x-1.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/emoji.imageset/Frame@3x-1.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/emoji_selected.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/emoji_selected.imageset/Contents.json new file mode 100644 index 00000000..5fe0024e --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/emoji_selected.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "emoji_selected@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "emoji_selected@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/emoji_selected.imageset/emoji_selected@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/emoji_selected.imageset/emoji_selected@2x.png new file mode 100644 index 00000000..6ffedaf1 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/emoji_selected.imageset/emoji_selected@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/emoji_selected.imageset/emoji_selected@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/emoji_selected.imageset/emoji_selected@3x.png new file mode 100644 index 00000000..ede77e8f Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/emoji_selected.imageset/emoji_selected@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/file.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/file.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/file.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/file.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/file.imageset/Frame@2x-3.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/file.imageset/Frame@2x-3.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/file.imageset/Frame@2x-3.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/file.imageset/Frame@2x-3.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/file.imageset/Frame@3x-3.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/file.imageset/Frame@3x-3.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/file.imageset/Frame@3x-3.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/file.imageset/Frame@3x-3.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/msg_pin.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_1.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/msg_pin.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_1.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_1.imageset/Frame@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_1.imageset/Frame@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_1.imageset/Frame@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_1.imageset/Frame@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_1.imageset/Frame@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_1.imageset/Frame@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_1.imageset/Frame@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_1.imageset/Frame@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_2.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_2.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_2.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_2.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_2.imageset/Frame@2x-1.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_2.imageset/Frame@2x-1.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_2.imageset/Frame@2x-1.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_2.imageset/Frame@2x-1.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_2.imageset/Frame@3x-1.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_2.imageset/Frame@3x-1.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_2.imageset/Frame@3x-1.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_2.imageset/Frame@3x-1.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_3.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_3.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_3.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_3.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_3.imageset/Frame@2x-2.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_3.imageset/Frame@2x-2.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_3.imageset/Frame@2x-2.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_3.imageset/Frame@2x-2.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_3.imageset/Frame@3x-2.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_3.imageset/Frame@3x-2.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/left_play_3.imageset/Frame@3x-2.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/left_play_3.imageset/Frame@3x-2.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_1.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/mic.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_1.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/mic.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/mic.imageset/Frame@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/mic.imageset/Frame@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/mic.imageset/Frame@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/mic.imageset/Frame@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/mic.imageset/Frame@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/mic.imageset/Frame@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/mic.imageset/Frame@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/mic.imageset/Frame@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/mic_selected.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/mic_selected.imageset/Contents.json new file mode 100644 index 00000000..c83d6c1d --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/mic_selected.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "mic_selected@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "mic_selected@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/mic_selected.imageset/mic_selected@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/mic_selected.imageset/mic_selected@2x.png new file mode 100644 index 00000000..ebf7c977 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/mic_selected.imageset/mic_selected@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/mic_selected.imageset/mic_selected@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/mic_selected.imageset/mic_selected@3x.png new file mode 100644 index 00000000..159d32e9 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/mic_selected.imageset/mic_selected@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/audio_record.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/msg_pin.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/audio_record.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/msg_pin.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/msg_pin.imageset/Frame@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/msg_pin.imageset/Frame@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/msg_pin.imageset/Frame@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/msg_pin.imageset/Frame@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/msg_pin.imageset/Frame@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/msg_pin.imageset/Frame@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/msg_pin.imageset/Frame@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/msg_pin.imageset/Frame@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/photo.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/photo.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/photo.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/photo.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/photo.imageset/Frame@2x-2.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/photo.imageset/Frame@2x-2.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/photo.imageset/Frame@2x-2.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/photo.imageset/Frame@2x-2.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/photo.imageset/Frame@3x-2.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/photo.imageset/Frame@3x-2.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/photo.imageset/Frame@3x-2.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/photo.imageset/Frame@3x-2.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/delete.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_1.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/delete.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_1.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_1.imageset/Frame@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_1.imageset/Frame@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_1.imageset/Frame@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_1.imageset/Frame@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_1.imageset/Frame@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_1.imageset/Frame@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_1.imageset/Frame@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_1.imageset/Frame@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_2.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_2.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_2.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_2.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_2.imageset/Frame@2x-1.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_2.imageset/Frame@2x-1.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_2.imageset/Frame@2x-1.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_2.imageset/Frame@2x-1.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_2.imageset/Frame@3x-1.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_2.imageset/Frame@3x-1.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_2.imageset/Frame@3x-1.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_2.imageset/Frame@3x-1.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_3.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_3.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_3.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_3.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_3.imageset/Frame@2x-2.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_3.imageset/Frame@2x-2.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_3.imageset/Frame@2x-2.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_3.imageset/Frame@2x-2.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_3.imageset/Frame@3x-2.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_3.imageset/Frame@3x-2.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/play_3.imageset/Frame@3x-2.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/play_3.imageset/Frame@3x-2.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_1.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_1.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_1.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_1.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_1.imageset/Group 311@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_1.imageset/Group 311@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_1.imageset/Group 311@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_1.imageset/Group 311@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_1.imageset/Group 311@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_1.imageset/Group 311@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_1.imageset/Group 311@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_1.imageset/Group 311@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_2.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_2.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_2.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_2.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_2.imageset/Group 310@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_2.imageset/Group 310@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_2.imageset/Group 310@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_2.imageset/Group 310@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_2.imageset/Group 310@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_2.imageset/Group 310@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_2.imageset/Group 310@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_2.imageset/Group 310@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_3.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_3.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_3.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_3.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_3.imageset/Group 309@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_3.imageset/Group 309@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_3.imageset/Group 309@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_3.imageset/Group 309@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_3.imageset/Group 309@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_3.imageset/Group 309@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_3.imageset/Group 309@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_3.imageset/Group 309@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_4.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_4.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_4.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_4.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_4.imageset/Group 308@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_4.imageset/Group 308@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_4.imageset/Group 308@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_4.imageset/Group 308@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_4.imageset/Group 308@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_4.imageset/Group 308@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/record_4.imageset/Group 308@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/record_4.imageset/Group 308@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/sendMessage_failed.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/sendMessage_failed.imageset/Contents.json new file mode 100644 index 00000000..2c0a5452 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/sendMessage_failed.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "sendMessage_failed@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "sendMessage_failed@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/sendMessage_failed.imageset/sendMessage_failed@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/sendMessage_failed.imageset/sendMessage_failed@2x.png new file mode 100644 index 00000000..d4dd2d29 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/sendMessage_failed.imageset/sendMessage_failed@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/sendMessage_failed.imageset/sendMessage_failed@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/sendMessage_failed.imageset/sendMessage_failed@3x.png new file mode 100644 index 00000000..c8d3953c Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Chat/sendMessage_failed.imageset/sendMessage_failed@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowDown.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowDown.imageset/Contents.json new file mode 100644 index 00000000..ddb7e7db --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowDown.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "arrowDown@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "arrowDown@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowDown.imageset/arrowDown@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowDown.imageset/arrowDown@2x.png new file mode 100644 index 00000000..690fe588 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowDown.imageset/arrowDown@2x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowDown.imageset/arrowDown@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowDown.imageset/arrowDown@3x.png new file mode 100644 index 00000000..b721d7c4 Binary files /dev/null and b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowDown.imageset/arrowDown@3x.png differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowRight.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowRight.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowRight.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowRight.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowRight.imageset/Vector 87@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowRight.imageset/Vector 87@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowRight.imageset/Vector 87@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowRight.imageset/Vector 87@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowRight.imageset/Vector 87@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowRight.imageset/Vector 87@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowRight.imageset/Vector 87@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowRight.imageset/Vector 87@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowDown.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowUp.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowDown.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowUp.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowUp.imageset/Frame 214@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowUp.imageset/Frame 214@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowUp.imageset/Frame 214@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowUp.imageset/Frame 214@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowUp.imageset/Frame 214@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowUp.imageset/Frame 214@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowUp.imageset/Frame 214@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/arrowUp.imageset/Frame 214@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/right_arrow.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/audio_record.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/right_arrow.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/audio_record.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/audio_record.imageset/Frame@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/audio_record.imageset/Frame@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/audio_record.imageset/Frame@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/audio_record.imageset/Frame@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/audio_record.imageset/Frame@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/audio_record.imageset/Frame@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/audio_record.imageset/Frame@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/audio_record.imageset/Frame@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/backArrow.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/backArrow.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/backArrow.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/backArrow.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/backArrow.imageset/backArrow@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/backArrow.imageset/backArrow@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/backArrow.imageset/backArrow@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/backArrow.imageset/backArrow@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/backArrow.imageset/backArrow@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/backArrow.imageset/backArrow@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/backArrow.imageset/backArrow@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/backArrow.imageset/backArrow@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/search.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/delete.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/search.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/delete.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/delete.imageset/Frame@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/delete.imageset/Frame@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/delete.imageset/Frame@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/delete.imageset/Frame@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/delete.imageset/Frame@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/delete.imageset/Frame@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/delete.imageset/Frame@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/delete.imageset/Frame@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_copy.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/right_arrow.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_copy.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/right_arrow.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/right_arrow.imageset/Frame@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/right_arrow.imageset/Frame@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/right_arrow.imageset/Frame@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/right_arrow.imageset/Frame@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/right_arrow.imageset/Frame@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/right_arrow.imageset/Frame@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/right_arrow.imageset/Frame@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/right_arrow.imageset/Frame@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/rolePlaceholder.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/rolePlaceholder.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/rolePlaceholder.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/rolePlaceholder.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/rolePlaceholder.imageset/Frame 1018@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/rolePlaceholder.imageset/Frame 1018@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/rolePlaceholder.imageset/Frame 1018@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/rolePlaceholder.imageset/Frame 1018@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/rolePlaceholder.imageset/Frame 1018@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/rolePlaceholder.imageset/Frame 1018@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/rolePlaceholder.imageset/Frame 1018@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/rolePlaceholder.imageset/Frame 1018@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/myComputer.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/search.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/myComputer.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/search.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/search.imageset/Frame@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/search.imageset/Frame@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/search.imageset/Frame@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/search.imageset/Frame@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/search.imageset/Frame@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/search.imageset/Frame@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/search.imageset/Frame@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/search.imageset/Frame@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/select.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/select.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/select.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/select.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/select.imageset/select@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/select.imageset/select@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/select.imageset/select@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/select.imageset/select@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/select.imageset/select@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/select.imageset/select@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/select.imageset/select@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/select.imageset/select@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/setting_add.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/setting_add.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/setting_add.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/setting_add.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/setting_add.imageset/setting_add@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/setting_add.imageset/setting_add@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/setting_add.imageset/setting_add@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/setting_add.imageset/setting_add@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/setting_add.imageset/setting_add@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/setting_add.imageset/setting_add@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/setting_add.imageset/setting_add@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/setting_add.imageset/setting_add@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/sign_add.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/sign_add.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/sign_add.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/sign_add.imageset/Contents.json diff --git "a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/sign_add.imageset/\346\267\273\345\212\240@2x.png" "b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/sign_add.imageset/\346\267\273\345\212\240@2x.png" similarity index 100% rename from "NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/sign_add.imageset/\346\267\273\345\212\240@2x.png" rename to "NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/sign_add.imageset/\346\267\273\345\212\240@2x.png" diff --git "a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/sign_add.imageset/\346\267\273\345\212\240@3x.png" "b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/sign_add.imageset/\346\267\273\345\212\240@3x.png" similarity index 100% rename from "NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/sign_add.imageset/\346\267\273\345\212\240@3x.png" rename to "NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/sign_add.imageset/\346\267\273\345\212\240@3x.png" diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/three_point.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/three_point.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/three_point.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/three_point.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/three_point.imageset/threePoint@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/three_point.imageset/threePoint@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/three_point.imageset/threePoint@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/three_point.imageset/threePoint@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/three_point.imageset/threePoint@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/three_point.imageset/threePoint@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/three_point.imageset/threePoint@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/three_point.imageset/threePoint@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/unselect.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/unselect.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/unselect.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/unselect.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/unselect.imageset/unselect@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/unselect.imageset/unselect@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/unselect.imageset/unselect@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/unselect.imageset/unselect@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/unselect.imageset/unslect@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/unselect.imageset/unslect@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/unselect.imageset/unslect@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/unselect.imageset/unslect@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/video_record.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/video_record.imageset/Contents.json new file mode 100644 index 00000000..6a4d508b --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/video_record.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Vector@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Vector@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/video_record.imageset/Vector@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/video_record.imageset/Vector@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/video_record.imageset/Vector@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/video_record.imageset/Vector@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/video_record.imageset/Vector@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/video_record.imageset/Vector@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/video_record.imageset/Vector@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Commom/video_record.imageset/Vector@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Members/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Members/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_audio.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_audio.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_audio.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_audio.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_audio.imageset/file_mp3@1x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_audio.imageset/file_mp3@1x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_audio.imageset/file_mp3@1x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_audio.imageset/file_mp3@1x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_audio.imageset/file_mp3@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_audio.imageset/file_mp3@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_audio.imageset/file_mp3@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_audio.imageset/file_mp3@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_audio.imageset/file_mp3@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_audio.imageset/file_mp3@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_audio.imageset/file_mp3@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_audio.imageset/file_mp3@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_doc.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_doc.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_doc.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_doc.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_doc.imageset/file_doc@1x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_doc.imageset/file_doc@1x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_doc.imageset/file_doc@1x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_doc.imageset/file_doc@1x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_doc.imageset/file_doc@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_doc.imageset/file_doc@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_doc.imageset/file_doc@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_doc.imageset/file_doc@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_doc.imageset/file_doc@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_doc.imageset/file_doc@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_doc.imageset/file_doc@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_doc.imageset/file_doc@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_html.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_html.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_html.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_html.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_html.imageset/file_html@1x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_html.imageset/file_html@1x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_html.imageset/file_html@1x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_html.imageset/file_html@1x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_html.imageset/file_html@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_html.imageset/file_html@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_html.imageset/file_html@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_html.imageset/file_html@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_html.imageset/file_html@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_html.imageset/file_html@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_html.imageset/file_html@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_html.imageset/file_html@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_img.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_img.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_img.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_img.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_img.imageset/file_img@1x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_img.imageset/file_img@1x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_img.imageset/file_img@1x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_img.imageset/file_img@1x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_img.imageset/file_img@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_img.imageset/file_img@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_img.imageset/file_img@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_img.imageset/file_img@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_img.imageset/file_img@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_img.imageset/file_img@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_img.imageset/file_img@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_img.imageset/file_img@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_keynote.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_keynote.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_keynote.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_keynote.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_keynote.imageset/file_keynote@1x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_keynote.imageset/file_keynote@1x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_keynote.imageset/file_keynote@1x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_keynote.imageset/file_keynote@1x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_keynote.imageset/file_keynote@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_keynote.imageset/file_keynote@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_keynote.imageset/file_keynote@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_keynote.imageset/file_keynote@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_keynote.imageset/file_keynote@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_keynote.imageset/file_keynote@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_keynote.imageset/file_keynote@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_keynote.imageset/file_keynote@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_pdf.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_pdf.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_pdf.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_pdf.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_pdf.imageset/file_pdf@1x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_pdf.imageset/file_pdf@1x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_pdf.imageset/file_pdf@1x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_pdf.imageset/file_pdf@1x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_pdf.imageset/file_pdf@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_pdf.imageset/file_pdf@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_pdf.imageset/file_pdf@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_pdf.imageset/file_pdf@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_pdf.imageset/file_pdf@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_pdf.imageset/file_pdf@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_pdf.imageset/file_pdf@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_pdf.imageset/file_pdf@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_ppt.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_ppt.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_ppt.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_ppt.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_ppt.imageset/file_ppt@1x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_ppt.imageset/file_ppt@1x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_ppt.imageset/file_ppt@1x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_ppt.imageset/file_ppt@1x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_ppt.imageset/file_ppt@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_ppt.imageset/file_ppt@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_ppt.imageset/file_ppt@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_ppt.imageset/file_ppt@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_ppt.imageset/file_ppt@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_ppt.imageset/file_ppt@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_ppt.imageset/file_ppt@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_ppt.imageset/file_ppt@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_txt.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_txt.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_txt.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_txt.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_txt.imageset/file_txt@1x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_txt.imageset/file_txt@1x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_txt.imageset/file_txt@1x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_txt.imageset/file_txt@1x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_txt.imageset/file_txt@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_txt.imageset/file_txt@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_txt.imageset/file_txt@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_txt.imageset/file_txt@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_txt.imageset/file_txt@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_txt.imageset/file_txt@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_txt.imageset/file_txt@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_txt.imageset/file_txt@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_unknown.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_unknown.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_unknown.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_unknown.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_unknown.imageset/file_unknown@1x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_unknown.imageset/file_unknown@1x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_unknown.imageset/file_unknown@1x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_unknown.imageset/file_unknown@1x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_unknown.imageset/file_unknown@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_unknown.imageset/file_unknown@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_unknown.imageset/file_unknown@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_unknown.imageset/file_unknown@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_unknown.imageset/file_unknown@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_unknown.imageset/file_unknown@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_unknown.imageset/file_unknown@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_unknown.imageset/file_unknown@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_vedio.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_vedio.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_vedio.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_vedio.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_vedio.imageset/file_mp4@1x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_vedio.imageset/file_mp4@1x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_vedio.imageset/file_mp4@1x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_vedio.imageset/file_mp4@1x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_vedio.imageset/file_mp4@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_vedio.imageset/file_mp4@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_vedio.imageset/file_mp4@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_vedio.imageset/file_mp4@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_vedio.imageset/file_mp4@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_vedio.imageset/file_mp4@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_vedio.imageset/file_mp4@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_vedio.imageset/file_mp4@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_xls.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_xls.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_xls.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_xls.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_xls.imageset/file_xls@1x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_xls.imageset/file_xls@1x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_xls.imageset/file_xls@1x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_xls.imageset/file_xls@1x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_xls.imageset/file_xls@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_xls.imageset/file_xls@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_xls.imageset/file_xls@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_xls.imageset/file_xls@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_xls.imageset/file_xls@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_xls.imageset/file_xls@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_xls.imageset/file_xls@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_xls.imageset/file_xls@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_zip.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_zip.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_zip.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_zip.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_zip.imageset/file_zip@1x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_zip.imageset/file_zip@1x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_zip.imageset/file_zip@1x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_zip.imageset/file_zip@1x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_zip.imageset/file_zip@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_zip.imageset/file_zip@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_zip.imageset/file_zip@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_zip.imageset/file_zip@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_zip.imageset/file_zip@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_zip.imageset/file_zip@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/File/file_zip.imageset/file_zip@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/File/file_zip.imageset/file_zip@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_loacaiton_img.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_loacaiton_img.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_loacaiton_img.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_loacaiton_img.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_loacaiton_img.imageset/chat_loacaiton_img@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_loacaiton_img.imageset/chat_loacaiton_img@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_loacaiton_img.imageset/chat_loacaiton_img@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_loacaiton_img.imageset/chat_loacaiton_img@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_loacaiton_img.imageset/chat_loacaiton_img@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_loacaiton_img.imageset/chat_loacaiton_img@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_loacaiton_img.imageset/chat_loacaiton_img@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_loacaiton_img.imageset/chat_loacaiton_img@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_back.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_back.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_back.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_back.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_back.imageset/chat_map_back@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_back.imageset/chat_map_back@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_back.imageset/chat_map_back@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_back.imageset/chat_map_back@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_back.imageset/chat_map_back@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_back.imageset/chat_map_back@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_back.imageset/chat_map_back@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_back.imageset/chat_map_back@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_empty.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_empty.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_empty.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_empty.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_empty.imageset/map_empty@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_empty.imageset/map_empty@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_empty.imageset/map_empty@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_empty.imageset/map_empty@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_empty.imageset/map_empty@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_empty.imageset/map_empty@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_empty.imageset/map_empty@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_empty.imageset/map_empty@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_path.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_path.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_path.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_path.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_path.imageset/chat_map_path@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_path.imageset/chat_map_path@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_path.imageset/chat_map_path@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_path.imageset/chat_map_path@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_path.imageset/chat_map_path@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_path.imageset/chat_map_path@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_path.imageset/chat_map_path@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_path.imageset/chat_map_path@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_select.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_select.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_select.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_select.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_select.imageset/chat_map_select@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_select.imageset/chat_map_select@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_select.imageset/chat_map_select@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_select.imageset/chat_map_select@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_select.imageset/chat_map_select@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_select.imageset/chat_map_select@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/chat_map_select.imageset/chat_map_select@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/chat_map_select.imageset/chat_map_select@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/location_point.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/location_point.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/location_point.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/location_point.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/location_point.imageset/location_point@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/location_point.imageset/location_point@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/location_point.imageset/location_point@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/location_point.imageset/location_point@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/location_point.imageset/location_point@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/location_point.imageset/location_point@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/location_point.imageset/location_point@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/location_point.imageset/location_point@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/map_reset_normal.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/map_reset_normal.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/map_reset_normal.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/map_reset_normal.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/map_reset_normal.imageset/map_select_normal@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/map_reset_normal.imageset/map_select_normal@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/map_reset_normal.imageset/map_select_normal@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/map_reset_normal.imageset/map_select_normal@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/map_reset_normal.imageset/map_select_normal@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/map_reset_normal.imageset/map_select_normal@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/map_reset_normal.imageset/map_select_normal@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/map_reset_normal.imageset/map_select_normal@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/map_reset_select.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/map_reset_select.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/map_reset_select.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/map_reset_select.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/map_reset_select.imageset/map_reset_select@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/map_reset_select.imageset/map_reset_select@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/map_reset_select.imageset/map_reset_select@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/map_reset_select.imageset/map_reset_select@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/map_reset_select.imageset/map_reset_select@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/map_reset_select.imageset/map_reset_select@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Map/map_reset_select.imageset/map_reset_select@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/Map/map_reset_select.imageset/map_reset_select@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_collection.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_collection.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_collection.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_collection.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_collection.imageset/Frame@2x-5.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_collection.imageset/Frame@2x-5.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_collection.imageset/Frame@2x-5.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_collection.imageset/Frame@2x-5.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_collection.imageset/Frame@3x-5.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_collection.imageset/Frame@3x-5.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_collection.imageset/Frame@3x-5.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_collection.imageset/Frame@3x-5.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/sendMessage_failed.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_copy.imageset/Contents.json similarity index 79% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/sendMessage_failed.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_copy.imageset/Contents.json index a1a85bc4..5c4d3b18 100644 --- a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/sendMessage_failed.imageset/Contents.json +++ b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_copy.imageset/Contents.json @@ -1,15 +1,16 @@ { "images" : [ { - "filename" : "sendMessage_failed.png", "idiom" : "universal", "scale" : "1x" }, { + "filename" : "Frame@2x.png", "idiom" : "universal", "scale" : "2x" }, { + "filename" : "Frame@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_copy.imageset/Frame@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_copy.imageset/Frame@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_copy.imageset/Frame@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_copy.imageset/Frame@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_copy.imageset/Frame@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_copy.imageset/Frame@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_copy.imageset/Frame@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_copy.imageset/Frame@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_delete.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_delete.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_delete.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_delete.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_delete.imageset/Frame 45@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_delete.imageset/Frame 45@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_delete.imageset/Frame 45@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_delete.imageset/Frame 45@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_delete.imageset/Frame 45@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_delete.imageset/Frame 45@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_delete.imageset/Frame 45@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_delete.imageset/Frame 45@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_forward.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_forward.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_forward.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_forward.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_forward.imageset/Frame@2x-2.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_forward.imageset/Frame@2x-2.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_forward.imageset/Frame@2x-2.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_forward.imageset/Frame@2x-2.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_forward.imageset/Frame@3x-2.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_forward.imageset/Frame@3x-2.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_forward.imageset/Frame@3x-2.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_forward.imageset/Frame@3x-2.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_pin.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_pin.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_pin.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_pin.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_pin.imageset/Frame@2x-3.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_pin.imageset/Frame@2x-3.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_pin.imageset/Frame@2x-3.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_pin.imageset/Frame@2x-3.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_pin.imageset/Frame@3x-3.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_pin.imageset/Frame@3x-3.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_pin.imageset/Frame@3x-3.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_pin.imageset/Frame@3x-3.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_recall.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_recall.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_recall.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_recall.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_recall.imageset/Frame@2x-6.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_recall.imageset/Frame@2x-6.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_recall.imageset/Frame@2x-6.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_recall.imageset/Frame@2x-6.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_recall.imageset/Frame@3x-6.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_recall.imageset/Frame@3x-6.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_recall.imageset/Frame@3x-6.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_recall.imageset/Frame@3x-6.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_replay.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_replay.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_replay.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_replay.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_replay.imageset/Frame@2x-1.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_replay.imageset/Frame@2x-1.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_replay.imageset/Frame@2x-1.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_replay.imageset/Frame@2x-1.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_replay.imageset/Frame@3x-1.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_replay.imageset/Frame@3x-1.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_replay.imageset/Frame@3x-1.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_replay.imageset/Frame@3x-1.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_select.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_select.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_select.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_select.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_select.imageset/Frame@2x-4.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_select.imageset/Frame@2x-4.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_select.imageset/Frame@2x-4.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_select.imageset/Frame@2x-4.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_select.imageset/Frame@3x-4.png b/NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_select.imageset/Frame@3x-4.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/operation/op_select.imageset/Frame@3x-4.png rename to NEChatUIKit/NEChatUIKit/Assets/NEBaseChatUIKit.xcassets/operation/op_select.imageset/Frame@3x-4.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_read_all.imageset/Group 156@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_read_all.imageset/Group 156@2x.png deleted file mode 100644 index 6e11dcc2..00000000 Binary files a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_read_all.imageset/Group 156@2x.png and /dev/null differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_read_all.imageset/Group 156@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_read_all.imageset/Group 156@3x.png deleted file mode 100644 index a884d05e..00000000 Binary files a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_read_all.imageset/Group 156@3x.png and /dev/null differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/sendMessage_failed.imageset/sendMessage_failed.png b/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/sendMessage_failed.imageset/sendMessage_failed.png deleted file mode 100644 index 46d65710..00000000 Binary files a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/sendMessage_failed.imageset/sendMessage_failed.png and /dev/null differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowDown.imageset/Frame 214@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowDown.imageset/Frame 214@2x.png deleted file mode 100644 index 92db4e7c..00000000 Binary files a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowDown.imageset/Frame 214@2x.png and /dev/null differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowDown.imageset/Frame 214@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowDown.imageset/Frame 214@3x.png deleted file mode 100644 index d5d2b7f2..00000000 Binary files a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/arrowDown.imageset/Frame 214@3x.png and /dev/null differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/memberPlaceholder.imageset/Frame 1016@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/memberPlaceholder.imageset/Frame 1016@2x.png deleted file mode 100644 index f35b38b1..00000000 Binary files a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/memberPlaceholder.imageset/Frame 1016@2x.png and /dev/null differ diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/memberPlaceholder.imageset/Frame 1016@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/memberPlaceholder.imageset/Frame 1016@3x.png deleted file mode 100644 index 4403d35d..00000000 Binary files a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Commom/memberPlaceholder.imageset/Frame 1016@3x.png and /dev/null differ diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/Contents.json similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_message_receive.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_message_receive.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_message_receive.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_message_receive.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_message_receive.imageset/chat_message_receive@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_message_receive.imageset/chat_message_receive@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_message_receive.imageset/chat_message_receive@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_message_receive.imageset/chat_message_receive@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_message_receive.imageset/chat_message_receive@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_message_receive.imageset/chat_message_receive@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_message_receive.imageset/chat_message_receive@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_message_receive.imageset/chat_message_receive@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_message_send.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_message_send.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_message_send.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_message_send.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_message_send.imageset/chat_message_send@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_message_send.imageset/chat_message_send@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_message_send.imageset/chat_message_send@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_message_send.imageset/chat_message_send@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_message_send.imageset/chat_message_send@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_message_send.imageset/chat_message_send@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_message_send.imageset/chat_message_send@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_message_send.imageset/chat_message_send@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_record.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_record.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_record.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_record.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_record.imageset/Group 280@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_record.imageset/Group 280@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_record.imageset/Group 280@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_record.imageset/Group 280@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_record.imageset/Group 280@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_record.imageset/Group 280@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Chat/chat_record.imageset/Group 280@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Chat/chat_record.imageset/Group 280@3x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Contents.json similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Contents.json diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Members/Contents.json similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Members/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Members/chat_team.imageset/Contents.json b/NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Members/chat_team.imageset/Contents.json similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Members/chat_team.imageset/Contents.json rename to NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Members/chat_team.imageset/Contents.json diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Members/chat_team.imageset/Group 117@2x.png b/NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Members/chat_team.imageset/Group 117@2x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Members/chat_team.imageset/Group 117@2x.png rename to NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Members/chat_team.imageset/Group 117@2x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Members/chat_team.imageset/Group 117@3x.png b/NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Members/chat_team.imageset/Group 117@3x.png similarity index 100% rename from NEChatUIKit/NEChatUIKit/Assets/NEChatUIKit.xcassets/Members/chat_team.imageset/Group 117@3x.png rename to NEChatUIKit/NEChatUIKit/Assets/NormalChatUIKit.xcassets/Members/chat_team.imageset/Group 117@3x.png diff --git a/NEChatUIKit/NEChatUIKit/Assets/en.lproj/Localizable.strings b/NEChatUIKit/NEChatUIKit/Assets/en.lproj/Localizable.strings index c187fba1..2437c7c9 100644 --- a/NEChatUIKit/NEChatUIKit/Assets/en.lproj/Localizable.strings +++ b/NEChatUIKit/NEChatUIKit/Assets/en.lproj/Localizable.strings @@ -5,7 +5,7 @@ //MAKR:common "ok"="OK"; -"send_to"="send to"; + //MAKR:message "send_picture"="get a picture"; "send_voice"="get a audio"; @@ -75,6 +75,7 @@ "pin_text_P2P"="pinned this message"; "pin_text_team"="pinned this message"; +"chat_setting"="chat setting"; "session_set_top"="sticky to top"; "message_remind"="open notification"; @@ -90,6 +91,7 @@ "operation_collection"="favorite"; "operation_delete"="delete"; "operation_recall"="recall"; +"withdrew_message" = "withdrew this message"; "message_has_be_withdrawn" = "message recalled"; "message_reedit" = "reedit"; "message_revoke_confim" = "Wether to recall this message"; @@ -101,11 +103,11 @@ "collection_success"="Favorite"; "no_permession"="No Permission"; "msg_reply"="reply"; -"msg_image"="picture"; -"msg_audio"="audio"; -"msg_video"="video"; -"msg_file"="file"; -"msg_location"="location"; +"msg_image"="picture message"; +"msg_audio"="audio message"; +"msg_video"="video message"; +"msg_file"="file message"; +"msg_location"="location message"; "msg_custom"="custom message"; "msg_unknown"="Unknown message type"; "message_read"="Reading Status"; @@ -124,7 +126,8 @@ "mdhm"="MM.dd HH:mm"; "ymdhm"="yyyy.MM.dd HH:mm"; -"chat_takePicture"="Capture video"; +"chat_takePicture"="Camera"; +"chat_photo"="Album"; "chat_rtc"="Audio and video call"; "chat_location"="Location"; "chat_file"="File"; @@ -136,7 +139,7 @@ "search_result_empty"="Not found"; "no_map_plugin"="Map module not integrated"; "location_not_auth"="The geographic location is not authorized. Please open it in the settings"; -"fileSize_over_limit"="Oops!File size limit."; +"fileSize_over_limit"="Oops!File size limit over XXXM."; "message_recalled"="message recalled"; @@ -146,10 +149,12 @@ "call_complete"="Talk time"; "call_canceled"="Call cancellation"; "call_rejected"="Rejected"; -"call_timeout"="No answer after timeout"; +"call_timeout"="Unanswered"; "call_busy"="The busy line is not answered"; "editable_time_expired"="Editable time has expired"; +"ravokable_time_expired"="Ravokable time has expired"; +"ravoked_failed"="Ravoked failed"; "message_not_found"="This message is gone"; "unkonw_pin_message"="unkonw message type"; @@ -162,3 +167,18 @@ "failed_operation"="Failed Operation"; "team_not_exist"="team not exist"; "unpin_failed"="Unpin failed"; + +"fun_hold_to_talk"="Hold to talk"; + +"release_to_send"="release to send"; +"release_to_cancel"="release to cancel"; + +"stop_record"="Recording will stop after %d"; + + +// MARK: Fun UI +"fun_chat_input_placeholder"="Enter what you want to say..."; + +"no_location"="Please select the location you want to send"; + +"delete_failed"="Delete failed"; diff --git a/NEChatUIKit/NEChatUIKit/Assets/fun_vioce_data.json b/NEChatUIKit/NEChatUIKit/Assets/fun_vioce_data.json new file mode 100644 index 00000000..9740d907 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Assets/fun_vioce_data.json @@ -0,0 +1 @@ +{"v":"5.6.3","fr":30,"ip":0,"op":68,"w":222,"h":60,"nm":"222x60","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"30","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[438.838,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,70]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,20]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"29","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[422.984,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,80]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,64]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,30]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,60]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,80]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,80]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"28","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[407.13,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,70]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,30]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,30]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,70]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,40]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"27","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[391.275,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,90]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,74]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,80]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,70]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,90]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"26","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[375.421,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,30]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,60]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,60]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,80]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,30]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"25","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[359.567,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,10]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14.01,"s":[8,34.976]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,10.051]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,19.97]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,10.04]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,19.951]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,-0.001]},"t":64,"s":[8,10.06]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"24","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[343.712,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,32.507]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,15.024]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,29.969]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,25.015]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,39.94]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,20.099]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,39.88]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"23","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[327.858,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,24.496]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,34.985]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,15.041]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,49.894]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,15.139]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,34.902]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,20.09]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"22","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[312.004,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,45]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,37.507]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,20.024]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,39.959]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,10.09]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,34.901]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,10.123]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,44.79]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"21","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[296.149,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,15]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,19.496]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,29.985]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,10.041]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,29.94]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,10.08]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,39.852]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,15.15]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"20","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[280.295,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,70]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,20]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"19","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[264.44,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,80]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,64]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,30]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,60]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,80]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,80]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"18","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[248.586,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,70]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,30]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,30]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,70]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,40]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"17","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[232.732,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,90]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,74]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,80]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,70]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,90]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"16","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[216.877,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,30]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,60]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,60]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,80]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,30]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"15","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[201.023,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,10]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14.01,"s":[8,34.976]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,10.051]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,19.97]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,10.04]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,19.951]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,-0.001]},"t":64,"s":[8,10.06]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"14","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[185.169,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,32.507]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,15.024]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,29.969]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,25.015]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,39.94]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,20.099]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,39.88]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"13","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[169.314,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,24.496]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,34.985]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,15.041]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,49.894]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,15.139]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,34.902]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,20.09]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"12","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[153.46,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,45]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,37.507]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,20.024]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,39.959]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,10.09]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,34.901]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,10.123]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,44.79]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"11","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[137.606,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,15]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,19.496]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,29.985]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,10.041]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,29.94]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,10.08]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,39.852]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,15.15]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"10","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[121.751,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,70]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,20]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"9","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[105.897,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,80]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,64]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,30]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,60]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,80]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,80]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"8","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[90.043,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,70]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,30]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,30]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,70]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,40]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":"7","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[74.188,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,90]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,74]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,80]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,70]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,90]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":25,"ty":4,"nm":"6","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[58.334,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,30]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,60]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,60]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,80]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,30]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":26,"ty":4,"nm":"5","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[42.48,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,10]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14.01,"s":[8,34.976]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,10.051]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,19.97]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,10.04]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,19.951]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,-0.001]},"t":64,"s":[8,10.06]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":27,"ty":4,"nm":"4","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[26.625,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,40]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,32.507]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,15.024]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,29.969]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,25.015]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,39.94]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,20.099]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,39.88]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"3","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[10.771,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,20]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,24.496]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,34.985]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,15.041]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,49.894]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,15.139]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,34.902]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,20.09]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":"2","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[454.693,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,45]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,37.507]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,20.024]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,39.959]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,10.09]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,34.901]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,10.123]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,44.79]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"1","sr":1,"ks":{"o":{"a":0,"k":40,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[470.547,49.842,0],"ix":2},"a":{"a":0,"k":[-30.264,-2.298,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":0,"s":[8,8]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":4,"s":[8,15]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":7,"s":[8,19.496]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":14,"s":[8,29.985]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":24,"s":[8,10.041]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":34,"s":[8,29.94]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":44,"s":[8,10.08]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.167,0.167],"y":[0,0.167]},"t":54,"s":[8,39.852]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.01,0.01],"y":[0,0]},"t":64,"s":[8,15.15]},{"t":69,"s":[8,8]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30.264,-2.298],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"player_visualization","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[111,30,0],"ix":2},"a":{"a":0,"k":[240,48,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":480,"h":96,"ip":0,"op":69,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/NEChatUIKit/NEChatUIKit/Assets/zh-Hans.lproj/Localizable.strings b/NEChatUIKit/NEChatUIKit/Assets/zh-Hans.lproj/Localizable.strings index 498907b4..8c57aa07 100644 --- a/NEChatUIKit/NEChatUIKit/Assets/zh-Hans.lproj/Localizable.strings +++ b/NEChatUIKit/NEChatUIKit/Assets/zh-Hans.lproj/Localizable.strings @@ -5,7 +5,6 @@ //MAKR:common "ok"="确认"; -"send_to"="发送给 "; //MAKR:message "send_picture"="发来了一张图片"; @@ -21,7 +20,7 @@ "take_photo"="拍照"; "select_from_album"="从相册选择"; "select_from_icloud"="从iCloud选择"; -"editing"="正在输入中..."; +"editing"="对方正在输入中..."; "downloading"="正在下载中..."; "read"="已读(0)"; "unread"="未读(0)"; @@ -33,7 +32,7 @@ "humans"="人"; "enter"="加入"; "unknown_system_message"="未知消息类型"; -"You"="你 "; +"You"="你"; "discussion_group"="群"; "group"="群"; "group_chat"="群聊"; @@ -74,6 +73,7 @@ "team_all_no_mute"="群禁言已关闭"; "pin_text_P2P"="标记了这条信息"; "pin_text_team"="标记了这条信息"; +"chat_setting"="聊天设置"; "session_set_top"="聊天置顶"; "message_remind"="开启消息提醒"; "open_soon"="暂未开放"; @@ -88,6 +88,7 @@ "operation_collection"="收藏"; "operation_delete"="删除"; "operation_recall"="撤回"; +"withdrew_message" = "撤回了一条消息"; "message_has_be_withdrawn" = "此消息已撤回"; "message_reedit" = "重新编辑"; "message_revoke_confim" = "确认要撤回该消息吗?"; @@ -99,13 +100,13 @@ "collection_success"="已收藏"; "no_permession"="暂无权限"; "msg_reply"="回复"; -"msg_image"="图片"; +"msg_image"="图片消息"; "msg_audio"="语音消息"; -"msg_video"="视频"; -"msg_file"="文件"; +"msg_video"="视频消息"; +"msg_file"="文件消息"; "msg_location"="地理位置"; -"msg_custom"="自定义"; -"msg_unknown"="未知消息类型"; +"msg_custom"="自定义消息"; +"msg_unknown"="未知消息体"; "message_read"="消息阅读状态"; "message_all_unread"="全部成员未读"; "user_select"="选择提醒"; @@ -123,6 +124,7 @@ "ymdhm"="yyyy年MM月dd日 HH:mm"; "chat_takePicture"="拍摄"; +"chat_photo"="相册"; "chat_rtc"="音视频通话"; "chat_location"="位置"; "chat_file"="文件"; @@ -134,9 +136,9 @@ "search_result_empty"="未找到你要搜的地址"; "no_map_plugin"="未集成地图模块"; "location_not_auth"="地理位置未授权,请去设置中开启"; -"fileSize_over_limit"="当前文件大小超出发送限制,请重新选择"; +"fileSize_over_limit"="当前文件大小超出XXXM发送限制,请重新选择"; -"message_recalled"="消息已撤回"; +"message_recalled"="此消息已撤回"; "video_call"="视频通话"; "audio_call"="音频通话"; @@ -144,10 +146,13 @@ "call_complete"="通话时长"; "call_canceled"="已取消"; "call_rejected"="已拒绝"; -"call_timeout"="超时未接听"; +"call_timeout"="未接听"; "call_busy"="忙线未接听"; +"remote_no_anwser"="对方未接听"; "editable_time_expired"="已超过可编辑时间"; +"ravokable_time_expired"="已超过时间无法撤回"; +"ravoked_failed"="撤回失败"; "message_not_found"="该消息已撤回或删除"; "unkonw_pin_message"="暂不支持消息类型"; @@ -160,3 +165,18 @@ "failed_operation"="操作失败"; "team_not_exist"="群组不存在"; "unpin_failed"="取消标记失败"; + +"fun_hold_to_talk"="按住 说话"; + +"release_to_send"="松开 发送"; +"release_to_cancel"="松开 取消"; + +"stop_record"="%d″ 后将停止录音"; + + +// MARK: Fun UI +"fun_chat_input_placeholder"="请输入您想说的..."; + +"no_location"="请选择你要发送的位置信息"; + +"delete_failed"="删除失败"; diff --git a/NEChatUIKit/NEChatUIKit/Classes/Base/BaseView/NEChatBaseCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Base/BaseView/NEChatBaseCell.swift index 8967e920..e5941978 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Base/BaseView/NEChatBaseCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Base/BaseView/NEChatBaseCell.swift @@ -4,6 +4,7 @@ // found in the LICENSE file. import UIKit +import NECommonKit @objcMembers open class NEChatBaseCell: UITableViewCell { @@ -16,7 +17,7 @@ open class NEChatBaseCell: UITableViewCell { fatalError("init(coder:) has not been implemented") } - public func uploadProgress(_ progress: Float) { + public func uploadProgress(byRight: Bool, _ progress: Float) { fatalError("override in sub class") } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Base/BaseViewController/ChatBaseViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/Base/BaseViewController/ChatBaseViewController.swift index 18a97e8c..a49a229d 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Base/BaseViewController/ChatBaseViewController.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Base/BaseViewController/ChatBaseViewController.swift @@ -5,12 +5,51 @@ import UIKit import NECoreKit +import NECommonUIKit + +@objcMembers +open class ChatBaseViewController: UIViewController, UIGestureRecognizerDelegate { + var topConstant: CGFloat = 0 + public let customNavigationView = NENavigationView() + + override open var title: String? { + get { + super.title + } + + set { + super.title = newValue + customNavigationView.navTitle.text = newValue + } + } -@objc open class ChatBaseViewController: UIViewController { override open func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = .white - setupBackUI() + navigationController?.interactivePopGestureRecognizer?.delegate = self + view.backgroundColor = NEKitChatConfig.shared.ui.chatViewBackground ?? .white + + if !NEKitChatConfig.shared.ui.showTitleBar { + navigationController?.isNavigationBarHidden = true + return + } + + if let useSystemNav = NEConfigManager.instance.getParameter(key: useSystemNav) as? Bool, useSystemNav { + navigationController?.isNavigationBarHidden = false + setupBackUI() + } else { + navigationController?.isNavigationBarHidden = true + topConstant = NEConstant.navigationAndStatusHeight + customNavigationView.translatesAutoresizingMaskIntoConstraints = false + customNavigationView.addBackButtonTarget(target: self, selector: #selector(backEvent)) + customNavigationView.addMoreButtonTarget(target: self, selector: #selector(toSetting)) + view.addSubview(customNavigationView) + NSLayoutConstraint.activate([ + customNavigationView.leftAnchor.constraint(equalTo: view.leftAnchor), + customNavigationView.rightAnchor.constraint(equalTo: view.rightAnchor), + customNavigationView.topAnchor.constraint(equalTo: view.topAnchor), + customNavigationView.heightAnchor.constraint(equalToConstant: topConstant), + ]) + } } private func setupBackUI() { @@ -21,9 +60,13 @@ import NECoreKit target: self, action: #selector(backEvent) ) + navigationController?.navigationBar.topItem?.backBarButtonItem = UIBarButtonItem() + navigationController?.navigationBar.topItem?.backBarButtonItem?.tintColor = .ne_darkText } - @objc func backEvent() { + func backEvent() { navigationController?.popViewController(animated: true) } + + func toSetting() {} } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/ChatViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/ChatViewController.swift index d6dbfd56..2bf134b0 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/ChatViewController.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/ChatViewController.swift @@ -15,53 +15,36 @@ import WebKit import NEChatKit import Photos -let leftCellTypeSufixx = "_left" -let rightCellTypeSufixx = "_right" - @objcMembers open class ChatViewController: ChatBaseViewController, UINavigationControllerDelegate, ChatInputViewDelegate, ChatViewModelDelegate, NIMMediaManagerDelegate, - MessageOperationViewDelegate, UIGestureRecognizerDelegate, UITableViewDataSource, + MessageOperationViewDelegate, UITableViewDataSource, UITableViewDelegate, UIDocumentPickerDelegate, UIDocumentInteractionControllerDelegate, CLLocationManagerDelegate, UITextViewDelegate { private let tag = "ChatViewController" - public var viewmodel: ChatViewModel - public var inputViewTopConstraint: NSLayoutConstraint? - public var tableViewBottomConstraint: NSLayoutConstraint? - public var menuView: ChatInputView = .init() - public var operationView: MessageOperationView? - private var playingCell: ChatAudioCell? + private let kCallKitDismissNoti = "kCallKitDismissNoti" + private let kCallKitShowNoti = "kCallKitShowNoti" + private var playingCell: ChatAudioCellProtocol? private var playingModel: MessageAudioModel? private var atUsers = [NSRange]() private var timer: Timer? - var replyView = ReplyView() - private var isFile = false - let interactionController = UIDocumentInteractionController() + private var isFile: Bool? // 是否以文件形式发送 private var needMarkReadMsgs = [NIMMessage]() private var isCurrentPage = true - var titleContent = "" - public var bottomExanpndHeight: CGFloat = 204 // 底部展开高度 - public var registerCellDic = [ - getLeftCellType(MessageType.text.rawValue): ChatTextLeftCell.self, - getRitghtCellType(MessageType.text.rawValue): ChatTextRightCell.self, - getLeftCellType(MessageType.rtcCallRecord.rawValue): ChatCallRecordLeftCell.self, - getRitghtCellType(MessageType.rtcCallRecord.rawValue): ChatCallRecordRightCell.self, - getLeftCellType(MessageType.audio.rawValue): ChatAudioLeftCell.self, - getRitghtCellType(MessageType.audio.rawValue): ChatAudioRightCell.self, - getLeftCellType(MessageType.image.rawValue): ChatImageLeftCell.self, - getRitghtCellType(MessageType.image.rawValue): ChatImageRightCell.self, - getLeftCellType(MessageType.revoke.rawValue): ChatRevokeLeftCell.self, - getRitghtCellType(MessageType.revoke.rawValue): ChatRevokeRightCell.self, - getLeftCellType(MessageType.video.rawValue): ChatVideoLeftCell.self, - getRitghtCellType(MessageType.video.rawValue): ChatVideoRightCell.self, - getLeftCellType(MessageType.file.rawValue): ChatFileLeftCell.self, - getRitghtCellType(MessageType.file.rawValue): ChatFileRightCell.self, - getLeftCellType(MessageType.reply.rawValue): ChatReplyLeftCell.self, - getRitghtCellType(MessageType.reply.rawValue): ChatReplyRightCell.self, - getLeftCellType(MessageType.location.rawValue): ChatLocationLeftCell.self, - getRitghtCellType(MessageType.location.rawValue): ChatLocationRightCell.self, - "\(MessageType.time.rawValue)": ChatTimeTableViewCell.self, - ] + var replyView = ReplyView() + public var titleContent = "" + let interactionController = UIDocumentInteractionController() + + public var viewmodel: ChatViewModel + public var inputViewTopConstraint: NSLayoutConstraint? + public var tableViewBottomConstraint: NSLayoutConstraint? + public var menuView: NEBaseChatInputView! + public var operationView: MessageOperationView? + public var operationCellFilter: [OperationType]? + public var bottomExanpndHeight: CGFloat = 204 // 底部展开高度 + public var normalInputHeight: CGFloat = 100 + public var normalOffset: CGFloat = 0 + public var registerCellDic = [String: UITableViewCell.Type]() public lazy var inputTopExtendView: UIView = { let content = UIView() @@ -87,6 +70,8 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel public init(session: NIMSession) { viewmodel = ChatViewModel(session: session, anchor: nil) super.init(nibName: nil, bundle: nil) + menuView = getMenuView() + NEKeyboardManager.shared.enable = false NEKeyboardManager.shared.enableAutoToolbar = false NIMSDK.shared().mediaManager.add(self) @@ -97,7 +82,7 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel fatalError("init(coder:) has not been implemented") } - override func backEvent() { + override open func backEvent() { super.backEvent() cleanDelegate() } @@ -112,7 +97,15 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } - public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { + func appEnterBackground() { + isCurrentPage = false + } + + func appEnterForegournd() { + isCurrentPage = true + } + + open func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { textView.typingAttributes = [NSAttributedString.Key.foregroundColor: UIColor.ne_darkText, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)] return true } @@ -122,11 +115,18 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel NEKeyboardManager.shared.enable = false NEKeyboardManager.shared.shouldResignOnTouchOutside = false isCurrentPage = true - navigationController?.isNavigationBarHidden = false markNeedReadMsg() getSessionInfo(session: viewmodel.session) - tableView.reloadData() clearAtRemind() + + weak var weakSelf = self + NEChatDetectNetworkTool.shareInstance.netWorkReachability { status in + if status == .notReachable, let networkView = weakSelf?.brokenNetworkView { + weakSelf?.view.addSubview(networkView) + } else { + weakSelf?.brokenNetworkView.removeFromSuperview() + } + } } override open func viewWillDisappear(_ animated: Bool) { @@ -163,18 +163,16 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel return } if let uid = model?.message?.from { - UserInfoProvider.shared.fetchUserInfo([uid]) { [weak self] error, users in - if let u = users?.first { - Router.shared.use( - ContactUserInfoPageRouter, - parameters: ["nav": self?.navigationController as Any, "user": u], - closure: nil - ) - } - } + Router.shared.use( + ContactUserInfoPageRouter, + parameters: ["nav": navigationController as Any, "uid": uid], + closure: nil + ) } } + open func setOperationItems(items: inout [OperationItem], model: MessageContentModel?) {} + /// 长按消息内容 /// - Parameters: /// - cell: 长按cell @@ -186,6 +184,19 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel return } + var filterItems = items + if let filter = operationCellFilter { + filterItems = items.filter { item in + if let type = item.type { + return !filter.contains(type) + } + return true + } + } + + // 供用户自定义 items + setOperationItems(items: &filterItems, model: model) + if model?.isRevoked == true { return } @@ -193,8 +204,8 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel viewmodel.operationModel = model // size - let w = items.count <= 5 ? 60.0 * Double(items.count) + 16.0 : 60.0 * 5 + 16.0 - let h = items.count <= 5 ? 56.0 + 16.0 : 56.0 * 2 + 16.0 + let w = filterItems.count <= 5 ? 60.0 * Double(filterItems.count) + 16.0 : 60.0 * 5 + 16.0 + let h = filterItems.count <= 5 ? 56.0 + 16.0 : 56.0 * 2 + 16.0 if let index = tableView.indexPath(for: cell) { let rectInTableView = tableView.rectForRow(at: index) @@ -213,31 +224,39 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel msg.isOutgoingMsg { frameX = kScreenWidth - w } - let frame = CGRect(x: frameX, y: operationY, width: w, height: h) + var frame = CGRect(x: frameX, y: operationY, width: w, height: h) + if frame.origin.y + h < tableView.frame.origin.y { + frame.origin.y = tableView.frame.origin.y + } else if frame.origin.y + h > view.frame.size.height { + frame.origin.y = tableView.frame.origin.y + tableView.frame.size.height - h + } + operationView = MessageOperationView(frame: frame) operationView!.delegate = self - operationView!.items = items + operationView!.items = filterItems view.addSubview(operationView!) } } // MARK: lazy Method - private lazy var brokenNetworkView: ChatBrokenNetworkView = { + public var networkToolHeight: CGFloat = 36 + + public lazy var brokenNetworkView: NEBrokenNetworkView = { let view = - ChatBrokenNetworkView(frame: CGRect(x: 0, y: kNavigationHeight + KStatusBarHeight, - width: kScreenWidth, height: 36)) + NEBrokenNetworkView(frame: CGRect(x: 0, y: kNavigationHeight + KStatusBarHeight, + width: kScreenWidth, height: networkToolHeight)) return view }() - lazy var tableView: UITableView = { + public lazy var tableView: UITableView = { let tableView = UITableView(frame: .zero, style: .plain) tableView.translatesAutoresizingMaskIntoConstraints = false tableView.separatorStyle = .none tableView.showsVerticalScrollIndicator = false tableView.delegate = self tableView.dataSource = self - tableView.backgroundColor = .white + tableView.backgroundColor = .clear tableView.mj_header = MJRefreshNormalHeader( refreshingTarget: self, refreshingAction: #selector(loadMoreData) @@ -248,8 +267,8 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel // MARK: UIGestureRecognizerDelegate - public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, - shouldReceive touch: UITouch) -> Bool { + open func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, + shouldReceive touch: UITouch) -> Bool { // print("touch.view:\(touch.view)") guard let view = touch.view else { return true @@ -268,12 +287,12 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel return true } - public func remoteUserEditing() { + open func remoteUserEditing() { title = chatLocalizable("editing") trigerEndTimer() } - public func remoteUserEndEditing() { + open func remoteUserEndEditing() { title = titleContent } @@ -307,29 +326,17 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel // MARK: objc 方法 - public func toSetting() { - if viewmodel.session.sessionType == .team { - Router.shared.use( - TeamSettingViewRouter, - parameters: ["nav": navigationController as Any, - "teamid": viewmodel.session.sessionId], - closure: nil - ) - } else if viewmodel.session.sessionType == .P2P { - let userSetting = UserSettingViewController() - userSetting.userId = viewmodel.session.sessionId - navigationController?.pushViewController(userSetting, animated: true) - } - } + override open func toSetting() {} // MARK: private 方法 open func commonUI() { title = viewmodel.session.sessionId + customNavigationView.bottomLine.isHidden = false view.addSubview(tableView) tableViewBottomConstraint = tableView.bottomAnchor.constraint( equalTo: view.bottomAnchor, - constant: -100 - inputTopExtendHeight + constant: -normalInputHeight - inputTopExtendHeight ) tableViewBottomConstraint?.isActive = true view.addSubview(navigationBarBottomExtendView) @@ -358,6 +365,7 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel navigationBarBottomExtendView.leftAnchor.constraint(equalTo: view.leftAnchor), navigationBarBottomExtendView.rightAnchor.constraint(equalTo: view.rightAnchor), ]) + NSLayoutConstraint.activate([ tableView.topAnchor.constraint( equalTo: navigationBarBottomExtendView.bottomAnchor, @@ -369,13 +377,8 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } tableView.register( - ChatBaseLeftCell.self, - forCellReuseIdentifier: "\(ChatBaseLeftCell.self)" - ) - - tableView.register( - ChatBaseRightCell.self, - forCellReuseIdentifier: "\(ChatBaseRightCell.self)" + NEBaseChatMessageCell.self, + forCellReuseIdentifier: "\(NEBaseChatMessageCell.self)" ) NEChatUIKitClient.instance.getRegisterCustomCell().forEach { (key: String, value: UITableViewCell.Type) in @@ -387,16 +390,15 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } viewmodel.delegate = self - menuView.backgroundColor = UIColor(hexString: "#EFF1F3") menuView.translatesAutoresizingMaskIntoConstraints = false menuView.delegate = self - menuView.chatAddMoreView.configData(data: NEChatUIKitClient.instance.getMoreActionData(sessionType: viewmodel.session.sessionType)) + expandMoreAction() view.addSubview(menuView) inputViewTopConstraint = menuView.topAnchor.constraint( equalTo: view.bottomAnchor, - constant: -100 + constant: -normalInputHeight ) NSLayoutConstraint.activate([ menuView.leftAnchor.constraint(equalTo: view.leftAnchor), @@ -414,35 +416,34 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel inputTopExtendView.rightAnchor.constraint(equalTo: view.rightAnchor), ]) - weak var weakSelf = self - NEChatDetectNetworkTool.shareInstance.netWorkReachability { status in - if status == .notReachable, let networkView = weakSelf?.brokenNetworkView { - weakSelf?.view.addSubview(networkView) - } else { - weakSelf?.brokenNetworkView.removeFromSuperview() - weakSelf?.viewmodel.refreshReceipts() - } + if NEKitChatConfig.shared.ui.showTitleBarRightIcon { + let image = NEKitChatConfig.shared.ui.titleBarRightRes ?? UIImage.ne_imageNamed(name: "three_point") + addRightAction(image, #selector(toSetting), self) + customNavigationView.setMoreButtonImage(image) + } else { + customNavigationView.moreButton.isHidden = true + } + + if let pan = navigationController?.interactivePopGestureRecognizer { + tableView.panGestureRecognizer.require(toFail: pan) } - addRightAction(UIImage.ne_imageNamed(name: "three_point"), #selector(toSetting), self) } func loadData() { - // title - getSessionInfo(session: viewmodel.session) weak var weakSelf = self - viewmodel.queryRoamMsgHasMoreTime_v2 { error, historyEnd, newEnd, models, index in + viewmodel.queryRoamMsgHasMoreTime_v2 { error, historyEnd, newEnd, index in NELog.infoLog( ModuleName + " " + self.tag, - desc: "CALLBACK queryRoamMsgHasMoreTime_v2 " + (error?.localizedDescription ?? "no error") + desc: #function + "CALLBACK queryRoamMsgHasMoreTime_v2 " + (error?.localizedDescription ?? "no error") ) - weakSelf?.viewmodel.refreshReceipts() - if let ms = models, ms.count > 0 { + + if let ms = weakSelf?.viewmodel.messages, ms.count > 0 { weakSelf?.tableView.reloadData() if weakSelf?.viewmodel.isHistoryChat == true { let indexPath = IndexPath(row: index, section: 0) print("queryRoamMsgHasMoreTime_v2 index : ", index) - weakSelf?.tableView.scrollToRow(at: indexPath, at: .none, animated: false) + weakSelf?.tableView.scrollToRow(at: indexPath, at: .middle, animated: false) if newEnd > 0 { weakSelf?.addBottomLoadMore() } @@ -459,6 +460,7 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } else if let err = error { weakSelf?.showToast(err.localizedDescription) } + weakSelf?.loadDataFinish() } } @@ -467,7 +469,7 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel viewmodel.dropDownRemoteRefresh { error, count, messages in NELog.infoLog( ModuleName + " " + self.tag, - desc: "CALLBACK dropDownRemoteRefresh " + (error?.localizedDescription ?? "no error") + desc: #function + "CALLBACK dropDownRemoteRefresh " + (error?.localizedDescription ?? "no error") ) print("dropDownRemoteRefresh messages count ", messages?.count as Any) @@ -490,13 +492,13 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel viewmodel.pullRemoteRefresh { error, count, datas in NELog.infoLog( ModuleName + " " + self.tag, - desc: "CALLBACK pullRemoteRefresh " + (error?.localizedDescription ?? "no error") + desc: #function + "CALLBACK pullRemoteRefresh " + (error?.localizedDescription ?? "no error") ) if count <= 0 { weakSelf?.removeBottomLoadMore() } else { weakSelf?.tableView.mj_footer?.endRefreshing() - weakSelf?.tableView.reloadData() + weakSelf?.didRefreshTable() } } } @@ -515,30 +517,38 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel selector: #selector(keyBoardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) + + NotificationCenter.default.addObserver(self, selector: #selector(didShowCallView), name: Notification.Name(kCallKitShowNoti), object: nil) + + NotificationCenter.default.addObserver(self, selector: #selector(appEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil) + + NotificationCenter.default.addObserver(self, selector: #selector(appEnterForegournd), name: UIApplication.willEnterForegroundNotification, object: nil) + let tap = UITapGestureRecognizer(target: self, action: #selector(viewTap)) tap.delegate = self + tap.cancelsTouchesInView = false view.addGestureRecognizer(tap) } - func addBottomLoadMore() { + open func addBottomLoadMore() { tableView.mj_footer = MJRefreshBackNormalFooter( refreshingTarget: self, refreshingAction: #selector(loadCloserToNowData) ) } - func removeBottomLoadMore() { + open func removeBottomLoadMore() { tableView.mj_footer?.endRefreshingWithNoMoreData() tableView.mj_footer = nil viewmodel.isHistoryChat = false // 转为普通聊天页面 } func markNeedReadMsg() { - if isCurrentPage { + if isCurrentPage, needMarkReadMsgs.count > 0 { viewmodel.markRead(messages: needMarkReadMsgs) { error in NELog.infoLog( ModuleName + " " + self.tag, - desc: "CALLBACK markRead " + (error?.localizedDescription ?? "no error") + desc: #function + "CALLBACK markRead " + (error?.localizedDescription ?? "no error") ) } needMarkReadMsgs = [NIMMessage]() @@ -547,33 +557,39 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel // MARK: 键盘通知相关操作 - func keyBoardWillShow(_ notification: Notification) { + open func keyBoardWillShow(_ notification: Notification) { if menuView.currentType != .text { return } + menuView.currentButton?.isSelected = false + + menuView.contentSubView?.isHidden = true let oldKeyboardRect = (notification .userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue + let keyboardRect = (notification .userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue + print("chat view key board size : ", keyboardRect) + layoutInputView(offset: keyboardRect.size.height) + weak var weakSelf = self + UIView.animate(withDuration: 0.25, animations: { + weakSelf?.view.layoutIfNeeded() + }) + // 键盘已经弹出 if oldKeyboardRect == keyboardRect { return } - print("chat view key board size : ", keyboardRect) - layoutInputView(offset: keyboardRect.size.height) - - UIView.animate(withDuration: 0.25, animations: { - self.view.layoutIfNeeded() - }) scrollTableViewToBottom() } - func keyBoardWillHide(_ notification: Notification) { + open func keyBoardWillHide(_ notification: Notification) { if menuView.currentType != .text { return } + menuView.currentButton?.isSelected = false // 解决点击operation点击无效问题 // if operationView?.superview != nil { // operationView?.removeFromSuperview() @@ -585,42 +601,51 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel print("self.viewmodel.messages.count\(viewmodel.messages.count)") print("self.tableView.numberOfRows(inSection: 0)\(tableView.numberOfRows(inSection: 0))") if viewmodel.messages.count > 0 { - let indexPath = IndexPath(row: viewmodel.messages.count - 1, section: 0) weak var weakSelf = self DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: DispatchWorkItem(block: { - weakSelf?.tableView.scrollToRow(at: indexPath, at: .bottom, animated: true) + if let row = weakSelf?.tableView.numberOfRows(inSection: 0) { + let indexPath = IndexPath(row: row - 1, section: 0) + weakSelf?.tableView.scrollToRow(at: indexPath, at: .bottom, animated: true) + } })) } } - public func layoutInputView(offset: CGFloat) { + open func layoutInputView(offset: CGFloat) { print("layoutInputView offset : ", offset) + print("normalOffset : ", normalOffset) + print("normalInputHeight : ", normalInputHeight) weak var weakSelf = self + let topValue = normalInputHeight - normalOffset + if offset == 0 { + menuView.contentSubView?.isHidden = true + menuView.currentButton?.isSelected = false + } UIView.animate(withDuration: 0.1, animations: { - weakSelf?.inputViewTopConstraint?.constant = -100 - offset - weakSelf?.tableViewBottomConstraint?.constant = -100 - offset - (weakSelf?.inputTopExtendHeight ?? 0) + weakSelf?.inputViewTopConstraint?.constant = -topValue - offset + weakSelf?.tableViewBottomConstraint?.constant = -topValue - offset - (weakSelf?.inputTopExtendHeight ?? 0) }) } // MARK: ChatInputViewDelegate - public func sendText(text: String?, attribute: NSAttributedString?) { + open func sendText(text: String?, attribute: NSAttributedString?) { guard let content = text, content.count > 0 else { return } let remoteExt = menuView.getRemoteExtension(attribute) menuView.cleartAtCache() + weak var weakSelf = self if viewmodel.isReplying, let msg = viewmodel.operationModel?.message { viewmodel.replyMessageWithoutThread(message: MessageUtils.textMessage(text: content, remoteExt: remoteExt), target: msg) { [weak self] error in NELog.infoLog( ModuleName + " " + (self?.tag ?? "ChatViewController"), - desc: "CALLBACK replyMessage " + (error?.localizedDescription ?? "no error") + desc: #function + "CALLBACK replyMessage " + (error?.localizedDescription ?? "no error") ) if error != nil { - self?.view.makeToast(error?.localizedDescription) + weakSelf?.view.makeToast(error?.localizedDescription) } else { - self?.viewmodel.isReplying = false - self?.replyView.removeFromSuperview() + weakSelf?.closeReply(button: nil) } } @@ -628,16 +653,16 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel viewmodel.sendTextMessage(text: content, remoteExt: remoteExt) { [weak self] error in NELog.infoLog( ModuleName + " " + (self?.tag ?? "ChatViewController"), - desc: "CALLBACK sendTextMessage " + (error?.localizedDescription ?? "no error") + desc: #function + "CALLBACK sendTextMessage " + (error?.localizedDescription ?? "no error") ) if error != nil { - self?.view.makeToast(error?.localizedDescription) + weakSelf?.view.makeToast(error?.localizedDescription) } } } } - public func didSelectMoreCell(cell: NEInputMoreCell) { + open func didSelectMoreCell(cell: NEInputMoreCell) { if let delegate = cell.cellData?.customDelegate as? AnyObject, let action = cell.cellData?.action { // 用户自定义更多面板按钮 _ = delegate.perform(action) @@ -670,16 +695,25 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel didToSearchLocationView() } else if let type = cell.cellData?.type, type == .takePicture { - showBottomVideoAction(self, false) + isFile = false + showTakePicture() } else if let type = cell.cellData?.type, type == .file { isFile = true - showBottomFileAction(self) + showFileAction() } else if let type = cell.cellData?.type, type == .rtc { showRtcCallAction() } else {} } - func showRtcCallAction() { + open func showTakePicture() { + showBottomVideoAction(self, false) + } + + open func showFileAction() { + showBottomFileAction(self) + } + + open func showRtcCallAction() { var param = [String: AnyObject]() param["remoteUserAccid"] = viewmodel.session.sessionId as AnyObject param["currentUserAccid"] = NIMSDK.shared().loginManager.currentAccount() as AnyObject @@ -716,7 +750,7 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } - public func textChanged(text: String) -> Bool { + open func textChanged(text: String) -> Bool { if text == "@" { // 做p2p类型判断 if viewmodel.session.sessionType == .P2P { @@ -733,7 +767,7 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } - public func textDelete(range: NSRange, text: String) -> Bool { + open func textDelete(range: NSRange, text: String) -> Bool { var index = -1 var removeRange: NSRange? for (i, r) in atUsers.enumerated() { @@ -785,7 +819,7 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel return true } - public func textFieldDidChange(_ textField: UITextView) { + open func textFieldDidChange(_ textField: UITextView) { if let text = textField.text { if text.count > 0 { viewmodel.sendInputTypingState() @@ -795,35 +829,43 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } - public func textFieldDidEndEditing(_ textField: UITextView) { + open func textFieldDidEndEditing(_ textField: UITextView) { viewmodel.sendInputTypingEndState() } - public func textFieldDidBeginEditing(_ textField: UITextView) { + open func textFieldDidBeginEditing(_ textField: UITextView) { if let count = textField.text?.count, count > 0 { viewmodel.sendInputTypingState() } } - public func willSelectItem(button: UIButton, index: Int) { + open func willSelectItem(button: UIButton?, index: Int) { operationView?.removeFromSuperview() - if index == 0 { - layoutInputView(offset: bottomExanpndHeight) - scrollTableViewToBottom() - } else if index == 1 { - layoutInputView(offset: bottomExanpndHeight) - scrollTableViewToBottom() - } else if index == 2 { - goPhotoAlbumWithVideo(self) + if button?.isSelected == true { + if index == 0 { + // 语音 + layoutInputView(offset: bottomExanpndHeight) + scrollTableViewToBottom() + } else if index == 1 { + // emoji + layoutInputView(offset: bottomExanpndHeight) + scrollTableViewToBottom() + } else if index == 2 { + // 相册 + isFile = false + goPhotoAlbumWithVideo(self) + } else if index == 3 { + // 更多 + layoutInputView(offset: bottomExanpndHeight) + scrollTableViewToBottom() + UIApplication.shared.keyWindow?.endEditing(true) + } } else { - // 更多 - layoutInputView(offset: bottomExanpndHeight) - scrollTableViewToBottom() - UIApplication.shared.keyWindow?.endEditing(true) + layoutInputView(offset: 0) } } - func showMenue(sourceView: UIView) { + open func showMenue(sourceView: UIView) { let alert = UIAlertController( title: chatLocalizable("choose"), message: nil, @@ -851,7 +893,7 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel present(alert, animated: true, completion: nil) } - func willSelectImage() { + open func willSelectImage() { let imagePickerVC = UIImagePickerController() imagePickerVC.delegate = self imagePickerVC.allowsEditing = false @@ -859,7 +901,7 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel present(imagePickerVC, animated: true) {} } - func takePhoto() { + open func takePhoto() { let imagePickerVC = UIImagePickerController() imagePickerVC.delegate = self imagePickerVC.allowsEditing = false @@ -867,16 +909,16 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel present(imagePickerVC, animated: true) {} } - func clearAtRemind() { + open func clearAtRemind() { let sessionId = viewmodel.session.sessionId let param = ["sessionId": sessionId] Router.shared.use("ClearAtMessageRemind", parameters: param, closure: nil) } - func sendMediaMessage(didFinishPickingMediaWithInfo info: [UIImagePickerController + open func sendMediaMessage(didFinishPickingMediaWithInfo info: [UIImagePickerController .InfoKey: Any]) { var imageName = "IMG_0001" - if isFile, + if isFile == true, let imgUrl = info[.referenceURL] as? URL { let fetchRes = PHAsset.fetchAssets(withALAssetURLs: [imgUrl], options: nil) let asset = fetchRes.firstObject @@ -889,14 +931,13 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel // video print("image picker video : url", url) weak var weakSelf = self - if isFile { + if isFile == true { copyFileToSend(url: url, displayName: imageName) - isFile = false } else { viewmodel.sendVideoMessage(url: url) { error in NELog.infoLog( - ModuleName + " " + self.tag, - desc: "CALLBACK sendVideoMessage " + (error?.localizedDescription ?? "no error") + ModuleName + " " + (weakSelf?.tag ?? "ChatViewController"), + desc: #function + "CALLBACK sendVideoMessage " + (error?.localizedDescription ?? "no error") ) if let err = error { weakSelf?.showToast(err.localizedDescription) @@ -911,29 +952,28 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel return } - if isFile, + if isFile == true, let imgData = image.pngData() { let imgSize_MB = Double(imgData.count) / 1e6 - print("@@# imgSize_MB: \(imgSize_MB) MB") + NELog.infoLog(ModuleName + " " + tag, desc: #function + "imgSize_MB: \(imgSize_MB) MB") if imgSize_MB > NEKitChatConfig.shared.ui.fileSizeLimit { - showToast(chatLocalizable("fileSize_over_limit")) + showToast(chatLocalizable("fileSize_over_limit").replacingOccurrences(of: "XXX", with: "\(NEKitChatConfig.shared.ui.fileSizeLimit)")) } else { viewmodel.sendFileMessage(data: imgData, displayName: imageName) { [weak self] error in NELog.infoLog( ModuleName + " " + (self?.tag ?? "ChatViewController"), - desc: "CALLBACK sendFileMessage \(imageName) by Data " + (error?.localizedDescription ?? "no error") + desc: #function + "CALLBACK sendFileMessage" + (error?.localizedDescription ?? "no error") ) if error != nil { self?.view.makeToast(error!.localizedDescription) } } } - isFile = false } else { viewmodel.sendImageMessage(image: image) { [weak self] error in NELog.infoLog( ModuleName + " " + (self?.tag ?? "ChatViewController"), - desc: "CALLBACK sendImageMessage " + (error?.localizedDescription ?? "no error") + desc: #function + "CALLBACK sendImageMessage " + (error?.localizedDescription ?? "no error") ) if error != nil { self?.view.makeToast(error?.localizedDescription) @@ -944,9 +984,9 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel // MARK: UIImagePickerControllerDelegate - public func imagePickerController(_ picker: UIImagePickerController, - didFinishPickingMediaWithInfo info: [UIImagePickerController - .InfoKey: Any]) { + open func imagePickerController(_ picker: UIImagePickerController, + didFinishPickingMediaWithInfo info: [UIImagePickerController + .InfoKey: Any]) { // picker.dismiss(animated: true, completion: nil) // sendMediaMessage(didFinishPickingMediaWithInfo: info) weak var weakSelf = self @@ -955,9 +995,8 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel }) } - public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { + open func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { picker.dismiss(animated: true) - isFile = false } // MARK: UIDocumentPickerDelegate @@ -966,29 +1005,27 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel let desPath = NSTemporaryDirectory() + "\(url.lastPathComponent)" let dirUrl = URL(fileURLWithPath: desPath) if !FileManager.default.fileExists(atPath: desPath) { - print("@@# file not exist:", desPath) + NELog.infoLog(ModuleName + " " + tag, desc: #function + "file not exist") do { try FileManager.default.copyItem(at: url, to: dirUrl) } catch { - print("❌ copyItem [\(desPath)] ERROR", error) + NELog.errorLog(ModuleName + " " + tag, desc: #function + "copyItem [\(desPath)] ERROR: \(error)") } } if FileManager.default.fileExists(atPath: desPath) { - print("@@# fileExists:", desPath) + NELog.infoLog(ModuleName + " " + tag, desc: #function + "fileExists") do { let fileAttributes = try FileManager.default.attributesOfItem(atPath: desPath) if let size_B = fileAttributes[FileAttributeKey.size] as? Double { - print("@@# size:\(size_B)B") let size_MB = size_B / 1e6 - print("@@# size:\(size_MB)MB") if size_MB > NEKitChatConfig.shared.ui.fileSizeLimit { - showToast(chatLocalizable("fileSize_over_limit")) + showToast(chatLocalizable("fileSize_over_limit").replacingOccurrences(of: "XXX", with: "\(NEKitChatConfig.shared.ui.fileSizeLimit)")) try? FileManager.default.removeItem(atPath: desPath) } else { viewmodel.sendFileMessage(filePath: desPath, displayName: displayName) { [weak self] error in NELog.infoLog( ModuleName + " " + (self?.tag ?? "ChatViewController"), - desc: "CALLBACK sendFileMessage " + (error?.localizedDescription ?? "no error") + desc: #function + "CALLBACK sendFileMessage " + (error?.localizedDescription ?? "no error") ) if error != nil { self?.view.makeToast(error!.localizedDescription) @@ -997,15 +1034,14 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } } catch { - print("@@#\(#function) get file size error:", error) + NELog.errorLog(ModuleName + " " + tag, desc: #function + "get file size error: \(error)") } } } - public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { + open func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { controller.dismiss(animated: true) guard let url = urls.first else { return } - print("@@# url", url) // 开始安全访问权限 let fileUrlAuthozied = url.startAccessingSecurityScopedResource() @@ -1017,46 +1053,44 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel // 停止安全访问权限 url.stopAccessingSecurityScopedResource() } else { - print("@@#❌ fileUrlAuthozied FAILED, url:", url) + NELog.errorLog(ModuleName + " " + tag, desc: #function + "fileUrlAuthozied FAILED") } - isFile = false } // MARK: UIDocumentInteractionControllerDelegate - public func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController { + open func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController { self } - public func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { + open func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { controller.dismiss(animated: true) - isFile = false } // MARK: ChatViewModelDelegate - public func didLeaveTeam() { + open func didLeaveTeam() { weak var weakSelf = self showSingleAlert(message: chatLocalizable("team_has_quit")) { weakSelf?.navigationController?.popViewController(animated: true) } } - public func didDismissTeam() { + open func didDismissTeam() { weak var weakSelf = self showSingleAlert(message: chatLocalizable("team_has_been_removed")) { weakSelf?.navigationController?.popViewController(animated: true) } } - public func onRecvMessages(_ messages: [NIMMessage]) { + open func onRecvMessages(_ messages: [NIMMessage]) { insertRows() if isCurrentPage, UIApplication.shared.applicationState == .active { viewmodel.markRead(messages: messages) { error in NELog.infoLog( ModuleName + " " + self.tag, - desc: "CALLBACK markRead " + (error?.localizedDescription ?? "no error") + desc: #function + "CALLBACK markRead " + (error?.localizedDescription ?? "no error") ) } } else { @@ -1064,13 +1098,13 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } - public func willSend(_ message: NIMMessage) { + open func willSend(_ message: NIMMessage) { insertRows() } - public func send(_ message: NIMMessage, progress: Float) {} + open func send(_ message: NIMMessage, progress: Float) {} - public func send(_ message: NIMMessage, didCompleteWithError error: Error?) { + open func send(_ message: NIMMessage, didCompleteWithError error: Error?) { if indexPathsWithMessags([message]).count > 0 { tableViewReloadIndexs(indexPathsWithMessags([message])) } @@ -1088,7 +1122,7 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel return indexPaths } - public func onDeleteMessage(_ message: NIMMessage, atIndexs: [IndexPath], reloadIndex: [IndexPath]) { + open func onDeleteMessage(_ message: NIMMessage, atIndexs: [IndexPath], reloadIndex: [IndexPath]) { if atIndexs.isEmpty { return } @@ -1098,40 +1132,33 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel })) } - public func updateDownloadProgress(_ message: NIMMessage, atIndex: IndexPath, progress: Float) { + open func updateDownloadProgress(_ message: NIMMessage, atIndex: IndexPath, progress: Float) { tableViewUpdateDownload(atIndex) } - public func onRevokeMessage(_ message: NIMMessage, atIndexs: [IndexPath]) { + open func onRevokeMessage(_ message: NIMMessage, atIndexs: [IndexPath]) { if atIndexs.isEmpty { return } - print("on revoke message at indexs :", atIndexs) -// weak var weakSelf = self -// viewmodel.saveRevokeMessage(message) { error in -// print("message id : ", message.messageId) -// if let err = error { -// NELog.infoLog(weakSelf?.className() ?? "chat view controller", desc: err.localizedDescription) -// } -// } + NELog.infoLog(className(), desc: "on revoke message at indexs \(atIndexs)") tableViewReloadIndexs(atIndexs) } - public func onAddMessagePin(_ message: NIMMessage, atIndexs: [IndexPath]) { + open func onAddMessagePin(_ message: NIMMessage, atIndexs: [IndexPath]) { tableViewReloadIndexs(atIndexs) } - public func onRemoveMessagePin(_ message: NIMMessage, atIndexs: [IndexPath]) { + open func onRemoveMessagePin(_ message: NIMMessage, atIndexs: [IndexPath]) { tableViewReloadIndexs(atIndexs) } - public func tableViewDeleteIndexs(_ indexs: [IndexPath]) { + open func tableViewDeleteIndexs(_ indexs: [IndexPath]) { tableView.beginUpdates() tableView.deleteRows(at: indexs, with: .none) tableView.endUpdates() } - public func tableViewReloadIndexs(_ indexs: [IndexPath]) { + open func tableViewReloadIndexs(_ indexs: [IndexPath]) { weak var weakSelf = self if #available(iOS 11.0, *) { tableView.performBatchUpdates { @@ -1144,22 +1171,30 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } - public func didReadedMessageIndexs() { - tableView.reloadData() + open func didReadedMessageIndexs() { + didRefreshTable() } - public func tableViewUpdateDownload(_ index: IndexPath) { - tableView.beginUpdates() - tableView.reloadRows(at: [index], with: .none) - tableView.endUpdates() + open func tableViewUpdateDownload(_ index: IndexPath) { + if #available(iOS 11.0, *) { + tableView.performBatchUpdates { + tableView.reloadRows(at: [index], with: .none) + } + } else { + tableView.beginUpdates() + tableView.reloadRows(at: [index], with: .none) + tableView.endUpdates() + } } - public func didRefreshTable() { - tableView.reloadData() + open func didRefreshTable() { + DispatchQueue.main.async { [weak self] in + self?.tableView.reloadData() + } } // record audio - public func startRecord() { + open func startRecord() { let dur = 60.0 if NEAuthManager.hasAudioAuthoriztion() { NIMSDK.shared().mediaManager.record(forDuration: dur) @@ -1175,11 +1210,11 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } - public func moveOutView() {} + open func moveOutView() {} - public func moveInView() {} + open func moveInView() {} - public func endRecord(insideView: Bool) { + open func endRecord(insideView: Bool) { print("[record] stop:\(insideView)") if insideView { // send @@ -1190,7 +1225,7 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } - func viewTap(tap: UITapGestureRecognizer) { + open func viewTap(tap: UITapGestureRecognizer) { if let opeView = operationView, view.subviews.contains(opeView) { opeView.removeFromSuperview() @@ -1206,31 +1241,40 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel // MARK: audio play - private func startPlay(cell: ChatAudioCell?, model: MessageAudioModel?) { - guard let audio = model?.message?.messageObject as? NIMAudioObject else { + func startPlaying(audio: NIMAudioObject, isSend: Bool) { + playingCell?.startAnimation(byRight: isSend) + if let url = audio.path { + if viewmodel.getHandSetEnable() == true { + NIMSDK.shared().mediaManager.switch(.receiver) + } else { + NIMSDK.shared().mediaManager.switch(.speaker) + } + NIMSDK.shared().mediaManager.play(url) + } + } + + private func startPlay(cell: ChatAudioCellProtocol?, model: MessageAudioModel?) { + guard let audio = model?.message?.messageObject as? NIMAudioObject, + let isSend = model?.message?.isOutgoingMsg else { return } - if NIMSDK.shared().mediaManager.isPlaying() { - stopPlay() + if playingModel == model { + if NIMSDK.shared().mediaManager.isPlaying() { + stopPlay() + } else { + startPlaying(audio: audio, isSend: isSend) + } } else { stopPlay() playingCell = cell playingModel = model - playingCell?.startAnimation() - if let url = audio.path { - if viewmodel.getHandSetEnable() == true { - NIMSDK.shared().mediaManager.switch(.receiver) - } else { - NIMSDK.shared().mediaManager.switch(.speaker) - } - NIMSDK.shared().mediaManager.play(url) - } + startPlaying(audio: audio, isSend: isSend) } } - private func stopPlay() { + public func stopPlay() { if NIMSDK.shared().mediaManager.isPlaying() { - playingCell?.startAnimation() + playingCell?.startAnimation(byRight: playingModel?.message?.isOutgoingMsg ?? true) NIMSDK.shared().mediaManager.stopPlay() } } @@ -1245,54 +1289,54 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel // MARK: NIMMediaManagerDelegate // play - public func playAudio(_ filePath: String, didBeganWithError error: Error?) { + open func playAudio(_ filePath: String, didBeganWithError error: Error?) { print(#function + "\(error)") if let e = error { showToast(e.localizedDescription) // stop - playingCell?.stopAnimation() + playingCell?.stopAnimation(byRight: playingModel?.message?.isOutgoingMsg ?? true) playingModel?.isPlaying = false } } - public func playAudio(_ filePath: String, didCompletedWithError error: Error?) { + open func playAudio(_ filePath: String, didCompletedWithError error: Error?) { print(#function + "\(error)") if let e = error { showToast(e.localizedDescription) } // stop - playingCell?.stopAnimation() + playingCell?.stopAnimation(byRight: playingModel?.message?.isOutgoingMsg ?? true) playingModel?.isPlaying = false } - public func stopPlayAudio(_ filePath: String, didCompletedWithError error: Error?) { + open func stopPlayAudio(_ filePath: String, didCompletedWithError error: Error?) { print(#function + "\(error)") if let e = error { showToast(e.localizedDescription) } - playingCell?.stopAnimation() + playingCell?.stopAnimation(byRight: playingModel?.message?.isOutgoingMsg ?? true) playingModel?.isPlaying = false } - public func playAudio(_ filePath: String, progress value: Float) {} + open func playAudio(_ filePath: String, progress value: Float) {} - public func playAudioInterruptionEnd() { + open func playAudioInterruptionEnd() { print(#function) } - public func playAudioInterruptionBegin() { + open func playAudioInterruptionBegin() { print(#function) // stop play - playingCell?.stopAnimation() + playingCell?.stopAnimation(byRight: playingModel?.message?.isOutgoingMsg ?? true) playingModel?.isPlaying = false } // record - public func recordAudio(_ filePath: String?, didBeganWithError error: Error?) { + open func recordAudio(_ filePath: String?, didBeganWithError error: Error?) { print("[record] sdk Began error:\(error)") } - public func recordAudio(_ filePath: String?, didCompletedWithError error: Error?) { + open func recordAudio(_ filePath: String?, didCompletedWithError error: Error?) { print("[record] sdk Completed error:\(error)") menuView.stopRecordAnimation() guard let fp = filePath else { @@ -1306,7 +1350,7 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel viewmodel.sendAudioMessage(filePath: fp) { error in NELog.infoLog( ModuleName + " " + self.tag, - desc: "CALLBACK sendAudioMessage " + (error?.localizedDescription ?? "no error") + desc: #function + "CALLBACK sendAudioMessage " + (error?.localizedDescription ?? "no error") ) if let e = error { self.showToast(e.localizedDescription) @@ -1317,13 +1361,13 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } - public func recordAudioDidCancelled() { + open func recordAudioDidCancelled() { print("[record] sdk cancel") } - public func recordAudioProgress(_ currentTime: TimeInterval) {} + open func recordAudioProgress(_ currentTime: TimeInterval) {} - public func recordAudioInterruptionBegin() { + open func recordAudioInterruptionBegin() { print(#function) } @@ -1352,16 +1396,30 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } if !indexs.isEmpty { - tableView.insertRows(at: indexs, with: .none) - tableView.scrollToRow( - at: IndexPath(row: viewmodel.messages.count - 1, section: 0), - at: .bottom, - animated: false - ) + if #available(iOS 11.0, *) { + self.tableView.performBatchUpdates { + self.tableView.insertRows(at: indexs, with: .bottom) + } completion: { finished in + self.tableView.scrollToRow( + at: IndexPath(row: self.viewmodel.messages.count - 1, section: 0), + at: .bottom, + animated: false + ) + } + } else { + tableView.insertRows(at: indexs, with: .bottom) + DispatchQueue.main.asyncAfter(deadline: .now() + 0.15, execute: DispatchWorkItem(block: { + self.tableView.scrollToRow( + at: IndexPath(row: self.viewmodel.messages.count - 1, section: 0), + at: .bottom, + animated: false + ) + })) + } } } - func addToAtUsers(addText: String, isReply: Bool = false, accid: String, _ isLongPress: Bool = false) { + open func addToAtUsers(addText: String, isReply: Bool = false, accid: String, _ isLongPress: Bool = false) { if let font = menuView.textView.font { let mutaString = NSMutableAttributedString(attributedString: menuView.textView.attributedText) let atString = NSAttributedString(string: addText, attributes: [NSAttributedString.Key.foregroundColor: UIColor.ne_blueText, NSAttributedString.Key.font: font]) @@ -1403,8 +1461,12 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } + func getUserSelectVC() -> NEBaseSelectUserViewController { + NEBaseSelectUserViewController(sessionId: viewmodel.session.sessionId, showSelf: false) + } + private func showUserSelectVC(text: String) { - let selectVC = SelectUserViewController(sessionId: viewmodel.session.sessionId, showSelf: false) + let selectVC = getUserSelectVC() selectVC.modalPresentationStyle = .formSheet selectVC.selectedBlock = { [weak self] index, model in var addText = "" @@ -1428,7 +1490,7 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel // MARK: MessageOperationViewDelegate - public func didSelectedItem(item: OperationItem) { + open func didSelectedItem(item: OperationItem) { switch item.type { case .copy: copyMessage() @@ -1447,13 +1509,13 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel case .removePin: removePinMessage() default: - doNothing() + customOperation() } } - private func doNothing() {} + open func customOperation() {} - private func copyMessage() { + open func copyMessage() { if let model = viewmodel.operationModel as? MessageTextModel, let text = model.message?.text { let pasteboard = UIPasteboard.general @@ -1462,18 +1524,22 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } - private func deleteMessage() { + open func deleteMessage() { showAlert(message: chatLocalizable("message_delete_comfirm")) { if let message = self.viewmodel.operationModel?.message { - self.viewmodel.deleteMessage(message: message) + self.viewmodel.deleteMessage(message: message) { error in + if error != nil { + self.showToast(chatLocalizable("delete_failed")) + } + } } } } - private func showReplyMessageView(isReEdit: Bool = false) { + open func showReplyMessageView(isReEdit: Bool = false) { viewmodel.isReplying = true view.addSubview(replyView) - replyView.closeButton.addTarget(self, action: #selector(cancelReply), for: .touchUpInside) + replyView.closeButton.addTarget(self, action: #selector(closeReply), for: .touchUpInside) replyView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ replyView.leadingAnchor.constraint(equalTo: menuView.leadingAnchor), @@ -1522,7 +1588,7 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel case .custom: text += "[\(chatLocalizable("msg_custom"))]" default: - text += "" + text += "[\(chatLocalizable("msg_unknown"))]" } replyView.textLabel.attributedText = NEEmotionTool.getAttWithStr(str: text, font: replyView.textLabel.font, @@ -1532,12 +1598,12 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } - @objc private func cancelReply(button: UIButton) { + open func closeReply(button: UIButton?) { replyView.removeFromSuperview() viewmodel.isReplying = false } - private func recallMessage() { + open func recallMessage() { weak var weakSelf = self showAlert(message: chatLocalizable("message_revoke_confim")) { if let message = weakSelf?.viewmodel.operationModel?.message { @@ -1550,10 +1616,16 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel weakSelf?.viewmodel.revokeMessage(message: message) { error in NELog.infoLog( ModuleName + " " + (weakSelf?.tag ?? ""), - desc: "CALLBACK revokeMessage " + (error?.localizedDescription ?? "no error") + desc: #function + "CALLBACK revokeMessage " + (error?.localizedDescription ?? "no error") ) - if error != nil { - weakSelf?.showToast(error!.localizedDescription) + if let err = error as? NSError { + if err.code == 408 { + weakSelf?.showToast(chatLocalizable("ravoked_failed")) + } else if err.code == 508 { + weakSelf?.showToast(chatLocalizable("ravokable_time_expired")) + } else { + weakSelf?.showToast(err.localizedDescription) + } } else { // 自己撤回成功 & 收到对方撤回 都会走回调方法 onRevokeMessage // 撤回成功的逻辑统一在代理方法中处理 onRevokeMessage @@ -1569,12 +1641,12 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } - private func collectionMessage() { + open func collectionMessage() { if let message = viewmodel.operationModel?.message { viewmodel.addColletion(message) { error, info in NELog.infoLog( ModuleName + " " + self.tag, - desc: "CALLBACK addColletion " + (error?.localizedDescription ?? "no error") + desc: #function + "CALLBACK addColletion " + (error?.localizedDescription ?? "no error") ) if error != nil { self.showToast(error!.localizedDescription) @@ -1585,84 +1657,96 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } - private func forwardMessage() { - if let message = viewmodel.operationModel?.message { - weak var weakSelf = self - let userAction = UIAlertAction(title: chatLocalizable("contact_user"), - style: .default) { action in + open func getForwardAlertController() -> NEBaseForwardAlertViewController { + NEBaseForwardAlertViewController() + } - Router.shared.register(ContactSelectedUsersRouter) { param in - print("user setting accids : ", param) - var items = [ForwardItem]() - - if let users = param["im_user"] as? [NIMUser] { - users.forEach { user in - let item = ForwardItem() - item.uid = user.userId - item.avatar = user.userInfo?.avatarUrl - item.name = user.userInfo?.nickName - items.append(item) - } + func forwardMessageToUser(message: NIMMessage) { + weak var weakSelf = self + Router.shared.register(ContactSelectedUsersRouter) { param in + print("user setting accids : ", param) + var items = [ForwardItem]() + + if let users = param["im_user"] as? [NIMUser] { + users.forEach { user in + let item = ForwardItem() + item.uid = user.userId + item.avatar = user.userInfo?.avatarUrl + item.name = user.userInfo?.nickName + items.append(item) + } - let forwardAlert = ForwardAlertViewController() - forwardAlert.setItems(items) - if let senderName = message.senderName { - forwardAlert.context = senderName - } - weakSelf?.addChild(forwardAlert) - weakSelf?.view.addSubview(forwardAlert.view) + let forwardAlert = weakSelf?.getForwardAlertController() ?? NEBaseForwardAlertViewController() + forwardAlert.setItems(items) + if let senderName = message.senderName { + forwardAlert.context = senderName + } + weakSelf?.addChild(forwardAlert) + weakSelf?.view.addSubview(forwardAlert.view) - DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: DispatchWorkItem(block: { - UIApplication.shared.keyWindow?.endEditing(true) - })) + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: DispatchWorkItem(block: { + UIApplication.shared.keyWindow?.endEditing(true) + })) - forwardAlert.sureBlock = { - print("sure click ") - weakSelf?.viewmodel.forwardUserMessage(message, users) - } - } + forwardAlert.sureBlock = { + print("sure click ") + weakSelf?.viewmodel.forwardUserMessage(message, users) } - var param = [String: Any]() - param["nav"] = weakSelf?.navigationController as Any - param["limit"] = 6 - if let session = weakSelf?.viewmodel.session, session.sessionType == .P2P { - var filters = Set() - filters.insert(session.sessionId) - param["filters"] = filters + } + } + var param = [String: Any]() + param["nav"] = weakSelf?.navigationController as Any + param["limit"] = 6 + if let session = weakSelf?.viewmodel.session, session.sessionType == .P2P { + var filters = Set() + filters.insert(session.sessionId) + param["filters"] = filters + } + Router.shared.use(ContactUserSelectRouter, parameters: param, closure: nil) + } + + func forwardMessageToTeam(message: NIMMessage) { + weak var weakSelf = self + Router.shared.register(ContactTeamDataRouter) { param in + if let team = param["team"] as? NIMTeam { + let item = ForwardItem() + item.avatar = team.avatarUrl + item.name = team.getShowName() + item.uid = team.teamId + + let forwardAlert = weakSelf!.getForwardAlertController() + forwardAlert.setItems([item]) + if let senderName = message.senderName { + forwardAlert.context = senderName } - Router.shared.use(ContactUserSelectRouter, parameters: param, closure: nil) + forwardAlert.sureBlock = { + weakSelf?.viewmodel.forwardTeamMessage(message, team) + } + weakSelf?.addChild(forwardAlert) + weakSelf?.view.addSubview(forwardAlert.view) + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: DispatchWorkItem(block: { + UIApplication.shared.keyWindow?.endEditing(true) + })) } + } - let teamAction = UIAlertAction(title: chatLocalizable("team"), style: .default) { action in + Router.shared.use( + ContactTeamListRouter, + parameters: ["nav": weakSelf?.navigationController as Any], + closure: nil + ) + } - Router.shared.register(ContactTeamDataRouter) { param in - if let team = param["team"] as? NIMTeam { - let item = ForwardItem() - item.avatar = team.avatarUrl - item.name = team.getShowName() - item.uid = team.teamId - - let forwardAlert = ForwardAlertViewController() - forwardAlert.setItems([item]) - if let senderName = message.senderName { - forwardAlert.context = senderName - } - forwardAlert.sureBlock = { - weakSelf?.viewmodel.forwardTeamMessage(message, team) - } - weakSelf?.addChild(forwardAlert) - weakSelf?.view.addSubview(forwardAlert.view) - DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: DispatchWorkItem(block: { - UIApplication.shared.keyWindow?.endEditing(true) - })) - } - } + open func forwardMessage() { + if let message = viewmodel.operationModel?.message { + weak var weakSelf = self + let userAction = UIAlertAction(title: chatLocalizable("contact_user"), + style: .default) { action in + weakSelf?.forwardMessageToUser(message: message) + } - Router.shared.use( - ContactTeamListRouter, - parameters: ["nav": weakSelf?.navigationController as Any], - closure: nil - ) + let teamAction = UIAlertAction(title: chatLocalizable("team"), style: .default) { action in + weakSelf?.forwardMessageToTeam(message: message) } let cancelAction = UIAlertAction(title: chatLocalizable("cancel"), @@ -1673,7 +1757,7 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } - private func pinMessage() { + open func pinMessage() { guard let optModel = viewmodel.operationModel, !optModel.isPined else { return } @@ -1684,13 +1768,13 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel viewmodel.pinMessage(message) { [weak self] error, pinItem, index in NELog.infoLog( ModuleName + " " + (self?.tag ?? "ChatViewController"), - desc: "CALLBACK pinMessage " + (error?.localizedDescription ?? "no error") + desc: #function + "CALLBACK pinMessage " + (error?.localizedDescription ?? "no error") ) if let err = error as? NSError { if err.code == 408 { - self?.view.makeToast(chatLocalizable("failed_operation")) + self?.view.makeToast(commonLocalizable("network_error"), position: .center) } else { - self?.view.makeToast(error?.localizedDescription) + self?.view.makeToast(error?.localizedDescription, position: .center) } } else { // update UI @@ -1702,7 +1786,7 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } - private func removePinMessage() { + open func removePinMessage() { guard let optModel = viewmodel.operationModel, optModel.isPined else { return } @@ -1711,15 +1795,15 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel viewmodel.removePinMessage(message) { [weak self] error, pinItem, index in NELog.infoLog( ModuleName + " " + (self?.tag ?? "ChatViewController"), - desc: "CALLBACK removePinMessage " + (error?.localizedDescription ?? "no error") + desc: #function + "CALLBACK removePinMessage " + (error?.localizedDescription ?? "no error") ) if let err = error as? NSError { if err.code == 404 { return } else if err.code == 408 { - self?.view.makeToast(chatLocalizable("failed_operation")) + self?.view.makeToast(commonLocalizable("network_error"), position: .center) } else { - self?.view.makeToast(error?.localizedDescription) + self?.view.makeToast(error?.localizedDescription, position: .center) } } else { // update UI @@ -1733,124 +1817,75 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel // MARK: UITableViewDataSource, UITableViewDelegate - public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { let count = viewmodel.messages.count print("numberOfRowsInSection count : ", count) return count } - public func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { + open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { let model = viewmodel.messages[indexPath.row] var reuseId = "" - if let isSend = model.message?.isOutgoingMsg, isSend { - if model.replyedModel?.isReplay == true { - reuseId = ChatViewController.getRitghtCellType(MessageType.reply.rawValue) - } else { - let key = ChatViewController.getRitghtCellType(model.type.rawValue) - if model.type == .custom, let object = model.message?.messageObject as? NIMCustomObject, let custom = object.attachment as? NECustomAttachmentProtocol { - if registerCellDic["\(custom.customType)"] != nil { - reuseId = "\(custom.customType)" - } else { - reuseId = "\(ChatBaseRightCell.self)" - } - } else if model.type == .time || model.type == .notification || model.type == .tip { - reuseId = "\(MessageType.time.rawValue)" - } else if registerCellDic[key] != nil { - reuseId = key + if model.replyedModel?.isReplay == true, + model.isRevoked == false { + reuseId = "\(MessageType.reply.rawValue)" + } else { + let key = "\(model.type.rawValue)" + if model.type == .custom, let object = model.message?.messageObject as? NIMCustomObject, let custom = object.attachment as? NECustomAttachmentProtocol { + if registerCellDic["\(custom.customType)"] != nil { + reuseId = "\(custom.customType)" } else { - reuseId = "\(ChatBaseRightCell.self)" + reuseId = "\(NEBaseChatMessageCell.self)" } + } else if model.type == .time || model.type == .notification || model.type == .tip { + reuseId = "\(MessageType.time.rawValue)" + } else if registerCellDic[key] != nil { + reuseId = key + } else { + reuseId = "\(NEBaseChatMessageCell.self)" } + } - let cell = tableView.dequeueReusableCell(withIdentifier: reuseId, for: indexPath) - if let c = cell as? ChatTimeTableViewCell { - if let m = model as? MessageTipsModel { - c.setModel(m) - } - return c - } else if let c = cell as? ChatBaseRightCell { - c.delegate = self - if let m = model as? MessageContentModel { - c.setModel(m) - } - - if let audioCell = cell as? ChatAudioRightCell, - let m = model as? MessageAudioModel, - m.message?.messageId == playingModel?.message?.messageId { - if NIMSDK.shared().mediaManager.isPlaying() { - playingCell = audioCell - playingCell?.startAnimation() - } - } - - return c - } else if let c = cell as? NEChatBaseCell, let m = model as? MessageContentModel { + let cell = tableView.dequeueReusableCell(withIdentifier: reuseId, for: indexPath) + if let c = cell as? NEBaseChatMessageTipCell { + if let m = model as? MessageTipsModel { + m.resetNotiText() c.setModel(m) - return cell - } else { - return ChatBaseRightCell() } - } else { - if model.replyedModel?.isReplay == true { - reuseId = ChatViewController.getLeftCellType(MessageType.reply.rawValue) - } else { - let key = ChatViewController.getLeftCellType(model.type.rawValue) - if model.type == .custom, let object = model.message?.messageObject as? NIMCustomObject, let custom = object.attachment as? NECustomAttachmentProtocol { - if registerCellDic["\(custom.customType)"] != nil { - reuseId = "\(custom.customType)" - } else { - reuseId = "\(ChatBaseLeftCell.self)" - } - } else if model.type == .time || model.type == .notification || model.type == .tip { - reuseId = "\(MessageType.time.rawValue)" - } else if registerCellDic[key] != nil { - reuseId = key - } else { - reuseId = "\(ChatBaseLeftCell.self)" - } - } - - let cell = tableView.dequeueReusableCell(withIdentifier: reuseId, for: indexPath) - if let c = cell as? ChatTimeTableViewCell { - if let m = model as? MessageTipsModel { - c.setModel(m) - } - return c - } else if let c = cell as? ChatBaseLeftCell { - c.delegate = self - + return c + } else if let c = cell as? NEBaseChatMessageCell { + c.delegate = self + if let m = model as? MessageContentModel { // 更新好友昵称、头像 - if let m = model as? MessageContentModel { - if let from = model.message?.from, - let user = viewmodel.newUserInfoDic[from] { - if let uid = user.userId, - viewmodel.session.sessionType == .team || - viewmodel.session.sessionType == .superTeam { - m.fullName = viewmodel.getShowName(userId: uid, teamId: viewmodel.session.sessionId) - m.shortName = viewmodel.getShortName(name: user.showName(false) ?? "", length: 2) - } - m.avatar = user.userInfo?.avatarUrl + if let from = model.message?.from, + let user = viewmodel.newUserInfoDic[from] { + if let uid = user.userId, + viewmodel.session.sessionType == .team || + viewmodel.session.sessionType == .superTeam { + m.fullName = viewmodel.getShowName(userId: uid, teamId: viewmodel.session.sessionId) + m.shortName = viewmodel.getShortName(name: user.showName(false) ?? "", length: 2) } - c.setModel(m) + m.avatar = user.userInfo?.avatarUrl } + c.setModel(m) + } - if let audioCell = cell as? ChatAudioLeftCell, - let m = model as? MessageAudioModel, - m.message?.messageId == playingModel?.message?.messageId { - if NIMSDK.shared().mediaManager.isPlaying() { - playingCell = audioCell - playingCell?.startAnimation() - } + if let audioCell = cell as? ChatAudioCellProtocol, + let m = model as? MessageAudioModel, + m.message?.messageId == playingModel?.message?.messageId { + if NIMSDK.shared().mediaManager.isPlaying() { + playingCell = audioCell + playingCell?.startAnimation(byRight: true) } - - return c - } else if let c = cell as? NEChatBaseCell, let m = model as? MessageContentModel { - c.setModel(m) - return cell - } else { - return ChatBaseLeftCell() } + + return c + } else if let c = cell as? NEChatBaseCell, let m = model as? MessageContentModel { + c.setModel(m) + return cell + } else { + return NEBaseChatMessageCell() } } @@ -1859,38 +1894,38 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel if menuView.textView.isFirstResponder { menuView.textView.resignFirstResponder() } else { - layoutInputView(offset: 0) +// layoutInputView(offset: 0) } } - public func tableView(_ tableView: UITableView, - heightForRowAt indexPath: IndexPath) -> CGFloat { + open func tableView(_ tableView: UITableView, + heightForRowAt indexPath: IndexPath) -> CGFloat { let m = viewmodel.messages[indexPath.row] if m.type == .custom { if let object = m.message?.messageObject as? NIMCustomObject, let custom = object.attachment as? NECustomAttachmentProtocol { return custom.cellHeight } } - return CGFloat(m.height) + return m.cellHeight() } - public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + open func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { 0 } - public func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat { + open func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat { 0 } // MARK: UIScrollViewDelegate - public func scrollViewDidScroll(_ scrollView: UIScrollView) { + public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { operationView?.removeFromSuperview() } // MARK: CLLocationManagerDelegate -// public func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { +// open func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { // if #available(iOS 14.0, *) { // if manager.authorizationStatus == .authorizedAlways || manager.authorizationStatus == .authorizedWhenInUse { // didToSearchLocationView() @@ -1902,7 +1937,10 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel // } // } - public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { + open func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { + if isCurrentPage == false { + return + } if #available(iOS 14.0, *) { if manager.authorizationStatus == .authorizedAlways || manager.authorizationStatus == .authorizedWhenInUse { didToSearchLocationView() @@ -1914,43 +1952,23 @@ open class ChatViewController: ChatBaseViewController, UINavigationControllerDel } } - public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {} + open func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {} - public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {} + open func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {} -// public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { +// open func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { // print(error) // } -} - -// MARK: ChatBaseCellDelegate -extension ChatViewController: ChatBaseCellDelegate { - public func didLongPressAvatar(_ cell: UITableViewCell, _ model: MessageContentModel?) { - print("didLongPressAvatar") - if viewmodel.session.sessionType == .P2P { - return - } - var addText = "" - var accid = "" - - if let m = model, let from = m.message?.from { - accid = from - addText += viewmodel.getShowName(userId: from, teamId: viewmodel.session.sessionId, false) - } - - addText = "@" + addText + "" - - addToAtUsers(addText: addText, accid: accid, true) + func getTextViewController(text: String) -> TextViewController { + let textViewController = TextViewController(content: text) + textViewController.view.backgroundColor = .white + return textViewController } - public func didTapAvatarView(_ cell: UITableViewCell, _ model: MessageContentModel?) { - didTapHeadPortrait(model: model) - } - - func didTapMessage(_ cell: UITableViewCell?, _ model: MessageContentModel?, _ replyIndex: Int? = nil) { + open func didTapMessage(_ cell: UITableViewCell?, _ model: MessageContentModel?, _ replyIndex: Int? = nil) { if model?.type == .audio { - startPlay(cell: cell as? ChatAudioCell, model: model as? MessageAudioModel) + startPlay(cell: cell as? ChatAudioCellProtocol, model: model as? MessageAudioModel) } else if model?.type == .image { if let imageObject = model?.message?.messageObject as? NIMImageObject { var imageUrl = "" @@ -1993,30 +2011,28 @@ extension ChatViewController: ChatBaseCellDelegate { animated: true) } videoModel.state = .Downalod - if let left = cell as? ChatVideoLeftCell { - left.setModel(videoModel) - } else if let right = cell as? ChatVideoRightCell { - right.setModel(videoModel) + if let videoCell = cell as? NEBaseChatMessageCell { + videoCell.setModel(videoModel) } viewmodel.downLoad(urlString, path) { progress in - NELog.infoLog(ModuleName + " " + (weakSelf?.tag ?? "ChatViewController"), desc: "CALLBACK downLoad: \(progress)") + NELog.infoLog(ModuleName + " " + (weakSelf?.tag ?? "ChatViewController"), desc: #function + "CALLBACK downLoad: \(progress)") videoModel.progress = progress if progress >= 1.0 { videoModel.state = .Success } - videoModel.cell?.uploadProgress(progress) + videoModel.cell?.uploadProgress(byRight: videoModel.message?.isOutgoingMsg ?? true, progress) } _: { error in if let err = error as NSError? { weakSelf?.showToast(err.localizedDescription) } } } - } else if replyIndex != nil, model?.type == .text { + } else if replyIndex != nil, model?.type == .text || model?.type == .reply { print("message did tap: text") if let text = model?.message?.text { - let textView = TextViewController(content: text) + let textView = getTextViewController(text: text) textView.modalPresentationStyle = .fullScreen DispatchQueue.main.asyncAfter(deadline: .now() + 0.25, execute: DispatchWorkItem(block: { [weak self] in self?.navigationController?.present(textView, animated: false) @@ -2042,14 +2058,12 @@ extension ChatViewController: ChatBaseCellDelegate { animated: true) } fileModel.state = .Downalod - if let left = cell as? ChatFileLeftCell { - left.setModel(fileModel) - } else if let right = cell as? ChatFileRightCell { - right.setModel(fileModel) + if let fileCell = cell as? NEBaseChatMessageCell { + fileCell.setModel(fileModel) } viewmodel.downLoad(urlString, path) { [weak self] progress in - NELog.infoLog(ModuleName + " " + (self?.tag ?? "ChatViewController"), desc: "@@# CALLBACK downLoad: \(progress)") + NELog.infoLog(ModuleName + " " + (self?.tag ?? "ChatViewController"), desc: #function + "downLoad file progress: \(progress)") var newProgress = progress if newProgress < 0 { newProgress = abs(progress) / fileModel.size @@ -2058,7 +2072,7 @@ extension ChatViewController: ChatBaseCellDelegate { if newProgress >= 1.0 { fileModel.state = .Success } - fileModel.cell?.uploadProgress(newProgress) + fileModel.cell?.uploadProgress(byRight: fileModel.message?.isOutgoingMsg ?? true, newProgress) } _: { [weak self] error in if let err = error as NSError? { @@ -2068,7 +2082,6 @@ extension ChatViewController: ChatBaseCellDelegate { } } else { let url = URL(fileURLWithPath: path) - print("@@# file:\(url) has download") interactionController.url = url interactionController.delegate = self // UIDocumentInteractionControllerDelegate if interactionController.presentPreview(animated: true) {} @@ -2095,7 +2108,47 @@ extension ChatViewController: ChatBaseCellDelegate { } } - public func didTapMessageView(_ cell: UITableViewCell, _ model: MessageContentModel?) { + // MARK: OVERRIDE + + open func getMenuView() -> NEBaseChatInputView { + NEBaseChatInputView() + } + + open func expandMoreAction() { + menuView.chatAddMoreView.configData(data: NEChatUIKitClient.instance.getMoreActionData(sessionType: viewmodel.session.sessionType)) + } +} + +// MARK: ChatBaseCellDelegate + +extension ChatViewController: ChatBaseCellDelegate { + open func didLongPressAvatar(_ cell: UITableViewCell, _ model: MessageContentModel?) { + print("didLongPressAvatar") + if viewmodel.session.sessionType == .P2P { + return + } + var addText = "" + var accid = "" + + if let m = model, let from = m.message?.from { + accid = from + addText += viewmodel.getShowName(userId: from, teamId: viewmodel.session.sessionId, false) + } + + addText = "@" + addText + "" + + addToAtUsers(addText: addText, accid: accid, true) + } + + open func didTapAvatarView(_ cell: UITableViewCell, _ model: MessageContentModel?) { + didTapHeadPortrait(model: model) + } + + open func didTapMessageView(_ cell: UITableViewCell, _ model: MessageContentModel?) { + if model?.isRevoked == true { + return + } + var replyId: String? = model?.message?.repliedMessageId if let yxReplyMsg = model?.message?.remoteExt?[keyReplyMsgKey] as? [String: Any] { replyId = yxReplyMsg["idClient"] as? String @@ -2121,11 +2174,11 @@ extension ChatViewController: ChatBaseCellDelegate { } } - public func didLongPressMessageView(_ cell: UITableViewCell, _ model: MessageContentModel?) { + open func didLongPressMessageView(_ cell: UITableViewCell, _ model: MessageContentModel?) { didLongTouchMessageView(cell, model) } - public func didTapResendView(_ cell: UITableViewCell, _ model: MessageContentModel?) { + open func didTapResendView(_ cell: UITableViewCell, _ model: MessageContentModel?) { if playingCell?.messageId == model?.message?.messageId { if playingCell?.isPlaying == true { stopPlay() @@ -2150,18 +2203,21 @@ extension ChatViewController: ChatBaseCellDelegate { } } - public func didTapReeditButton(_ cell: UITableViewCell, _ model: MessageContentModel?) { + open func didTapReeditButton(_ cell: UITableViewCell, _ model: MessageContentModel?) { if model?.type == .revoke, model?.message?.messageType == .text, let message = model?.message { let time = message.timestamp let date = Date() let currentTime = date.timeIntervalSince1970 if currentTime - time >= 60 * 2 { showToast(chatLocalizable("editable_time_expired")) - tableView.reloadData() + didRefreshTable() return } if model?.message?.remoteExt?[keyReplyMsgKey] != nil { + viewmodel.operationModel = model showReplyMessageView(isReEdit: true) + } else { + closeReply(button: nil) } guard let text = message.text else { return @@ -2195,18 +2251,15 @@ extension ChatViewController: ChatBaseCellDelegate { } } - public func didTapReadView(_ cell: UITableViewCell, _ model: MessageContentModel?) { - if let msg = model?.message, msg.session?.sessionType == .team { - let readVC = ReadViewController(message: msg) - navigationController?.pushViewController(readVC, animated: true) - } - } + open func didTapReadView(_ cell: UITableViewCell, _ model: MessageContentModel?) {} - public static func getLeftCellType(_ type: Int) -> String { - "\(type)\(leftCellTypeSufixx)" - } + open func loadDataFinish() {} + + // MARK: call kit noti - public static func getRitghtCellType(_ type: Int) -> String { - "\(type)\(rightCellTypeSufixx)" + open func didShowCallView() { + stopPlay() } + + open func didDismissCallView() {} } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/PinMessageViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/NEBasePinMessageViewController.swift similarity index 50% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/PinMessageViewController.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/NEBasePinMessageViewController.swift index 8f7ad386..3d1cc826 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/PinMessageViewController.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/NEBasePinMessageViewController.swift @@ -6,8 +6,9 @@ import UIKit import NIMSDK let PinMessageDefaultType = 1000 + @objcMembers -public class PinMessageViewController: ChatBaseViewController, UITableViewDataSource, UITableViewDelegate, PinMessageViewModelDelegate, PinMessageCellDelegate { +open class NEBasePinMessageViewController: ChatBaseViewController, UITableViewDataSource, UITableViewDelegate, PinMessageViewModelDelegate, PinMessageCellDelegate { let viewmodel = PinMessageViewModel() var session: NIMSession @@ -21,16 +22,6 @@ public class PinMessageViewController: ChatBaseViewController, UITableViewDataSo fatalError("init(coder:) has not been implemented") } - var cellClassDic = [ - NIMMessageType.text.rawValue: PinMessageTextCell.self, - NIMMessageType.image.rawValue: PinMessageImageCell.self, - NIMMessageType.audio.rawValue: PinMessageAudioCell.self, - NIMMessageType.video.rawValue: PinMessageVideoCell.self, - NIMMessageType.location.rawValue: PinMessageLocationCell.self, - NIMMessageType.file.rawValue: PinMessageFileCell.self, - PinMessageDefaultType: PinMessageDefaultCell.self, - ] - private lazy var tableView: UITableView = { let tableView = UITableView(frame: .zero, style: .plain) tableView.translatesAutoresizingMaskIntoConstraints = false @@ -38,13 +29,12 @@ public class PinMessageViewController: ChatBaseViewController, UITableViewDataSo tableView.showsVerticalScrollIndicator = false tableView.delegate = self tableView.dataSource = self - tableView.backgroundColor = .white + tableView.backgroundColor = .clear tableView.keyboardDismissMode = .onDrag - tableView.backgroundColor = UIColor(hexString: "#EFF1F3") return tableView }() - private lazy var emptyView: NEEmptyDataView = { + public lazy var emptyView: NEEmptyDataView = { let view = NEEmptyDataView( imageName: "user_empty", content: chatLocalizable("no_pin_message"), @@ -81,47 +71,25 @@ public class PinMessageViewController: ChatBaseViewController, UITableViewDataSo func setupUI() { title = chatLocalizable("operation_pin") + customNavigationView.navTitle.text = chatLocalizable("operation_pin") + customNavigationView.moreButton.isHidden = true view.addSubview(tableView) - if #available(iOS 10, *) { - NSLayoutConstraint.activate([ - tableView.topAnchor.constraint( - equalTo: view.topAnchor, - constant: kNavigationHeight + KStatusBarHeight - ), - tableView.leftAnchor.constraint(equalTo: view.leftAnchor), - tableView.rightAnchor.constraint(equalTo: view.rightAnchor), - tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), - ]) - } else { - NSLayoutConstraint.activate([ - tableView.topAnchor.constraint( - equalTo: view.topAnchor, - constant: 0 - ), - tableView.leftAnchor.constraint(equalTo: view.leftAnchor), - tableView.rightAnchor.constraint(equalTo: view.rightAnchor), - tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), - ]) - } + NSLayoutConstraint.activate([ + tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: NEConstant.navigationAndStatusHeight), + tableView.leftAnchor.constraint(equalTo: view.leftAnchor), + tableView.rightAnchor.constraint(equalTo: view.rightAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) view.addSubview(emptyView) - if #available(iOS 11.0, *) { - NSLayoutConstraint.activate([ - emptyView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), - emptyView.leftAnchor.constraint(equalTo: view.leftAnchor), - emptyView.rightAnchor.constraint(equalTo: view.rightAnchor), - emptyView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), - ]) - } else { - NSLayoutConstraint.activate([ - emptyView.topAnchor.constraint(equalTo: view.topAnchor), - emptyView.leftAnchor.constraint(equalTo: view.leftAnchor), - emptyView.rightAnchor.constraint(equalTo: view.rightAnchor), - emptyView.bottomAnchor.constraint(equalTo: view.bottomAnchor), - ]) - } - - cellClassDic.forEach { (key: Int, value: PinMessageBaseCell.Type) in + NSLayoutConstraint.activate([ + emptyView.topAnchor.constraint(equalTo: tableView.topAnchor), + emptyView.leftAnchor.constraint(equalTo: tableView.leftAnchor), + emptyView.rightAnchor.constraint(equalTo: tableView.rightAnchor), + emptyView.bottomAnchor.constraint(equalTo: tableView.bottomAnchor), + ]) + let cellClassDic = getRegisterCellDic() + cellClassDic.forEach { (key: Int, value: NEBasePinMessageCell.Type) in tableView.register(value, forCellReuseIdentifier: "\(key)") } } @@ -159,7 +127,7 @@ public class PinMessageViewController: ChatBaseViewController, UITableViewDataSo public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let model = viewmodel.items[indexPath.row] - let cell = tableView.dequeueReusableCell(withIdentifier: "\(model.getMessageType())", for: indexPath) as! PinMessageBaseCell + let cell = tableView.dequeueReusableCell(withIdentifier: "\(model.getMessageType())", for: indexPath) as! NEBasePinMessageCell cell.delegate = self cell.configure(model) return cell @@ -174,7 +142,45 @@ public class PinMessageViewController: ChatBaseViewController, UITableViewDataSo return model.cellHeight() } - func showAction(item: PinMessageModel) { + func cancelPinActionClicked(item: PinMessageModel) { + weak var weakSelf = self + if NEChatDetectNetworkTool.shareInstance.manager?.isReachable == false { + weakSelf?.showToast(commonLocalizable("network_error")) + return + } + weakSelf?.viewmodel.removePinMessage(item.message) { error, model in + if let err = error { + // weakSelf?.showToast(err.localizedDescription) + } else { + if let index = weakSelf?.viewmodel.items.firstIndex(of: item) { + NotificationCenter.default.post(name: Notification.Name(removePinMessageNoti), object: item.message) + weakSelf?.viewmodel.items.remove(at: index) + weakSelf?.emptyView.isHidden = (weakSelf?.viewmodel.items.count ?? 0) > 0 + weakSelf?.tableView.reloadData() + weakSelf?.showToast(chatLocalizable("cancel_pin_success")) + } + } + } + } + + func copyActionClicked(item: PinMessageModel) { + weak var weakSelf = self + let text = item.message.text + let pasteboard = UIPasteboard.general + pasteboard.string = text + weakSelf?.view.makeToast(chatLocalizable("copy_success"), duration: 2, position: .center) + } + + func forwardActionClicked(item: PinMessageModel) { + weak var weakSelf = self + if NEChatDetectNetworkTool.shareInstance.manager?.isReachable == false { + weakSelf?.showToast(commonLocalizable("network_error")) + return + } + weakSelf?.forwardMessage(item.message) + } + + open func showAction(item: PinMessageModel) { var actions = [UIAlertAction]() weak var weakSelf = self /* @@ -200,126 +206,112 @@ public class PinMessageViewController: ChatBaseViewController, UITableViewDataSo actions.append(jumpAction) */ let cancelPinAction = UIAlertAction(title: chatLocalizable("operation_cancel_pin"), style: .default) { _ in - - if NEChatDetectNetworkTool.shareInstance.manager?.isReachable == false { - weakSelf?.showToast(commonLocalizable("network_error")) - return - } - weakSelf?.viewmodel.removePinMessage(item.message) { error, model in - if let err = error { -// weakSelf?.showToast(err.localizedDescription) - } else { - if let index = weakSelf?.viewmodel.items.firstIndex(of: item) { - NotificationCenter.default.post(name: Notification.Name(removePinMessageNoti), object: item.message) - weakSelf?.viewmodel.items.remove(at: index) - weakSelf?.emptyView.isHidden = (weakSelf?.viewmodel.items.count ?? 0) > 0 - weakSelf?.tableView.reloadData() - weakSelf?.showToast(chatLocalizable("cancel_pin_success")) - } - } - } + weakSelf?.cancelPinActionClicked(item: item) } actions.append(cancelPinAction) if item.message.messageType == .text { let copyAction = UIAlertAction(title: chatLocalizable("operation_copy"), style: .default) { _ in - let text = item.message.text - let pasteboard = UIPasteboard.general - pasteboard.string = text - weakSelf?.view.makeToast(chatLocalizable("copy_success"), duration: 2, position: .center) + weakSelf?.copyActionClicked(item: item) } actions.append(copyAction) } if item.message.messageType != .audio { let forwardAction = UIAlertAction(title: chatLocalizable("operation_forward"), style: .default) { _ in - if NEChatDetectNetworkTool.shareInstance.manager?.isReachable == false { - weakSelf?.showToast(commonLocalizable("network_error")) - return - } - weakSelf?.forwardMessage(item.message) + weakSelf?.forwardActionClicked(item: item) } - actions.append(forwardAction) } - let cancelAction = UIAlertAction(title: chatLocalizable("cancel"), style: .cancel) { _ in - } + let cancelAction = UIAlertAction(title: chatLocalizable("cancel"), style: .cancel) { _ in } actions.append(cancelAction) showActionSheet(actions) } - private func forwardMessage(_ message: NIMMessage) { + open func getForwardAlertController() -> NEBaseForwardAlertViewController { + NEBaseForwardAlertViewController() + } + + func forwardMessageToUser(_ message: NIMMessage) { weak var weakSelf = self - let userAction = UIAlertAction(title: chatLocalizable("contact_user"), - style: .default) { action in + Router.shared.register(ContactSelectedUsersRouter) { param in + print("user setting accids : ", param) + var items = [ForwardItem]() - Router.shared.register(ContactSelectedUsersRouter) { param in - print("user setting accids : ", param) - var items = [ForwardItem]() - - if let users = param["im_user"] as? [NIMUser] { - users.forEach { user in - let item = ForwardItem() - item.uid = user.userId - item.avatar = user.userInfo?.avatarUrl - item.name = user.userInfo?.nickName - items.append(item) - } - - let forwardAlert = ForwardAlertViewController() - forwardAlert.setItems(items) - if let senderName = message.senderName { - forwardAlert.context = senderName - } - weakSelf?.addChild(forwardAlert) - weakSelf?.view.addSubview(forwardAlert.view) - - forwardAlert.sureBlock = { - print("sure click ") - weakSelf?.viewmodel.forwardUserMessage(message, users) - } + if let users = param["im_user"] as? [NIMUser] { + users.forEach { user in + let item = ForwardItem() + item.uid = user.userId + item.avatar = user.userInfo?.avatarUrl + item.name = user.userInfo?.nickName + items.append(item) + } + + let forwardAlert = weakSelf!.getForwardAlertController() + forwardAlert.setItems(items) + if let senderName = message.senderName { + forwardAlert.context = senderName + } + weakSelf?.addChild(forwardAlert) + weakSelf?.view.addSubview(forwardAlert.view) + + forwardAlert.sureBlock = { + print("sure click ") + weakSelf?.viewmodel.forwardUserMessage(message, users) } } - var param = [String: Any]() - param["nav"] = weakSelf?.navigationController as Any - param["limit"] = 6 - if let session = weakSelf?.session, session.sessionType == .P2P { - var filters = Set() - filters.insert(session.sessionId) - param["filters"] = filters - } - Router.shared.use(ContactUserSelectRouter, parameters: param, closure: nil) } + var param = [String: Any]() + param["nav"] = weakSelf?.navigationController as Any + param["limit"] = 6 + if let session = weakSelf?.session, session.sessionType == .P2P { + var filters = Set() + filters.insert(session.sessionId) + param["filters"] = filters + } + Router.shared.use(ContactUserSelectRouter, parameters: param, closure: nil) + } - let teamAction = UIAlertAction(title: chatLocalizable("team"), style: .default) { action in - - Router.shared.register(ContactTeamDataRouter) { param in - if let team = param["team"] as? NIMTeam { - let item = ForwardItem() - item.avatar = team.avatarUrl - item.name = team.getShowName() - item.uid = team.teamId - - let forwardAlert = ForwardAlertViewController() - forwardAlert.setItems([item]) - if let senderName = message.senderName { - forwardAlert.context = senderName - } - forwardAlert.sureBlock = { - weakSelf?.viewmodel.forwardTeamMessage(message, team) - } - weakSelf?.addChild(forwardAlert) - weakSelf?.view.addSubview(forwardAlert.view) + func forwardMessageToTeam(_ message: NIMMessage) { + weak var weakSelf = self + Router.shared.register(ContactTeamDataRouter) { param in + if let team = param["team"] as? NIMTeam { + let item = ForwardItem() + item.avatar = team.avatarUrl + item.name = team.getShowName() + item.uid = team.teamId + + let forwardAlert = weakSelf!.getForwardAlertController() + forwardAlert.setItems([item]) + if let senderName = message.senderName { + forwardAlert.context = senderName + } + forwardAlert.sureBlock = { + weakSelf?.viewmodel.forwardTeamMessage(message, team) } + weakSelf?.addChild(forwardAlert) + weakSelf?.view.addSubview(forwardAlert.view) } + } - Router.shared.use( - ContactTeamListRouter, - parameters: ["nav": weakSelf?.navigationController as Any], - closure: nil - ) + Router.shared.use( + ContactTeamListRouter, + parameters: ["nav": weakSelf?.navigationController as Any], + closure: nil + ) + } + + open func forwardMessage(_ message: NIMMessage) { + weak var weakSelf = self + let userAction = UIAlertAction(title: chatLocalizable("contact_user"), + style: .default) { action in + weakSelf?.forwardMessageToUser(message) + } + + let teamAction = UIAlertAction(title: chatLocalizable("team"), style: .default) { action in + weakSelf?.forwardMessageToTeam(message) } let cancelAction = UIAlertAction(title: chatLocalizable("cancel"), @@ -337,10 +329,23 @@ public class PinMessageViewController: ChatBaseViewController, UITableViewDataSo // MARK: PinMessageCellDelegate - func didClickMore(_ model: PinMessageModel?) { + public func didClickMore(_ model: PinMessageModel?) { print("did click more") if let item = model { showAction(item: item) } } + + open func getRegisterCellDic() -> [Int: NEBasePinMessageCell.Type] { + let cellClassDic = [ + NIMMessageType.text.rawValue: NEBasePinMessageTextCell.self, + NIMMessageType.image.rawValue: NEBasePinMessageImageCell.self, + NIMMessageType.audio.rawValue: NEBasePinMessageAudioCell.self, + NIMMessageType.video.rawValue: NEBasePinMessageVideoCell.self, + NIMMessageType.location.rawValue: NEBasePinMessageLocationCell.self, + NIMMessageType.file.rawValue: NEBasePinMessageFileCell.self, + PinMessageDefaultType: NEBasePinMessageDefaultCell.self, + ] + return cellClassDic + } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/ReadViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/NEBaseReadViewController.swift similarity index 76% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/ReadViewController.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/NEBaseReadViewController.swift index 3910388a..8ee51b38 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/ReadViewController.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/NEBaseReadViewController.swift @@ -9,7 +9,7 @@ import NECoreIMKit import NECommonUIKit @objcMembers -public class ReadViewController: ChatBaseViewController, UIScrollViewDelegate, UITableViewDelegate, +open class NEBaseReadViewController: ChatBaseViewController, UIScrollViewDelegate, UITableViewDelegate, UITableViewDataSource { public var read: Bool = true public var line: UIView = .init() @@ -25,18 +25,20 @@ public class ReadViewController: ChatBaseViewController, UIScrollViewDelegate, U super.init(nibName: nil, bundle: nil) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - override public func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() commonUI() loadData(message: message) } - func commonUI() { + open func commonUI() { title = chatLocalizable("message_read") + customNavigationView.moreButton.isHidden = true + readButton.titleLabel?.font = UIFont.systemFont(ofSize: 14) readButton.setTitle(chatLocalizable("read"), for: .normal) readButton.setTitleColor(UIColor.ne_darkText, for: .normal) @@ -45,41 +47,18 @@ public class ReadViewController: ChatBaseViewController, UIScrollViewDelegate, U view.addSubview(readButton) unreadButton.titleLabel?.font = UIFont.systemFont(ofSize: 14) - unreadButton.setTitleColor(UIColor.ne_darkText, for: .normal) unreadButton.setTitle(chatLocalizable("unread"), for: .normal) + unreadButton.setTitleColor(UIColor.ne_darkText, for: .normal) unreadButton.translatesAutoresizingMaskIntoConstraints = false unreadButton.addTarget(self, action: #selector(unreadButtonEvent), for: .touchUpInside) view.addSubview(unreadButton) - - if #available(iOS 11.0, *) { - NSLayoutConstraint.activate([ - readButton.topAnchor.constraint( - equalTo: self.view.safeAreaLayoutGuide.topAnchor, - constant: 0 - ), - readButton.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), - readButton.heightAnchor.constraint(equalToConstant: 48), - readButton.widthAnchor.constraint(equalTo: unreadButton.widthAnchor), - ]) - } else { - // Fallback on earlier versions - if #available(iOS 10.0, *) { - NSLayoutConstraint.activate([ - readButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 0), - readButton.leadingAnchor.constraint(equalTo: view.leadingAnchor), - readButton.heightAnchor.constraint(equalToConstant: 48), - readButton.widthAnchor.constraint(equalTo: unreadButton.widthAnchor), - ]) - } else { - NSLayoutConstraint.activate([ - readButton.topAnchor.constraint(equalTo: view.topAnchor, constant: kNavigationHeight + KStatusBarHeight), - readButton.leadingAnchor.constraint(equalTo: view.leadingAnchor), - readButton.heightAnchor.constraint(equalToConstant: 48), - readButton.widthAnchor.constraint(equalTo: unreadButton.widthAnchor), - ]) - } - } + NSLayoutConstraint.activate([ + readButton.topAnchor.constraint(equalTo: view.topAnchor, constant: topConstant), + readButton.leadingAnchor.constraint(equalTo: view.leadingAnchor), + readButton.heightAnchor.constraint(equalToConstant: 48), + readButton.widthAnchor.constraint(equalTo: unreadButton.widthAnchor), + ]) NSLayoutConstraint.activate([ unreadButton.topAnchor.constraint(equalTo: readButton.topAnchor), @@ -89,7 +68,6 @@ public class ReadViewController: ChatBaseViewController, UIScrollViewDelegate, U ]) line.translatesAutoresizingMaskIntoConstraints = false - line.backgroundColor = UIColor.ne_blueText view.addSubview(line) lineLeftCons = line.leadingAnchor.constraint(equalTo: view.leadingAnchor) NSLayoutConstraint.activate([ @@ -123,12 +101,7 @@ public class ReadViewController: ChatBaseViewController, UIScrollViewDelegate, U readTableView.sectionHeaderHeight = 0 readTableView.sectionFooterHeight = 0 readTableView.translatesAutoresizingMaskIntoConstraints = false - readTableView.register( - UserTableViewCell.self, - forCellReuseIdentifier: "\(UserTableViewCell.self)" - ) readTableView.separatorStyle = .none - readTableView.rowHeight = 62 readTableView.tableFooterView = UIView() view.addSubview(readTableView) @@ -151,7 +124,7 @@ public class ReadViewController: ChatBaseViewController, UIScrollViewDelegate, U } } - func readButtonEvent(button: UIButton) { + open func readButtonEvent(button: UIButton) { if read { return } @@ -170,7 +143,7 @@ public class ReadViewController: ChatBaseViewController, UIScrollViewDelegate, U } } - func unreadButtonEvent(button: UIButton) { + open func unreadButtonEvent(button: UIButton) { if !read { return } @@ -192,8 +165,12 @@ public class ReadViewController: ChatBaseViewController, UIScrollViewDelegate, U func loadData(message: NIMMessage) { NIMSDK.shared().chatManager.queryMessageReceiptDetail(message) { anError, receiptInfo in print("anError:\(anError) receiptInfo:\(receiptInfo)") - if let error = anError { - self.showToast(error.localizedDescription) + if let error = anError as? NSError { + if error.code == 408 { + self.showToast(commonLocalizable("network_error")) + } else { + self.showToast(error.localizedDescription) + } return } @@ -224,7 +201,7 @@ public class ReadViewController: ChatBaseViewController, UIScrollViewDelegate, U } } - public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if read { return readUsers.count } else { @@ -232,12 +209,7 @@ public class ReadViewController: ChatBaseViewController, UIScrollViewDelegate, U } } - public func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell( - withIdentifier: "\(UserTableViewCell.self)", - for: indexPath - ) as! UserTableViewCell + func cellSetModel(cell: UserBaseTableViewCell, indexPath: IndexPath) -> UITableViewCell { if read { let model = readUsers[indexPath.row] cell.setModel(model) @@ -249,7 +221,16 @@ public class ReadViewController: ChatBaseViewController, UIScrollViewDelegate, U return cell } - private lazy var emptyView: NEEmptyDataView = { + open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell( + withIdentifier: "\(UserBaseTableViewCell.self)", + for: indexPath + ) as! UserBaseTableViewCell + return cellSetModel(cell: cell, indexPath: indexPath) + } + + public lazy var emptyView: NEEmptyDataView = { let view = NEEmptyDataView( imageName: "emptyView", content: chatLocalizable("message_all_unread"), diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/SelectUserViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/NEBaseSelectUserViewController.swift similarity index 85% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/SelectUserViewController.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/NEBaseSelectUserViewController.swift index 8cfc992b..94d00a54 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/SelectUserViewController.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/NEBaseSelectUserViewController.swift @@ -9,7 +9,7 @@ import NECoreIMKit public typealias DidSelectedAtRow = (_ index: Int, _ model: ChatTeamMemberInfoModel?) -> Void @objcMembers -public class SelectUserViewController: ChatBaseViewController, UITableViewDelegate, +open class NEBaseSelectUserViewController: ChatBaseViewController, UITableViewDelegate, UITableViewDataSource { public var tableView = UITableView(frame: .zero, style: .plain) public var sessionId: String @@ -17,7 +17,7 @@ public class SelectUserViewController: ChatBaseViewController, UITableViewDelega public var selectedBlock: DidSelectedAtRow? var teamInfo: ChatTeamInfoModel? private var showSelf = true // 是否展示自己 - private let className = "SelectUserViewController" + var className = "SelectUserViewController" init(sessionId: String, showSelf: Bool = true) { self.sessionId = sessionId @@ -25,12 +25,14 @@ public class SelectUserViewController: ChatBaseViewController, UITableViewDelega super.init(nibName: nil, bundle: nil) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override public func viewDidLoad() { super.viewDidLoad() + navigationController?.isNavigationBarHidden = true + customNavigationView.isHidden = true commonUI() loadData() } @@ -62,12 +64,12 @@ public class SelectUserViewController: ChatBaseViewController, UITableViewDelega let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.text = chatLocalizable("user_select") - label.font = UIFont.systemFont(ofSize: 16) + label.font = UIFont.systemFont(ofSize: 16, weight: .semibold) label.textAlignment = .center - label.textColor = UIColor.darkGray + label.textColor = .ne_darkText view.addSubview(label) NSLayoutConstraint.activate([ - label.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16), + label.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0), label.topAnchor.constraint(equalTo: view.topAnchor), label.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0), label.heightAnchor.constraint(equalToConstant: 50), @@ -78,12 +80,7 @@ public class SelectUserViewController: ChatBaseViewController, UITableViewDelega tableView.sectionHeaderHeight = 0 tableView.sectionFooterHeight = 0 tableView.translatesAutoresizingMaskIntoConstraints = false - tableView.register( - ChatTeamMemberCell.self, - forCellReuseIdentifier: "\(ChatTeamMemberCell.self)" - ) tableView.separatorStyle = .none - tableView.rowHeight = 62 tableView.tableFooterView = UIView() view.addSubview(tableView) @@ -140,19 +137,7 @@ public class SelectUserViewController: ChatBaseViewController, UITableViewDelega public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell( - withIdentifier: "\(ChatTeamMemberCell.self)", - for: indexPath - ) as! ChatTeamMemberCell - if indexPath.row == 0 { - cell.headerView.image = UIImage.ne_imageNamed(name: "chat_team") - cell.nameLabel.text = chatLocalizable("user_select_all") - } else { - if let model = teamInfo?.users[indexPath.row - 1] { - cell.configure(model) - } - } - return cell + UITableViewCell() } public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/UserSettingViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/NEBaseUserSettingViewController.swift similarity index 81% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/UserSettingViewController.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/NEBaseUserSettingViewController.swift index 95695d82..5aadd396 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/UserSettingViewController.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/NEBaseUserSettingViewController.swift @@ -8,7 +8,7 @@ import NECommonKit import NIMSDK @objcMembers -public class UserSettingViewController: ChatBaseViewController, UserSettingViewModelDelegate, +open class NEBaseUserSettingViewController: ChatBaseViewController, UserSettingViewModelDelegate, UITableViewDataSource, UITableViewDelegate { var userId: String? @@ -19,7 +19,6 @@ public class UserSettingViewController: ChatBaseViewController, UserSettingViewM imageView.translatesAutoresizingMaskIntoConstraints = false imageView.clipsToBounds = true imageView.titleLabel.font = NEConstant.defaultTextFont(16.0) - imageView.layer.cornerRadius = 21.0 imageView.isUserInteractionEnabled = true return imageView }() @@ -43,7 +42,7 @@ public class UserSettingViewController: ChatBaseViewController, UserSettingViewM lazy var contentTable: UITableView = { let table = UITableView() table.translatesAutoresizingMaskIntoConstraints = false - table.backgroundColor = NEConstant.hexRGB(0xF1F1F6) + table.backgroundColor = .clear table.dataSource = self table.delegate = self table.separatorColor = .clear @@ -58,38 +57,40 @@ public class UserSettingViewController: ChatBaseViewController, UserSettingViewM return table }() - public var cellClassDic = [ - UserSettingType.SwitchType.rawValue: UserSettingSwitchCell.self, - UserSettingType.SelectType.rawValue: UserSettingSelectCell.self, - ] + public var cellClassDic = [Int: NEBaseUserSettingCell.Type]() override public func viewDidLoad() { super.viewDidLoad() viewmodel.delegate = self - setupUI() if let uid = userId { viewmodel.getUserSettingModel(uid) contentTable.tableHeaderView = headerView() contentTable.reloadData() } + setupUI() } func setupUI() { view.backgroundColor = .ne_backcolor + title = chatLocalizable("chat_setting") + customNavigationView.moreButton.isHidden = true view.addSubview(contentTable) NSLayoutConstraint.activate([ contentTable.leftAnchor.constraint(equalTo: view.leftAnchor), contentTable.rightAnchor.constraint(equalTo: view.rightAnchor), - contentTable.topAnchor.constraint(equalTo: view.topAnchor), + contentTable.topAnchor.constraint(equalTo: view.topAnchor, constant: topConstant), contentTable.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) - cellClassDic.forEach { (key: Int, value: UserSettingBaseCell.Type) in + cellClassDic.forEach { (key: Int, value: NEBaseUserSettingCell.Type) in contentTable.register(value, forCellReuseIdentifier: "\(key)") } + if let pan = navigationController?.interactivePopGestureRecognizer { + contentTable.panGestureRecognizer.require(toFail: pan) + } } - func headerView() -> UIView { + open func headerView() -> UIView { let header = UIView(frame: CGRect(x: 0, y: 0, width: view.width, height: 110)) header.backgroundColor = .clear let cornerBack = UIView() @@ -100,7 +101,7 @@ public class UserSettingViewController: ChatBaseViewController, UserSettingViewM NSLayoutConstraint.activate([ cornerBack.bottomAnchor.constraint(equalTo: header.bottomAnchor, constant: -12), cornerBack.leftAnchor.constraint(equalTo: header.leftAnchor, constant: 20), - cornerBack.rightAnchor.constraint(equalTo: header.rightAnchor, constant: -20), + cornerBack.widthAnchor.constraint(equalToConstant: kScreenWidth - 40), cornerBack.heightAnchor.constraint(equalToConstant: 86.0), ]) @@ -118,7 +119,10 @@ public class UserSettingViewController: ChatBaseViewController, UserSettingViewM if let url = viewmodel.userInfo?.userInfo?.avatarUrl { userHeader.sd_setImage(with: URL(string: url), completed: nil) + userHeader.setTitle("") + userHeader.backgroundColor = .clear } else if let name = viewmodel.userInfo?.showName(false) { + userHeader.sd_setImage(with: nil) userHeader.setTitle(name) userHeader.backgroundColor = UIColor.colorWithString(string: viewmodel.userInfo?.userId) } @@ -143,6 +147,16 @@ public class UserSettingViewController: ChatBaseViewController, UserSettingViewM return header } + open func filterStackViewController() -> [UIViewController]? { + navigationController?.viewControllers.filter { + if $0.isKind(of: ChatViewController.self) || $0 + .isKind(of: NEBaseUserSettingViewController.self) { + return false + } + return true + } + } + func createDiscuss() { weak var weakSelf = self Router.shared.register(ContactSelectedUsersRouter) { param in @@ -150,7 +164,7 @@ public class UserSettingViewController: ChatBaseViewController, UserSettingViewM var convertParam = [String: Any]() param.forEach { (key: String, value: Any) in if key == "names", let names = value as? String { - convertParam[key] = "\(weakSelf?.userId ?? "")、\(names)" + convertParam[key] = "\(weakSelf?.nameLabel.text ?? "")、\(names)" } else { convertParam[key] = value } @@ -182,13 +196,7 @@ public class UserSettingViewController: ChatBaseViewController, UserSettingViewM let session = NIMSession(teamid, type: .team) DispatchQueue.main.async { - if let allControllers = weakSelf?.navigationController?.viewControllers.filter({ - if $0.isKind(of: P2PChatViewController.self) || $0 - .isKind(of: UserSettingViewController.self) { - return false - } - return true - }) { + if let allControllers = weakSelf?.filterStackViewController() { weakSelf?.navigationController?.viewControllers = allControllers Router.shared.use( PushTeamChatVCRouter, @@ -204,7 +212,7 @@ public class UserSettingViewController: ChatBaseViewController, UserSettingViewM } } - func showUserInfo() { + open func showUserInfo() { if let user = viewmodel.userInfo { Router.shared.use( ContactUserInfoPageRouter, @@ -234,18 +242,22 @@ public class UserSettingViewController: ChatBaseViewController, UserSettingViewM if let cell = tableView.dequeueReusableCell( withIdentifier: "\(model.type)", for: indexPath - ) as? UserSettingBaseCell { + ) as? NEBaseUserSettingCell { cell.configure(model) return cell } return UITableViewCell() } - public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + func getPinMessageViewController(session: NIMSession) -> NEBasePinMessageViewController { + NEBasePinMessageViewController(session: session) + } + + open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if indexPath.row == 0 { if let accid = userId { let session = NIMSession(accid, type: .P2P) - let pin = PinMessageViewController(session: session) + let pin = getPinMessageViewController(session: session) navigationController?.pushViewController(pin, animated: true) } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/NEDetailMapController.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/NEDetailMapController.swift index 4754bbc5..9af758d8 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/NEDetailMapController.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/NEDetailMapController.swift @@ -6,6 +6,7 @@ import UIKit import NEChatKit import NECoreKit +@objcMembers public class NEDetailMapController: ChatBaseViewController, NEMapGuideBottomViewDelegate { // 地图展示类型 public var mapType: NEMapType? @@ -45,6 +46,16 @@ public class NEDetailMapController: ChatBaseViewController, NEMapGuideBottomView override public func viewWillAppear(_ animated: Bool) { navigationController?.navigationBar.isHidden = true + weak var weakSelf = self + NEChatDetectNetworkTool.shareInstance.netWorkReachability { status in + if status == .notReachable { + weakSelf?.sendBtn.isEnabled = false + weakSelf?.sendBtn.alpha = 0.5 + } else { + weakSelf?.sendBtn.isEnabled = true + weakSelf?.sendBtn.alpha = 1.0 + } + } } override public func viewWillDisappear(_ animated: Bool) { @@ -232,7 +243,7 @@ public class NEDetailMapController: ChatBaseViewController, NEMapGuideBottomView // MARK: 键盘通知相关操作 - @objc func keyBoardWillShow(_ notification: Notification) { + func keyBoardWillShow(_ notification: Notification) { foldKeyBoard = false searchCancelBtn.isHidden = false searchViewConstraint?.constant = -64 @@ -244,7 +255,7 @@ public class NEDetailMapController: ChatBaseViewController, NEMapGuideBottomView }) } - @objc func keyBoardWillHide(_ notification: Notification) { + func keyBoardWillHide(_ notification: Notification) { foldKeyBoard = true // layoutInputView(offset: 0) } @@ -369,8 +380,8 @@ public class NEDetailMapController: ChatBaseViewController, NEMapGuideBottomView textField.font = UIFont.systemFont(ofSize: 14) textField.textColor = UIColor.ne_greyText textField.layer.cornerRadius = 8 - textField.backgroundColor = UIColor(hexString: "0xEFF1F4") - textField.clearButtonMode = .whileEditing + textField.backgroundColor = .ne_lightBackgroundColor + textField.clearButtonMode = .always textField.returnKeyType = .search textField.addTarget(self, action: #selector(searchTextFieldChange), for: .editingChanged) return textField @@ -383,13 +394,14 @@ public class NEDetailMapController: ChatBaseViewController, NEMapGuideBottomView return bgView }() - @objc func resetClick() { + func resetClick() { if let map = mapView { resetBtn.isSelected = false if mapType == .detail, let map = mapView { NEChatKitClient.instance.delegate?.setMapCenter?(mapview: map) return } + searchTextField.text = nil toSearchLocalWithMapView() NEChatKitClient.instance.delegate?.setMapCenter?(mapview: map) currentIndex = 0 @@ -397,7 +409,7 @@ public class NEDetailMapController: ChatBaseViewController, NEMapGuideBottomView } } - @objc func cancelSearch() { + func cancelSearch() { UIApplication.shared.keyWindow?.endEditing(true) UIView.animate(withDuration: 0.25, animations: { self.searchCancelBtn.isHidden = true @@ -421,15 +433,15 @@ public class NEDetailMapController: ChatBaseViewController, NEMapGuideBottomView emptyLabel.isHidden = true } - @objc func backBackClick() { + func backBackClick() { navigationController?.popViewController(animated: true) } - @objc func cancelBtnClick() { + func cancelBtnClick() { navigationController?.popViewController(animated: true) } - @objc func sendBtnClick() { + func sendBtnClick() { var model: ChatLocaitonModel? if model == nil { @@ -443,15 +455,18 @@ public class NEDetailMapController: ChatBaseViewController, NEMapGuideBottomView } if let m = model { - if let block = completion { - block(m) - } - } else {} - - navigationController?.popViewController(animated: true) + navigationController?.popViewController(animated: false) + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: DispatchWorkItem(block: { + if let block = self.completion { + block(m) + } + })) + } else { + showToast(chatLocalizable("no_location")) + } } - @objc func searchTextFieldChange(textfield: SearchTextField) { + func searchTextFieldChange(textfield: SearchTextField) { guard let searchText = textfield.text else { return } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/TextViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/TextViewController.swift index f89ad880..5ecc9284 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/TextViewController.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/TextViewController.swift @@ -4,77 +4,104 @@ import Foundation -class TextViewController: ChatBaseViewController { +@objcMembers +open class TextViewController: ChatBaseViewController { let leftRightMargin: CGFloat = 24 + var contentMaxWidth: CGFloat = 0 let textFont = UIFont.systemFont(ofSize: 24, weight: .regular) - lazy var textView: CopyableTextView = { - let textView = CopyableTextView() - textView.isEditable = false - textView.isSelectable = false - textView.translatesAutoresizingMaskIntoConstraints = false - textView.font = .systemFont(ofSize: 24, weight: .regular) - return textView + + lazy var scrollView: UIScrollView = { + let scrollView = UIScrollView() + scrollView.isScrollEnabled = true + scrollView.translatesAutoresizingMaskIntoConstraints = false + return scrollView + }() + + var contentLabelTopAnchor: NSLayoutConstraint? + var contentLabelLeftAnchor: NSLayoutConstraint? + lazy var contentLabel: CopyableLabel = { + let contentLabel = CopyableLabel() + contentLabel.numberOfLines = 0 + contentLabel.translatesAutoresizingMaskIntoConstraints = false + contentLabel.font = textFont + contentLabel.backgroundColor = .clear + return contentLabel }() init(content: String) { super.init(nibName: nil, bundle: nil) - textView.copyString = content - let att = NEEmotionTool.getAttWithStr(str: content, font: textFont) - textView.attributedText = att + contentMaxWidth = kScreenWidth - leftRightMargin * 2 + let att = NEEmotionTool.getAttWithStr(str: content, font: textFont, CGPoint(x: 0, y: -3)) + contentLabel.copyString = att.string + contentLabel.attributedText = att let line = String.calculateMaxLines(width: kScreenWidth - 2 * leftRightMargin, string: att.string, font: textFont) - textView.textAlignment = line > 1 ? .justified : .center + contentLabel.textAlignment = .justified } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - override func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() navigationController?.isNavigationBarHidden = true + customNavigationView.isHidden = true let tap = UITapGestureRecognizer(target: self, action: #selector(viewTap)) - textView.addGestureRecognizer(tap) + scrollView.addGestureRecognizer(tap) setupUI() contentSizeToFit() } - @objc func viewTap() { + open func viewTap() { UIMenuController.shared.setMenuVisible(false, animated: true) dismiss(animated: false) } - func setupUI() { - view.addSubview(textView) + open func setupUI() { + view.addSubview(scrollView) if #available(iOS 11.0, *) { NSLayoutConstraint.activate([ - textView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), - textView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), - textView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: leftRightMargin), - textView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -leftRightMargin), + scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), + scrollView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0), + scrollView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -0), ]) } else { NSLayoutConstraint.activate([ - textView.topAnchor.constraint(equalTo: view.topAnchor), - textView.bottomAnchor.constraint(equalTo: view.bottomAnchor), - textView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: leftRightMargin), - textView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -leftRightMargin), + scrollView.topAnchor.constraint(equalTo: view.topAnchor), + scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + scrollView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0), + scrollView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -0), ]) } + + scrollView.addSubview(contentLabel) + contentLabel.preferredMaxLayoutWidth = contentMaxWidth + contentLabelTopAnchor = contentLabel.topAnchor.constraint(equalTo: scrollView.topAnchor) + contentLabelLeftAnchor = contentLabel.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: leftRightMargin) + NSLayoutConstraint.activate([ + contentLabelTopAnchor!, + contentLabel.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor), + contentLabelLeftAnchor!, + contentLabel.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: -leftRightMargin), + ]) } // textView 垂直居中 func contentSizeToFit() { - guard !textView.text.isEmpty else { - return - } - let textSize = String.getTextRectSize(textView.text, font: textFont, size: CGSize(width: kScreenWidth - leftRightMargin * 2, height: CGFloat.greatestFiniteMagnitude)) + let textSize = contentLabel.attributedText?.finalSize(textFont, CGSize(width: contentMaxWidth, height: CGFloat.greatestFiniteMagnitude)) ?? .zero let textViewHeight = kScreenHeight - kNavigationHeight - KStatusBarHeight if textSize.height <= textViewHeight { let offsetY = (textViewHeight - textSize.height) / 2 - let offset = UIEdgeInsets(top: offsetY, left: 0, bottom: 0, right: 0) - textView.contentInset = offset + contentLabelTopAnchor?.constant = offsetY + } + + if textSize.width <= contentMaxWidth { + let offsetX = (kScreenWidth - textSize.width) / 2 + contentLabelLeftAnchor?.constant = offsetX } + scrollView.contentSize = textSize } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Emoji/InputEmoticonContainerView.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Emoji/InputEmoticonContainerView.swift index 10c98694..804a8813 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Emoji/InputEmoticonContainerView.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Emoji/InputEmoticonContainerView.swift @@ -149,6 +149,7 @@ public class InputEmoticonContainerView: UIView { // MAKR: lazy method private lazy var emoticonPageView: EmojiPageView = { let pageView = EmojiPageView(frame: self.bounds) + pageView.translatesAutoresizingMaskIntoConstraints = false pageView.dataSource = self pageView.pageViewDelegate = self return pageView diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Helper/NotificationMessageUtils.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Helper/NotificationMessageUtils.swift index b6688817..ac420fe8 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Helper/NotificationMessageUtils.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Helper/NotificationMessageUtils.swift @@ -177,7 +177,7 @@ public class NotificationMessageUtils: NSObject { if let object = message.messageObject as? NIMNotificationObject { if let content = object.content as? NIMTeamNotificationContent { if content.sourceID == NIMSDK.shared().loginManager.currentAccount() { - return chatLocalizable("You") + return chatLocalizable("You") + " " } else { if let sourceId = content.sourceID { return getShowName(userId: sourceId, nimSession: message.session) @@ -197,7 +197,7 @@ public class NotificationMessageUtils: NSObject { } for targetID in targetIDs { if targetID == NIMSDK.shared().loginManager.currentAccount() { - toNames.append(chatLocalizable("You")) + toNames.append(chatLocalizable("You") + " ") } else { toNames .append(getShowName(userId: targetID, nimSession: message.session)) diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Helper/ReplyMessageUtil.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Helper/ReplyMessageUtil.swift index c1da4a28..c1892062 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Helper/ReplyMessageUtil.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Helper/ReplyMessageUtil.swift @@ -13,7 +13,7 @@ public class ReplyMessageUtil: NSObject { } text += ": " switch model.type { - case .text: + case .text, .reply: if let t = model.message?.text { text += t } else { diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageAudioModel.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageAudioModel.swift index f3650ce3..e51515cd 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageAudioModel.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageAudioModel.swift @@ -14,7 +14,7 @@ class MessageAudioModel: MessageContentModel { super.init(message: message) type = .audio var audioW = 96.0 - let audioTotalWidth = 265.0 + let audioTotalWidth = kScreenWidth <= 325 ? 230 : 265.0 // contentSize if let obj = message?.messageObject as? NIMAudioObject { duration = obj.duration / 1000 @@ -22,7 +22,7 @@ class MessageAudioModel: MessageContentModel { audioW = min(Double(duration) * 8 + audioW, audioTotalWidth) } } - contentSize = CGSize(width: audioW, height: qChat_min_h) - height = Float(contentSize.height + qChat_margin) + fullNameHeight + contentSize = CGSize(width: audioW, height: chat_min_h) + height = Float(contentSize.height + chat_content_margin) + fullNameHeight } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageCallRecordModel.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageCallRecordModel.swift index f2e609c3..6fac26f0 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageCallRecordModel.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageCallRecordModel.swift @@ -61,16 +61,12 @@ class MessageCallRecordModel: MessageContentModel { attributeStr?.addAttribute(NSAttributedString.Key.foregroundColor, value: NEKitChatConfig.shared.ui.messageTextColor, range: NSMakeRange(0, attributeStr?.length ?? 0)) } - let textSize = NEChatUITool.getSizeWithAtt( - att: attributeStr ?? NSAttributedString(string: ""), - font: DefaultTextFont(16), - maxSize: CGSize(width: qChat_content_maxW, height: CGFloat.greatestFiniteMagnitude) - ) + let textSize = attributeStr?.finalSize(NEKitChatConfig.shared.ui.messageTextSize, CGSize(width: chat_content_maxW, height: CGFloat.greatestFiniteMagnitude)) ?? .zero - var h = qChat_min_h + var h = chat_min_h h = textSize.height + (isAuiodRecord ? 20 : 24) - contentSize = CGSize(width: textSize.width + qChat_cell_margin * 2, height: h) + contentSize = CGSize(width: textSize.width + chat_cell_margin * 2, height: h) - height = Float(contentSize.height + qChat_margin) + fullNameHeight + height = Float(contentSize.height + chat_content_margin) + fullNameHeight } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageContentModel.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageContentModel.swift index 2ca1bcec..f22dd7c8 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageContentModel.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageContentModel.swift @@ -11,14 +11,19 @@ import NECoreIMKit @objcMembers public class MessageContentModel: NSObject, MessageModel { + public var offset: CGFloat = 0 + public func cellHeight() -> CGFloat { + CGFloat(height) + offset + } + public var isReplay: Bool = false public var pinAccount: String? public var pinShowName: String? public var type: MessageType = .custom public var message: NIMMessage? - public var contentSize: CGSize - public var height: Float + public var contentSize = CGSize(width: 32.0, height: chat_min_h) + public var height: Float = 48 public var shortName: String? // 昵称 > uid public var fullName: String? // 备注 >(群昵称)> 昵称 > uid public var avatar: String? @@ -30,29 +35,9 @@ public class MessageContentModel: NSObject, MessageModel { public var replyedModel: MessageModel? { didSet { if let reply = replyedModel as? MessageContentModel, reply.isReplay == true { + type = .reply replyText = ReplyMessageUtil.textForReplyModel(model: reply) - if let t = replyText { - let size = String.getTextRectSize( - t, - font: UIFont.systemFont(ofSize: 12.0), - size: CGSize( - width: qChat_content_maxW, - height: CGFloat.greatestFiniteMagnitude - ) - ) - var width = size.width - if replyedModel?.type == .location { - let locationMinWidth: CGFloat = 76 - if width < locationMinWidth { - width = locationMinWidth - } - } - contentSize = CGSize( - width: max(contentSize.width, width), - height: contentSize.height + chat_reply_height - ) - height = Float(contentSize.height + qChat_margin) + fullNameHeight - } + // height 计算移至 getMessageModel(model:) } } } @@ -70,15 +55,15 @@ public class MessageContentModel: NSObject, MessageModel { } // 只有文本消息,才计算可编辑按钮的宽度 if let isSend = message?.isOutgoingMsg, isSend, message?.messageType == .text, timeOut == false { - contentSize = CGSize(width: 218, height: qChat_min_h) + contentSize = CGSize(width: 218, height: chat_min_h) } else { - contentSize = CGSize(width: 130, height: qChat_min_h) + contentSize = CGSize(width: 130, height: chat_min_h) } - height = Float(contentSize.height + qChat_margin) + fullNameHeight + height = Float(contentSize.height + chat_content_margin) + fullNameHeight } else { type = .custom - contentSize = CGSize(width: 32.0, height: qChat_min_h) - height = Float(qChat_min_h + qChat_margin) + fullNameHeight + contentSize = CGSize(width: 32.0, height: chat_min_h) + height = Float(chat_min_h + chat_content_margin) + fullNameHeight } } } @@ -86,21 +71,19 @@ public class MessageContentModel: NSObject, MessageModel { public var isPined: Bool = false { didSet { if isPined { - height = Float(contentSize.height + qChat_margin + chat_pin_height) + fullNameHeight + height = Float(contentSize.height + chat_content_margin) + fullNameHeight + Float(chat_pin_height) } else { - height = Float(contentSize.height + qChat_margin) + fullNameHeight + height = Float(contentSize.height + chat_content_margin) + fullNameHeight } } } public required init(message: NIMMessage?) { self.message = message - contentSize = CGSize(width: 32.0, height: qChat_min_h) if message?.session?.sessionType == .team, - !IMKitEngine.instance.isMySelf(message?.from) { + !IMKitClient.instance.isMySelf(message?.from) { fullNameHeight = 20 } print("self.fullNameHeight\(fullNameHeight)") - height = Float(qChat_min_h + qChat_margin) + fullNameHeight } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageFileModel.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageFileModel.swift index 2318fc83..9ac8dc78 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageFileModel.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageFileModel.swift @@ -28,6 +28,6 @@ class MessageFileModel: MessageContentModel { fileLength = fileObject.fileLength } contentSize = chat_file_size - height = Float(contentSize.height + qChat_margin) + fullNameHeight + height = Float(contentSize.height + chat_content_margin) + fullNameHeight } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageImageModel.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageImageModel.swift index 8f1635d6..bb018124 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageImageModel.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageImageModel.swift @@ -19,13 +19,13 @@ class MessageImageModel: MessageContentModel { imageUrl = imageObject.url } contentSize = ChatMessageHelper.getSizeWithMaxSize( - qChat_pic_size, + chat_pic_size, size: imageObject.size, - miniWH: qChat_min_h + miniWH: chat_min_h ) } else { - contentSize = qChat_pic_size + contentSize = chat_pic_size } - height = Float(contentSize.height + qChat_margin) + fullNameHeight + height = Float(contentSize.height + chat_content_margin) + fullNameHeight } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageLocationModel.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageLocationModel.swift index 12bb9e75..0898fc28 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageLocationModel.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageLocationModel.swift @@ -20,6 +20,6 @@ class MessageLocationModel: MessageContentModel { title = message?.text contentSize = CGSize(width: 242, height: 140) } - height = Float(contentSize.height + qChat_margin) + fullNameHeight + height = Float(contentSize.height + chat_content_margin) + fullNameHeight } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageModel.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageModel.swift index 45c68297..23a2041d 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageModel.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageModel.swift @@ -48,4 +48,8 @@ public protocol MessageModel: NSObjectProtocol { var isReplay: Bool { get set } init(message: NIMMessage?) + + var offset: CGFloat { get set } + + func cellHeight() -> CGFloat } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageReplyModel.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageReplyModel.swift deleted file mode 100644 index 70c5967f..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageReplyModel.swift +++ /dev/null @@ -1,41 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import Foundation -import NIMSDK - -@objcMembers -class MessageReplyModel: MessageContentModel { - let targetHeight = 26.0 - public var text: String? - public var targetText: String? - public var targetMessage: NIMMessage? - required init(message: NIMMessage?, targetMessage: NIMMessage?) { - super.init(message: message) - self.targetMessage = targetMessage - type = .reply - text = message?.text -// targetText = "|" + targetMessage?.from + ": " - let textSize = String.getTextRectSize( - text ?? "", - font: DefaultTextFont(16), - size: CGSize(width: qChat_content_maxW, height: CGFloat.greatestFiniteMagnitude) - ) - var h = qChat_min_h - if textSize.height > qChat_min_h { - h = textSize.height + 32 + targetHeight - } - contentSize = CGSize(width: textSize.width + qChat_cell_margin * 2, height: h) - height = Float(contentSize.height + qChat_margin) + fullNameHeight - } - - public required init(message: NIMMessage?) { - fatalError("init(message:) has not been implemented") - } - -// func replyTextWithMessage(_ message:) -> <#return type#> { -// <#function body#> -// } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageTextModel.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageTextModel.swift index e13faeea..b0afadef 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageTextModel.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageTextModel.swift @@ -36,15 +36,10 @@ class MessageTextModel: MessageContentModel { } } - let textSize = NEChatUITool.getSizeWithAtt( - att: attributeStr ?? NSAttributedString(string: ""), - font: NEKitChatConfig.shared.ui.messageTextSize, - maxSize: CGSize(width: qChat_content_maxW, height: CGFloat.greatestFiniteMagnitude) - ) + let textSize = attributeStr?.finalSize(NEKitChatConfig.shared.ui.messageTextSize, CGSize(width: chat_text_maxW, height: CGFloat.greatestFiniteMagnitude)) ?? .zero + textHeight = textSize.height - var h = qChat_min_h - h = textSize.height + 24 - contentSize = CGSize(width: textSize.width + qChat_margin * 2, height: h) - height = Float(contentSize.height + qChat_margin) + fullNameHeight + contentSize = CGSize(width: textSize.width + chat_content_margin * 2, height: textHeight + chat_content_margin * 2) + height = Float(contentSize.height + chat_content_margin) + fullNameHeight } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageTipsModel.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageTipsModel.swift index 0ae12fc7..98a36570 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageTipsModel.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageTipsModel.swift @@ -8,6 +8,12 @@ import NIMSDK @objcMembers class MessageTipsModel: NSObject, MessageModel { + var offset: CGFloat = 0 + + func cellHeight() -> CGFloat { + CGFloat(height) + offset + } + var tipTimeStamp: TimeInterval? var isReplay: Bool = false @@ -20,8 +26,8 @@ class MessageTipsModel: NSObject, MessageModel { var replyText: String? var type: MessageType = .tip var message: NIMMessage? - var contentSize: CGSize - var height: Float + var contentSize: CGSize = .zero + var height: Float = 28 var shortName: String? var fullName: String? var avatar: String? @@ -30,7 +36,8 @@ class MessageTipsModel: NSObject, MessageModel { var replyedModel: MessageModel? var isRevokedText: Bool = false weak var tipMessage: NIMMessage? - required init(message: NIMMessage?) { + + func commonInit(message: NIMMessage?) { if let msg = message { if msg.messageType == .notification { text = NotificationMessageUtils.textForNotification(message: msg) @@ -39,11 +46,37 @@ class MessageTipsModel: NSObject, MessageModel { text = msg.text type = .tip } + + tipMessage = msg + tipTimeStamp = msg.timestamp + } + + var font: UIFont = .systemFont(ofSize: NEKitChatConfig.shared.ui.timeTextSize) + + contentSize = String.getTextRectSize(text ?? "", + font: font, + size: CGSize(width: chat_text_maxW, height: CGFloat.greatestFiniteMagnitude)) + height = Float(max(contentSize.height + chat_content_margin, 28)) + } + + required init(message: NIMMessage?) { + super.init() + commonInit(message: message) + } + + init(message: NIMMessage?, initType: MessageType = .tip, initText: String? = nil) { + super.init() + type = initType + text = initText + commonInit(message: message) + } + + public func resetNotiText() { + if let msg = tipMessage { + if msg.messageType == .notification { + text = NotificationMessageUtils.textForNotification(message: msg) + type = .notification + } } - tipMessage = message - tipTimeStamp = message?.timestamp - contentSize = CGSize(width: kScreenWidth - 64 * 2, height: kScreenHeight) - let size = String.getTextRectSize(text ?? "", font: DefaultTextFont(NEKitChatConfig.shared.ui.timeTextSize), size: contentSize) - height = Float(size.height) } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageVideoModel.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageVideoModel.swift index 729e0c6b..82440a82 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageVideoModel.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/MessageVideoModel.swift @@ -24,13 +24,13 @@ class MessageVideoModel: MessageContentModel { if let videoObject = message?.messageObject as? NIMVideoObject { imageUrl = videoObject.url contentSize = ChatMessageHelper.getSizeWithMaxSize( - qChat_pic_size, + chat_pic_size, size: videoObject.coverSize, - miniWH: qChat_min_h + miniWH: chat_min_h ) } else { - contentSize = qChat_pic_size + contentSize = chat_pic_size } - height = Float(contentSize.height + qChat_margin) + fullNameHeight + height = Float(contentSize.height + chat_content_margin) + fullNameHeight } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/NEMoreItemModel.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/NEMoreItemModel.swift index 0b1518c3..fc38231d 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/NEMoreItemModel.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/NEMoreItemModel.swift @@ -12,7 +12,8 @@ public enum NEMoreActionType: Int { case game case file case remind - case other + case photo + case other = 100 } public class NEMoreItemModel: NSObject { @@ -26,7 +27,7 @@ public class NEMoreItemModel: NSObject { public var type: NEMoreActionType? // 代理类 - public var customDelegate: AnyObject? + public weak var customDelegate: AnyObject? // 动态事件 public var action: Selector? diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/OperationItem.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/OperationItem.swift index 2477964f..9aa565a4 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/OperationItem.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/Model/OperationItem.swift @@ -24,7 +24,7 @@ public class OperationItem: NSObject { public var imageName: String = "" public var type: OperationType? - static func copyItem() -> OperationItem { + public static func copyItem() -> OperationItem { let item = OperationItem() item.text = chatLocalizable("operation_copy") item.imageName = "op_copy" @@ -32,7 +32,7 @@ public class OperationItem: NSObject { return item } - static func replayItem() -> OperationItem { + public static func replayItem() -> OperationItem { let item = OperationItem() item.text = chatLocalizable("operation_replay") item.imageName = "op_replay" @@ -40,7 +40,7 @@ public class OperationItem: NSObject { return item } - static func forwardItem() -> OperationItem { + public static func forwardItem() -> OperationItem { let item = OperationItem() item.text = chatLocalizable("operation_forward") item.imageName = "op_forward" @@ -48,7 +48,7 @@ public class OperationItem: NSObject { return item } - static func pinItem() -> OperationItem { + public static func pinItem() -> OperationItem { let item = OperationItem() item.text = chatLocalizable("operation_pin") item.imageName = "op_pin" @@ -56,7 +56,7 @@ public class OperationItem: NSObject { return item } - static func removePinItem() -> OperationItem { + public static func removePinItem() -> OperationItem { let item = OperationItem() item.text = chatLocalizable("operation_cancel_pin") item.imageName = "op_pin" @@ -64,7 +64,7 @@ public class OperationItem: NSObject { return item } -// static func selectItem() -> OperationItem { +// static public func selectItem() -> OperationItem { // OperationItem( // text: chatLocalizable("operation_select"), // imageName: "op_select", @@ -72,7 +72,7 @@ public class OperationItem: NSObject { // ) // } -// static func collectionItem() -> OperationItem { +// static public func collectionItem() -> OperationItem { // OperationItem( // text: chatLocalizable("operation_collection"), // imageName: "op_collection", @@ -80,7 +80,7 @@ public class OperationItem: NSObject { // ) // } - static func deleteItem() -> OperationItem { + public static func deleteItem() -> OperationItem { let item = OperationItem() item.text = chatLocalizable("operation_delete") item.imageName = "op_delete" @@ -88,7 +88,7 @@ public class OperationItem: NSObject { return item } - static func recallItem() -> OperationItem { + public static func recallItem() -> OperationItem { let item = OperationItem() item.text = chatLocalizable("operation_recall") item.imageName = "op_recall" diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatAudioLeftCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatAudioLeftCell.swift deleted file mode 100644 index da308c9d..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatAudioLeftCell.swift +++ /dev/null @@ -1,75 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit - -@objcMembers -public class ChatAudioLeftCell: ChatBaseLeftCell, ChatAudioCell { - var isPlaying: Bool = false - var audioImageView = UIImageView(image: UIImage.ne_imageNamed(name: "left_play_3")) - var timeLabel = UILabel() - var messageId: String? - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - commonUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func commonUI() { - audioImageView.contentMode = .center - audioImageView.translatesAutoresizingMaskIntoConstraints = false - bubbleImage.addSubview(audioImageView) - NSLayoutConstraint.activate([ - audioImageView.leftAnchor.constraint(equalTo: bubbleImage.leftAnchor, constant: 16), - audioImageView.centerYAnchor.constraint(equalTo: bubbleImage.centerYAnchor), - audioImageView.widthAnchor.constraint(equalToConstant: 28), - audioImageView.heightAnchor.constraint(equalToConstant: 28), - ]) - - timeLabel.font = UIFont.systemFont(ofSize: 14) - timeLabel.textColor = UIColor.ne_darkText - timeLabel.textAlignment = .left - timeLabel.translatesAutoresizingMaskIntoConstraints = false - bubbleImage.addSubview(timeLabel) - NSLayoutConstraint.activate([ - timeLabel.leftAnchor.constraint(equalTo: audioImageView.rightAnchor, constant: 12), - timeLabel.centerYAnchor.constraint(equalTo: bubbleImage.centerYAnchor), - timeLabel.rightAnchor.constraint(equalTo: bubbleImage.rightAnchor, constant: -12), - timeLabel.heightAnchor.constraint(equalToConstant: 28), - ]) - audioImageView.animationDuration = 1 - if let leftImage1 = UIImage.ne_imageNamed(name: "left_play_1"), - let leftmage2 = UIImage.ne_imageNamed(name: "left_play_2"), - let leftmage3 = UIImage.ne_imageNamed(name: "left_play_3") { - audioImageView.animationImages = [leftImage1, leftmage2, leftmage3] - } - } - - func startAnimation() { - if !audioImageView.isAnimating { -// self.messageModel?.audioPlaying = true - audioImageView.startAnimating() - } - } - - func stopAnimation() { - if audioImageView.isAnimating { -// self.messageModel?.audioPlaying = false - audioImageView.stopAnimating() - } - } - - override open func setModel(_ model: MessageContentModel) { - super.setModel(model) - if let m = model as? MessageAudioModel { - timeLabel.text = "\(m.duration)" + "s" - m.isPlaying ? startAnimation() : stopAnimation() - messageId = m.message?.messageId - } - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatAudioRightCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatAudioRightCell.swift deleted file mode 100644 index 240dc6b4..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatAudioRightCell.swift +++ /dev/null @@ -1,89 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit - -protocol ChatAudioCell { - var isPlaying: Bool { get set } - var messageId: String? { get set } - func startAnimation() - func stopAnimation() -} - -@objcMembers -public class ChatAudioRightCell: ChatBaseRightCell, ChatAudioCell { - var messageId: String? - var isPlaying: Bool = false - var audioImageView = UIImageView(image: UIImage.ne_imageNamed(name: "audio_play")) - var timeLabel = UILabel() - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - commonUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func commonUI() { - audioImageView.contentMode = .center - audioImageView.translatesAutoresizingMaskIntoConstraints = false - bubbleImage.addSubview(audioImageView) - NSLayoutConstraint.activate([ - audioImageView.rightAnchor.constraint(equalTo: bubbleImage.rightAnchor, constant: -16), - audioImageView.centerYAnchor.constraint(equalTo: bubbleImage.centerYAnchor), - audioImageView.widthAnchor.constraint(equalToConstant: 28), - audioImageView.heightAnchor.constraint(equalToConstant: 28), - ]) - - timeLabel.font = UIFont.systemFont(ofSize: 14) - timeLabel.textColor = UIColor.ne_darkText - timeLabel.textAlignment = .right - timeLabel.translatesAutoresizingMaskIntoConstraints = false - bubbleImage.addSubview(timeLabel) - NSLayoutConstraint.activate([ - timeLabel.rightAnchor.constraint(equalTo: audioImageView.leftAnchor, constant: -12), - timeLabel.centerYAnchor.constraint(equalTo: bubbleImage.centerYAnchor), - timeLabel.heightAnchor.constraint(equalToConstant: 28), - ]) - - audioImageView.animationDuration = 1 - if let image1 = UIImage.ne_imageNamed(name: "play_1"), - let image2 = UIImage.ne_imageNamed(name: "play_2"), - let image3 = UIImage.ne_imageNamed(name: "play_3") { - audioImageView.animationImages = [image1, image2, image3] - } - } - - func startAnimation() { - if !audioImageView.isAnimating { - audioImageView.startAnimating() - if let m = contentModel as? MessageAudioModel { - m.isPlaying = true - isPlaying = true - } - } - } - - func stopAnimation() { - if audioImageView.isAnimating { - audioImageView.stopAnimating() - if let m = contentModel as? MessageAudioModel { - m.isPlaying = false - isPlaying = false - } - } - } - - override open func setModel(_ model: MessageContentModel) { - super.setModel(model) - if let m = model as? MessageAudioModel { - timeLabel.text = "\(m.duration)" + "s" - m.isPlaying ? startAnimation() : stopAnimation() - messageId = m.message?.messageId - } - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatBaseLeftCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatBaseLeftCell.swift deleted file mode 100644 index 0554ad4e..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatBaseLeftCell.swift +++ /dev/null @@ -1,277 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NIMSDK -@objcMembers -public class ChatBaseLeftCell: NEChatBaseCell { - public var avatarImage = UIImageView() - public var nameLabel = UILabel() - public var fullNameLabel = UILabel() - public var bubbleImage = UIImageView() - public var activityView = ChatActivityIndicatorView() - public var seletedBtn = UIButton(type: .custom) - public var pinImage = UIImageView() - public var pinLabel = UILabel() - public var bubbleW: NSLayoutConstraint? - public weak var delegate: ChatBaseCellDelegate? - private let bubbleWidth = 32.0 - public var contentModel: MessageContentModel? - public var fullNameH: NSLayoutConstraint? - private var pinLabelH: NSLayoutConstraint? - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - baseCommonUI() - addGesture() - initSubviewsLayout() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func baseCommonUI() { - // avatar - selectionStyle = .none - backgroundColor = .white - avatarImage.layer.cornerRadius = 16 - avatarImage.backgroundColor = UIColor(hexString: "#537FF4") - avatarImage.translatesAutoresizingMaskIntoConstraints = false - avatarImage.clipsToBounds = true - avatarImage.isUserInteractionEnabled = true - avatarImage.contentMode = .scaleAspectFill - contentView.addSubview(avatarImage) - NSLayoutConstraint.activate([ - avatarImage.leftAnchor.constraint(equalTo: leftAnchor, constant: 16), - avatarImage.widthAnchor.constraint(equalToConstant: 32), - avatarImage.heightAnchor.constraint(equalToConstant: 32), - avatarImage.topAnchor.constraint(equalTo: topAnchor, constant: 4), - ]) - - // name - nameLabel.textAlignment = .center - nameLabel.translatesAutoresizingMaskIntoConstraints = false - nameLabel.font = UIFont.systemFont(ofSize: NEKitChatConfig.shared.ui.userNickTextSize) - nameLabel.textColor = NEKitChatConfig.shared.ui.userNickColor - contentView.addSubview(nameLabel) - NSLayoutConstraint.activate([ - nameLabel.leftAnchor.constraint(equalTo: avatarImage.leftAnchor), - nameLabel.rightAnchor.constraint(equalTo: avatarImage.rightAnchor), - nameLabel.topAnchor.constraint(equalTo: avatarImage.topAnchor), - nameLabel.bottomAnchor.constraint(equalTo: avatarImage.bottomAnchor), - ]) - - // name - fullNameLabel.translatesAutoresizingMaskIntoConstraints = false - fullNameLabel.font = UIFont.systemFont(ofSize: 12) - fullNameLabel.textColor = UIColor.ne_lightText - contentView.addSubview(fullNameLabel) - fullNameH = fullNameLabel.heightAnchor.constraint(equalToConstant: 0) - NSLayoutConstraint.activate([ - fullNameLabel.leftAnchor.constraint(equalTo: avatarImage.rightAnchor, constant: 8), - fullNameLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16), - fullNameLabel.topAnchor.constraint(equalTo: avatarImage.topAnchor), - fullNameH!, - ]) - -// bubbleImage - if let bgColor = NEKitChatConfig.shared.ui.receiveMessageBg { - bubbleImage.backgroundColor = bgColor - } else if let image = NEKitChatConfig.shared.ui.leftBubbleBg { - bubbleImage.image = image - .resizableImage(withCapInsets: UIEdgeInsets(top: 35, left: 25, bottom: 10, right: 25)) - } - bubbleImage.translatesAutoresizingMaskIntoConstraints = false - bubbleImage.isUserInteractionEnabled = true - contentView.addSubview(bubbleImage) - bubbleW = bubbleImage.widthAnchor.constraint(equalToConstant: bubbleWidth) - NSLayoutConstraint.activate([ - bubbleW!, - bubbleImage.leftAnchor.constraint(equalTo: avatarImage.rightAnchor, constant: 8), - bubbleImage.topAnchor.constraint(equalTo: fullNameLabel.bottomAnchor, constant: 0), -// self.bubbleImage.topAnchor.constraint(equalTo: self.topAnchor, constant: 4), - ]) - -// activityView - contentView.addSubview(activityView) - activityView.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - activityView.leftAnchor.constraint(equalTo: bubbleImage.rightAnchor, constant: 8), - activityView.centerYAnchor.constraint(equalTo: bubbleImage.centerYAnchor, constant: 0), - activityView.widthAnchor.constraint(equalToConstant: 25), - activityView.heightAnchor.constraint(equalToConstant: 25), - ]) - -// seletedBtn - contentView.addSubview(seletedBtn) - seletedBtn.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - seletedBtn.leftAnchor.constraint(equalTo: leftAnchor, constant: 16), - seletedBtn.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 0), - seletedBtn.widthAnchor.constraint(equalToConstant: 18), - seletedBtn.heightAnchor.constraint(equalToConstant: 18), - ]) - -// pinImage.image = UIImage.ne_imageNamed(name: "msg_pin") - pinImage.translatesAutoresizingMaskIntoConstraints = false - pinImage.contentMode = .scaleAspectFit - contentView.addSubview(pinImage) - NSLayoutConstraint.activate([ - pinImage.leftAnchor.constraint(equalTo: leftAnchor, constant: 16), - pinImage.widthAnchor.constraint(equalToConstant: 10), - pinImage.topAnchor.constraint(equalTo: bubbleImage.bottomAnchor, constant: 4), - pinImage.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -4), - ]) - - contentView.addSubview(pinLabel) - pinLabel.translatesAutoresizingMaskIntoConstraints = false - pinLabel.textAlignment = .left - pinLabel.font = UIFont.systemFont(ofSize: 12) - pinLabel.textColor = UIColor.ne_greenText - pinLabel.isHidden = true - pinLabelH = pinLabel.heightAnchor.constraint(equalToConstant: 0) - pinLabel.lineBreakMode = .byTruncatingMiddle - - NSLayoutConstraint.activate([ - pinLabel.topAnchor.constraint(equalTo: bubbleImage.bottomAnchor, constant: 4), - pinLabel.rightAnchor.constraint(equalTo: rightAnchor, constant: -16), - pinLabel.leftAnchor.constraint(equalTo: pinImage.rightAnchor, constant: 2), - pinLabelH!, - pinLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -4), - ]) - } - - func addGesture() { -// avatar - let tap = UITapGestureRecognizer(target: self, action: #selector(tapAvatar)) - avatarImage.addGestureRecognizer(tap) - - let avatarLongGesture = UILongPressGestureRecognizer(target: self, action: #selector(longPressAvatar)) - avatarImage.addGestureRecognizer(avatarLongGesture) - - let messageTap = UITapGestureRecognizer(target: self, action: #selector(tapMessage)) - bubbleImage.addGestureRecognizer(messageTap) - - let messageLongPress = UILongPressGestureRecognizer( - target: self, - action: #selector(longPress) - ) - bubbleImage.addGestureRecognizer(messageLongPress) - } - - func initSubviewsLayout() { - if NEKitChatConfig.shared.ui.avatarType == .rectangle { - avatarImage.layer.cornerRadius = NEKitChatConfig.shared.ui.avatarCornerRadius - } else if NEKitChatConfig.shared.ui.avatarType == .cycle { - avatarImage.layer.cornerRadius = 16.0 - } - } - -// MARK: event - - func tapAvatar(tap: UITapGestureRecognizer) { - print(#function) - delegate?.didTapAvatarView(self, contentModel) - } - - func tapMessage(tap: UITapGestureRecognizer) { - print(#function) - delegate?.didTapMessageView(self, contentModel) - } - - func longPressAvatar(longPress: UITapGestureRecognizer) { - if longPress.state == .began { - delegate?.didLongPressAvatar(self, contentModel) - } - } - - func longPress(longPress: UILongPressGestureRecognizer) { - print(#function) - switch longPress.state { - case .began: - print("state:begin") - delegate?.didLongPressMessageView(self, contentModel) - case .changed: - print("state:changed") - case .ended: - print("state:ended") - case .cancelled: - print("state:cancelled") - case .failed: - print("state:failed") - default: - print("state:default") - } - } - -// MARK: set data - - override open func setModel(_ model: MessageContentModel) { - contentModel = model - updatePinStatus(model) - bubbleW?.constant = model.contentSize.width - // avatar - nameLabel.text = model.shortName - if model.fullNameHeight > 0 { - fullNameLabel.text = model.fullName - fullNameLabel.isHidden = false - } else { - fullNameLabel.text = nil - fullNameLabel.isHidden = true - } - fullNameH?.constant = CGFloat(model.fullNameHeight) - avatarImage.backgroundColor = UIColor - .colorWithString(string: model.message?.from) - if let avatarURL = model.avatar { - avatarImage - .sd_setImage(with: URL(string: avatarURL)) { [weak self] image, error, type, url in - if image != nil { - self?.avatarImage.image = image - self?.nameLabel.isHidden = true - } else { - self?.avatarImage.image = nil - self?.nameLabel.isHidden = false - } - } - } else { - avatarImage.image = nil - nameLabel.isHidden = false - } - switch model.message?.deliveryState { - case .delivering: - activityView.messageStatus = .sending - case .deliveried: - activityView.messageStatus = .successed - case .failed: - activityView.messageStatus = .failed - default: break - } - } - - private func updatePinStatus(_ model: MessageContentModel) { - pinLabel.isHidden = !model.isPined - pinImage.isHidden = !model.isPined - contentView.backgroundColor = model.isPined ? NEKitChatConfig.shared.ui - .signalBgColor : .white - if model.isPined { - let pinText = model.message?.session?.sessionType == .P2P ? chatLocalizable("pin_text_P2P") : chatLocalizable("pin_text_team") - if model.pinAccount == nil { - pinLabel.text = chatLocalizable("You") + pinText - } else if let account = model.pinAccount, account == NIMSDK.shared().loginManager.currentAccount() { - pinLabel.text = chatLocalizable("You") + pinText - } else if let text = model.pinShowName { - pinLabel.text = text + pinText - } - - pinImage.image = UIImage.ne_imageNamed(name: "msg_pin") - pinLabelH?.constant = chat_pin_height - - } else { - pinImage.image = nil - pinLabelH?.constant = 0 - } - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatBaseRightCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatBaseRightCell.swift deleted file mode 100644 index 25c56ed8..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatBaseRightCell.swift +++ /dev/null @@ -1,366 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NECoreIMKit -import NECoreKit -import NIMSDK -public protocol ChatBaseCellDelegate: NSObjectProtocol { - func didTapAvatarView(_ cell: UITableViewCell, _ model: MessageContentModel?) - func didTapMessageView(_ cell: UITableViewCell, _ model: MessageContentModel?) - func didLongPressMessageView(_ cell: UITableViewCell, _ model: MessageContentModel?) - func didTapResendView(_ cell: UITableViewCell, _ model: MessageContentModel?) -// reedit button event on revokecell - func didTapReeditButton(_ cell: UITableViewCell, _ model: MessageContentModel?) - func didTapReadView(_ cell: UITableViewCell, _ model: MessageContentModel?) - func didLongPressAvatar(_ cell: UITableViewCell, _ model: MessageContentModel?) -} - -@objcMembers -public class ChatBaseRightCell: NEChatBaseCell { - public var pinImage = UIImageView() - public var avatarImage = UIImageView() - public var nameLabel = UILabel() - public var bubbleImage = UIImageView() - public var activityView = ChatActivityIndicatorView() - public var readView = CirleProgressView(frame: CGRect(x: 0, y: 0, width: 16, height: 16)) - public var seletedBtn = UIButton(type: .custom) - public var pinLabel = UILabel() - public var bubbleW: NSLayoutConstraint? - public weak var delegate: ChatBaseCellDelegate? - public var contentModel: MessageContentModel? - private let bubbleWidth = 32.0 - private var pinLabelW: NSLayoutConstraint? - private var pinLabelH: NSLayoutConstraint? - private var tapGesture: UITapGestureRecognizer? - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - baseCommonUI() - addGesture() - initSubviewsLayout() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func baseCommonUI() { - // avatar - selectionStyle = .none - backgroundColor = .white - avatarImage.layer.cornerRadius = 16 - avatarImage.backgroundColor = UIColor(hexString: "#537FF4") - avatarImage.translatesAutoresizingMaskIntoConstraints = false - avatarImage.clipsToBounds = true - avatarImage.isUserInteractionEnabled = true - avatarImage.contentMode = .scaleAspectFill - contentView.addSubview(avatarImage) - NSLayoutConstraint.activate([ - avatarImage.rightAnchor.constraint(equalTo: rightAnchor, constant: -16), - avatarImage.widthAnchor.constraint(equalToConstant: 32), - avatarImage.heightAnchor.constraint(equalToConstant: 32), - avatarImage.topAnchor.constraint(equalTo: topAnchor, constant: 4), - ]) - - // name - nameLabel.textAlignment = .center - nameLabel.translatesAutoresizingMaskIntoConstraints = false - nameLabel.font = UIFont.systemFont(ofSize: NEKitChatConfig.shared.ui.userNickTextSize) - nameLabel.textColor = NEKitChatConfig.shared.ui.userNickColor - contentView.addSubview(nameLabel) - NSLayoutConstraint.activate([ - nameLabel.leftAnchor.constraint(equalTo: avatarImage.leftAnchor), - nameLabel.rightAnchor.constraint(equalTo: avatarImage.rightAnchor), - nameLabel.topAnchor.constraint(equalTo: avatarImage.topAnchor), - nameLabel.bottomAnchor.constraint(equalTo: avatarImage.bottomAnchor), - ]) - -// bubbleImage - if let bgColor = NEKitChatConfig.shared.ui.selfMessageBg { - bubbleImage.backgroundColor = bgColor - } else if let image = NEKitChatConfig.shared.ui.rightBubbleBg { - bubbleImage.image = image - .resizableImage(withCapInsets: UIEdgeInsets(top: 35, left: 25, bottom: 10, right: 25)) - } - bubbleImage.translatesAutoresizingMaskIntoConstraints = false - bubbleImage.isUserInteractionEnabled = true - contentView.addSubview(bubbleImage) - let top = NSLayoutConstraint( - item: bubbleImage, - attribute: .top, - relatedBy: .equal, - toItem: contentView, - attribute: .top, - multiplier: 1.0, - constant: 4 - ) - let right = NSLayoutConstraint( - item: bubbleImage, - attribute: .right, - relatedBy: .equal, - toItem: avatarImage, - attribute: .left, - multiplier: 1.0, - constant: -8 - ) - bubbleW = NSLayoutConstraint( - item: bubbleImage, - attribute: .width, - relatedBy: .equal, - toItem: nil, - attribute: .notAnAttribute, - multiplier: 1.0, - constant: bubbleWidth - ) - contentView.addConstraints([top, right]) - bubbleImage.addConstraint(bubbleW!) - -// activityView - contentView.addSubview(activityView) - activityView.translatesAutoresizingMaskIntoConstraints = false - activityView.failBtn.addTarget(self, action: #selector(resend), for: .touchUpInside) - NSLayoutConstraint.activate([ - activityView.rightAnchor.constraint(equalTo: bubbleImage.leftAnchor, constant: -8), - activityView.centerYAnchor.constraint(equalTo: bubbleImage.centerYAnchor, constant: 0), - activityView.widthAnchor.constraint(equalToConstant: 25), - activityView.heightAnchor.constraint(equalToConstant: 25), - ]) - -// readView - contentView.addSubview(readView) - readView.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - readView.rightAnchor.constraint(equalTo: bubbleImage.leftAnchor, constant: -8), - readView.bottomAnchor.constraint(equalTo: bubbleImage.bottomAnchor, constant: 0), - readView.widthAnchor.constraint(equalToConstant: 16), - readView.heightAnchor.constraint(equalToConstant: 16), - ]) - -// seletedBtn - contentView.addSubview(seletedBtn) - seletedBtn.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - seletedBtn.leftAnchor.constraint(equalTo: leftAnchor, constant: 16), - seletedBtn.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 0), - seletedBtn.widthAnchor.constraint(equalToConstant: 18), - seletedBtn.heightAnchor.constraint(equalToConstant: 18), - ]) - - contentView.addSubview(pinLabel) - pinLabel.translatesAutoresizingMaskIntoConstraints = false - pinLabel.textColor = UIColor.ne_greenText - pinLabel.font = UIFont.systemFont(ofSize: 12) - pinLabel.textAlignment = .right - pinLabel.lineBreakMode = .byTruncatingMiddle - - pinLabelW = pinLabel.widthAnchor.constraint(equalToConstant: 210) - pinLabelH = pinLabel.heightAnchor.constraint(equalToConstant: 0) - - NSLayoutConstraint.activate([ - pinLabel.topAnchor.constraint(equalTo: bubbleImage.bottomAnchor, constant: 4), - pinLabel.rightAnchor.constraint(equalTo: bubbleImage.rightAnchor, constant: 0), - pinLabelW!, - pinLabelH!, - pinLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -4), - ]) - - pinImage.translatesAutoresizingMaskIntoConstraints = false - pinImage.contentMode = .scaleAspectFit - contentView.addSubview(pinImage) - NSLayoutConstraint.activate([ - pinImage.topAnchor.constraint(equalTo: bubbleImage.bottomAnchor, constant: 4), - pinImage.widthAnchor.constraint(equalToConstant: 10), - pinImage.rightAnchor.constraint(equalTo: pinLabel.leftAnchor, constant: -2), - pinImage.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -4), - ]) - } - - func addGesture() { -// avatar - let tap = UITapGestureRecognizer(target: self, action: #selector(tapAvatar)) - avatarImage.addGestureRecognizer(tap) - - let messageTap = UITapGestureRecognizer(target: self, action: #selector(tapMessage)) - bubbleImage.addGestureRecognizer(messageTap) - - let messageLongPress = UILongPressGestureRecognizer( - target: self, - action: #selector(longPress) - ) -// messageLongPress.minimumPressDuration - bubbleImage.addGestureRecognizer(messageLongPress) - - let tapReadView = UITapGestureRecognizer(target: self, action: #selector(tapReadView)) - readView.addGestureRecognizer(tapReadView) - tapGesture = tapReadView - } - - func initSubviewsLayout() { - if NEKitChatConfig.shared.ui.avatarType == .rectangle { - avatarImage.layer.cornerRadius = NEKitChatConfig.shared.ui.avatarCornerRadius - } else if NEKitChatConfig.shared.ui.avatarType == .cycle { - avatarImage.layer.cornerRadius = 16.0 - } - } - -// MARK: event - - func tapAvatar(tap: UITapGestureRecognizer) { - print(#function) - delegate?.didTapAvatarView(self, contentModel) - } - - func tapMessage(tap: UITapGestureRecognizer) { - print(#function) - delegate?.didTapMessageView(self, contentModel) - } - - func longPress(longPress: UILongPressGestureRecognizer) { - print(#function) - switch longPress.state { - case .began: - print("state:begin") - delegate?.didLongPressMessageView(self, contentModel) - case .changed: - print("state:changed") - case .ended: - print("state:ended") - case .cancelled: - print("state:cancelled") - case .failed: - print("state:failed") - default: - print("state:default") - } - } - - func resend(button: UIButton) { - print("state:default") - delegate?.didTapResendView(self, contentModel) - } - - func tapReadView(tap: UITapGestureRecognizer) { - print(#function) - delegate?.didTapReadView(self, contentModel) - } - -// MARK: set data - - override open func setModel(_ model: MessageContentModel) { - contentModel = model - updatePinStatus(model) - tapGesture?.isEnabled = true - bubbleW?.constant = model.contentSize.width -// print("set model width : ", model.contentSize.width) - // avatar - nameLabel.text = model.shortName - avatarImage.backgroundColor = UIColor - .colorWithString(string: model.message?.from) - if let avatarURL = model.avatar { - avatarImage - .sd_setImage(with: URL(string: avatarURL)) { [weak self] image, error, type, url in - if error == nil { - self?.nameLabel.isHidden = true - } else { - self?.nameLabel.isHidden = false - } - } - } else { - avatarImage.image = nil - nameLabel.isHidden = false - } - switch model.message?.deliveryState { - case .delivering: - activityView.messageStatus = .sending - case .deliveried: - // 同一个账号,在多端登录,被对方拉黑,需要根据isBlackListed判断,进而更新信息状态 - if let isBlackMsg = model.message?.isBlackListed, isBlackMsg { - activityView.messageStatus = .failed - } else { - activityView.messageStatus = .successed - } - case .failed: - activityView.messageStatus = .failed - default: break - } - - if model.message?.deliveryState == .deliveried { - if model.message?.session?.sessionType == .P2P { - let receiptEnable = model.message?.setting?.teamReceiptEnabled ?? false - if receiptEnable, - IMKitClient.instance.repo.getShowReadStatus() == true { - readView.isHidden = false - if let read = model.message?.isRemoteRead, read { - readView.progress = 1 - } else { - readView.progress = 0 - } - // 未读消息需要判断是否被拉黑,拉黑情况,已读未读状态不展示。 - if let isBlackMsg = model.message?.isBlackListed, isBlackMsg { - readView.isHidden = true - } else { - readView.isHidden = false - } - - } else { - readView.isHidden = true - } - - } else if model.message?.session?.sessionType == .team { - let receiptEnable = model.message?.setting?.teamReceiptEnabled ?? false - if receiptEnable, - IMKitClient.instance.repo.getShowReadStatus() == true { - readView.isHidden = false - let readCount = model.message?.teamReceiptInfo?.readCount ?? 0 - let unreadCount = model.message?.teamReceiptInfo?.unreadCount ?? 0 - let total = Float(readCount + unreadCount) - if total > 0 { - let progress = Float(readCount) / total - readView.progress = progress - if progress >= 1.0 { - tapGesture?.isEnabled = false - } - } else { - readView.progress = 0 - } - } else { - readView.isHidden = true - } - } - } else { - readView.isHidden = true - } - } - - private func updatePinStatus(_ model: MessageContentModel) { - pinLabel.isHidden = !model.isPined - pinImage.isHidden = !model.isPined - contentView.backgroundColor = model.isPined ? NEKitChatConfig.shared.ui - .signalBgColor : .white - if model.isPined { - let pinText = model.message?.session?.sessionType == .P2P ? chatLocalizable("pin_text_P2P") : chatLocalizable("pin_text_team") - if model.pinAccount == nil { - pinLabel.text = chatLocalizable("You") + pinText - } else if let account = model.pinAccount, account == NIMSDK.shared().loginManager.currentAccount() { - pinLabel.text = chatLocalizable("You") + pinText - } else if let text = model.pinShowName { - pinLabel.text = text + pinText - } - - pinImage.image = UIImage.ne_imageNamed(name: "msg_pin") - let size = String.getTextRectSize( - pinLabel.text ?? pinText, - font: UIFont.systemFont(ofSize: 12.0), - size: CGSize(width: kScreenWidth - 56 - 22, height: CGFloat.greatestFiniteMagnitude) - ) - pinLabelW?.constant = size.width + 1 - pinLabelH?.constant = chat_pin_height - } else { - pinImage.image = nil - pinLabelH?.constant = 0 - } - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatCallRecordLeftCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatCallRecordLeftCell.swift deleted file mode 100644 index 45f19726..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatCallRecordLeftCell.swift +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit - -@objcMembers -class ChatCallRecordLeftCell: ChatBaseLeftCell { - public let contentLabel = UILabel() - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - commonUI() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - - func commonUI() { - contentLabel.translatesAutoresizingMaskIntoConstraints = false - contentLabel.isEnabled = false - contentLabel.numberOfLines = 0 - contentLabel.isUserInteractionEnabled = false - contentLabel.font = DefaultTextFont(16) - contentLabel.backgroundColor = .clear - bubbleImage.addSubview(contentLabel) - NSLayoutConstraint.activate([ - contentLabel.rightAnchor.constraint(equalTo: bubbleImage.rightAnchor, constant: 0), - contentLabel.leftAnchor.constraint(equalTo: bubbleImage.leftAnchor, constant: 8), - contentLabel.topAnchor.constraint(equalTo: bubbleImage.topAnchor, constant: 0), - contentLabel.bottomAnchor.constraint(equalTo: bubbleImage.bottomAnchor, constant: 0), - ]) - } - - override open func setModel(_ model: MessageContentModel) { - super.setModel(model) - if let m = model as? MessageCallRecordModel { - contentLabel.attributedText = m.attributeStr - } - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatCallRecordRightCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatCallRecordRightCell.swift deleted file mode 100644 index 2ce17ec5..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatCallRecordRightCell.swift +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit - -@objcMembers -class ChatCallRecordRightCell: ChatBaseRightCell { - public let contentLabel = UILabel() - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - commonUI() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - - func commonUI() { - contentLabel.translatesAutoresizingMaskIntoConstraints = false - contentLabel.isEnabled = false - contentLabel.numberOfLines = 0 - contentLabel.isUserInteractionEnabled = false - contentLabel.font = DefaultTextFont(16) - contentLabel.backgroundColor = .clear - bubbleImage.addSubview(contentLabel) - NSLayoutConstraint.activate([ - contentLabel.rightAnchor.constraint(equalTo: bubbleImage.rightAnchor, constant: 0), - contentLabel.leftAnchor.constraint(equalTo: bubbleImage.leftAnchor, constant: 8), - contentLabel.topAnchor.constraint(equalTo: bubbleImage.topAnchor, constant: 0), - contentLabel.bottomAnchor.constraint(equalTo: bubbleImage.bottomAnchor, constant: 0), - ]) - - activityView.removeFromSuperview() - } - - override open func setModel(_ model: MessageContentModel) { - super.setModel(model) - if let m = model as? MessageCallRecordModel { - contentLabel.attributedText = m.attributeStr - } - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatFileLeftCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatFileLeftCell.swift deleted file mode 100644 index 5495898d..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatFileLeftCell.swift +++ /dev/null @@ -1,176 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NECommonKit -import NIMSDK - -@objcMembers -public class ChatFileLeftCell: ChatBaseLeftCell { - lazy var imgView: UIImageView = { - let view_img = UIImageView() - view_img.translatesAutoresizingMaskIntoConstraints = false - view_img.backgroundColor = .clear - return view_img - }() - - lazy var stateView: FileStateView = { - let state = FileStateView() - state.translatesAutoresizingMaskIntoConstraints = false - state.backgroundColor = .clear - return state - }() - - lazy var titleLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.isUserInteractionEnabled = false - label.numberOfLines = 1 - label.lineBreakMode = .byTruncatingMiddle - label.font = DefaultTextFont(14) - label.textAlignment = .left - return label - }() - - lazy var sizeLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.textColor = UIColor(hexString: "#999999") - label.font = NEConstant.defaultTextFont(10.0) - label.textAlignment = .left - return label - }() - - lazy var labelView: UIView = { - let view = UIView() - view.translatesAutoresizingMaskIntoConstraints = false - view.isUserInteractionEnabled = false - view.addSubview(titleLabel) - NSLayoutConstraint.activate([ - titleLabel.leftAnchor.constraint(equalTo: view.leftAnchor), - titleLabel.topAnchor.constraint(equalTo: view.topAnchor), - titleLabel.rightAnchor.constraint(equalTo: view.rightAnchor), - titleLabel.heightAnchor.constraint(equalToConstant: 18), - ]) - view.addSubview(sizeLabel) - NSLayoutConstraint.activate([ - sizeLabel.leftAnchor.constraint(equalTo: view.leftAnchor), - sizeLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 5), - sizeLabel.rightAnchor.constraint(equalTo: view.rightAnchor), - sizeLabel.heightAnchor.constraint(equalToConstant: 10), - ]) - return view - }() - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - setupUI() - bubbleImage.image = nil - bubbleImage.layer.cornerRadius = 8 - bubbleImage.layer.borderColor = UIColor.ne_borderColor.cgColor - bubbleImage.layer.borderWidth = 1 - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func setupUI() { - addSubview(imgView) - NSLayoutConstraint.activate([ - imgView.leftAnchor.constraint(equalTo: bubbleImage.leftAnchor, constant: 10), - imgView.topAnchor.constraint(equalTo: bubbleImage.topAnchor, constant: 10), - imgView.widthAnchor.constraint(equalToConstant: 32), - imgView.heightAnchor.constraint(equalToConstant: 32), - ]) - - addSubview(stateView) - NSLayoutConstraint.activate([ - stateView.leftAnchor.constraint(equalTo: bubbleImage.leftAnchor, constant: 10), - stateView.topAnchor.constraint(equalTo: bubbleImage.topAnchor, constant: 10), - stateView.widthAnchor.constraint(equalToConstant: 32), - stateView.heightAnchor.constraint(equalToConstant: 32), - ]) - - addSubview(labelView) - NSLayoutConstraint.activate([ - labelView.leftAnchor.constraint(equalTo: imgView.rightAnchor, constant: 15), - labelView.topAnchor.constraint(equalTo: bubbleImage.topAnchor, constant: 10), - labelView.rightAnchor.constraint(equalTo: bubbleImage.rightAnchor, constant: -10), - labelView.bottomAnchor.constraint(equalTo: bubbleImage.bottomAnchor, constant: 0), - ]) - } - - override open func setModel(_ model: MessageContentModel) { - super.setModel(model) - if let fileObject = model.message?.messageObject as? NIMFileObject { - if let fileModel = model as? MessageFileModel { - fileModel.cell = self - fileModel.size = Float(fileObject.fileLength) - if fileModel.state == .Success { - stateView.state = .FileOpen - } else { - stateView.state = .FileDownload - stateView.setProgress(fileModel.progress) - if fileModel.progress >= 1 { - fileModel.state = .Success - } - } - } - var imageName = "file_unknown" - var displayName = "未知文件" - if let filePath = fileObject.path as? NSString { - displayName = filePath.lastPathComponent - switch filePath.pathExtension.lowercased() { - case file_doc_support: - imageName = "file_doc" - case file_xls_support: - imageName = "file_xls" - case file_img_support: - imageName = "file_img" - case file_ppt_support: - imageName = "file_ppt" - case file_txt_support: - imageName = "file_txt" - case file_audio_support: - imageName = "file_audio" - case file_vedio_support: - imageName = "file_vedio" - case file_zip_support: - imageName = "file_zip" - case file_pdf_support: - imageName = "file_pdf" - case file_html_support: - imageName = "file_html" - case "key", "keynote": - imageName = "file_keynote" - default: - imageName = "file_unknown" - } - } - imgView.image = UIImage.ne_imageNamed(name: imageName) - titleLabel.text = fileObject.displayName ?? displayName - let size_B = Double(fileObject.fileLength) - var size_str = String(format: "%.1f B", size_B) - if size_B > 1e3 { - let size_KB = size_B / 1e3 - size_str = String(format: "%.1f KB", size_KB) - if size_KB > 1e3 { - let size_MB = size_KB / 1e3 - size_str = String(format: "%.1f MB", size_MB) - if size_MB > 1e3 { - let size_GB = size_KB / 1e6 - size_str = String(format: "%.1f GB", size_GB) - } - } - } - sizeLabel.text = size_str - } - } - - override public func uploadProgress(_ progress: Float) { - stateView.setProgress(progress) - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatFileRightCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatFileRightCell.swift deleted file mode 100644 index f42c92cc..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatFileRightCell.swift +++ /dev/null @@ -1,176 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NECommonKit -import NIMSDK - -@objcMembers -public class ChatFileRightCell: ChatBaseRightCell { - lazy var imgView: UIImageView = { - let view_img = UIImageView() - view_img.translatesAutoresizingMaskIntoConstraints = false - view_img.backgroundColor = .clear - return view_img - }() - - lazy var stateView: FileStateView = { - let state = FileStateView() - state.translatesAutoresizingMaskIntoConstraints = false - state.backgroundColor = .clear - return state - }() - - lazy var titleLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.isUserInteractionEnabled = false - label.numberOfLines = 1 - label.lineBreakMode = .byTruncatingMiddle - label.font = DefaultTextFont(14) - label.textAlignment = .left - return label - }() - - lazy var sizeLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.textColor = UIColor(hexString: "#999999") - label.font = NEConstant.defaultTextFont(10.0) - label.textAlignment = .left - return label - }() - - lazy var labelView: UIView = { - let view = UIView() - view.translatesAutoresizingMaskIntoConstraints = false - view.isUserInteractionEnabled = false - view.addSubview(titleLabel) - NSLayoutConstraint.activate([ - titleLabel.leftAnchor.constraint(equalTo: view.leftAnchor), - titleLabel.topAnchor.constraint(equalTo: view.topAnchor), - titleLabel.rightAnchor.constraint(equalTo: view.rightAnchor), - titleLabel.heightAnchor.constraint(equalToConstant: 18), - ]) - view.addSubview(sizeLabel) - NSLayoutConstraint.activate([ - sizeLabel.leftAnchor.constraint(equalTo: view.leftAnchor), - sizeLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 5), - sizeLabel.rightAnchor.constraint(equalTo: view.rightAnchor), - sizeLabel.heightAnchor.constraint(equalToConstant: 10), - ]) - return view - }() - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - setupUI() - bubbleImage.image = nil - bubbleImage.layer.cornerRadius = 8 - bubbleImage.layer.borderColor = UIColor.ne_borderColor.cgColor - bubbleImage.layer.borderWidth = 1 - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func setupUI() { - addSubview(imgView) - NSLayoutConstraint.activate([ - imgView.leftAnchor.constraint(equalTo: bubbleImage.leftAnchor, constant: 10), - imgView.topAnchor.constraint(equalTo: bubbleImage.topAnchor, constant: 10), - imgView.widthAnchor.constraint(equalToConstant: 32), - imgView.heightAnchor.constraint(equalToConstant: 32), - ]) - - addSubview(stateView) - NSLayoutConstraint.activate([ - stateView.leftAnchor.constraint(equalTo: bubbleImage.leftAnchor, constant: 10), - stateView.topAnchor.constraint(equalTo: bubbleImage.topAnchor, constant: 10), - stateView.widthAnchor.constraint(equalToConstant: 32), - stateView.heightAnchor.constraint(equalToConstant: 32), - ]) - - addSubview(labelView) - NSLayoutConstraint.activate([ - labelView.leftAnchor.constraint(equalTo: imgView.rightAnchor, constant: 15), - labelView.topAnchor.constraint(equalTo: bubbleImage.topAnchor, constant: 10), - labelView.rightAnchor.constraint(equalTo: bubbleImage.rightAnchor, constant: -10), - labelView.bottomAnchor.constraint(equalTo: bubbleImage.bottomAnchor, constant: 0), - ]) - } - - override open func setModel(_ model: MessageContentModel) { - super.setModel(model) - if let fileObject = model.message?.messageObject as? NIMFileObject { - if let fileModel = model as? MessageFileModel { - fileModel.cell = self - fileModel.size = Float(fileObject.fileLength) - if fileModel.state == .Success { - stateView.state = .FileOpen - } else { - stateView.state = .FileDownload - stateView.setProgress(fileModel.progress) - if fileModel.progress >= 1 { - fileModel.state = .Success - } - } - } - var imageName = "file_unknown" - var displayName = "未知文件" - if let filePath = fileObject.path as? NSString { - displayName = filePath.lastPathComponent - switch filePath.pathExtension.lowercased() { - case file_doc_support: - imageName = "file_doc" - case file_xls_support: - imageName = "file_xls" - case file_img_support: - imageName = "file_img" - case file_ppt_support: - imageName = "file_ppt" - case file_txt_support: - imageName = "file_txt" - case file_audio_support: - imageName = "file_audio" - case file_vedio_support: - imageName = "file_vedio" - case file_zip_support: - imageName = "file_zip" - case file_pdf_support: - imageName = "file_pdf" - case file_html_support: - imageName = "file_html" - case "key", "keynote": - imageName = "file_keynote" - default: - imageName = "file_unknown" - } - } - imgView.image = UIImage.ne_imageNamed(name: imageName) - titleLabel.text = fileObject.displayName ?? displayName - let size_B = Double(fileObject.fileLength) - var size_str = String(format: "%.1f B", size_B) - if size_B > 1e3 { - let size_KB = size_B / 1e3 - size_str = String(format: "%.1f KB", size_KB) - if size_KB > 1e3 { - let size_MB = size_KB / 1e3 - size_str = String(format: "%.1f MB", size_MB) - if size_MB > 1e3 { - let size_GB = size_KB / 1e6 - size_str = String(format: "%.1f GB", size_GB) - } - } - } - sizeLabel.text = size_str - } - } - - override public func uploadProgress(_ progress: Float) { - stateView.setProgress(progress) - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatImageLeftCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatImageLeftCell.swift deleted file mode 100644 index 02e58761..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatImageLeftCell.swift +++ /dev/null @@ -1,61 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NIMSDK - -@objcMembers -public class ChatImageLeftCell: ChatBaseLeftCell { - public let contentImageView = UIImageView() - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - commonUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func commonUI() { - contentImageView.translatesAutoresizingMaskIntoConstraints = false - contentImageView.contentMode = .scaleAspectFill - contentImageView.clipsToBounds = true - contentImageView.addCustomCorner( - conrners: [.bottomLeft, .bottomRight, .topRight], - radius: 8, - backcolor: .white - ) - bubbleImage.addSubview(contentImageView) - NSLayoutConstraint.activate([ - contentImageView.rightAnchor.constraint(equalTo: bubbleImage.rightAnchor, constant: 0), - contentImageView.leftAnchor.constraint(equalTo: bubbleImage.leftAnchor, constant: 0), - contentImageView.topAnchor.constraint(equalTo: bubbleImage.topAnchor, constant: 0), - contentImageView.bottomAnchor.constraint( - equalTo: bubbleImage.bottomAnchor, - constant: 0 - ), - ]) - } - - override open func setModel(_ model: MessageContentModel) { - super.setModel(model) - if let m = model as? MessageImageModel, let imageUrl = m.imageUrl { - if imageUrl.hasPrefix("http") { - contentImageView.sd_setImage( - with: URL(string: imageUrl), - placeholderImage: nil, - options: .retryFailed, - progress: nil, - completed: nil - ) - } else { - contentImageView.image = UIImage(contentsOfFile: imageUrl) - } - - } else { - contentImageView.image = nil - } - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatImageRightCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatImageRightCell.swift deleted file mode 100644 index 3df475ff..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatImageRightCell.swift +++ /dev/null @@ -1,67 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NIMSDK - -@objcMembers -public class ChatImageRightCell: ChatBaseRightCell { - public let contentImageView = UIImageView() - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - commonUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func commonUI() { - contentImageView.translatesAutoresizingMaskIntoConstraints = false - contentImageView.contentMode = .scaleAspectFill - contentImageView.addCustomCorner( - conrners: [.topLeft, .bottomLeft, .bottomRight], - radius: 8, - backcolor: .white - ) - contentImageView.clipsToBounds = true - - bubbleImage.addSubview(contentImageView) - NSLayoutConstraint.activate([ - contentImageView.rightAnchor.constraint(equalTo: bubbleImage.rightAnchor, constant: 0), - contentImageView.leftAnchor.constraint(equalTo: bubbleImage.leftAnchor, constant: 0), - contentImageView.topAnchor.constraint(equalTo: bubbleImage.topAnchor, constant: 0), - contentImageView.bottomAnchor.constraint( - equalTo: bubbleImage.bottomAnchor, - constant: 0 - ), - ]) - } - - override open func setModel(_ model: MessageContentModel) { - super.setModel(model) - if let m = model as? MessageImageModel, let imageUrl = m.imageUrl { - if imageUrl.hasPrefix("http") { - contentImageView.sd_setImage( - with: URL(string: imageUrl), - placeholderImage: nil, - options: .retryFailed, - progress: nil, - completed: nil - ) - } else { - contentImageView.image = UIImage(contentsOfFile: imageUrl) - } - } - -// if let imageObject = model.message?.messageObject as? NIMImageObject { -// if let filePath = imageObject.path { -// contentImageView.image = UIImage.init(contentsOfFile: filePath) -// }else{ -// contentImageView.sd_setImage(with: URL.init(string: imageObject.url ?? ""), placeholderImage: nil, options: .retryFailed, progress: nil, completed: nil) -// } -// } - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatLocationLeftCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatLocationLeftCell.swift deleted file mode 100644 index 0dd892ff..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatLocationLeftCell.swift +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NEChatKit - -@objcMembers -class ChatLocationLeftCell: ChatBaseLeftCell { - private lazy var titleLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.textColor = UIColor.ne_darkText - label.font = UIFont.systemFont(ofSize: 16.0) - return label - }() - - private lazy var subTitleLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.textColor = UIColor.ne_lightText - label.font = UIFont.systemFont(ofSize: 12.0) - return label - }() - - private lazy var emptyLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.font = UIFont.systemFont(ofSize: 16) - label.text = chatLocalizable("no_map_plugin") - label.textAlignment = .center - label.textColor = UIColor.ne_greyText - return label - }() - - private var mapView: UIView? - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - commonUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func commonUI() { - let back = UIView() - back.backgroundColor = UIColor.white - contentView.addSubview(back) - bubbleImage.isHidden = true - back.translatesAutoresizingMaskIntoConstraints = false - back.clipsToBounds = true - back.layer.cornerRadius = 4 - back.layer.borderWidth = 1 - back.layer.borderColor = UIColor.ne_outlineColor.cgColor - - let messageLongPress = UILongPressGestureRecognizer( - target: self, - action: #selector(longPress) - ) - - back.addGestureRecognizer(messageLongPress) - NSLayoutConstraint.activate([ - back.leftAnchor.constraint(equalTo: bubbleImage.leftAnchor), - back.topAnchor.constraint(equalTo: bubbleImage.topAnchor), - back.rightAnchor.constraint(equalTo: bubbleImage.rightAnchor), - back.bottomAnchor.constraint(equalTo: bubbleImage.bottomAnchor), - ]) - - let messageTap = UITapGestureRecognizer(target: self, action: #selector(tapMessage)) - back.addGestureRecognizer(messageTap) - - back.addSubview(titleLabel) - NSLayoutConstraint.activate([ - titleLabel.leftAnchor.constraint(equalTo: back.leftAnchor, constant: 16), - titleLabel.rightAnchor.constraint(equalTo: back.rightAnchor, constant: -16), - titleLabel.topAnchor.constraint(equalTo: back.topAnchor, constant: 10), - ]) - - back.addSubview(subTitleLabel) - NSLayoutConstraint.activate([ - subTitleLabel.leftAnchor.constraint(equalTo: titleLabel.leftAnchor), - subTitleLabel.rightAnchor.constraint(equalTo: titleLabel.rightAnchor), - subTitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4), - ]) - - if let map = NEChatKitClient.instance.delegate?.getCellMapView?() as? UIView { - mapView = map - back.addSubview(map) - map.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - map.leftAnchor.constraint(equalTo: back.leftAnchor), - map.bottomAnchor.constraint(equalTo: back.bottomAnchor), - map.rightAnchor.constraint(equalTo: back.rightAnchor), - map.topAnchor.constraint(equalTo: subTitleLabel.bottomAnchor, constant: 4), - ]) - - let pointImage = UIImageView() - pointImage.translatesAutoresizingMaskIntoConstraints = false - pointImage.image = coreLoader.loadImage("location_point") - map.addSubview(pointImage) - NSLayoutConstraint.activate([ - pointImage.centerXAnchor.constraint(equalTo: map.centerXAnchor), - pointImage.bottomAnchor.constraint(equalTo: map.bottomAnchor, constant: -30), - ]) - } else { - back.addSubview(emptyLabel) - NSLayoutConstraint.activate([ - emptyLabel.leftAnchor.constraint(equalTo: back.leftAnchor), - emptyLabel.rightAnchor.constraint(equalTo: back.rightAnchor), - emptyLabel.bottomAnchor.constraint(equalTo: back.bottomAnchor, constant: -40), - ]) - } - } - - override open func setModel(_ model: MessageContentModel) { - super.setModel(model) - if let m = model as? MessageLocationModel { - titleLabel.text = m.title - subTitleLabel.text = m.subTitle - if let lat = m.lat, let lng = m.lng, let map = mapView { - NEChatKitClient.instance.delegate?.setMapviewLocation?(lat: lat, lng: lng, mapview: map) - } - } - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatLocationRightCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatLocationRightCell.swift deleted file mode 100644 index 3fee7ecf..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatLocationRightCell.swift +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NEChatKit - -@objcMembers -class ChatLocationRightCell: ChatBaseRightCell { - private lazy var titleLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.textColor = UIColor.ne_darkText - label.font = UIFont.systemFont(ofSize: 16.0) - return label - }() - - private lazy var subTitleLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.textColor = UIColor.ne_lightText - label.font = UIFont.systemFont(ofSize: 12.0) - return label - }() - - private lazy var emptyLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.font = UIFont.systemFont(ofSize: 16) - label.text = chatLocalizable("no_map_plugin") - label.textAlignment = .center - label.textColor = UIColor.ne_greyText - return label - }() - - private var mapView: UIView? - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - commonUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func commonUI() { - let back = UIView() - back.backgroundColor = UIColor.white - contentView.addSubview(back) - bubbleImage.isHidden = true - back.translatesAutoresizingMaskIntoConstraints = false - back.clipsToBounds = true - back.layer.cornerRadius = 4 - back.layer.borderWidth = 1 - back.layer.borderColor = UIColor.ne_outlineColor.cgColor - let messageLongPress = UILongPressGestureRecognizer( - target: self, - action: #selector(longPress) - ) - - back.addGestureRecognizer(messageLongPress) - NSLayoutConstraint.activate([ - back.leftAnchor.constraint(equalTo: bubbleImage.leftAnchor), - back.topAnchor.constraint(equalTo: bubbleImage.topAnchor), - back.rightAnchor.constraint(equalTo: bubbleImage.rightAnchor), - back.bottomAnchor.constraint(equalTo: bubbleImage.bottomAnchor), - ]) - let messageTap = UITapGestureRecognizer(target: self, action: #selector(tapMessage)) - back.addGestureRecognizer(messageTap) - - back.addSubview(titleLabel) - NSLayoutConstraint.activate([ - titleLabel.leftAnchor.constraint(equalTo: back.leftAnchor, constant: 16), - titleLabel.rightAnchor.constraint(equalTo: back.rightAnchor, constant: -16), - titleLabel.topAnchor.constraint(equalTo: back.topAnchor, constant: 10), - ]) - - back.addSubview(subTitleLabel) - NSLayoutConstraint.activate([ - subTitleLabel.leftAnchor.constraint(equalTo: titleLabel.leftAnchor), - subTitleLabel.rightAnchor.constraint(equalTo: titleLabel.rightAnchor), - subTitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4), - ]) - - if let map = NEChatKitClient.instance.delegate?.getCellMapView?() as? UIView { - mapView = map - back.addSubview(map) - map.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - map.leftAnchor.constraint(equalTo: back.leftAnchor), - map.bottomAnchor.constraint(equalTo: back.bottomAnchor), - map.rightAnchor.constraint(equalTo: back.rightAnchor), - map.topAnchor.constraint(equalTo: subTitleLabel.bottomAnchor, constant: 4), - ]) - - let pointImage = UIImageView() - pointImage.translatesAutoresizingMaskIntoConstraints = false - pointImage.image = coreLoader.loadImage("location_point") - map.addSubview(pointImage) - NSLayoutConstraint.activate([ - pointImage.centerXAnchor.constraint(equalTo: map.centerXAnchor), - pointImage.bottomAnchor.constraint(equalTo: map.bottomAnchor, constant: -30), - ]) - } else { - back.addSubview(emptyLabel) - NSLayoutConstraint.activate([ - emptyLabel.leftAnchor.constraint(equalTo: back.leftAnchor), - emptyLabel.rightAnchor.constraint(equalTo: back.rightAnchor), - emptyLabel.bottomAnchor.constraint(equalTo: back.bottomAnchor, constant: -40), - ]) - } - } - - override open func setModel(_ model: MessageContentModel) { - super.setModel(model) - if let m = model as? MessageLocationModel { - titleLabel.text = m.title - subTitleLabel.text = m.subTitle - if let lat = m.lat, let lng = m.lng, let map = mapView { - NEChatKitClient.instance.delegate?.setMapviewLocation?(lat: lat, lng: lng, mapview: map) - } - } - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatReplyLeftCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatReplyLeftCell.swift deleted file mode 100644 index 62028219..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatReplyLeftCell.swift +++ /dev/null @@ -1,81 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit - -@objcMembers -public class ChatReplyLeftCell: ChatBaseLeftCell { - public let replyLabel = UILabel() - public let textView = UITextView() - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - commonUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func commonUI() { - replyLabel.font = UIFont.systemFont(ofSize: 12) - replyLabel.textColor = UIColor(hexString: "#929299") - replyLabel.translatesAutoresizingMaskIntoConstraints = false - addSubview(replyLabel) - NSLayoutConstraint.activate([ - replyLabel.leadingAnchor.constraint(equalTo: bubbleImage.leadingAnchor, constant: qChat_margin), - replyLabel.topAnchor.constraint(equalTo: bubbleImage.topAnchor, constant: qChat_margin - 1), - replyLabel.heightAnchor.constraint(equalToConstant: 26.0), - replyLabel.trailingAnchor.constraint(equalTo: bubbleImage.trailingAnchor, constant: -qChat_margin), - ]) - - textView.translatesAutoresizingMaskIntoConstraints = false - textView.isEditable = false - textView.isScrollEnabled = false - textView.showsVerticalScrollIndicator = false - textView.isUserInteractionEnabled = false - textView.textContainer.maximumNumberOfLines = 0 - textView.textContainerInset = .zero - textView.textContainer.lineFragmentPadding = 0 - textView.font = DefaultTextFont(16) - textView.backgroundColor = .red - textView.contentMode = .center - textView.backgroundColor = .clear - bubbleImage.addSubview(textView) - NSLayoutConstraint.activate([ - textView.rightAnchor.constraint(equalTo: bubbleImage.rightAnchor, constant: -qChat_margin), - textView.leftAnchor.constraint(equalTo: bubbleImage.leftAnchor, constant: qChat_margin), - textView.topAnchor.constraint(equalTo: replyLabel.bottomAnchor, constant: -(qChat_margin - 1)), - textView.bottomAnchor.constraint(equalTo: bubbleImage.bottomAnchor, constant: -qChat_margin), - ]) - } - - func sizeWidthFromString(_ text: String, _ font: UIFont) -> Double { - // 根据内容计算size - let maxSize = CGSize(width: qChat_content_maxW, height: 0) - let attibutes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font: font] - let labelSize = NSString(string: text).boundingRect(with: maxSize, attributes: attibutes, context: nil) - return ceil(labelSize.width) + qChat_margin * 2 - } - - override open func setModel(_ model: MessageContentModel) { - if let m = model as? MessageTextModel { - textView.attributedText = m.attributeStr - if let text = textView.attributedText, - let font = textView.font { - model.contentSize.width = max(sizeWidthFromString(text.string, font), model.contentSize.width) - } - } - - if let text = model.replyText, - let font = replyLabel.font { - replyLabel.attributedText = NEEmotionTool.getAttWithStr(str: text, - font: replyLabel.font, - color: replyLabel.textColor) - model.contentSize.width = max(sizeWidthFromString(text, font), model.contentSize.width) - } - - super.setModel(model) - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatReplyRightCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatReplyRightCell.swift deleted file mode 100644 index bd443f24..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatReplyRightCell.swift +++ /dev/null @@ -1,81 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit - -@objcMembers -public class ChatReplyRightCell: ChatBaseRightCell { - public let replyLabel = UILabel() - public let textView = UITextView() - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - commonUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func commonUI() { - replyLabel.font = UIFont.systemFont(ofSize: 12) - replyLabel.textColor = UIColor(hexString: "#929299") - replyLabel.translatesAutoresizingMaskIntoConstraints = false - addSubview(replyLabel) - NSLayoutConstraint.activate([ - replyLabel.leadingAnchor.constraint(equalTo: bubbleImage.leadingAnchor, constant: qChat_margin), - replyLabel.topAnchor.constraint(equalTo: bubbleImage.topAnchor, constant: qChat_margin - 1), - replyLabel.heightAnchor.constraint(equalToConstant: 26.0), - replyLabel.trailingAnchor.constraint(equalTo: bubbleImage.trailingAnchor, constant: -qChat_margin), - ]) - - textView.translatesAutoresizingMaskIntoConstraints = false - textView.isEditable = false - textView.isScrollEnabled = false - textView.showsVerticalScrollIndicator = false - textView.isUserInteractionEnabled = false - textView.textContainer.maximumNumberOfLines = 0 - textView.textContainerInset = .zero - textView.textContainer.lineFragmentPadding = 0 - textView.font = DefaultTextFont(16) - textView.backgroundColor = .red - textView.contentMode = .center - textView.backgroundColor = .clear - bubbleImage.addSubview(textView) - NSLayoutConstraint.activate([ - textView.rightAnchor.constraint(equalTo: bubbleImage.rightAnchor, constant: -qChat_margin), - textView.leftAnchor.constraint(equalTo: bubbleImage.leftAnchor, constant: qChat_margin), - textView.topAnchor.constraint(equalTo: replyLabel.bottomAnchor, constant: -(qChat_margin - 1)), - textView.bottomAnchor.constraint(equalTo: bubbleImage.bottomAnchor, constant: -qChat_margin), - ]) - } - - func sizeWidthFromString(_ text: String, _ font: UIFont) -> Double { - // 根据内容计算size - let maxSize = CGSize(width: qChat_content_maxW, height: 0) - let attibutes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font: font] - let labelSize = NSString(string: text).boundingRect(with: maxSize, attributes: attibutes, context: nil) - return ceil(labelSize.width) + qChat_margin * 2 - } - - override open func setModel(_ model: MessageContentModel) { - if let m = model as? MessageTextModel { - textView.attributedText = m.attributeStr - if let text = textView.attributedText, - let font = textView.font { - model.contentSize.width = max(sizeWidthFromString(text.string, font), model.contentSize.width) - } - } - - if let text = model.replyText, - let font = replyLabel.font { - replyLabel.attributedText = NEEmotionTool.getAttWithStr(str: text, - font: replyLabel.font, - color: replyLabel.textColor) - model.contentSize.width = max(sizeWidthFromString(text, font), model.contentSize.width) - } - - super.setModel(model) - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatRevokeLeftCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatRevokeLeftCell.swift deleted file mode 100644 index f464dd94..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatRevokeLeftCell.swift +++ /dev/null @@ -1,38 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit - -@objcMembers -public class ChatRevokeLeftCell: ChatBaseLeftCell { - public var label = UILabel() - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - commonUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func commonUI() { - label.translatesAutoresizingMaskIntoConstraints = false - label.textColor = UIColor.ne_greyText - label.font = UIFont.systemFont(ofSize: 16.0) - bubbleImage.addSubview(label) - NSLayoutConstraint.activate([ - label.leftAnchor.constraint(equalTo: bubbleImage.leftAnchor, constant: 16), - label.topAnchor.constraint(equalTo: bubbleImage.topAnchor, constant: 0), - label.heightAnchor.constraint(equalToConstant: qChat_min_h), - label.rightAnchor.constraint(equalTo: bubbleImage.rightAnchor, constant: -16), - label.bottomAnchor.constraint(equalTo: bubbleImage.bottomAnchor, constant: 0), - ]) - } - - override open func setModel(_ model: MessageContentModel) { - super.setModel(model) - label.text = chatLocalizable("message_has_be_withdrawn") - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatRevokeRightCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatRevokeRightCell.swift deleted file mode 100644 index 8d598ca6..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatRevokeRightCell.swift +++ /dev/null @@ -1,91 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit - -// protocol ChatRevokeRightCellDelegate: NEChatBaseCellDelegate { -// func onReeditMessage(_ cell: UITableViewCell, _ model: MessageContentModel?) -// } - -// typealias ReeditBlock = (_ cell: ChatRevokeRightCell, _ model: MessageContentModel?) -> () - -@objcMembers -public class ChatRevokeRightCell: ChatBaseRightCell { - public var label = UILabel() - public var reeditButton = UIButton(type: .custom) -// public var reeditBlock: ReeditBlock? -// public override var delegate: NEChatBaseCellDelegate? - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - commonUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func commonUI() { - label.translatesAutoresizingMaskIntoConstraints = false - label.textColor = UIColor.ne_greyText - label.font = UIFont.systemFont(ofSize: 16.0) - bubbleImage.addSubview(label) - NSLayoutConstraint.activate([ - label.leftAnchor.constraint(equalTo: bubbleImage.leftAnchor, constant: 16), - label.widthAnchor.constraint(equalToConstant: 100), - label.heightAnchor.constraint(equalToConstant: qChat_min_h), - label.topAnchor.constraint(equalTo: bubbleImage.topAnchor, constant: 0), - label.bottomAnchor.constraint(equalTo: bubbleImage.bottomAnchor, constant: 0), - ]) - - reeditButton.translatesAutoresizingMaskIntoConstraints = false - reeditButton.setImage(UIImage.ne_imageNamed(name: "right_arrow"), for: .normal) - reeditButton.titleLabel?.font = UIFont.systemFont(ofSize: 16.0) - reeditButton.setTitleColor(UIColor.ne_blueText, for: .normal) - reeditButton.titleEdgeInsets = UIEdgeInsets(top: 0, left: -30, bottom: 0, right: 0) - reeditButton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 70, bottom: 0, right: 0) - - bubbleImage.addSubview(reeditButton) - NSLayoutConstraint.activate([ - reeditButton.leftAnchor.constraint(equalTo: label.rightAnchor, constant: 8), - reeditButton.rightAnchor.constraint(equalTo: bubbleImage.rightAnchor, constant: -8), - reeditButton.topAnchor.constraint(equalTo: bubbleImage.topAnchor, constant: 0), - reeditButton.bottomAnchor.constraint(equalTo: bubbleImage.bottomAnchor, constant: 0), - ]) - reeditButton.addTarget(self, action: #selector(reeditEvent), for: .touchUpInside) - } - - override open func setModel(_ model: MessageContentModel) { - if let time = model.message?.timestamp { - let date = Date() - let currentTime = date.timeIntervalSince1970 - if currentTime - time >= 60 * 2 { - model.timeOut = true - } - } - if let isSend = model.message?.isOutgoingMsg, isSend, model.isRevokedText == true, model.timeOut == false { - model.contentSize = CGSize(width: 218, height: qChat_min_h) - } else { - model.contentSize = CGSize(width: 130, height: qChat_min_h) - } - super.setModel(model) - label.text = chatLocalizable("message_has_be_withdrawn") - reeditButton.setTitle(chatLocalizable("message_reedit"), for: .normal) - - if model.isRevokedText == true { - if model.timeOut == true { - reeditButton.isHidden = true - } else { - reeditButton.isHidden = false - } - } else { - reeditButton.isHidden = true - } - } - - func reeditEvent(button: UIButton) { - print(#function) - delegate?.didTapReeditButton(self, contentModel) - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatTextLeftCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatTextLeftCell.swift deleted file mode 100644 index 86db72ec..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatTextLeftCell.swift +++ /dev/null @@ -1,43 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit - -@objcMembers -public class ChatTextLeftCell: ChatBaseLeftCell { - public let contentLabel = UILabel() - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - commonUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func commonUI() { - contentLabel.translatesAutoresizingMaskIntoConstraints = false - contentLabel.isEnabled = false - contentLabel.numberOfLines = 0 - contentLabel.isUserInteractionEnabled = false - contentLabel.font = DefaultTextFont(16) - contentLabel.backgroundColor = .clear - contentLabel.textAlignment = .justified - bubbleImage.addSubview(contentLabel) - NSLayoutConstraint.activate([ - contentLabel.rightAnchor.constraint(equalTo: bubbleImage.rightAnchor, constant: -qChat_margin), - contentLabel.leftAnchor.constraint(equalTo: bubbleImage.leftAnchor, constant: qChat_margin), - contentLabel.topAnchor.constraint(equalTo: bubbleImage.topAnchor, constant: 0), - contentLabel.bottomAnchor.constraint(equalTo: bubbleImage.bottomAnchor, constant: 0), - ]) - } - - override open func setModel(_ model: MessageContentModel) { - super.setModel(model) - if let m = model as? MessageTextModel { - contentLabel.attributedText = m.attributeStr - } - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatTextRightCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatTextRightCell.swift deleted file mode 100644 index d8e002d8..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatTextRightCell.swift +++ /dev/null @@ -1,42 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit - -@objcMembers -public class ChatTextRightCell: ChatBaseRightCell { - public let contentLabel = UILabel() - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - commonUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func commonUI() { - contentLabel.translatesAutoresizingMaskIntoConstraints = false - contentLabel.isEnabled = false - contentLabel.isUserInteractionEnabled = false - contentLabel.numberOfLines = 0 - contentLabel.font = DefaultTextFont(16) - contentLabel.textAlignment = .justified - bubbleImage.addSubview(contentLabel) - NSLayoutConstraint.activate([ - contentLabel.rightAnchor.constraint(equalTo: bubbleImage.rightAnchor, constant: -qChat_margin), - contentLabel.leftAnchor.constraint(equalTo: bubbleImage.leftAnchor, constant: qChat_margin), - contentLabel.topAnchor.constraint(equalTo: bubbleImage.topAnchor, constant: 0), - contentLabel.bottomAnchor.constraint(equalTo: bubbleImage.bottomAnchor, constant: 0), - ]) - } - - override open func setModel(_ model: MessageContentModel) { - super.setModel(model) - if let m = model as? MessageTextModel { - contentLabel.attributedText = m.attributeStr - } - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatVideoLeftCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatVideoLeftCell.swift deleted file mode 100644 index e45cc282..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatVideoLeftCell.swift +++ /dev/null @@ -1,130 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NIMSDK - -@objcMembers -public class ChatVideoLeftCell: ChatImageLeftCell { - weak var weakModel: MessageVideoModel? - - lazy var stateView: VideoStateView = { - let state = VideoStateView() - state.translatesAutoresizingMaskIntoConstraints = false - state.backgroundColor = .clear - return state - }() - - lazy var timeLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.textColor = .white - label.font = NEConstant.defaultTextFont(10.0) - label.textAlignment = .center - return label - }() - - lazy var timeView: UIView = { - let view = UIView() - view.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(timeLabel) - NSLayoutConstraint.activate([ - timeLabel.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 4), - timeLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 2), - timeLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -4), - timeLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -2), - ]) - view.clipsToBounds = true - view.layer.cornerRadius = 4.0 - view.backgroundColor = NEConstant.hexRGB(0x000000).withAlphaComponent(0.6) - return view - }() - - override public func awakeFromNib() { - super.awakeFromNib() - // Initialization code - } - - override public func setSelected(_ selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - - // Configure the view for the selected state - } - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - setupUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func setupUI() { - contentImageView.addSubview(stateView) - contentImageView.addCustomCorner(conrners: [.topLeft], radius: 8, backcolor: .white) - NSLayoutConstraint.activate([ - stateView.centerXAnchor.constraint(equalTo: contentImageView.centerXAnchor), - stateView.centerYAnchor.constraint(equalTo: contentImageView.centerYAnchor), - stateView.heightAnchor.constraint(equalToConstant: 60), - stateView.widthAnchor.constraint(equalToConstant: 60), - ]) - - contentImageView.addSubview(timeView) - NSLayoutConstraint.activate([ - timeView.rightAnchor.constraint(equalTo: contentImageView.rightAnchor, constant: -7), - timeView.bottomAnchor.constraint(equalTo: contentImageView.bottomAnchor, constant: -7), - ]) - } - - override open func setModel(_ model: MessageContentModel) { - super.setModel(model) - if let videoObject = model.message?.messageObject as? NIMVideoObject { - if let path = videoObject.coverUrl { - contentImageView.sd_setImage( - with: URL(string: path), - placeholderImage: nil, - options: .retryFailed, - progress: nil, - completed: nil - ) - } else { - contentImageView.sd_setImage( - with: URL(string: videoObject.coverUrl ?? ""), - placeholderImage: nil, - options: .retryFailed, - progress: nil, - completed: nil - ) - } - - if videoObject.duration > 0 { - timeView.isHidden = false - timeLabel.text = Date.getFormatPlayTime(TimeInterval(videoObject.duration / 1000)) - } else { - timeView.isHidden = true - } - - if let videoModel = model as? MessageVideoModel { - weakModel?.cell = nil - weakModel = videoModel - videoModel.cell = self - if videoModel.state == .Success { - stateView.state = .VideoPlay - } else { - stateView.state = .VideoDownload - stateView.setProgress(videoModel.progress) - if videoModel.progress >= 1 { - videoModel.state = .Success - } - } - } - } - } - - override public func uploadProgress(_ progress: Float) { - stateView.setProgress(progress) - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatVideoRightCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatVideoRightCell.swift deleted file mode 100644 index b5ea9e8a..00000000 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatVideoRightCell.swift +++ /dev/null @@ -1,137 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NECommonKit -import NIMSDK - -@objcMembers -public class ChatVideoRightCell: ChatImageRightCell { - weak var weakModel: MessageVideoModel? - - lazy var stateView: VideoStateView = { - let state = VideoStateView() - state.translatesAutoresizingMaskIntoConstraints = false - state.backgroundColor = .clear - return state - }() - - lazy var timeLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.textColor = .white - label.font = NEConstant.defaultTextFont(10.0) - label.textAlignment = .center - return label - }() - - lazy var timeView: UIView = { - let view = UIView() - view.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(timeLabel) - NSLayoutConstraint.activate([ - timeLabel.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 4), - timeLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 2), - timeLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -4), - timeLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -2), - ]) - view.clipsToBounds = true - view.layer.cornerRadius = 4.0 - view.backgroundColor = NEConstant.hexRGB(0x000000).withAlphaComponent(0.6) - return view - }() - - override public func awakeFromNib() { - super.awakeFromNib() - // Initialization code - } - - override public func setSelected(_ selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - - // Configure the view for the selected state - } - -// override func draw(_ rect: CGRect) { -// super.draw(rect) -// bubbleImage.addCorner(conrners: .allCorners ,radius: 8) -// contentImageView.addCorner(conrners: .allCorners, radius: 8) -// } - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - setupUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func setupUI() { - contentImageView.addSubview(stateView) - contentImageView.addCustomCorner(conrners: [.topRight], radius: 8, backcolor: .white) - NSLayoutConstraint.activate([ - stateView.centerXAnchor.constraint(equalTo: contentImageView.centerXAnchor), - stateView.centerYAnchor.constraint(equalTo: contentImageView.centerYAnchor), - stateView.heightAnchor.constraint(equalToConstant: 60), - stateView.widthAnchor.constraint(equalToConstant: 60), - ]) - - contentImageView.addSubview(timeView) - NSLayoutConstraint.activate([ - timeView.rightAnchor.constraint(equalTo: contentImageView.rightAnchor, constant: -7), - timeView.bottomAnchor.constraint(equalTo: contentImageView.bottomAnchor, constant: -7), - ]) - } - - override open func setModel(_ model: MessageContentModel) { - super.setModel(model) - if let videoObject = model.message?.messageObject as? NIMVideoObject { - if let path = videoObject.coverPath, FileManager.default.fileExists(atPath: path) { - contentImageView.sd_setImage( - with: URL(fileURLWithPath: path), - placeholderImage: nil, - options: .retryFailed, - progress: nil, - completed: nil - ) - } else { - contentImageView.sd_setImage( - with: URL(string: videoObject.coverUrl ?? ""), - placeholderImage: nil, - options: .retryFailed, - progress: nil, - completed: nil - ) - } - - if videoObject.duration > 0 { - timeView.isHidden = false - timeLabel.text = Date.getFormatPlayTime(TimeInterval(videoObject.duration / 1000)) - } else { - timeView.isHidden = true - } - - if let videoModel = model as? MessageVideoModel { - weakModel?.cell = nil - weakModel = videoModel - videoModel.cell = self - if videoModel.state == .Success { - stateView.state = .VideoPlay - } else { - stateView.state = .VideoDownload - stateView.setProgress(videoModel.progress) - if videoModel.progress >= 1 { - videoModel.state = .Success - } - } - } - } - } - - override public func uploadProgress(_ progress: Float) { - stateView.setProgress(progress) - } -} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseChatMessageCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseChatMessageCell.swift new file mode 100644 index 00000000..bfe2fc26 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseChatMessageCell.swift @@ -0,0 +1,600 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit +import NECoreKit +import NIMSDK + +@objc +public protocol ChatBaseCellDelegate: NSObjectProtocol { + // 单击头像 + func didTapAvatarView(_ cell: UITableViewCell, _ model: MessageContentModel?) + + // 长按头像 + func didLongPressAvatar(_ cell: UITableViewCell, _ model: MessageContentModel?) + + // 单击消息体 + func didTapMessageView(_ cell: UITableViewCell, _ model: MessageContentModel?) + + // 长按消息体 + func didLongPressMessageView(_ cell: UITableViewCell, _ model: MessageContentModel?) + + // 单击重发按钮 + func didTapResendView(_ cell: UITableViewCell, _ model: MessageContentModel?) + + // 单击重新编辑按钮 + func didTapReeditButton(_ cell: UITableViewCell, _ model: MessageContentModel?) + + // 单击已读未读按钮 + func didTapReadView(_ cell: UITableViewCell, _ model: MessageContentModel?) +} + +@objc +protocol ChatAudioCellProtocol { + var isPlaying: Bool { get set } + var messageId: String? { get set } + func startAnimation(byRight: Bool) + func stopAnimation(byRight: Bool) +} + +@objcMembers +open class NEBaseChatMessageCell: NEChatBaseCell { + public var seletedBtn = UIButton(type: .custom) // 多选按钮 + private let bubbleWidth: CGFloat = 218 // 气泡默认宽度 + public weak var delegate: ChatBaseCellDelegate? + public var contentModel: MessageContentModel? // 消息模型 + + /// Left + public var avatarImageLeft = UIImageView() // 左侧头像 + public var nameLabelLeft = UILabel() // 左侧头像文字(无头像预设) + public var bubbleImageLeft = UIImageView() // 左侧气泡 + public var bubbleTopAnchorLeft: NSLayoutConstraint? // 左侧气泡顶部布局约束 + public var bubbleWLeft: NSLayoutConstraint? // 左侧气泡宽度布局约束 + public var bubbleHLeft: NSLayoutConstraint? // 左侧气泡高度布局约束 + public var pinImageLeft = UIImageView() // 左侧标记图片 + public var pinLabelLeft = UILabel() // 左侧标记文案 + private var pinLabelHLeft: NSLayoutConstraint? // 左侧标记文案宽度布局约束 + private var pinLabelWLeft: NSLayoutConstraint? // 左侧标记文案高度布局约束 + public var fullNameLabel = UILabel() // 群昵称(只在群聊中有效) + public var fullNameH: NSLayoutConstraint? // 群昵称高度布局约束 + + /// Right + public var avatarImageRight = UIImageView() // 右侧头像 + public var nameLabelRight = UILabel() // 右侧头像文字(无头像预设) + public var bubbleImageRight = UIImageView() // 右侧气泡 + public var bubbleWRight: NSLayoutConstraint? // 右侧气泡宽度布局约束 + public var bubbleHRight: NSLayoutConstraint? // 右侧气泡高度布局约束 + public var pinImageRight = UIImageView() // 右侧标记图片 + public var pinLabelRight = UILabel() // 右侧标记文案 + private var pinLabelHRight: NSLayoutConstraint? // 右侧标记文案宽度布局约束 + private var pinLabelWRight: NSLayoutConstraint? // 右侧标记文案高度布局约束 + // 已读未读视图 + public var readView = CirleProgressView(frame: CGRect(x: 0, y: 0, width: 16, height: 16)) + // 已读未读点击手势 + private var tapGesture: UITapGestureRecognizer? + public var activityView = ChatActivityIndicatorView() // 消息状态视图 + + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + initProperty() + baseCommonUI() + addGesture() + initSubviewsLayout() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func initProperty() { + // avatar + avatarImageLeft.backgroundColor = UIColor(hexString: "#537FF4") + avatarImageLeft.translatesAutoresizingMaskIntoConstraints = false + avatarImageLeft.clipsToBounds = true + avatarImageLeft.isUserInteractionEnabled = true + avatarImageLeft.contentMode = .scaleAspectFill + + avatarImageRight.backgroundColor = UIColor(hexString: "#537FF4") + avatarImageRight.translatesAutoresizingMaskIntoConstraints = false + avatarImageRight.clipsToBounds = true + avatarImageRight.isUserInteractionEnabled = true + avatarImageRight.contentMode = .scaleAspectFill + + // name + nameLabelLeft.textAlignment = .center + nameLabelLeft.translatesAutoresizingMaskIntoConstraints = false + nameLabelLeft.font = UIFont.systemFont(ofSize: NEKitChatConfig.shared.ui.userNickTextSize) + nameLabelLeft.textColor = NEKitChatConfig.shared.ui.userNickColor + + nameLabelRight.textAlignment = .center + nameLabelRight.translatesAutoresizingMaskIntoConstraints = false + nameLabelRight.font = UIFont.systemFont(ofSize: NEKitChatConfig.shared.ui.userNickTextSize) + nameLabelRight.textColor = NEKitChatConfig.shared.ui.userNickColor + + // fullName + fullNameLabel.translatesAutoresizingMaskIntoConstraints = false + fullNameLabel.font = UIFont.systemFont(ofSize: 12) + fullNameLabel.textColor = UIColor.ne_lightText + + // bubbleImage + bubbleImageLeft.backgroundColor = NEKitChatConfig.shared.ui.receiveMessageBg + var image = NEKitChatConfig.shared.ui.leftBubbleBg ?? UIImage.ne_imageNamed(name: "chat_message_receive") + bubbleImageLeft.image = image? + .resizableImage(withCapInsets: UIEdgeInsets(top: 35, left: 25, bottom: 10, right: 25)) + bubbleImageLeft.translatesAutoresizingMaskIntoConstraints = false + bubbleImageLeft.isUserInteractionEnabled = true + + bubbleImageRight.backgroundColor = NEKitChatConfig.shared.ui.selfMessageBg + image = NEKitChatConfig.shared.ui.rightBubbleBg ?? UIImage.ne_imageNamed(name: "chat_message_send") + bubbleImageRight.image = image? + .resizableImage(withCapInsets: UIEdgeInsets(top: 35, left: 25, bottom: 10, right: 25)) + bubbleImageRight.translatesAutoresizingMaskIntoConstraints = false + bubbleImageRight.isUserInteractionEnabled = true + + pinLabelLeft.translatesAutoresizingMaskIntoConstraints = false + pinLabelLeft.textColor = UIColor.ne_greenText + pinLabelLeft.font = UIFont.systemFont(ofSize: 12) + pinLabelLeft.textAlignment = .left + pinLabelLeft.lineBreakMode = .byTruncatingMiddle + + pinLabelRight.translatesAutoresizingMaskIntoConstraints = false + pinLabelRight.textColor = UIColor.ne_greenText + pinLabelRight.font = UIFont.systemFont(ofSize: 12) + pinLabelRight.textAlignment = .right + pinLabelRight.lineBreakMode = .byTruncatingMiddle + + pinImageLeft.translatesAutoresizingMaskIntoConstraints = false + pinImageLeft.contentMode = .scaleAspectFit + + pinImageRight.translatesAutoresizingMaskIntoConstraints = false + pinImageRight.contentMode = .scaleAspectFit + } + + open func baseCommonUI() { + baseCommonUIRight() + baseCommonUILeft() + } + + open func baseCommonUILeft() { + contentView.addSubview(avatarImageLeft) + NSLayoutConstraint.activate([ + avatarImageLeft.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 4), + avatarImageLeft.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16), + avatarImageLeft.widthAnchor.constraint(equalToConstant: 32), + avatarImageLeft.heightAnchor.constraint(equalToConstant: 32), + ]) + + contentView.addSubview(nameLabelLeft) + NSLayoutConstraint.activate([ + nameLabelLeft.leftAnchor.constraint(equalTo: avatarImageLeft.leftAnchor), + nameLabelLeft.rightAnchor.constraint(equalTo: avatarImageLeft.rightAnchor), + nameLabelLeft.topAnchor.constraint(equalTo: avatarImageLeft.topAnchor), + nameLabelLeft.bottomAnchor.constraint(equalTo: avatarImageLeft.bottomAnchor), + ]) + + contentView.addSubview(fullNameLabel) + fullNameH = fullNameLabel.heightAnchor.constraint(equalToConstant: 0) + NSLayoutConstraint.activate([ + fullNameLabel.leftAnchor.constraint(equalTo: avatarImageLeft.rightAnchor, constant: chat_content_margin), + fullNameLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16), + fullNameLabel.topAnchor.constraint(equalTo: avatarImageLeft.topAnchor), + fullNameH!, + ]) + + // bubbleImageLeft + contentView.addSubview(bubbleImageLeft) + bubbleTopAnchorLeft = bubbleImageLeft.topAnchor.constraint(equalTo: fullNameLabel.bottomAnchor, constant: 0) + bubbleWLeft = bubbleImageLeft.widthAnchor.constraint(equalToConstant: bubbleWidth) + bubbleHLeft = bubbleImageLeft.heightAnchor.constraint(equalToConstant: bubbleWidth) + NSLayoutConstraint.activate([ + bubbleTopAnchorLeft!, + bubbleImageLeft.leftAnchor.constraint(equalTo: avatarImageLeft.rightAnchor, constant: chat_content_margin), + bubbleWLeft!, + bubbleHLeft!, + ]) + + contentView.addSubview(pinLabelLeft) + pinLabelHLeft = pinLabelLeft.heightAnchor.constraint(equalToConstant: 0) + pinLabelWLeft = pinLabelLeft.widthAnchor.constraint(equalToConstant: 210) + NSLayoutConstraint.activate([ + pinLabelLeft.topAnchor.constraint(equalTo: bubbleImageLeft.bottomAnchor, constant: 4), + pinLabelLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor, constant: 14), + pinLabelWLeft!, + pinLabelHLeft!, + ]) + + contentView.addSubview(pinImageLeft) + NSLayoutConstraint.activate([ + pinImageLeft.rightAnchor.constraint(equalTo: pinLabelLeft.leftAnchor, constant: -2), + pinImageLeft.widthAnchor.constraint(equalToConstant: 10), + pinImageLeft.centerYAnchor.constraint(equalTo: pinLabelLeft.centerYAnchor), + ]) + } + + open func baseCommonUIRight() { + selectionStyle = .none + backgroundColor = .clear + + contentView.addSubview(avatarImageRight) + NSLayoutConstraint.activate([ + avatarImageRight.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16), + avatarImageRight.widthAnchor.constraint(equalToConstant: 32), + avatarImageRight.heightAnchor.constraint(equalToConstant: 32), + avatarImageRight.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 4), + ]) + + contentView.addSubview(nameLabelRight) + NSLayoutConstraint.activate([ + nameLabelRight.leftAnchor.constraint(equalTo: avatarImageRight.leftAnchor), + nameLabelRight.rightAnchor.constraint(equalTo: avatarImageRight.rightAnchor), + nameLabelRight.topAnchor.constraint(equalTo: avatarImageRight.topAnchor), + nameLabelRight.bottomAnchor.constraint(equalTo: avatarImageRight.bottomAnchor), + ]) + + contentView.addSubview(bubbleImageRight) + bubbleWRight = bubbleImageRight.widthAnchor.constraint(equalToConstant: bubbleWidth) + bubbleHRight = bubbleImageRight.heightAnchor.constraint(equalToConstant: bubbleWidth) + NSLayoutConstraint.activate([ + bubbleImageRight.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 4), + bubbleImageRight.rightAnchor.constraint(equalTo: avatarImageRight.leftAnchor, constant: -chat_content_margin), + bubbleWRight!, + bubbleHRight!, + ]) + +// activityView + contentView.addSubview(activityView) + activityView.translatesAutoresizingMaskIntoConstraints = false + activityView.failBtn.addTarget(self, action: #selector(resend), for: .touchUpInside) + NSLayoutConstraint.activate([ + activityView.rightAnchor.constraint(equalTo: bubbleImageRight.leftAnchor, constant: -chat_content_margin), + activityView.centerYAnchor.constraint(equalTo: bubbleImageRight.centerYAnchor, constant: 0), + activityView.widthAnchor.constraint(equalToConstant: 25), + activityView.heightAnchor.constraint(equalToConstant: 25), + ]) + +// readView + contentView.addSubview(readView) + readView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + readView.rightAnchor.constraint(equalTo: bubbleImageRight.leftAnchor, constant: -chat_content_margin), + readView.bottomAnchor.constraint(equalTo: bubbleImageRight.bottomAnchor, constant: 0), + readView.widthAnchor.constraint(equalToConstant: 16), + readView.heightAnchor.constraint(equalToConstant: 16), + ]) + +// seletedBtn + contentView.addSubview(seletedBtn) + seletedBtn.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + seletedBtn.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16), + seletedBtn.centerYAnchor.constraint(equalTo: contentView.centerYAnchor, constant: 0), + seletedBtn.widthAnchor.constraint(equalToConstant: 18), + seletedBtn.heightAnchor.constraint(equalToConstant: 18), + ]) + + contentView.addSubview(pinLabelRight) + pinLabelHRight = pinLabelRight.heightAnchor.constraint(equalToConstant: 0) + pinLabelWRight = pinLabelRight.widthAnchor.constraint(equalToConstant: 210) + NSLayoutConstraint.activate([ + pinLabelRight.topAnchor.constraint(equalTo: bubbleImageRight.bottomAnchor, constant: 4), + pinLabelRight.rightAnchor.constraint(equalTo: bubbleImageRight.rightAnchor, constant: 0), + pinLabelWRight!, + pinLabelHRight!, + ]) + + contentView.addSubview(pinImageRight) + NSLayoutConstraint.activate([ + pinImageRight.rightAnchor.constraint(equalTo: pinLabelRight.leftAnchor, constant: -2), + pinImageRight.centerYAnchor.constraint(equalTo: pinLabelRight.centerYAnchor), + pinImageRight.widthAnchor.constraint(equalToConstant: 10), + ]) + } + + open func addGesture() { +// avatar + let tapRight = UITapGestureRecognizer(target: self, action: #selector(tapAvatar)) + tapRight.cancelsTouchesInView = false + avatarImageRight.addGestureRecognizer(tapRight) + let tapLeft = UITapGestureRecognizer(target: self, action: #selector(tapAvatar)) + tapLeft.cancelsTouchesInView = false + avatarImageLeft.addGestureRecognizer(tapLeft) + + let avatarLongGesture = UILongPressGestureRecognizer(target: self, action: #selector(longPressAvatar)) + avatarImageLeft.addGestureRecognizer(avatarLongGesture) + + let messageTapRight = UITapGestureRecognizer(target: self, action: #selector(tapMessage)) + messageTapRight.cancelsTouchesInView = false + bubbleImageRight.addGestureRecognizer(messageTapRight) + let messageTapLeft = UITapGestureRecognizer(target: self, action: #selector(tapMessage)) + messageTapLeft.cancelsTouchesInView = false + bubbleImageLeft.addGestureRecognizer(messageTapLeft) + + let messageLongPressRight = UILongPressGestureRecognizer( + target: self, + action: #selector(longPress) + ) + bubbleImageRight.addGestureRecognizer(messageLongPressRight) + let messageLongPressLeft = UILongPressGestureRecognizer( + target: self, + action: #selector(longPress) + ) + bubbleImageLeft.addGestureRecognizer(messageLongPressLeft) + + let tapReadView = UITapGestureRecognizer(target: self, action: #selector(tapReadView)) + readView.addGestureRecognizer(tapReadView) + tapGesture = tapReadView + } + + open func initSubviewsLayout() { + if NEKitChatConfig.shared.ui.avatarType == .rectangle, + let radius = NEKitChatConfig.shared.ui.avatarCornerRadius { + avatarImageRight.layer.cornerRadius = radius + avatarImageLeft.layer.cornerRadius = radius + } else if NEKitChatConfig.shared.ui.avatarType == .cycle { + avatarImageRight.layer.cornerRadius = 16.0 + avatarImageLeft.layer.cornerRadius = 16.0 + } else { + avatarImageRight.layer.cornerRadius = 16.0 + avatarImageLeft.layer.cornerRadius = 16.0 + } + } + +// MARK: event + + open func tapAvatar(tap: UITapGestureRecognizer) { + print(#function) + delegate?.didTapAvatarView(self, contentModel) + } + + open func tapMessage(tap: UITapGestureRecognizer) { + print(#function) + delegate?.didTapMessageView(self, contentModel) + } + + open func longPressAvatar(longPress: UITapGestureRecognizer) { + if longPress.state == .began { + delegate?.didLongPressAvatar(self, contentModel) + } + } + + open func longPress(longPress: UILongPressGestureRecognizer) { + print(#function) + switch longPress.state { + case .began: + print("state:begin") + delegate?.didLongPressMessageView(self, contentModel) + case .changed: + print("state:changed") + case .ended: + print("state:ended") + case .cancelled: + print("state:cancelled") + case .failed: + print("state:failed") + default: + print("state:default") + } + } + + open func resend(button: UIButton) { + print("state:default") + delegate?.didTapResendView(self, contentModel) + } + + open func tapReadView(tap: UITapGestureRecognizer) { + print(#function) + delegate?.didTapReadView(self, contentModel) + } + +// MARK: set data + + override open func setModel(_ model: MessageContentModel) { + guard let isSend = model.message?.isOutgoingMsg else { + return + } + let bubbleW = isSend ? bubbleWRight : bubbleWLeft + let bubbleH = isSend ? bubbleHRight : bubbleHLeft + let nameLabel = isSend ? nameLabelRight : nameLabelLeft + let avatarImage = isSend ? avatarImageRight : avatarImageLeft + + contentModel = model + tapGesture?.isEnabled = true + showLeftOrRight(showRight: isSend) + updatePinStatus(model) + + bubbleW?.constant = model.contentSize.width + bubbleH?.constant = model.contentSize.height + + // avatar + nameLabel.text = model.shortName + if let avatarURL = model.avatar { + avatarImage + .sd_setImage(with: URL(string: avatarURL)) { image, error, type, url in + if image != nil { + avatarImage.image = image + nameLabel.isHidden = true + avatarImage.backgroundColor = .clear + } else { + avatarImage.image = nil + nameLabel.isHidden = false + avatarImage.backgroundColor = UIColor + .colorWithString(string: model.message?.from) + } + } + } else { + avatarImage.image = nil + nameLabel.isHidden = false + avatarImage.backgroundColor = UIColor + .colorWithString(string: model.message?.from) + } + + if model.fullNameHeight > 0 { + fullNameLabel.text = model.fullName + fullNameLabel.isHidden = false + bubbleTopAnchorLeft?.constant = 0 + } else { + fullNameLabel.text = nil + fullNameLabel.isHidden = true + bubbleTopAnchorLeft?.constant = 4 + } + fullNameH?.constant = CGFloat(model.fullNameHeight) + + switch model.message?.deliveryState { + case .delivering: + activityView.messageStatus = .sending + case .deliveried: + // 同一个账号,在多端登录,被对方拉黑,需要根据isBlackListed判断,进而更新信息状态 + if let isBlackMsg = model.message?.isBlackListed, isBlackMsg { + activityView.messageStatus = .failed + } else { + activityView.messageStatus = .successed + } + case .failed: + activityView.messageStatus = .failed + default: break + } + + if isSend, model.message?.deliveryState == .deliveried { + if model.message?.session?.sessionType == .P2P { + let receiptEnable = model.message?.setting?.teamReceiptEnabled ?? false + if receiptEnable, + IMKitClient.instance.repo.getShowReadStatus(), + NEKitChatConfig.shared.ui.showP2pMessageStatus == true { + readView.isHidden = false + if let read = model.message?.isRemoteRead, read { + readView.progress = 1 + } else { + readView.progress = 0 + } + // 未读消息需要判断是否被拉黑,拉黑情况,已读未读状态不展示。 + if let isBlackMsg = model.message?.isBlackListed, isBlackMsg { + readView.isHidden = true + } else { + readView.isHidden = false + } + + } else { + readView.isHidden = true + } + + } else if model.message?.session?.sessionType == .team { + let receiptEnable = model.message?.setting?.teamReceiptEnabled ?? false + if receiptEnable, + IMKitClient.instance.repo.getShowReadStatus(), + NEKitChatConfig.shared.ui.showTeamMessageStatus == true { + readView.isHidden = false + let readCount = model.message?.teamReceiptInfo?.readCount ?? 0 + let unreadCount = model.message?.teamReceiptInfo?.unreadCount ?? 0 + let total = Float(readCount + unreadCount) + if (readCount + unreadCount) >= NEKitChatConfig.shared.maxReadingNum { + readView.isHidden = true + return + } + if total > 0 { + let progress = Float(readCount) / total + readView.progress = progress + if progress >= 1.0 { + tapGesture?.isEnabled = false + } + } else { + readView.progress = 0 + } + } else { + readView.isHidden = true + } + } + } else { + readView.isHidden = true + } + } + + /// 根据消息发送方向决定元素的显隐 + /// @param showRight 是否右侧显示(是否是发送的消息) + open func showLeftOrRight(showRight: Bool) { + avatarImageLeft.isHidden = showRight + nameLabelLeft.isHidden = showRight + bubbleImageLeft.isHidden = showRight + pinImageLeft.isHidden = showRight + pinLabelLeft.isHidden = showRight + fullNameLabel.isHidden = showRight + + activityView.isHidden = !showRight + avatarImageRight.isHidden = !showRight + nameLabelRight.isHidden = !showRight + bubbleImageRight.isHidden = !showRight + pinImageRight.isHidden = !showRight + pinLabelRight.isHidden = !showRight + readView.isHidden = !showRight + } + + /// 更新标记状态 + open func updatePinStatus(_ model: MessageContentModel) { + guard let isSend = model.message?.isOutgoingMsg else { + return + } + let pinLabel = isSend ? pinLabelRight : pinLabelLeft + let pinImage = isSend ? pinImageRight : pinImageLeft + let pinLabelH = isSend ? pinLabelHRight : pinLabelHLeft + let pinLabelW = isSend ? pinLabelWRight : pinLabelWLeft + + pinLabel.isHidden = !model.isPined + pinImage.isHidden = !model.isPined + contentView.backgroundColor = model.isPined ? NEKitChatConfig.shared.ui + .signalBgColor : .clear + if model.isPined { + let pinText = model.message?.session?.sessionType == .P2P ? chatLocalizable("pin_text_P2P") : chatLocalizable("pin_text_team") + if model.pinAccount == nil { + pinLabel.text = chatLocalizable("You") + " " + pinText + } else if let account = model.pinAccount, account == NIMSDK.shared().loginManager.currentAccount() { + pinLabel.text = chatLocalizable("You") + " " + pinText + } else if let text = model.pinShowName { + pinLabel.text = text + pinText + } + + pinImage.image = UIImage.ne_imageNamed(name: "msg_pin") + let size = String.getTextRectSize( + pinLabel.text ?? pinText, + font: UIFont.systemFont(ofSize: 12.0), + size: CGSize(width: kScreenWidth - 56 - 22, height: CGFloat.greatestFiniteMagnitude) + ) + pinLabelH?.constant = CGFloat(chat_pin_height) + pinLabelW?.constant = size.width + 1 + } else { + pinImage.image = nil + pinLabelH?.constant = 0 + pinLabelW?.constant = 0 + } + } + + /// 设置头像大小(正方形) + func setAvatarImgSize(size: CGFloat) { + NSLayoutConstraint.deactivate(avatarImageLeft.constraints) + NSLayoutConstraint.activate([ + avatarImageLeft.widthAnchor.constraint(equalToConstant: size), + avatarImageLeft.heightAnchor.constraint(equalToConstant: size), + ]) + NSLayoutConstraint.deactivate(avatarImageRight.constraints) + NSLayoutConstraint.activate([ + avatarImageRight.widthAnchor.constraint(equalToConstant: size), + avatarImageRight.heightAnchor.constraint(equalToConstant: size), + ]) + } + + func sizeWidthFromString(_ text: NSAttributedString, _ font: UIFont) -> Double { + // 根据内容计算size + let maxSize = CGSize(width: chat_content_maxW, height: CGFloat.greatestFiniteMagnitude) + let labelSize = text.boundingRect(with: maxSize, options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil) + return ceil(labelSize.width) + chat_content_margin * 2 + } + + func sizeHeightFromString(_ text: NSAttributedString, _ font: UIFont) -> Double { + // 根据内容计算size + let maxSize = CGSize(width: chat_content_maxW, height: CGFloat.greatestFiniteMagnitude) + let labelSize = text.boundingRect(with: maxSize, options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil) + + return ceil(labelSize.height) + chat_content_margin * 2 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatTimeTableViewCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseChatMessageTipCell.swift similarity index 68% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatTimeTableViewCell.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseChatMessageTipCell.swift index 42679185..5f6a380b 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatTimeTableViewCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseChatMessageTipCell.swift @@ -6,34 +6,39 @@ import UIKit @objcMembers -public class ChatTimeTableViewCell: UITableViewCell { +open class NEBaseChatMessageTipCell: UITableViewCell { var timeLabelWidthAnchor: NSLayoutConstraint? - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) selectionStyle = .none + backgroundColor = .clear + commonUI() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func commonUI() { timeLabel.numberOfLines = 0 contentView.addSubview(timeLabel) NSLayoutConstraint.activate([ - timeLabel.topAnchor.constraint(equalTo: contentView.topAnchor), + timeLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), timeLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), ]) - timeLabelWidthAnchor = timeLabel.widthAnchor.constraint(equalToConstant: kScreenWidth - 64 * 2) + timeLabelWidthAnchor = timeLabel.widthAnchor.constraint(equalToConstant: chat_content_maxW) timeLabelWidthAnchor?.isActive = true } - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - func setModel(_ model: MessageTipsModel) { timeLabel.text = model.text timeLabelWidthAnchor?.constant = model.contentSize.width } - private lazy var timeLabel: UILabel = { + public lazy var timeLabel: UILabel = { let label = UILabel() - label.font = DefaultTextFont(NEKitChatConfig.shared.ui.timeTextSize) + label.font = .systemFont(ofSize: NEKitChatConfig.shared.ui.timeTextSize) label.textColor = NEKitChatConfig.shared.ui.timeTextColor label.textAlignment = .center label.translatesAutoresizingMaskIntoConstraints = false diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatTeamMemberCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseChatTeamMemberCell.swift similarity index 83% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatTeamMemberCell.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseChatTeamMemberCell.swift index 20bc9419..7151fd1e 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/ChatTeamMemberCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseChatTeamMemberCell.swift @@ -8,21 +8,19 @@ import NECommonUIKit import NEChatKit @objcMembers -public class ChatTeamMemberCell: UITableViewCell { - lazy var headerView: NEUserHeaderView = { +open class NEBaseChatTeamMemberCell: UITableViewCell { + public lazy var headerView: NEUserHeaderView = { let header = NEUserHeaderView(frame: .zero) header.titleLabel.font = NEConstant.defaultTextFont(14) header.titleLabel.textColor = UIColor.white - header.layer.cornerRadius = 21 header.clipsToBounds = true header.translatesAutoresizingMaskIntoConstraints = false return header }() - lazy var nameLabel: UILabel = { + public lazy var nameLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false - label.font = NEConstant.defaultTextFont(16.0) label.textColor = .ne_darkText return label }() @@ -33,17 +31,17 @@ public class ChatTeamMemberCell: UITableViewCell { // Configure the view for the selected state } - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) selectionStyle = .none setupUI() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } - func setupUI() { + open func setupUI() { contentView.addSubview(headerView) NSLayoutConstraint.activate([ headerView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 21), @@ -60,7 +58,7 @@ public class ChatTeamMemberCell: UITableViewCell { ]) } - func configure(_ model: ChatTeamMemberInfoModel) { + open func configure(_ model: ChatTeamMemberInfoModel) { if let url = model.nimUser?.userInfo?.avatarUrl { headerView.sd_setImage(with: URL(string: url), completed: nil) headerView.setTitle("") diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/UserSettingBaseCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseUserSettingCell.swift similarity index 79% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/UserSettingBaseCell.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseUserSettingCell.swift index 7a15c65d..6021a110 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/UserSettingBaseCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseUserSettingCell.swift @@ -4,10 +4,10 @@ // found in the LICENSE file. @objcMembers -public class UserSettingBaseCell: CornerCell { - var model: UserSettingCellModel? +open class NEBaseUserSettingCell: CornerCell { + public var model: UserSettingCellModel? - lazy var titleLabel: UILabel = { + public lazy var titleLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.textColor = NEConstant.hexRGB(0x333333) @@ -21,13 +21,13 @@ public class UserSettingBaseCell: CornerCell { return imageView }() - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) selectionStyle = .none showDefaultLine = true } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } @@ -42,7 +42,7 @@ public class UserSettingBaseCell: CornerCell { // Configure the view for the selected state } - func configure(_ anyModel: Any) { + open func configure(_ anyModel: Any) { if let m = anyModel as? UserSettingCellModel { model = m cornerType = m.cornerType diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/UserSettingSelectCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseUserSettingSelectCell.swift similarity index 52% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/UserSettingSelectCell.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseUserSettingSelectCell.swift index c37bb7c7..86a8fadf 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/UserSettingSelectCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseUserSettingSelectCell.swift @@ -5,7 +5,7 @@ import UIKit @objcMembers -public class UserSettingSelectCell: UserSettingBaseCell { +open class NEBaseUserSettingSelectCell: NEBaseUserSettingCell { public lazy var subTitleLabel: UILabel = { let label = UILabel() label.textColor = NEConstant.hexRGB(0x999999) @@ -14,50 +14,29 @@ public class UserSettingSelectCell: UserSettingBaseCell { return label }() - override public func awakeFromNib() { - super.awakeFromNib() - // Initialization code - } - - override public func setSelected(_ selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - - // Configure the view for the selected state - } - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) selectionStyle = .none setupUI() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } - func setupUI() { + open func setupUI() { contentView.addSubview(titleLabel) - NSLayoutConstraint.activate([ - titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 36), - titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16), - titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -84), - ]) - + contentView.addSubview(arrow) contentView.addSubview(subTitleLabel) + NSLayoutConstraint.activate([ subTitleLabel.leftAnchor.constraint(equalTo: titleLabel.leftAnchor), subTitleLabel.rightAnchor.constraint(equalTo: titleLabel.rightAnchor), subTitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 6.0), ]) - - contentView.addSubview(arrow) - NSLayoutConstraint.activate([ - arrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - arrow.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -36), - ]) } - override func configure(_ anyModel: Any) { + override open func configure(_ anyModel: Any) { super.configure(anyModel) if let model = anyModel as? UserSettingCellModel { subTitleLabel.text = model.subTitle diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/UserSettingSwitchCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseUserSettingSwitchCell.swift similarity index 57% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/UserSettingSwitchCell.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseUserSettingSwitchCell.swift index ae96b3d4..3483d3c0 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/UserSettingSwitchCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/NEBaseUserSettingSwitchCell.swift @@ -6,8 +6,8 @@ import UIKit @objcMembers -public class UserSettingSwitchCell: UserSettingBaseCell { - var tSwitch: UISwitch = { +open class NEBaseUserSettingSwitchCell: NEBaseUserSettingCell { + public var tSwitch: UISwitch = { let q = UISwitch() q.translatesAutoresizingMaskIntoConstraints = false q.onTintColor = NEConstant.hexRGB(0x337EFF) @@ -25,40 +25,30 @@ public class UserSettingSwitchCell: UserSettingBaseCell { // Configure the view for the selected state } - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) selectionStyle = .none setupUI() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } - override func configure(_ anyModel: Any) { + override open func configure(_ anyModel: Any) { super.configure(anyModel) if let open = model?.switchOpen { tSwitch.isOn = open } } - func setupUI() { + open func setupUI() { contentView.addSubview(titleLabel) - NSLayoutConstraint.activate([ - titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 36), - titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -84), - ]) - contentView.addSubview(tSwitch) - NSLayoutConstraint.activate([ - tSwitch.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - tSwitch.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -36), - ]) tSwitch.addTarget(self, action: #selector(switchChange(_:)), for: .touchUpInside) } - func switchChange(_ s: UISwitch) { + open func switchChange(_ s: UISwitch) { if let block = model?.swichChange { block(s.isOn) } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/OperationCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/OperationCell.swift index ce0d17bd..5f7cc36c 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/OperationCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/OperationCell.swift @@ -10,7 +10,7 @@ import UIKit // } @objcMembers -public class OperationCell: UICollectionViewCell { +open class OperationCell: UICollectionViewCell { public var imageView = UIImageView() public var label = UILabel() // public weak var delegate: OperationCellDelegate? @@ -21,7 +21,7 @@ public class OperationCell: UICollectionViewCell { } } - override init(frame: CGRect) { + override public init(frame: CGRect) { super.init(frame: frame) imageView.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(imageView) @@ -48,7 +48,7 @@ public class OperationCell: UICollectionViewCell { // self.contentView.addGestureRecognizer(tap) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageAudioCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageAudioCell.swift similarity index 78% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageAudioCell.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageAudioCell.swift index 89cc78b0..2bc3651a 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageAudioCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageAudioCell.swift @@ -4,42 +4,31 @@ import UIKit -class PinMessageAudioCell: PinMessageBaseCell { +@objcMembers +open class NEBasePinMessageAudioCell: NEBasePinMessageCell { var audioImageView = UIImageView(image: UIImage.ne_imageNamed(name: "left_play_3")) var audioTimeLabel = UILabel() public var bubbleImage = UIImageView() - override func awakeFromNib() { - super.awakeFromNib() - // Initialization code - } - - override func setSelected(_ selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - - // Configure the view for the selected state - } - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } - override func setupUI() { + override open func setupUI() { super.setupUI() - if let image = NEKitChatConfig.shared.ui.leftBubbleBg { - bubbleImage.image = image - .resizableImage(withCapInsets: UIEdgeInsets(top: 35, left: 25, bottom: 10, right: 25)) - } + let image = NEKitChatConfig.shared.ui.leftBubbleBg ?? UIImage.ne_imageNamed(name: "chat_message_receive") + bubbleImage.image = image? + .resizableImage(withCapInsets: UIEdgeInsets(top: 35, left: 25, bottom: 10, right: 25)) bubbleImage.translatesAutoresizingMaskIntoConstraints = false bubbleImage.isUserInteractionEnabled = true backView.addSubview(bubbleImage) - contentWidth = bubbleImage.widthAnchor.constraint(equalToConstant: 0) - contentHeight = bubbleImage.heightAnchor.constraint(equalToConstant: 0) + contentWidth = bubbleImage.widthAnchor.constraint(equalToConstant: chat_content_maxW) + contentHeight = bubbleImage.heightAnchor.constraint(equalToConstant: chat_content_maxW) NSLayoutConstraint.activate([ contentHeight!, contentWidth!, @@ -70,7 +59,7 @@ class PinMessageAudioCell: PinMessageBaseCell { ]) } - override func configure(_ item: PinMessageModel) { + override public func configure(_ item: PinMessageModel) { super.configure(item) if let m = item.chatmodel as? MessageAudioModel { audioTimeLabel.text = "\(m.duration)" + "s" diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageBaseCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageCell.swift similarity index 83% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageBaseCell.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageCell.swift index a56b7647..ec8dbf95 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageBaseCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageCell.swift @@ -7,11 +7,13 @@ import NIMSDK import NECommonUIKit import NECommonKit -protocol PinMessageCellDelegate { +@objc +public protocol PinMessageCellDelegate { func didClickMore(_ model: PinMessageModel?) } -class PinMessageBaseCell: UITableViewCell { +@objcMembers +open class NEBasePinMessageCell: UITableViewCell { public var contentWidth: NSLayoutConstraint? public var contentHeight: NSLayoutConstraint? @@ -50,7 +52,10 @@ class PinMessageBaseCell: UITableViewCell { public let line = UIView() - override func awakeFromNib() { + public var backLeftConstraint: NSLayoutConstraint? + public var backRightConstraint: NSLayoutConstraint? + + override open func awakeFromNib() { super.awakeFromNib() // Initialization code } @@ -58,27 +63,32 @@ class PinMessageBaseCell: UITableViewCell { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) selectionStyle = .none + backgroundColor = .clear setupUI() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } - override func setSelected(_ selected: Bool, animated: Bool) { + override open func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) // Configure the view for the selected state } - public func setupUI() { - contentView.backgroundColor = UIColor(hexString: "#EFF1F3") + open func setupUI() { + contentView.backgroundColor = .clear backView.translatesAutoresizingMaskIntoConstraints = false - contentView.addSubview(backView) backView.backgroundColor = UIColor.white + contentView.addSubview(backView) + + backLeftConstraint = backView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20) + backRightConstraint = backView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20) + NSLayoutConstraint.activate([ - backView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20), - backView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20), + backLeftConstraint!, + backRightConstraint!, backView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 12), backView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), ]) @@ -142,7 +152,9 @@ class PinMessageBaseCell: UITableViewCell { public func configure(_ item: PinMessageModel) { pinModel = item - headerView.configHeadData(headUrl: item.chatmodel?.avatar, name: item.chatmodel?.fullName ?? "") + headerView.configHeadData(headUrl: item.chatmodel?.avatar, + name: item.chatmodel?.fullName ?? "", + uid: item.chatmodel?.message?.from ?? "") nameLabel.text = item.chatmodel?.fullName print("config time : ", item.message.timestamp) timeLabel.text = String.stringFromDate(date: Date(timeIntervalSince1970: item.message.timestamp)) @@ -151,7 +163,7 @@ class PinMessageBaseCell: UITableViewCell { contentHeight?.constant = item.chatmodel?.contentSize.height ?? 0 } - @objc func moreClick() { + func moreClick() { delegate?.didClickMore(pinModel) } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageDefaultCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageDefaultCell.swift similarity index 66% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageDefaultCell.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageDefaultCell.swift index 57caa222..c9e5df7b 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageDefaultCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageDefaultCell.swift @@ -4,13 +4,14 @@ import UIKit -class PinMessageDefaultCell: PinMessageTextCell { - override func awakeFromNib() { +@objcMembers +open class NEBasePinMessageDefaultCell: NEBasePinMessageTextCell { + override open func awakeFromNib() { super.awakeFromNib() // Initialization code } - override func setSelected(_ selected: Bool, animated: Bool) { + override open func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) // Configure the view for the selected state @@ -20,15 +21,15 @@ class PinMessageDefaultCell: PinMessageTextCell { super.init(style: style, reuseIdentifier: reuseIdentifier) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } - override func setupUI() { + override open func setupUI() { super.setupUI() } - override func configure(_ item: PinMessageModel) { + override public func configure(_ item: PinMessageModel) { super.configure(item) contentLabel.text = chatLocalizable("unkonw_pin_message") } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageFileCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageFileCell.swift similarity index 93% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageFileCell.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageFileCell.swift index 805bf04b..38a6f05e 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageFileCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageFileCell.swift @@ -5,7 +5,8 @@ import UIKit import NIMSDK -class PinMessageFileCell: PinMessageBaseCell { +@objcMembers +open class NEBasePinMessageFileCell: NEBasePinMessageCell { public var bubbleImage = UIImageView() lazy var imgView: UIImageView = { @@ -56,12 +57,12 @@ class PinMessageFileCell: PinMessageBaseCell { return view }() - override func awakeFromNib() { + override open func awakeFromNib() { super.awakeFromNib() // Initialization code } - override func setSelected(_ selected: Bool, animated: Bool) { + override open func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) // Configure the view for the selected state @@ -71,11 +72,11 @@ class PinMessageFileCell: PinMessageBaseCell { super.init(style: style, reuseIdentifier: reuseIdentifier) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } - override func setupUI() { + override open func setupUI() { super.setupUI() bubbleImage.image = nil @@ -85,8 +86,8 @@ class PinMessageFileCell: PinMessageBaseCell { bubbleImage.translatesAutoresizingMaskIntoConstraints = false bubbleImage.isUserInteractionEnabled = true backView.addSubview(bubbleImage) - contentWidth = bubbleImage.widthAnchor.constraint(equalToConstant: 0) - contentHeight = bubbleImage.heightAnchor.constraint(equalToConstant: 0) + contentWidth = bubbleImage.widthAnchor.constraint(equalToConstant: chat_content_maxW) + contentHeight = bubbleImage.heightAnchor.constraint(equalToConstant: chat_content_maxW) NSLayoutConstraint.activate([ contentHeight!, contentWidth!, @@ -111,7 +112,7 @@ class PinMessageFileCell: PinMessageBaseCell { ]) } - override func configure(_ item: PinMessageModel) { + override public func configure(_ item: PinMessageModel) { super.configure(item) if let fileObject = item.message.messageObject as? NIMFileObject { var imageName = "file_unknown" diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageImageCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageImageCell.swift similarity index 85% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageImageCell.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageImageCell.swift index 95b7ee8f..78f7e2b8 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageImageCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageImageCell.swift @@ -4,15 +4,16 @@ import UIKit -class PinMessageImageCell: PinMessageBaseCell { +@objcMembers +open class NEBasePinMessageImageCell: NEBasePinMessageCell { public let contentImageView = UIImageView() - override func awakeFromNib() { + override open func awakeFromNib() { super.awakeFromNib() // Initialization code } - override func setSelected(_ selected: Bool, animated: Bool) { + override open func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) // Configure the view for the selected state @@ -22,11 +23,11 @@ class PinMessageImageCell: PinMessageBaseCell { super.init(style: style, reuseIdentifier: reuseIdentifier) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } - override func setupUI() { + override open func setupUI() { super.setupUI() contentImageView.translatesAutoresizingMaskIntoConstraints = false contentImageView.contentMode = .scaleAspectFill @@ -47,7 +48,7 @@ class PinMessageImageCell: PinMessageBaseCell { contentHeight?.isActive = true } - override func configure(_ item: PinMessageModel) { + override public func configure(_ item: PinMessageModel) { super.configure(item) if let m = item.chatmodel as? MessageImageModel, let imageUrl = m.imageUrl { diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageLocationCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageLocationCell.swift similarity index 92% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageLocationCell.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageLocationCell.swift index 56a3fe3a..bf6b44ec 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageLocationCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageLocationCell.swift @@ -4,8 +4,10 @@ import UIKit import NEChatKit +import NECommonKit -class PinMessageLocationCell: PinMessageBaseCell { +@objcMembers +open class NEBasePinMessageLocationCell: NEBasePinMessageCell { private lazy var locationTitleLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false @@ -34,12 +36,12 @@ class PinMessageLocationCell: PinMessageBaseCell { var mapView: UIView? - override func awakeFromNib() { + override open func awakeFromNib() { super.awakeFromNib() // Initialization code } - override func setSelected(_ selected: Bool, animated: Bool) { + override open func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) // Configure the view for the selected state @@ -49,11 +51,11 @@ class PinMessageLocationCell: PinMessageBaseCell { super.init(style: style, reuseIdentifier: reuseIdentifier) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } - override func setupUI() { + override open func setupUI() { super.setupUI() let back = UIView() @@ -66,8 +68,8 @@ class PinMessageLocationCell: PinMessageBaseCell { back.layer.borderColor = UIColor.ne_outlineColor.cgColor backView.addSubview(back) - contentWidth = back.widthAnchor.constraint(equalToConstant: 0) - contentHeight = back.heightAnchor.constraint(equalToConstant: 0) + contentWidth = back.widthAnchor.constraint(equalToConstant: chat_content_maxW) + contentHeight = back.heightAnchor.constraint(equalToConstant: chat_content_maxW) NSLayoutConstraint.activate([ contentWidth!, contentHeight!, @@ -118,7 +120,7 @@ class PinMessageLocationCell: PinMessageBaseCell { } } - override func configure(_ item: PinMessageModel) { + override public func configure(_ item: PinMessageModel) { super.configure(item) if let m = item.chatmodel as? MessageLocationModel { locationTitleLabel.text = m.title diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageTextCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageTextCell.swift similarity index 87% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageTextCell.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageTextCell.swift index ef4c8c7f..f8835637 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageTextCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageTextCell.swift @@ -4,7 +4,8 @@ import UIKit -class PinMessageTextCell: PinMessageBaseCell { +@objcMembers +open class NEBasePinMessageTextCell: NEBasePinMessageCell { lazy var contentLabel: UILabel = { let label = UILabel() label.font = UIFont.systemFont(ofSize: 14.0) @@ -16,12 +17,12 @@ class PinMessageTextCell: PinMessageBaseCell { public let replyLabel = UILabel() - override func awakeFromNib() { + override open func awakeFromNib() { super.awakeFromNib() // Initialization code } - override func setSelected(_ selected: Bool, animated: Bool) { + override open func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) // Configure the view for the selected state @@ -31,11 +32,11 @@ class PinMessageTextCell: PinMessageBaseCell { super.init(style: style, reuseIdentifier: reuseIdentifier) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } - override func setupUI() { + override open func setupUI() { super.setupUI() replyLabel.font = UIFont.systemFont(ofSize: 12) replyLabel.textColor = UIColor(hexString: "#929299") @@ -55,7 +56,7 @@ class PinMessageTextCell: PinMessageBaseCell { ]) } - override func configure(_ item: PinMessageModel) { + override public func configure(_ item: PinMessageModel) { super.configure(item) if let model = item.chatmodel as? MessageTextModel { contentLabel.attributedText = model.attributeStr diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageVideoCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageVideoCell.swift similarity index 93% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageVideoCell.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageVideoCell.swift index 92e1ecd9..a32bece2 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/PinMessageVideoCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/PinCell/NEBasePinMessageVideoCell.swift @@ -5,7 +5,8 @@ import UIKit import NIMSDK -class PinMessageVideoCell: PinMessageImageCell { +@objcMembers +open class NEBasePinMessageVideoCell: NEBasePinMessageImageCell { lazy var stateView: VideoStateView = { let state = VideoStateView() state.translatesAutoresizingMaskIntoConstraints = false @@ -42,11 +43,11 @@ class PinMessageVideoCell: PinMessageImageCell { super.init(style: style, reuseIdentifier: reuseIdentifier) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } - override func setupUI() { + override public func setupUI() { super.setupUI() contentImageView.addSubview(stateView) contentImageView.addCustomCorner(conrners: [.topLeft], radius: 8, backcolor: .white) @@ -66,7 +67,7 @@ class PinMessageVideoCell: PinMessageImageCell { stateView.isUserInteractionEnabled = false } - override func configure(_ item: PinMessageModel) { + override public func configure(_ item: PinMessageModel) { super.configure(item) if let videoObject = item.chatmodel?.message?.messageObject as? NIMVideoObject { diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/UserTableViewCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/UserBaseTableViewCell.swift similarity index 58% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/UserTableViewCell.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/UserBaseTableViewCell.swift index ee62e74e..bd9cd79d 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/UserTableViewCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/Cell/UserBaseTableViewCell.swift @@ -7,45 +7,55 @@ import UIKit import NECoreIMKit @objcMembers -public class UserTableViewCell: UITableViewCell { - public var avatarImage = UIImageView() - public var nameLabel = UILabel() - public var titleLabel = UILabel() +open class UserBaseTableViewCell: UITableViewCell { + public lazy var avatarImage: UIImageView = { + let avatarImage = UIImageView() + avatarImage.backgroundColor = UIColor(hexString: "#537FF4") + avatarImage.translatesAutoresizingMaskIntoConstraints = false + avatarImage.clipsToBounds = true + avatarImage.isUserInteractionEnabled = true + avatarImage.contentMode = .scaleAspectFill + return avatarImage + }() + + public lazy var nameLabel: UILabel = { + let nameLabel = UILabel() + nameLabel.textAlignment = .center + nameLabel.translatesAutoresizingMaskIntoConstraints = false + nameLabel.font = UIFont.systemFont(ofSize: 12) + nameLabel.textColor = .white + nameLabel.text = "placeholder" + return nameLabel + }() + + public lazy var titleLabel: UILabel = { + let titleLabel = UILabel() + titleLabel.translatesAutoresizingMaskIntoConstraints = false + titleLabel.text = "placeholder" + return titleLabel + }() + public var userModel: User? - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) + selectionStyle = .none + backgroundColor = .white baseCommonUI() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - func baseCommonUI() { - // avatar + open func baseCommonUI() { selectionStyle = .none backgroundColor = .white - avatarImage.layer.cornerRadius = 21 - avatarImage.backgroundColor = UIColor(hexString: "#537FF4") - avatarImage.translatesAutoresizingMaskIntoConstraints = false - avatarImage.clipsToBounds = true - avatarImage.isUserInteractionEnabled = true contentView.addSubview(avatarImage) - NSLayoutConstraint.activate([ - avatarImage.leftAnchor.constraint(equalTo: leftAnchor, constant: 16), - avatarImage.widthAnchor.constraint(equalToConstant: 42), - avatarImage.heightAnchor.constraint(equalToConstant: 42), - avatarImage.topAnchor.constraint(equalTo: topAnchor, constant: 10), - ]) + contentView.addSubview(nameLabel) + contentView.addSubview(titleLabel) // name - nameLabel.textAlignment = .center - nameLabel.translatesAutoresizingMaskIntoConstraints = false - nameLabel.font = UIFont.systemFont(ofSize: 12) - nameLabel.textColor = .white - nameLabel.text = "placeholder" - contentView.addSubview(nameLabel) NSLayoutConstraint.activate([ nameLabel.leftAnchor.constraint(equalTo: avatarImage.leftAnchor), nameLabel.rightAnchor.constraint(equalTo: avatarImage.rightAnchor), @@ -55,26 +65,11 @@ public class UserTableViewCell: UITableViewCell { titleLabel.translatesAutoresizingMaskIntoConstraints = false titleLabel.text = "placeholder" - titleLabel.font = UIFont.systemFont(ofSize: 16) - titleLabel.textColor = UIColor( - red: 51 / 255.0, - green: 51 / 255.0, - blue: 51 / 255.0, - alpha: 1.0 - ) - contentView.addSubview(titleLabel) - NSLayoutConstraint.activate([ - titleLabel.leftAnchor.constraint(equalTo: avatarImage.rightAnchor, constant: 12), - titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -35), - titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor, constant: 0), - titleLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), - ]) } - public func setModel(_ model: User) { + open func setModel(_ model: User) { userModel = model - avatarImage.backgroundColor = UIColor.colorWithString(string: model.userId) - nameLabel.text = model.shortName(count: 2) + nameLabel.text = model.shortName(showAlias: false, count: 2) titleLabel.text = model.showName() if let avatarURL = model.userInfo?.avatarUrl { @@ -83,14 +78,17 @@ public class UserTableViewCell: UITableViewCell { if image != nil { self?.avatarImage.image = image self?.nameLabel.isHidden = true + self?.avatarImage.backgroundColor = .clear } else { self?.avatarImage.image = nil self?.nameLabel.isHidden = false + self?.avatarImage.backgroundColor = UIColor.colorWithString(string: model.userId) } } } else { avatarImage.image = nil nameLabel.isHidden = false + avatarImage.backgroundColor = UIColor.colorWithString(string: model.userId) } } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/ChatActivityIndicatorView.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/ChatActivityIndicatorView.swift index a7b8aae9..625da261 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/ChatActivityIndicatorView.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/ChatActivityIndicatorView.swift @@ -49,6 +49,7 @@ public class ChatActivityIndicatorView: UIView { } func commonUI() { + backgroundColor = .clear addSubview(failBtn) addSubview(activity) NSLayoutConstraint.activate([ diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/ChatRecordView.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/ChatRecordView.swift index d6345e72..7a4c1c6b 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/ChatRecordView.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/ChatRecordView.swift @@ -5,6 +5,7 @@ import UIKit +@objc public protocol ChatRecordViewDelegate: NSObjectProtocol { func startRecord() func moveOutView() diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/CirleProgressView.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/CirleProgressView.swift index 8017fa82..0b1da856 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/CirleProgressView.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/CirleProgressView.swift @@ -29,8 +29,8 @@ public class CirleProgressView: UIView { } } - private var borderLayer = CAShapeLayer() - private var sectorLayer = CAShapeLayer() + public var borderLayer = CAShapeLayer() + public var sectorLayer = CAShapeLayer() private var imageView = UIImageView(image: UIImage.ne_imageNamed(name: "chat_unread")) // override func draw(_ rect: CGRect) { @@ -39,7 +39,7 @@ public class CirleProgressView: UIView { override init(frame: CGRect) { super.init(frame: frame) - backgroundColor = .white + backgroundColor = .clear imageView.frame = bounds imageView.contentMode = .center addSubview(imageView) @@ -59,6 +59,7 @@ public class CirleProgressView: UIView { layer.addSublayer(borderLayer) sectorLayer.frame = bounds + sectorLayer.fillColor = UIColor.ne_blueText.cgColor layer.addSublayer(sectorLayer) } @@ -80,6 +81,5 @@ public class CirleProgressView: UIView { ) sectorPath.addLine(to: center) sectorLayer.path = sectorPath.cgPath - sectorLayer.fillColor = UIColor.ne_blueText.cgColor } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/CopyableTextView.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/CopyableLabel.swift similarity index 80% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/CopyableTextView.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/CopyableLabel.swift index c4bf9a71..c0353db0 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/CopyableTextView.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/CopyableLabel.swift @@ -7,19 +7,20 @@ import UIKit import NECommonUIKit import MobileCoreServices -class CopyableTextView: UITextView { +@objcMembers +open class CopyableLabel: UILabel { var copyString: String? override public var canBecomeFirstResponder: Bool { true } - override init(frame: CGRect, textContainer: NSTextContainer?) { - super.init(frame: frame, textContainer: textContainer) + override init(frame: CGRect) { + super.init(frame: frame) sharedInit() } - required init?(coder aDecoder: NSCoder) { + public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) sharedInit() } @@ -32,7 +33,6 @@ class CopyableTextView: UITextView { )) } - @objc func copyText(_ sender: Any?) { if let copy = copyString { UIPasteboard.general.string = copy @@ -41,7 +41,7 @@ class CopyableTextView: UITextView { makeToast(chatLocalizable("copy_success"), duration: 2, position: .bottom) } - override func copy(_ sender: Any?) { + override open func copy(_ sender: Any?) { if let attribute = attributedText { if let data = try? attribute.data(from: NSMakeRange(0, attribute.length)) { UIPasteboard.general.setData(data, forPasteboardType: (kUTTypeRTF as NSString) as String) @@ -50,7 +50,7 @@ class CopyableTextView: UITextView { UIMenuController.shared.setMenuVisible(false, animated: true) } - @objc func showMenu(sender: Any?) { + func showMenu(sender: Any?) { becomeFirstResponder() let menu = UIMenuController.shared if !menu.isMenuVisible { @@ -61,7 +61,7 @@ class CopyableTextView: UITextView { } } - override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { + override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { if action == #selector(copyText) { return true } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/MessageOperationView.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/MessageOperationView.swift index b3bba313..777b826c 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/MessageOperationView.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/MessageOperationView.swift @@ -5,6 +5,7 @@ import UIKit +@objc public protocol MessageOperationViewDelegate: AnyObject { func didSelectedItem(item: OperationItem) } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/ChatInputView.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/NEBaseChatInputView.swift similarity index 75% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/ChatInputView.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/NEBaseChatInputView.swift index df75f8d6..9a0a0c69 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/ChatInputView.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/NEBaseChatInputView.swift @@ -8,7 +8,8 @@ import NECommonKit import NECoreKit import UITextView_Placeholder -@objc public enum ChatMenuType: Int { +@objc +public enum ChatMenuType: Int { case text = 0 case audio case emoji @@ -21,29 +22,12 @@ public let atRangeOffset = 1 public let atSegmentsKey = "segments" public let atTextKey = "text" -@objc -public protocol ChatInputViewDelegate: NSObjectProtocol { - func sendText(text: String?, attribute: NSAttributedString?) - func willSelectItem(button: UIButton, index: Int) - func didSelectMoreCell(cell: NEInputMoreCell) - - @discardableResult - func textChanged(text: String) -> Bool - func textDelete(range: NSRange, text: String) -> Bool - func startRecord() - func moveOutView() - func moveInView() - func endRecord(insideView: Bool) - func textFieldDidChange(_ textField: UITextView) - func textFieldDidEndEditing(_ textField: UITextView) - func textFieldDidBeginEditing(_ textField: UITextView) -} - @objcMembers -open class ChatInputView: UIView, ChatRecordViewDelegate, - InputEmoticonContainerViewDelegate, UITextViewDelegate, NEMoreViewDelagate { +open class NEBaseChatInputView: UIView, ChatRecordViewDelegate, + InputEmoticonContainerViewDelegate, UITextViewDelegate, NEMoreViewDelegate { public weak var delegate: ChatInputViewDelegate? public var currentType: ChatMenuType = .text + public var currentButton: UIButton? public var menuHeight = 100.0 public var contentHeight = 204.0 public var atCache: NIMInputAtCache? @@ -52,13 +36,27 @@ open class ChatInputView: UIView, ChatRecordViewDelegate, public var nickAccidDic = [String: String]() - public var textView = UITextView() // RSKPlaceholderTextView() + public var textView: UITextView = { + let textView = UITextView() + textView.layer.cornerRadius = 8 + textView.font = UIFont.systemFont(ofSize: 16) + textView.clipsToBounds = true + textView.translatesAutoresizingMaskIntoConstraints = false + textView.backgroundColor = .white + textView.returnKeyType = .send + textView.allowsEditingTextAttributes = true + textView.typingAttributes = [NSAttributedString.Key.foregroundColor: UIColor.ne_darkText, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)] + textView.linkTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.ne_darkText, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)] + textView.dataDetectorTypes = [] + return textView + }() + public var stackView = UIStackView() var contentView = UIView() public var contentSubView: UIView? - private var greyView = UIView() - private var recordView = ChatRecordView(frame: .zero) - private var textInput: UITextInput? + public var greyView = UIView() + public var recordView = ChatRecordView(frame: .zero) + public var textInput: UITextInput? public var textviewLeftConstraint: NSLayoutConstraint? public var textviewRightConstraint: NSLayoutConstraint? @@ -76,118 +74,29 @@ open class ChatInputView: UIView, ChatRecordViewDelegate, NotificationCenter.default.removeObserver(self) } - func commonUI() { - backgroundColor = UIColor(hexString: "#EFF1F3") - textView.layer.cornerRadius = 8 - textView.font = UIFont.systemFont(ofSize: 16) - textView.clipsToBounds = true - textView.translatesAutoresizingMaskIntoConstraints = false - textView.backgroundColor = .white - textView.returnKeyType = .send - textView.delegate = self - textView.allowsEditingTextAttributes = true - textView.typingAttributes = [NSAttributedString.Key.foregroundColor: UIColor.ne_darkText, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)] - textView.linkTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.ne_darkText, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)] - textView.dataDetectorTypes = [] - addSubview(textView) - textviewLeftConstraint = textView.leftAnchor.constraint(equalTo: leftAnchor, constant: 7) - textviewRightConstraint = textView.rightAnchor.constraint(equalTo: rightAnchor, constant: -7) - - NSLayoutConstraint.activate([ - textviewLeftConstraint!, - textviewRightConstraint!, - textView.topAnchor.constraint(equalTo: topAnchor, constant: 6), - textView.heightAnchor.constraint(equalToConstant: 40), - ]) - textInput = textView - - let imageNames = ["mic", "emoji", "photo", "add"] - - var items = [UIButton]() - for i in 0 ... 3 { - let button = UIButton(type: .custom) - button.setImage(UIImage.ne_imageNamed(name: imageNames[i]), for: .normal) - button.translatesAutoresizingMaskIntoConstraints = false - button.addTarget(self, action: #selector(buttonEvent), for: .touchUpInside) - button.tag = i + 5 - items.append(button) - } - - stackView = UIStackView(arrangedSubviews: items) - stackView.translatesAutoresizingMaskIntoConstraints = false - stackView.distribution = .fillEqually - addSubview(stackView) - NSLayoutConstraint.activate([ - stackView.leftAnchor.constraint(equalTo: leftAnchor), - stackView.rightAnchor.constraint(equalTo: rightAnchor), - stackView.heightAnchor.constraint(equalToConstant: 54), - stackView.topAnchor.constraint(equalTo: textView.bottomAnchor, constant: 0), - ]) - - greyView.translatesAutoresizingMaskIntoConstraints = false - greyView.backgroundColor = UIColor(hexString: "#EFF1F3") - greyView.isHidden = true - addSubview(greyView) - NSLayoutConstraint.activate([ - greyView.leftAnchor.constraint(equalTo: leftAnchor, constant: 0), - greyView.topAnchor.constraint(equalTo: topAnchor, constant: 0), - greyView.rightAnchor.constraint(equalTo: rightAnchor, constant: 0), - greyView.heightAnchor.constraint(equalToConstant: 100), - ]) - - addSubview(contentView) - contentView.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - contentView.leftAnchor.constraint(equalTo: leftAnchor), - contentView.rightAnchor.constraint(equalTo: rightAnchor), - contentView.heightAnchor.constraint(equalToConstant: contentHeight), - contentView.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 0), - ]) - - recordView.isHidden = true - recordView.translatesAutoresizingMaskIntoConstraints = false - recordView.delegate = self - recordView.backgroundColor = UIColor.ne_backgroundColor - contentView.addSubview(recordView) - NSLayoutConstraint.activate([ - recordView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 0), - recordView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: 0), - recordView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0), - recordView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0), - ]) - - contentView.addSubview(emojiView) - - contentView.addSubview(chatAddMoreView) - } + open func commonUI() {} public func addRecordView() { - if currentType != .audio { - currentType = .audio - textView.resignFirstResponder() - contentSubView?.isHidden = true - contentSubView = recordView - contentSubView?.isHidden = false - } + currentType = .audio + textView.resignFirstResponder() + contentSubView?.isHidden = true + contentSubView = recordView + contentSubView?.isHidden = false } public func addEmojiView() { - if currentType != .emoji { - currentType = .emoji - textView.resignFirstResponder() - contentSubView?.isHidden = true - contentSubView = emojiView - contentSubView?.isHidden = false - } + currentType = .emoji + textView.resignFirstResponder() + contentSubView?.isHidden = true + contentSubView = emojiView + contentSubView?.isHidden = false } public func addMoreActionView() { - if currentType != .addMore { - currentType = .addMore - contentSubView?.isHidden = true - contentSubView = chatAddMoreView - contentSubView?.isHidden = false - } + currentType = .addMore + contentSubView?.isHidden = true + contentSubView = chatAddMoreView + contentSubView?.isHidden = false } // MARK: ===================== lazy method ===================== @@ -338,12 +247,20 @@ open class ChatInputView: UIView, ChatRecordViewDelegate, // return true // } - func buttonEvent(button: UIButton) { + public func buttonEvent(button: UIButton) { + button.isSelected = !button.isSelected + if button.tag - 5 != 2, button != currentButton { + currentButton?.isSelected = false + currentButton = button + } + switch button.tag - 5 { case 0: addRecordView() case 1: addEmojiView() + case 2: + button.isSelected = true case 3: addMoreActionView() default: diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/ForwardAlertViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/NEBaseForwardAlertViewController.swift similarity index 86% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/ForwardAlertViewController.swift rename to NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/NEBaseForwardAlertViewController.swift index fb5bb560..dd11364d 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/ForwardAlertViewController.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/NEBaseForwardAlertViewController.swift @@ -7,6 +7,7 @@ import UIKit import NECommonKit import NECommonUIKit +@objc public class ForwardItem: NSObject { var name: String? var uid: String? @@ -15,13 +16,12 @@ public class ForwardItem: NSObject { } @objcMembers -public class ForwardUserCell: UICollectionViewCell { +public class NEBaseForwardUserCell: UICollectionViewCell { lazy var userHeader: NEUserHeaderView = { let header = NEUserHeaderView(frame: .zero) header.translatesAutoresizingMaskIntoConstraints = false header.titleLabel.font = NEConstant.defaultTextFont(11.0) header.clipsToBounds = true - header.layer.cornerRadius = 16.0 return header }() @@ -46,7 +46,8 @@ public class ForwardUserCell: UICollectionViewCell { } @objcMembers -public class ForwardAlertViewController: UIViewController { +public class NEBaseForwardAlertViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, + UICollectionViewDelegateFlowLayout { var datas = [ForwardItem]() typealias ForwardCallBack = () -> Void @@ -54,6 +55,9 @@ public class ForwardAlertViewController: UIViewController { var sureBlock: ForwardCallBack? var context = "" + public let sureBtn = UIButton() + public let tip = UILabel() + lazy var userCollection: UICollectionView = { let flow = UICollectionViewFlowLayout() flow.scrollDirection = .horizontal @@ -80,7 +84,6 @@ public class ForwardAlertViewController: UIViewController { lazy var oneUserHead: NEUserHeaderView = { let header = NEUserHeaderView(frame: .zero) header.clipsToBounds = true - header.layer.cornerRadius = 16.0 header.translatesAutoresizingMaskIntoConstraints = false return header }() @@ -118,7 +121,6 @@ public class ForwardAlertViewController: UIViewController { contentView.widthAnchor.constraint(equalToConstant: 276), ]) - let tip = UILabel() tip.translatesAutoresizingMaskIntoConstraints = false tip.font = NEConstant.defaultTextFont(16.0) tip.textColor = .ne_darkText @@ -206,10 +208,9 @@ public class ForwardAlertViewController: UIViewController { canceBtn.setTitle(chatLocalizable("cancel"), for: .normal) canceBtn.setTitleColor(.ne_greyText, for: .normal) - let sureBtn = UIButton() sureBtn.translatesAutoresizingMaskIntoConstraints = false sureBtn.addTarget(self, action: #selector(sureClick), for: .touchUpInside) - sureBtn.setTitle(chatLocalizable("confirm"), for: .normal) + sureBtn.setTitle(chatLocalizable("send"), for: .normal) sureBtn.setTitleColor(.ne_blueText, for: .normal) contentView.addSubview(canceBtn) @@ -227,11 +228,6 @@ public class ForwardAlertViewController: UIViewController { sureBtn.topAnchor.constraint(equalTo: horizontalLine.bottomAnchor), sureBtn.leftAnchor.constraint(equalTo: verticalLine.rightAnchor), ]) - - userCollection.register( - ForwardUserCell.self, - forCellWithReuseIdentifier: "\(ForwardUserCell.self)" - ) } public func setItems(_ items: [ForwardItem]) { @@ -248,6 +244,7 @@ public class ForwardAlertViewController: UIViewController { if let url = item.avatar { oneUserHead.sd_setImage(with: URL(string: url), completed: nil) oneUserHead.titleLabel.text = "" + oneUserHead.backgroundColor = .clear } else { oneUserHead.backgroundColor = UIColor.colorWithString(string: item.uid) oneUserHead.image = nil @@ -259,16 +256,6 @@ public class ForwardAlertViewController: UIViewController { } } - /* - // MARK: - Navigation - - // In a storyboard-based application, you will often want to do a little preparation before navigation - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - // Get the new view controller using segue.destination. - // Pass the selected object to the new view controller. - } - */ - func sureClick() { if let block = sureBlock { block() @@ -291,37 +278,33 @@ public class ForwardAlertViewController: UIViewController { view.removeFromSuperview() removeFromParent() } -} -extension ForwardAlertViewController: UICollectionViewDelegate, UICollectionViewDataSource, - UICollectionViewDelegateFlowLayout { public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { datas.count } - public func collectionView(_ collectionView: UICollectionView, - cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - if let cell = collectionView.dequeueReusableCell( - withReuseIdentifier: "\(ForwardUserCell.self)", - for: indexPath - ) as? ForwardUserCell { - let item = datas[indexPath.row] - if let url = item.avatar { - cell.userHeader.sd_setImage(with: URL(string: url), completed: nil) - cell.userHeader.titleLabel.text = "" - } else { - cell.userHeader.backgroundColor = UIColor.colorWithString(string: item.uid) - cell.userHeader.image = nil - if let name = item.name { - cell.userHeader.setTitle(name) - } else if let uid = item.uid { - cell.userHeader.setTitle(uid) - } + open func setCellModel(cell: NEBaseForwardUserCell, indexPath: IndexPath) -> UICollectionViewCell { + let item = datas[indexPath.row] + if let url = item.avatar { + cell.userHeader.sd_setImage(with: URL(string: url), completed: nil) + cell.userHeader.titleLabel.text = "" + cell.userHeader.backgroundColor = .clear + } else { + cell.userHeader.backgroundColor = UIColor.colorWithString(string: item.uid) + cell.userHeader.image = nil + if let name = item.name { + cell.userHeader.setTitle(name) + } else if let uid = item.uid { + cell.userHeader.setTitle(uid) } - return cell } - return UICollectionViewCell() + return cell + } + + public func collectionView(_ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + UICollectionViewCell() } public func collectionView(_ collectionView: UICollectionView, diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/NEChatMoreActionView.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/NEChatMoreActionView.swift index b169c3c6..803642f0 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/NEChatMoreActionView.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/NEChatMoreActionView.swift @@ -6,7 +6,7 @@ import UIKit @objc -public protocol NEMoreViewDelagate: NSObjectProtocol { +public protocol NEMoreViewDelegate: NSObjectProtocol { func moreViewDidSelectMoreCell(moreView: NEChatMoreActionView, cell: NEInputMoreCell) } @@ -23,7 +23,7 @@ public class NEChatMoreActionView: UIView { private var itemIndexs: [IndexPath: NSNumber]? - public weak var delegate: NEMoreViewDelagate? + public weak var delegate: NEMoreViewDelegate? override init(frame: CGRect) { super.init(frame: frame) diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/NEInputMoreCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/NEInputMoreCell.swift index bfaef7ac..76204030 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/NEInputMoreCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/ChatView/NEInputMoreCell.swift @@ -5,6 +5,7 @@ import UIKit +@objcMembers public class NEInputMoreCell: UICollectionViewCell { public var cellData: NEMoreItemModel? diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/MapView/NEMapAddressCell.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/MapView/NEMapAddressCell.swift index 5c141e0e..9ee5b0e5 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/MapView/NEMapAddressCell.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/MapView/NEMapAddressCell.swift @@ -5,6 +5,7 @@ import UIKit import NEChatKit +@objcMembers public class NEMapAddressCell: UITableViewCell { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/MapView/NEMapGuideBottomView.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/MapView/NEMapGuideBottomView.swift index c0e39d72..a381cd9a 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/View/MapView/NEMapGuideBottomView.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/View/MapView/NEMapGuideBottomView.swift @@ -4,10 +4,12 @@ import UIKit +@objc public protocol NEMapGuideBottomViewDelegate: NSObjectProtocol { func didClickGuide() } +@objcMembers public class NEMapGuideBottomView: UIView { public weak var delegate: NEMapGuideBottomViewDelegate? @@ -74,7 +76,7 @@ public class NEMapGuideBottomView: UIView { return label }() - @objc func guideBtnClick() { + func guideBtnClick() { if let delegate = delegate { delegate.didClickGuide() } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/ViewModel/ChatViewModel.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/ViewModel/ChatViewModel.swift index a44e8631..5b78a870 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/ViewModel/ChatViewModel.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/ViewModel/ChatViewModel.swift @@ -33,6 +33,9 @@ public protocol ChatViewModelDelegate: NSObjectProtocol { func didLeaveTeam() func didDismissTeam() func didRefreshTable() + + @objc optional + func getMessageModel(model: MessageModel) } let revokeLocalMessage = "revoke_message_local" @@ -41,7 +44,7 @@ let removePinMessageNoti = "remove_pin_message_noti" @objcMembers public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDelegate, - NIMConversationManagerDelegate, NIMSystemNotificationManagerDelegate, ChatExtendProviderDelegate, NIMUserManagerDelegate { + NIMConversationManagerDelegate, NIMSystemNotificationManagerDelegate, ChatExtendProviderDelegate, FriendProviderDelegate { public var team: NIMTeam? public var session: NIMSession public var messages = [MessageModel]() @@ -66,13 +69,15 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel public var filterInviteSet = Set() + public var deletingMsgDic = Set() + init(session: NIMSession) { NELog.infoLog(ModuleName + " " + className, desc: #function + ", sessionId:" + session.sessionId) self.session = session anchor = nil super.init() - NIMSDK.shared().userManager.add(self) repo.addChatDelegate(delegate: self) + repo.addContactDelegate(delegate: self) repo.addSessionDelegate(delegate: self) repo.addSystemNotificationDelegate(delegate: self) repo.addChatExtendDelegate(delegate: self) @@ -87,8 +92,8 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel if anchor != nil { isHistoryChat = true } - NIMSDK.shared().userManager.add(self) repo.addChatDelegate(delegate: self) + repo.addContactDelegate(delegate: self) repo.addSessionDelegate(delegate: self) repo.addSystemNotificationDelegate(delegate: self) repo.addChatExtendDelegate(delegate: self) @@ -249,9 +254,10 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel // 第一条消息默认显示时间 if i == datas.count - 1 { - let model = MessageTipsModel(message: msg) - model.type = .time - model.text = String.stringFromDate(date: Date(timeIntervalSince1970: msg.timestamp)) + let timeText = String.stringFromDate(date: Date(timeIntervalSince1970: msg.timestamp)) + let model = MessageTipsModel(message: nil, + initType: .time, + initText: timeText) weakSelf?.messages.insert(model, at: 0) } } else { @@ -281,6 +287,7 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel desc: "CALLBACK markRead " + (error?.localizedDescription ?? "no error") ) } + weakSelf?.refreshReceipts(messages: messageArray) } } else { completion(error, 0, weakSelf?.messages) @@ -288,8 +295,7 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel } } - public func queryRoamMsgHasMoreTime_v2(_ completion: @escaping (Error?, NSInteger, NSInteger, - [MessageModel]?, Int) -> Void) { + public func queryRoamMsgHasMoreTime_v2(_ completion: @escaping (Error?, NSInteger, NSInteger, Int) -> Void) { NELog.infoLog(ModuleName + " " + className, desc: #function) weak var weakSelf = self // 记录可信时间戳 @@ -299,7 +305,7 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel ModuleName + " " + self.className, desc: "CALLBACK getMessageHistory " + (error?.localizedDescription ?? "no error") ) - completion(error, count, 0, models, 0) + completion(error, count, 0, 0) } } else { @@ -325,39 +331,32 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel historyDatas.append(contentsOf: ms) } print("drop down remote refresh : ", historyDatas.count) - group.leave() - } - - group.enter() - weakSelf?.getMessagesModelDynamically(.asc, message: weakSelf?.anchor) { error, value, models in - NELog.infoLog( - ModuleName + " " + self.className, - desc: "CALLBACK pullRemoteRefresh " + (error?.localizedDescription ?? "no error") - ) - newEnd = value - if err != nil { - err = error - } - if let ms = models { - newDatas.append(contentsOf: ms) - } - print("pull remote refresh : ", newDatas.count) - group.leave() - } - - group.notify(queue: DispatchQueue.main, execute: { - var finalDatas = [MessageModel]() - finalDatas.append(contentsOf: historyDatas) if let anchorMessage = weakSelf?.anchor { let model = self.modelFromMessage(message: anchorMessage) weakSelf?.filterRevokeMessage([model]) if NotificationMessageUtils.isDiscussSeniorTeamUpdateCustomNoti(message: anchorMessage) == false { - weakSelf?.messages.insert(model, at: moreEnd) - finalDatas.append(model) + weakSelf?.messages.append(model) } } - finalDatas.append(contentsOf: newDatas) - completion(err, moreEnd, newEnd, finalDatas, historyDatas.count) + weakSelf?.getMessagesModelDynamically(.asc, message: weakSelf?.anchor) { error, value, models in + NELog.infoLog( + ModuleName + " " + self.className, + desc: "CALLBACK pullRemoteRefresh " + (error?.localizedDescription ?? "no error") + ) + newEnd = value + if err != nil { + err = error + } + if let ms = models { + newDatas.append(contentsOf: ms) + } + print("pull remote refresh : ", newDatas.count) + group.leave() + } + } + + group.notify(queue: DispatchQueue.main, execute: { + completion(err, moreEnd, newEnd, historyDatas.count) }) } } @@ -515,6 +514,15 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel // 下拉获取历史消息 public func dropDownRemoteRefresh(_ completion: @escaping (Error?, NSInteger, [MessageModel]?) -> Void) { + // 首次会话下拉,没有锚点消息,需要手动设置锚点消息 + if oldMsg == nil { + for msg in messages { + if let mmsg = msg.message { + oldMsg = mmsg + break + } + } + } getMessagesModelDynamically(.desc, message: oldMsg, completion) NELog.infoLog(ModuleName + " " + className, desc: #function) } @@ -522,10 +530,6 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel // 上拉获取最新消息 public func pullRemoteRefresh(_ completion: @escaping (Error?, NSInteger, [MessageModel]?) -> Void) { -// var message = messages.last?.message -// if message == nil, let tip = messages.last as? MessageTipsModel { -// message = tip.tipMessage -// } getMessagesModelDynamically(.asc, message: newMsg, completion) NELog.infoLog(ModuleName + " " + className, desc: #function) } @@ -621,16 +625,37 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel receipts.append(receipt) } } - repo.markTeamMessageRead(param: receipts) { error, failedReceipts in - print("!! chatViewModel markReadInTeam error:\(error)") - completion(error) + let receiptsChunk = receipts.chunk(50) + for receipt in receiptsChunk { + repo.markTeamMessageRead(param: receipt) { error, failedReceipts in + print("!! chatViewModel markReadInTeam error:\(String(describing: error))") + completion(error) + } } } - public func deleteMessage(message: NIMMessage) { + public func deleteMessage(message: NIMMessage, _ completion: @escaping (Error?) -> Void) { NELog.infoLog(ModuleName + " " + className, desc: #function + ", messageId:" + message.messageId) - repo.deleteMessage(message: message) - deleteMessageUpdateUI(message) + if deletingMsgDic.contains(message.messageId) { + return + } + deletingMsgDic.insert(message.messageId) + if message.serverID.count <= 0 { + repo.deleteMessage(message: message) + deleteMessageUpdateUI(message) + deletingMsgDic.remove(message.messageId) + completion(nil) + return + } + weak var weakSelf = self + repo.deleteServerMessage(message: message, ext: nil) { error in + if error == nil { + weakSelf?.deleteMessageUpdateUI(message) + } else { + completion(error) + } + weakSelf?.deletingMsgDic.remove(message.messageId) + } } public func replyMessage(_ message: NIMMessage, _ target: NIMMessage, @@ -698,25 +723,33 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel } } - // MARK: NIMUserManagerDelegate + // MARK: FriendProviderDelegate - public func onFriendChanged(_ user: NIMUser) { + public func onFriendChanged(user: User) { if let uid = user.userId { - newUserInfoDic[uid] = User(user: user) + newUserInfoDic[uid] = user delegate?.didRefreshTable() } } + public func onUserInfoChanged(user: User) { + if let uid = user.userId { + newUserInfoDic[uid] = user + delegate?.didRefreshTable() + } + } + + public func onBlackListChanged() {} + // MARK: NIMChatManagerDelegate // 收到消息 public func onRecvMessages(_ messages: [NIMMessage]) { NELog.infoLog(ModuleName + " " + className, desc: #function + ", messages.count: \(messages.count)") - print("\(#function) 1messages:\(messages.count)") var count = 0 for msg in messages { if msg.session?.sessionId == session.sessionId { - if msg.serverID.count <= 0 { + if msg.serverID.count <= 0, msg.messageType != .custom { continue } if msg.isDeleted == true { @@ -749,12 +782,10 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel }*/ count += 1 // 自定义消息处理 - if msg.messageType == .custom { - } else { - newMsg = msg - addTimeMessage(msg) - self.messages.append(modelFromMessage(message: msg)) - } + newMsg = msg + addTimeMessage(msg) + let model = modelFromMessage(message: msg) + self.messages.append(model) } } if count > 0 { delegate?.onRecvMessages(messages) } @@ -797,7 +828,7 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel delegate?.send(message, progress: progress) } - public func send(_ message: NIMMessage, didCompleteWithError error: Error?) { + open func send(_ message: NIMMessage, didCompleteWithError error: Error?) { NELog.infoLog(ModuleName + " " + className, desc: #function + ", messageId: " + message.messageId) print("\(#function) message deliveryState:\(message.deliveryState) error:\(error)") for (i, msg) in messages.enumerated() { @@ -898,13 +929,14 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel guard let msg = notification.message else { return } + revokeMessageUpdateUI(msg) } public func onRecvMessageReceipts(_ receipts: [NIMMessageReceipt]) { NELog.infoLog(ModuleName + " " + className, desc: #function + ", receipts.count: \(receipts.count)") print( - "chatViewModel: receipts:\(receipts.count) messageId:\(receipts.first?.messageId) messageId:\(receipts.first?.timestamp)" + "chatViewModel: :\(receipts.count) messageId:\(receipts.first?.messageId) messageId:\(receipts.first?.timestamp)" ) delegate?.didReadedMessageIndexs() } @@ -1055,9 +1087,10 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel let curTs = message.timestamp let dur = firstTs - curTs if (dur / 60) > 5 { - let model = MessageTipsModel(message: message) - model.type = .time - model.text = String.stringFromDate(date: Date(timeIntervalSince1970: firstTs)) + let timeText = String.stringFromDate(date: Date(timeIntervalSince1970: firstTs)) + let model = MessageTipsModel(message: nil, + initType: .time, + initText: timeText) messages.insert(model, at: 0) return true } @@ -1067,9 +1100,10 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel private func timeModel(_ message: NIMMessage) -> MessageModel { NELog.infoLog(ModuleName + " " + className, desc: #function + ", messageId: " + message.messageId) let curTs = message.timestamp - let model = MessageTipsModel(message: message) - model.type = .time - model.text = String.stringFromDate(date: Date(timeIntervalSince1970: curTs)) + let timeText = String.stringFromDate(date: Date(timeIntervalSince1970: curTs)) + let model = MessageTipsModel(message: nil, + initType: .time, + initText: timeText) return model } @@ -1092,21 +1126,12 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel model = MessageImageModel(message: message) case .audio: model = MessageAudioModel(message: message) -// case .video: -// <#code#> - case .notification: + case .notification, .tip: model = MessageTipsModel(message: message) case .file: model = MessageFileModel(message: message) - case .tip: - model = MessageTipsModel(message: message) -// case .robot: -// <#code#> -// case .rtcCallRecord: -// <#code#> case .custom: model = MessageCustomModel(message: message) - case .location: model = MessageLocationModel(message: message) case .rtcCallRecord: @@ -1147,6 +1172,7 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel } else { model.isPined = false } + delegate?.getMessageModel?(model: model) return model } @@ -1256,7 +1282,7 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel replyIndex.append(i) } } else { - if model.message?.serverID == message.serverID { + if model.message?.messageId == message.messageId { index = i hasFind = true } @@ -1293,6 +1319,7 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel var index = -1 var replyIndex = [Int]() var hasFind = false + for (i, model) in messages.enumerated() { if hasFind { var replyId: String? = model.message?.repliedMessageId @@ -1310,6 +1337,7 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel } } } + var indexs = [IndexPath]() if index >= 0 { messages[index].isRevoked = true @@ -1380,16 +1408,12 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel public func forwardUserMessage(_ message: NIMMessage, _ users: [NIMUser]) { NELog.infoLog(ModuleName + " " + className, desc: #function + ", messageId: " + message.messageId) - weak var weakSelf = self users.forEach { user in if let uid = user.userId { let session = NIMSession(uid, type: .P2P) - // weakSelf?.repo.makeForwardMessage(message, session) - if let forwardMessage = weakSelf?.repo.makeForwardMessage(message) { + if let forwardMessage = repo.makeForwardMessage(message) { clearForwardAtMark(forwardMessage) - weakSelf?.repo.sendMessage(message: forwardMessage, session: session) { error in - NELog.infoLog("chat view model ", desc: "forward message : \(error?.localizedDescription ?? "")") - } + repo.sendForwardMessage(forwardMessage, session) } } } @@ -1399,12 +1423,9 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel NELog.infoLog(ModuleName + " " + className, desc: #function + ", messageId: " + message.messageId) if let tid = team.teamId { let session = NIMSession(tid, type: .team) - // repo.makeForwardMessage(message, session) if let forwardMessage = repo.makeForwardMessage(message) { clearForwardAtMark(forwardMessage) - repo.sendMessage(message: forwardMessage, session: session) { error in - NELog.infoLog("chat view model ", desc: "forward message : \(error?.localizedDescription ?? "")") - } + repo.sendForwardMessage(forwardMessage, session) } } } @@ -1534,7 +1555,7 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel } } - public func refreshReceipts() { + public func refreshReceipts(messages: [NIMMessage]) { if session.sessionType != .team { return } @@ -1543,14 +1564,14 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel } print("refresh team id : ", session.sessionId) var receiptsMessages = [NIMMessage]() - messages.forEach { model in - if let message = model.message, message.setting?.teamReceiptEnabled == true, - let unreadCount = message.teamReceiptInfo?.unreadCount, unreadCount > 0 { - print("unread count : ", unreadCount as Any) + messages.forEach { message in + if message.setting?.teamReceiptEnabled == true { receiptsMessages.append(message) } } - repo.refreshReceipts(receiptsMessages) + for receipt in receiptsMessages.chunk(50) { + repo.refreshReceipts(receipt) + } } @discardableResult @@ -1570,27 +1591,34 @@ public class ChatViewModel: NSObject, ChatRepoMessageDelegate, NIMChatManagerDel // MARK: NIMConversationManagerDelegate -// remote -// public func onRecvMessagesDeleted(_ messages: [NIMMessage], exts: [String : String]?) { -// if let message = messages.first { -// var index = -1 -// for (i, model) in self.messages.enumerated() { -// if model.message?.serverID == message.serverID { -// index = i -// break -// } -// } -// if index > 0 { -// self.messages.remove(at: index) -// } -// self.delegate?.onDeleteMessage(message) -// } -// print("onRecvMessagesDeleted: \(messages.first) exts:\(exts)") -// } -// -// public func onRecvMessageDeleted(_ message: NIMMessage, ext: String?) { -// print("onRecvMessagesDeleted: \(message) exts:\(ext)") -// } + // remote + public func onRecvMessagesDeleted(_ messages: [NIMMessage], exts: [String: String]?) { + var messageIDs = Set() + messages.forEach { message in + if message.session?.sessionId != session.sessionId { + return + } + if message.messageId.count <= 0 { + return + } + messageIDs.insert(message.messageId) + } + if messageIDs.count > 0 { + self.messages.removeAll { model in + if let messageId = model.message?.messageId, messageId.count > 0 { + if messageIDs.contains(messageId) { + return true + } + } + return false + } + if let lastModel = self.messages.last as? MessageTipsModel, lastModel.type == .time { + self.messages.removeLast() + } + delegate?.didRefreshTable() + } + } + deinit { print("deinit") } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/ViewModel/PinMessageViewModel.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/ViewModel/PinMessageViewModel.swift index 28afccdc..03a080f5 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/ViewModel/PinMessageViewModel.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/ViewModel/PinMessageViewModel.swift @@ -12,19 +12,31 @@ public protocol PinMessageViewModelDelegate: NSObjectProtocol { } @objcMembers -public class PinMessageViewModel: NSObject, ChatExtendProviderDelegate, NIMChatManagerDelegate { +public class PinMessageViewModel: NSObject, ChatExtendProviderDelegate, NIMChatManagerDelegate, NIMConversationManagerDelegate { public let chatRepo = ChatRepo() public var items = [PinMessageModel]() public var delegate: PinMessageViewModelDelegate? + public var session: NIMSession? override public init() { super.init() chatRepo.addChatDelegate(delegate: self) chatRepo.addChatExtendDelegate(delegate: self) + NIMSDK.shared().conversationManager.add(self) + } + + public func onRecvMessagesDeleted(_ messages: [NIMMessage], exts: [String: String]?) { + for message in messages { + if message.session?.sessionId == session?.sessionId { + delegate?.didNeedRefreshUI() + break + } + } } public func getPinitems(session: NIMSession, _ completion: @escaping (Error?) -> Void) { weak var weakSelf = self + self.session = session chatRepo.fetchPinMessage(session.sessionId, session.sessionType) { error, pinItems in if let pins = pinItems { if error == nil { @@ -92,14 +104,12 @@ public class PinMessageViewModel: NSObject, ChatExtendProviderDelegate, NIMChatM public func forwardUserMessage(_ message: NIMMessage, _ users: [NIMUser]) { NELog.infoLog(ModuleName + " " + className(), desc: #function + ", messageId: " + message.messageId) - weak var weakSelf = self users.forEach { user in if let uid = user.userId { let session = NIMSession(uid, type: .P2P) - if let forwardMessage = weakSelf?.chatRepo.makeForwardMessage(message) { - weakSelf?.clearForwardAtMark(forwardMessage) - weakSelf?.chatRepo.sendMessage(message: forwardMessage, session: session) { error in - } + if let forwardMessage = chatRepo.makeForwardMessage(message) { + clearForwardAtMark(forwardMessage) + chatRepo.sendForwardMessage(forwardMessage, session) } } } @@ -111,9 +121,7 @@ public class PinMessageViewModel: NSObject, ChatExtendProviderDelegate, NIMChatM let session = NIMSession(tid, type: .team) if let forwardMessage = chatRepo.makeForwardMessage(message) { clearForwardAtMark(forwardMessage) - chatRepo.sendMessage(message: forwardMessage, session: session) { error in - NELog.infoLog("chat view model ", desc: "forward message : \(error?.localizedDescription ?? "")") - } + chatRepo.sendForwardMessage(forwardMessage, session) } } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/ViewModel/TeamChatViewModel.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/ViewModel/TeamChatViewModel.swift index 0a9cbd71..87a6473b 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/ViewModel/TeamChatViewModel.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/ViewModel/TeamChatViewModel.swift @@ -6,6 +6,7 @@ import Foundation import NIMSDK import CoreText import NECoreIMKit + @objc public protocol TeamChatViewModelDelegate: ChatViewModelDelegate { func onTeamRemoved(team: NIMTeam) diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/ViewModel/TeamMemberSelectVM.swift b/NEChatUIKit/NEChatUIKit/Classes/Chat/ViewModel/TeamMemberSelectVM.swift index 4e224587..ff78d649 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/ViewModel/TeamMemberSelectVM.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Chat/ViewModel/TeamMemberSelectVM.swift @@ -6,6 +6,7 @@ import Foundation import NIMSDK import NEChatKit import NECoreIMKit + @objcMembers public class TeamMemberSelectVM: NSObject { public var chatRepo: ChatRepo = .init() diff --git a/NEChatUIKit/NEChatUIKit/Classes/ChatConfig/ChatUIConfig.swift b/NEChatUIKit/NEChatUIKit/Classes/ChatConfig/ChatUIConfig.swift index bcb77912..de742d2f 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/ChatConfig/ChatUIConfig.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/ChatConfig/ChatUIConfig.swift @@ -17,10 +17,10 @@ public class ChatUIConfig: NSObject { /// UI 元素自定义 // 头像圆角大小 - public var avatarCornerRadius = 4.0 + public var avatarCornerRadius: CGFloat? // 头像类型 - public var avatarType: NEChatAvatarType = .cycle + public var avatarType: NEChatAvatarType? // 设置聊天消息标记的背景色 public var signalBgColor = UIColor.ne_yellowBackgroundColor @@ -29,13 +29,13 @@ public class ChatUIConfig: NSObject { public var timeTextColor = UIColor.ne_emptyTitleColor // 时间字体大小 - public var timeTextSize: Float = 12 + public var timeTextSize: CGFloat = 14 // 右侧聊天背景气泡 - public var rightBubbleBg = UIImage.ne_imageNamed(name: "chat_message_send") + public var rightBubbleBg: UIImage? // 左侧聊天背景气泡 - public var leftBubbleBg = UIImage.ne_imageNamed(name: "chat_message_receive") + public var leftBubbleBg: UIImage? // 聊天字体大小(文本类型) public var messageTextSize = UIFont.systemFont(ofSize: 16) @@ -44,13 +44,10 @@ public class ChatUIConfig: NSObject { public var messageTextColor = UIColor.ne_darkText // 自己发送的消息体的背景色 - public var selfMessageBg: UIColor? + public var selfMessageBg: UIColor = .clear // 接收到的消息体的背景色 - public var receiveMessageBg: UIColor? - - // 他人发送消息内容的背景资源ID - // 自己发送消息内容的背景资源ID + public var receiveMessageBg: UIColor = .clear // 不设置头像的用户所展示的文字头像中的文字颜色 public var userNickColor: UIColor = .white @@ -59,28 +56,19 @@ public class ChatUIConfig: NSObject { public var userNickTextSize: CGFloat = 12 // 单聊中是否展示已读未读状态 - public var showP2pMessageStatus: Bool? + public var showP2pMessageStatus: Bool = true // 群聊中是否展示已读未读状态 - public var showTeamMessageStatus: Bool? + public var showTeamMessageStatus: Bool = true // 会话界面是否展示标题栏 - public var showTitleBar: Bool? + public var showTitleBar: Bool = true // 是否展示标题栏右侧图标按钮 - public var showTitleBarRightIcon: Bool? + public var showTitleBarRightIcon: Bool = true // 设置标题栏右侧图标按钮展示图标 public var titleBarRightRes: UIImage? // 标题栏右侧图标的点击事件 public var titleBarRightClick: (() -> Void)? // 设置会话界面背景色 - public var chatViewBackground: UIColor = .white - - /// 界面布局自定义 - // 会话界面(即聊天界面)的标题视图 - // 会话界面的消息列表上方的小块视图 - // 会话界面的消息列表视图 - // 会话界面的消息列表下视图 - // 会话界面的底部输入框视图 - // 会话界面的消息列表 - // 会话界面的底部输入框视图 + public var chatViewBackground: UIColor? /// 用户可自定义参数 diff --git a/NEChatUIKit/NEChatUIKit/Classes/ChatConfig/NEKitChatConfig.swift b/NEChatUIKit/NEChatUIKit/Classes/ChatConfig/NEKitChatConfig.swift index b11bae19..f29d9027 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/ChatConfig/NEKitChatConfig.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/ChatConfig/NEKitChatConfig.swift @@ -9,6 +9,8 @@ import UIKit public class NEKitChatConfig: NSObject { public static let shared = NEKitChatConfig() + public var maxReadingNum = 200 // 群未读显示限制数,默认超过200人不显示已读未读进度 + // chat UI配置相关 public var ui = ChatUIConfig() diff --git a/NEChatUIKit/NEChatUIKit/Classes/ChatRouter/NEBaseChatRouter.swift b/NEChatUIKit/NEChatUIKit/Classes/ChatRouter/NEBaseChatRouter.swift new file mode 100644 index 00000000..33540dd6 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/ChatRouter/NEBaseChatRouter.swift @@ -0,0 +1,23 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import NIMSDK +import NECommonKit +import SDWebImage +import SDWebImageWebPCoder +import SDWebImageSVGKitPlugin + +@objcMembers +public class ChatRouter: NSObject { + public static func setupInit() { + NIMKitFileLocationHelper.setStaticAppkey(NIMSDK.shared().appKey()) + NIMKitFileLocationHelper.setStaticUserId(NIMSDK.shared().loginManager.currentAccount()) + let webpCoder = SDImageWebPCoder() + SDImageCodersManager.shared.addCoder(webpCoder) + let svgCoder = SDImageSVGKCoder.shared + SDImageCodersManager.shared.addCoder(svgCoder) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Common/ChatCellConstantValue.swift b/NEChatUIKit/NEChatUIKit/Classes/Common/ChatCellConstantValue.swift index 474ab1de..17070440 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Common/ChatCellConstantValue.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Common/ChatCellConstantValue.swift @@ -6,28 +6,31 @@ import Foundation // 距离cell边缘的距离 -public let qChat_cell_margin = 16.0 +public let chat_cell_margin = 16.0 // 控件之间的间距 -public let qChat_margin = 8.0 +public let chat_content_margin = 8.0 // 头像宽高 -public let qChat_headWH = 32.0 +public let chat_headWH = 32.0 // 时间cell的高度(固定) -public let qChat_timeCellH = 21.0 +public let chat_timeCellH = 21.0 // 图片最大宽高 -public let qChat_pic_size = CGSize(width: 150, height: 200) +public let chat_pic_size = CGSize(width: 150, height: 200) // 文件宽高 public let chat_file_size = CGSize(width: 254, height: 56) // 单行气泡高度 -public let qChat_min_h = 40.0 +public let chat_min_h = 40.0 -// 内容尾部距离cell边框的间距 +// 回复消息replyLabel高度 public let chat_reply_height = 16.0 -// 内容最大宽度 -public let qChat_content_maxW = (kScreenWidth - 136) +// 气泡最大宽度 +public let chat_content_maxW = (kScreenWidth - 136) + +// 文本内容最大宽度 +public let chat_text_maxW = chat_content_maxW - 2 * chat_content_margin // pin消息需要增加的高度 public let chat_pin_height = 16.0 diff --git a/NEChatUIKit/NEChatUIKit/Classes/Common/NEChatUITool.swift b/NEChatUIKit/NEChatUIKit/Classes/Common/NEChatUITool.swift index 992ed786..44385449 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Common/NEChatUITool.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Common/NEChatUITool.swift @@ -5,6 +5,7 @@ import Foundation +@objcMembers public class NEChatUITool { // 计算富文本size class func getSizeWithAtt(att: NSAttributedString, font: UIFont, maxSize: CGSize) -> CGSize { diff --git a/NEChatUIKit/NEChatUIKit/Classes/Extension/ChatStringExtension.swift b/NEChatUIKit/NEChatUIKit/Classes/Extension/ChatStringExtension.swift index 531c772f..20889428 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Extension/ChatStringExtension.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/Extension/ChatStringExtension.swift @@ -5,6 +5,13 @@ import Foundation +// 缓存的用于计算高度的Label +var tempLabelForCalc: UILabel = { + let label = UILabel() + label.numberOfLines = 0 + return label +}() + extension String { // 计算文字size static func getTextRectSize(_ text: String, font: UIFont, size: CGSize) -> CGSize { @@ -12,7 +19,7 @@ extension String { let option = NSStringDrawingOptions.usesLineFragmentOrigin let rect: CGRect = text.boundingRect(with: size, options: option, attributes: attributes, context: nil) - return rect.size + return CGSize(width: ceil(rect.width), height: ceil(rect.height)) } /// 计算 string 的行数,使用 font 的 lineHeight @@ -43,6 +50,29 @@ extension String { return fmt.string(from: date) } + static func date24To12(_ string: String?) -> String { + guard let str = string else { + return "" + } + let fmt = DateFormatter() + fmt.dateFormat = "HH:mm" + if let date = fmt.date(from: str) { + fmt.dateFormat = "a hh:mm" + return fmt.string(from: date) + } + fmt.dateFormat = chatLocalizable("mdhm") + if let date = fmt.date(from: str) { + fmt.dateFormat = "MM月dd日 a hh:mm" + return fmt.string(from: date) + } + fmt.dateFormat = chatLocalizable("ymdhm") + if let date = fmt.date(from: str) { + fmt.dateFormat = "yyyy年MM月dd日 a hh:mm" + return fmt.string(from: date) + } + return "" + } + static func firstDayInYear() -> Date? { let format = DateFormatter() format.dateFormat = "yyyy-MM-dd" @@ -50,3 +80,23 @@ extension String { return format.date(from: "\(year)-01-01") } } + +extension String { + // 利用 sizeThatFits 计算 UIlabel 纯文本大小 + func finalSize(_ font: UIFont, _ size: CGSize, _ lines: Int = 0) -> CGSize { + tempLabelForCalc.numberOfLines = lines + tempLabelForCalc.font = font + tempLabelForCalc.text = self + return tempLabelForCalc.sizeThatFits(size) + } +} + +extension NSAttributedString { + // 利用 sizeThatFits 计算 UIlabel 富文本大小 + func finalSize(_ font: UIFont, _ size: CGSize, _ lines: Int = 0) -> CGSize { + tempLabelForCalc.numberOfLines = lines + tempLabelForCalc.font = font + tempLabelForCalc.attributedText = self + return tempLabelForCalc.sizeThatFits(size) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageAudioCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageAudioCell.swift new file mode 100644 index 00000000..9f649440 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageAudioCell.swift @@ -0,0 +1,144 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FunChatMessageAudioCell: FunChatMessageBaseCell, ChatAudioCellProtocol { + public var messageId: String? + public var isPlaying: Bool = false + + public var audioImageViewLeft = UIImageView(image: UIImage.ne_imageNamed(name: "left_play_3")) + public var timeLabelLeft = UILabel() + + public var audioImageViewRight = UIImageView(image: UIImage.ne_imageNamed(name: "audio_play")) + public var timeLabelRight = UILabel() + + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + commonUI() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func commonUI() { + commonUIRight() + commonUILeft() + } + + open func commonUILeft() { + audioImageViewLeft.contentMode = .center + audioImageViewLeft.translatesAutoresizingMaskIntoConstraints = false + bubbleImageLeft.addSubview(audioImageViewLeft) + NSLayoutConstraint.activate([ + audioImageViewLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor, constant: 16), + audioImageViewLeft.centerYAnchor.constraint(equalTo: bubbleImageLeft.centerYAnchor), + audioImageViewLeft.widthAnchor.constraint(equalToConstant: 28), + audioImageViewLeft.heightAnchor.constraint(equalToConstant: 28), + ]) + + timeLabelLeft.font = UIFont.systemFont(ofSize: 14) + timeLabelLeft.textColor = UIColor.ne_darkText + timeLabelLeft.textAlignment = .left + timeLabelLeft.translatesAutoresizingMaskIntoConstraints = false + bubbleImageLeft.addSubview(timeLabelLeft) + NSLayoutConstraint.activate([ + timeLabelLeft.leftAnchor.constraint(equalTo: audioImageViewLeft.rightAnchor, constant: 12), + timeLabelLeft.centerYAnchor.constraint(equalTo: bubbleImageLeft.centerYAnchor), + timeLabelLeft.rightAnchor.constraint(equalTo: bubbleImageLeft.rightAnchor, constant: -12), + timeLabelLeft.heightAnchor.constraint(equalToConstant: 28), + ]) + audioImageViewLeft.animationDuration = 1 + if let leftImage1 = UIImage.ne_imageNamed(name: "left_play_1"), + let leftmage2 = UIImage.ne_imageNamed(name: "left_play_2"), + let leftmage3 = UIImage.ne_imageNamed(name: "left_play_3") { + audioImageViewLeft.animationImages = [leftImage1, leftmage2, leftmage3] + } + } + + open func commonUIRight() { + audioImageViewRight.contentMode = .center + audioImageViewRight.translatesAutoresizingMaskIntoConstraints = false + bubbleImageRight.addSubview(audioImageViewRight) + NSLayoutConstraint.activate([ + audioImageViewRight.rightAnchor.constraint(equalTo: bubbleImageRight.rightAnchor, constant: -16), + audioImageViewRight.centerYAnchor.constraint(equalTo: bubbleImageRight.centerYAnchor), + audioImageViewRight.widthAnchor.constraint(equalToConstant: 28), + audioImageViewRight.heightAnchor.constraint(equalToConstant: 28), + ]) + + timeLabelRight.font = UIFont.systemFont(ofSize: 14) + timeLabelRight.textColor = UIColor.ne_darkText + timeLabelRight.textAlignment = .right + timeLabelRight.translatesAutoresizingMaskIntoConstraints = false + bubbleImageRight.addSubview(timeLabelRight) + NSLayoutConstraint.activate([ + timeLabelRight.rightAnchor.constraint(equalTo: audioImageViewRight.leftAnchor, constant: -12), + timeLabelRight.centerYAnchor.constraint(equalTo: bubbleImageRight.centerYAnchor), + timeLabelRight.heightAnchor.constraint(equalToConstant: 28), + ]) + + audioImageViewRight.animationDuration = 1 + if let image1 = UIImage.ne_imageNamed(name: "play_1"), + let image2 = UIImage.ne_imageNamed(name: "play_2"), + let image3 = UIImage.ne_imageNamed(name: "play_3") { + audioImageViewRight.animationImages = [image1, image2, image3] + } + } + + open func startAnimation(byRight: Bool) { + if byRight { + if !audioImageViewRight.isAnimating { + audioImageViewRight.startAnimating() + } + } else if !audioImageViewLeft.isAnimating { + audioImageViewLeft.startAnimating() + } + if let m = contentModel as? MessageAudioModel { + m.isPlaying = true + isPlaying = true + } + } + + open func stopAnimation(byRight: Bool) { + if byRight { + if audioImageViewRight.isAnimating { + audioImageViewRight.stopAnimating() + } + } else if audioImageViewLeft.isAnimating { + audioImageViewLeft.stopAnimating() + } + if let m = contentModel as? MessageAudioModel { + m.isPlaying = false + isPlaying = false + } + } + + override open func showLeftOrRight(showRight: Bool) { + super.showLeftOrRight(showRight: showRight) + audioImageViewLeft.isHidden = showRight + timeLabelLeft.isHidden = showRight + + audioImageViewRight.isHidden = !showRight + timeLabelRight.isHidden = !showRight + } + + override open func setModel(_ model: MessageContentModel) { + super.setModel(model) + guard let isSend = model.message?.isOutgoingMsg else { + return + } + if let m = model as? MessageAudioModel { + if isSend { + timeLabelRight.text = "\(m.duration)" + "″" + } else { + timeLabelLeft.text = "\(m.duration)" + "″" + } + m.isPlaying ? startAnimation(byRight: isSend) : stopAnimation(byRight: isSend) + messageId = m.message?.messageId + } + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageBaseCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageBaseCell.swift new file mode 100644 index 00000000..a1555c07 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageBaseCell.swift @@ -0,0 +1,46 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FunChatMessageBaseCell: NEBaseChatMessageCell { + public let funMargin: CGFloat = 5.2 + override open func initProperty() { + super.initProperty() + readView.borderLayer.strokeColor = UIColor.funChatThemeColor.cgColor + readView.sectorLayer.fillColor = UIColor.funChatThemeColor.cgColor + + var image = NEKitChatConfig.shared.ui.leftBubbleBg ?? UIImage.ne_imageNamed(name: "chat_message_receive_fun") + bubbleImageLeft.image = image? + .resizableImage(withCapInsets: UIEdgeInsets(top: 35, left: 25, bottom: 10, right: 25)) + + image = NEKitChatConfig.shared.ui.rightBubbleBg ?? UIImage.ne_imageNamed(name: "chat_message_send_fun") + bubbleImageRight.image = image? + .resizableImage(withCapInsets: UIEdgeInsets(top: 35, left: 25, bottom: 10, right: 25)) + } + + override open func baseCommonUI() { + super.baseCommonUI() + setAvatarImgSize(size: 42) + + contentView.updateLayoutConstraint(firstItem: fullNameLabel, seconedItem: avatarImageLeft, attribute: .left, constant: 8 + funMargin) + contentView.removeLayoutConstraint(firstItem: fullNameLabel, seconedItem: avatarImageLeft, attribute: .top) + fullNameLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0).isActive = true + } + + override open func initSubviewsLayout() { + if NEKitChatConfig.shared.ui.avatarType == .rectangle, + let radius = NEKitChatConfig.shared.ui.avatarCornerRadius { + avatarImageRight.layer.cornerRadius = radius + avatarImageLeft.layer.cornerRadius = radius + } else if NEKitChatConfig.shared.ui.avatarType == .cycle { + avatarImageRight.layer.cornerRadius = 21.0 + avatarImageLeft.layer.cornerRadius = 21.0 + } else { + avatarImageRight.layer.cornerRadius = 4 + avatarImageLeft.layer.cornerRadius = 4 + } + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageCallCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageCallCell.swift new file mode 100644 index 00000000..8f800203 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageCallCell.swift @@ -0,0 +1,75 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FunChatMessageCallCell: FunChatMessageBaseCell { + public let contentLabelLeft = UILabel() + public let contentLabelRight = UILabel() + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + commonUI() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + open func commonUI() { + commonUIRight() + commonUILeft() + } + + open func commonUILeft() { + contentLabelLeft.translatesAutoresizingMaskIntoConstraints = false + contentLabelLeft.isEnabled = false + contentLabelLeft.numberOfLines = 0 + contentLabelLeft.isUserInteractionEnabled = false + contentLabelLeft.font = NEKitChatConfig.shared.ui.messageTextSize + contentLabelLeft.textAlignment = .center + contentLabelLeft.backgroundColor = .clear + bubbleImageLeft.addSubview(contentLabelLeft) + NSLayoutConstraint.activate([ + contentLabelLeft.rightAnchor.constraint(equalTo: bubbleImageLeft.rightAnchor, constant: -chat_content_margin), + contentLabelLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor, constant: chat_content_margin + funMargin), + contentLabelLeft.centerYAnchor.constraint(equalTo: bubbleImageLeft.centerYAnchor), + ]) + } + + open func commonUIRight() { + contentLabelRight.translatesAutoresizingMaskIntoConstraints = false + contentLabelRight.isEnabled = false + contentLabelRight.numberOfLines = 0 + contentLabelRight.isUserInteractionEnabled = false + contentLabelRight.font = NEKitChatConfig.shared.ui.messageTextSize + contentLabelRight.textAlignment = .center + contentLabelRight.backgroundColor = .clear + bubbleImageRight.addSubview(contentLabelRight) + NSLayoutConstraint.activate([ + contentLabelRight.rightAnchor.constraint(equalTo: bubbleImageRight.rightAnchor, constant: -(chat_content_margin + funMargin)), + contentLabelRight.leftAnchor.constraint(equalTo: bubbleImageRight.leftAnchor, constant: chat_content_margin), + contentLabelRight.centerYAnchor.constraint(equalTo: bubbleImageRight.centerYAnchor), + ]) + + activityView.removeFromSuperview() + } + + override open func showLeftOrRight(showRight: Bool) { + super.showLeftOrRight(showRight: showRight) + contentLabelLeft.isHidden = showRight + contentLabelRight.isHidden = !showRight + } + + override open func setModel(_ model: MessageContentModel) { + super.setModel(model) + guard let isSend = model.message?.isOutgoingMsg else { + return + } + let contentLabel = isSend ? contentLabelRight : contentLabelLeft + if let m = model as? MessageCallRecordModel { + contentLabel.attributedText = m.attributeStr + } + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageFileCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageFileCell.swift new file mode 100644 index 00000000..b1105e74 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageFileCell.swift @@ -0,0 +1,296 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonKit +import NIMSDK + +@objcMembers +open class FunChatMessageFileCell: FunChatMessageBaseCell { + weak var weakModel: MessageFileModel? + + public lazy var imgViewLeft: UIImageView = { + let view_img = UIImageView() + view_img.translatesAutoresizingMaskIntoConstraints = false + view_img.backgroundColor = .clear + return view_img + }() + + public lazy var stateViewLeft: FileStateView = { + let state = FileStateView() + state.translatesAutoresizingMaskIntoConstraints = false + state.backgroundColor = .clear + return state + }() + + public lazy var titleLabelLeft: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.isUserInteractionEnabled = false + label.numberOfLines = 1 + label.lineBreakMode = .byTruncatingMiddle + label.font = DefaultTextFont(14) + label.textAlignment = .left + return label + }() + + public lazy var sizeLabelLeft: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = UIColor(hexString: "#999999") + label.font = NEConstant.defaultTextFont(10.0) + label.textAlignment = .left + return label + }() + + public lazy var labelViewLeft: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.isUserInteractionEnabled = false + view.addSubview(titleLabelLeft) + NSLayoutConstraint.activate([ + titleLabelLeft.leftAnchor.constraint(equalTo: view.leftAnchor), + titleLabelLeft.topAnchor.constraint(equalTo: view.topAnchor), + titleLabelLeft.rightAnchor.constraint(equalTo: view.rightAnchor), + titleLabelLeft.heightAnchor.constraint(equalToConstant: 18), + ]) + view.addSubview(sizeLabelLeft) + NSLayoutConstraint.activate([ + sizeLabelLeft.leftAnchor.constraint(equalTo: view.leftAnchor), + sizeLabelLeft.topAnchor.constraint(equalTo: titleLabelLeft.bottomAnchor, constant: 5), + sizeLabelLeft.rightAnchor.constraint(equalTo: view.rightAnchor), + sizeLabelLeft.heightAnchor.constraint(equalToConstant: 10), + ]) + return view + }() + + public lazy var imgViewRight: UIImageView = { + let view_img = UIImageView() + view_img.translatesAutoresizingMaskIntoConstraints = false + view_img.backgroundColor = .clear + return view_img + }() + + public lazy var stateViewRight: FileStateView = { + let state = FileStateView() + state.translatesAutoresizingMaskIntoConstraints = false + state.backgroundColor = .clear + return state + }() + + public lazy var titleLabelRight: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.isUserInteractionEnabled = false + label.numberOfLines = 1 + label.lineBreakMode = .byTruncatingMiddle + label.font = DefaultTextFont(14) + label.textAlignment = .left + return label + }() + + public lazy var sizeLabelRight: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = UIColor(hexString: "#999999") + label.font = NEConstant.defaultTextFont(10.0) + label.textAlignment = .left + return label + }() + + public lazy var labelViewRight: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.isUserInteractionEnabled = false + view.addSubview(titleLabelRight) + NSLayoutConstraint.activate([ + titleLabelRight.leftAnchor.constraint(equalTo: view.leftAnchor), + titleLabelRight.topAnchor.constraint(equalTo: view.topAnchor), + titleLabelRight.rightAnchor.constraint(equalTo: view.rightAnchor), + titleLabelRight.heightAnchor.constraint(equalToConstant: 18), + ]) + view.addSubview(sizeLabelRight) + NSLayoutConstraint.activate([ + sizeLabelRight.leftAnchor.constraint(equalTo: view.leftAnchor), + sizeLabelRight.topAnchor.constraint(equalTo: titleLabelRight.bottomAnchor, constant: 5), + sizeLabelRight.rightAnchor.constraint(equalTo: view.rightAnchor), + sizeLabelRight.heightAnchor.constraint(equalToConstant: 10), + ]) + return view + }() + + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + setupUI() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func setupUI() { + setupUIRight() + setupUILeft() + } + + open func setupUILeft() { + bubbleImageLeft.image = nil + bubbleImageLeft.backgroundColor = .white + bubbleImageLeft.layer.cornerRadius = 4 + bubbleImageLeft.layer.borderColor = UIColor.ne_borderColor.cgColor + bubbleImageLeft.layer.borderWidth = 1 + + addSubview(imgViewLeft) + NSLayoutConstraint.activate([ + imgViewLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor, constant: 10), + imgViewLeft.centerYAnchor.constraint(equalTo: bubbleImageLeft.centerYAnchor), + imgViewLeft.widthAnchor.constraint(equalToConstant: 32), + imgViewLeft.heightAnchor.constraint(equalToConstant: 32), + ]) + + addSubview(stateViewLeft) + NSLayoutConstraint.activate([ + stateViewLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor, constant: 10), + stateViewLeft.topAnchor.constraint(equalTo: bubbleImageLeft.topAnchor, constant: 10), + stateViewLeft.widthAnchor.constraint(equalToConstant: 32), + stateViewLeft.heightAnchor.constraint(equalToConstant: 32), + ]) + + addSubview(labelViewLeft) + NSLayoutConstraint.activate([ + labelViewLeft.leftAnchor.constraint(equalTo: imgViewLeft.rightAnchor, constant: 15), + labelViewLeft.topAnchor.constraint(equalTo: bubbleImageLeft.topAnchor, constant: 10), + labelViewLeft.rightAnchor.constraint(equalTo: bubbleImageLeft.rightAnchor, constant: -10), + labelViewLeft.bottomAnchor.constraint(equalTo: bubbleImageLeft.bottomAnchor, constant: 0), + ]) + } + + open func setupUIRight() { + bubbleImageRight.image = nil + bubbleImageRight.backgroundColor = .white + bubbleImageRight.layer.cornerRadius = 4 + bubbleImageRight.layer.borderColor = UIColor.ne_borderColor.cgColor + bubbleImageRight.layer.borderWidth = 1 + + addSubview(imgViewRight) + NSLayoutConstraint.activate([ + imgViewRight.leftAnchor.constraint(equalTo: bubbleImageRight.leftAnchor, constant: 10), + imgViewRight.centerYAnchor.constraint(equalTo: bubbleImageRight.centerYAnchor), + imgViewRight.widthAnchor.constraint(equalToConstant: 32), + imgViewRight.heightAnchor.constraint(equalToConstant: 32), + ]) + + addSubview(stateViewRight) + NSLayoutConstraint.activate([ + stateViewRight.leftAnchor.constraint(equalTo: bubbleImageRight.leftAnchor, constant: 10), + stateViewRight.topAnchor.constraint(equalTo: bubbleImageRight.topAnchor, constant: 10), + stateViewRight.widthAnchor.constraint(equalToConstant: 32), + stateViewRight.heightAnchor.constraint(equalToConstant: 32), + ]) + + addSubview(labelViewRight) + NSLayoutConstraint.activate([ + labelViewRight.leftAnchor.constraint(equalTo: imgViewRight.rightAnchor, constant: 15), + labelViewRight.topAnchor.constraint(equalTo: bubbleImageRight.topAnchor, constant: 10), + labelViewRight.rightAnchor.constraint(equalTo: bubbleImageRight.rightAnchor, constant: -10), + labelViewRight.bottomAnchor.constraint(equalTo: bubbleImageRight.bottomAnchor, constant: 0), + ]) + } + + override open func showLeftOrRight(showRight: Bool) { + super.showLeftOrRight(showRight: showRight) + imgViewLeft.isHidden = showRight + stateViewLeft.isHidden = showRight + labelViewLeft.isHidden = showRight + + imgViewRight.isHidden = !showRight + stateViewRight.isHidden = !showRight + labelViewRight.isHidden = !showRight + } + + override open func setModel(_ model: MessageContentModel) { + super.setModel(model) + guard let isSend = model.message?.isOutgoingMsg else { + return + } + let stateView = isSend ? stateViewRight : stateViewLeft + let imgView = isSend ? imgViewRight : imgViewLeft + let titleLabel = isSend ? titleLabelRight : titleLabelLeft + let sizeLabel = isSend ? sizeLabelRight : sizeLabelLeft + let bubbleW = isSend ? bubbleWRight : bubbleWLeft + + bubbleW?.constant = kScreenWidth <= 320 ? 222 : 242 // 适配小屏幕 + + if let fileObject = model.message?.messageObject as? NIMFileObject { + if let fileModel = model as? MessageFileModel { + weakModel?.cell = nil + weakModel = fileModel + fileModel.cell = self + fileModel.size = Float(fileObject.fileLength) + if fileModel.state == .Success { + stateView.state = .FileOpen + } else { + stateView.state = .FileDownload + stateView.setProgress(fileModel.progress) + if fileModel.progress >= 1 { + fileModel.state = .Success + } + } + } + var imageName = "file_unknown" + var displayName = "未知文件" + if let filePath = fileObject.path as? NSString { + displayName = filePath.lastPathComponent + switch filePath.pathExtension.lowercased() { + case file_doc_support: + imageName = "file_doc" + case file_xls_support: + imageName = "file_xls" + case file_img_support: + imageName = "file_img" + case file_ppt_support: + imageName = "file_ppt" + case file_txt_support: + imageName = "file_txt" + case file_audio_support: + imageName = "file_audio" + case file_vedio_support: + imageName = "file_vedio" + case file_zip_support: + imageName = "file_zip" + case file_pdf_support: + imageName = "file_pdf" + case file_html_support: + imageName = "file_html" + case "key", "keynote": + imageName = "file_keynote" + default: + imageName = "file_unknown" + } + } + imgView.image = UIImage.ne_imageNamed(name: imageName) + titleLabel.text = fileObject.displayName ?? displayName + let size_B = Double(fileObject.fileLength) + var size_str = String(format: "%.1f B", size_B) + if size_B > 1e3 { + let size_KB = size_B / 1e3 + size_str = String(format: "%.1f KB", size_KB) + if size_KB > 1e3 { + let size_MB = size_KB / 1e3 + size_str = String(format: "%.1f MB", size_MB) + if size_MB > 1e3 { + let size_GB = size_KB / 1e6 + size_str = String(format: "%.1f GB", size_GB) + } + } + } + sizeLabel.text = size_str + } + } + + override open func uploadProgress(byRight: Bool, _ progress: Float) { + let stateView = byRight ? stateViewRight : stateViewLeft + stateView.setProgress(progress) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageImageCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageImageCell.swift new file mode 100644 index 00000000..ba8c6f90 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageImageCell.swift @@ -0,0 +1,85 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class FunChatMessageImageCell: FunChatMessageBaseCell { + public let contentImageViewLeft = UIImageView() + public let contentImageViewRight = UIImageView() + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + commonUI() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func commonUI() { + commonUIRight() + commonUILeft() + } + + open func commonUILeft() { + contentImageViewLeft.translatesAutoresizingMaskIntoConstraints = false + contentImageViewLeft.contentMode = .scaleAspectFill + contentImageViewLeft.clipsToBounds = true + contentImageViewLeft.layer.cornerRadius = 4 + bubbleImageLeft.image = nil + bubbleImageLeft.addSubview(contentImageViewLeft) + NSLayoutConstraint.activate([ + contentImageViewLeft.rightAnchor.constraint(equalTo: bubbleImageLeft.rightAnchor), + contentImageViewLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor), + contentImageViewLeft.topAnchor.constraint(equalTo: bubbleImageLeft.topAnchor), + contentImageViewLeft.bottomAnchor.constraint(equalTo: bubbleImageLeft.bottomAnchor), + ]) + } + + open func commonUIRight() { + contentImageViewRight.translatesAutoresizingMaskIntoConstraints = false + contentImageViewRight.contentMode = .scaleAspectFill + contentImageViewRight.clipsToBounds = true + contentImageViewRight.layer.cornerRadius = 4 + bubbleImageRight.image = nil + bubbleImageRight.addSubview(contentImageViewRight) + NSLayoutConstraint.activate([ + contentImageViewRight.rightAnchor.constraint(equalTo: bubbleImageRight.rightAnchor), + contentImageViewRight.leftAnchor.constraint(equalTo: bubbleImageRight.leftAnchor), + contentImageViewRight.topAnchor.constraint(equalTo: bubbleImageRight.topAnchor), + contentImageViewRight.bottomAnchor.constraint(equalTo: bubbleImageRight.bottomAnchor), + ]) + } + + override open func showLeftOrRight(showRight: Bool) { + super.showLeftOrRight(showRight: showRight) + contentImageViewLeft.isHidden = showRight + contentImageViewRight.isHidden = !showRight + } + + override open func setModel(_ model: MessageContentModel) { + super.setModel(model) + guard let isSend = model.message?.isOutgoingMsg else { + return + } + let contentImageView = isSend ? contentImageViewRight : contentImageViewLeft + + if let m = model as? MessageImageModel, let imageUrl = m.imageUrl { + if imageUrl.hasPrefix("http") { + contentImageView.sd_setImage( + with: URL(string: imageUrl), + placeholderImage: nil, + options: .retryFailed, + progress: nil, + completed: nil + ) + } else { + contentImageView.image = UIImage(contentsOfFile: imageUrl) + } + } else { + contentImageView.image = nil + } + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageLocationCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageLocationCell.swift new file mode 100644 index 00000000..6e93279e --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageLocationCell.swift @@ -0,0 +1,245 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NEChatKit + +@objcMembers +open class FunChatMessageLocationCell: FunChatMessageBaseCell { + public lazy var titleLabelLeft: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = UIColor.ne_darkText + label.font = UIFont.systemFont(ofSize: 16.0) + return label + }() + + public lazy var subTitleLabelLeft: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = UIColor.ne_lightText + label.font = UIFont.systemFont(ofSize: 12.0) + return label + }() + + public lazy var emptyLabelLeft: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.font = UIFont.systemFont(ofSize: 16) + label.text = chatLocalizable("no_map_plugin") + label.textAlignment = .center + label.textColor = UIColor.ne_greyText + return label + }() + + public var mapViewLeft: UIView? + let backgroundViewLeft = UIView() + + // Right + public lazy var titleLabelRight: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = UIColor.ne_darkText + label.font = UIFont.systemFont(ofSize: 16.0) + return label + }() + + public lazy var subTitleLabelRight: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = UIColor.ne_lightText + label.font = UIFont.systemFont(ofSize: 12.0) + return label + }() + + public lazy var emptyLabelRight: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.font = UIFont.systemFont(ofSize: 16) + label.text = chatLocalizable("no_map_plugin") + label.textAlignment = .center + label.textColor = UIColor.ne_greyText + return label + }() + + public var mapViewRight: UIView? + let backgroundViewRight = UIView() + + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + commonUI() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func commonUI() { + commonUIRight() + commonUILeft() + } + + open func commonUILeft() { + backgroundViewLeft.backgroundColor = UIColor.white + contentView.addSubview(backgroundViewLeft) + bubbleImageLeft.isHidden = true + backgroundViewLeft.translatesAutoresizingMaskIntoConstraints = false + backgroundViewLeft.clipsToBounds = true + backgroundViewLeft.layer.cornerRadius = 4 + backgroundViewLeft.layer.borderWidth = 1 + backgroundViewLeft.layer.borderColor = UIColor.ne_outlineColor.cgColor + + let messageLongPress = UILongPressGestureRecognizer( + target: self, + action: #selector(longPress) + ) + + backgroundViewLeft.addGestureRecognizer(messageLongPress) + NSLayoutConstraint.activate([ + backgroundViewLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor), + backgroundViewLeft.topAnchor.constraint(equalTo: bubbleImageLeft.topAnchor), + backgroundViewLeft.rightAnchor.constraint(equalTo: bubbleImageLeft.rightAnchor), + backgroundViewLeft.bottomAnchor.constraint(equalTo: bubbleImageLeft.bottomAnchor), + ]) + + let messageTap = UITapGestureRecognizer(target: self, action: #selector(tapMessage)) + backgroundViewLeft.addGestureRecognizer(messageTap) + + backgroundViewLeft.addSubview(titleLabelLeft) + NSLayoutConstraint.activate([ + titleLabelLeft.leftAnchor.constraint(equalTo: backgroundViewLeft.leftAnchor, constant: 16), + titleLabelLeft.rightAnchor.constraint(equalTo: backgroundViewLeft.rightAnchor, constant: -16), + titleLabelLeft.topAnchor.constraint(equalTo: backgroundViewLeft.topAnchor, constant: 10), + ]) + + backgroundViewLeft.addSubview(subTitleLabelLeft) + NSLayoutConstraint.activate([ + subTitleLabelLeft.leftAnchor.constraint(equalTo: titleLabelLeft.leftAnchor), + subTitleLabelLeft.rightAnchor.constraint(equalTo: titleLabelLeft.rightAnchor), + subTitleLabelLeft.topAnchor.constraint(equalTo: titleLabelLeft.bottomAnchor, constant: 4), + ]) + + if let map = NEChatKitClient.instance.delegate?.getCellMapView?() as? UIView { + mapViewLeft = map + backgroundViewLeft.addSubview(map) + map.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + map.leftAnchor.constraint(equalTo: backgroundViewLeft.leftAnchor), + map.bottomAnchor.constraint(equalTo: backgroundViewLeft.bottomAnchor), + map.rightAnchor.constraint(equalTo: backgroundViewLeft.rightAnchor), + map.topAnchor.constraint(equalTo: subTitleLabelLeft.bottomAnchor, constant: 4), + ]) + + let pointImage = UIImageView() + pointImage.translatesAutoresizingMaskIntoConstraints = false + pointImage.image = coreLoader.loadImage("location_point") + map.addSubview(pointImage) + NSLayoutConstraint.activate([ + pointImage.centerXAnchor.constraint(equalTo: map.centerXAnchor), + pointImage.bottomAnchor.constraint(equalTo: map.bottomAnchor, constant: -30), + ]) + } else { + backgroundViewLeft.addSubview(emptyLabelLeft) + NSLayoutConstraint.activate([ + emptyLabelLeft.leftAnchor.constraint(equalTo: backgroundViewLeft.leftAnchor), + emptyLabelLeft.rightAnchor.constraint(equalTo: backgroundViewLeft.rightAnchor), + emptyLabelLeft.bottomAnchor.constraint(equalTo: backgroundViewLeft.bottomAnchor, constant: -40), + ]) + } + } + + open func commonUIRight() { + backgroundViewRight.backgroundColor = UIColor.white + contentView.addSubview(backgroundViewRight) + bubbleImageRight.isHidden = true + backgroundViewRight.translatesAutoresizingMaskIntoConstraints = false + backgroundViewRight.clipsToBounds = true + backgroundViewRight.layer.cornerRadius = 4 + backgroundViewRight.layer.borderWidth = 1 + backgroundViewRight.layer.borderColor = UIColor.ne_outlineColor.cgColor + let messageLongPress = UILongPressGestureRecognizer( + target: self, + action: #selector(longPress) + ) + + backgroundViewRight.addGestureRecognizer(messageLongPress) + NSLayoutConstraint.activate([ + backgroundViewRight.leftAnchor.constraint(equalTo: bubbleImageRight.leftAnchor), + backgroundViewRight.topAnchor.constraint(equalTo: bubbleImageRight.topAnchor), + backgroundViewRight.rightAnchor.constraint(equalTo: bubbleImageRight.rightAnchor), + backgroundViewRight.bottomAnchor.constraint(equalTo: bubbleImageRight.bottomAnchor), + ]) + let messageTap = UITapGestureRecognizer(target: self, action: #selector(tapMessage)) + backgroundViewRight.addGestureRecognizer(messageTap) + + backgroundViewRight.addSubview(titleLabelRight) + NSLayoutConstraint.activate([ + titleLabelRight.leftAnchor.constraint(equalTo: backgroundViewRight.leftAnchor, constant: 16), + titleLabelRight.rightAnchor.constraint(equalTo: backgroundViewRight.rightAnchor, constant: -16), + titleLabelRight.topAnchor.constraint(equalTo: backgroundViewRight.topAnchor, constant: 10), + ]) + + backgroundViewRight.addSubview(subTitleLabelRight) + NSLayoutConstraint.activate([ + subTitleLabelRight.leftAnchor.constraint(equalTo: titleLabelRight.leftAnchor), + subTitleLabelRight.rightAnchor.constraint(equalTo: titleLabelRight.rightAnchor), + subTitleLabelRight.topAnchor.constraint(equalTo: titleLabelRight.bottomAnchor, constant: 4), + ]) + + if let map = NEChatKitClient.instance.delegate?.getCellMapView?() as? UIView { + mapViewRight = map + backgroundViewRight.addSubview(map) + map.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + map.leftAnchor.constraint(equalTo: backgroundViewRight.leftAnchor), + map.bottomAnchor.constraint(equalTo: backgroundViewRight.bottomAnchor), + map.rightAnchor.constraint(equalTo: backgroundViewRight.rightAnchor), + map.topAnchor.constraint(equalTo: subTitleLabelRight.bottomAnchor, constant: 4), + ]) + + let pointImage = UIImageView() + pointImage.translatesAutoresizingMaskIntoConstraints = false + pointImage.image = coreLoader.loadImage("location_point") + map.addSubview(pointImage) + NSLayoutConstraint.activate([ + pointImage.centerXAnchor.constraint(equalTo: map.centerXAnchor), + pointImage.bottomAnchor.constraint(equalTo: map.bottomAnchor, constant: -30), + ]) + } else { + backgroundViewRight.addSubview(emptyLabelRight) + NSLayoutConstraint.activate([ + emptyLabelRight.leftAnchor.constraint(equalTo: backgroundViewRight.leftAnchor), + emptyLabelRight.rightAnchor.constraint(equalTo: backgroundViewRight.rightAnchor), + emptyLabelRight.bottomAnchor.constraint(equalTo: backgroundViewRight.bottomAnchor, constant: -40), + ]) + } + } + + override open func showLeftOrRight(showRight: Bool) { + super.showLeftOrRight(showRight: showRight) + backgroundViewLeft.isHidden = showRight + backgroundViewRight.isHidden = !showRight + } + + override open func setModel(_ model: MessageContentModel) { + super.setModel(model) + guard let isSend = model.message?.isOutgoingMsg else { + return + } + let titleLabel = isSend ? titleLabelRight : titleLabelLeft + let subTitleLabel = isSend ? subTitleLabelRight : subTitleLabelLeft + let mapView = isSend ? mapViewRight : mapViewLeft + let bubbleW = isSend ? bubbleWRight : bubbleWLeft + + bubbleW?.constant = kScreenWidth <= 320 ? 222 : 242 // 适配小屏幕 + + if let m = model as? MessageLocationModel { + titleLabel.text = m.title + subTitleLabel.text = m.subTitle + if let lat = m.lat, let lng = m.lng, let map = mapView { + NEChatKitClient.instance.delegate?.setMapviewLocation?(lat: lat, lng: lng, mapview: map) + } + } + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageReplyCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageReplyCell.swift new file mode 100644 index 00000000..a477f106 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageReplyCell.swift @@ -0,0 +1,140 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FunChatMessageReplyCell: FunChatMessageTextCell { + public lazy var replyLabelLeft: UILabel = { + let replyLabelLeft = UILabel() + replyLabelLeft.numberOfLines = 2 + replyLabelLeft.textColor = UIColor(hexString: "#666666") // 换肤颜色提取 + replyLabelLeft.translatesAutoresizingMaskIntoConstraints = false + replyLabelLeft.font = UIFont.systemFont(ofSize: 13) + replyLabelLeft.textAlignment = .justified + return replyLabelLeft + }() + + public lazy var replyTextViewLeft: UIView = { + let replyTextView = UIView() + replyTextView.translatesAutoresizingMaskIntoConstraints = false + replyTextView.backgroundColor = .funChatInputReplyBg + replyTextView.layer.cornerRadius = 4 + return replyTextView + }() + + // Right + + public lazy var replyLabelRight: UILabel = { + let replyLabelRight = UILabel() + replyLabelRight.numberOfLines = 2 + replyLabelRight.textColor = .ne_greyText + replyLabelRight.translatesAutoresizingMaskIntoConstraints = false + replyLabelRight.font = UIFont.systemFont(ofSize: 13) + replyLabelRight.textAlignment = .justified + return replyLabelRight + }() + + public lazy var replyTextViewRight: UIView = { + let replyTextView = UIView() + replyTextView.translatesAutoresizingMaskIntoConstraints = false + replyTextView.backgroundColor = .funChatInputReplyBg + replyTextView.layer.cornerRadius = 4 + return replyTextView + }() + + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + commonUI() + addReplyGesture() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func commonUI() { + super.commonUI() + commonUIRight() + commonUILeft() + } + + open func commonUILeft() { + contentView.addSubview(replyTextViewLeft) + NSLayoutConstraint.activate([ + replyTextViewLeft.topAnchor.constraint(equalTo: bubbleImageLeft.bottomAnchor, constant: chat_content_margin), + replyTextViewLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor, constant: funMargin), + replyTextViewLeft.heightAnchor.constraint(equalToConstant: 44), + replyTextViewLeft.widthAnchor.constraint(lessThanOrEqualToConstant: chat_content_maxW - funMargin), + ]) + + contentView.removeLayoutConstraint(firstItem: pinLabelLeft, seconedItem: bubbleImageLeft, attribute: .top) + contentView.updateLayoutConstraint(firstItem: pinLabelLeft, seconedItem: bubbleImageLeft, attribute: .left, constant: 14 + funMargin) + pinLabelLeft.topAnchor.constraint(equalTo: replyTextViewLeft.bottomAnchor, constant: 4).isActive = true + + replyTextViewLeft.addSubview(replyLabelLeft) + NSLayoutConstraint.activate([ + replyLabelLeft.topAnchor.constraint(equalTo: replyTextViewLeft.topAnchor, constant: 4), + replyLabelLeft.bottomAnchor.constraint(equalTo: replyTextViewLeft.bottomAnchor, constant: -4), + replyLabelLeft.leftAnchor.constraint(equalTo: replyTextViewLeft.leftAnchor, constant: 12), + replyLabelLeft.rightAnchor.constraint(equalTo: replyTextViewLeft.rightAnchor, constant: -12), + ]) + } + + open func commonUIRight() { + contentView.addSubview(replyTextViewRight) + NSLayoutConstraint.activate([ + replyTextViewRight.topAnchor.constraint(equalTo: bubbleImageRight.bottomAnchor, constant: chat_content_margin), + replyTextViewRight.rightAnchor.constraint(equalTo: bubbleImageRight.rightAnchor, constant: -funMargin), + replyTextViewRight.heightAnchor.constraint(equalToConstant: 44), + replyTextViewRight.widthAnchor.constraint(lessThanOrEqualToConstant: chat_content_maxW - funMargin), + ]) + + contentView.removeLayoutConstraint(firstItem: pinLabelRight, seconedItem: bubbleImageRight, attribute: .top) + contentView.updateLayoutConstraint(firstItem: pinLabelRight, seconedItem: bubbleImageRight, attribute: .right, constant: -funMargin) + pinLabelRight.topAnchor.constraint(equalTo: replyTextViewRight.bottomAnchor, constant: 4).isActive = true + + replyTextViewRight.addSubview(replyLabelRight) + NSLayoutConstraint.activate([ + replyLabelRight.topAnchor.constraint(equalTo: replyTextViewRight.topAnchor, constant: 4), + replyLabelRight.bottomAnchor.constraint(equalTo: replyTextViewRight.bottomAnchor, constant: -4), + replyLabelRight.leftAnchor.constraint(equalTo: replyTextViewRight.leftAnchor, constant: 12), + replyLabelRight.rightAnchor.constraint(equalTo: replyTextViewRight.rightAnchor, constant: -12), + ]) + } + + override open func showLeftOrRight(showRight: Bool) { + super.showLeftOrRight(showRight: showRight) + replyTextViewLeft.isHidden = showRight + replyTextViewRight.isHidden = !showRight + } + + open func addReplyGesture() { + let replyViewTapLeft = UITapGestureRecognizer(target: self, action: #selector(tapReplyView(tap:))) + replyTextViewLeft.addGestureRecognizer(replyViewTapLeft) + let replyViewTapRight = UITapGestureRecognizer(target: self, action: #selector(tapReplyView(tap:))) + replyTextViewRight.addGestureRecognizer(replyViewTapRight) + } + + open func tapReplyView(tap: UITapGestureRecognizer) { + print(#function) + delegate?.didTapMessageView(self, contentModel) + } + + override open func setModel(_ model: MessageContentModel) { + super.setModel(model) + guard let isSend = model.message?.isOutgoingMsg else { + return + } + let replyLabel = isSend ? replyLabelRight : replyLabelLeft + + if let text = model.replyText, + let font = replyLabel.font { + let normalReplyText = NEEmotionTool.getAttWithStr(str: text, + font: font, + color: replyLabel.textColor) + replyLabel.attributedText = normalReplyText.attributedSubstring(from: NSRange(location: 1, length: normalReplyText.length - 1)) + } + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageRevokeCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageRevokeCell.swift new file mode 100644 index 00000000..405c928f --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageRevokeCell.swift @@ -0,0 +1,130 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FunChatMessageRevokeCell: FunChatMessageBaseCell { + public var revokeLabelLeft = UILabel() + public var revokeLabelRight = UILabel() + public var reeditButton = UIButton(type: .custom) + var revokeLabelRightXAnchor: NSLayoutConstraint? + + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + commonUI() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func commonUI() { + commonUIRight() + commonUILeft() + } + + open func commonUILeft() { + revokeLabelLeft.translatesAutoresizingMaskIntoConstraints = false + revokeLabelLeft.textColor = UIColor.ne_greyText + revokeLabelLeft.textAlignment = .center + revokeLabelLeft.lineBreakMode = .byTruncatingMiddle + revokeLabelLeft.font = UIFont.systemFont(ofSize: 14.0) + contentView.addSubview(revokeLabelLeft) + NSLayoutConstraint.activate([ + revokeLabelLeft.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16), + revokeLabelLeft.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16), + revokeLabelLeft.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + revokeLabelLeft.heightAnchor.constraint(equalToConstant: 16), + ]) + } + + open func commonUIRight() { + revokeLabelRight.translatesAutoresizingMaskIntoConstraints = false + revokeLabelRight.textColor = UIColor.ne_greyText + revokeLabelRight.textAlignment = .center + revokeLabelRight.font = UIFont.systemFont(ofSize: 14.0) + contentView.addSubview(revokeLabelRight) + revokeLabelRightXAnchor = revokeLabelRight.centerXAnchor.constraint(equalTo: contentView.centerXAnchor, constant: 0) + revokeLabelRightXAnchor?.isActive = true + NSLayoutConstraint.activate([ + revokeLabelRight.widthAnchor.constraint(equalToConstant: 120), + revokeLabelRight.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + revokeLabelRight.heightAnchor.constraint(equalToConstant: 16), + ]) + + reeditButton.translatesAutoresizingMaskIntoConstraints = false + reeditButton.titleLabel?.font = UIFont.systemFont(ofSize: 14.0) + reeditButton.setTitleColor(UIColor.ne_blueText, for: .normal) + + contentView.addSubview(reeditButton) + NSLayoutConstraint.activate([ + reeditButton.leftAnchor.constraint(equalTo: revokeLabelRight.rightAnchor, constant: 8), + reeditButton.widthAnchor.constraint(equalToConstant: 58), + reeditButton.topAnchor.constraint(equalTo: revokeLabelRight.topAnchor, constant: 0), + reeditButton.bottomAnchor.constraint(equalTo: revokeLabelRight.bottomAnchor, constant: 0), + ]) + reeditButton.addTarget(self, action: #selector(reeditEvent), for: .touchUpInside) + } + + override open func showLeftOrRight(showRight: Bool) { + super.showLeftOrRight(showRight: showRight) + revokeLabelLeft.isHidden = showRight + reeditButton.isHidden = !showRight + revokeLabelRight.isHidden = !showRight + avatarImageLeft.isHidden = true + bubbleImageLeft.isHidden = true + avatarImageRight.isHidden = true + bubbleImageRight.isHidden = true + seletedBtn.isHidden = true + pinLabelLeft.isHidden = true + pinImageLeft.isHidden = true + pinLabelRight.isHidden = true + pinImageRight.isHidden = true + } + + override open func setModel(_ model: MessageContentModel) { + if let time = model.message?.timestamp { + let date = Date() + let currentTime = date.timeIntervalSince1970 + if currentTime - time >= 60 * 2 { + model.timeOut = true + } + } + + guard let isSend = model.message?.isOutgoingMsg else { + return + } + let revokeLabel = isSend ? revokeLabelRight : revokeLabelLeft + + model.contentSize = CGSize(width: kScreenWidth, height: 0) + super.setModel(model) + fullNameLabel.isHidden = true + + revokeLabel.textColor = .funChatInputViewPlaceholderTextColor + if isSend { + revokeLabel.text = chatLocalizable("You") + chatLocalizable("withdrew_message") + } else { + revokeLabel.text = (model.fullName ?? "") + " " + chatLocalizable("withdrew_message") + } + reeditButton.setTitle(chatLocalizable("message_reedit"), for: .normal) + + if isSend, model.isRevokedText == true { + if model.timeOut == true { + reeditButton.isHidden = true + revokeLabelRightXAnchor?.constant = 0 + } else { + reeditButton.isHidden = false + revokeLabelRightXAnchor?.constant = -32 + } + } else { + reeditButton.isHidden = true + } + } + + func reeditEvent(button: UIButton) { + print(#function) + delegate?.didTapReeditButton(self, contentModel) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageTextCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageTextCell.swift new file mode 100644 index 00000000..2a84a01e --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageTextCell.swift @@ -0,0 +1,81 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FunChatMessageTextCell: FunChatMessageBaseCell { + public lazy var contentLabelLeft: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.isEnabled = false + label.numberOfLines = 0 + label.isUserInteractionEnabled = false + label.font = NEKitChatConfig.shared.ui.messageTextSize + label.backgroundColor = .clear + label.textAlignment = .justified + return label + }() + + public lazy var contentLabelRight: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.isEnabled = false + label.numberOfLines = 0 + label.isUserInteractionEnabled = false + label.font = NEKitChatConfig.shared.ui.messageTextSize + label.backgroundColor = .clear + label.textAlignment = .justified + return label + }() + + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + commonUI() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func commonUI() { + bubbleImageLeft.addSubview(contentLabelLeft) + NSLayoutConstraint.activate([ + contentLabelLeft.rightAnchor.constraint(equalTo: bubbleImageLeft.rightAnchor, constant: -chat_content_margin), + contentLabelLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor, constant: chat_content_margin + funMargin), + contentLabelLeft.topAnchor.constraint(equalTo: bubbleImageLeft.topAnchor, constant: chat_content_margin), + contentLabelLeft.bottomAnchor.constraint(equalTo: bubbleImageLeft.bottomAnchor, constant: -chat_content_margin), + ]) + contentView.updateLayoutConstraint(firstItem: pinLabelLeft, seconedItem: bubbleImageLeft, attribute: .left, constant: 14 + funMargin) + + bubbleImageRight.addSubview(contentLabelRight) + NSLayoutConstraint.activate([ + contentLabelRight.rightAnchor.constraint(equalTo: bubbleImageRight.rightAnchor, constant: -chat_content_margin - funMargin), + contentLabelRight.leftAnchor.constraint(equalTo: bubbleImageRight.leftAnchor, constant: chat_content_margin), + contentLabelRight.topAnchor.constraint(equalTo: bubbleImageRight.topAnchor, constant: chat_content_margin), + contentLabelRight.bottomAnchor.constraint(equalTo: bubbleImageRight.bottomAnchor, constant: -chat_content_margin), + ]) + contentView.updateLayoutConstraint(firstItem: pinLabelRight, seconedItem: bubbleImageRight, attribute: .right, constant: -funMargin) + } + + override open func showLeftOrRight(showRight: Bool) { + super.showLeftOrRight(showRight: showRight) + contentLabelLeft.isHidden = showRight + contentLabelRight.isHidden = !showRight + } + + override open func setModel(_ model: MessageContentModel) { + super.setModel(model) + guard let isSend = model.message?.isOutgoingMsg else { + return + } + let contentLabel = isSend ? contentLabelRight : contentLabelLeft + let bubbleW = isSend ? bubbleWRight : bubbleWLeft + + if let m = model as? MessageTextModel { + contentLabel.attributedText = m.attributeStr + } + bubbleW?.constant += funMargin + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageTipCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageTipCell.swift new file mode 100644 index 00000000..d607b0d7 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageTipCell.swift @@ -0,0 +1,15 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FunChatMessageTipCell: NEBaseChatMessageTipCell { + override open func commonUI() { + super.commonUI() + timeLabel.font = .systemFont(ofSize: 14) + timeLabel.textColor = .funRecordAudioTextColor + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageVideoCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageVideoCell.swift new file mode 100644 index 00000000..66b5efce --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatMessageVideoCell.swift @@ -0,0 +1,180 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonKit +import NIMSDK + +@objcMembers +open class FunChatMessageVideoCell: FunChatMessageImageCell { + weak var weakModel: MessageVideoModel? + public lazy var stateViewLeft: VideoStateView = { + let state = VideoStateView() + state.translatesAutoresizingMaskIntoConstraints = false + state.backgroundColor = .clear + return state + }() + + public lazy var timeLabelLeft: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = .white + label.font = NEConstant.defaultTextFont(10.0) + label.textAlignment = .center + return label + }() + + public lazy var timeViewLeft: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(timeLabelLeft) + NSLayoutConstraint.activate([ + timeLabelLeft.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 4), + timeLabelLeft.topAnchor.constraint(equalTo: view.topAnchor, constant: 2), + timeLabelLeft.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -4), + timeLabelLeft.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -2), + ]) + view.clipsToBounds = true + view.layer.cornerRadius = 4.0 + view.backgroundColor = NEConstant.hexRGB(0x000000).withAlphaComponent(0.6) + return view + }() + + // Right + public lazy var stateViewRight: VideoStateView = { + let state = VideoStateView() + state.translatesAutoresizingMaskIntoConstraints = false + state.backgroundColor = .clear + return state + }() + + public lazy var timeLabelRight: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = .white + label.font = NEConstant.defaultTextFont(10.0) + label.textAlignment = .center + return label + }() + + public lazy var timeViewRight: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(timeLabelRight) + NSLayoutConstraint.activate([ + timeLabelRight.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 4), + timeLabelRight.topAnchor.constraint(equalTo: view.topAnchor, constant: 2), + timeLabelRight.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -4), + timeLabelRight.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -2), + ]) + view.clipsToBounds = true + view.layer.cornerRadius = 4.0 + view.backgroundColor = NEConstant.hexRGB(0x000000).withAlphaComponent(0.6) + return view + }() + + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + setupUI() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func setupUI() { + setupUIRight() + setupUILeft() + } + + open func setupUILeft() { + contentImageViewLeft.addSubview(stateViewLeft) + NSLayoutConstraint.activate([ + stateViewLeft.centerXAnchor.constraint(equalTo: contentImageViewLeft.centerXAnchor), + stateViewLeft.centerYAnchor.constraint(equalTo: contentImageViewLeft.centerYAnchor), + stateViewLeft.heightAnchor.constraint(equalToConstant: 60), + stateViewLeft.widthAnchor.constraint(equalToConstant: 60), + ]) + + contentImageViewLeft.addSubview(timeViewLeft) + NSLayoutConstraint.activate([ + timeViewLeft.rightAnchor.constraint(equalTo: contentImageViewLeft.rightAnchor, constant: -7), + timeViewLeft.bottomAnchor.constraint(equalTo: contentImageViewLeft.bottomAnchor, constant: -7), + ]) + } + + open func setupUIRight() { + contentImageViewRight.addSubview(stateViewRight) + NSLayoutConstraint.activate([ + stateViewRight.centerXAnchor.constraint(equalTo: contentImageViewRight.centerXAnchor), + stateViewRight.centerYAnchor.constraint(equalTo: contentImageViewRight.centerYAnchor), + stateViewRight.heightAnchor.constraint(equalToConstant: 60), + stateViewRight.widthAnchor.constraint(equalToConstant: 60), + ]) + + contentImageViewRight.addSubview(timeViewRight) + NSLayoutConstraint.activate([ + timeViewRight.rightAnchor.constraint(equalTo: contentImageViewRight.rightAnchor, constant: -7), + timeViewRight.bottomAnchor.constraint(equalTo: contentImageViewRight.bottomAnchor, constant: -7), + ]) + } + + override open func setModel(_ model: MessageContentModel) { + super.setModel(model) + guard let isSend = model.message?.isOutgoingMsg else { + return + } + let contentImageView = isSend ? contentImageViewRight : contentImageViewLeft + let timeView = isSend ? timeViewRight : timeViewLeft + let timeLabel = isSend ? timeLabelRight : timeLabelLeft + let stateView = isSend ? stateViewRight : stateViewLeft + + if let videoObject = model.message?.messageObject as? NIMVideoObject { + if let path = videoObject.coverPath, FileManager.default.fileExists(atPath: path) { + contentImageView.sd_setImage( + with: URL(fileURLWithPath: path), + placeholderImage: nil, + options: .retryFailed, + progress: nil, + completed: nil + ) + } else { + contentImageView.sd_setImage( + with: URL(string: videoObject.coverUrl ?? ""), + placeholderImage: nil, + options: .retryFailed, + progress: nil, + completed: nil + ) + } + + if videoObject.duration > 0 { + timeView.isHidden = false + timeLabel.text = Date.getFormatPlayTime(TimeInterval(videoObject.duration / 1000)) + } else { + timeView.isHidden = true + } + + if let videoModel = model as? MessageVideoModel { + weakModel?.cell = nil + weakModel = videoModel + videoModel.cell = self + if videoModel.state == .Success { + stateView.state = .VideoPlay + } else { + stateView.state = .VideoDownload + stateView.setProgress(videoModel.progress) + if videoModel.progress >= 1 { + videoModel.state = .Success + } + } + } + } + } + + override open func uploadProgress(byRight: Bool, _ progress: Float) { + let stateView = byRight ? stateViewRight : stateViewLeft + stateView.setProgress(progress) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatTeamMemberCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatTeamMemberCell.swift new file mode 100644 index 00000000..1737da2c --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunChatTeamMemberCell.swift @@ -0,0 +1,40 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonUIKit +import NEChatKit + +@objcMembers +open class FunChatTeamMemberCell: NEBaseChatTeamMemberCell { + override open func setupUI() { + super.setupUI() + + headerView.layer.cornerRadius = 4 + NSLayoutConstraint.activate([ + headerView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16), + headerView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + headerView.widthAnchor.constraint(equalToConstant: 40), + headerView.heightAnchor.constraint(equalToConstant: 40), + ]) + + NSLayoutConstraint.activate([ + nameLabel.leftAnchor.constraint(equalTo: headerView.rightAnchor, constant: 11.0), + nameLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + nameLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -29), + ]) + + let line = UIView() + line.translatesAutoresizingMaskIntoConstraints = false + line.backgroundColor = .funChatLineBorderColor + contentView.addSubview(line) + NSLayoutConstraint.activate([ + line.leftAnchor.constraint(equalTo: headerView.leftAnchor), + line.rightAnchor.constraint(equalTo: contentView.rightAnchor), + line.heightAnchor.constraint(equalToConstant: 0.6), + line.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + ]) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunUserSettingSelectCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunUserSettingSelectCell.swift new file mode 100644 index 00000000..c0cb12da --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunUserSettingSelectCell.swift @@ -0,0 +1,34 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FunUserSettingSelectCell: NEBaseUserSettingSelectCell { + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + edgeInset = .zero + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + override open func setupUI() { + super.setupUI() + contentView.updateLayoutConstraint(firstItem: dividerLine, seconedItem: contentView, attribute: .left, constant: 16) + contentView.updateLayoutConstraint(firstItem: dividerLine, seconedItem: contentView, attribute: .right, constant: 0) + + NSLayoutConstraint.activate([ + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16), + titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -84), + ]) + + NSLayoutConstraint.activate([ + arrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + arrow.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20), + ]) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunUserSettingSwitchCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunUserSettingSwitchCell.swift new file mode 100644 index 00000000..4be6c606 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunUserSettingSwitchCell.swift @@ -0,0 +1,36 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FunUserSettingSwitchCell: NEBaseUserSettingSwitchCell { + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + edgeInset = .zero + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + override open func setupUI() { + super.setupUI() + contentView.updateLayoutConstraint(firstItem: dividerLine, seconedItem: contentView, attribute: .left, constant: 16) + contentView.updateLayoutConstraint(firstItem: dividerLine, seconedItem: contentView, attribute: .right, constant: 0) + + NSLayoutConstraint.activate([ + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16), + titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -84), + ]) + + tSwitch.onTintColor = .funChatThemeColor + NSLayoutConstraint.activate([ + tSwitch.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + tSwitch.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -14), + ]) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunUserTableViewCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunUserTableViewCell.swift new file mode 100644 index 00000000..304a3111 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/FunUserTableViewCell.swift @@ -0,0 +1,39 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit + +@objcMembers +open class FunUserTableViewCell: UserBaseTableViewCell { + override open func baseCommonUI() { + super.baseCommonUI() + // avatar + avatarImage.layer.cornerRadius = 4 + NSLayoutConstraint.activate([ + avatarImage.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16), + avatarImage.widthAnchor.constraint(equalToConstant: 40), + avatarImage.heightAnchor.constraint(equalToConstant: 40), + avatarImage.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 12), + ]) + + titleLabel.textColor = .ne_darkText + NSLayoutConstraint.activate([ + titleLabel.leftAnchor.constraint(equalTo: avatarImage.rightAnchor, constant: 11), + titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -29), + titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + ]) + + let line = UIView() + line.translatesAutoresizingMaskIntoConstraints = false + line.backgroundColor = .funChatLineBorderColor + contentView.addSubview(line) + NSLayoutConstraint.activate([ + line.leftAnchor.constraint(equalTo: avatarImage.leftAnchor), + line.rightAnchor.constraint(equalTo: contentView.rightAnchor), + line.heightAnchor.constraint(equalToConstant: 0.6), + line.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + ]) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageAudioCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageAudioCell.swift new file mode 100644 index 00000000..c184bcdd --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageAudioCell.swift @@ -0,0 +1,20 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FunPinMessageAudioCell: NEBasePinMessageAudioCell { + override open func setupUI() { + super.setupUI() + + backLeftConstraint?.constant = 0 + backRightConstraint?.constant = 0 + backView.layer.cornerRadius = 0 + headerView.layer.cornerRadius = 4.0 + let image = NEKitChatConfig.shared.ui.leftBubbleBg ?? UIImage.ne_imageNamed(name: "fun_pin_message_audio_bg") + bubbleImage.image = image? + .resizableImage(withCapInsets: UIEdgeInsets(top: 35, left: 25, bottom: 10, right: 25)) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageDefaultCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageDefaultCell.swift new file mode 100644 index 00000000..02ffcd0f --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageDefaultCell.swift @@ -0,0 +1,16 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FunPinMessageDefaultCell: NEBasePinMessageTextCell { + override open func setupUI() { + super.setupUI() + backLeftConstraint?.constant = 0 + backRightConstraint?.constant = 0 + backView.layer.cornerRadius = 0 + headerView.layer.cornerRadius = 4.0 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageFileCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageFileCell.swift new file mode 100644 index 00000000..e5040709 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageFileCell.swift @@ -0,0 +1,16 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FunPinMessageFileCell: NEBasePinMessageFileCell { + override open func setupUI() { + super.setupUI() + backLeftConstraint?.constant = 0 + backRightConstraint?.constant = 0 + backView.layer.cornerRadius = 0 + headerView.layer.cornerRadius = 4.0 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageImageCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageImageCell.swift new file mode 100644 index 00000000..5a19b7af --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageImageCell.swift @@ -0,0 +1,16 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FunPinMessageImageCell: NEBasePinMessageImageCell { + override open func setupUI() { + super.setupUI() + backLeftConstraint?.constant = 0 + backRightConstraint?.constant = 0 + backView.layer.cornerRadius = 0 + headerView.layer.cornerRadius = 4.0 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageLocationCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageLocationCell.swift new file mode 100644 index 00000000..f1406251 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageLocationCell.swift @@ -0,0 +1,17 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NEChatKit + +@objcMembers +open class FunPinMessageLocationCell: NEBasePinMessageLocationCell { + override open func setupUI() { + super.setupUI() + backLeftConstraint?.constant = 0 + backRightConstraint?.constant = 0 + backView.layer.cornerRadius = 0 + headerView.layer.cornerRadius = 4.0 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageTextCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageTextCell.swift new file mode 100644 index 00000000..666dc099 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageTextCell.swift @@ -0,0 +1,16 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FunPinMessageTextCell: NEBasePinMessageTextCell { + override open func setupUI() { + super.setupUI() + backLeftConstraint?.constant = 0 + backRightConstraint?.constant = 0 + backView.layer.cornerRadius = 0 + headerView.layer.cornerRadius = 4.0 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageVideoCell.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageVideoCell.swift new file mode 100644 index 00000000..858b5177 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Cell/PinCell/FunPinMessageVideoCell.swift @@ -0,0 +1,17 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class FunPinMessageVideoCell: NEBasePinMessageVideoCell { + override open func setupUI() { + super.setupUI() + backLeftConstraint?.constant = 0 + backRightConstraint?.constant = 0 + backView.layer.cornerRadius = 0 + headerView.layer.cornerRadius = 4.0 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunChatViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunChatViewController.swift new file mode 100644 index 00000000..106b76c0 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunChatViewController.swift @@ -0,0 +1,404 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK +import NECommonKit + +@objcMembers +open class FunChatViewController: ChatViewController, FunChatInputViewDelegate, NIMUserManagerDelegate, FunChatRecordViewDelegate { + public weak var recordView: FunRecordAudioView? + public var currentKeyboardHeight: CGFloat = 0 + + override public init(session: NIMSession) { + super.init(session: session) + registerCellDic = [ + "\(MessageType.text.rawValue)": FunChatMessageTextCell.self, + "\(MessageType.rtcCallRecord.rawValue)": FunChatMessageCallCell.self, + "\(MessageType.audio.rawValue)": FunChatMessageAudioCell.self, + "\(MessageType.image.rawValue)": FunChatMessageImageCell.self, + "\(MessageType.revoke.rawValue)": FunChatMessageRevokeCell.self, + "\(MessageType.video.rawValue)": FunChatMessageVideoCell.self, + "\(MessageType.file.rawValue)": FunChatMessageFileCell.self, + "\(MessageType.reply.rawValue)": FunChatMessageReplyCell.self, + "\(MessageType.location.rawValue)": FunChatMessageLocationCell.self, + "\(MessageType.time.rawValue)": FunChatMessageTipCell.self, + ] + + normalInputHeight = 90 + networkToolHeight = 48 + customNavigationView.bottomLine.backgroundColor = .funChatNavigationBottomLineColor + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .funChatBackgroundColor // 换肤颜色提取 + view.bringSubviewToFront(menuView) + brokenNetworkView.errorIcon.isHidden = false + brokenNetworkView.backgroundColor = .funChatNetworkBrokenBackgroundColor + brokenNetworkView.content.textColor = .funChatNetworkBrokenTitleColor + getFunInputView()?.funDelegate = self + } + + override open func didLongTouchMessageView(_ cell: UITableViewCell, _ model: MessageContentModel?) { + super.didLongTouchMessageView(cell, model) + operationView?.layer.cornerRadius = 8 + } + + override open func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + let m = viewmodel.messages[indexPath.row] + if m.type == .custom { + if let object = m.message?.messageObject as? NIMCustomObject, let custom = object.attachment as? NECustomAttachmentProtocol { + return custom.cellHeight + } + } + + if let contentModel = m as? MessageContentModel { + if contentModel.type == .revoke { + return 28 + } + } + + return m.cellHeight() + } + + override open func getMenuView() -> NEBaseChatInputView { + let input = FunChatInputView() + let gesture = UILongPressGestureRecognizer(target: self, action: #selector(holdToSpeak(gesture:))) + input.holdToSpeakView.addGestureRecognizer(gesture) + return input + } + + override open func getForwardAlertController() -> NEBaseForwardAlertViewController { + FunForwardAlertViewController() + } + + override func getUserSelectVC() -> NEBaseSelectUserViewController { + FunSelectUserViewController(sessionId: viewmodel.session.sessionId, showSelf: false) + } + + override func getTextViewController(text: String) -> TextViewController { + let textViewController = super.getTextViewController(text: text) + textViewController.view.backgroundColor = .funChatBackgroundColor + return textViewController + } + + open func recordModeChangeDidClick() { + normalOffset = 0 + layoutInputView(offset: 0) + UIApplication.shared.keyWindow?.endEditing(true) + } + + open func didHideReplyMode() { + viewmodel.isReplying = false + if currentKeyboardHeight > 0 { + normalOffset = 30 + } else { + normalOffset = 0 + } + layoutInputView(offset: currentKeyboardHeight) + } + + public func didShowReplyMode() { + viewmodel.isReplying = true + menuView.textView.becomeFirstResponder() + } + + override open func expandMoreAction() { + var items = NEChatUIKitClient.instance.getMoreActionData(sessionType: viewmodel.session.sessionType) + let photo = NEMoreItemModel() + photo.image = UIImage.ne_imageNamed(name: "fun_chat_photo") + photo.title = chatLocalizable("chat_photo") + photo.type = .photo + photo.customDelegate = self + photo.action = #selector(openPhoto) + items.insert(photo, at: 0) + menuView.chatAddMoreView.configData(data: items) + } + + func openPhoto() { + NELog.infoLog(className(), desc: "open photo") + willSelectItem(button: menuView.currentButton, index: showPhotoTag) + } + + override open func showRtcCallAction() { + var param = [String: AnyObject]() + param["remoteUserAccid"] = viewmodel.session.sessionId as AnyObject + param["currentUserAccid"] = NIMSDK.shared().loginManager.currentAccount() as AnyObject + param["remoteShowName"] = titleContent as AnyObject + if let user = viewmodel.repo.getUserInfo(userId: viewmodel.session.sessionId), let avatar = user.userInfo?.avatarUrl { + param["remoteAvatar"] = avatar as AnyObject + } + + let videoCallAction = NECustomAlertAction(title: chatLocalizable("video_call")) { + param["type"] = NSNumber(integerLiteral: 2) as AnyObject + Router.shared.use(CallViewRouter, parameters: param) + } + let audioCallAction = NECustomAlertAction(title: chatLocalizable("audio_call")) { + param["type"] = NSNumber(integerLiteral: 1) as AnyObject + Router.shared.use(CallViewRouter, parameters: param) + } + showCustomActionSheet([videoCallAction, audioCallAction]) + } + + override open func forwardMessage() { + if let message = viewmodel.operationModel?.message { + weak var weakSelf = self + let userAction = NECustomAlertAction(title: chatLocalizable("contact_user")) { + weakSelf?.forwardMessageToUser(message: message) + } + + let teamAction = NECustomAlertAction(title: chatLocalizable("team")) { + weakSelf?.forwardMessageToTeam(message: message) + } + + showCustomActionSheet([teamAction, userAction]) + } + } + + /// 设置按钮点击事件 + override open func toSetting() { + if let block = NEKitChatConfig.shared.ui.titleBarRightClick { + block() + return + } + if viewmodel.session.sessionType == .team { + Router.shared.use( + TeamSettingViewRouter, + parameters: ["nav": navigationController as Any, + "teamid": viewmodel.session.sessionId], + closure: nil + ) + } else if viewmodel.session.sessionType == .P2P { + let userSetting = FunUserSettingViewController() + userSetting.userId = viewmodel.session.sessionId + navigationController?.pushViewController(userSetting, animated: true) + } + } + + override open func keyBoardWillShow(_ notification: Notification) { + if viewmodel.isReplying { + normalOffset = -10 + } else { + normalOffset = 30 + } + let keyboardRect = (notification + .userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue + currentKeyboardHeight = keyboardRect.height + super.keyBoardWillShow(notification) + } + + override open func keyBoardWillHide(_ notification: Notification) { + if viewmodel.isReplying { + normalOffset = -30 + } else { + normalOffset = 0 + } + currentKeyboardHeight = 0 + super.keyBoardWillHide(notification) + } + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override open func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + + open func holdToSpeak(gesture: UILongPressGestureRecognizer) { + switch gesture.state { + case .possible: + + break + case .began: + print("start show record audio view") + if NEAuthManager.hasAudioAuthoriztion() { + showRecordView() + } else { + weak var weakSelf = self + NEAuthManager.requestAudioAuthorization { granted in + if granted == false { + DispatchQueue.main.async { + weakSelf?.showSingleAlert(message: commonLocalizable("jump_microphone_setting")) {} + } + } + } + } + case .changed: + let location = gesture.location(in: view) + if location.y < UIScreen.main.bounds.height - FunRecordAudioView.getGestureHeight() { + recordView?.changeToCancelStyle() + } else { + recordView?.changeToNormalStyle() + } + case .ended: + removeRecordView() + case .cancelled: + removeRecordView() + case .failed: + removeRecordView() + break + @unknown default: + break + } + } + + override open func showTakePicture() { + showCustomBottomVideoAction(self, false) + } + + override open func showFileAction() { + showCustomBottomFileAction(self) + } + + open func showRecordView() { + if recordView == nil { + let recordAudio = FunRecordAudioView() + recordAudio.delegate = self + recordAudio.frame = UIScreen.main.bounds + recordView = recordAudio + UIApplication.shared.keyWindow?.addSubview(recordAudio) + } + startRecord() + } + + open func removeRecordView() { + if let record = recordView { + if record.isRecordNormalStyle() { + endRecord(insideView: true) + } else { + endRecord(insideView: false) + } + } + recordView?.removeFromSuperview() + recordView = nil + } + + public func didEndRecord(view: FunRecordAudioView) { + endRecord(insideView: true) + view.removeFromSuperview() + if let hodlToSpeakView = getFunInputView()?.holdToSpeakView { + hodlToSpeakView.resignFirstResponder() + } + } + + func getFunInputView() -> FunChatInputView? { + if let funInput = menuView as? FunChatInputView { + return funInput + } + return nil + } + + override open func closeReply(button: UIButton?) { + viewmodel.isReplying = false + getFunInputView()?.hideReplyMode() + getFunInputView()?.replyLabel.attributedText = nil + } + + override open func showReplyMessageView(isReEdit: Bool = false) { + viewmodel.isReplying = true + getFunInputView()?.showReplyMode() + if var message = viewmodel.operationModel?.message { + if isReEdit { + if let replyMessage = viewmodel.getReplyMessageWithoutThread(message: message) as? MessageContentModel, let msg = replyMessage.message { + msg.text = message.text + message = msg + viewmodel.operationModel = replyMessage + } + } + var text = chatLocalizable("msg_reply") + if let uid = message.from { + var showName = viewmodel.getShowName(userId: uid, teamId: viewmodel.session.sessionId, false) + if viewmodel.session.sessionType != .P2P, + !IMKitClient.instance.isMySelf(uid) { + addToAtUsers(addText: "@" + showName + "", isReply: true, accid: uid) + } + let user = viewmodel.getUserInfo(userId: uid) + if let alias = user?.alias { + showName = alias + } + text += " " + showName + } + text += ": " + switch message.messageType { + case .text: + if let t = message.text { + text += t + } + case .image: + text += "[\(chatLocalizable("msg_image"))]" + case .audio: + text += "[\(chatLocalizable("msg_audio"))]" + case .video: + text += "[\(chatLocalizable("msg_video"))]" + case .file: + text += "[\(chatLocalizable("msg_file"))]" + case .location: + text += "[\(chatLocalizable("msg_location"))]" + case .custom: + text += "[\(chatLocalizable("msg_custom"))]" + default: + text += "[\(chatLocalizable("msg_unknown"))]" + } + getFunInputView()?.replyLabel.attributedText = NEEmotionTool.getAttWithStr(str: text, + font: .systemFont(ofSize: 13), + color: .ne_greyText) + if menuView.textView.isFirstResponder { + normalOffset = -10 + layoutInputView(offset: currentKeyboardHeight) + } else { + menuView.textView.becomeFirstResponder() + } + } + } + + override open func didTapReadView(_ cell: UITableViewCell, _ model: MessageContentModel?) { + if let msg = model?.message, msg.session?.sessionType == .team { + let readVC = FunReadViewController(message: msg) + navigationController?.pushViewController(readVC, animated: true) + } + } + + public func getMessageModel(model: MessageModel) { + if model.type == .tip || + model.type == .notification || + model.type == .time { + if let tipModel = model as? MessageTipsModel { + tipModel.contentSize = String.getTextRectSize(tipModel.text ?? "", + font: .systemFont(ofSize: 14), + size: CGSize(width: chat_text_maxW, height: CGFloat.greatestFiniteMagnitude)) + tipModel.height = Float(max(tipModel.contentSize.height + chat_content_margin, 28)) + } + return + } + + let contentWidth = model.contentSize.width + let contentHeight = model.contentSize.height + if contentHeight < 42 { + let subHeight = 42 - contentHeight + model.contentSize = CGSize(width: contentWidth, height: 42) + model.offset = CGFloat(subHeight) + } + + if model.type == .reply { + model.offset += 44 + chat_content_margin + } + + if model.type == .rtcCallRecord { + model.contentSize = CGSize(width: contentWidth, height: contentHeight - 2) + model.offset = -2 + } + } + + override open func addToAtUsers(addText: String, isReply: Bool = false, accid: String, _ isLongPress: Bool = false) { + if let isRecordMode = getFunInputView()?.isRecordMode(), isRecordMode { + getFunInputView()?.hideRecordMode() + } + getFunInputView()?.hideRecordMode() + super.addToAtUsers(addText: addText, isReply: isReply, accid: accid, isLongPress) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunForwardAlertViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunForwardAlertViewController.swift new file mode 100644 index 00000000..dcd38067 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunForwardAlertViewController.swift @@ -0,0 +1,40 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonKit +import NECommonUIKit + +@objcMembers +public class FunForwardUserCell: NEBaseForwardUserCell { + override func setupUI() { + super.setupUI() + userHeader.layer.cornerRadius = 4 + } +} + +@objcMembers +public class FunForwardAlertViewController: NEBaseForwardAlertViewController { + override public func setupUI() { + super.setupUI() + tip.font = .systemFont(ofSize: 16, weight: .semibold) + oneUserHead.layer.cornerRadius = 4.0 + sureBtn.setTitleColor(.funChatThemeColor, for: .normal) + userCollection.register( + FunForwardUserCell.self, + forCellWithReuseIdentifier: "\(FunForwardUserCell.self)" + ) + } + + override public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + if let cell = collectionView.dequeueReusableCell( + withReuseIdentifier: "\(FunForwardUserCell.self)", + for: indexPath + ) as? FunForwardUserCell { + return setCellModel(cell: cell, indexPath: indexPath) + } + return UICollectionViewCell() + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunGroupChatViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunGroupChatViewController.swift new file mode 100644 index 00000000..22043247 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunGroupChatViewController.swift @@ -0,0 +1,137 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class FunGroupChatViewController: FunChatViewController, TeamChatViewModelDelegate { + private var isLeaveTeamBySelf = false // 是否是主动退出群聊 + private var isdismissTeam = false // 群聊是否已解散 + private var onCurrentPage = false // 是否位于聊天详情页 + + public init(session: NIMSession, anchor: NIMMessage?) { + super.init(session: session) + viewmodel = TeamChatViewModel(session: session, anchor: anchor) + viewmodel.delegate = self + } + + /// 创建群的构造方法 + /// - Parameter sessionId: 会话id + public init(sessionId: String) { + let session = NIMSession(sessionId, type: .team) + super.init(session: session) + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + onCurrentPage = true + // 被动解散群聊 + if isdismissTeam { + weak var weakSelf = self + showSingleAlert(message: chatLocalizable("team_has_been_removed")) { + weakSelf?.navigationController?.popViewController(animated: true) + } + } + } + + override open func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + onCurrentPage = false + } + + override open func viewDidLoad() { + super.viewDidLoad() + NotificationCenter.default.addObserver(self, selector: #selector(leaveTeamBySelf), name: NotificationName.leaveTeamBySelf, object: nil) + } + + override open func getSessionInfo(session: NIMSession) { + if let vm = viewmodel as? TeamChatViewModel { + if let t = vm.getTeam(teamId: session.sessionId) { + updateTeamInfo(team: t) + } + } + } + + // MARK: private method + + func leaveTeamBySelf(noti: Notification) { + if let flag = noti.object as? Bool { + isLeaveTeamBySelf = flag + } + } + + private func getPlaceHolder(text: String) -> NSMutableAttributedString { + let attribute = NSMutableAttributedString(string: text) + let style = NSMutableParagraphStyle() + style.lineBreakMode = .byTruncatingTail + style.alignment = .left + attribute.addAttribute(.paragraphStyle, value: style, range: NSMakeRange(0, text.utf16.count)) + attribute.addAttribute(.font, value: UIFont.systemFont(ofSize: 16), range: NSMakeRange(0, text.utf16.count)) + attribute.addAttribute(.foregroundColor, value: UIColor.funChatInputViewPlaceholderTextColor, range: NSMakeRange(0, text.utf16.count)) + return attribute + } + + open func updateTeamInfo(team: NIMTeam) { + title = team.getShowName() + if team.inAllMuteMode(), team.owner != NIMSDK.shared().loginManager.currentAccount() { + // 群禁言 + menuView.textView.attributedPlaceholder = getPlaceHolder(text: chatLocalizable("team_mute")) + menuView.textView.backgroundColor = .funChatInputViewBackgroundColorInMute + layoutInputView(offset: 0) + getFunInputView()?.hideRecordMode() + menuView.isUserInteractionEnabled = false + } else { + // 解除群禁言 + menuView.textView.attributedPlaceholder = getPlaceHolder(text: chatLocalizable("fun_chat_input_placeholder")) + menuView.textView.backgroundColor = .white + menuView.isUserInteractionEnabled = true + } + } + + // MARK: TeamChatViewModelDelegate + + open func onTeamRemoved(team: NIMTeam) { + // 退出讨论组 + if team.clientCustomInfo?.contains(discussTeamKey) == true { + navigationController?.popViewController(animated: true) + return + } + + // 离开群聊 + if team.teamId == viewmodel.session.sessionId { + if team.owner != NIMSDK.shared().loginManager.currentAccount() { // 退出群聊 + if isLeaveTeamBySelf { + navigationController?.popViewController(animated: true) + } else { + isdismissTeam = true + // 被动解散群聊 + if onCurrentPage { + weak var weakSelf = self + showSingleAlert(message: chatLocalizable("team_has_been_removed")) { + weakSelf?.navigationController?.popViewController(animated: true) + } + } + } + } else { // 主动解散 + navigationController?.popViewController(animated: true) + } + } + } + + open func onTeamUpdate(team: NIMTeam) { + if team.teamId != viewmodel.session.sessionId { + return + } + updateTeamInfo(team: team) + } + + public func onTeamMemberUpdate(team: NIMTeam) { + didRefreshTable() + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunP2PChatViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunP2PChatViewController.swift new file mode 100644 index 00000000..741bd190 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunP2PChatViewController.swift @@ -0,0 +1,53 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class FunP2PChatViewController: FunChatViewController { + public init(session: NIMSession, anchor: NIMMessage?) { + super.init(session: session) + viewmodel = ChatViewModel(session: session, anchor: anchor) + } + + override open func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + } + + override open func getSessionInfo(session: NIMSession) { + let user = viewmodel.getUserInfo(userId: session.sessionId) + let showName = user?.showName() ?? "" + title = showName + titleContent = showName + let text = chatLocalizable("fun_chat_input_placeholder") + let attribute = NSMutableAttributedString(string: text) + let style = NSMutableParagraphStyle() + style.lineBreakMode = .byTruncatingTail + style.alignment = .left + attribute.addAttribute(.font, value: UIFont.systemFont(ofSize: 16), range: NSMakeRange(0, text.utf16.count)) + attribute.addAttribute(.foregroundColor, value: UIColor.funChatInputViewPlaceholderTextColor, range: NSMakeRange(0, text.utf16.count)) + attribute.addAttribute(.paragraphStyle, value: style, range: NSMakeRange(0, text.utf16.count)) + menuView.textView.attributedPlaceholder = attribute + } + + /// 创建个人聊天页构造方法 + /// - Parameter sessionId: 会话id + public init(sessionId: String) { + let session = NIMSession(sessionId, type: .P2P) + super.init(session: session) + } + + /// 重写父类的构造方法 + /// - Parameter session: sessionId + override public init(session: NIMSession) { + super.init(session: session) + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunPinMessageViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunPinMessageViewController.swift new file mode 100644 index 00000000..de03efa2 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunPinMessageViewController.swift @@ -0,0 +1,70 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class FunPinMessageViewController: NEBasePinMessageViewController { + override public func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .funChatBackgroundColor + emptyView.setEmptyImage(name: "fun_user_empty") + } + + override open func getRegisterCellDic() -> [Int: NEBasePinMessageCell.Type] { + let cellClassDic = [ + NIMMessageType.text.rawValue: FunPinMessageTextCell.self, + NIMMessageType.image.rawValue: FunPinMessageImageCell.self, + NIMMessageType.audio.rawValue: FunPinMessageAudioCell.self, + NIMMessageType.video.rawValue: FunPinMessageVideoCell.self, + NIMMessageType.location.rawValue: FunPinMessageLocationCell.self, + NIMMessageType.file.rawValue: FunPinMessageFileCell.self, + PinMessageDefaultType: FunPinMessageDefaultCell.self, + ] + return cellClassDic + } + + override open func showAction(item: PinMessageModel) { + var actions = [NECustomAlertAction]() + weak var weakSelf = self + + let cancelPinAction = NECustomAlertAction(title: chatLocalizable("operation_cancel_pin")) { + weakSelf?.cancelPinActionClicked(item: item) + } + actions.append(cancelPinAction) + + if item.message.messageType == .text { + let copyAction = NECustomAlertAction(title: chatLocalizable("operation_copy")) { + weakSelf?.copyActionClicked(item: item) + } + actions.append(copyAction) + } + + if item.message.messageType != .audio { + let forwardAction = NECustomAlertAction(title: chatLocalizable("operation_forward")) { + weakSelf?.forwardActionClicked(item: item) + } + actions.append(forwardAction) + } + + showCustomActionSheet(actions) + } + + override open func getForwardAlertController() -> NEBaseForwardAlertViewController { + FunForwardAlertViewController() + } + + override open func forwardMessage(_ message: NIMMessage) { + let userAction = NECustomAlertAction(title: chatLocalizable("contact_user")) { [weak self] in + self?.forwardMessageToUser(message) + } + + let teamAction = NECustomAlertAction(title: chatLocalizable("team")) { [weak self] in + self?.forwardMessageToTeam(message) + } + + showCustomActionSheet([teamAction, userAction]) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunReadViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunReadViewController.swift new file mode 100644 index 00000000..3d2d7c7e --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunReadViewController.swift @@ -0,0 +1,40 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK +import NECoreIMKit +import NECommonUIKit + +@objcMembers +open class FunReadViewController: NEBaseReadViewController { + override public func commonUI() { + super.commonUI() + navigationController?.navigationBar.backgroundColor = .white + customNavigationView.backgroundColor = .white + + readButton.setTitleColor(UIColor.funChatThemeColor, for: .normal) + line.backgroundColor = UIColor.funChatThemeColor + + readTableView.register( + FunUserTableViewCell.self, + forCellReuseIdentifier: "\(FunUserTableViewCell.self)" + ) + readTableView.rowHeight = 64 + + emptyView.setEmptyImage(name: "fun_emptyView") + } + + override public func readButtonEvent(button: UIButton) { + super.readButtonEvent(button: button) + readButton.setTitleColor(UIColor.funChatThemeColor, for: .normal) + unreadButton.setTitleColor(UIColor.ne_darkText, for: .normal) + } + + override public func unreadButtonEvent(button: UIButton) { + super.unreadButtonEvent(button: button) + readButton.setTitleColor(UIColor.ne_darkText, for: .normal) + unreadButton.setTitleColor(UIColor.funChatThemeColor, for: .normal) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunSelectUserViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunSelectUserViewController.swift new file mode 100644 index 00000000..4d81ca14 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunSelectUserViewController.swift @@ -0,0 +1,47 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NEChatKit +import NECoreIMKit + +@objcMembers +open class FunSelectUserViewController: NEBaseSelectUserViewController { + override init(sessionId: String, showSelf: Bool = true) { + super.init(sessionId: sessionId, showSelf: showSelf) + className = "FunSelectUserViewController" + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func commonUI() { + super.commonUI() + + tableView.register( + FunChatTeamMemberCell.self, + forCellReuseIdentifier: "\(FunChatTeamMemberCell.self)" + ) + tableView.rowHeight = 64 + } + + override open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell( + withIdentifier: "\(FunChatTeamMemberCell.self)", + for: indexPath + ) as! FunChatTeamMemberCell + if indexPath.row == 0 { + cell.headerView.image = UIImage.ne_imageNamed(name: "fun_all") + cell.nameLabel.text = chatLocalizable("user_select_all") + } else { + if let model = teamInfo?.users[indexPath.row - 1] { + cell.configure(model) + } + } + return cell + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunUserSettingViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunUserSettingViewController.swift new file mode 100644 index 00000000..b6bd9822 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/Controller/FunUserSettingViewController.swift @@ -0,0 +1,110 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonKit +import NIMSDK + +@objcMembers +open class FunUserSettingViewController: NEBaseUserSettingViewController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + cellClassDic = [ + UserSettingType.SwitchType.rawValue: FunUserSettingSwitchCell.self, + UserSettingType.SelectType.rawValue: FunUserSettingSelectCell.self, + ] + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override public func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .funChatBackgroundColor + viewmodel.cellDatas.forEach { cellModel in + cellModel.cornerType = .none + } + } + + override func setupUI() { + super.setupUI() + navigationController?.navigationBar.backgroundColor = .white + customNavigationView.backgroundColor = .white + customNavigationView.bottomLine.isHidden = false + userHeader.layer.cornerRadius = 4.0 + addBtn.setImage(coreLoader.loadImage("fun_setting_add"), for: .normal) + contentTable.rowHeight = 56 + } + + override public func headerView() -> UIView { + let header = UIView(frame: CGRect(x: 0, y: 0, width: view.width, height: 117)) + header.backgroundColor = .clear + let cornerBack = UIView() + cornerBack.backgroundColor = .white + cornerBack.translatesAutoresizingMaskIntoConstraints = false + header.addSubview(cornerBack) + NSLayoutConstraint.activate([ + cornerBack.bottomAnchor.constraint(equalTo: header.bottomAnchor, constant: -8), + cornerBack.leftAnchor.constraint(equalTo: header.leftAnchor), + cornerBack.rightAnchor.constraint(equalTo: header.rightAnchor), + cornerBack.heightAnchor.constraint(equalToConstant: 109.0), + ]) + + cornerBack.addSubview(userHeader) + NSLayoutConstraint.activate([ + userHeader.leftAnchor.constraint(equalTo: cornerBack.leftAnchor, constant: 22), + userHeader.topAnchor.constraint(equalTo: cornerBack.topAnchor, constant: 22), + userHeader.widthAnchor.constraint(equalToConstant: 50), + userHeader.heightAnchor.constraint(equalToConstant: 50), + ]) + let tap = UITapGestureRecognizer() + userHeader.addGestureRecognizer(tap) + tap.numberOfTapsRequired = 1 + tap.numberOfTouchesRequired = 1 + + if let url = viewmodel.userInfo?.userInfo?.avatarUrl { + userHeader.sd_setImage(with: URL(string: url), completed: nil) + userHeader.setTitle("") + userHeader.backgroundColor = .clear + } else if let name = viewmodel.userInfo?.shortName(showAlias: false, count: 2) { + userHeader.sd_setImage(with: nil) + userHeader.setTitle(name) + userHeader.backgroundColor = UIColor.colorWithString(string: viewmodel.userInfo?.userId) + } + + cornerBack.addSubview(addBtn) + NSLayoutConstraint.activate([ + addBtn.leftAnchor.constraint(equalTo: userHeader.rightAnchor, constant: 20.0), + addBtn.topAnchor.constraint(equalTo: userHeader.topAnchor), + addBtn.widthAnchor.constraint(equalToConstant: 50.0), + addBtn.heightAnchor.constraint(equalToConstant: 50.0), + ]) + addBtn.addTarget(self, action: #selector(createDiscuss), for: .touchUpInside) + + cornerBack.addSubview(nameLabel) + NSLayoutConstraint.activate([ + nameLabel.topAnchor.constraint(equalTo: userHeader.bottomAnchor, constant: 3.0), + nameLabel.centerXAnchor.constraint(equalTo: userHeader.centerXAnchor), + nameLabel.widthAnchor.constraint(equalTo: userHeader.widthAnchor), + ]) + nameLabel.text = viewmodel.userInfo?.showName() + + return header + } + + override public func filterStackViewController() -> [UIViewController]? { + navigationController?.viewControllers.filter { + if $0.isKind(of: FunP2PChatViewController.self) || $0 + .isKind(of: FunUserSettingViewController.self) { + return false + } + return true + } + } + + override func getPinMessageViewController(session: NIMSession) -> NEBasePinMessageViewController { + FunPinMessageViewController(session: session) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/FunChatRouter.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/FunChatRouter.swift new file mode 100644 index 00000000..058971e3 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/FunChatRouter.swift @@ -0,0 +1,59 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import NIMSDK + +public extension ChatRouter { + static func registerFun() { + // pin + Router.shared.register(PushPinMessageVCRouter) { param in + let nav = param["nav"] as? UINavigationController + guard let session = param["session"] as? NIMSession else { + return + } + let pin = FunPinMessageViewController(session: session) + nav?.pushViewController(pin, animated: true) + } + + // p2p + Router.shared.register(PushP2pChatVCRouter) { param in + print("param:\(param)") + let nav = param["nav"] as? UINavigationController + guard let session = param["session"] as? NIMSession else { + return + } + let anchor = param["anchor"] as? NIMMessage + var p2pChatVC = FunP2PChatViewController(session: session, anchor: anchor) + for (i, vc) in (nav?.viewControllers ?? []).enumerated() { + if vc.isKind(of: ChatViewController.self) { + nav?.viewControllers[i] = p2pChatVC + nav?.popToViewController(p2pChatVC, animated: true) + return + } + } + nav?.pushViewController(p2pChatVC, animated: true) + } + + // group + Router.shared.register(PushTeamChatVCRouter) { param in + print("param:\(param)") + let nav = param["nav"] as? UINavigationController + guard let session = param["session"] as? NIMSession else { + return + } + + let anchor = param["anchor"] as? NIMMessage + let groupVC = FunGroupChatViewController(session: session, anchor: anchor) + for (i, vc) in (nav?.viewControllers ?? []).enumerated() { + if vc.isKind(of: ChatViewController.self) { + nav?.viewControllers[i] = groupVC + nav?.popToViewController(groupVC, animated: true) + return + } + } + nav?.pushViewController(groupVC, animated: true) + } + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/FunChatUIColor.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/FunChatUIColor.swift new file mode 100644 index 00000000..d80cbede --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/FunChatUIColor.swift @@ -0,0 +1,29 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import NECommonKit + +public extension UIColor { + static let funChatInputBg = UIColor(hexString: "#F5F5F5") + static let funChatInputReplyBg = UIColor(hexString: "#E1E1E1") + static let funChatInputHoldspeakBg = UIColor(hexString: "#FFFFFF") + static let funChatInputHoldspeakTextColor = UIColor(hexString: "#222222") + static let funChatInputMoreActionViewLineColor = UIColor(hexString: "#DDDDDD") + + static let funRecordAudioViewBg = UIColor(hexString: "#000000") + static let funRecordAudioTextColor = UIColor(hexString: "#AAAAAA") + static let funRecordAudioProgressNormalColor = UIColor(hexString: "#A9EA7A") + static let funRecordAudioProgressCancelColor = UIColor(hexString: "#E75D58") + static let funRecordAudioLastTimeColor = UIColor(hexString: "#000000", 0.4) + + static let funChatThemeColor = UIColor(hexString: "#58BE6B") + static let funChatBackgroundColor = UIColor(hexString: "#EDEDED") + static let funChatLineBorderColor = UIColor(hexString: "#E5E5E5") + static let funChatNavigationBottomLineColor = UIColor(hexString: "#D5D5D5", 0.4) + static let funChatInputViewPlaceholderTextColor = UIColor(hexString: "#AAAAAA") + static let funChatInputViewBackgroundColorInMute = UIColor(hexString: "#E0E0E0") + static let funChatNetworkBrokenBackgroundColor = UIColor(hexString: "#FCEEEE") + static let funChatNetworkBrokenTitleColor = UIColor(white: 0, alpha: 0.5) +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/View/FunChatInputView.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/View/FunChatInputView.swift new file mode 100644 index 00000000..36fa2529 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/View/FunChatInputView.swift @@ -0,0 +1,276 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +let addMoreBtnTag = 8 +let addEmojBtnTag = 6 +let showPhotoTag = 2 + +@objc +public protocol FunChatInputViewDelegate: NSObjectProtocol { + func recordModeChangeDidClick() + func didHideReplyMode() + func didShowReplyMode() // 内部状态转换的回调,上次是回复UI样式,转转成录音模式后再转换回来,还要保持回复样式,此场景下对外回调 +} + +@objcMembers +open class FunChatInputView: NEBaseChatInputView { + /* + // Only override draw() if you perform custom drawing. + // An empty implementation adversely affects performance during animation. + override func draw(_ rect: CGRect) { + // Drawing code + } + */ + + var replyViewTopConstraint: NSLayoutConstraint? + + weak var funDelegate: FunChatInputViewDelegate? + + var defaultReplyTopSpace: CGFloat = 8 + + public var replyBackView: UIView = { + let back = UIView() + back.translatesAutoresizingMaskIntoConstraints = false + back.layer.cornerRadius = 4.0 + back.clipsToBounds = true + back.backgroundColor = UIColor.funChatInputReplyBg + return back + }() + + public lazy var replyLabel: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.backgroundColor = UIColor.clear + label.numberOfLines = 2 + return label + }() + + public var clearBtn: UIButton = { + let button = UIButton() + button.translatesAutoresizingMaskIntoConstraints = false + button.backgroundColor = UIColor.clear + button.setImage(coreLoader.loadImage("fun_chat_input_reply_clear"), for: .normal) + return button + }() + + public var changeRecordModeBtn: UIButton = { + let button = UIButton() + button.translatesAutoresizingMaskIntoConstraints = false + button.backgroundColor = UIColor.clear + button.setImage(coreLoader.loadImage("fun_chat_input_change_record"), for: .normal) + button.setImage(coreLoader.loadImage("fun_chat_input_keyboard"), for: .selected) + return button + }() + + public var showMoreActionBtn: UIButton = { + let button = UIButton() + button.translatesAutoresizingMaskIntoConstraints = false + button.backgroundColor = UIColor.clear + button.tag = addMoreBtnTag + button.setImage(coreLoader.loadImage("fun_chat_input_show_more"), for: .normal) + return button + }() + + public var showEmojBtn: UIButton = { + let button = UIButton() + button.translatesAutoresizingMaskIntoConstraints = false + button.backgroundColor = UIColor.clear + button.tag = addEmojBtnTag + button.setImage(coreLoader.loadImage("fun_chat_input_show_emoj"), for: .normal) + return button + }() + + public var holdToSpeakView: UIView = { + let view = UIView() + view.backgroundColor = UIColor.funChatInputHoldspeakBg + view.clipsToBounds = true + view.translatesAutoresizingMaskIntoConstraints = false + view.layer.cornerRadius = 4.0 + + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = UIColor.funChatInputHoldspeakTextColor + label.font = UIFont.systemFont(ofSize: 16, weight: .semibold) + view.addSubview(label) + NSLayoutConstraint.activate([ + label.centerYAnchor.constraint(equalTo: view.centerYAnchor), + label.centerXAnchor.constraint(equalTo: view.centerXAnchor), + ]) + label.text = chatLocalizable("fun_hold_to_talk") + + return view + }() + + override open func commonUI() { + backgroundColor = UIColor.funChatInputBg + + addSubview(textView) + textView.layer.cornerRadius = 4.0 + textView.delegate = self + textviewLeftConstraint = textView.leftAnchor.constraint(equalTo: leftAnchor, constant: 48) + textviewRightConstraint = textView.rightAnchor.constraint(equalTo: rightAnchor, constant: -88) + + NSLayoutConstraint.activate([ + textviewLeftConstraint!, + textviewRightConstraint!, + textView.topAnchor.constraint(equalTo: topAnchor, constant: 8), + textView.heightAnchor.constraint(equalToConstant: 40), + ]) + textInput = textView + + insertSubview(replyBackView, belowSubview: textView) + replyViewTopConstraint = replyBackView.topAnchor.constraint(equalTo: topAnchor, constant: defaultReplyTopSpace) + NSLayoutConstraint.activate([ + replyViewTopConstraint!, + replyBackView.heightAnchor.constraint(equalToConstant: 40), + replyBackView.leftAnchor.constraint(equalTo: textView.leftAnchor), + replyBackView.rightAnchor.constraint(equalTo: textView.rightAnchor), + ]) + + replyBackView.addSubview(replyLabel) + NSLayoutConstraint.activate([ + replyLabel.leftAnchor.constraint(equalTo: replyBackView.leftAnchor, constant: 5), + replyLabel.topAnchor.constraint(equalTo: replyBackView.topAnchor), + replyLabel.bottomAnchor.constraint(equalTo: replyBackView.bottomAnchor), + replyLabel.rightAnchor.constraint(equalTo: replyBackView.rightAnchor, constant: -42), + ]) + + replyBackView.addSubview(clearBtn) + NSLayoutConstraint.activate([ + clearBtn.rightAnchor.constraint(equalTo: replyBackView.rightAnchor), + clearBtn.bottomAnchor.constraint(equalTo: replyBackView.bottomAnchor), + clearBtn.topAnchor.constraint(equalTo: replyBackView.topAnchor), + clearBtn.leftAnchor.constraint(equalTo: replyLabel.rightAnchor), + ]) + clearBtn.addTarget(self, action: #selector(clearReplyMode), for: .touchUpInside) + + addSubview(changeRecordModeBtn) + NSLayoutConstraint.activate([ + changeRecordModeBtn.leftAnchor.constraint(equalTo: leftAnchor), + changeRecordModeBtn.topAnchor.constraint(equalTo: replyBackView.topAnchor), + changeRecordModeBtn.bottomAnchor.constraint(equalTo: replyBackView.bottomAnchor), + changeRecordModeBtn.rightAnchor.constraint(equalTo: replyBackView.leftAnchor), + ]) + changeRecordModeBtn.addTarget(self, action: #selector(changeToRecordMode), for: .touchUpInside) + + addSubview(showMoreActionBtn) + NSLayoutConstraint.activate([ + showMoreActionBtn.rightAnchor.constraint(equalTo: rightAnchor), + showMoreActionBtn.bottomAnchor.constraint(equalTo: replyBackView.bottomAnchor), + showMoreActionBtn.topAnchor.constraint(equalTo: replyBackView.topAnchor), + showMoreActionBtn.widthAnchor.constraint(equalToConstant: 44), + ]) + + showMoreActionBtn.addTarget(self, action: #selector(moreBtnClick), for: .touchUpInside) + + addSubview(showEmojBtn) + NSLayoutConstraint.activate([ + showEmojBtn.rightAnchor.constraint(equalTo: showMoreActionBtn.leftAnchor), + showEmojBtn.topAnchor.constraint(equalTo: replyBackView.topAnchor), + showEmojBtn.bottomAnchor.constraint(equalTo: replyBackView.bottomAnchor), + showEmojBtn.widthAnchor.constraint(equalToConstant: 44), + ]) + showEmojBtn.addTarget(self, action: #selector(emojBtnClick), for: .touchUpInside) + + addSubview(contentView) + contentView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + contentView.leftAnchor.constraint(equalTo: leftAnchor), + contentView.rightAnchor.constraint(equalTo: rightAnchor), + contentView.heightAnchor.constraint(equalToConstant: contentHeight), + contentView.topAnchor.constraint(equalTo: replyBackView.bottomAnchor, constant: 15), + ]) + + contentView.addSubview(emojiView) + + chatAddMoreView.frame = CGRect(x: chatAddMoreView.frame.origin.x, + y: chatAddMoreView.frame.origin.y + 10, + width: chatAddMoreView.frame.size.width, + height: chatAddMoreView.frame.size.height) + contentView.addSubview(chatAddMoreView) + + let moreActionViewLine = UIView() + moreActionViewLine.translatesAutoresizingMaskIntoConstraints = false + chatAddMoreView.addSubview(moreActionViewLine) + chatAddMoreView.clipsToBounds = false + moreActionViewLine.frame = CGRect(x: 0, y: -10, width: chatAddMoreView.width, height: 1.0) + moreActionViewLine.backgroundColor = UIColor.funChatInputMoreActionViewLineColor + + addSubview(holdToSpeakView) + NSLayoutConstraint.activate([ + holdToSpeakView.leftAnchor.constraint(equalTo: textView.leftAnchor), + holdToSpeakView.rightAnchor.constraint(equalTo: textView.rightAnchor), + holdToSpeakView.topAnchor.constraint(equalTo: textView.topAnchor), + holdToSpeakView.bottomAnchor.constraint(equalTo: textView.bottomAnchor), + ]) + holdToSpeakView.isHidden = true + } + + open func changeToRecordMode(_ button: UIButton) { + button.isSelected = !button.isSelected + if button.isSelected == true { + showRecordMode() + } else { + hideRecordMode() + } + } + + open func clearReplyMode() { + replyLabel.attributedText = nil + hideReplyMode() + } + + open func showRecordMode() { + currentType = .audio + holdToSpeakView.isHidden = false + hideReplyMode() + funDelegate?.recordModeChangeDidClick() + } + + open func hideRecordMode() { + holdToSpeakView.isHidden = true + changeRecordModeBtn.isSelected = false + if let replyText = replyLabel.attributedText, replyText.length > 0 { + showReplyMode() + funDelegate?.didShowReplyMode() + } + } + + open func showReplyMode() { + replyViewTopConstraint?.constant = 52 + if replyLabel.attributedText == nil { + hideRecordMode() + } else if let replyText = replyLabel.attributedText, replyText.length <= 0 { + hideRecordMode() + } + } + + open func hideReplyMode() { + if let topSpace = replyViewTopConstraint?.constant, topSpace == defaultReplyTopSpace { + return + } + replyViewTopConstraint?.constant = 8 + funDelegate?.didHideReplyMode() + } + + open func isRecordMode() -> Bool { + changeRecordModeBtn.isSelected + } + + @objc + private func moreBtnClick() { + hideRecordMode() + changeRecordModeBtn.isSelected = false + buttonEvent(button: showMoreActionBtn) + } + + @objc + private func emojBtnClick() { + hideRecordMode() + changeRecordModeBtn.isSelected = false + buttonEvent(button: showEmojBtn) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/FunUI/View/FunRecordAudioView.swift b/NEChatUIKit/NEChatUIKit/Classes/FunUI/View/FunRecordAudioView.swift new file mode 100644 index 00000000..a8a8524b --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/FunUI/View/FunRecordAudioView.swift @@ -0,0 +1,292 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import Lottie + +@objc +public protocol FunChatRecordViewDelegate: NSObjectProtocol { + func didEndRecord(view: FunRecordAudioView) +} + +@objcMembers +open class FunRecordAudioView: UIView { + public weak var delegate: FunChatRecordViewDelegate? + + public var maxDuration: Int = 60 + + private var timeCount = 0 + + public var lastTimeDuration = 10 + + public var timer: Timer? + + public var maxRecordProgressMargin: CGFloat = 30.0 + + public var minRecordProgressWidth: CGFloat = 165.0 + + lazy var lottieView: LOTAnimationView = { + let lottie = LOTAnimationView() + lottie.translatesAutoresizingMaskIntoConstraints = false + lottie.setAnimation(named: "fun_vioce_data", bundle: coreLoader.bundle) + lottie.loopAnimation = true + lottie.contentMode = .scaleToFill + lottie.translatesAutoresizingMaskIntoConstraints = false + return lottie + }() + + lazy var lottieContentView: UIView = { + let content = UIView() + content.translatesAutoresizingMaskIntoConstraints = false + content.backgroundColor = UIColor.clear + return content + }() + + public var triangleView: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = UIColor.funRecordAudioProgressNormalColor + view.transform = CGAffineTransform(rotationAngle: CGFloat.pi / 4) + return view + }() + + public var recordProgressView: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.clipsToBounds = true + view.layer.cornerRadius = 16.0 + view.backgroundColor = UIColor.funRecordAudioProgressNormalColor + return view + }() + + public let recordGestureArea: UIImageView = { + let imageView = UIImageView() + imageView.translatesAutoresizingMaskIntoConstraints = false + imageView.image = coreLoader.loadImage("fun_chat_record_gesture_inner") + imageView.highlightedImage = coreLoader.loadImage("fun_chat_record_gesture_outter") + imageView.isHighlighted = false + return imageView + }() + + public let recordCloseImage: UIImageView = { + let close = UIImageView() + close.contentMode = .center + close.translatesAutoresizingMaskIntoConstraints = false + close.image = coreLoader.loadImage("fun_chat_record_close_dark") + close.highlightedImage = coreLoader.loadImage("fun_chat_record_close_light") + close.isHighlighted = false + return close + }() + + public let releaseToSendLabel: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.font = UIFont.systemFont(ofSize: 16.0) + label.textColor = UIColor.funRecordAudioTextColor + label.text = chatLocalizable("release_to_send") + label.textAlignment = .center + return label + }() + + public let releaseToCancelLabel: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.font = UIFont.systemFont(ofSize: 16.0) + label.textColor = UIColor.funRecordAudioTextColor + label.text = chatLocalizable("release_to_cancel") + label.isHidden = true + label.textAlignment = .center + return label + }() + + public let lastTimeLabel: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.font = UIFont.systemFont(ofSize: 18.0) + label.textColor = UIColor.funRecordAudioLastTimeColor + label.textAlignment = .center + label.isHidden = true + return label + }() + + private var progressWidthIncreaseFactor: CGFloat = 0 + + private var progressWidthConstraint: NSLayoutConstraint? + + override init(frame: CGRect) { + super.init(frame: frame) + setupUI() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + open func setupUI() { + let totalWidth = UIScreen.main.bounds.width - maxRecordProgressMargin * 2 - minRecordProgressWidth + let delta = CGFloat(maxDuration - lastTimeDuration) + progressWidthIncreaseFactor = totalWidth / delta + + backgroundColor = UIColor.funRecordAudioViewBg.withAlphaComponent(0.7) + addSubview(recordGestureArea) + NSLayoutConstraint.activate([ + recordGestureArea.leftAnchor.constraint(equalTo: leftAnchor), + recordGestureArea.rightAnchor.constraint(equalTo: rightAnchor), + recordGestureArea.bottomAnchor.constraint(equalTo: bottomAnchor), + recordGestureArea.heightAnchor.constraint(equalToConstant: FunRecordAudioView.getGestureHeight()), + ]) + + addSubview(recordCloseImage) + NSLayoutConstraint.activate([ + recordCloseImage.centerXAnchor.constraint(equalTo: centerXAnchor), + recordCloseImage.centerYAnchor.constraint(equalTo: recordGestureArea.centerYAnchor, constant: -152), + recordCloseImage.widthAnchor.constraint(equalToConstant: 88.0), + recordCloseImage.heightAnchor.constraint(equalToConstant: 88.0), + ]) + + addSubview(releaseToSendLabel) + NSLayoutConstraint.activate([ + releaseToSendLabel.centerXAnchor.constraint(equalTo: centerXAnchor), + releaseToSendLabel.bottomAnchor.constraint(equalTo: recordGestureArea.topAnchor, constant: -16), + ]) + + addSubview(releaseToCancelLabel) + NSLayoutConstraint.activate([ + releaseToCancelLabel.centerXAnchor.constraint(equalTo: centerXAnchor), + releaseToCancelLabel.bottomAnchor.constraint(equalTo: recordCloseImage.topAnchor, constant: -16), + ]) + + addSubview(recordProgressView) + progressWidthConstraint = recordProgressView.widthAnchor.constraint(equalToConstant: minRecordProgressWidth) + NSLayoutConstraint.activate([ + recordProgressView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -354), + recordProgressView.heightAnchor.constraint(equalToConstant: 80), + progressWidthConstraint!, + recordProgressView.centerXAnchor.constraint(equalTo: centerXAnchor), + ]) + + recordProgressView.addSubview(lastTimeLabel) + NSLayoutConstraint.activate([ + lastTimeLabel.centerXAnchor.constraint(equalTo: recordProgressView.centerXAnchor), + lastTimeLabel.centerYAnchor.constraint(equalTo: recordProgressView.centerYAnchor), + ]) + + addSubview(lottieView) + NSLayoutConstraint.activate([ + lottieView.centerXAnchor.constraint(equalTo: recordProgressView.centerXAnchor), + lottieView.centerYAnchor.constraint(equalTo: recordProgressView.centerYAnchor), + lottieView.widthAnchor.constraint(equalToConstant: 80), + lottieView.heightAnchor.constraint(equalToConstant: 40), + ]) + lottieView.play() + + addSubview(triangleView) + insertSubview(triangleView, belowSubview: recordProgressView) + NSLayoutConstraint.activate([ + triangleView.widthAnchor.constraint(equalToConstant: 21), + triangleView.heightAnchor.constraint(equalToConstant: 21), + triangleView.centerXAnchor.constraint(equalTo: centerXAnchor), + triangleView.topAnchor.constraint(equalTo: recordProgressView.topAnchor, constant: 60), + ]) + + weak var weakSelf = self + let finalWidth = UIScreen.main.bounds.width - maxRecordProgressMargin * 2 + let animDuration = TimeInterval(maxDuration - lastTimeDuration) +// DispatchQueue.main.async { +// weakSelf?.progressWidthConstraint?.constant = finalWidth +// UIView.animate(withDuration: animDuration) { +// weakSelf?.layoutSubviews() +// } +// } + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: DispatchWorkItem(block: { + weakSelf?.progressWidthConstraint?.constant = finalWidth + UIView.animate(withDuration: animDuration) { + weakSelf?.layoutIfNeeded() + } + })) + +// UIView.animate(withDuration: TimeInterval(maxDuration - lastTimeDuration), delay: 0, options: [.curveLinear]) { +// weakSelf?.progressWidthConstraint?.constant = finalWidth +// } + + timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timeCountIncrease), userInfo: nil, repeats: true) + } + + static func getGestureHeight() -> CGFloat { + let windowWidth = UIScreen.main.bounds.width + return windowWidth / 375.0 * 128.0 + } + + public func changeToCancelStyle() { + if releaseToSendLabel.isHidden == true { + return + } + recordCloseImage.isHighlighted = true + recordGestureArea.isHighlighted = true + releaseToSendLabel.isHidden = true + releaseToCancelLabel.isHidden = false + recordProgressView.backgroundColor = UIColor.funRecordAudioProgressCancelColor + triangleView.backgroundColor = UIColor.funRecordAudioProgressCancelColor + } + + public func changeToNormalStyle() { + if releaseToSendLabel.isHidden == false { + return + } + recordCloseImage.isHighlighted = false + recordGestureArea.isHighlighted = false + releaseToSendLabel.isHidden = false + releaseToCancelLabel.isHidden = true + recordProgressView.backgroundColor = UIColor.funRecordAudioProgressNormalColor + triangleView.backgroundColor = UIColor.funRecordAudioProgressNormalColor + } + + public func isRecordNormalStyle() -> Bool { + if releaseToSendLabel.isHidden == false { + return true + } + return false + } + + func timeCountIncrease() { + print("timeCountIncrease : \(timeCount)") + let lastTime = maxDuration - timeCount + if lastTime == 0 { + timer?.invalidate() + timer = nil + delegate?.didEndRecord(view: self) + return + } + + if lastTimeDuration >= lastTime { + lastTimeLabel.isHidden = false + if lottieView.isAnimationPlaying { + lottieView.stop() + lottieView.isHidden = true + } + lastTimeLabel.text = String(format: chatLocalizable("stop_record"), lastTime) + } + timeCount += 1 + } + +// deinit { +// if let valid = timer?.isValid, valid { +// timer?.invalidate() +// timer = nil +// } +// } + + override open func willMove(toWindow newWindow: UIWindow?) {} + + override open func willMove(toSuperview newSuperview: UIView?) { + if newSuperview != nil { + return + } + if let valid = timer?.isValid, valid { + timer?.invalidate() + timer = nil + } + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageAudioCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageAudioCell.swift new file mode 100644 index 00000000..07b46670 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageAudioCell.swift @@ -0,0 +1,145 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class ChatMessageAudioCell: NormalChatMessageBaseCell, ChatAudioCellProtocol { + public var messageId: String? + public var isPlaying: Bool = false + + public var audioImageViewLeft = UIImageView(image: UIImage.ne_imageNamed(name: "left_play_3")) + public var timeLabelLeft = UILabel() + + public var audioImageViewRight = UIImageView(image: UIImage.ne_imageNamed(name: "audio_play")) + public var timeLabelRight = UILabel() + + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + commonUI() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func commonUI() { + commonUIRight() + commonUILeft() + } + + open func commonUILeft() { + audioImageViewLeft.contentMode = .center + audioImageViewLeft.translatesAutoresizingMaskIntoConstraints = false + bubbleImageLeft.addSubview(audioImageViewLeft) + NSLayoutConstraint.activate([ + audioImageViewLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor, constant: 16), + audioImageViewLeft.centerYAnchor.constraint(equalTo: bubbleImageLeft.centerYAnchor), + audioImageViewLeft.widthAnchor.constraint(equalToConstant: 28), + audioImageViewLeft.heightAnchor.constraint(equalToConstant: 28), + ]) + + timeLabelLeft.font = UIFont.systemFont(ofSize: 14) + timeLabelLeft.textColor = UIColor.ne_darkText + timeLabelLeft.textAlignment = .left + timeLabelLeft.translatesAutoresizingMaskIntoConstraints = false + bubbleImageLeft.addSubview(timeLabelLeft) + NSLayoutConstraint.activate([ + timeLabelLeft.leftAnchor.constraint(equalTo: audioImageViewLeft.rightAnchor, constant: 12), + timeLabelLeft.centerYAnchor.constraint(equalTo: bubbleImageLeft.centerYAnchor), + timeLabelLeft.rightAnchor.constraint(equalTo: bubbleImageLeft.rightAnchor, constant: -12), + timeLabelLeft.heightAnchor.constraint(equalToConstant: 28), + ]) + audioImageViewLeft.animationDuration = 1 + if let leftImage1 = UIImage.ne_imageNamed(name: "left_play_1"), + let leftmage2 = UIImage.ne_imageNamed(name: "left_play_2"), + let leftmage3 = UIImage.ne_imageNamed(name: "left_play_3") { + audioImageViewLeft.animationImages = [leftImage1, leftmage2, leftmage3] + } + } + + open func commonUIRight() { + audioImageViewRight.contentMode = .center + audioImageViewRight.translatesAutoresizingMaskIntoConstraints = false + bubbleImageRight.addSubview(audioImageViewRight) + NSLayoutConstraint.activate([ + audioImageViewRight.rightAnchor.constraint(equalTo: bubbleImageRight.rightAnchor, constant: -16), + audioImageViewRight.centerYAnchor.constraint(equalTo: bubbleImageRight.centerYAnchor), + audioImageViewRight.widthAnchor.constraint(equalToConstant: 28), + audioImageViewRight.heightAnchor.constraint(equalToConstant: 28), + ]) + + timeLabelRight.font = UIFont.systemFont(ofSize: 14) + timeLabelRight.textColor = UIColor.ne_darkText + timeLabelRight.textAlignment = .right + timeLabelRight.translatesAutoresizingMaskIntoConstraints = false + bubbleImageRight.addSubview(timeLabelRight) + NSLayoutConstraint.activate([ + timeLabelRight.rightAnchor.constraint(equalTo: audioImageViewRight.leftAnchor, constant: -12), + timeLabelRight.centerYAnchor.constraint(equalTo: bubbleImageRight.centerYAnchor), + timeLabelRight.heightAnchor.constraint(equalToConstant: 28), + ]) + + audioImageViewRight.animationDuration = 1 + if let image1 = UIImage.ne_imageNamed(name: "play_1"), + let image2 = UIImage.ne_imageNamed(name: "play_2"), + let image3 = UIImage.ne_imageNamed(name: "play_3") { + audioImageViewRight.animationImages = [image1, image2, image3] + } + } + + open func startAnimation(byRight: Bool) { + if byRight { + if !audioImageViewRight.isAnimating { + audioImageViewRight.startAnimating() + } + } else if !audioImageViewLeft.isAnimating { + audioImageViewLeft.startAnimating() + } + if let m = contentModel as? MessageAudioModel { + m.isPlaying = true + isPlaying = true + } + } + + open func stopAnimation(byRight: Bool) { + if byRight { + if audioImageViewRight.isAnimating { + audioImageViewRight.stopAnimating() + } + } else if audioImageViewLeft.isAnimating { + audioImageViewLeft.stopAnimating() + } + if let m = contentModel as? MessageAudioModel { + m.isPlaying = false + isPlaying = false + } + } + + override open func showLeftOrRight(showRight: Bool) { + super.showLeftOrRight(showRight: showRight) + audioImageViewLeft.isHidden = showRight + timeLabelLeft.isHidden = showRight + + audioImageViewRight.isHidden = !showRight + timeLabelRight.isHidden = !showRight + } + + override open func setModel(_ model: MessageContentModel) { + super.setModel(model) + guard let isSend = model.message?.isOutgoingMsg else { + return + } + if let m = model as? MessageAudioModel { + if isSend { + timeLabelRight.text = "\(m.duration)" + "s" + } else { + timeLabelLeft.text = "\(m.duration)" + "s" + } + m.isPlaying ? startAnimation(byRight: isSend) : stopAnimation(byRight: isSend) + messageId = m.message?.messageId + } + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageCallCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageCallCell.swift new file mode 100644 index 00000000..68c8c570 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageCallCell.swift @@ -0,0 +1,77 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class ChatMessageCallCell: NormalChatMessageBaseCell { + public let contentLabelLeft = UILabel() + public let contentLabelRight = UILabel() + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + commonUI() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + open func commonUI() { + commonUIRight() + commonUILeft() + } + + open func commonUILeft() { + contentLabelLeft.translatesAutoresizingMaskIntoConstraints = false + contentLabelLeft.isEnabled = false + contentLabelLeft.numberOfLines = 0 + contentLabelLeft.isUserInteractionEnabled = false + contentLabelLeft.font = NEKitChatConfig.shared.ui.messageTextSize + contentLabelLeft.textAlignment = .center + contentLabelLeft.backgroundColor = .clear + bubbleImageLeft.addSubview(contentLabelLeft) + NSLayoutConstraint.activate([ + contentLabelLeft.rightAnchor.constraint(equalTo: bubbleImageLeft.rightAnchor, constant: -chat_content_margin), + contentLabelLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor, constant: chat_content_margin), + contentLabelLeft.topAnchor.constraint(equalTo: bubbleImageLeft.topAnchor, constant: 0), + contentLabelLeft.bottomAnchor.constraint(equalTo: bubbleImageLeft.bottomAnchor, constant: 0), + ]) + } + + open func commonUIRight() { + contentLabelRight.translatesAutoresizingMaskIntoConstraints = false + contentLabelRight.isEnabled = false + contentLabelRight.numberOfLines = 0 + contentLabelRight.isUserInteractionEnabled = false + contentLabelRight.font = NEKitChatConfig.shared.ui.messageTextSize + contentLabelRight.textAlignment = .center + contentLabelRight.backgroundColor = .clear + bubbleImageRight.addSubview(contentLabelRight) + NSLayoutConstraint.activate([ + contentLabelRight.rightAnchor.constraint(equalTo: bubbleImageRight.rightAnchor, constant: -chat_content_margin), + contentLabelRight.leftAnchor.constraint(equalTo: bubbleImageRight.leftAnchor, constant: chat_content_margin), + contentLabelRight.topAnchor.constraint(equalTo: bubbleImageRight.topAnchor, constant: 0), + contentLabelRight.bottomAnchor.constraint(equalTo: bubbleImageRight.bottomAnchor, constant: 0), + ]) + + activityView.removeFromSuperview() + } + + override open func showLeftOrRight(showRight: Bool) { + super.showLeftOrRight(showRight: showRight) + contentLabelLeft.isHidden = showRight + contentLabelRight.isHidden = !showRight + } + + override open func setModel(_ model: MessageContentModel) { + super.setModel(model) + if let m = model as? MessageCallRecordModel { + if let isSend = model.message?.isOutgoingMsg, isSend { + contentLabelRight.attributedText = m.attributeStr + return + } + contentLabelLeft.attributedText = m.attributeStr + } + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageFileCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageFileCell.swift new file mode 100644 index 00000000..24e4971c --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageFileCell.swift @@ -0,0 +1,297 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonKit +import NIMSDK + +@objcMembers +open class ChatMessageFileCell: NormalChatMessageBaseCell { + weak var weakModel: MessageFileModel? + + public lazy var imgViewLeft: UIImageView = { + let view_img = UIImageView() + view_img.translatesAutoresizingMaskIntoConstraints = false + view_img.backgroundColor = .clear + return view_img + }() + + public lazy var stateViewLeft: FileStateView = { + let state = FileStateView() + state.translatesAutoresizingMaskIntoConstraints = false + state.backgroundColor = .clear + return state + }() + + public lazy var titleLabelLeft: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.isUserInteractionEnabled = false + label.numberOfLines = 1 + label.lineBreakMode = .byTruncatingMiddle + label.font = DefaultTextFont(14) + label.textAlignment = .left + return label + }() + + public lazy var sizeLabelLeft: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = UIColor(hexString: "#999999") + label.font = NEConstant.defaultTextFont(10.0) + label.textAlignment = .left + return label + }() + + public lazy var labelViewLeft: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.isUserInteractionEnabled = false + view.addSubview(titleLabelLeft) + NSLayoutConstraint.activate([ + titleLabelLeft.leftAnchor.constraint(equalTo: view.leftAnchor), + titleLabelLeft.topAnchor.constraint(equalTo: view.topAnchor), + titleLabelLeft.rightAnchor.constraint(equalTo: view.rightAnchor), + titleLabelLeft.heightAnchor.constraint(equalToConstant: 18), + ]) + view.addSubview(sizeLabelLeft) + NSLayoutConstraint.activate([ + sizeLabelLeft.leftAnchor.constraint(equalTo: view.leftAnchor), + sizeLabelLeft.topAnchor.constraint(equalTo: titleLabelLeft.bottomAnchor, constant: 5), + sizeLabelLeft.rightAnchor.constraint(equalTo: view.rightAnchor), + sizeLabelLeft.heightAnchor.constraint(equalToConstant: 10), + ]) + return view + }() + + public lazy var imgViewRight: UIImageView = { + let view_img = UIImageView() + view_img.translatesAutoresizingMaskIntoConstraints = false + view_img.backgroundColor = .clear + return view_img + }() + + public lazy var stateViewRight: FileStateView = { + let state = FileStateView() + state.translatesAutoresizingMaskIntoConstraints = false + state.backgroundColor = .clear + return state + }() + + public lazy var titleLabelRight: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.isUserInteractionEnabled = false + label.numberOfLines = 1 + label.lineBreakMode = .byTruncatingMiddle + label.font = DefaultTextFont(14) + label.textAlignment = .left + return label + }() + + public lazy var sizeLabelRight: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = UIColor(hexString: "#999999") + label.font = NEConstant.defaultTextFont(10.0) + label.textAlignment = .left + return label + }() + + public lazy var labelViewRight: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.isUserInteractionEnabled = false + view.addSubview(titleLabelRight) + NSLayoutConstraint.activate([ + titleLabelRight.leftAnchor.constraint(equalTo: view.leftAnchor), + titleLabelRight.topAnchor.constraint(equalTo: view.topAnchor), + titleLabelRight.rightAnchor.constraint(equalTo: view.rightAnchor), + titleLabelRight.heightAnchor.constraint(equalToConstant: 18), + ]) + view.addSubview(sizeLabelRight) + NSLayoutConstraint.activate([ + sizeLabelRight.leftAnchor.constraint(equalTo: view.leftAnchor), + sizeLabelRight.topAnchor.constraint(equalTo: titleLabelRight.bottomAnchor, constant: 5), + sizeLabelRight.rightAnchor.constraint(equalTo: view.rightAnchor), + sizeLabelRight.heightAnchor.constraint(equalToConstant: 10), + ]) + return view + }() + + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + setupUI() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func setupUI() { + setupUIRight() + setupUILeft() + } + + open func setupUILeft() { + bubbleImageLeft.image = nil + bubbleImageLeft.backgroundColor = .white + bubbleImageLeft.layer.cornerRadius = 8 + bubbleImageLeft.layer.borderColor = UIColor.ne_borderColor.cgColor + bubbleImageLeft.layer.borderWidth = 1 + + bubbleImageLeft.addSubview(imgViewLeft) + NSLayoutConstraint.activate([ + imgViewLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor, constant: 10), + imgViewLeft.centerYAnchor.constraint(equalTo: bubbleImageLeft.centerYAnchor), + imgViewLeft.widthAnchor.constraint(equalToConstant: 32), + imgViewLeft.heightAnchor.constraint(equalToConstant: 32), + ]) + + contentView.addSubview(stateViewLeft) + NSLayoutConstraint.activate([ + stateViewLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor, constant: 10), + stateViewLeft.topAnchor.constraint(equalTo: bubbleImageLeft.topAnchor, constant: 10), + stateViewLeft.widthAnchor.constraint(equalToConstant: 32), + stateViewLeft.heightAnchor.constraint(equalToConstant: 32), + ]) + + bubbleImageLeft.addSubview(labelViewLeft) + NSLayoutConstraint.activate([ + labelViewLeft.leftAnchor.constraint(equalTo: imgViewLeft.rightAnchor, constant: 15), + labelViewLeft.topAnchor.constraint(equalTo: bubbleImageLeft.topAnchor, constant: 10), + labelViewLeft.rightAnchor.constraint(equalTo: bubbleImageLeft.rightAnchor, constant: -10), + labelViewLeft.bottomAnchor.constraint(equalTo: bubbleImageLeft.bottomAnchor, constant: 0), + ]) + } + + open func setupUIRight() { + bubbleImageRight.image = nil + bubbleImageRight.backgroundColor = .white + bubbleImageRight.layer.cornerRadius = 8 + bubbleImageRight.layer.borderColor = UIColor.ne_borderColor.cgColor + bubbleImageRight.layer.borderWidth = 1 + + bubbleImageRight.addSubview(imgViewRight) + NSLayoutConstraint.activate([ + imgViewRight.leftAnchor.constraint(equalTo: bubbleImageRight.leftAnchor, constant: 10), + imgViewRight.centerYAnchor.constraint(equalTo: bubbleImageRight.centerYAnchor), + imgViewRight.widthAnchor.constraint(equalToConstant: 32), + imgViewRight.heightAnchor.constraint(equalToConstant: 32), + ]) + + contentView.addSubview(stateViewRight) + NSLayoutConstraint.activate([ + stateViewRight.leftAnchor.constraint(equalTo: bubbleImageRight.leftAnchor, constant: 10), + stateViewRight.topAnchor.constraint(equalTo: bubbleImageRight.topAnchor, constant: 10), + stateViewRight.widthAnchor.constraint(equalToConstant: 32), + stateViewRight.heightAnchor.constraint(equalToConstant: 32), + ]) + + bubbleImageRight.addSubview(labelViewRight) + NSLayoutConstraint.activate([ + labelViewRight.leftAnchor.constraint(equalTo: imgViewRight.rightAnchor, constant: 15), + labelViewRight.topAnchor.constraint(equalTo: bubbleImageRight.topAnchor, constant: 10), + labelViewRight.rightAnchor.constraint(equalTo: bubbleImageRight.rightAnchor, constant: -10), + labelViewRight.bottomAnchor.constraint(equalTo: bubbleImageRight.bottomAnchor, constant: 0), + ]) + } + + override open func showLeftOrRight(showRight: Bool) { + super.showLeftOrRight(showRight: showRight) + imgViewLeft.isHidden = showRight + stateViewLeft.isHidden = showRight + labelViewLeft.isHidden = showRight + + imgViewRight.isHidden = !showRight + stateViewRight.isHidden = !showRight + labelViewRight.isHidden = !showRight + } + + override open func setModel(_ model: MessageContentModel) { + super.setModel(model) + guard let isSend = model.message?.isOutgoingMsg else { + return + } + let stateView = isSend ? stateViewRight : stateViewLeft + let imgView = isSend ? imgViewRight : imgViewLeft + let titleLabel = isSend ? titleLabelRight : titleLabelLeft + let sizeLabel = isSend ? sizeLabelRight : sizeLabelLeft + let bubbleW = isSend ? bubbleWRight : bubbleWLeft + + bubbleW?.constant = kScreenWidth <= 320 ? 222 : 242 // 适配小屏幕 + + if let fileObject = model.message?.messageObject as? NIMFileObject { + if let fileModel = model as? MessageFileModel { + weakModel?.cell = nil + weakModel = fileModel + fileModel.cell = self + fileModel.size = Float(fileObject.fileLength) + if fileModel.state == .Success { + stateView.state = .FileOpen + } else { + stateView.state = .FileDownload + stateView.setProgress(fileModel.progress) + if fileModel.progress >= 1 { + fileModel.state = .Success + } + } + } + var imageName = "file_unknown" + var displayName = "未知文件" + if let filePath = fileObject.path as? NSString { + displayName = filePath.lastPathComponent + switch filePath.pathExtension.lowercased() { + case file_doc_support: + imageName = "file_doc" + case file_xls_support: + imageName = "file_xls" + case file_img_support: + imageName = "file_img" + case file_ppt_support: + imageName = "file_ppt" + case file_txt_support: + imageName = "file_txt" + case file_audio_support: + imageName = "file_audio" + case file_vedio_support: + imageName = "file_vedio" + case file_zip_support: + imageName = "file_zip" + case file_pdf_support: + imageName = "file_pdf" + case file_html_support: + imageName = "file_html" + case "key", "keynote": + imageName = "file_keynote" + default: + imageName = "file_unknown" + } + } + imgView.image = UIImage.ne_imageNamed(name: imageName) + titleLabel.text = fileObject.displayName ?? displayName + let size_B = Double(fileObject.fileLength) + var size_str = String(format: "%.1f B", size_B) + if size_B > 1e3 { + let size_KB = size_B / 1e3 + size_str = String(format: "%.1f KB", size_KB) + if size_KB > 1e3 { + let size_MB = size_KB / 1e3 + size_str = String(format: "%.1f MB", size_MB) + if size_MB > 1e3 { + let size_GB = size_KB / 1e6 + size_str = String(format: "%.1f GB", size_GB) + } + } + } + sizeLabel.text = size_str + } + } + + override open func uploadProgress(byRight: Bool, _ progress: Float) { + let stateView = byRight ? stateViewRight : stateViewLeft + stateView.setProgress(progress) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageImageCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageImageCell.swift new file mode 100644 index 00000000..63dacc68 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageImageCell.swift @@ -0,0 +1,99 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class ChatMessageImageCell: NormalChatMessageBaseCell { + public let contentImageViewLeft = UIImageView() + public let contentImageViewRight = UIImageView() + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + commonUI() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func commonUI() { + commonUIRight() + commonUILeft() + } + + open func commonUILeft() { + contentImageViewLeft.translatesAutoresizingMaskIntoConstraints = false + contentImageViewLeft.contentMode = .scaleAspectFill + contentImageViewLeft.clipsToBounds = true + contentImageViewLeft.addCustomCorner( + conrners: [.bottomLeft, .bottomRight, .topRight], + radius: 8, + backcolor: .white + ) + bubbleImageLeft.addSubview(contentImageViewLeft) + NSLayoutConstraint.activate([ + contentImageViewLeft.rightAnchor.constraint(equalTo: bubbleImageLeft.rightAnchor, constant: 0), + contentImageViewLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor, constant: 0), + contentImageViewLeft.topAnchor.constraint(equalTo: bubbleImageLeft.topAnchor, constant: 0), + contentImageViewLeft.bottomAnchor.constraint( + equalTo: bubbleImageLeft.bottomAnchor, + constant: 0 + ), + ]) + } + + open func commonUIRight() { + contentImageViewRight.translatesAutoresizingMaskIntoConstraints = false + contentImageViewRight.contentMode = .scaleAspectFill + contentImageViewRight.addCustomCorner( + conrners: [.topLeft, .bottomLeft, .bottomRight], + radius: 8, + backcolor: .white + ) + contentImageViewRight.clipsToBounds = true + + bubbleImageRight.addSubview(contentImageViewRight) + NSLayoutConstraint.activate([ + contentImageViewRight.rightAnchor.constraint(equalTo: bubbleImageRight.rightAnchor, constant: 0), + contentImageViewRight.leftAnchor.constraint(equalTo: bubbleImageRight.leftAnchor, constant: 0), + contentImageViewRight.topAnchor.constraint(equalTo: bubbleImageRight.topAnchor, constant: 0), + contentImageViewRight.bottomAnchor.constraint( + equalTo: bubbleImageRight.bottomAnchor, + constant: 0 + ), + ]) + } + + override open func showLeftOrRight(showRight: Bool) { + super.showLeftOrRight(showRight: showRight) + contentImageViewLeft.isHidden = showRight + contentImageViewRight.isHidden = !showRight + } + + override open func setModel(_ model: MessageContentModel) { + super.setModel(model) + guard let isSend = model.message?.isOutgoingMsg else { + return + } + let contentImageView = isSend ? contentImageViewRight : contentImageViewLeft + + if let m = model as? MessageImageModel, let imageUrl = m.imageUrl { + if imageUrl.hasPrefix("http") { + contentImageView.sd_setImage( + with: URL(string: imageUrl), + placeholderImage: nil, + options: .retryFailed, + progress: nil, + completed: nil + ) + } else { + contentImageView.image = UIImage(contentsOfFile: imageUrl) + } + } else { + contentImageView.image = nil + } + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageLocationCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageLocationCell.swift new file mode 100644 index 00000000..dcd1f9fe --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageLocationCell.swift @@ -0,0 +1,245 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NEChatKit + +@objcMembers +open class ChatMessageLocationCell: NormalChatMessageBaseCell { + public lazy var titleLabelLeft: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = UIColor.ne_darkText + label.font = UIFont.systemFont(ofSize: 16.0) + return label + }() + + public lazy var subTitleLabelLeft: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = UIColor.ne_lightText + label.font = UIFont.systemFont(ofSize: 12.0) + return label + }() + + public lazy var emptyLabelLeft: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.font = UIFont.systemFont(ofSize: 16) + label.text = chatLocalizable("no_map_plugin") + label.textAlignment = .center + label.textColor = UIColor.ne_greyText + return label + }() + + public var mapViewLeft: UIView? + let backgroundViewLeft = UIView() + + // Right + public lazy var titleLabelRight: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = UIColor.ne_darkText + label.font = UIFont.systemFont(ofSize: 16.0) + return label + }() + + public lazy var subTitleLabelRight: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = UIColor.ne_lightText + label.font = UIFont.systemFont(ofSize: 12.0) + return label + }() + + public lazy var emptyLabelRight: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.font = UIFont.systemFont(ofSize: 16) + label.text = chatLocalizable("no_map_plugin") + label.textAlignment = .center + label.textColor = UIColor.ne_greyText + return label + }() + + public var mapViewRight: UIView? + let backgroundViewRight = UIView() + + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + commonUI() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func commonUI() { + commonUIRight() + commonUILeft() + } + + open func commonUILeft() { + backgroundViewLeft.backgroundColor = UIColor.white + contentView.addSubview(backgroundViewLeft) + bubbleImageLeft.isHidden = true + backgroundViewLeft.translatesAutoresizingMaskIntoConstraints = false + backgroundViewLeft.clipsToBounds = true + backgroundViewLeft.layer.cornerRadius = 4 + backgroundViewLeft.layer.borderWidth = 1 + backgroundViewLeft.layer.borderColor = UIColor.ne_outlineColor.cgColor + + let messageLongPress = UILongPressGestureRecognizer( + target: self, + action: #selector(longPress) + ) + + backgroundViewLeft.addGestureRecognizer(messageLongPress) + NSLayoutConstraint.activate([ + backgroundViewLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor), + backgroundViewLeft.topAnchor.constraint(equalTo: bubbleImageLeft.topAnchor), + backgroundViewLeft.rightAnchor.constraint(equalTo: bubbleImageLeft.rightAnchor), + backgroundViewLeft.bottomAnchor.constraint(equalTo: bubbleImageLeft.bottomAnchor), + ]) + + let messageTap = UITapGestureRecognizer(target: self, action: #selector(tapMessage)) + backgroundViewLeft.addGestureRecognizer(messageTap) + + backgroundViewLeft.addSubview(titleLabelLeft) + NSLayoutConstraint.activate([ + titleLabelLeft.leftAnchor.constraint(equalTo: backgroundViewLeft.leftAnchor, constant: 16), + titleLabelLeft.rightAnchor.constraint(equalTo: backgroundViewLeft.rightAnchor, constant: -16), + titleLabelLeft.topAnchor.constraint(equalTo: backgroundViewLeft.topAnchor, constant: 10), + ]) + + backgroundViewLeft.addSubview(subTitleLabelLeft) + NSLayoutConstraint.activate([ + subTitleLabelLeft.leftAnchor.constraint(equalTo: titleLabelLeft.leftAnchor), + subTitleLabelLeft.rightAnchor.constraint(equalTo: titleLabelLeft.rightAnchor), + subTitleLabelLeft.topAnchor.constraint(equalTo: titleLabelLeft.bottomAnchor, constant: 4), + ]) + + if let map = NEChatKitClient.instance.delegate?.getCellMapView?() as? UIView { + mapViewLeft = map + backgroundViewLeft.addSubview(map) + map.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + map.leftAnchor.constraint(equalTo: backgroundViewLeft.leftAnchor), + map.bottomAnchor.constraint(equalTo: backgroundViewLeft.bottomAnchor), + map.rightAnchor.constraint(equalTo: backgroundViewLeft.rightAnchor), + map.topAnchor.constraint(equalTo: subTitleLabelLeft.bottomAnchor, constant: 4), + ]) + + let pointImage = UIImageView() + pointImage.translatesAutoresizingMaskIntoConstraints = false + pointImage.image = coreLoader.loadImage("location_point") + map.addSubview(pointImage) + NSLayoutConstraint.activate([ + pointImage.centerXAnchor.constraint(equalTo: map.centerXAnchor), + pointImage.bottomAnchor.constraint(equalTo: map.bottomAnchor, constant: -30), + ]) + } else { + backgroundViewLeft.addSubview(emptyLabelLeft) + NSLayoutConstraint.activate([ + emptyLabelLeft.leftAnchor.constraint(equalTo: backgroundViewLeft.leftAnchor), + emptyLabelLeft.rightAnchor.constraint(equalTo: backgroundViewLeft.rightAnchor), + emptyLabelLeft.bottomAnchor.constraint(equalTo: backgroundViewLeft.bottomAnchor, constant: -40), + ]) + } + } + + open func commonUIRight() { + backgroundViewRight.backgroundColor = UIColor.white + contentView.addSubview(backgroundViewRight) + bubbleImageRight.isHidden = true + backgroundViewRight.translatesAutoresizingMaskIntoConstraints = false + backgroundViewRight.clipsToBounds = true + backgroundViewRight.layer.cornerRadius = 4 + backgroundViewRight.layer.borderWidth = 1 + backgroundViewRight.layer.borderColor = UIColor.ne_outlineColor.cgColor + let messageLongPress = UILongPressGestureRecognizer( + target: self, + action: #selector(longPress) + ) + + backgroundViewRight.addGestureRecognizer(messageLongPress) + NSLayoutConstraint.activate([ + backgroundViewRight.leftAnchor.constraint(equalTo: bubbleImageRight.leftAnchor), + backgroundViewRight.topAnchor.constraint(equalTo: bubbleImageRight.topAnchor), + backgroundViewRight.rightAnchor.constraint(equalTo: bubbleImageRight.rightAnchor), + backgroundViewRight.bottomAnchor.constraint(equalTo: bubbleImageRight.bottomAnchor), + ]) + let messageTap = UITapGestureRecognizer(target: self, action: #selector(tapMessage)) + backgroundViewRight.addGestureRecognizer(messageTap) + + backgroundViewRight.addSubview(titleLabelRight) + NSLayoutConstraint.activate([ + titleLabelRight.leftAnchor.constraint(equalTo: backgroundViewRight.leftAnchor, constant: 16), + titleLabelRight.rightAnchor.constraint(equalTo: backgroundViewRight.rightAnchor, constant: -16), + titleLabelRight.topAnchor.constraint(equalTo: backgroundViewRight.topAnchor, constant: 10), + ]) + + backgroundViewRight.addSubview(subTitleLabelRight) + NSLayoutConstraint.activate([ + subTitleLabelRight.leftAnchor.constraint(equalTo: titleLabelRight.leftAnchor), + subTitleLabelRight.rightAnchor.constraint(equalTo: titleLabelRight.rightAnchor), + subTitleLabelRight.topAnchor.constraint(equalTo: titleLabelRight.bottomAnchor, constant: 4), + ]) + + if let map = NEChatKitClient.instance.delegate?.getCellMapView?() as? UIView { + mapViewRight = map + backgroundViewRight.addSubview(map) + map.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + map.leftAnchor.constraint(equalTo: backgroundViewRight.leftAnchor), + map.bottomAnchor.constraint(equalTo: backgroundViewRight.bottomAnchor), + map.rightAnchor.constraint(equalTo: backgroundViewRight.rightAnchor), + map.topAnchor.constraint(equalTo: subTitleLabelRight.bottomAnchor, constant: 4), + ]) + + let pointImage = UIImageView() + pointImage.translatesAutoresizingMaskIntoConstraints = false + pointImage.image = coreLoader.loadImage("location_point") + map.addSubview(pointImage) + NSLayoutConstraint.activate([ + pointImage.centerXAnchor.constraint(equalTo: map.centerXAnchor), + pointImage.bottomAnchor.constraint(equalTo: map.bottomAnchor, constant: -30), + ]) + } else { + backgroundViewRight.addSubview(emptyLabelRight) + NSLayoutConstraint.activate([ + emptyLabelRight.leftAnchor.constraint(equalTo: backgroundViewRight.leftAnchor), + emptyLabelRight.rightAnchor.constraint(equalTo: backgroundViewRight.rightAnchor), + emptyLabelRight.bottomAnchor.constraint(equalTo: backgroundViewRight.bottomAnchor, constant: -40), + ]) + } + } + + override open func showLeftOrRight(showRight: Bool) { + super.showLeftOrRight(showRight: showRight) + backgroundViewLeft.isHidden = showRight + backgroundViewRight.isHidden = !showRight + } + + override open func setModel(_ model: MessageContentModel) { + super.setModel(model) + guard let isSend = model.message?.isOutgoingMsg else { + return + } + let titleLabel = isSend ? titleLabelRight : titleLabelLeft + let subTitleLabel = isSend ? subTitleLabelRight : subTitleLabelLeft + let mapView = isSend ? mapViewRight : mapViewLeft + let bubbleW = isSend ? bubbleWRight : bubbleWLeft + + bubbleW?.constant = kScreenWidth <= 320 ? 222 : 242 // 适配小屏幕 + + if let m = model as? MessageLocationModel { + titleLabel.text = m.title + subTitleLabel.text = m.subTitle + if let lat = m.lat, let lng = m.lng, let map = mapView { + NEChatKitClient.instance.delegate?.setMapviewLocation?(lat: lat, lng: lng, mapview: map) + } + } + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageReplyCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageReplyCell.swift new file mode 100644 index 00000000..c70c7d6b --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageReplyCell.swift @@ -0,0 +1,107 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class ChatMessageReplyCell: ChatMessageTextCell { + public lazy var replyLabelLeft: UILabel = { + let replyLabel = UILabel() + replyLabel.font = UIFont.systemFont(ofSize: 13) + replyLabel.textColor = UIColor(hexString: "#929299") + replyLabel.textAlignment = .justified + replyLabel.translatesAutoresizingMaskIntoConstraints = false + return replyLabel + }() + + public lazy var replyLabelRight: UILabel = { + let replyLabel = UILabel() + replyLabel.font = UIFont.systemFont(ofSize: 13) + replyLabel.textColor = UIColor(hexString: "#929299") + replyLabel.textAlignment = .justified + replyLabel.translatesAutoresizingMaskIntoConstraints = false + return replyLabel + }() + + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + commonUI() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func commonUI() { + commonUIRight() + commonUILeft() + } + + open func commonUILeft() { + bubbleImageLeft.addSubview(replyLabelLeft) + NSLayoutConstraint.activate([ + replyLabelLeft.leadingAnchor.constraint(equalTo: bubbleImageLeft.leadingAnchor, constant: chat_content_margin), + replyLabelLeft.topAnchor.constraint(equalTo: bubbleImageLeft.topAnchor, constant: chat_content_margin), + replyLabelLeft.heightAnchor.constraint(equalToConstant: 16.0), + replyLabelLeft.trailingAnchor.constraint(equalTo: bubbleImageLeft.trailingAnchor, constant: -chat_content_margin), + ]) + + bubbleImageLeft.addSubview(contentLabelLeft) + NSLayoutConstraint.activate([ + contentLabelLeft.rightAnchor.constraint(equalTo: bubbleImageLeft.rightAnchor, constant: -chat_content_margin), + contentLabelLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor, constant: chat_content_margin), + contentLabelLeft.topAnchor.constraint(equalTo: replyLabelLeft.bottomAnchor, constant: chat_content_margin), + contentLabelLeft.bottomAnchor.constraint(equalTo: bubbleImageLeft.bottomAnchor, constant: -chat_content_margin), + ]) + } + + open func commonUIRight() { + bubbleImageRight.addSubview(replyLabelRight) + NSLayoutConstraint.activate([ + replyLabelRight.leadingAnchor.constraint(equalTo: bubbleImageRight.leadingAnchor, constant: chat_content_margin), + replyLabelRight.topAnchor.constraint(equalTo: bubbleImageRight.topAnchor, constant: chat_content_margin), + replyLabelRight.heightAnchor.constraint(equalToConstant: 16.0), + replyLabelRight.trailingAnchor.constraint(equalTo: bubbleImageRight.trailingAnchor, constant: -chat_content_margin), + ]) + + bubbleImageRight.addSubview(contentLabelRight) + NSLayoutConstraint.activate([ + contentLabelRight.rightAnchor.constraint(equalTo: bubbleImageRight.rightAnchor, constant: -chat_content_margin), + contentLabelRight.leftAnchor.constraint(equalTo: bubbleImageRight.leftAnchor, constant: chat_content_margin), + contentLabelRight.topAnchor.constraint(equalTo: replyLabelRight.bottomAnchor, constant: chat_content_margin), + contentLabelRight.bottomAnchor.constraint(equalTo: bubbleImageRight.bottomAnchor, constant: -chat_content_margin), + ]) + } + + override open func showLeftOrRight(showRight: Bool) { + super.showLeftOrRight(showRight: showRight) + replyLabelLeft.isHidden = showRight + replyLabelRight.isHidden = !showRight + } + + override open func setModel(_ model: MessageContentModel) { + guard let isSend = model.message?.isOutgoingMsg else { + return + } + let replyLabel = isSend ? replyLabelRight : replyLabelLeft + + if let text = model.replyText, + let font = replyLabel.font { + replyLabel.attributedText = NEEmotionTool.getAttWithStr(str: text, + font: font, + color: replyLabel.textColor) + if let attriText = replyLabel.attributedText { + let textSize = NEChatUITool.getSizeWithAtt( + att: attriText, + font: font, + maxSize: CGSize(width: chat_text_maxW, height: CGFloat.greatestFiniteMagnitude) + ) + model.contentSize.width = max(textSize.width + chat_content_margin * 2, model.contentSize.width) + } + } + + super.setModel(model) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageRevokeCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageRevokeCell.swift new file mode 100644 index 00000000..2960f211 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageRevokeCell.swift @@ -0,0 +1,122 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +// protocol ChatRevokeRightCellDelegate: NEChatBaseCellDelegate { +// func onReeditMessage(_ cell: UITableViewCell, _ model: MessageContentModel?) +// } + +// typealias ReeditBlock = (_ cell: ChatRevokeRightCell, _ model: MessageContentModel?) -> () + +@objcMembers +open class ChatMessageRevokeCell: NormalChatMessageBaseCell { + public var revokeLabelLeft = UILabel() + public var revokeLabelRight = UILabel() + public var reeditButton = UIButton(type: .custom) + public var reeditButtonW: NSLayoutConstraint? +// public var reeditBlock: ReeditBlock? +// public override var delegate: NEChatBaseCellDelegate? + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + commonUI() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func commonUI() { + commonUIRight() + commonUILeft() + } + + open func commonUILeft() { + revokeLabelLeft.translatesAutoresizingMaskIntoConstraints = false + revokeLabelLeft.textColor = UIColor.ne_greyText + revokeLabelLeft.font = UIFont.systemFont(ofSize: 16.0) + bubbleImageLeft.addSubview(revokeLabelLeft) + NSLayoutConstraint.activate([ + revokeLabelLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor, constant: 16), + revokeLabelLeft.topAnchor.constraint(equalTo: bubbleImageLeft.topAnchor, constant: 0), + revokeLabelLeft.rightAnchor.constraint(equalTo: bubbleImageLeft.rightAnchor, constant: -16), + revokeLabelLeft.bottomAnchor.constraint(equalTo: bubbleImageLeft.bottomAnchor, constant: 0), + ]) + } + + open func commonUIRight() { + revokeLabelRight.translatesAutoresizingMaskIntoConstraints = false + revokeLabelRight.textColor = UIColor.ne_greyText + revokeLabelRight.font = UIFont.systemFont(ofSize: 16.0) + bubbleImageRight.addSubview(revokeLabelRight) + NSLayoutConstraint.activate([ + revokeLabelRight.leftAnchor.constraint(equalTo: bubbleImageRight.leftAnchor, constant: 16), + revokeLabelRight.widthAnchor.constraint(equalToConstant: 100), + revokeLabelRight.topAnchor.constraint(equalTo: bubbleImageRight.topAnchor, constant: 0), + revokeLabelRight.bottomAnchor.constraint(equalTo: bubbleImageRight.bottomAnchor, constant: 0), + ]) + + reeditButton.translatesAutoresizingMaskIntoConstraints = false + reeditButton.setImage(UIImage.ne_imageNamed(name: "right_arrow"), for: .normal) + reeditButton.titleLabel?.font = UIFont.systemFont(ofSize: 16.0) + reeditButton.setTitleColor(UIColor.ne_blueText, for: .normal) + reeditButton.titleEdgeInsets = UIEdgeInsets(top: 0, left: -30, bottom: 0, right: 0) + reeditButton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 70, bottom: 0, right: 0) + + bubbleImageRight.addSubview(reeditButton) + reeditButtonW = reeditButton.widthAnchor.constraint(equalToConstant: 86) + NSLayoutConstraint.activate([ + reeditButton.leftAnchor.constraint(equalTo: revokeLabelRight.rightAnchor, constant: 8), + reeditButtonW!, + reeditButton.topAnchor.constraint(equalTo: bubbleImageRight.topAnchor, constant: 0), + reeditButton.bottomAnchor.constraint(equalTo: bubbleImageRight.bottomAnchor, constant: 0), + ]) + reeditButton.addTarget(self, action: #selector(reeditEvent), for: .touchUpInside) + } + + override open func showLeftOrRight(showRight: Bool) { + super.showLeftOrRight(showRight: showRight) + revokeLabelLeft.isHidden = showRight + revokeLabelRight.isHidden = !showRight + seletedBtn.isHidden = true + pinLabelLeft.isHidden = true + pinImageLeft.isHidden = true + pinLabelRight.isHidden = true + pinImageRight.isHidden = true + } + + override open func setModel(_ model: MessageContentModel) { + if let time = model.message?.timestamp { + let date = Date() + let currentTime = date.timeIntervalSince1970 + if currentTime - time >= 60 * 2 { + model.timeOut = true + } + } + if let isSend = model.message?.isOutgoingMsg, isSend, model.isRevokedText == true, model.timeOut == false { + reeditButtonW?.constant = 86 + reeditButton.isHidden = false + model.contentSize = CGSize(width: 218, height: chat_min_h) + } else { + reeditButtonW?.constant = 0 + reeditButton.isHidden = true + model.contentSize = CGSize(width: 130, height: chat_min_h) + } + super.setModel(model) + + guard let isSend = model.message?.isOutgoingMsg else { + return + } + let revokeLabel = isSend ? revokeLabelRight : revokeLabelLeft + + revokeLabel.text = chatLocalizable("message_has_be_withdrawn") + reeditButton.setTitle(chatLocalizable("message_reedit"), for: .normal) + } + + func reeditEvent(button: UIButton) { + print(#function) + delegate?.didTapReeditButton(self, contentModel) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageTextCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageTextCell.swift new file mode 100644 index 00000000..418b811c --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageTextCell.swift @@ -0,0 +1,78 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class ChatMessageTextCell: NormalChatMessageBaseCell { + public lazy var contentLabelLeft: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.isEnabled = false + label.numberOfLines = 0 + label.isUserInteractionEnabled = false + label.font = NEKitChatConfig.shared.ui.messageTextSize + label.backgroundColor = .clear + label.textAlignment = .justified + return label + }() + + public lazy var contentLabelRight: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.isEnabled = false + label.numberOfLines = 0 + label.isUserInteractionEnabled = false + label.font = NEKitChatConfig.shared.ui.messageTextSize + label.backgroundColor = .clear + label.textAlignment = .justified + return label + }() + + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + commonUI() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func commonUI() { + bubbleImageLeft.addSubview(contentLabelLeft) + NSLayoutConstraint.activate([ + contentLabelLeft.rightAnchor.constraint(equalTo: bubbleImageLeft.rightAnchor, constant: -chat_content_margin), + contentLabelLeft.leftAnchor.constraint(equalTo: bubbleImageLeft.leftAnchor, constant: chat_content_margin), + contentLabelLeft.topAnchor.constraint(equalTo: bubbleImageLeft.topAnchor, constant: chat_content_margin), + contentLabelLeft.bottomAnchor.constraint(equalTo: bubbleImageLeft.bottomAnchor, constant: -chat_content_margin), + ]) + + bubbleImageRight.addSubview(contentLabelRight) + NSLayoutConstraint.activate([ + contentLabelRight.rightAnchor.constraint(equalTo: bubbleImageRight.rightAnchor, constant: -chat_content_margin), + contentLabelRight.leftAnchor.constraint(equalTo: bubbleImageRight.leftAnchor, constant: chat_content_margin), + contentLabelRight.topAnchor.constraint(equalTo: bubbleImageRight.topAnchor, constant: chat_content_margin), + contentLabelRight.bottomAnchor.constraint(equalTo: bubbleImageRight.bottomAnchor, constant: -chat_content_margin), + ]) + } + + override open func showLeftOrRight(showRight: Bool) { + super.showLeftOrRight(showRight: showRight) + contentLabelLeft.isHidden = showRight + contentLabelRight.isHidden = !showRight + } + + override open func setModel(_ model: MessageContentModel) { + super.setModel(model) + guard let isSend = model.message?.isOutgoingMsg else { + return + } + let contentLabel = isSend ? contentLabelRight : contentLabelLeft + + if let m = model as? MessageTextModel { + contentLabel.attributedText = m.attributeStr + } + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageTipCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageTipCell.swift new file mode 100644 index 00000000..68dd8e83 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageTipCell.swift @@ -0,0 +1,9 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class ChatMessageTipCell: NEBaseChatMessageTipCell {} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageVideoCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageVideoCell.swift new file mode 100644 index 00000000..d482ebb8 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatMessageVideoCell.swift @@ -0,0 +1,183 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonKit +import NIMSDK + +@objcMembers +open class ChatMessageVideoCell: ChatMessageImageCell { + weak var weakModel: MessageVideoModel? + public lazy var stateViewLeft: VideoStateView = { + let state = VideoStateView() + state.translatesAutoresizingMaskIntoConstraints = false + state.backgroundColor = .clear + return state + }() + + public lazy var timeLabelLeft: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = .white + label.font = NEConstant.defaultTextFont(10.0) + label.textAlignment = .center + return label + }() + + public lazy var timeViewLeft: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(timeLabelLeft) + NSLayoutConstraint.activate([ + timeLabelLeft.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 4), + timeLabelLeft.topAnchor.constraint(equalTo: view.topAnchor, constant: 2), + timeLabelLeft.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -4), + timeLabelLeft.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -2), + ]) + view.clipsToBounds = true + view.layer.cornerRadius = 4.0 + view.backgroundColor = NEConstant.hexRGB(0x000000).withAlphaComponent(0.6) + return view + }() + + // Right + public lazy var stateViewRight: VideoStateView = { + let state = VideoStateView() + state.translatesAutoresizingMaskIntoConstraints = false + state.backgroundColor = .clear + return state + }() + + public lazy var timeLabelRight: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = .white + label.font = NEConstant.defaultTextFont(10.0) + label.textAlignment = .center + return label + }() + + public lazy var timeViewRight: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(timeLabelRight) + NSLayoutConstraint.activate([ + timeLabelRight.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 4), + timeLabelRight.topAnchor.constraint(equalTo: view.topAnchor, constant: 2), + timeLabelRight.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -4), + timeLabelRight.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -2), + ]) + view.clipsToBounds = true + view.layer.cornerRadius = 4.0 + view.backgroundColor = NEConstant.hexRGB(0x000000).withAlphaComponent(0.6) + return view + }() + + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + setupUI() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func setupUI() { + setupUIRight() + setupUILeft() + } + + open func setupUILeft() { + contentImageViewLeft.addSubview(stateViewLeft) + contentImageViewLeft.addCustomCorner(conrners: [.topLeft], radius: 8, backcolor: .white) + NSLayoutConstraint.activate([ + stateViewLeft.centerXAnchor.constraint(equalTo: contentImageViewLeft.centerXAnchor), + stateViewLeft.centerYAnchor.constraint(equalTo: contentImageViewLeft.centerYAnchor), + stateViewLeft.heightAnchor.constraint(equalToConstant: 60), + stateViewLeft.widthAnchor.constraint(equalToConstant: 60), + ]) + + contentImageViewLeft.addSubview(timeViewLeft) + NSLayoutConstraint.activate([ + timeViewLeft.rightAnchor.constraint(equalTo: contentImageViewLeft.rightAnchor, constant: -7), + timeViewLeft.bottomAnchor.constraint(equalTo: contentImageViewLeft.bottomAnchor, constant: -7), + ]) + } + + open func setupUIRight() { + contentImageViewRight.addSubview(stateViewRight) + contentImageViewRight.addCustomCorner(conrners: [.topRight], radius: 8, backcolor: .white) + NSLayoutConstraint.activate([ + stateViewRight.centerXAnchor.constraint(equalTo: contentImageViewRight.centerXAnchor), + stateViewRight.centerYAnchor.constraint(equalTo: contentImageViewRight.centerYAnchor), + stateViewRight.heightAnchor.constraint(equalToConstant: 60), + stateViewRight.widthAnchor.constraint(equalToConstant: 60), + ]) + + contentImageViewRight.addSubview(timeViewRight) + NSLayoutConstraint.activate([ + timeViewRight.rightAnchor.constraint(equalTo: contentImageViewRight.rightAnchor, constant: -7), + timeViewRight.bottomAnchor.constraint(equalTo: contentImageViewRight.bottomAnchor, constant: -7), + ]) + } + + override open func setModel(_ model: MessageContentModel) { + super.setModel(model) + guard let isSend = model.message?.isOutgoingMsg else { + return + } + let contentImageView = isSend ? contentImageViewRight : contentImageViewLeft + let timeView = isSend ? timeViewRight : timeViewLeft + let timeLabel = isSend ? timeLabelRight : timeLabelLeft + let stateView = isSend ? stateViewRight : stateViewLeft + + if let videoObject = model.message?.messageObject as? NIMVideoObject { + if let path = videoObject.coverPath, FileManager.default.fileExists(atPath: path) { + contentImageView.sd_setImage( + with: URL(fileURLWithPath: path), + placeholderImage: nil, + options: .retryFailed, + progress: nil, + completed: nil + ) + } else { + contentImageView.sd_setImage( + with: URL(string: videoObject.coverUrl ?? ""), + placeholderImage: nil, + options: .retryFailed, + progress: nil, + completed: nil + ) + } + + if videoObject.duration > 0 { + timeView.isHidden = false + timeLabel.text = Date.getFormatPlayTime(TimeInterval(videoObject.duration / 1000)) + } else { + timeView.isHidden = true + } + + if let videoModel = model as? MessageVideoModel { + weakModel?.cell = nil + weakModel = videoModel + videoModel.cell = self + if videoModel.state == .Success { + stateView.state = .VideoPlay + } else { + stateView.state = .VideoDownload + stateView.setProgress(videoModel.progress) + if videoModel.progress >= 1 { + videoModel.state = .Success + } + } + } + } + } + + override open func uploadProgress(byRight: Bool, _ progress: Float) { + let stateView = byRight ? stateViewRight : stateViewLeft + stateView.setProgress(progress) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatTeamMemberCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatTeamMemberCell.swift new file mode 100644 index 00000000..985e7915 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/ChatTeamMemberCell.swift @@ -0,0 +1,30 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonUIKit +import NEChatKit + +@objcMembers +open class ChatTeamMemberCell: NEBaseChatTeamMemberCell { + override open func setupUI() { + super.setupUI() + + headerView.layer.cornerRadius = 21 + NSLayoutConstraint.activate([ + headerView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 21), + headerView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + headerView.widthAnchor.constraint(equalToConstant: 42), + headerView.heightAnchor.constraint(equalToConstant: 42), + ]) + + nameLabel.font = NEConstant.defaultTextFont(16.0) + NSLayoutConstraint.activate([ + nameLabel.leftAnchor.constraint(equalTo: headerView.rightAnchor, constant: 14.0), + nameLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + nameLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -70), + ]) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/NormalChatMessageBaseCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/NormalChatMessageBaseCell.swift new file mode 100644 index 00000000..1b6e44de --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/NormalChatMessageBaseCell.swift @@ -0,0 +1,8 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class NormalChatMessageBaseCell: NEBaseChatMessageCell {} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageAudioCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageAudioCell.swift new file mode 100644 index 00000000..57c8677e --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageAudioCell.swift @@ -0,0 +1,8 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class PinMessageAudioCell: NEBasePinMessageAudioCell {} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageDefaultCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageDefaultCell.swift new file mode 100644 index 00000000..4366a21f --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageDefaultCell.swift @@ -0,0 +1,8 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class PinMessageDefaultCell: NEBasePinMessageTextCell {} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageFileCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageFileCell.swift new file mode 100644 index 00000000..6bc41a1c --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageFileCell.swift @@ -0,0 +1,9 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class PinMessageFileCell: NEBasePinMessageFileCell {} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageImageCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageImageCell.swift new file mode 100644 index 00000000..b3477ff7 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageImageCell.swift @@ -0,0 +1,8 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class PinMessageImageCell: NEBasePinMessageImageCell {} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageLocationCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageLocationCell.swift new file mode 100644 index 00000000..285b57d3 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageLocationCell.swift @@ -0,0 +1,9 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NEChatKit + +@objcMembers +open class PinMessageLocationCell: NEBasePinMessageLocationCell {} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageTextCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageTextCell.swift new file mode 100644 index 00000000..96c3b646 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageTextCell.swift @@ -0,0 +1,8 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class PinMessageTextCell: NEBasePinMessageTextCell {} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageVideoCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageVideoCell.swift new file mode 100644 index 00000000..48c81dfb --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/PinCell/PinMessageVideoCell.swift @@ -0,0 +1,9 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class PinMessageVideoCell: NEBasePinMessageVideoCell {} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/UserSettingSelectCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/UserSettingSelectCell.swift new file mode 100644 index 00000000..796a974a --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/UserSettingSelectCell.swift @@ -0,0 +1,30 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class UserSettingSelectCell: NEBaseUserSettingSelectCell { + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + override open func setupUI() { + super.setupUI() + NSLayoutConstraint.activate([ + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 36), + titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16), + titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -84), + ]) + + NSLayoutConstraint.activate([ + arrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + arrow.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -36), + ]) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/UserSettingSwitchCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/UserSettingSwitchCell.swift new file mode 100644 index 00000000..5bdbf7b8 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/UserSettingSwitchCell.swift @@ -0,0 +1,31 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class UserSettingSwitchCell: NEBaseUserSettingSwitchCell { + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + override open func setupUI() { + super.setupUI() + NSLayoutConstraint.activate([ + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 36), + titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -84), + ]) + + NSLayoutConstraint.activate([ + tSwitch.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + tSwitch.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -36), + ]) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/UserTableViewCell.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/UserTableViewCell.swift new file mode 100644 index 00000000..2b42a23a --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Cell/UserTableViewCell.swift @@ -0,0 +1,36 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit + +@objcMembers +open class UserTableViewCell: UserBaseTableViewCell { + override open func baseCommonUI() { + super.baseCommonUI() + // avatar + avatarImage.layer.cornerRadius = 21 + NSLayoutConstraint.activate([ + avatarImage.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16), + avatarImage.widthAnchor.constraint(equalToConstant: 42), + avatarImage.heightAnchor.constraint(equalToConstant: 42), + avatarImage.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10), + ]) + + titleLabel.font = UIFont.systemFont(ofSize: 16) + titleLabel.textColor = UIColor( + red: 51 / 255.0, + green: 51 / 255.0, + blue: 51 / 255.0, + alpha: 1.0 + ) + NSLayoutConstraint.activate([ + titleLabel.leftAnchor.constraint(equalTo: avatarImage.rightAnchor, constant: 12), + titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -35), + titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor, constant: 0), + titleLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + ]) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/ForwardAlertViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/ForwardAlertViewController.swift new file mode 100644 index 00000000..2d433230 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/ForwardAlertViewController.swift @@ -0,0 +1,38 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonKit +import NECommonUIKit + +@objcMembers +public class ForwardUserCell: NEBaseForwardUserCell { + override func setupUI() { + super.setupUI() + userHeader.layer.cornerRadius = 16 + } +} + +@objcMembers +public class ForwardAlertViewController: NEBaseForwardAlertViewController { + override public func setupUI() { + super.setupUI() + oneUserHead.layer.cornerRadius = 16.0 + userCollection.register( + ForwardUserCell.self, + forCellWithReuseIdentifier: "\(ForwardUserCell.self)" + ) + } + + override public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + if let cell = collectionView.dequeueReusableCell( + withReuseIdentifier: "\(ForwardUserCell.self)", + for: indexPath + ) as? ForwardUserCell { + return setCellModel(cell: cell, indexPath: indexPath) + } + return UICollectionViewCell() + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/GroupChatViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/GroupChatViewController.swift similarity index 78% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/GroupChatViewController.swift rename to NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/GroupChatViewController.swift index f8ae7c81..faf1f650 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/GroupChatViewController.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/GroupChatViewController.swift @@ -8,12 +8,13 @@ import NIMSDK import NECoreIMKit @objcMembers -open class GroupChatViewController: ChatViewController, TeamChatViewModelDelegate { +open class GroupChatViewController: NormalChatViewController, TeamChatViewModelDelegate { private var isLeaveTeamBySelf = false // 是否是主动退出群聊 private var isdismissTeam = false // 群聊是否已解散 + private var onCurrentPage = false // 是否位于聊天详情页 public init(session: NIMSession, anchor: NIMMessage?) { -// self.viewmodel = ChatViewModel(session: session) + // self.viewmodel = ChatViewModel(session: session) super.init(session: session) viewmodel = TeamChatViewModel(session: session, anchor: anchor) viewmodel.delegate = self @@ -32,7 +33,7 @@ open class GroupChatViewController: ChatViewController, TeamChatViewModelDelegat override open func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - + onCurrentPage = true // 被动解散群聊 if isdismissTeam { weak var weakSelf = self @@ -42,6 +43,11 @@ open class GroupChatViewController: ChatViewController, TeamChatViewModelDelegat } } + override open func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + onCurrentPage = false + } + override open func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(leaveTeamBySelf), name: NotificationName.leaveTeamBySelf, object: nil) @@ -55,7 +61,7 @@ open class GroupChatViewController: ChatViewController, TeamChatViewModelDelegat } } -// MARK: private method + // MARK: private method func leaveTeamBySelf(noti: Notification) { if let flag = noti.object as? Bool { @@ -74,23 +80,25 @@ open class GroupChatViewController: ChatViewController, TeamChatViewModelDelegat return attribute } - private func updateTeamInfo(team: NIMTeam) { + open func updateTeamInfo(team: NIMTeam) { title = team.getShowName() if team.inAllMuteMode(), team.owner != NIMSDK.shared().loginManager.currentAccount() { menuView.textView.isEditable = false menuView.textView.attributedPlaceholder = getPlaceHolder(text: chatLocalizable("team_mute")) + menuView.textView.backgroundColor = UIColor(hexString: "#E3E4E4") layoutInputView(offset: 0) menuView.stackView.isUserInteractionEnabled = false } else { menuView.textView.isEditable = true menuView.textView.attributedPlaceholder = getPlaceHolder(text: "\(chatLocalizable("send_to"))\(team.getShowName())") + menuView.textView.backgroundColor = .white menuView.stackView.isUserInteractionEnabled = true } } -// MARK: TeamChatViewModelDelegate + // MARK: TeamChatViewModelDelegate - public func onTeamRemoved(team: NIMTeam) { + open func onTeamRemoved(team: NIMTeam) { // 退出讨论组 if team.clientCustomInfo?.contains(discussTeamKey) == true { navigationController?.popViewController(animated: true) @@ -104,6 +112,13 @@ open class GroupChatViewController: ChatViewController, TeamChatViewModelDelegat navigationController?.popViewController(animated: true) } else { isdismissTeam = true + // 被动解散群聊 + if onCurrentPage { + weak var weakSelf = self + showSingleAlert(message: chatLocalizable("team_has_been_removed")) { + weakSelf?.navigationController?.popViewController(animated: true) + } + } } } else { // 主动解散 navigationController?.popViewController(animated: true) @@ -111,7 +126,7 @@ open class GroupChatViewController: ChatViewController, TeamChatViewModelDelegat } } - public func onTeamUpdate(team: NIMTeam) { + open func onTeamUpdate(team: NIMTeam) { if team.teamId != viewmodel.session.sessionId { return } @@ -119,6 +134,6 @@ open class GroupChatViewController: ChatViewController, TeamChatViewModelDelegat } public func onTeamMemberUpdate(team: NIMTeam) { - tableView.reloadData() + didRefreshTable() } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/NormalChatViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/NormalChatViewController.swift new file mode 100644 index 00000000..8d014315 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/NormalChatViewController.swift @@ -0,0 +1,91 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class NormalChatViewController: ChatViewController { + override public init(session: NIMSession) { + super.init(session: session) + customNavigationView.backgroundColor = .white + navigationController?.navigationBar.backgroundColor = .white + registerCellDic = [ + "\(MessageType.text.rawValue)": ChatMessageTextCell.self, + "\(MessageType.rtcCallRecord.rawValue)": ChatMessageCallCell.self, + "\(MessageType.audio.rawValue)": ChatMessageAudioCell.self, + "\(MessageType.image.rawValue)": ChatMessageImageCell.self, + "\(MessageType.revoke.rawValue)": ChatMessageRevokeCell.self, + "\(MessageType.video.rawValue)": ChatMessageVideoCell.self, + "\(MessageType.file.rawValue)": ChatMessageFileCell.self, + "\(MessageType.reply.rawValue)": ChatMessageReplyCell.self, + "\(MessageType.location.rawValue)": ChatMessageLocationCell.self, + "\(MessageType.time.rawValue)": ChatMessageTipCell.self, + ] + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func viewDidLoad() { + super.viewDidLoad() + } + + override open func getMenuView() -> NEBaseChatInputView { + ChatInputView() + } + + override open func getForwardAlertController() -> NEBaseForwardAlertViewController { + ForwardAlertViewController() + } + + override func getUserSelectVC() -> NEBaseSelectUserViewController { + SelectUserViewController(sessionId: viewmodel.session.sessionId, showSelf: false) + } + + override open func toSetting() { + if let block = NEKitChatConfig.shared.ui.titleBarRightClick { + block() + return + } + if viewmodel.session.sessionType == .team { + Router.shared.use( + TeamSettingViewRouter, + parameters: ["nav": navigationController as Any, + "teamid": viewmodel.session.sessionId], + closure: nil + ) + } else if viewmodel.session.sessionType == .P2P { + let userSetting = UserSettingViewController() + userSetting.userId = viewmodel.session.sessionId + navigationController?.pushViewController(userSetting, animated: true) + } + } + + override open func didLongTouchMessageView(_ cell: UITableViewCell, _ model: MessageContentModel?) { + super.didLongTouchMessageView(cell, model) + operationView?.layer.cornerRadius = 8 + operationView?.layer.borderColor = UIColor.ne_darkText.cgColor + operationView?.layer.borderWidth = 0.2 + } + + override open func didTapReadView(_ cell: UITableViewCell, _ model: MessageContentModel?) { + if let msg = model?.message, msg.session?.sessionType == .team { + let readVC = ReadViewController(message: msg) + navigationController?.pushViewController(readVC, animated: true) + } + } + + public func getMessageModel(model: MessageModel) { + if model.type == .reply { + let normalMoreHeight = chat_reply_height + chat_content_margin + model.contentSize = CGSize( + width: model.contentSize.width, + height: model.contentSize.height + normalMoreHeight + ) + model.height += Float(normalMoreHeight) + } + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/P2PChatViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/P2PChatViewController.swift similarity index 88% rename from NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/P2PChatViewController.swift rename to NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/P2PChatViewController.swift index dd74862f..5e1bff6e 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/Chat/Controller/P2PChatViewController.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/P2PChatViewController.swift @@ -7,7 +7,7 @@ import UIKit import NIMSDK @objcMembers -open class P2PChatViewController: ChatViewController { +open class P2PChatViewController: NormalChatViewController { public init(session: NIMSession, anchor: NIMMessage?) { super.init(session: session) viewmodel = ChatViewModel(session: session, anchor: anchor) @@ -24,8 +24,6 @@ open class P2PChatViewController: ChatViewController { let showName = user?.showName() ?? "" title = showName titleContent = showName -// menuView.textField.placeholder = chatLocalizable("send_to") + showName -// menuView.textField.placeholder = (chatLocalizable("send_to") + showName) as NSString? let text = "\(chatLocalizable("send_to"))\(showName)" let attribute = NSMutableAttributedString(string: text) let style = NSMutableParagraphStyle() diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/PinMessageViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/PinMessageViewController.swift new file mode 100644 index 00000000..1b97e1eb --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/PinMessageViewController.swift @@ -0,0 +1,33 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class PinMessageViewController: NEBasePinMessageViewController { + override public func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .ne_lightBackgroundColor + customNavigationView.backgroundColor = .ne_lightBackgroundColor + navigationController?.navigationBar.backgroundColor = .ne_lightBackgroundColor + } + + override open func getRegisterCellDic() -> [Int: NEBasePinMessageCell.Type] { + let cellClassDic = [ + NIMMessageType.text.rawValue: PinMessageTextCell.self, + NIMMessageType.image.rawValue: PinMessageImageCell.self, + NIMMessageType.audio.rawValue: PinMessageAudioCell.self, + NIMMessageType.video.rawValue: PinMessageVideoCell.self, + NIMMessageType.location.rawValue: PinMessageLocationCell.self, + NIMMessageType.file.rawValue: PinMessageFileCell.self, + PinMessageDefaultType: PinMessageDefaultCell.self, + ] + return cellClassDic + } + + override open func getForwardAlertController() -> NEBaseForwardAlertViewController { + ForwardAlertViewController() + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/ReadViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/ReadViewController.swift new file mode 100644 index 00000000..2091e680 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/ReadViewController.swift @@ -0,0 +1,35 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK +import NECoreIMKit +import NECommonUIKit + +@objcMembers +open class ReadViewController: NEBaseReadViewController { + override init(message: NIMMessage) { + super.init(message: message) + customNavigationView.backgroundColor = .white + navigationController?.navigationBar.backgroundColor = .white + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override public func commonUI() { + super.commonUI() + customNavigationView.bottomLine.isHidden = false + readButton.setTitleColor(UIColor.ne_darkText, for: .normal) + line.backgroundColor = UIColor.ne_blueText + + readTableView.register( + UserTableViewCell.self, + forCellReuseIdentifier: "\(UserTableViewCell.self)" + ) + readTableView.rowHeight = 62 + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/SelectUserViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/SelectUserViewController.swift new file mode 100644 index 00000000..35257338 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/SelectUserViewController.swift @@ -0,0 +1,47 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NEChatKit +import NECoreIMKit + +@objcMembers +open class SelectUserViewController: NEBaseSelectUserViewController { + override init(sessionId: String, showSelf: Bool = true) { + super.init(sessionId: sessionId, showSelf: showSelf) + className = "SelectUserViewController" + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func commonUI() { + super.commonUI() + + tableView.register( + ChatTeamMemberCell.self, + forCellReuseIdentifier: "\(ChatTeamMemberCell.self)" + ) + tableView.rowHeight = 62 + } + + override open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell( + withIdentifier: "\(ChatTeamMemberCell.self)", + for: indexPath + ) as! ChatTeamMemberCell + if indexPath.row == 0 { + cell.headerView.image = UIImage.ne_imageNamed(name: "chat_team") + cell.nameLabel.text = chatLocalizable("user_select_all") + } else { + if let model = teamInfo?.users[indexPath.row - 1] { + cell.configure(model) + } + } + return cell + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/UserSettingViewController.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/UserSettingViewController.swift new file mode 100644 index 00000000..0044488e --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/Controller/UserSettingViewController.swift @@ -0,0 +1,34 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonKit +import NIMSDK + +@objcMembers +open class UserSettingViewController: NEBaseUserSettingViewController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + customNavigationView.backgroundColor = .white + navigationController?.navigationBar.backgroundColor = .white + cellClassDic = [ + UserSettingType.SwitchType.rawValue: UserSettingSwitchCell.self, + UserSettingType.SelectType.rawValue: UserSettingSelectCell.self, + ] + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func setupUI() { + super.setupUI() + userHeader.layer.cornerRadius = 21.0 + } + + override func getPinMessageViewController(session: NIMSession) -> NEBasePinMessageViewController { + PinMessageViewController(session: session) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/ChatRouter/ChatRouter.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/NormalChatRouter.swift similarity index 77% rename from NEChatUIKit/NEChatUIKit/Classes/ChatRouter/ChatRouter.swift rename to NEChatUIKit/NEChatUIKit/Classes/NormalUI/NormalChatRouter.swift index 06e089ae..69c6a80c 100644 --- a/NEChatUIKit/NEChatUIKit/Classes/ChatRouter/ChatRouter.swift +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/NormalChatRouter.swift @@ -3,16 +3,10 @@ // Use of this source code is governed by a MIT license that can be // found in the LICENSE file. -import Foundation import NIMSDK -import NECommonKit -import SDWebImage -import SDWebImageWebPCoder -import SDWebImageSVGKitPlugin -@objcMembers -public class ChatRouter: NSObject { - public static func register() { +public extension ChatRouter { + static func register() { // pin Router.shared.register(PushPinMessageVCRouter) { param in let nav = param["nav"] as? UINavigationController @@ -48,7 +42,7 @@ public class ChatRouter: NSObject { let anchor = param["anchor"] as? NIMMessage var p2pChatVC = P2PChatViewController(session: session, anchor: anchor) for (i, vc) in (nav?.viewControllers ?? []).enumerated() { - if vc.isMember(of: P2PChatViewController.self) { + if vc.isKind(of: ChatViewController.self) { nav?.viewControllers[i] = p2pChatVC nav?.popToViewController(p2pChatVC, animated: true) return @@ -68,7 +62,7 @@ public class ChatRouter: NSObject { let anchor = param["anchor"] as? NIMMessage let groupVC = GroupChatViewController(session: session, anchor: anchor) for (i, vc) in (nav?.viewControllers ?? []).enumerated() { - if vc.isMember(of: GroupChatViewController.self) { + if vc.isKind(of: ChatViewController.self) { nav?.viewControllers[i] = groupVC nav?.popToViewController(groupVC, animated: true) return @@ -77,13 +71,4 @@ public class ChatRouter: NSObject { nav?.pushViewController(groupVC, animated: true) } } - - public static func setupInit() { - NIMKitFileLocationHelper.setStaticAppkey(NIMSDK.shared().appKey()) - NIMKitFileLocationHelper.setStaticUserId(NIMSDK.shared().loginManager.currentAccount()) - let webpCoder = SDImageWebPCoder() - SDImageCodersManager.shared.addCoder(webpCoder) - let svgCoder = SDImageSVGKCoder.shared - SDImageCodersManager.shared.addCoder(svgCoder) - } } diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/NormalChatUIColor.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/NormalChatUIColor.swift new file mode 100644 index 00000000..307d5f9e --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/NormalChatUIColor.swift @@ -0,0 +1,10 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import NECommonKit + +public extension UIColor { + static let normalChatInputBg = UIColor(hexString: "#EFF1F3") +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/NormalUI/View/ChatInpuView.swift b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/View/ChatInpuView.swift new file mode 100644 index 00000000..54ad16a9 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/NormalUI/View/ChatInpuView.swift @@ -0,0 +1,84 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation + +@objcMembers +open class ChatInputView: NEBaseChatInputView { + override public func commonUI() { + backgroundColor = UIColor.normalChatInputBg + addSubview(textView) + textView.delegate = self + textviewLeftConstraint = textView.leftAnchor.constraint(equalTo: leftAnchor, constant: 7) + textviewRightConstraint = textView.rightAnchor.constraint(equalTo: rightAnchor, constant: -7) + NSLayoutConstraint.activate([ + textviewLeftConstraint!, + textviewRightConstraint!, + textView.topAnchor.constraint(equalTo: topAnchor, constant: 6), + textView.heightAnchor.constraint(equalToConstant: 40), + ]) + textInput = textView + + let imageNames = ["mic", "emoji", "photo", "add"] + let imageNamesSelected = ["mic_selected", "emoji_selected", "photo", "add_selected"] + + var items = [UIButton]() + for i in 0 ... 3 { + let button = UIButton(type: .custom) + button.setImage(UIImage.ne_imageNamed(name: imageNames[i]), for: .normal) + button.setImage(UIImage.ne_imageNamed(name: imageNamesSelected[i]), for: .selected) + button.translatesAutoresizingMaskIntoConstraints = false + button.addTarget(self, action: #selector(buttonEvent), for: .touchUpInside) + button.tag = i + 5 + items.append(button) + } + + stackView = UIStackView(arrangedSubviews: items) + stackView.translatesAutoresizingMaskIntoConstraints = false + stackView.distribution = .fillEqually + addSubview(stackView) + NSLayoutConstraint.activate([ + stackView.leftAnchor.constraint(equalTo: leftAnchor), + stackView.rightAnchor.constraint(equalTo: rightAnchor), + stackView.heightAnchor.constraint(equalToConstant: 54), + stackView.topAnchor.constraint(equalTo: textView.bottomAnchor, constant: 0), + ]) + + greyView.translatesAutoresizingMaskIntoConstraints = false + greyView.backgroundColor = UIColor(hexString: "#EFF1F3") + greyView.isHidden = true + addSubview(greyView) + NSLayoutConstraint.activate([ + greyView.leftAnchor.constraint(equalTo: leftAnchor, constant: 0), + greyView.topAnchor.constraint(equalTo: topAnchor, constant: 0), + greyView.rightAnchor.constraint(equalTo: rightAnchor, constant: 0), + greyView.heightAnchor.constraint(equalToConstant: 100), + ]) + + addSubview(contentView) + contentView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + contentView.leftAnchor.constraint(equalTo: leftAnchor), + contentView.rightAnchor.constraint(equalTo: rightAnchor), + contentView.heightAnchor.constraint(equalToConstant: contentHeight), + contentView.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 0), + ]) + + recordView.isHidden = true + recordView.translatesAutoresizingMaskIntoConstraints = false + recordView.delegate = self + recordView.backgroundColor = UIColor.ne_backgroundColor + contentView.addSubview(recordView) + NSLayoutConstraint.activate([ + recordView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 0), + recordView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: 0), + recordView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0), + recordView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0), + ]) + + contentView.addSubview(emojiView) + + contentView.addSubview(chatAddMoreView) + } +} diff --git a/NEChatUIKit/NEChatUIKit/Classes/Protocol/ChatInputViewDelegate.swift b/NEChatUIKit/NEChatUIKit/Classes/Protocol/ChatInputViewDelegate.swift new file mode 100644 index 00000000..fcaa46a4 --- /dev/null +++ b/NEChatUIKit/NEChatUIKit/Classes/Protocol/ChatInputViewDelegate.swift @@ -0,0 +1,23 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation + +@objc +public protocol ChatInputViewDelegate: NSObjectProtocol { + func sendText(text: String?, attribute: NSAttributedString?) + func willSelectItem(button: UIButton?, index: Int) + func didSelectMoreCell(cell: NEInputMoreCell) + + @discardableResult + func textChanged(text: String) -> Bool + func textDelete(range: NSRange, text: String) -> Bool + func startRecord() + func moveOutView() + func moveInView() + func endRecord(insideView: Bool) + func textFieldDidChange(_ textField: UITextView) + func textFieldDidEndEditing(_ textField: UITextView) + func textFieldDidBeginEditing(_ textField: UITextView) +} diff --git a/NEContactUIKit/NEContactUIKit.podspec b/NEContactUIKit/NEContactUIKit.podspec index 2b829ef0..87599377 100644 --- a/NEContactUIKit/NEContactUIKit.podspec +++ b/NEContactUIKit/NEContactUIKit.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'NEContactUIKit' - s.version = '9.5.0' + s.version = '9.6.0' s.summary = 'Netease XKit' # This description is used to generate tags and improve search results. @@ -27,13 +27,12 @@ Pod::Spec.new do |s| 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64', 'BUILD_LIBRARY_FOR_DISTRIBUTION' => 'YES' } - s.ios.deployment_target = '9.0' + s.ios.deployment_target = '10.0' s.swift_version = '5.0' s.source_files = 'NEContactUIKit/Classes/**/*' s.resource = 'NEContactUIKit/Assets/**/*' - s.dependency 'NEContactKit' + s.dependency 'NEChatKit' s.dependency 'NECommonUIKit' - s.dependency 'YXAlog' end diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/Contents.json similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funAdd.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funAdd.imageset/Contents.json new file mode 100644 index 00000000..6133208c --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funAdd.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "funAdd@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "funAdd@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funAdd.imageset/funAdd@2x.png b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funAdd.imageset/funAdd@2x.png new file mode 100644 index 00000000..fa611a32 Binary files /dev/null and b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funAdd.imageset/funAdd@2x.png differ diff --git a/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funAdd.imageset/funAdd@3x.png b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funAdd.imageset/funAdd@3x.png new file mode 100644 index 00000000..36d84662 Binary files /dev/null and b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funAdd.imageset/funAdd@3x.png differ diff --git a/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funBlackName.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funBlackName.imageset/Contents.json new file mode 100644 index 00000000..bebc8b23 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funBlackName.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "FunBlackName@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "FunBlackName@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funBlackName.imageset/FunBlackName@2x.png b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funBlackName.imageset/FunBlackName@2x.png new file mode 100644 index 00000000..c5d96ec5 Binary files /dev/null and b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funBlackName.imageset/FunBlackName@2x.png differ diff --git a/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funBlackName.imageset/FunBlackName@3x.png b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funBlackName.imageset/FunBlackName@3x.png new file mode 100644 index 00000000..aedd29c3 Binary files /dev/null and b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funBlackName.imageset/FunBlackName@3x.png differ diff --git a/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funGroup.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funGroup.imageset/Contents.json new file mode 100644 index 00000000..7481d90b --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funGroup.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "FunGroup@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "FunGroup@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funGroup.imageset/FunGroup@2x.png b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funGroup.imageset/FunGroup@2x.png new file mode 100644 index 00000000..21e2ac83 Binary files /dev/null and b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funGroup.imageset/FunGroup@2x.png differ diff --git a/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funGroup.imageset/FunGroup@3x.png b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funGroup.imageset/FunGroup@3x.png new file mode 100644 index 00000000..51d5eb0f Binary files /dev/null and b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funGroup.imageset/FunGroup@3x.png differ diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/search.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funSearch.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/search.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funSearch.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funSearch.imageset/search@2x.png b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funSearch.imageset/search@2x.png new file mode 100644 index 00000000..e2ce7a50 Binary files /dev/null and b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funSearch.imageset/search@2x.png differ diff --git a/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funSearch.imageset/search@3x.png b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funSearch.imageset/search@3x.png new file mode 100644 index 00000000..36a33195 Binary files /dev/null and b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funSearch.imageset/search@3x.png differ diff --git a/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funValid.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funValid.imageset/Contents.json new file mode 100644 index 00000000..5ce7168b --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funValid.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "funValid@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "funValid@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funValid.imageset/funValid@2x.png b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funValid.imageset/funValid@2x.png new file mode 100644 index 00000000..e66d6a3e Binary files /dev/null and b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funValid.imageset/funValid@2x.png differ diff --git a/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funValid.imageset/funValid@3x.png b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funValid.imageset/funValid@3x.png new file mode 100644 index 00000000..7075444a Binary files /dev/null and b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/funValid.imageset/funValid@3x.png differ diff --git a/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/fun_select.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/fun_select.imageset/Contents.json new file mode 100644 index 00000000..ea2e4827 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/fun_select.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "clicked_we@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "clicked_we@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/fun_select.imageset/clicked_we@2x.png b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/fun_select.imageset/clicked_we@2x.png new file mode 100644 index 00000000..f69ac913 Binary files /dev/null and b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/fun_select.imageset/clicked_we@2x.png differ diff --git a/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/fun_select.imageset/clicked_we@3x.png b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/fun_select.imageset/clicked_we@3x.png new file mode 100644 index 00000000..75777604 Binary files /dev/null and b/NEContactUIKit/NEContactUIKit/Assets/FunContactUIKit.xcassets/fun_select.imageset/clicked_we@3x.png differ diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/add.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/add.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/add.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/add.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/add.imageset/add@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/add.imageset/add@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/add.imageset/add@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/add.imageset/add@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/add.imageset/add@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/add.imageset/add@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/add.imageset/add@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/add.imageset/add@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/addBlack.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/addBlack.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/addBlack.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/addBlack.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/addBlack.imageset/Group 367@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/addBlack.imageset/Group 367@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/addBlack.imageset/Group 367@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/addBlack.imageset/Group 367@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/addBlack.imageset/Group 367@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/addBlack.imageset/Group 367@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/addBlack.imageset/Group 367@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/addBlack.imageset/Group 367@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/arrowRight.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/arrowRight.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/arrowRight.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/arrowRight.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/arrowRight.imageset/Vector 87@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/arrowRight.imageset/Vector 87@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/arrowRight.imageset/Vector 87@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/arrowRight.imageset/Vector 87@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/arrowRight.imageset/Vector 87@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/arrowRight.imageset/Vector 87@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/arrowRight.imageset/Vector 87@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/arrowRight.imageset/Vector 87@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/backArrow.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/backArrow.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/backArrow.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/backArrow.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/backArrow.imageset/back@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/backArrow.imageset/back@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/backArrow.imageset/back@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/backArrow.imageset/back@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/backArrow.imageset/back@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/backArrow.imageset/back@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/backArrow.imageset/back@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/backArrow.imageset/back@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/blackName.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/blackName.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/blackName.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/blackName.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/blackName.imageset/blackName@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/blackName.imageset/blackName@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/blackName.imageset/blackName@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/blackName.imageset/blackName@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/blackName.imageset/blackName@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/blackName.imageset/blackName@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/blackName.imageset/blackName@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/blackName.imageset/blackName@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/contact_search.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/contact_search.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/contact_search.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/contact_search.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/contact_search.imageset/contact_search@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/contact_search.imageset/contact_search@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/contact_search.imageset/contact_search@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/contact_search.imageset/contact_search@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/contact_search.imageset/contact_search@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/contact_search.imageset/contact_search@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/contact_search.imageset/contact_search@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/contact_search.imageset/contact_search@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/finishFlag.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/finishFlag.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/finishFlag.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/finishFlag.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/finishFlag.imageset/grayRight@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/finishFlag.imageset/grayRight@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/finishFlag.imageset/grayRight@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/finishFlag.imageset/grayRight@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/finishFlag.imageset/grayRight@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/finishFlag.imageset/grayRight@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/finishFlag.imageset/grayRight@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/finishFlag.imageset/grayRight@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/group.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/group.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/group.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/group.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/group.imageset/group@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/group.imageset/group@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/group.imageset/group@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/group.imageset/group@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/group.imageset/group@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/group.imageset/group@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/group.imageset/group@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/group.imageset/group@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/myComputer.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/myComputer.imageset/Contents.json new file mode 100644 index 00000000..5c4d3b18 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/myComputer.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/myComputer.imageset/Frame@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/myComputer.imageset/Frame@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/myComputer.imageset/Frame@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/myComputer.imageset/Frame@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/myComputer.imageset/Frame@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/myComputer.imageset/Frame@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/myComputer.imageset/Frame@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/myComputer.imageset/Frame@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/refused.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/refused.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/refused.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/refused.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/refused.imageset/refuse@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/refused.imageset/refuse@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/refused.imageset/refuse@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/refused.imageset/refuse@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/refused.imageset/refuse@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/refused.imageset/refuse@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/refused.imageset/refuse@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/refused.imageset/refuse@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/search.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/search.imageset/Contents.json new file mode 100644 index 00000000..4a62afc6 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/search.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "search@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "search@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/search.imageset/search@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/search.imageset/search@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/search.imageset/search@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/search.imageset/search@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/search.imageset/search@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/search.imageset/search@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/search.imageset/search@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/search.imageset/search@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/unselect.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/unselect.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/unselect.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/unselect.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/unselect.imageset/unselect@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/unselect.imageset/unselect@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/unselect.imageset/unselect@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/unselect.imageset/unselect@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/unselect.imageset/unslect@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/unselect.imageset/unslect@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/unselect.imageset/unslect@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/unselect.imageset/unslect@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/valid.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/valid.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/valid.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/valid.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/valid.imageset/valid@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/valid.imageset/valid@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/valid.imageset/valid@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/valid.imageset/valid@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/valid.imageset/valid@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/valid.imageset/valid@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/valid.imageset/valid@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NEBaseContactUIKit.xcassets/valid.imageset/valid@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/user_empty.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/user_empty.imageset/Contents.json deleted file mode 100644 index 68b5b589..00000000 --- a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/user_empty.imageset/Contents.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x" - }, - { - "filename" : "user_empty@2x.png", - "idiom" : "universal", - "scale" : "2x" - }, - { - "filename" : "user_empty@3x.png", - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/user_empty.imageset/user_empty@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/user_empty.imageset/user_empty@2x.png deleted file mode 100644 index 6fc940f0..00000000 Binary files a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/user_empty.imageset/user_empty@2x.png and /dev/null differ diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/user_empty.imageset/user_empty@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/user_empty.imageset/user_empty@3x.png deleted file mode 100644 index b4667dc3..00000000 Binary files a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/user_empty.imageset/user_empty@3x.png and /dev/null differ diff --git a/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/select.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/select.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/select.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/select.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/select.imageset/select@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/select.imageset/select@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/select.imageset/select@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/select.imageset/select@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/select.imageset/select@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/select.imageset/select@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/select.imageset/select@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/select.imageset/select@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_0.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_0.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_0.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_0.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_0.imageset/icon_1@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_0.imageset/icon_1@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_0.imageset/icon_1@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_0.imageset/icon_1@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_0.imageset/icon_1@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_0.imageset/icon_1@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_0.imageset/icon_1@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_0.imageset/icon_1@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_1.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_1.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_1.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_1.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_1.imageset/icon_2@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_1.imageset/icon_2@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_1.imageset/icon_2@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_1.imageset/icon_2@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_1.imageset/icon_2@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_1.imageset/icon_2@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_1.imageset/icon_2@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_1.imageset/icon_2@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_2.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_2.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_2.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_2.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_2.imageset/icon_3@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_2.imageset/icon_3@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_2.imageset/icon_3@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_2.imageset/icon_3@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_2.imageset/icon_3@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_2.imageset/icon_3@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_2.imageset/icon_3@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_2.imageset/icon_3@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_3.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_3.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_3.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_3.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_3.imageset/icon_4@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_3.imageset/icon_4@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_3.imageset/icon_4@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_3.imageset/icon_4@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_3.imageset/icon_4@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_3.imageset/icon_4@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_3.imageset/icon_4@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_3.imageset/icon_4@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_4.imageset/Contents.json b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_4.imageset/Contents.json similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_4.imageset/Contents.json rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_4.imageset/Contents.json diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_4.imageset/icon_5@2x.png b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_4.imageset/icon_5@2x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_4.imageset/icon_5@2x.png rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_4.imageset/icon_5@2x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_4.imageset/icon_5@3x.png b/NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_4.imageset/icon_5@3x.png similarity index 100% rename from NEContactUIKit/NEContactUIKit/Assets/NEKitContact.xcassets/team/icon_4.imageset/icon_5@3x.png rename to NEContactUIKit/NEContactUIKit/Assets/NormalContactUIKit.xcassets/team/icon_4.imageset/icon_5@3x.png diff --git a/NEContactUIKit/NEContactUIKit/Assets/en.lproj/Localizable.strings b/NEContactUIKit/NEContactUIKit/Assets/en.lproj/Localizable.strings index 0014116b..e441bef8 100644 --- a/NEContactUIKit/NEContactUIKit/Assets/en.lproj/Localizable.strings +++ b/NEContactUIKit/NEContactUIKit/Assets/en.lproj/Localizable.strings @@ -3,11 +3,14 @@ // Use of this source code is governed by a MIT license that can be // found in the LICENSE file. - +"contact"="Contact"; +"search"="Search"; "alert_tip"="tip"; "alert_sure"="ok"; "alert_cancel"="cancel"; +"close"="close"; +"nick"="Nick"; "account"="Account"; "noteName"="Nick Name"; "remove_black" = "Remove"; @@ -21,6 +24,7 @@ "email"="e-mail"; "sign"="What's Up"; "delete_friend"="Delete Contact"; +"delete_title"="Delete \"XXX\" Contact"; "add_friend"="Add Contact"; "add_blackList"="block"; "send_friend_apply"="Contact request sent"; @@ -50,3 +54,6 @@ // error toast "validate_processed"="Already done on other devices"; "failed_operation"="Failed Operation"; +"network_error"="Network is not available, please check"; + +"black_tip"=" You won't receive message from this memberlist"; diff --git a/NEContactUIKit/NEContactUIKit/Assets/zh-Hans.lproj/Localizable.strings b/NEContactUIKit/NEContactUIKit/Assets/zh-Hans.lproj/Localizable.strings index c99cdea1..516c19ba 100644 --- a/NEContactUIKit/NEContactUIKit/Assets/zh-Hans.lproj/Localizable.strings +++ b/NEContactUIKit/NEContactUIKit/Assets/zh-Hans.lproj/Localizable.strings @@ -3,11 +3,14 @@ // Use of this source code is governed by a MIT license that can be // found in the LICENSE file. - +"contact"="通讯录"; +"search"="搜索"; "alert_tip"="提示"; "alert_sure"="确定"; "alert_cancel"="取消"; +"close"="关闭"; +"nick"="昵称"; "account"="账号"; "noteName"="备注名"; "remove_black" = "解除"; @@ -21,6 +24,7 @@ "email"="邮箱"; "sign"="个性签名"; "delete_friend"="删除好友"; +"delete_title"="将联系人\“XXX\”删除"; "add_friend"="添加好友"; "add_blackList"="加入黑名单"; "send_friend_apply"="好友申请已发送"; @@ -50,3 +54,6 @@ // error toast "validate_processed"="该验证消息已在其他端处理"; "failed_operation"="操作失败"; +"network_error"="当前网络不可用,请检查你的网络设置"; + +"black_tip"=" 你不会收到列表中任何联系人的消息"; diff --git a/NEContactUIKit/NEContactUIKit/Classes/Base/ContactBaseViewCell.swift b/NEContactUIKit/NEContactUIKit/Classes/Base/NEBaseContactViewCell.swift similarity index 87% rename from NEContactUIKit/NEContactUIKit/Classes/Base/ContactBaseViewCell.swift rename to NEContactUIKit/NEContactUIKit/Classes/Base/NEBaseContactViewCell.swift index 4420e381..2245ffd2 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Base/ContactBaseViewCell.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Base/NEBaseContactViewCell.swift @@ -6,7 +6,7 @@ import UIKit @objcMembers -open class ContactBaseViewCell: UITableViewCell { +open class NEBaseContactViewCell: UITableViewCell { public lazy var avatarImage: UIImageView = { let avatar = UIImageView() avatar.translatesAutoresizingMaskIntoConstraints = false @@ -87,20 +87,13 @@ open class ContactBaseViewCell: UITableViewCell { super.init(coder: coder) } - func setupCommonCircleHeader() { - avatarImage.layer.cornerRadius = 18 - avatarImage.translatesAutoresizingMaskIntoConstraints = false + open func setupCommonCircleHeader() { contentView.addSubview(avatarImage) leftConstraint = avatarImage.leftAnchor.constraint( equalTo: contentView.leftAnchor, constant: 20 ) leftConstraint?.isActive = true - NSLayoutConstraint.activate([ - avatarImage.widthAnchor.constraint(equalToConstant: 36), - avatarImage.heightAnchor.constraint(equalToConstant: 36), - avatarImage.centerYAnchor.constraint(equalTo: contentView.centerYAnchor, constant: 0), - ]) } func showNameOnCircleHeader(_ name: String) { diff --git a/NEContactUIKit/NEContactUIKit/Classes/NEKitContactUI.h b/NEContactUIKit/NEContactUIKit/Classes/Base/NEKitContactUI.h similarity index 100% rename from NEContactUIKit/NEContactUIKit/Classes/NEKitContactUI.h rename to NEContactUIKit/NEContactUIKit/Classes/Base/NEKitContactUI.h diff --git a/NEContactUIKit/NEContactUIKit/Classes/BlackList/Views/BlackListCell.swift b/NEContactUIKit/NEContactUIKit/Classes/BlackList/Cell/NEBaseBlackListCell.swift similarity index 82% rename from NEContactUIKit/NEContactUIKit/Classes/BlackList/Views/BlackListCell.swift rename to NEContactUIKit/NEContactUIKit/Classes/BlackList/Cell/NEBaseBlackListCell.swift index 5fc127e1..8d084099 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/BlackList/Views/BlackListCell.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/BlackList/Cell/NEBaseBlackListCell.swift @@ -1,4 +1,3 @@ - // Copyright (c) 2022 NetEase, Inc. All rights reserved. // Use of this source code is governed by a MIT license that can be // found in the LICENSE file. @@ -6,32 +5,29 @@ import UIKit import NECoreIMKit -protocol TeamTableViewCellDelegate: AnyObject { +@objc +protocol BlackListCellDelegate: AnyObject { func removeUser(account: String?, index: Int) } @objcMembers -class BlackListCell: TeamTableViewCell { - weak var delegate: TeamTableViewCellDelegate? +open class NEBaseBlackListCell: NEBaseTeamTableViewCell { + weak var delegate: BlackListCellDelegate? var index = 0 private var model: User? var button = UIButton() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) - commonUI() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func commonUI() { super.commonUI() - button.layer.borderWidth = 1 - button.layer.borderColor = UIColor(red: 0.2, green: 0.494, blue: 1, alpha: 1).cgColor button.layer.cornerRadius = 4 - button.setTitleColor(UIColor(red: 0.2, green: 0.494, blue: 1, alpha: 1), for: .normal) button.titleLabel?.font = UIFont.systemFont(ofSize: 14) button.translatesAutoresizingMaskIntoConstraints = false button.contentMode = .center @@ -54,7 +50,7 @@ class BlackListCell: TeamTableViewCell { bottomLine.heightAnchor.constraint(equalToConstant: 1), ]) - titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -80).isActive = true + contentView.updateLayoutConstraint(firstItem: titleLabel, seconedItem: contentView, attribute: .right, constant: -80) } func buttonEvent(sender: UIButton) { @@ -66,7 +62,7 @@ class BlackListCell: TeamTableViewCell { return } self.model = user - avatarImage.backgroundColor = UIColor.colorWithString(string: user.userId) + // title titleLabel.text = user.showName() @@ -74,9 +70,11 @@ class BlackListCell: TeamTableViewCell { if let imageUrl = user.userInfo?.avatarUrl { nameLabel.text = "" avatarImage.sd_setImage(with: URL(string: imageUrl), completed: nil) + avatarImage.backgroundColor = .clear } else { nameLabel.text = user.shortName(showAlias: false, count: 2) avatarImage.image = nil + avatarImage.backgroundColor = UIColor.colorWithString(string: user.userId) } } diff --git a/NEContactUIKit/NEContactUIKit/Classes/BlackList/ViewController/BlackListViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/BlackList/ViewController/NEBaseBlackListViewController.swift similarity index 62% rename from NEContactUIKit/NEContactUIKit/Classes/BlackList/ViewController/BlackListViewController.swift rename to NEContactUIKit/NEContactUIKit/Classes/BlackList/ViewController/NEBaseBlackListViewController.swift index 921a0cd1..c4d7f411 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/BlackList/ViewController/BlackListViewController.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/BlackList/ViewController/NEBaseBlackListViewController.swift @@ -9,21 +9,32 @@ import NECoreIMKit import NECommonKit @objcMembers -public class BlackListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, - TeamTableViewCellDelegate { +open class NEBaseBlackListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, + BlackListCellDelegate, UIGestureRecognizerDelegate { + public let customNavigationView = NENavigationView() var tableView = UITableView(frame: .zero, style: .plain) var viewModel = BlackListViewModel() public var blackList: [User]? - private let className = "BlackListViewController" + var className = "BlackListBaseViewController" override public func viewDidLoad() { super.viewDidLoad() + view.backgroundColor = .white + navigationController?.interactivePopGestureRecognizer?.delegate = self + if let useSystemNav = NEConfigManager.instance.getParameter(key: useSystemNav) as? Bool, useSystemNav { + navigationController?.isNavigationBarHidden = false + } else { + navigationController?.isNavigationBarHidden = true + } + + viewModel.delegate = self commonUI() loadData() } func commonUI() { title = localizable("blacklist") + customNavigationView.navTitle.text = title let image = UIImage.ne_imageNamed(name: "backArrow")?.withRenderingMode(.alwaysOriginal) navigationItem.leftBarButtonItem = UIBarButtonItem( image: image, @@ -39,27 +50,35 @@ public class BlackListViewController: UIViewController, UITableViewDelegate, UIT action: #selector(addBlack) ) + customNavigationView.translatesAutoresizingMaskIntoConstraints = false + customNavigationView.addBackButtonTarget(target: self, selector: #selector(backEvent)) + customNavigationView.setMoreButtonImage(UIImage.ne_imageNamed(name: "add")) + customNavigationView.addMoreButtonTarget(target: self, selector: #selector(addBlack)) + view.addSubview(customNavigationView) + NSLayoutConstraint.activate([ + customNavigationView.leftAnchor.constraint(equalTo: view.leftAnchor), + customNavigationView.rightAnchor.constraint(equalTo: view.rightAnchor), + customNavigationView.topAnchor.constraint(equalTo: view.topAnchor), + customNavigationView.heightAnchor.constraint(equalToConstant: NEConstant.navigationAndStatusHeight), + ]) + tableView.separatorStyle = .none tableView.delegate = self tableView.dataSource = self tableView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(tableView) NSLayoutConstraint.activate([ - tableView.topAnchor.constraint(equalTo: view.topAnchor), + tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: NEConstant.navigationAndStatusHeight), tableView.leftAnchor.constraint(equalTo: view.leftAnchor), tableView.rightAnchor.constraint(equalTo: view.rightAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) - tableView.register( - BlackListCell.self, - forCellReuseIdentifier: "\(NSStringFromClass(TeamTableViewCell.self))" - ) - tableView.rowHeight = 62 + let headView = UIView(frame: CGRect(x: 0, y: 0, width: Int(NEConstant.screenWidth), height: 40)) let contentLabel = UILabel(frame: CGRect(x: 20, y: 0, width: Int(NEConstant.screenWidth) - 20, height: 40)) - contentLabel.text = " 你不会收到列表中任何联系人的消息" + contentLabel.text = localizable("black_tip") contentLabel.textColor = UIColor.ne_emptyTitleColor contentLabel.font = UIFont.systemFont(ofSize: 14) headView.addSubview(contentLabel) @@ -77,22 +96,19 @@ public class BlackListViewController: UIViewController, UITableViewDelegate, UIT public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell( - withIdentifier: "\(NSStringFromClass(TeamTableViewCell.self))", - for: indexPath - ) as! BlackListCell - cell.delegate = self - cell.index = indexPath.row - cell.setModel(blackList?[indexPath.row] as Any) - return cell + UITableViewCell() } func backEvent() { navigationController?.popViewController(animated: true) } + open func getContactSelectVC() -> NEBaseContactsSelectedViewController { + NEBaseContactsSelectedViewController() + } + func addBlack() { - let contactSelectVC = ContactsSelectedViewController() + let contactSelectVC = getContactSelectVC() navigationController?.pushViewController(contactSelectVC, animated: true) contactSelectVC.callBack = { [weak self] selectMemberarray in var users = [User]() @@ -120,16 +136,21 @@ public class BlackListViewController: UIViewController, UITableViewDelegate, UIT num -= 1 if num == 0 { print("add black finished") - self?.blackList?.append(contentsOf: suc) - self?.tableView.reloadData() + self?.loadData() } } } } - // MARK: TeamTableViewCellDelegate + // MARK: BlackListCellDelegate func removeUser(account: String?, index: Int) { + weak var weakSelf = self + if NEChatDetectNetworkTool.shareInstance.manager?.isReachable == false { + weakSelf?.showToast(commonLocalizable("network_error")) + return + } + guard let acc = account else { return } @@ -148,3 +169,15 @@ public class BlackListViewController: UIViewController, UITableViewDelegate, UIT } } } + +// MARK: FriendProviderDelegate + +extension NEBaseBlackListViewController: FriendProviderDelegate { + public func onFriendChanged(user: NECoreIMKit.User) {} + + public func onUserInfoChanged(user: NECoreIMKit.User) {} + + public func onBlackListChanged() { + loadData() + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/BlackList/ViewModel/BlackListViewModel.swift b/NEContactUIKit/NEContactUIKit/Classes/BlackList/ViewModel/BlackListViewModel.swift index 8012ce70..8fe019cb 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/BlackList/ViewModel/BlackListViewModel.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/BlackList/ViewModel/BlackListViewModel.swift @@ -3,13 +3,14 @@ // found in the LICENSE file. import Foundation -import NEContactKit +import NEChatKit import NECoreKit import NECoreIMKit @objcMembers public class BlackListViewModel: NSObject, FriendProviderDelegate { var contactRepo = ContactRepo() + public weak var delegate: FriendProviderDelegate? private let className = "BlackListViewModel" override init() { @@ -37,17 +38,17 @@ public class BlackListViewModel: NSObject, FriendProviderDelegate { public func onFriendChanged(user: User) { NELog.infoLog(ModuleName + " " + className, desc: #function + ", userId:\(user.userId ?? "nil")") - print(#file + #function) + delegate?.onFriendChanged(user: user) } public func onUserInfoChanged(user: User) { NELog.infoLog(ModuleName + " " + className, desc: #function + ", userId:\(user.userId ?? "nil")") - print(#file + #function) + delegate?.onUserInfoChanged(user: user) } public func onBlackListChanged() { NELog.infoLog(ModuleName + " " + className, desc: #function) - print(#file + #function) + delegate?.onBlackListChanged() } public func onRecieveNotification(notification: XNotification) { diff --git a/NEContactUIKit/NEContactUIKit/Classes/Common/ContactCellDataProtrol.swift b/NEContactUIKit/NEContactUIKit/Classes/Common/ContactCellDataProtrol.swift index 0e7df70a..5160ed6e 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Common/ContactCellDataProtrol.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Common/ContactCellDataProtrol.swift @@ -6,6 +6,7 @@ import Foundation import UIKit +@objc public protocol ContactCellDataProtrol: NSObjectProtocol { func setModel(_ model: ContactInfo) } diff --git a/NEContactUIKit/NEContactUIKit/Classes/Common/ContactConst.swift b/NEContactUIKit/NEContactUIKit/Classes/Common/ContactConst.swift index f3f4530c..f11b86fc 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Common/ContactConst.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Common/ContactConst.swift @@ -7,18 +7,19 @@ import Foundation import CoreText import NECoreKit +@objc public enum ContactCellType: Int { case ContactOthers = 1 // blacklist groups computer and so on case ContactPerson = 2 // contact person case ContactCutom = 50 // custom type start with 50 } -public typealias ConttactClickCallBack = (_ index: Int, _ section: Int?) +public typealias ContactClickCallBack = (_ index: Int, _ section: Int?) -> Void // parameter type contain ContactCellType and custom type public typealias ContactsSelectCompletion = ([ContactInfo]) -> Void? -let coreLoader = CoreLoader() +let coreLoader = CoreLoader() func localizable(_ key: String) -> String { coreLoader.localizable(key) } diff --git a/NEContactUIKit/NEContactUIKit/Classes/Common/NEBaseContactRouter.swift b/NEContactUIKit/NEContactUIKit/Classes/Common/NEBaseContactRouter.swift new file mode 100644 index 00000000..5987373f --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/Common/NEBaseContactRouter.swift @@ -0,0 +1,12 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import NECoreKit +import NECoreIMKit +import NIMSDK + +@objcMembers +public class ContactRouter: NSObject {} diff --git a/NEContactUIKit/NEContactUIKit/Classes/ContactConfig/ContactUIConfig.swift b/NEContactUIKit/NEContactUIKit/Classes/ContactConfig/ContactUIConfig.swift index c4c2ff62..0ebefc87 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/ContactConfig/ContactUIConfig.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/ContactConfig/ContactUIConfig.swift @@ -16,10 +16,10 @@ public class ContactUIConfig: NSObject { public var avatarCornerRadius = 4.0 /// 头像类型 - public var avatarType: NEContactAvatarType = .cycle + public var avatarType: NEContactAvatarType? // 通讯录标题大小 - public var titleFont = UIFont.systemFont(ofSize: 14) + public var titleFont: UIFont? /// 通讯录标题颜色 public var titleColor = UIColor.ne_darkText @@ -34,5 +34,5 @@ public class ContactUIConfig: NSObject { public var divideLineColor = UIColor.ne_borderColor /// 检索标题字体颜色 - public var indexTitleColor = UIColor.ne_emptyTitleColor + public var indexTitleColor: UIColor? } diff --git a/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunBlackListCell.swift b/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunBlackListCell.swift new file mode 100644 index 00000000..3f96e17b --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunBlackListCell.swift @@ -0,0 +1,36 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit + +@objcMembers +class FunBlackListCell: NEBaseBlackListCell { + private lazy var bottomLine: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = .funContactLineBorderColor + return view + }() + + override func commonUI() { + super.commonUI() + button.layer.borderColor = UIColor(hexString: "#D9D9D9").cgColor + button.setTitleColor(.ne_darkText, for: .normal) + + avatarImage.layer.cornerRadius = 4 + avatarImage.updateLayoutConstraint(firstItem: avatarImage, seconedItem: nil, attribute: .width, constant: 40) + avatarImage.updateLayoutConstraint(firstItem: avatarImage, seconedItem: nil, attribute: .height, constant: 40) + + titleLabel.textColor = .ne_darkText + + contentView.addSubview(bottomLine) + NSLayoutConstraint.activate([ + bottomLine.leftAnchor.constraint(equalTo: avatarImage.leftAnchor), + bottomLine.rightAnchor.constraint(equalTo: contentView.rightAnchor), + bottomLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + bottomLine.heightAnchor.constraint(equalToConstant: 1), + ]) + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunContactSelectedCell.swift b/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunContactSelectedCell.swift new file mode 100644 index 00000000..8b8f9d5a --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunContactSelectedCell.swift @@ -0,0 +1,49 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FunContactSelectedCell: NEBaseContactSelectedCell { + override open func setupCommonCircleHeader() { + super.setupCommonCircleHeader() + NSLayoutConstraint.activate([ + avatarImage.widthAnchor.constraint(equalToConstant: 40), + avatarImage.heightAnchor.constraint(equalToConstant: 40), + avatarImage.centerYAnchor.constraint(equalTo: contentView.centerYAnchor, constant: 0), + ]) + } + + override open func commonUI() { + super.commonUI() + sImage.highlightedImage = UIImage.ne_imageNamed(name: "fun_select") + NSLayoutConstraint.activate([ + sImage.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + sImage.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16), + ]) + + bottomLine.backgroundColor = .funContactLineBorderColor + } + + override open func initSubviewsLayout() { + if NEKitContactConfig.shared.ui.avatarType == .rectangle { + avatarImage.layer.cornerRadius = NEKitContactConfig.shared.ui.avatarCornerRadius + } else if NEKitContactConfig.shared.ui.avatarType == .cycle { + avatarImage.layer.cornerRadius = 20.0 + } else { + avatarImage.layer.cornerRadius = 4.0 // Fun UI + } + } + + override open func setConfig() { + super.setConfig() + titleLabel.font = NEKitContactConfig.shared.ui.titleFont ?? UIFont.systemFont(ofSize: 17) + } + + override open func setModel(_ model: ContactInfo) { + super.setModel(model) + arrow.isHidden = true + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunContactTableViewCell.swift b/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunContactTableViewCell.swift new file mode 100644 index 00000000..08199f6c --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunContactTableViewCell.swift @@ -0,0 +1,46 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit +import Foundation +import NECoreKit + +@objcMembers +open class FunContactTableViewCell: NEBaseContactTableViewCell { + override open func setupCommonCircleHeader() { + super.setupCommonCircleHeader() + NSLayoutConstraint.activate([ + avatarImage.widthAnchor.constraint(equalToConstant: 40), + avatarImage.heightAnchor.constraint(equalToConstant: 40), + avatarImage.centerYAnchor.constraint(equalTo: contentView.centerYAnchor, constant: 0), + ]) + } + + override open func commonUI() { + super.commonUI() + bottomLine.backgroundColor = .funContactLineBorderColor + } + + override open func initSubviewsLayout() { + if NEKitContactConfig.shared.ui.avatarType == .rectangle { + avatarImage.layer.cornerRadius = NEKitContactConfig.shared.ui.avatarCornerRadius + } else if NEKitContactConfig.shared.ui.avatarType == .cycle { + avatarImage.layer.cornerRadius = 20.0 + } else { + avatarImage.layer.cornerRadius = 4.0 // Fun UI + } + } + + override open func setConfig() { + super.setConfig() + titleLabel.font = NEKitContactConfig.shared.ui.titleFont ?? UIFont.systemFont(ofSize: 17) + } + + override open func setModel(_ model: ContactInfo) { + super.setModel(model) + arrow.isHidden = true + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunContactUnCheckCell.swift b/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunContactUnCheckCell.swift new file mode 100644 index 00000000..9cf0e0f8 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunContactUnCheckCell.swift @@ -0,0 +1,20 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonUIKit + +@objcMembers +open class FunContactUnCheckCell: NEBaseContactUnCheckCell { + override func setupUI() { + super.setupUI() + avatarImage.layer.cornerRadius = 4 + NSLayoutConstraint.activate([ + avatarImage.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + avatarImage.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), + avatarImage.widthAnchor.constraint(equalToConstant: 40), + avatarImage.heightAnchor.constraint(equalToConstant: 40), + ]) + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunSystemNotificationCell.swift b/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunSystemNotificationCell.swift new file mode 100644 index 00000000..3537b336 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunSystemNotificationCell.swift @@ -0,0 +1,33 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreKit +import NECommonUIKit +import NECoreIMKit +import NIMSDK + +@objcMembers +open class FunSystemNotificationCell: NEBaseSystemNotificationCell { + override open func setupCommonCircleHeader() { + super.setupCommonCircleHeader() + avatarImage.layer.cornerRadius = 4 + NSLayoutConstraint.activate([ + avatarImage.widthAnchor.constraint(equalToConstant: 40), + avatarImage.heightAnchor.constraint(equalToConstant: 40), + avatarImage.centerYAnchor.constraint(equalTo: contentView.centerYAnchor, constant: 0), + ]) + } + + override open func setupUI() { + super.setupUI() + + contentView.updateLayoutConstraint(firstItem: line, seconedItem: contentView, attribute: .right, constant: 0) + line.backgroundColor = .funContactLineBorderColor + agreeBtn.backgroundColor = .funContactThemeColor + agreeBtn.setTitleColor(.white, for: .normal) + agreeBtn.layer.borderColor = UIColor.funContactThemeColor.cgColor + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunTeamTableViewCell.swift b/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunTeamTableViewCell.swift new file mode 100644 index 00000000..d3360f04 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/FunUI/Cell/FunTeamTableViewCell.swift @@ -0,0 +1,33 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit + +@objcMembers +open class FunTeamTableViewCell: NEBaseTeamTableViewCell { + private lazy var bottomLine: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = .funContactLineBorderColor + return view + }() + + override func commonUI() { + super.commonUI() + avatarImage.layer.cornerRadius = 4 + avatarImage.updateLayoutConstraint(firstItem: avatarImage, seconedItem: nil, attribute: .width, constant: 40) + avatarImage.updateLayoutConstraint(firstItem: avatarImage, seconedItem: nil, attribute: .height, constant: 40) + + titleLabel.textColor = .ne_darkText + + contentView.addSubview(bottomLine) + NSLayoutConstraint.activate([ + bottomLine.leftAnchor.constraint(equalTo: avatarImage.leftAnchor), + bottomLine.rightAnchor.constraint(equalTo: contentView.rightAnchor), + bottomLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + bottomLine.heightAnchor.constraint(equalToConstant: 1), + ]) + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/FunUI/FunContactRouter.swift b/NEContactUIKit/NEContactUIKit/Classes/FunUI/FunContactRouter.swift new file mode 100644 index 00000000..92982b32 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/FunUI/FunContactRouter.swift @@ -0,0 +1,58 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import NECoreKit +import NECoreIMKit +import NIMSDK + +public extension ContactRouter { + static func registerFun() { + Router.shared.register(ContactUserSelectRouter) { param in + print("param:\(param)") + let nav = param["nav"] as? UINavigationController + let contactSelectVC = FunContactsSelectedViewController() + if let fiters = param["filters"] as? Set { + contactSelectVC.filterUsers = fiters + } + if let limit = param["limit"] as? Int, limit > 0 { + contactSelectVC.limit = limit + } + if let uid = param["uid"] as? String { + contactSelectVC.userId = uid + } + nav?.pushViewController(contactSelectVC, animated: true) + } + + Router.shared.register(ContactAddFriendRouter) { param in + let nav = param["nav"] as? UINavigationController + let findFrined = FunFindFriendViewController() + nav?.pushViewController(findFrined, animated: true) + } + + Router.shared.register(ContactUserInfoPageRouter) { param in + if let nav = param["nav"] as? UINavigationController { + if let user = param["user"] as? User { + let userInfoVC = FunContactUserViewController(user: user) + nav.pushViewController(userInfoVC, animated: true) + } else if let nimUser = param["nim_user"] as? User { + let userInfoVC = FunContactUserViewController(user: nimUser) + nav.pushViewController(userInfoVC, animated: true) + } else if let uid = param["uid"] as? String { + let userInfoVC = FunContactUserViewController(uid: uid) + nav.pushViewController(userInfoVC, animated: true) + } + } + } + + Router.shared.register(ContactTeamListRouter) { param in + if let nav = param["nav"] as? UINavigationController { + let team = FunTeamListViewController() + team.isClickCallBack = true + nav.pushViewController(team, animated: true) + } + } + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/FunUI/FunContactUIColor.swift b/NEContactUIKit/NEContactUIKit/Classes/FunUI/FunContactUIColor.swift new file mode 100644 index 00000000..7bdfe155 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/FunUI/FunContactUIColor.swift @@ -0,0 +1,13 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import NECommonKit + +public extension UIColor { + static let funContactThemeColor = UIColor(hexString: "#58BE6B") + static let funContactBackgroundColor = UIColor(hexString: "#EDEDED") + static let funContactLineBorderColor = UIColor(hexString: "#E5E5E5") + static let funContactUserViewChatTitleTextColor = UIColor(hexString: "#525C8C") +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/FunUI/View/FunUserInfoHeaderView.swift b/NEContactUIKit/NEContactUIKit/Classes/FunUI/View/FunUserInfoHeaderView.swift new file mode 100644 index 00000000..d523928c --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/FunUI/View/FunUserInfoHeaderView.swift @@ -0,0 +1,42 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit + +@objcMembers +open class FunUserInfoHeaderView: NEBaseUserInfoHeaderView { + override public func commonUI() { + super.commonUI() + avatarImage.layer.cornerRadius = 4 + + NSLayoutConstraint.activate([ + lineView.leftAnchor.constraint(equalTo: titleLabel.leftAnchor), + lineView.rightAnchor.constraint(equalTo: rightAnchor), + lineView.bottomAnchor.constraint(equalTo: bottomAnchor), + lineView.heightAnchor.constraint(equalToConstant: 1), + ]) + } + + override public func setData(user: User?) { + super.setData(user: user) + guard let u = user else { + return + } + + // title + + if let alias = u.alias, !alias.isEmpty { + commonUI(showDetail: true) + titleLabel.text = alias + let uid = u.userId ?? "" + detailLabel.text = "\(localizable("nick")):\(u.userInfo?.nickName ?? uid)" + detailLabel2.text = "\(localizable("account")):\(uid)" + } else { + commonUI(showDetail: false) + titleLabel.text = u.showName() + detailLabel.text = "\(localizable("account")):\(u.userId ?? "")" + } + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunBlackListViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunBlackListViewController.swift new file mode 100644 index 00000000..647f69b3 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunBlackListViewController.swift @@ -0,0 +1,45 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreKit +import NECoreIMKit +import NECommonKit + +@objcMembers +open class FunBlackListViewController: NEBaseBlackListViewController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + className = "FunBlackListViewController" + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func commonUI() { + super.commonUI() + tableView.register( + FunBlackListCell.self, + forCellReuseIdentifier: "\(NSStringFromClass(FunBlackListCell.self))" + ) + tableView.rowHeight = 64 + } + + override public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell( + withIdentifier: "\(NSStringFromClass(FunBlackListCell.self))", + for: indexPath + ) as! FunBlackListCell + cell.delegate = self + cell.index = indexPath.row + cell.setModel(blackList?[indexPath.row] as Any) + return cell + } + + override public func getContactSelectVC() -> NEBaseContactsSelectedViewController { + FunContactsSelectedViewController() + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunContactRemakNameViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunContactRemakNameViewController.swift new file mode 100644 index 00000000..62a3bbca --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunContactRemakNameViewController.swift @@ -0,0 +1,31 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit +import NECoreKit + +@objcMembers +open class FunContactRemakNameViewController: NEBaseContactRemakNameViewController { + override func setupUI() { + super.setupUI() + let clearItem = UIBarButtonItem( + title: localizable("save"), + style: .done, + target: self, + action: #selector(saveAlias) + ) + clearItem.tintColor = .funContactThemeColor + navigationItem.rightBarButtonItem = clearItem + + customNavigationView.moreButton.setTitleColor(.funContactThemeColor, for: .normal) + + NSLayoutConstraint.activate([ + aliasInput.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0), + aliasInput.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0), + aliasInput.topAnchor.constraint(equalTo: view.topAnchor, constant: topConstant), + aliasInput.heightAnchor.constraint(equalToConstant: 60), + ]) + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunContactUserViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunContactUserViewController.swift new file mode 100644 index 00000000..585d5b08 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunContactUserViewController.swift @@ -0,0 +1,75 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit +import NECoreKit +import NIMSDK + +@objcMembers +open class FunContactUserViewController: NEBaseContactUserViewController { + func initFun() { + className = "FunContactUserViewController" + headerView = FunUserInfoHeaderView() + } + + override public init(user: User?) { + super.init(user: user) + initFun() + } + + override public init(uid: String) { + super.init(uid: uid) + initFun() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func commonUI() { + super.commonUI() + tableView.rowHeight = 46 + } + + override open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let item = data[indexPath.section][indexPath.row] + let cell = super.tableView(tableView, cellForRowAt: indexPath) + if let c = cell as? CenterTextCell, item.title == localizable("chat") || item.title == localizable("add_friend") { + c.titleLabel.textColor = .funContactUserViewChatTitleTextColor + return c + } + if let c = cell as? TextWithSwitchCell { + c.switchButton.onTintColor = .funContactThemeColor + return c + } + return cell + } + + open func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + let item = data[indexPath.section][indexPath.row] + if item.title == localizable("sign") { + return 66 + } + return 46 + } + + override public func getContactRemakNameViewController() -> NEBaseContactRemakNameViewController { + FunContactRemakNameViewController() + } + + override public func deleteFriend(user: User?) { + let titleAction = NECustomAlertAction(title: localizable("delete_title").replacingOccurrences(of: "XXX", with: user?.showName(true) ?? "")) {} + titleAction.contentText.font = .systemFont(ofSize: 13) + titleAction.contentText.textColor = UIColor(hexString: "#8F8F8F") + + let deleteAction = NECustomAlertAction(title: localizable("delete_friend")) { [weak self] in + self?.deleteFriendAction(user: user) + } + deleteAction.contentText.textColor = .ne_redText + + showCustomActionSheet([titleAction, deleteAction]) + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunContactsSelectedViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunContactsSelectedViewController.swift new file mode 100644 index 00000000..7fbbb572 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunContactsSelectedViewController.swift @@ -0,0 +1,59 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreKit +import NIMSDK + +@objcMembers +open class FunContactsSelectedViewController: NEBaseContactsSelectedViewController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + customCells = [ContactCellType.ContactPerson.rawValue: FunContactSelectedCell.self] + view.backgroundColor = .funContactBackgroundColor + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func setupUI() { + super.setupUI() + emptyView.setEmptyImage(name: "fun_user_empty") + collectionBackView.backgroundColor = .white + collection.register( + FunContactUnCheckCell.self, + forCellWithReuseIdentifier: "\(NSStringFromClass(FunContactUnCheckCell.self))" + ) + tableView.rowHeight = 64 + } + + override open func setupNavRightItem() { + super.setupNavRightItem() + customNavigationView.moreButton.backgroundColor = .funContactThemeColor + sureBtn.backgroundColor = .funContactThemeColor + } + + override open func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let sectionView: ContactSectionView = tableView + .dequeueReusableHeaderFooterView( + withIdentifier: "\(NSStringFromClass(ContactSectionView.self))" + ) as! ContactSectionView + sectionView.titleLabel.textColor = NEKitContactConfig.shared.ui.indexTitleColor ?? .ne_greyText + sectionView.line.isHidden = true + sectionView.titleLabel.text = viewModel.contacts[section].initial + return sectionView + } + + override open func collectionView(_ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let contactInfo = selectArray[indexPath.row] + let cell = collectionView.dequeueReusableCell( + withReuseIdentifier: "\(NSStringFromClass(FunContactUnCheckCell.self))", + for: indexPath + ) as? FunContactUnCheckCell + cell?.configure(contactInfo) + return cell ?? UICollectionViewCell() + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunContactsViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunContactsViewController.swift new file mode 100644 index 00000000..1e0dc824 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunContactsViewController.swift @@ -0,0 +1,201 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit +import NECoreKit + +@objcMembers +open class FunContactsViewController: NEBaseContactsViewController { + public lazy var searchView: FunSearchView = { + let view = FunSearchView() + view.translatesAutoresizingMaskIntoConstraints = false + view.searchBotton.setImage(UIImage.ne_imageNamed(name: "funSearch"), for: .normal) + view.searchBotton.setTitle(localizable("search"), for: .normal) + return view + }() + + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nil, bundle: nil) + viewModel = ContactViewModel(contactHeaders: [ + ContactHeadItem( + name: localizable("validation_message"), + imageName: "funValid", + router: ValidationMessageRouter, + color: UIColor(hexString: "#60CFA7") + ), + ContactHeadItem( + name: localizable("blacklist"), + imageName: "funBlackName", + router: ContactBlackListRouter, + color: UIColor(hexString: "#53C3F3") + ), + ContactHeadItem( + name: localizable("mine_groupchat"), + imageName: "funGroup", + router: ContactGroupRouter, + color: UIColor(hexString: "#BE65D9") + ), + ]) + customCells = [ + ContactCellType.ContactPerson.rawValue: FunContactTableViewCell.self, + ContactCellType.ContactOthers.rawValue: FunContactTableViewCell.self, + ] + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + override open func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .funContactBackgroundColor + } + + deinit { + if let searchViewGestures = searchView.gestureRecognizers { + searchViewGestures.forEach { gesture in + searchView.removeGestureRecognizer(gesture) + } + } + } + + override open func commonUI() { + super.commonUI() + + let tap = UITapGestureRecognizer(target: self, action: #selector(searchAction)) + tap.cancelsTouchesInView = false + searchView.addGestureRecognizer(tap) + view.addSubview(searchView) + NSLayoutConstraint.activate([ + searchView.topAnchor.constraint(equalTo: view.topAnchor, constant: topConstant + 12), + searchView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8), + searchView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8), + searchView.heightAnchor.constraint(equalToConstant: 36), + ]) + + NSLayoutConstraint.activate([ + topView.topAnchor.constraint(equalTo: searchView.bottomAnchor, constant: 12), + topView.leftAnchor.constraint(equalTo: view.leftAnchor), + topView.rightAnchor.constraint(equalTo: view.rightAnchor), + ]) + + tableView.backgroundColor = .clear + + tableView.register( + ContactSectionView.self, + forHeaderFooterViewReuseIdentifier: "\(NSStringFromClass(ContactSectionView.self))" + ) + + customCells.forEach { (key: Int, value: NEBaseContactTableViewCell.Type) in + tableView.register(value, forCellReuseIdentifier: "\(key)") + } + + emptyView.setEmptyImage(name: "fun_user_empty") + } + + override open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let info = viewModel.contacts[indexPath.section].contacts[indexPath.row] + var reusedId = "\(info.contactCellType)" + let cell = tableView.dequeueReusableCell(withIdentifier: reusedId, for: indexPath) + + if let c = cell as? FunContactTableViewCell { + return configCell(info: info, c, indexPath) + } + return cell + } + + override open func tableView(_ tableView: UITableView, + viewForHeaderInSection section: Int) -> UIView? { + if let sectionView = super.tableView(tableView, viewForHeaderInSection: section) as? ContactSectionView { + sectionView.line.isHidden = true + return sectionView + } + return nil + } + + override open func tableView(_ tableView: UITableView, + heightForRowAt indexPath: IndexPath) -> CGFloat { + 64 + } + + override open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let info = viewModel.contacts[indexPath.section].contacts[indexPath.row] + if let callBack = clickCallBacks[info.contactCellType] { + callBack(indexPath.row, indexPath.section) + return + } + if info.contactCellType == ContactCellType.ContactOthers.rawValue { + switch info.router { + case ValidationMessageRouter: + let validationController = FunValidationMessageViewController() + validationController.hidesBottomBarWhenPushed = true + navigationController?.pushViewController(validationController, animated: true) + case ContactBlackListRouter: + let blackVC = FunBlackListViewController() + blackVC.hidesBottomBarWhenPushed = true + navigationController?.pushViewController(blackVC, animated: true) + + case ContactGroupRouter: + // My Team + let teamVC = FunTeamListViewController() + teamVC.hidesBottomBarWhenPushed = true + navigationController?.pushViewController(teamVC, animated: true) + + case ContactPersonRouter: + + break + + case ContactComputerRouter: + // let select = ContactsSelectedViewController() + // select.CallBack = { contacts in + // print("select contacs : ", contacts) + // } + // select.hidesBottomBarWhenPushed = true + // self.navigationController?.pushViewController(select, animated: true) + break + default: + break + } + } else { + let userInfoVC = FunContactUserViewController(user: info.user) + userInfoVC.hidesBottomBarWhenPushed = true + navigationController?.pushViewController(userInfoVC, animated: true) + } + } + + override open func getFindFriendViewController() -> NEBaseFindFriendViewController { + FunFindFriendViewController() + } +} + +extension FunContactsViewController { + override open func initSystemNav() { + edgesForExtendedLayout = [] + let addItem = UIBarButtonItem( + image: UIImage.ne_imageNamed(name: "funAdd"), + style: .plain, + target: self, + action: #selector(goToFindFriend) + ) + addItem.tintColor = UIColor(hexString: "333333") + + navigationItem.rightBarButtonItems = [addItem] + navView.addBtn.setImage(UIImage.ne_imageNamed(name: "funAdd"), for: .normal) + + if NEKitContactConfig.shared.ui.hiddenRightBtns { + navigationItem.rightBarButtonItems = [] + navView.addBtn.isHidden = true + } + + title = localizable("contact") + navView.navigationTitle.text = localizable("contact") + navView.backgroundColor = .funContactBackgroundColor + navView.bottomLine.isHidden = true + navView.brandBtn.isHidden = true + navView.navigationTitle.isHidden = false + navView.searchBtn.isHidden = true + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunFindFriendViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunFindFriendViewController.swift new file mode 100644 index 00000000..ad176480 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunFindFriendViewController.swift @@ -0,0 +1,74 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreKit +import NECoreIMKit + +@objc +open class FunFindFriendViewController: NEBaseFindFriendViewController { + override open func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + } + + override open func setupUI() { + view.backgroundColor = UIColor(hexString: "0xEDEDED") + + let searchBack = UIView() + view.addSubview(searchBack) + searchBack.backgroundColor = UIColor.white + searchBack.translatesAutoresizingMaskIntoConstraints = false + searchBack.clipsToBounds = true + searchBack.layer.cornerRadius = 4.0 + NSLayoutConstraint.activate([ + searchBack.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20), + searchBack.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), + searchBack.topAnchor.constraint(equalTo: view.topAnchor, constant: 10 + topConstant), + searchBack.heightAnchor.constraint(equalToConstant: 36), + ]) + + let searchImage = UIImageView() + searchBack.addSubview(searchImage) + searchImage.image = UIImage.ne_imageNamed(name: "search") + searchImage.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + searchImage.centerYAnchor.constraint(equalTo: searchBack.centerYAnchor), + searchImage.leftAnchor.constraint(equalTo: searchBack.leftAnchor, constant: 18), + searchImage.widthAnchor.constraint(equalToConstant: 13), + searchImage.heightAnchor.constraint(equalToConstant: 13), + ]) + + searchBack.addSubview(searchInput) + searchInput.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + searchInput.leftAnchor.constraint(equalTo: searchImage.rightAnchor, constant: 5), + searchInput.rightAnchor.constraint(equalTo: searchBack.rightAnchor, constant: -18), + searchInput.topAnchor.constraint(equalTo: searchBack.topAnchor), + searchInput.bottomAnchor.constraint(equalTo: searchBack.bottomAnchor), + ]) + searchInput.textColor = UIColor(hexString: "0x333333") + searchInput.placeholder = localizable("input_userId") + searchInput.font = UIFont.systemFont(ofSize: 14.0) + searchInput.returnKeyType = .search + searchInput.delegate = self + searchInput.clearButtonMode = .always + + NotificationCenter.default.addObserver( + self, + selector: #selector(textFieldChange), + name: UITextField.textDidChangeNotification, + object: nil + ) + + view.addSubview(emptyView) + NSLayoutConstraint.activate([ + emptyView.centerXAnchor.constraint(equalTo: view.centerXAnchor), + emptyView.topAnchor.constraint(equalTo: searchInput.bottomAnchor, constant: 74), + ]) + + emptyView.setEmptyImage(name: "fun_user_empty") + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunTeamListViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunTeamListViewController.swift new file mode 100644 index 00000000..262830d8 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunTeamListViewController.swift @@ -0,0 +1,30 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK +import NECoreKit + +@objcMembers +open class FunTeamListViewController: NEBaseTeamListViewController { + override func commonUI() { + super.commonUI() + tableView.register( + FunTeamTableViewCell.self, + forCellReuseIdentifier: "\(NSStringFromClass(FunTeamTableViewCell.self))" + ) + tableView.rowHeight = 72 + } + + override public func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell( + withIdentifier: "\(NSStringFromClass(FunTeamTableViewCell.self))", + for: indexPath + ) as! FunTeamTableViewCell + cell.setModel(viewModel.teamList[indexPath.row]) + return cell + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunValidationMessageViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunValidationMessageViewController.swift new file mode 100644 index 00000000..b688062e --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/FunUI/ViewController/FunValidationMessageViewController.swift @@ -0,0 +1,59 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreKit +import NECoreIMKit + +@objcMembers +open class FunValidationMessageViewController: NEBaseValidationMessageViewController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + tag = "FunValidationMessageViewController" + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func setupUI() { + super.setupUI() + let clearItem = UIBarButtonItem( + title: localizable("clear"), + style: .done, + target: self, + action: #selector(clearMessage) + ) + clearItem.tintColor = .ne_darkText + let textAttributes: [NSAttributedString.Key: Any] = [.font: UIFont.systemFont(ofSize: 16, weight: .regular)] + + clearItem.setTitleTextAttributes(textAttributes, for: .normal) + navigationItem.rightBarButtonItem = clearItem + + customNavigationView.moreButton.titleLabel?.font = .systemFont(ofSize: 16) + + tableView.register( + FunSystemNotificationCell.self, + forCellReuseIdentifier: "\(FunSystemNotificationCell.self)" + ) + + emptyView.setEmptyImage(name: "fun_user_empty") + } +} + +extension FunValidationMessageViewController { + override open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let noti = viewModel.datas[indexPath.row] + let reuseIdentifier = "\(FunSystemNotificationCell.self)" + let cell = tableView.dequeueReusableCell( + withIdentifier: reuseIdentifier, + for: indexPath + ) as! FunSystemNotificationCell + cell.delegate = self + cell.confige(noti) + return cell + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/Model/ContactInfo.swift b/NEContactUIKit/NEContactUIKit/Classes/Model/ContactInfo.swift index 03c876a3..79bf6531 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Model/ContactInfo.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Model/ContactInfo.swift @@ -8,7 +8,8 @@ import NECoreIMKit import UIKit import NECoreKit -public class ContactInfo { +@objcMembers +open class ContactInfo: NSObject { func getRowHeight() -> CGFloat? { nil } diff --git a/NEContactUIKit/NEContactUIKit/Classes/Model/ContactSection.swift b/NEContactUIKit/NEContactUIKit/Classes/Model/ContactSection.swift index f319604d..456f2523 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Model/ContactSection.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Model/ContactSection.swift @@ -4,10 +4,11 @@ // found in the LICENSE file. import Foundation -import NEContactKit +import NEChatKit import NECoreIMKit -public class ContactSection { +@objcMembers +open class ContactSection { public var initial: String public var contacts: Array = [ContactInfo]() init(initial: String, contacts: [ContactInfo]) { diff --git a/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/BlackListCell.swift b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/BlackListCell.swift new file mode 100644 index 00000000..02102774 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/BlackListCell.swift @@ -0,0 +1,41 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit + +@objcMembers +open class BlackListCell: NEBaseBlackListCell { + override func commonUI() { + super.commonUI() + avatarImage.layer.cornerRadius = 21 + + titleLabel.font = UIFont.systemFont(ofSize: 16) + titleLabel.textColor = UIColor( + red: 51 / 255.0, + green: 51 / 255.0, + blue: 51 / 255.0, + alpha: 1.0 + ) + + button.layer.borderColor = UIColor(red: 0.2, green: 0.494, blue: 1, alpha: 1).cgColor + + button.setTitleColor(UIColor(red: 0.2, green: 0.494, blue: 1, alpha: 1), for: .normal) + + contentView.addSubview(bottomLine) + NSLayoutConstraint.activate([ + bottomLine.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20), + bottomLine.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20), + bottomLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + bottomLine.heightAnchor.constraint(equalToConstant: 1), + ]) + } + + private lazy var bottomLine: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = UIColor.ne_greyLine + return view + }() +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/ContactSelectedCell.swift b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/ContactSelectedCell.swift new file mode 100644 index 00000000..7638e4ce --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/ContactSelectedCell.swift @@ -0,0 +1,31 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +@objcMembers +open class ContactSelectedCell: NEBaseContactSelectedCell { + override open func commonUI() { + super.commonUI() + sImage.highlightedImage = UIImage.ne_imageNamed(name: "select") + NSLayoutConstraint.activate([ + sImage.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + sImage.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20), + ]) + } + + override open func setConfig() { + super.setConfig() + titleLabel.font = NEKitContactConfig.shared.ui.titleFont ?? UIFont.systemFont(ofSize: 14) + } + + override open func setupCommonCircleHeader() { + super.setupCommonCircleHeader() + NSLayoutConstraint.activate([ + avatarImage.widthAnchor.constraint(equalToConstant: 36), + avatarImage.heightAnchor.constraint(equalToConstant: 36), + avatarImage.centerYAnchor.constraint(equalTo: contentView.centerYAnchor, constant: 0), + ]) + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/ContactTableViewCell.swift b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/ContactTableViewCell.swift new file mode 100644 index 00000000..695d358b --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/ContactTableViewCell.swift @@ -0,0 +1,38 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit +import Foundation +import NECoreKit + +@objcMembers +open class ContactTableViewCell: NEBaseContactTableViewCell { + override open func setConfig() { + super.setConfig() + titleLabel.font = NEKitContactConfig.shared.ui.titleFont ?? UIFont.systemFont(ofSize: 14) + } + + override open func commonUI() { + super.commonUI() + bottomLine.backgroundColor = .ne_greyLine + } + + override open func setupCommonCircleHeader() { + super.setupCommonCircleHeader() + NSLayoutConstraint.activate([ + avatarImage.widthAnchor.constraint(equalToConstant: 36), + avatarImage.heightAnchor.constraint(equalToConstant: 36), + avatarImage.centerYAnchor.constraint(equalTo: contentView.centerYAnchor, constant: 0), + ]) + } + + override open func setModel(_ model: ContactInfo) { + super.setModel(model) + if model.contactCellType == 2 { + bottomLine.isHidden = true + } + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/ContactUnCheckCell.swift b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/ContactUnCheckCell.swift new file mode 100644 index 00000000..a89767db --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/ContactUnCheckCell.swift @@ -0,0 +1,20 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonUIKit + +@objcMembers +open class ContactUnCheckCell: NEBaseContactUnCheckCell { + override func setupUI() { + super.setupUI() + avatarImage.layer.cornerRadius = 18 + NSLayoutConstraint.activate([ + avatarImage.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + avatarImage.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), + avatarImage.widthAnchor.constraint(equalToConstant: 36), + avatarImage.heightAnchor.constraint(equalToConstant: 36), + ]) + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/SystemNotificationCell.swift b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/SystemNotificationCell.swift new file mode 100644 index 00000000..43b7b04a --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/SystemNotificationCell.swift @@ -0,0 +1,23 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreKit +import NECommonUIKit +import NECoreIMKit +import NIMSDK + +@objcMembers +open class SystemNotificationCell: NEBaseSystemNotificationCell { + override open func setupCommonCircleHeader() { + super.setupCommonCircleHeader() + avatarImage.layer.cornerRadius = 18 + NSLayoutConstraint.activate([ + avatarImage.widthAnchor.constraint(equalToConstant: 36), + avatarImage.heightAnchor.constraint(equalToConstant: 36), + avatarImage.centerYAnchor.constraint(equalTo: contentView.centerYAnchor, constant: 0), + ]) + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/TeamTableViewCell.swift b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/TeamTableViewCell.swift new file mode 100644 index 00000000..acedd184 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/Cell/TeamTableViewCell.swift @@ -0,0 +1,22 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit + +@objcMembers +open class TeamTableViewCell: NEBaseTeamTableViewCell { + override func commonUI() { + super.commonUI() + avatarImage.layer.cornerRadius = 21 + + titleLabel.font = UIFont.systemFont(ofSize: 16) + titleLabel.textColor = UIColor( + red: 51 / 255.0, + green: 51 / 255.0, + blue: 51 / 255.0, + alpha: 1.0 + ) + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/Common/ContactRouter.swift b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/NromalContactRouter.swift similarity index 95% rename from NEContactUIKit/NEContactUIKit/Classes/Common/ContactRouter.swift rename to NEContactUIKit/NEContactUIKit/Classes/NormalUI/NromalContactRouter.swift index 7833fe5e..cd48bfb1 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Common/ContactRouter.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/NromalContactRouter.swift @@ -8,9 +8,8 @@ import NECoreKit import NECoreIMKit import NIMSDK -@objcMembers -public class ContactRouter: NSObject { - public static func register() { +public extension ContactRouter { + static func register() { Router.shared.register(ContactUserSelectRouter) { param in print("param:\(param)") let nav = param["nav"] as? UINavigationController diff --git a/NEContactUIKit/NEContactUIKit/Classes/NormalUI/View/UserInfoHeaderView.swift b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/View/UserInfoHeaderView.swift new file mode 100644 index 00000000..823f4d63 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/View/UserInfoHeaderView.swift @@ -0,0 +1,42 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit + +@objcMembers +open class UserInfoHeaderView: NEBaseUserInfoHeaderView { + override public func commonUI() { + super.commonUI() + avatarImage.layer.cornerRadius = 30 + + NSLayoutConstraint.activate([ + lineView.leftAnchor.constraint(equalTo: leftAnchor), + lineView.rightAnchor.constraint(equalTo: rightAnchor), + lineView.bottomAnchor.constraint(equalTo: bottomAnchor), + lineView.heightAnchor.constraint(equalToConstant: 6), + ]) + } + + override public func setData(user: User?) { + super.setData(user: user) + guard let u = user else { + return + } + // title + + if let alias = u.alias, !alias.isEmpty { + commonUI(showDetail: true) + titleLabel.text = alias + let uid = u.userId ?? "" + detailLabel.text = "\(localizable("nick")):\(u.userInfo?.nickName ?? uid)" + detailLabel2.text = "\(localizable("account")):\(uid)" + } else { + commonUI(showDetail: false) + titleLabel.text = u.showName() + detailLabel.text = "\(localizable("account")):\(u.userId ?? "")" + } + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/BlackListViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/BlackListViewController.swift new file mode 100644 index 00000000..2f961197 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/BlackListViewController.swift @@ -0,0 +1,47 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreKit +import NECoreIMKit +import NECommonKit + +@objcMembers +open class BlackListViewController: NEBaseBlackListViewController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + className = "BlackListViewController" + customNavigationView.backgroundColor = .white + navigationController?.navigationBar.backgroundColor = .white + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func commonUI() { + super.commonUI() + tableView.register( + BlackListCell.self, + forCellReuseIdentifier: "\(NSStringFromClass(BlackListCell.self))" + ) + tableView.rowHeight = 62 + } + + override open func getContactSelectVC() -> NEBaseContactsSelectedViewController { + ContactsSelectedViewController() + } + + override public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell( + withIdentifier: "\(NSStringFromClass(BlackListCell.self))", + for: indexPath + ) as! BlackListCell + cell.delegate = self + cell.index = indexPath.row + cell.setModel(blackList?[indexPath.row] as Any) + return cell + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/ContactRemakNameViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/ContactRemakNameViewController.swift new file mode 100644 index 00000000..a411c57f --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/ContactRemakNameViewController.swift @@ -0,0 +1,32 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit +import NECoreKit + +@objcMembers +open class ContactRemakNameViewController: NEBaseContactRemakNameViewController { + override func setupUI() { + super.setupUI() + aliasInput.layer.cornerRadius = 8 + + let clearItem = UIBarButtonItem( + title: localizable("save"), + style: .done, + target: self, + action: #selector(saveAlias) + ) + clearItem.tintColor = UIColor(hexString: "337EFF") + navigationItem.rightBarButtonItem = clearItem + + NSLayoutConstraint.activate([ + aliasInput.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20), + aliasInput.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), + aliasInput.topAnchor.constraint(equalTo: view.topAnchor, constant: 10 + topConstant), + aliasInput.heightAnchor.constraint(equalToConstant: 50), + ]) + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/ContactUserViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/ContactUserViewController.swift new file mode 100644 index 00000000..69b2858a --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/ContactUserViewController.swift @@ -0,0 +1,40 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit +import NECoreKit +import NIMSDK + +@objcMembers +open class ContactUserViewController: NEBaseContactUserViewController { + func initNormal() { + className = "ContactUserViewController" + headerView = UserInfoHeaderView() + } + + override public init(user: User?) { + super.init(user: user) + initNormal() + } + + override public init(uid: String) { + super.init(uid: uid) + initNormal() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func commonUI() { + super.commonUI() + tableView.rowHeight = 62 + } + + override public func getContactRemakNameViewController() -> NEBaseContactRemakNameViewController { + ContactRemakNameViewController() + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/ContactsSelectedViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/ContactsSelectedViewController.swift new file mode 100644 index 00000000..b968baed --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/ContactsSelectedViewController.swift @@ -0,0 +1,62 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreKit +import NIMSDK + +@objcMembers +open class ContactsSelectedViewController: NEBaseContactsSelectedViewController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + customCells = [ContactCellType.ContactPerson.rawValue: ContactSelectedCell.self] + view.backgroundColor = .ne_backcolor + customNavigationView.backgroundColor = .white + navigationController?.navigationBar.backgroundColor = .white + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func setupUI() { + super.setupUI() + collectionBackViewTopMargin = 0 + collectionBackViewTopAnchor?.constant = topConstant + + collection.register( + ContactUnCheckCell.self, + forCellWithReuseIdentifier: "\(NSStringFromClass(ContactUnCheckCell.self))" + ) + tableView.rowHeight = 52 + } + + override open func setupNavRightItem() { + super.setupNavRightItem() + customNavigationView.moreButton.backgroundColor = .white + customNavigationView.moreButton.setTitleColor(UIColor(hexString: "337EFF"), for: .normal) + sureBtn.backgroundColor = .white + sureBtn.setTitleColor(UIColor(hexString: "337EFF"), for: .normal) + } + + override open func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let sectionView: ContactSectionView = tableView + .dequeueReusableHeaderFooterView( + withIdentifier: "\(NSStringFromClass(ContactSectionView.self))" + ) as! ContactSectionView + sectionView.titleLabel.text = viewModel.contacts[section].initial + return sectionView + } + + override open func collectionView(_ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let contactInfo = selectArray[indexPath.row] + let cell = collectionView.dequeueReusableCell( + withReuseIdentifier: "\(NSStringFromClass(ContactUnCheckCell.self))", + for: indexPath + ) as? ContactUnCheckCell + cell?.configure(contactInfo) + return cell ?? UICollectionViewCell() + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/ContactsViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/ContactsViewController.swift new file mode 100644 index 00000000..a5266679 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/ContactsViewController.swift @@ -0,0 +1,170 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit +import NECoreKit + +@objcMembers +open class ContactsViewController: NEBaseContactsViewController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nil, bundle: nil) + viewModel = ContactViewModel(contactHeaders: [ + ContactHeadItem( + name: localizable("validation_message"), + imageName: "valid", + router: ValidationMessageRouter, + color: UIColor(hexString: "#60CFA7") + ), + ContactHeadItem( + name: localizable("blacklist"), + imageName: "blackName", + router: ContactBlackListRouter, + color: UIColor(hexString: "#53C3F3") + ), + ContactHeadItem( + name: localizable("mine_groupchat"), + imageName: "group", + router: ContactGroupRouter, + color: UIColor(hexString: "#BE65D9") + ), + ]) + customCells = [ + ContactCellType.ContactPerson.rawValue: ContactTableViewCell.self, + ContactCellType.ContactOthers.rawValue: ContactTableViewCell.self, + ] + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + override open func viewDidLoad() { + super.viewDidLoad() + commonUI() + } + + override open func commonUI() { + super.commonUI() + + NSLayoutConstraint.activate([ + topView.topAnchor.constraint(equalTo: view.topAnchor, constant: topConstant), + topView.leftAnchor.constraint(equalTo: view.leftAnchor), + topView.rightAnchor.constraint(equalTo: view.rightAnchor), + ]) + + tableView.register( + ContactSectionView.self, + forHeaderFooterViewReuseIdentifier: "\(NSStringFromClass(ContactSectionView.self))" + ) + + customCells.forEach { (key: Int, value: NEBaseContactTableViewCell.Type) in + tableView.register(value, forCellReuseIdentifier: "\(key)") + } + } + + override open func getFindFriendViewController() -> NEBaseFindFriendViewController { + FindFriendViewController() + } + + override open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let info = viewModel.contacts[indexPath.section].contacts[indexPath.row] + var reusedId = "\(info.contactCellType)" + let cell = tableView.dequeueReusableCell(withIdentifier: reusedId, for: indexPath) + + if let c = cell as? ContactTableViewCell { + return configCell(info: info, c, indexPath) + } + return cell + } + + override open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let info = viewModel.contacts[indexPath.section].contacts[indexPath.row] + if let callBack = clickCallBacks[info.contactCellType] { + callBack(indexPath.row, indexPath.section) + return + } + if info.contactCellType == ContactCellType.ContactOthers.rawValue { + switch info.router { + case ValidationMessageRouter: + let validationController = ValidationMessageViewController() + validationController.hidesBottomBarWhenPushed = true + navigationController?.pushViewController(validationController, animated: true) + case ContactBlackListRouter: + let blackVC = BlackListViewController() + blackVC.hidesBottomBarWhenPushed = true + navigationController?.pushViewController(blackVC, animated: true) + + case ContactGroupRouter: + // My Team + let teamVC = TeamListViewController() + teamVC.hidesBottomBarWhenPushed = true + navigationController?.pushViewController(teamVC, animated: true) + + case ContactPersonRouter: + + break + + case ContactComputerRouter: + // let select = ContactsSelectedViewController() + // select.CallBack = { contacts in + // print("select contacs : ", contacts) + // } + // select.hidesBottomBarWhenPushed = true + // self.navigationController?.pushViewController(select, animated: true) + break + default: + break + } + } else { + let userInfoVC = ContactUserViewController(user: info.user) + userInfoVC.hidesBottomBarWhenPushed = true + navigationController?.pushViewController(userInfoVC, animated: true) + } + } +} + +extension ContactsViewController { + override open func initSystemNav() { + super.initSystemNav() + let addItem = UIBarButtonItem( + image: UIImage.ne_imageNamed(name: "add"), + style: .plain, + target: self, + action: #selector(goToFindFriend) + ) + addItem.tintColor = UIColor(hexString: "333333") + let searchItem = UIBarButtonItem( + image: UIImage.ne_imageNamed(name: "contact_search"), + style: .plain, + target: self, + action: #selector(searchContact) + ) + searchItem.imageInsets = UIEdgeInsets(top: 0, left: 35, bottom: 0, right: 0) + searchItem.tintColor = UIColor(hexString: "333333") + + navigationItem.rightBarButtonItems = [addItem, searchItem] + if NEKitContactConfig.shared.ui.hiddenSearchBtn { + navigationItem.rightBarButtonItems = [addItem] + navView.searchBtn.isHidden = true + } + if NEKitContactConfig.shared.ui.hiddenRightBtns { + navigationItem.rightBarButtonItems = [] + navView.searchBtn.isHidden = true + navView.addBtn.isHidden = true + } + + let brandBarBtn = UIButton() + brandBarBtn.setTitle(localizable("contact"), for: .normal) + brandBarBtn.setTitleColor(UIColor.black, for: .normal) + brandBarBtn.titleLabel?.font = NEConstant.textFont("PingFangSC-Medium", 20) + let brandBtn = UIBarButtonItem(customView: brandBarBtn) + navigationItem.leftBarButtonItem = brandBtn + + navView.brandBtn.setImage(nil, for: .normal) + navView.brandBtn.setTitle(localizable("contact"), for: .normal) + navView.brandBtn.titleEdgeInsets = UIEdgeInsets.zero + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/FindFriendViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/FindFriendViewController.swift new file mode 100644 index 00000000..3b7a1121 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/FindFriendViewController.swift @@ -0,0 +1,18 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FindFriendViewController: NEBaseFindFriendViewController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + customNavigationView.backgroundColor = .white + navigationController?.navigationBar.backgroundColor = .white + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/TeamListViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/TeamListViewController.swift new file mode 100644 index 00000000..a2e391c4 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/TeamListViewController.swift @@ -0,0 +1,32 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK +import NECoreKit + +@objcMembers +open class TeamListViewController: NEBaseTeamListViewController { + override func commonUI() { + super.commonUI() + customNavigationView.backgroundColor = .white + navigationController?.navigationBar.backgroundColor = .white + tableView.register( + TeamTableViewCell.self, + forCellReuseIdentifier: "\(NSStringFromClass(TeamTableViewCell.self))" + ) + tableView.rowHeight = 62 + } + + override public func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell( + withIdentifier: "\(NSStringFromClass(TeamTableViewCell.self))", + for: indexPath + ) as! TeamTableViewCell + cell.setModel(viewModel.teamList[indexPath.row]) + return cell + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/ValidationMessageViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/ValidationMessageViewController.swift new file mode 100644 index 00000000..d188b12c --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/NormalUI/ViewController/ValidationMessageViewController.swift @@ -0,0 +1,60 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreKit +import NECoreIMKit + +@objcMembers +open class ValidationMessageViewController: NEBaseValidationMessageViewController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + tag = "ValidationMessageViewController" + customNavigationView.backgroundColor = .white + navigationController?.navigationBar.backgroundColor = .white + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func setupUI() { + super.setupUI() + let clearItem = UIBarButtonItem( + title: localizable("clear"), + style: .done, + target: self, + action: #selector(clearMessage) + ) + clearItem.tintColor = .ne_darkText + var textAttributes = [NSAttributedString.Key: Any]() + textAttributes[.font] = UIFont.systemFont(ofSize: 14, weight: .regular) + + clearItem.setTitleTextAttributes(textAttributes, for: .normal) + navigationItem.rightBarButtonItem = clearItem + + customNavigationView.moreButton.titleLabel?.font = .systemFont(ofSize: 16) + + tableView.register( + SystemNotificationCell.self, + forCellReuseIdentifier: "\(SystemNotificationCell.self)" + ) + } +} + +extension ValidationMessageViewController { + override open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let noti = viewModel.datas[indexPath.row] + let reuseIdentifier = "\(SystemNotificationCell.self)" + let cell = tableView.dequeueReusableCell( + withIdentifier: reuseIdentifier, + for: indexPath + ) as! SystemNotificationCell + cell.delegate = self + cell.confige(noti) + return cell + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/Team/Views/TeamTableViewCell.swift b/NEContactUIKit/NEContactUIKit/Classes/Team/Cell/NEBaseTeamTableViewCell.swift similarity index 90% rename from NEContactUIKit/NEContactUIKit/Classes/Team/Views/TeamTableViewCell.swift rename to NEContactUIKit/NEContactUIKit/Classes/Team/Cell/NEBaseTeamTableViewCell.swift index c0dcf7cf..29134e22 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Team/Views/TeamTableViewCell.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Team/Cell/NEBaseTeamTableViewCell.swift @@ -1,4 +1,3 @@ - // Copyright (c) 2022 NetEase, Inc. All rights reserved. // Use of this source code is governed by a MIT license that can be // found in the LICENSE file. @@ -7,7 +6,7 @@ import UIKit import NECoreIMKit @objcMembers -public class TeamTableViewCell: UITableViewCell { +open class NEBaseTeamTableViewCell: UITableViewCell { public var avatarImage = UIImageView() public var nameLabel = UILabel() public var titleLabel = UILabel() @@ -18,16 +17,15 @@ public class TeamTableViewCell: UITableViewCell { commonUI() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func commonUI() { selectionStyle = .none - avatarImage.backgroundColor = UIColor.colorWithNumber(number: 0) - avatarImage.layer.cornerRadius = 21 avatarImage.translatesAutoresizingMaskIntoConstraints = false avatarImage.clipsToBounds = true + avatarImage.contentMode = .scaleAspectFill contentView.addSubview(avatarImage) NSLayoutConstraint.activate([ avatarImage.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20), @@ -49,13 +47,6 @@ public class TeamTableViewCell: UITableViewCell { ]) titleLabel.translatesAutoresizingMaskIntoConstraints = false - titleLabel.font = UIFont.systemFont(ofSize: 16) - titleLabel.textColor = UIColor( - red: 51 / 255.0, - green: 51 / 255.0, - blue: 51 / 255.0, - alpha: 1.0 - ) contentView.addSubview(titleLabel) NSLayoutConstraint.activate([ titleLabel.leftAnchor.constraint(equalTo: avatarImage.rightAnchor, constant: 12), @@ -87,9 +78,11 @@ public class TeamTableViewCell: UITableViewCell { // self.nameLabel.text = name.count > 2 ? String(name[name.index(name.endIndex, offsetBy: -2)...]) : name if let url = team.thumbAvatarUrl { avatarImage.sd_setImage(with: URL(string: url), completed: nil) + avatarImage.backgroundColor = .clear } else { // random avatar // avatarImage.image = randomAvatar(teamId: team.teamId) + avatarImage.backgroundColor = UIColor.colorWithString(string: team.teamId) } } diff --git a/NEContactUIKit/NEContactUIKit/Classes/Team/ViewController/TeamListViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/Team/ViewController/NEBaseTeamListViewController.swift similarity index 64% rename from NEContactUIKit/NEContactUIKit/Classes/Team/ViewController/TeamListViewController.swift rename to NEContactUIKit/NEContactUIKit/Classes/Team/ViewController/NEBaseTeamListViewController.swift index e7cd416f..7cc16cad 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Team/ViewController/TeamListViewController.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Team/ViewController/NEBaseTeamListViewController.swift @@ -8,13 +8,22 @@ import NIMSDK import NECoreKit @objcMembers -public class TeamListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { +open class NEBaseTeamListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIGestureRecognizerDelegate { + public let customNavigationView = NENavigationView() var tableView = UITableView(frame: .zero, style: .plain) var viewModel = TeamListViewModel() var isClickCallBack = false override public func viewDidLoad() { super.viewDidLoad() + view.backgroundColor = .white + navigationController?.interactivePopGestureRecognizer?.delegate = self + if let useSystemNav = NEConfigManager.instance.getParameter(key: useSystemNav) as? Bool, useSystemNav { + navigationController?.isNavigationBarHidden = false + } else { + navigationController?.isNavigationBarHidden = true + } + commonUI() loadData() weak var weakSelf = self @@ -25,6 +34,7 @@ public class TeamListViewController: UIViewController, UITableViewDelegate, UITa func commonUI() { title = localizable("mine_groupchat") + customNavigationView.navTitle.text = title let image = UIImage.ne_imageNamed(name: "backArrow")?.withRenderingMode(.alwaysOriginal) navigationItem.leftBarButtonItem = UIBarButtonItem( image: image, @@ -32,22 +42,29 @@ public class TeamListViewController: UIViewController, UITableViewDelegate, UITa target: self, action: #selector(backEvent) ) + + customNavigationView.translatesAutoresizingMaskIntoConstraints = false + customNavigationView.addBackButtonTarget(target: self, selector: #selector(backEvent)) + customNavigationView.moreButton.isHidden = true + view.addSubview(customNavigationView) + NSLayoutConstraint.activate([ + customNavigationView.leftAnchor.constraint(equalTo: view.leftAnchor), + customNavigationView.rightAnchor.constraint(equalTo: view.rightAnchor), + customNavigationView.topAnchor.constraint(equalTo: view.topAnchor), + customNavigationView.heightAnchor.constraint(equalToConstant: NEConstant.navigationAndStatusHeight), + ]) + tableView.separatorStyle = .none tableView.delegate = self tableView.dataSource = self tableView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(tableView) NSLayoutConstraint.activate([ - tableView.topAnchor.constraint(equalTo: view.topAnchor), + tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: NEConstant.navigationAndStatusHeight), tableView.leftAnchor.constraint(equalTo: view.leftAnchor), tableView.rightAnchor.constraint(equalTo: view.rightAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) - tableView.register( - TeamTableViewCell.self, - forCellReuseIdentifier: "\(NSStringFromClass(TeamTableViewCell.self))" - ) - tableView.rowHeight = 62 tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 0.1)) } @@ -62,12 +79,7 @@ public class TeamListViewController: UIViewController, UITableViewDelegate, UITa public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell( - withIdentifier: "\(NSStringFromClass(TeamTableViewCell.self))", - for: indexPath - ) as! TeamTableViewCell - cell.setModel(viewModel.teamList[indexPath.row]) - return cell + UITableViewCell() } public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { diff --git a/NEContactUIKit/NEContactUIKit/Classes/Team/ViewModel/TeamListViewModel.swift b/NEContactUIKit/NEContactUIKit/Classes/Team/ViewModel/TeamListViewModel.swift index cf4a8b5a..980053fd 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Team/ViewModel/TeamListViewModel.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Team/ViewModel/TeamListViewModel.swift @@ -3,7 +3,7 @@ // found in the LICENSE file. import Foundation -import NEContactKit +import NEChatKit import NECoreKit import NECoreIMKit diff --git a/NEContactUIKit/NEContactUIKit/Classes/UserInfo/UserInfoHeaderView.swift b/NEContactUIKit/NEContactUIKit/Classes/UserInfo/UserInfoHeaderView.swift deleted file mode 100644 index 19e1ddf4..00000000 --- a/NEContactUIKit/NEContactUIKit/Classes/UserInfo/UserInfoHeaderView.swift +++ /dev/null @@ -1,106 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NECoreIMKit - -@objcMembers -public class UserInfoHeaderView: UIView { - public var avatarImage = UIImageView() - public var nameLabel = UILabel() - public var titleLabel = UILabel() - public var detailLabel = UILabel() - lazy var lineView: UIView = { - let view = UIView() - view.backgroundColor = .ne_greyLine - view.translatesAutoresizingMaskIntoConstraints = false - return view - }() - - override init(frame: CGRect) { - super.init(frame: frame) - backgroundColor = .white - avatarImage.layer.cornerRadius = 30 - avatarImage.backgroundColor = UIColor(hexString: "#537FF4") - avatarImage.translatesAutoresizingMaskIntoConstraints = false - avatarImage.contentMode = .scaleAspectFill - avatarImage.clipsToBounds = true - addSubview(avatarImage) - NSLayoutConstraint.activate([ - avatarImage.leftAnchor.constraint(equalTo: leftAnchor, constant: 20), - avatarImage.widthAnchor.constraint(equalToConstant: 60), - avatarImage.heightAnchor.constraint(equalToConstant: 60), - avatarImage.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 0), - ]) - - nameLabel.textAlignment = .center - nameLabel.translatesAutoresizingMaskIntoConstraints = false - nameLabel.font = UIFont.systemFont(ofSize: 22) - nameLabel.textColor = .white - addSubview(nameLabel) - NSLayoutConstraint.activate([ - nameLabel.leftAnchor.constraint(equalTo: avatarImage.leftAnchor), - nameLabel.rightAnchor.constraint(equalTo: avatarImage.rightAnchor), - nameLabel.topAnchor.constraint(equalTo: avatarImage.topAnchor), - nameLabel.bottomAnchor.constraint(equalTo: avatarImage.bottomAnchor), - ]) - - titleLabel.translatesAutoresizingMaskIntoConstraints = false - titleLabel.font = UIFont.boldSystemFont(ofSize: 22) - titleLabel.textColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1.0) - addSubview(titleLabel) - NSLayoutConstraint.activate([ - titleLabel.leftAnchor.constraint(equalTo: avatarImage.rightAnchor, constant: 20), - titleLabel.rightAnchor.constraint(equalTo: rightAnchor, constant: -35), - titleLabel.topAnchor.constraint(equalTo: avatarImage.topAnchor), - titleLabel.heightAnchor.constraint(equalToConstant: 25), - ]) - - detailLabel.translatesAutoresizingMaskIntoConstraints = false - detailLabel.font = UIFont.boldSystemFont(ofSize: 16) - detailLabel.textColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1.0) - addSubview(detailLabel) - NSLayoutConstraint.activate([ - detailLabel.leftAnchor.constraint(equalTo: titleLabel.leftAnchor), - detailLabel.rightAnchor.constraint(equalTo: titleLabel.rightAnchor), - detailLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 8), - detailLabel.heightAnchor.constraint(equalToConstant: 22), - ]) - - addSubview(lineView) - NSLayoutConstraint.activate([ - lineView.leftAnchor.constraint(equalTo: leftAnchor), - lineView.rightAnchor.constraint(equalTo: rightAnchor), - lineView.bottomAnchor.constraint(equalTo: bottomAnchor), - lineView.heightAnchor.constraint(equalToConstant: 6), - ]) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - public func setData(user: User?) { - guard let user = user else { - return - } - - // avatar - if let imageUrl = user.userInfo?.avatarUrl, !imageUrl.isEmpty { - avatarImage.sd_setImage(with: URL(string: imageUrl), completed: nil) - nameLabel.isHidden = true - } else { - avatarImage.sd_setImage(with: nil) - avatarImage.backgroundColor = UIColor.colorWithString(string: user.userId) - nameLabel.text = user.shortName(showAlias: false, count: 2) - nameLabel.isHidden = false - } - - // title - titleLabel.text = user.showName() - - detailLabel.text = "\(localizable("account")):\(user.userId ?? "")" - } -} diff --git a/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/CenterTextCell.swift b/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/CenterTextCell.swift index 8a4f38be..b6137a5f 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/CenterTextCell.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/CenterTextCell.swift @@ -5,7 +5,7 @@ import UIKit @objcMembers -public class CenterTextCell: UITableViewCell { +open class CenterTextCell: UITableViewCell { public var titleLabel: UILabel = .init() public var line = UIView() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { @@ -34,7 +34,7 @@ public class CenterTextCell: UITableViewCell { ]) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } diff --git a/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/ContactBaseTextCell.swift b/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/ContactBaseTextCell.swift index bc9c183d..0362b53e 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/ContactBaseTextCell.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/ContactBaseTextCell.swift @@ -5,7 +5,7 @@ import UIKit @objcMembers -public class ContactBaseTextCell: UITableViewCell { +open class ContactBaseTextCell: UITableViewCell { public var titleLabel: UILabel = .init() public var line = UIView() @@ -19,7 +19,7 @@ public class ContactBaseTextCell: UITableViewCell { contentView.addSubview(titleLabel) NSLayoutConstraint.activate([ titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20), - titleLabel.widthAnchor.constraint(equalToConstant: 100), + titleLabel.widthAnchor.constraint(equalToConstant: 90), titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor), titleLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), ]) @@ -36,7 +36,7 @@ public class ContactBaseTextCell: UITableViewCell { ]) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/TextWithDetailTextCell.swift b/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/TextWithDetailTextCell.swift index 3286b9b8..d422ac69 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/TextWithDetailTextCell.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/TextWithDetailTextCell.swift @@ -5,7 +5,7 @@ import UIKit @objcMembers -public class TextWithDetailTextCell: ContactBaseTextCell { +open class TextWithDetailTextCell: ContactBaseTextCell { public var detailTitleLabel = UILabel() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { @@ -13,9 +13,10 @@ public class TextWithDetailTextCell: ContactBaseTextCell { detailTitleLabel.translatesAutoresizingMaskIntoConstraints = false detailTitleLabel.font = UIFont.systemFont(ofSize: 12) detailTitleLabel.textColor = UIColor(hexString: "#A6ADB6") + detailTitleLabel.textAlignment = .right contentView.addSubview(detailTitleLabel) NSLayoutConstraint.activate([ - detailTitleLabel.leftAnchor.constraint(equalTo: titleLabel.rightAnchor, constant: 20), + detailTitleLabel.leftAnchor.constraint(equalTo: titleLabel.rightAnchor), detailTitleLabel.rightAnchor.constraint( equalTo: contentView.rightAnchor, constant: -20 @@ -25,7 +26,7 @@ public class TextWithDetailTextCell: ContactBaseTextCell { ]) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } diff --git a/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/TextWithRightArrowCell.swift b/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/TextWithRightArrowCell.swift index 8fa3ddf5..09aadb5c 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/TextWithRightArrowCell.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/TextWithRightArrowCell.swift @@ -5,7 +5,7 @@ import UIKit @objcMembers -public class TextWithRightArrowCell: ContactBaseTextCell { +open class TextWithRightArrowCell: ContactBaseTextCell { public var arrowImage = UIImageView(image: UIImage.ne_imageNamed(name: "arrowRight")) override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { @@ -21,7 +21,7 @@ public class TextWithRightArrowCell: ContactBaseTextCell { ]) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/TextWithSwitchCell.swift b/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/TextWithSwitchCell.swift index ae188ee3..6b4b44e6 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/TextWithSwitchCell.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/UserInfo/Views/TextWithSwitchCell.swift @@ -7,7 +7,7 @@ import UIKit public typealias ValueChangeBlock = (_ title: String?, _ value: Bool) -> Void @objcMembers -public class TextWithSwitchCell: ContactBaseTextCell { +open class TextWithSwitchCell: ContactBaseTextCell { public var block: ValueChangeBlock? public var switchButton = UISwitch() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { @@ -25,7 +25,7 @@ public class TextWithSwitchCell: ContactBaseTextCell { ]) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/NEContactUIKit/NEContactUIKit/Classes/Validation/ViewController/ValidationMessageViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/Validation/Controller/NEBaseValidationMessageViewController.swift similarity index 81% rename from NEContactUIKit/NEContactUIKit/Classes/Validation/ViewController/ValidationMessageViewController.swift rename to NEContactUIKit/NEContactUIKit/Classes/Validation/Controller/NEBaseValidationMessageViewController.swift index fececd04..6cb42311 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Validation/ViewController/ValidationMessageViewController.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Validation/Controller/NEBaseValidationMessageViewController.swift @@ -1,4 +1,3 @@ - // Copyright (c) 2022 NetEase, Inc. All rights reserved. // Use of this source code is governed by a MIT license that can be // found in the LICENSE file. @@ -8,19 +7,13 @@ import NECoreKit import NECoreIMKit @objcMembers -public class ValidationMessageViewController: ContactBaseViewController { - let viewModel = ValidationMessageViewModel() - - let tableView = UITableView() - private let tag = "ValidationMessageViewController" +open class NEBaseValidationMessageViewController: NEBaseContactViewController { + public let viewModel = ValidationMessageViewModel() + public let tableView = UITableView() + var tag = "ValidationMessageViewController" - override public func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() - - // Do any additional setup after loading the view. - title = localizable("validation_message") - emptyView.setttingContent(content: localizable("no_validation_message")) - // viewModel.getValidationMessage() setupUI() loadData() @@ -34,7 +27,7 @@ public class ValidationMessageViewController: ContactBaseViewController { } // 返回上一级页面 - override func backToPrevious() { + override open func backToPrevious() { super.backToPrevious() viewModel.clearNotiUnreadCount() } @@ -53,7 +46,7 @@ public class ValidationMessageViewController: ContactBaseViewController { } } - func setupUI() { + open func setupUI() { let clearItem = UIBarButtonItem( title: localizable("clear"), style: .done, @@ -67,6 +60,12 @@ public class ValidationMessageViewController: ContactBaseViewController { clearItem.setTitleTextAttributes(textAttributes, for: .normal) navigationItem.rightBarButtonItem = clearItem + title = localizable("validation_message") + customNavigationView.navTitle.text = title + customNavigationView.setMoreButtonTitle(localizable("clear")) + customNavigationView.moreButton.setTitleColor(.ne_darkText, for: .normal) + customNavigationView.addMoreButtonTarget(target: self, selector: #selector(clearMessage)) + tableView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(tableView) tableView.dataSource = self @@ -74,17 +73,13 @@ public class ValidationMessageViewController: ContactBaseViewController { tableView.separatorStyle = .none NSLayoutConstraint.activate([ - tableView.topAnchor.constraint(equalTo: view.topAnchor), + tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: NEConstant.navigationAndStatusHeight), tableView.leftAnchor.constraint(equalTo: view.leftAnchor), tableView.rightAnchor.constraint(equalTo: view.rightAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) - tableView.register( - SystemNotificationCell.self, - forCellReuseIdentifier: "\(SystemNotificationCell.self)" - ) - + emptyView.settingContent(content: localizable("no_validation_message")) view.addSubview(emptyView) NSLayoutConstraint.activate([ emptyView.topAnchor.constraint(equalTo: tableView.topAnchor, constant: 100), @@ -101,34 +96,31 @@ public class ValidationMessageViewController: ContactBaseViewController { emptyView.isHidden = false } } + + public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + viewModel.clearNotiUnreadCount() + return true + } } -extension ValidationMessageViewController: UITableViewDelegate, UITableViewDataSource { - public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { +extension NEBaseValidationMessageViewController: UITableViewDelegate, UITableViewDataSource { + open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { viewModel.datas.count } - public func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let noti = viewModel.datas[indexPath.row] - let reuseIdentifier = "\(SystemNotificationCell.self)" - let cell = tableView.dequeueReusableCell( - withIdentifier: reuseIdentifier, - for: indexPath - ) as! SystemNotificationCell - cell.delegate = self - cell.confige(noti) - return cell + open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + UITableViewCell() } - public func tableView(_ tableView: UITableView, - heightForRowAt indexPath: IndexPath) -> CGFloat { + open func tableView(_ tableView: UITableView, + heightForRowAt indexPath: IndexPath) -> CGFloat { 60 } } -extension ValidationMessageViewController: SystemNotificationCellDelegate { - func changeValidationStatus(notifiModel: XNotification, notiStatus: IMHandleStatus) { +extension NEBaseValidationMessageViewController: SystemNotificationCellDelegate { + public func changeValidationStatus(notifiModel: XNotification, notiStatus: IMHandleStatus) { var notifiModels = [XNotification]() if let msgList = notifiModel.msgList, msgList.count > 0 { @@ -149,7 +141,7 @@ extension ValidationMessageViewController: SystemNotificationCellDelegate { loadData() } - func onAccept(_ notifiModel: XNotification) { + open func onAccept(_ notifiModel: XNotification) { weak var weakSelf = self guard let teamId = notifiModel.targetID, let invitorId = notifiModel.sourceID else { return @@ -194,7 +186,7 @@ extension ValidationMessageViewController: SystemNotificationCellDelegate { } } - func onRefuse(_ notifiModel: XNotification) { + open func onRefuse(_ notifiModel: XNotification) { weak var weakSelf = self guard let teamId = notifiModel.targetID, let invitorId = notifiModel.sourceID else { return diff --git a/NEContactUIKit/NEContactUIKit/Classes/Validation/ViewModel/ValidationMessageViewModel.swift b/NEContactUIKit/NEContactUIKit/Classes/Validation/ViewModel/ValidationMessageViewModel.swift index ded62392..dab28fec 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Validation/ViewModel/ValidationMessageViewModel.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Validation/ViewModel/ValidationMessageViewModel.swift @@ -3,7 +3,7 @@ // found in the LICENSE file. import Foundation -import NEContactKit +import NEChatKit import NECoreIMKit import NECoreKit @@ -105,9 +105,9 @@ public class ValidationMessageViewModel: NSObject, ContactRepoSystemNotiDelegate for xNoti in xNotiList { var noti = xNoti - // 过期事件:7天(10080s) + // 过期事件:7天(604800s) if noti.handleStatus == .HandleTypePending, - dateNow - (noti.timestamp ?? 0) > 10080 { + dateNow - (noti.timestamp ?? 0) > 604_800 { noti.handleStatus = .HandleTypeOutOfDate } diff --git a/NEContactUIKit/NEContactUIKit/Classes/Validation/Views/SystemNotificationCell.swift b/NEContactUIKit/NEContactUIKit/Classes/Validation/Views/NEBaseSystemNotificationCell.swift similarity index 87% rename from NEContactUIKit/NEContactUIKit/Classes/Validation/Views/SystemNotificationCell.swift rename to NEContactUIKit/NEContactUIKit/Classes/Validation/Views/NEBaseSystemNotificationCell.swift index af25da2d..093389b6 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Validation/Views/SystemNotificationCell.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Validation/Views/NEBaseSystemNotificationCell.swift @@ -9,32 +9,20 @@ import NECommonUIKit import NECoreIMKit import NIMSDK -protocol SystemNotificationCellDelegate: AnyObject { - func onAccept(_ notifiModel: XNotification) - func onRefuse(_ notifiModel: XNotification) -} - -enum NotificationHandleType: Int { - case Pending = 0 - case agree - case refuse - case OutOfDate -} - @objcMembers -public class SystemNotificationCell: BaseValidationCell { +open class NEBaseSystemNotificationCell: NEBaseValidationCell { private var notifModel: XNotification? - weak var delegate: SystemNotificationCellDelegate? + public weak var delegate: SystemNotificationCellDelegate? - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } - override func setupUI() { + override open func setupUI() { super.setupUI() contentView.addSubview(agreeBtn) contentView.addSubview(rejectBtn) @@ -70,7 +58,7 @@ public class SystemNotificationCell: BaseValidationCell { ]) } - override public func confige(_ model: XNotification) { + override open func confige(_ model: XNotification) { super.confige(model) notifModel = model let hideActionButton = shouldHideActionButton() @@ -137,7 +125,7 @@ public class SystemNotificationCell: BaseValidationCell { } } - var rejectBtn: ExpandButton = { + public var rejectBtn: ExpandButton = { let button = ExpandButton() button.translatesAutoresizingMaskIntoConstraints = false button.setTitle(localizable("refuse"), for: .normal) @@ -150,7 +138,7 @@ public class SystemNotificationCell: BaseValidationCell { return button }() - var agreeBtn: ExpandButton = { + public var agreeBtn: ExpandButton = { let button = ExpandButton() button.translatesAutoresizingMaskIntoConstraints = false button.setTitle(localizable("agree"), for: .normal) @@ -164,14 +152,14 @@ public class SystemNotificationCell: BaseValidationCell { return button }() - private lazy var resultImage: UIImageView = { + public lazy var resultImage: UIImageView = { let rightImage = UIImageView() rightImage.translatesAutoresizingMaskIntoConstraints = false rightImage.image = UIImage.ne_imageNamed(name: "finishFlag") return rightImage }() - private lazy var resultLabel: UILabel = { + public lazy var resultLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.textColor = UIColor(hexString: "B3B7BC") @@ -180,13 +168,13 @@ public class SystemNotificationCell: BaseValidationCell { return label }() - func rejectClick(_ sender: UIButton) { + open func rejectClick(_ sender: UIButton) { if let model = notifModel { delegate?.onRefuse(model) } } - func agreeClick(_ sender: UIButton) { + open func agreeClick(_ sender: UIButton) { if let model = notifModel { delegate?.onAccept(model) } diff --git a/NEContactUIKit/NEContactUIKit/Classes/Validation/Views/BaseValidationCell.swift b/NEContactUIKit/NEContactUIKit/Classes/Validation/Views/NEBaseValidationCell.swift similarity index 89% rename from NEContactUIKit/NEContactUIKit/Classes/Validation/Views/BaseValidationCell.swift rename to NEContactUIKit/NEContactUIKit/Classes/Validation/Views/NEBaseValidationCell.swift index 6ece33fe..58efc226 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Validation/Views/BaseValidationCell.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Validation/Views/NEBaseValidationCell.swift @@ -7,9 +7,22 @@ import UIKit import NECoreIMKit import NIMSDK +public protocol SystemNotificationCellDelegate: AnyObject { + func onAccept(_ notifiModel: XNotification) + func onRefuse(_ notifiModel: XNotification) +} + +enum NotificationHandleType: Int { + case Pending = 0 + case agree + case refuse + case OutOfDate +} + @objcMembers -public class BaseValidationCell: ContactBaseViewCell { +open class NEBaseValidationCell: NEBaseContactViewCell { public var titleLabelRightMargin: NSLayoutConstraint? + let line = UIView() override public func awakeFromNib() { super.awakeFromNib() @@ -27,11 +40,11 @@ public class BaseValidationCell: ContactBaseViewCell { setupUI() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } - func setupUI() { + open func setupUI() { setupCommonCircleHeader() contentView.addSubview(redAngleView) @@ -59,7 +72,6 @@ public class BaseValidationCell: ContactBaseViewCell { optionLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -180), ]) - let line = UIView() addSubview(line) line.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ @@ -71,7 +83,7 @@ public class BaseValidationCell: ContactBaseViewCell { line.backgroundColor = UIColor(hexString: "#F5F8FC") } - public func confige(_ model: XNotification) { + open func confige(_ model: XNotification) { var optionLabelContent = "" var nickName = "" var teamName = "" @@ -97,9 +109,11 @@ public class BaseValidationCell: ContactBaseViewCell { if let headerUrl = model.userInfo?.userInfo?.avatarUrl, !headerUrl.isEmpty { avatarImage.sd_setImage(with: URL(string: headerUrl), completed: nil) nameLabel.text = "" + avatarImage.backgroundColor = .clear } else if let teamUrl = model.teamInfo?.avatarUrl, !teamUrl.isEmpty { avatarImage.sd_setImage(with: URL(string: teamUrl), completed: nil) nameLabel.text = "" + avatarImage.backgroundColor = .clear } else { // 无头像设置其name if !nickName.isEmpty { @@ -110,6 +124,7 @@ public class BaseValidationCell: ContactBaseViewCell { } } avatarImage.sd_setImage(with: URL(string: ""), completed: nil) + avatarImage.backgroundColor = UIColor.colorWithString(string: model.userInfo?.userId) } // 设置未读状态(未读数角标+底色) diff --git a/NEContactUIKit/NEContactUIKit/Classes/ViewModel/ContactGroup.swift b/NEContactUIKit/NEContactUIKit/Classes/ViewModel/ContactGroup.swift index ce67ca0c..bfbec8e0 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/ViewModel/ContactGroup.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/ViewModel/ContactGroup.swift @@ -5,4 +5,5 @@ import Foundation +@objcMembers public class ContactGroup {} diff --git a/NEContactUIKit/NEContactUIKit/Classes/ViewModel/ContactUserViewModel.swift b/NEContactUIKit/NEContactUIKit/Classes/ViewModel/ContactUserViewModel.swift index ec9ef843..4d2ea531 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/ViewModel/ContactUserViewModel.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/ViewModel/ContactUserViewModel.swift @@ -3,7 +3,7 @@ // found in the LICENSE file. import Foundation -import NEContactKit +import NEChatKit import NECoreKit import NECoreIMKit import CoreMedia @@ -52,4 +52,12 @@ public class ContactUserViewModel: NSObject { completion(error, users?.first) } } + + public func fetchUserInfo(accountList: [String], + _ completion: @escaping ([User]?, NSError?) -> Void) { + NELog.infoLog(ModuleName + " " + className, desc: #function + ", uid: \(accountList)") + contactRepo.fetchUserInfo(accountList: accountList) { users, error in + completion(users, error) + } + } } diff --git a/NEContactUIKit/NEContactUIKit/Classes/ViewModel/ContactViewModel.swift b/NEContactUIKit/NEContactUIKit/Classes/ViewModel/ContactViewModel.swift index fc6b092b..0a308e95 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/ViewModel/ContactViewModel.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/ViewModel/ContactViewModel.swift @@ -3,7 +3,7 @@ // found in the LICENSE file. import Foundation -import NEContactKit +import NEChatKit import NECoreKit import NECoreIMKit import UIKit @@ -43,7 +43,7 @@ public class ContactViewModel: NSObject, ContactRepoSystemNotiDelegate { public func onRecieveNotification(_ notification: XNotification) {} - func loadData(fetch: Bool = false, _ filters: Set? = nil, completion: @escaping (NSError?) -> Void) { + func loadData(fetch: Bool = false, _ filters: Set? = nil, completion: @escaping (NSError?, Int) -> Void) { NELog.infoLog(ModuleName + " " + className, desc: #function) weak var weakSelf = self getContactList(fetch, filters) { contacts, error in @@ -54,12 +54,12 @@ public class ContactViewModel: NSObject, ContactRepoSystemNotiDelegate { if let headSection = weakSelf?.headerSection(headerItem: weakSelf?.contactHeaders) { weakSelf?.contacts.insert(headSection, at: 0) } - completion(nil) + completion(nil, users.count) } } } - func reLoadData(completion: @escaping (NSError?) -> Void) { + func reLoadData(completion: @escaping (NSError?, Int) -> Void) { loadData(fetch: true, completion: completion) } @@ -67,7 +67,11 @@ public class ContactViewModel: NSObject, ContactRepoSystemNotiDelegate { NELog.infoLog(ModuleName + " " + className, desc: #function + ", filters.count: \(filters?.count ?? 0)") var contactList: [ContactSection] = [] weak var weakSelf = self - contactRepo.getFriendList(fetch) { friends, error in + var local = false + if NEChatDetectNetworkTool.shareInstance.manager?.isReachable == false { + local = true + } + contactRepo.getFriendList(fetch, local: local) { friends, error in if var users = friends { NELog.infoLog("contact bar getFriendList", desc: "friend count:\(friends?.count)") weakSelf?.initalDict = [String: [ContactInfo]]() @@ -99,7 +103,7 @@ public class ContactViewModel: NSObject, ContactRepoSystemNotiDelegate { let inital = name?.initalLetter() ?? "#" let contactInfo = ContactInfo() contactInfo.user = contact - contactInfo.headerBackColor = UIColor.colorWithString(string: contact.showName() ?? "") + contactInfo.headerBackColor = UIColor.colorWithString(string: contact.userId ?? "") if digitRegular.evaluate(with: inital) { // [0-9] digitList.append(contactInfo) @@ -137,7 +141,11 @@ public class ContactViewModel: NSObject, ContactRepoSystemNotiDelegate { var result = contactList.sorted { s1, s2 in s1.initial < s2.initial } - result.append(ContactSection(initial: "#", contacts: digitList + specialCharList)) + + let specialList = digitList + specialCharList + if specialList.count > 0 { + result.append(ContactSection(initial: "#", contacts: specialList)) + } completion(result, nil) } } diff --git a/NEContactUIKit/NEContactUIKit/Classes/ViewModel/FindFriendViewModel.swift b/NEContactUIKit/NEContactUIKit/Classes/ViewModel/FindFriendViewModel.swift index 6c3672a5..0adbdc00 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/ViewModel/FindFriendViewModel.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/ViewModel/FindFriendViewModel.swift @@ -3,7 +3,7 @@ // found in the LICENSE file. import Foundation -import NEContactKit +import NEChatKit import NECoreKit import NECoreIMKit diff --git a/NEContactUIKit/NEContactUIKit/Classes/Views/Cell/ContactSelectedCell.swift b/NEContactUIKit/NEContactUIKit/Classes/Views/Cell/NEBaseContactSelectedCell.swift similarity index 76% rename from NEContactUIKit/NEContactUIKit/Classes/Views/Cell/ContactSelectedCell.swift rename to NEContactUIKit/NEContactUIKit/Classes/Views/Cell/NEBaseContactSelectedCell.swift index 46a0fd26..a0068eaf 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Views/Cell/ContactSelectedCell.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Views/Cell/NEBaseContactSelectedCell.swift @@ -5,7 +5,7 @@ import UIKit @objcMembers -public class ContactSelectedCell: ContactTableViewCell { +open class NEBaseContactSelectedCell: NEBaseContactTableViewCell { let sImage = UIImageView() var sModel: ContactInfo? @@ -21,17 +21,12 @@ public class ContactSelectedCell: ContactTableViewCell { // Configure the view for the selected state } - override func commonUI() { + override open func commonUI() { super.commonUI() leftConstraint?.constant = 50 contentView.addSubview(sImage) sImage.image = UIImage.ne_imageNamed(name: "unselect") - sImage.highlightedImage = UIImage.ne_imageNamed(name: "select") sImage.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - sImage.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - sImage.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20), - ]) } override public func setModel(_ model: ContactInfo) { diff --git a/NEContactUIKit/NEContactUIKit/Classes/Views/ContactTableViewCell.swift b/NEContactUIKit/NEContactUIKit/Classes/Views/Cell/NEBaseContactTableViewCell.swift similarity index 80% rename from NEContactUIKit/NEContactUIKit/Classes/Views/ContactTableViewCell.swift rename to NEContactUIKit/NEContactUIKit/Classes/Views/Cell/NEBaseContactTableViewCell.swift index aac37ebe..8cb25674 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Views/ContactTableViewCell.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Views/Cell/NEBaseContactTableViewCell.swift @@ -9,7 +9,7 @@ import Foundation import NECoreKit @objcMembers -open class ContactTableViewCell: ContactBaseViewCell, ContactCellDataProtrol { +open class NEBaseContactTableViewCell: NEBaseContactViewCell, ContactCellDataProtrol { public lazy var arrow: UIImageView = { let imageView = UIImageView(image: UIImage.ne_imageNamed(name: "arrowRight")) imageView.translatesAutoresizingMaskIntoConstraints = false @@ -17,6 +17,12 @@ open class ContactTableViewCell: ContactBaseViewCell, ContactCellDataProtrol { return imageView }() + public lazy var bottomLine: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) commonUI() @@ -27,8 +33,7 @@ open class ContactTableViewCell: ContactBaseViewCell, ContactCellDataProtrol { fatalError("init(coder:) has not been implemented") } - func commonUI() { - // circle avatar head image with name suffix string + open func commonUI() { setupCommonCircleHeader() contentView.addSubview(titleLabel) @@ -47,6 +52,14 @@ open class ContactTableViewCell: ContactBaseViewCell, ContactCellDataProtrol { arrow.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), ]) + contentView.addSubview(bottomLine) + NSLayoutConstraint.activate([ + bottomLine.leftAnchor.constraint(equalTo: avatarImage.leftAnchor), + bottomLine.rightAnchor.constraint(equalTo: contentView.rightAnchor), + bottomLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + bottomLine.heightAnchor.constraint(equalToConstant: 1), + ]) + contentView.addSubview(redAngleView) NSLayoutConstraint.activate([ redAngleView.centerYAnchor.constraint(equalTo: arrow.centerYAnchor), @@ -54,16 +67,17 @@ open class ContactTableViewCell: ContactBaseViewCell, ContactCellDataProtrol { ]) } - func initSubviewsLayout() { + open func initSubviewsLayout() { if NEKitContactConfig.shared.ui.avatarType == .rectangle { avatarImage.layer.cornerRadius = NEKitContactConfig.shared.ui.avatarCornerRadius } else if NEKitContactConfig.shared.ui.avatarType == .cycle { avatarImage.layer.cornerRadius = 18.0 + } else { + avatarImage.layer.cornerRadius = 18.0 // Normal UI } } - func setConfig() { - titleLabel.font = NEKitContactConfig.shared.ui.titleFont + open func setConfig() { titleLabel.textColor = NEKitContactConfig.shared.ui.titleColor nameLabel.font = UIFont.systemFont(ofSize: 14.0) nameLabel.textColor = UIColor.white @@ -75,8 +89,15 @@ open class ContactTableViewCell: ContactBaseViewCell, ContactCellDataProtrol { } setConfig() - if model.contactCellType == 2 { - // person + if model.contactCellType == 1 { + NELog.infoLog("contact other cell configData", desc: "\(user.alias), image name:\(user.userInfo?.avatarUrl)") + nameLabel.text = "" + titleLabel.text = user.alias + avatarImage.image = UIImage.ne_imageNamed(name: user.userInfo?.avatarUrl) + avatarImage.backgroundColor = model.headerBackColor + arrow.isHidden = false + } else { + // person、custom titleLabel.text = user.showName() nameLabel.text = user.shortName(showAlias: false, count: 2) @@ -91,14 +112,6 @@ open class ContactTableViewCell: ContactBaseViewCell, ContactCellDataProtrol { avatarImage.backgroundColor = model.headerBackColor } arrow.isHidden = true - - } else { - NELog.infoLog("contact other cell configData", desc: "\(user.alias), image name:\(user.userInfo?.avatarUrl)") - nameLabel.text = "" - titleLabel.text = user.alias - avatarImage.image = UIImage.ne_imageNamed(name: user.userInfo?.avatarUrl) - avatarImage.backgroundColor = model.headerBackColor - arrow.isHidden = false } } } diff --git a/NEContactUIKit/NEContactUIKit/Classes/Views/Cell/ContactUnCheckCell.swift b/NEContactUIKit/NEContactUIKit/Classes/Views/Cell/NEBaseContactUnCheckCell.swift similarity index 61% rename from NEContactUIKit/NEContactUIKit/Classes/Views/Cell/ContactUnCheckCell.swift rename to NEContactUIKit/NEContactUIKit/Classes/Views/Cell/NEBaseContactUnCheckCell.swift index 9717d03c..fe95169d 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Views/Cell/ContactUnCheckCell.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Views/Cell/NEBaseContactUnCheckCell.swift @@ -6,30 +6,23 @@ import UIKit import NECommonUIKit @objcMembers -public class ContactUnCheckCell: UICollectionViewCell { +open class NEBaseContactUnCheckCell: UICollectionViewCell { override init(frame: CGRect) { super.init(frame: frame) setupUI() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } func setupUI() { contentView.addSubview(avatarImage) - NSLayoutConstraint.activate([ - avatarImage.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - avatarImage.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), - avatarImage.widthAnchor.constraint(equalToConstant: 36), - avatarImage.heightAnchor.constraint(equalToConstant: 36), - ]) } lazy var avatarImage: NEUserHeaderView = { let view = NEUserHeaderView(frame: .zero) view.titleLabel.font = UIFont.systemFont(ofSize: 16.0) - view.layer.cornerRadius = 18 view.clipsToBounds = true view.translatesAutoresizingMaskIntoConstraints = false return view @@ -38,7 +31,8 @@ public class ContactUnCheckCell: UICollectionViewCell { func configure(_ model: ContactInfo) { avatarImage.configHeadData( headUrl: model.user?.userInfo?.avatarUrl, - name: model.user?.showName() ?? "" + name: model.user?.showName() ?? "", + uid: model.user?.userId ?? "" ) } } diff --git a/NEContactUIKit/NEContactUIKit/Classes/Views/ContactBaseViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/Views/ContactBaseViewController.swift deleted file mode 100644 index aac9390a..00000000 --- a/NEContactUIKit/NEContactUIKit/Classes/Views/ContactBaseViewController.swift +++ /dev/null @@ -1,56 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit - -@objcMembers -open class ContactBaseViewController: UIViewController { - lazy var emptyView: NEEmptyDataView = { - let view = NEEmptyDataView( - imageName: "user_empty", - content: "", - frame: CGRect.zero - ) - view.translatesAutoresizingMaskIntoConstraints = false - view.isHidden = true - return view - - }() - - override public func viewDidLoad() { - super.viewDidLoad() - - // Do any additional setup after loading the view. - view.backgroundColor = .white - edgesForExtendedLayout = [] - - setupBackUI() - } - - private func setupBackUI() { - navigationController?.navigationBar.tintColor = .white - let backItem = UIBarButtonItem( - image: UIImage.ne_imageNamed(name: "backArrow"), - style: .plain, - target: self, - action: #selector(backToPrevious) - ) - backItem.tintColor = UIColor(hexString: "333333") - navigationItem.leftBarButtonItem = backItem - } - - func backToPrevious() { - navigationController?.popViewController(animated: true) - } - /* - // MARK: - Navigation - - // In a storyboard-based application, you will often want to do a little preparation before navigation - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - // Get the new view controller using segue.destination. - // Pass the selected object to the new view controller. - } - */ -} diff --git a/NEContactUIKit/NEContactUIKit/Classes/Views/ContactHeadItem.swift b/NEContactUIKit/NEContactUIKit/Classes/Views/ContactHeadItem.swift index 9e325ef0..c8be407c 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Views/ContactHeadItem.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Views/ContactHeadItem.swift @@ -5,7 +5,8 @@ import Foundation -public class ContactHeadItem { +@objcMembers +open class ContactHeadItem { public var name: String? public var imageName: String? public var color = UIColor(hexString: "#60CFA7") diff --git a/NEContactUIKit/NEContactUIKit/Classes/Views/ContactSectionView.swift b/NEContactUIKit/NEContactUIKit/Classes/Views/ContactSectionView.swift index db6feaa9..9e9fbd4e 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Views/ContactSectionView.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Views/ContactSectionView.swift @@ -6,7 +6,7 @@ import UIKit @objcMembers -public class ContactSectionView: UITableViewHeaderFooterView { +open class ContactSectionView: UITableViewHeaderFooterView { public var titleLabel = UILabel() var line = UIView() @@ -15,32 +15,32 @@ public class ContactSectionView: UITableViewHeaderFooterView { commonUI() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func commonUI() { contentView.backgroundColor = .white titleLabel.translatesAutoresizingMaskIntoConstraints = false - - titleLabel.textColor = NEKitContactConfig.shared.ui.indexTitleColor + titleLabel.backgroundColor = .white + titleLabel.textColor = NEKitContactConfig.shared.ui.indexTitleColor ?? UIColor.ne_emptyTitleColor titleLabel.font = UIFont.systemFont(ofSize: 14.0) - addSubview(titleLabel) + contentView.addSubview(titleLabel) NSLayoutConstraint.activate([ - titleLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 20), - titleLabel.topAnchor.constraint(equalTo: topAnchor), - titleLabel.bottomAnchor.constraint(equalTo: bottomAnchor), - titleLabel.rightAnchor.constraint(equalTo: rightAnchor, constant: -20), + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20), + titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor), + titleLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: 20), ]) line.translatesAutoresizingMaskIntoConstraints = false line.backgroundColor = NEKitContactConfig.shared.ui.divideLineColor - addSubview(line) + contentView.addSubview(line) NSLayoutConstraint.activate([ line.leftAnchor.constraint(equalTo: titleLabel.leftAnchor), line.heightAnchor.constraint(equalToConstant: 1.0), - line.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -1.0), - line.rightAnchor.constraint(equalTo: rightAnchor), + line.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0), + line.rightAnchor.constraint(equalTo: contentView.rightAnchor), ]) } } diff --git a/NEContactUIKit/NEContactUIKit/Classes/Views/ContactsSelectedViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/Views/ContactsSelectedViewController.swift deleted file mode 100644 index f4b35993..00000000 --- a/NEContactUIKit/NEContactUIKit/Classes/Views/ContactsSelectedViewController.swift +++ /dev/null @@ -1,331 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NECoreKit -import NIMSDK - -@objcMembers -open class ContactsSelectedViewController: ContactBaseViewController { - public var callBack: ContactsSelectCompletion? - - public var filterUsers: Set? - var lastTitleIndex = 0 - public var limit = 10 // max select count - - // 单聊中对方的userId - public var userId: String? - - var selectArray = [ContactInfo]() - let selectDic = [String: ContactInfo]() - lazy var collection: UICollectionView = { - let layout = UICollectionViewFlowLayout() - layout.scrollDirection = .horizontal - layout.minimumLineSpacing = 0 - layout.minimumInteritemSpacing = 0 - let collect = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout) - collect.contentInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5) - return collect - }() - - let sureBtn = UIButton(frame: CGRect(x: 0, y: 0, width: 80, height: 44)) - - var collectionHeight: NSLayoutConstraint? - - public var customCells: [Int: ContactTableViewCell.Type] = - [ContactCellType.ContactPerson.rawValue: ContactSelectedCell.self] // custom ui cell - - let viewModel = ContactViewModel(contactHeaders: nil) - - let tableView = UITableView() - - override public func viewDidLoad() { - super.viewDidLoad() - - // Do any additional setup after loading the view. - title = localizable("select") - emptyView.setttingContent(content: localizable("no_friend")) -// setupUI() -// setupNavRightItem() - -// viewModel.loadData(filterUsers) - weak var weakSelf = self - - viewModel.loadData(filterUsers) { error in - weakSelf?.setupUI() - weakSelf?.setupNavRightItem() - weakSelf?.tableView.reloadData() - weakSelf?.emptyView.isHidden = (weakSelf?.viewModel.contacts.count ?? 0) > 0 - } - } - - override public func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - navigationController?.isNavigationBarHidden = false - } - - func setupUI() { - view.addSubview(collection) - collection.delegate = self - collection.dataSource = self - collection.allowsMultipleSelection = false - collection.translatesAutoresizingMaskIntoConstraints = false - collectionHeight = collection.heightAnchor.constraint(equalToConstant: 0) - collectionHeight?.isActive = true - collection.backgroundColor = UIColor(hexString: "F2F4F5") - NSLayoutConstraint.activate([ - collection.topAnchor.constraint(equalTo: view.topAnchor), - collection.leftAnchor.constraint(equalTo: view.leftAnchor), - collection.rightAnchor.constraint(equalTo: view.rightAnchor), - ]) - collection.register( - ContactUnCheckCell.self, - forCellWithReuseIdentifier: "\(NSStringFromClass(ContactUnCheckCell.self))" - ) - - view.addSubview(tableView) - tableView.delegate = self - tableView.dataSource = self - tableView.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - tableView.leftAnchor.constraint(equalTo: view.leftAnchor), - tableView.rightAnchor.constraint(equalTo: view.rightAnchor), - tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), - tableView.topAnchor.constraint(equalTo: collection.bottomAnchor), - ]) - - view.addSubview(emptyView) - NSLayoutConstraint.activate([ - emptyView.topAnchor.constraint(equalTo: tableView.topAnchor), - emptyView.bottomAnchor.constraint(equalTo: tableView.bottomAnchor), - emptyView.leftAnchor.constraint(equalTo: tableView.leftAnchor), - emptyView.rightAnchor.constraint(equalTo: tableView.rightAnchor), - ]) - - customCells.forEach { (key: Int, value: AnyClass) in - if value is ContactCellDataProtrol.Type { - self.tableView.register( - value, - forCellReuseIdentifier: "\(NSStringFromClass(value))" - ) - } - } - tableView.register( - ContactSectionView.self, - forHeaderFooterViewReuseIdentifier: "\(NSStringFromClass(ContactSectionView.self))" - ) - tableView.rowHeight = 52 - tableView.sectionHeaderHeight = 40 - tableView.sectionFooterHeight = 0 - tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 0.1)) - tableView.separatorStyle = .none - } - - func setupNavRightItem() { - let rightItem = UIBarButtonItem(customView: sureBtn) - navigationItem.rightBarButtonItem = rightItem - sureBtn.addTarget(self, action: #selector(sureClick(_:)), for: .touchUpInside) - sureBtn.setTitle(localizable("alert_sure"), for: .normal) - sureBtn.setTitleColor(UIColor(hexString: "337EFF"), for: .normal) - sureBtn.titleLabel?.font = UIFont.systemFont(ofSize: 16.0) - sureBtn.contentHorizontalAlignment = .right - } - - /* - // MARK: - Navigation - - // In a storyboard-based application, you will often want to do a little preparation before navigation - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - // Get the new view controller using segue.destination. - // Pass the selected object to the new view controller. - } - */ -} - -// action -extension ContactsSelectedViewController { - @objc func sureClick(_ sender: UIButton) { - if selectArray.count <= 0 { - showToast(localizable("select_contact")) - return - } - if let completion = callBack { - completion(selectArray) - } - var accids = [String]() - var names = [String]() - - names.append(viewModel.contactRepo.getUserName()) - - var users = [NIMUser]() - for c in selectArray { - accids.append(c.user?.userId ?? "") - if let name = c.user?.userInfo?.nickName { - names.append(name) - } else if let accid = c.user?.userId { - names.append(accid) - } - if let user = c.user?.imUser { - users.append(user) - } - } - - if let uid = userId { - accids.append(uid) - } - let nameString = names.joined(separator: "、") - print("name string : ", nameString) - Router.shared.use( - ContactSelectedUsersRouter, - parameters: ["accids": accids, "names": nameString, "im_user": users], - closure: nil - ) - navigationController?.popViewController(animated: true) - } -} - -extension ContactsSelectedViewController: UICollectionViewDelegate, UICollectionViewDataSource, - UICollectionViewDelegateFlowLayout, UITableViewDelegate, UITableViewDataSource { - // MARK: - Table View DataSource And Delegate - - public func numberOfSections(in tableView: UITableView) -> Int { - viewModel.contacts.count - } - - public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - viewModel.contacts[section].contacts.count - } - - public func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let info = viewModel.contacts[indexPath.section].contacts[indexPath.row] - if let cellClass = customCells[info.contactCellType] { - let anyCell = tableView.dequeueReusableCell( - withIdentifier: "\(NSStringFromClass(cellClass))", - for: indexPath - ) as? ContactTableViewCell - anyCell?.setModel(info) - if let cell = anyCell { - return cell - } - } - return UITableViewCell() - } - - public func tableView(_ tableView: UITableView, - viewForHeaderInSection section: Int) -> UIView? { - let sectionView: ContactSectionView = tableView - .dequeueReusableHeaderFooterView( - withIdentifier: "\(NSStringFromClass(ContactSectionView.self))" - ) as! ContactSectionView - sectionView.titleLabel.text = viewModel.contacts[section].initial - return sectionView - } - - public func tableView(_ tableView: UITableView, - heightForHeaderInSection section: Int) -> CGFloat { - if viewModel.contacts[section].initial.count > 0 { - return 40 - } - return 0 - } - - public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let info = viewModel.contacts[indexPath.section].contacts[indexPath.row] - let cell = tableView.cellForRow(at: indexPath) as? ContactSelectedCell - if info.isSelected == true { - didUnselectContact(info) - cell?.setSelect() - } else { - if selectArray.count >= limit { - view.makeToast("超出\(limit)人限制") - return - } - didSelectContact(info) - cell?.setUnselect() - } - } - - public func sectionIndexTitles(for tableView: UITableView) -> [String]? { - viewModel.indexs - } - - public func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int { - for (i, t) in viewModel.contacts.enumerated() { - if t.initial == title { - lastTitleIndex = i - return i - } - } - return lastTitleIndex - } - - // MARK: Collection View DataSource And Delegate - - public func collectionView(_ collectionView: UICollectionView, - numberOfItemsInSection section: Int) -> Int { - selectArray.count - } - - public func collectionView(_ collectionView: UICollectionView, - didSelectItemAt indexPath: IndexPath) { - let contactInfo = selectArray[indexPath.row] - didUnselectContact(contactInfo) - } - - public func collectionView(_ collectionView: UICollectionView, - cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - let contactInfo = selectArray[indexPath.row] - let cell = collectionView.dequeueReusableCell( - withReuseIdentifier: "\(NSStringFromClass(ContactUnCheckCell.self))", - for: indexPath - ) as? ContactUnCheckCell - cell?.configure(contactInfo) - return cell ?? UICollectionViewCell() - } - - public func collectionView(_ collectionView: UICollectionView, - layout collectionViewLayout: UICollectionViewLayout, - sizeForItemAt indexPath: IndexPath) -> CGSize { - CGSize(width: 46, height: 52) - } - - func didSelectContact(_ contact: ContactInfo) { - contact.isSelected = true - if selectArray.contains(where: { c in - contact === c - }) == false { - selectArray.append(contact) - if let height = collectionHeight?.constant, height <= 0 { - collectionHeight?.constant = 52 - } - } - collection.reloadData() - tableView.reloadData() - refreshSelectCount() - } - - func didUnselectContact(_ contact: ContactInfo) { - contact.isSelected = false - selectArray.removeAll { c in - contact === c - } - if selectArray.count <= 0 { - collection.reloadData() - collectionHeight?.constant = 0 - } - collection.reloadData() - tableView.reloadData() - refreshSelectCount() - } - - func refreshSelectCount() { - if selectArray.count > 0 { - sureBtn.setTitle("确定(\(selectArray.count))", for: .normal) - } else { - sureBtn.setTitle(localizable("alert_sure"), for: .normal) - } - } -} diff --git a/NEContactUIKit/NEContactUIKit/Classes/Views/ContactsViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/Views/ContactsViewController.swift deleted file mode 100644 index a167069f..00000000 --- a/NEContactUIKit/NEContactUIKit/Classes/Views/ContactsViewController.swift +++ /dev/null @@ -1,333 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NECoreIMKit -import NECoreKit - -public protocol ContactsViewControllerDelegate { - func onDataLoaded() -} - -@objcMembers -open class ContactsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, - SystemMessageProviderDelegate, FriendProviderDelegate { - public var delegate: ContactsViewControllerDelegate? - - // custom ui cell - public var customCells: [Int: ContactTableViewCell.Type] = [ - ContactCellType.ContactPerson.rawValue: ContactTableViewCell.self, - ContactCellType.ContactOthers.rawValue: ContactTableViewCell.self, - ] - - public var clickCallBacks = [Int: ConttactClickCallBack]() - var lastTitleIndex = 0 - - public var topViewHeight: CGFloat = 0 { - didSet { - topViewHeightAnchor?.constant = topViewHeight - topView.isHidden = topViewHeight <= 0 - } - } - - public var topViewHeightAnchor: NSLayoutConstraint? - public lazy var topView: UIView = { - let view = UIView() - view.translatesAutoresizingMaskIntoConstraints = false - view.backgroundColor = .clear - return view - }() - - public lazy var tableView: UITableView = { - let tableView = UITableView(frame: .zero, style: .grouped) - tableView.translatesAutoresizingMaskIntoConstraints = false - tableView.separatorStyle = .none - tableView.delegate = self - tableView.dataSource = self - tableView.backgroundColor = UIColor.ne_backgroundColor - tableView.rowHeight = 52 - tableView.sectionHeaderHeight = 40 - tableView.sectionFooterHeight = 0 - tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 0.1)) - return tableView - }() - - public var viewModel = ContactViewModel(contactHeaders: [ - ContactHeadItem( - name: localizable("validation_message"), - imageName: "valid", - router: ValidationMessageRouter, - color: UIColor(hexString: "#60CFA7") - ), - ContactHeadItem( - name: localizable("blacklist"), - imageName: "blackName", - router: ContactBlackListRouter, - color: UIColor(hexString: "#53C3F3") - ), - ContactHeadItem( - name: localizable("mine_groupchat"), - imageName: "group", - router: ContactGroupRouter, - color: UIColor(hexString: "#BE65D9") - ), - ]) - override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { - super.init(nibName: nil, bundle: nil) - viewModel.contactRepo.addNotificationDelegate(delegate: self) - viewModel.contactRepo.addContactDelegate(delegate: self) - } - - public required init?(coder: NSCoder) { - super.init(coder: coder) - } - - override open func viewDidLoad() { - super.viewDidLoad() - weak var weakSelf = self - viewModel.refresh = { - weakSelf?.tableView.reloadData() - } - - // 添加UI - addNavbarAction() - commonUI() - } - - override open func viewWillAppear(_ animated: Bool) { - // 刷新数据 - viewModel.reLoadData { [weak self] error in - if error == nil { - self?.delegate?.onDataLoaded() - self?.tableView.reloadData() - } - } - } - - open func commonUI() { - view.addSubview(topView) - NSLayoutConstraint.activate([ - topView.topAnchor.constraint(equalTo: view.topAnchor), - topView.leftAnchor.constraint(equalTo: view.leftAnchor), - topView.rightAnchor.constraint(equalTo: view.rightAnchor), - ]) - topViewHeightAnchor = topView.heightAnchor.constraint(equalToConstant: topViewHeight) - topViewHeightAnchor?.isActive = true - - view.addSubview(tableView) - NSLayoutConstraint.activate([ - tableView.leftAnchor.constraint(equalTo: view.leftAnchor), - tableView.rightAnchor.constraint(equalTo: view.rightAnchor), - tableView.topAnchor.constraint(equalTo: topView.bottomAnchor), - tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), - ]) - - tableView.register( - ContactSectionView.self, - forHeaderFooterViewReuseIdentifier: "\(NSStringFromClass(ContactSectionView.self))" - ) - - customCells.forEach { (key: Int, value: ContactTableViewCell.Type) in - tableView.register(value, forCellReuseIdentifier: "\(key)") - } - } - - open func loadData() { - viewModel.loadData { [weak self] error in - if error == nil { - self?.delegate?.onDataLoaded() - self?.tableView.reloadData() - } - } - } - - // UITableViewDataSource - open func numberOfSections(in tableView: UITableView) -> Int { - viewModel.contacts.count - } - - open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - NELog.infoLog(ModuleName + " " + className(), desc: "contact section: \(section), count:\(viewModel.contacts[section].contacts.count)") - - return viewModel.contacts[section].contacts.count - } - - open func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let info = viewModel.contacts[indexPath.section].contacts[indexPath.row] - var reusedId = "\(info.contactCellType)" - let cell = tableView.dequeueReusableCell(withIdentifier: reusedId, for: indexPath) - - if let c = cell as? ContactTableViewCell { - c.setModel(info) - if indexPath.section == 0, indexPath.row == 0, viewModel.unreadCount > 0 { - c.redAngleView.isHidden = false - c.redAngleView.text = viewModel.unreadCount > 99 ? "99+" : "\(viewModel.unreadCount)" - } else { - c.redAngleView.isHidden = true - } - } - return cell - } - - open func tableView(_ tableView: UITableView, - viewForHeaderInSection section: Int) -> UIView? { - let sectionView: ContactSectionView = tableView - .dequeueReusableHeaderFooterView( - withIdentifier: "\(NSStringFromClass(ContactSectionView.self))" - ) as! ContactSectionView - sectionView.titleLabel.text = viewModel.contacts[section].initial - return sectionView - } - - open func tableView(_ tableView: UITableView, - heightForHeaderInSection section: Int) -> CGFloat { - if viewModel.contacts[section].initial.count > 0 { - return 40 - } - return 0 - } - - open func sectionIndexTitles(for tableView: UITableView) -> [String]? { - viewModel.indexs - } - - open func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, - at index: Int) -> Int { - for (i, t) in viewModel.contacts.enumerated() { - if t.initial == title { - lastTitleIndex = i - return i - } - } - return lastTitleIndex - } - - open func tableView(_ tableView: UITableView, - heightForRowAt indexPath: IndexPath) -> CGFloat { - 52 - } - - open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let info = viewModel.contacts[indexPath.section].contacts[indexPath.row] - if let callBack = clickCallBacks[info.contactCellType] { - callBack(indexPath.row, indexPath.section) - return - } - if info.contactCellType == ContactCellType.ContactOthers.rawValue { - switch info.router { - case ValidationMessageRouter: - let validationController = ValidationMessageViewController() - validationController.hidesBottomBarWhenPushed = true - navigationController?.pushViewController(validationController, animated: true) - case ContactBlackListRouter: - let blackVC = BlackListViewController() - blackVC.hidesBottomBarWhenPushed = true - navigationController?.pushViewController(blackVC, animated: true) - - case ContactGroupRouter: - // My Team - let teamVC = TeamListViewController() - teamVC.hidesBottomBarWhenPushed = true - navigationController?.pushViewController(teamVC, animated: true) - - case ContactPersonRouter: - - break - - case ContactComputerRouter: -// let select = ContactsSelectedViewController() -// select.CallBack = { contacts in -// print("select contacs : ", contacts) -// } -// select.hidesBottomBarWhenPushed = true -// self.navigationController?.pushViewController(select, animated: true) - break - default: - break - } - } else { - let userInfoVC = ContactUserViewController(user: info.user) - userInfoVC.hidesBottomBarWhenPushed = true - navigationController?.pushViewController(userInfoVC, animated: true) - } - } - -// MARK: SystemMessageProviderDelegate - - public func onRecieveNotification(notification: XNotification) { - print("onRecieveNotification type:\(notification.type)") - if notification.type == .addFriendDirectly { - loadData() - } - } - - public func onNotificationUnreadCountChanged(count: Int) { - print("unread count:\(count)") - } - -// MARK: FriendProviderDelegate - - public func onFriendChanged(user: User) { - print("onFriendChanged:\(user.userId)") - loadData() - } - - public func onBlackListChanged() { - print("onBlackListChanged") - loadData() - } - - public func onUserInfoChanged(user: User) { - print("onUserInfoChanged:\(user.userId)") - loadData() - } - - public func onReceive(_ notification: NIMCustomSystemNotification) {} -} - -extension ContactsViewController { - open func addNavbarAction() { - edgesForExtendedLayout = [] - let addItem = UIBarButtonItem( - image: UIImage.ne_imageNamed(name: "add"), - style: .plain, - target: self, - action: #selector(goToFindFriend) - ) - addItem.tintColor = UIColor(hexString: "333333") - let searchItem = UIBarButtonItem( - image: UIImage.ne_imageNamed(name: "contact_search"), - style: .plain, - target: self, - action: #selector(searchContact) - ) - searchItem.imageInsets = UIEdgeInsets(top: 0, left: 35, bottom: 0, right: 0) - searchItem.tintColor = UIColor(hexString: "333333") - if NEKitContactConfig.shared.ui.hiddenRightBtns { - return - } else { - if NEKitContactConfig.shared.ui.hiddenSearchBtn { - navigationItem.rightBarButtonItems = [addItem] - } else { - navigationItem.rightBarButtonItems = [addItem, searchItem] - } - } - } - - @objc private func goToFindFriend() { - let findFriendController = FindFriendViewController() - findFriendController.hidesBottomBarWhenPushed = true - navigationController?.pushViewController(findFriendController, animated: true) - } - - @objc private func searchContact() { - Router.shared.use( - SearchContactPageRouter, - parameters: ["nav": navigationController as Any], - closure: nil - ) - } -} diff --git a/NEContactUIKit/NEContactUIKit/Classes/UserInfo/ViewController/ContactRemakNameViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseContactRemakNameViewController.swift similarity index 79% rename from NEContactUIKit/NEContactUIKit/Classes/UserInfo/ViewController/ContactRemakNameViewController.swift rename to NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseContactRemakNameViewController.swift index e36dbbf4..76470bcf 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/UserInfo/ViewController/ContactRemakNameViewController.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseContactRemakNameViewController.swift @@ -8,7 +8,7 @@ import NECoreIMKit import NECoreKit @objcMembers -public class ContactRemakNameViewController: ContactBaseViewController, UITextFieldDelegate { +open class NEBaseContactRemakNameViewController: NEBaseContactViewController, UITextFieldDelegate { typealias ModifyBlock = (_ user: User) -> Void var completion: ModifyBlock? @@ -19,14 +19,13 @@ public class ContactRemakNameViewController: ContactBaseViewController, UITextFi let textField = UITextField() textField.backgroundColor = .white textField.clipsToBounds = true - textField.layer.cornerRadius = 8 textField.font = UIFont.systemFont(ofSize: 16.0) textField.translatesAutoresizingMaskIntoConstraints = false let leftSpace = UIView(frame: CGRect(x: 0, y: 0, width: 16, height: 0)) textField.leftView = leftSpace textField.leftViewMode = .always textField.delegate = self - textField.clearButtonMode = .whileEditing + textField.clearButtonMode = .always textField.addTarget(self, action: #selector(textFieldChange), for: .editingChanged) return textField }() @@ -41,31 +40,19 @@ public class ContactRemakNameViewController: ContactBaseViewController, UITextFi override public func viewDidLoad() { super.viewDidLoad() - - // Do any additional setup after loading the view. - setupUI() } func setupUI() { - view.backgroundColor = UIColor(hexString: "F2F4F5") - let clearItem = UIBarButtonItem( - title: localizable("save"), - style: .done, - target: self, - action: #selector(saveAlias) - ) - clearItem.tintColor = UIColor(hexString: "337EFF") - navigationItem.rightBarButtonItem = clearItem title = localizable("noteName") + customNavigationView.navTitle.text = title + view.backgroundColor = UIColor(hexString: "F2F4F5") + + customNavigationView.setMoreButtonTitle(localizable("save")) + customNavigationView.addMoreButtonTarget(target: self, selector: #selector(saveAlias)) + view.addSubview(aliasInput) aliasInput.placeholder = localizable("input_noteName") - NSLayoutConstraint.activate([ - aliasInput.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20), - aliasInput.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), - aliasInput.topAnchor.constraint(equalTo: view.topAnchor, constant: 10), - aliasInput.heightAnchor.constraint(equalToConstant: 50), - ]) if let alias = user?.alias { aliasInput.text = alias } @@ -83,10 +70,16 @@ public class ContactRemakNameViewController: ContactBaseViewController, UITextFi aliasInput.text = "" return } + + weak var weakSelf = self + if NEChatDetectNetworkTool.shareInstance.manager?.isReachable == false { + weakSelf?.showToast(commonLocalizable("network_error")) + return + } + user?.alias = aliasInput.text if let u = user { view.makeToastActivity(.center) - weak var weakSelf = self viewmodel.update(u) { error in NELog.infoLog( "ContactRemakNameViewController", diff --git a/NEContactUIKit/NEContactUIKit/Classes/UserInfo/ViewController/ContactUserViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseContactUserViewController.swift similarity index 60% rename from NEContactUIKit/NEContactUIKit/Classes/UserInfo/ViewController/ContactUserViewController.swift rename to NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseContactUserViewController.swift index 29d48f6a..06c368f5 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/UserInfo/ViewController/ContactUserViewController.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseContactUserViewController.swift @@ -9,49 +9,54 @@ import NECoreKit import NIMSDK @objcMembers -public class ContactUserViewController: ContactBaseViewController, UITableViewDelegate, +open class NEBaseContactUserViewController: NEBaseContactViewController, UITableViewDelegate, UITableViewDataSource { - private var user: User? - private var uid: String? + var user: User? + var uid: String? public var isBlack: Bool = false - private let className = "ContactUserViewController" + var className = "ContactUserViewController" - let viewModel = ContactUserViewModel() - var tableView = UITableView(frame: .zero, style: .grouped) + public let viewModel = ContactUserViewModel() + public var tableView = UITableView(frame: .zero, style: .grouped) var data = [[UserItem]]() - var headerView: UserInfoHeaderView? + public var headerView = NEBaseUserInfoHeaderView() - init(user: User?) { + public init(user: User?) { super.init(nibName: nil, bundle: nil) self.user = user + uid = user?.userId } - init(uid: String) { + public init(uid: String) { super.init(nibName: nil, bundle: nil) self.uid = uid } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - override public func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() - if user != nil { - commonUI() - loadData() - } else if let userId = uid { + commonUI() + loadData() + if let userId = uid { weak var weakSelf = self - viewModel.getUserInfo(userId) { error, user in + if NEChatDetectNetworkTool.shareInstance.manager?.isReachable == false { + weakSelf?.showToast(commonLocalizable("network_error"), .bottom) + } + view.makeToastActivity(.center) + viewModel.fetchUserInfo(accountList: [userId]) { users, error in + weakSelf?.view.hideToastActivity() NELog.infoLog( - self.className, + weakSelf?.className ?? "ContactUserViewController", desc: "CALLBACK getUserInfo " + (error?.localizedDescription ?? "no error") ) if let err = error { weakSelf?.showToast(err.localizedDescription) - } else if let u = user { + } else if let u = users?.first { weakSelf?.user = u - weakSelf?.commonUI() + NotificationCenter.default.post(name: NotificationName.updateFriendInfo, object: u) weakSelf?.loadData() } } @@ -60,35 +65,22 @@ public class ContactUserViewController: ContactBaseViewController, UITableViewDe NIMSDK.shared().systemNotificationManager.add(self) } - override func backToPrevious() { - super.backToPrevious() - NotificationCenter.default.post(name: NotificationName.updateFriendInfo, object: user) - } + open func commonUI() { + navigationController?.navigationBar.backgroundColor = .white + customNavigationView.backgroundColor = .white - func commonUI() { tableView.separatorStyle = .none tableView.delegate = self tableView.dataSource = self tableView.translatesAutoresizingMaskIntoConstraints = false - tableView.sectionHeaderHeight = 6 view.addSubview(tableView) - if #available(iOS 11.0, *) { - NSLayoutConstraint.activate([ - self.tableView.topAnchor - .constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor), - self.tableView.leftAnchor.constraint(equalTo: self.view.leftAnchor), - self.tableView.rightAnchor.constraint(equalTo: self.view.rightAnchor), - self.tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor), - ]) - } else { - // Fallback on earlier versions - NSLayoutConstraint.activate([ - tableView.topAnchor.constraint(equalTo: view.topAnchor), - tableView.leftAnchor.constraint(equalTo: view.leftAnchor), - tableView.rightAnchor.constraint(equalTo: view.rightAnchor), - tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), - ]) - } + NSLayoutConstraint.activate([ + tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: topConstant), + tableView.leftAnchor.constraint(equalTo: view.leftAnchor), + tableView.rightAnchor.constraint(equalTo: view.rightAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + tableView.register( TextWithRightArrowCell.self, forCellReuseIdentifier: "\(TextWithRightArrowCell.self)" @@ -104,12 +96,14 @@ public class ContactUserViewController: ContactBaseViewController, UITableViewDe tableView.register(CenterTextCell.self, forCellReuseIdentifier: "\(CenterTextCell.self)") tableView.register(UITableViewCell.self, forCellReuseIdentifier: "\(UITableViewCell.self)") - tableView.rowHeight = 62 - headerView = - UserInfoHeaderView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, - height: 113)) - headerView?.setData(user: user) tableView.tableHeaderView = headerView + headerView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + headerView.leftAnchor.constraint(equalTo: tableView.leftAnchor), + headerView.topAnchor.constraint(equalTo: tableView.topAnchor), + headerView.heightAnchor.constraint(equalToConstant: 113), + headerView.widthAnchor.constraint(equalToConstant: NEConstant.screenWidth), + ]) } func loadData() { @@ -179,19 +173,23 @@ public class ContactUserViewController: ContactBaseViewController, UITableViewDe ], ] } + + headerView.setData(user: user) + tableView.tableHeaderView = tableView.tableHeaderView + tableView.tableHeaderView?.layoutIfNeeded() tableView.reloadData() } - public func numberOfSections(in tableView: UITableView) -> Int { + open func numberOfSections(in tableView: UITableView) -> Int { data.count } - public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { data[section].count } - public func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { + open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { let item = data[indexPath.section][indexPath.row] let cell = tableView.dequeueReusableCell( withIdentifier: "\(item.cellClass)", @@ -206,6 +204,9 @@ public class ContactUserViewController: ContactBaseViewController, UITableViewDe if let c = cell as? TextWithDetailTextCell { c.titleLabel.text = item.title c.detailTitleLabel.text = item.detailTitle + if item.title == localizable("sign") { + c.detailTitleLabel.numberOfLines = 2 + } return c } @@ -215,7 +216,9 @@ public class ContactUserViewController: ContactBaseViewController, UITableViewDe c.block = { [weak self] title, value in print("title:\(title) value\(value)") if title == localizable("add_blackList") { - self?.blackList(isBlack: value) + self?.blackList(isBlack: value) { + c.switchButton.isOn = !c.switchButton.isOn + } } else if title == localizable("message_remind") {} } @@ -230,7 +233,28 @@ public class ContactUserViewController: ContactBaseViewController, UITableViewDe return cell } - public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + if section == 0 { + return 0 + } + return 6.0 + } + + public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let header = UIView() + header.backgroundColor = UIColor.clear + return header + } + + public func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { + 0 + } + + public func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { + nil + } + + open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let item = data[indexPath.section][indexPath.row] if item.title == localizable("noteName") { toEditRemarks() @@ -257,12 +281,16 @@ public class ContactUserViewController: ContactBaseViewController, UITableViewDe } } + open func getContactRemakNameViewController() -> NEBaseContactRemakNameViewController { + NEBaseContactRemakNameViewController() + } + func toEditRemarks() { - let remark = ContactRemakNameViewController() + let remark = getContactRemakNameViewController() remark.user = user - remark.completion = { u in - self.user = u - self.headerView?.setData(user: u) + remark.completion = { [weak self] u in + self?.user = u + self?.headerView.setData(user: u) NotificationCenter.default.post(name: NotificationName.updateFriendInfo, object: u) } navigationController?.pushViewController(remark, animated: true) @@ -274,7 +302,14 @@ public class ContactUserViewController: ContactBaseViewController, UITableViewDe print("edit remarks") } - func blackList(isBlack: Bool) { + func blackList(isBlack: Bool, completion: () -> Void) { + weak var weakSelf = self + if NEChatDetectNetworkTool.shareInstance.manager?.isReachable == false { + weakSelf?.showToast(commonLocalizable("network_error")) + completion() + return + } + guard let userId = user?.userId else { return } @@ -318,31 +353,59 @@ public class ContactUserViewController: ContactBaseViewController, UITableViewDe } } - func deleteFriend(user: User?) { - showAlert( - title: localizable("sure_delte_friend"), - message: "", - sureText: localizable("alert_sure"), - cancelText: localizable("alert_cancel") - ) { [self] in - if let userId = user?.userId { - viewModel.deleteFriend(account: userId) { error in - NELog.infoLog( - self.className, - desc: "CALLBACK deleteFriend " + (error?.localizedDescription ?? "no error") - ) - if error != nil { - self.showToast(error?.localizedDescription ?? "") - } else { - self.navigationController?.popViewController(animated: true) - } + func deleteFriendAction(user: User?) { + weak var weakSelf = self + if NEChatDetectNetworkTool.shareInstance.manager?.isReachable == false { + weakSelf?.showToast(commonLocalizable("network_error")) + return + } + if let userId = user?.userId { + viewModel.deleteFriend(account: userId) { error in + NELog.infoLog( + self.className, + desc: "CALLBACK deleteFriend " + (error?.localizedDescription ?? "no error") + ) + if error != nil { + self.showToast(error?.localizedDescription ?? "") + } else { + self.navigationController?.popViewController(animated: true) } } - } cancelBack: {} + } + } + + open func deleteFriend(user: User?) { + let alertController = UIAlertController( + title: localizable("delete_title").replacingOccurrences(of: "XXX", with: user?.showName(true) ?? ""), + message: nil, + preferredStyle: .actionSheet + ) + + let cancelAction = UIAlertAction( + title: commonLocalizable("cancel"), + style: .cancel, + handler: nil + ) + cancelAction.setValue(UIColor.ne_darkText, forKey: "_titleTextColor") + + let deleteAction = UIAlertAction(title: localizable("delete_friend"), + style: .default) { [weak self] action in + self?.deleteFriendAction(user: user) + } + deleteAction.setValue(UIColor.ne_redText, forKey: "_titleTextColor") + + alertController.addAction(cancelAction) + alertController.addAction(deleteAction) + fixAlertOnIpad(alertController) + present(alertController, animated: true, completion: nil) } func addFriend() { weak var weakSelf = self + if NEChatDetectNetworkTool.shareInstance.manager?.isReachable == false { + weakSelf?.showToast(commonLocalizable("network_error")) + return + } if let account = user?.userId { viewModel.addFriend(account) { error in NELog.infoLog( @@ -368,8 +431,8 @@ public class ContactUserViewController: ContactBaseViewController, UITableViewDe } } -extension ContactUserViewController: NIMSystemNotificationManagerDelegate { - public func onReceive(_ notification: NIMSystemNotification) { +extension NEBaseContactUserViewController: NIMSystemNotificationManagerDelegate { + open func onReceive(_ notification: NIMSystemNotification) { if notification.type == .friendAdd, let obj = notification.attachment as? NIMUserAddAttachment, obj.operationType == .verify { diff --git a/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseContactViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseContactViewController.swift new file mode 100644 index 00000000..e0483136 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseContactViewController.swift @@ -0,0 +1,76 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class NEBaseContactViewController: UIViewController, UIGestureRecognizerDelegate { + var topConstant: CGFloat = 0 + public let customNavigationView = NENavigationView() + + public lazy var emptyView: NEEmptyDataView = { + let view = NEEmptyDataView( + imageName: "user_empty", + content: "", + frame: CGRect.zero + ) + view.translatesAutoresizingMaskIntoConstraints = false + view.isHidden = true + return view + + }() + + override open func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + view.backgroundColor = .white + edgesForExtendedLayout = [] + navigationController?.interactivePopGestureRecognizer?.delegate = self + + if let useSystemNav = NEConfigManager.instance.getParameter(key: useSystemNav) as? Bool, useSystemNav { + navigationController?.isNavigationBarHidden = false + setupBackUI() + } else { + navigationController?.isNavigationBarHidden = true + topConstant = NEConstant.navigationAndStatusHeight + customNavigationView.translatesAutoresizingMaskIntoConstraints = false + customNavigationView.addBackButtonTarget(target: self, selector: #selector(backToPrevious)) + customNavigationView.moreButton.isHidden = true + view.addSubview(customNavigationView) + NSLayoutConstraint.activate([ + customNavigationView.leftAnchor.constraint(equalTo: view.leftAnchor), + customNavigationView.rightAnchor.constraint(equalTo: view.rightAnchor), + customNavigationView.topAnchor.constraint(equalTo: view.topAnchor), + customNavigationView.heightAnchor.constraint(equalToConstant: topConstant), + ]) + } + } + + open func setupBackUI() { + navigationController?.navigationBar.tintColor = .white + let backItem = UIBarButtonItem( + image: UIImage.ne_imageNamed(name: "backArrow"), + style: .plain, + target: self, + action: #selector(backToPrevious) + ) + backItem.tintColor = UIColor(hexString: "333333") + navigationItem.leftBarButtonItem = backItem + } + + open func backToPrevious() { + navigationController?.popViewController(animated: true) + } + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseContactsSelectedViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseContactsSelectedViewController.swift new file mode 100644 index 00000000..1c333472 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseContactsSelectedViewController.swift @@ -0,0 +1,343 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreKit +import NIMSDK + +@objcMembers +open class NEBaseContactsSelectedViewController: NEBaseContactViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UITableViewDelegate, UITableViewDataSource { + public var callBack: ContactsSelectCompletion? + + public var filterUsers: Set? + var lastTitleIndex = 0 + public var limit = 10 // max select count + + // 单聊中对方的userId + public var userId: String? + + public var selectArray = [ContactInfo]() + public let selectDic = [String: ContactInfo]() + + public lazy var collectionBackView: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = .clear + view.layer.cornerRadius = 4 + return view + }() + + public lazy var collection: UICollectionView = { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .horizontal + layout.minimumLineSpacing = 0 + layout.minimumInteritemSpacing = 0 + let collect = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout) + collect.contentInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5) + return collect + }() + + public var sureBtn = UIButton(frame: CGRect(x: 0, y: 0, width: 76, height: 32)) + + var collectionBackViewTopMargin: CGFloat = 12 + var collectionBackViewTopAnchor: NSLayoutConstraint? + var collectionBackViewHeight: CGFloat = 52 + var collectionBackViewHeightAnchor: NSLayoutConstraint? + + public var customCells = [Int: NEBaseContactTableViewCell.Type]() // custom ui cell + + public let viewModel = ContactViewModel(contactHeaders: nil) + + public lazy var tableView: UITableView = { + let table = UITableView(frame: .zero, style: .plain) + table.backgroundColor = .clear + table.sectionIndexColor = .ne_greyText + table.delegate = self + table.dataSource = self + table.translatesAutoresizingMaskIntoConstraints = false + table.separatorStyle = .none + table.contentInset = .init(top: -10, left: 0, bottom: 0, right: 0) + if #available(iOS 15.0, *) { + table.sectionHeaderTopPadding = 0 + } + return table + }() + + var tableViewTopAnchor: NSLayoutConstraint? + + override open func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + weak var weakSelf = self + viewModel.loadData(filterUsers) { error, userSectionCount in + weakSelf?.emptyView.isHidden = userSectionCount > 0 + weakSelf?.tableView.reloadData() + weakSelf?.emptyView.isHidden = (weakSelf?.viewModel.contacts.count ?? 0) > 0 + } + } + + override open func viewDidLoad() { + super.viewDidLoad() + title = localizable("select") + customNavigationView.navTitle.text = title + emptyView.settingContent(content: localizable("no_friend")) + setupUI() + setupNavRightItem() + } + + open func setupUI() { + view.addSubview(collectionBackView) + collectionBackViewTopAnchor = collectionBackView.topAnchor.constraint(equalTo: view.topAnchor, constant: topConstant + collectionBackViewTopMargin) + collectionBackViewHeightAnchor = collectionBackView.heightAnchor.constraint(equalToConstant: 0) + NSLayoutConstraint.activate([ + collectionBackViewTopAnchor!, + collectionBackView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 16), + collectionBackView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -16), + collectionBackViewHeightAnchor!, + ]) + + view.addSubview(collection) + collection.backgroundColor = .clear + collection.delegate = self + collection.dataSource = self + collection.allowsMultipleSelection = false + collection.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + collection.centerYAnchor.constraint(equalTo: collectionBackView.centerYAnchor), + collection.leftAnchor.constraint(equalTo: collectionBackView.leftAnchor), + collection.rightAnchor.constraint(equalTo: collectionBackView.rightAnchor), + collection.heightAnchor.constraint(equalToConstant: collectionBackViewHeight), + ]) + + view.addSubview(tableView) + + tableViewTopAnchor = tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: topConstant) + NSLayoutConstraint.activate([ + tableView.leftAnchor.constraint(equalTo: view.leftAnchor), + tableView.rightAnchor.constraint(equalTo: view.rightAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + tableViewTopAnchor!, + ]) + + tableView.register( + ContactSectionView.self, + forHeaderFooterViewReuseIdentifier: "\(NSStringFromClass(ContactSectionView.self))" + ) + + customCells.forEach { (key: Int, value: AnyClass) in + if value is ContactCellDataProtrol.Type { + self.tableView.register( + value, + forCellReuseIdentifier: "\(NSStringFromClass(value))" + ) + } + } + + view.addSubview(emptyView) + NSLayoutConstraint.activate([ + emptyView.topAnchor.constraint(equalTo: tableView.topAnchor), + emptyView.bottomAnchor.constraint(equalTo: tableView.bottomAnchor), + emptyView.leftAnchor.constraint(equalTo: tableView.leftAnchor), + emptyView.rightAnchor.constraint(equalTo: tableView.rightAnchor), + ]) + } + + open func setupNavRightItem() { + if let useSystemNav = NEConfigManager.instance.getParameter(key: useSystemNav) as? Bool, useSystemNav { + let rightItem = UIBarButtonItem(customView: sureBtn) + navigationItem.rightBarButtonItem = rightItem + sureBtn.addTarget(self, action: #selector(sureClick(_:)), for: .touchUpInside) + sureBtn.setTitle(localizable("alert_sure"), for: .normal) + sureBtn.setTitleColor(.white, for: .normal) + sureBtn.layer.cornerRadius = 4 + sureBtn.contentHorizontalAlignment = .center + sureBtn.titleLabel?.font = UIFont.systemFont(ofSize: 16.0) + } else { + customNavigationView.setMoreButtonTitle(localizable("alert_sure")) + customNavigationView.moreButton.setTitleColor(.white, for: .normal) + customNavigationView.moreButton.layer.cornerRadius = 4 + customNavigationView.moreButton.contentHorizontalAlignment = .center + customNavigationView.addMoreButtonTarget(target: self, selector: #selector(sureClick(_:))) + customNavigationView.setBackButtonTitle(localizable("close")) + customNavigationView.backButton.setTitleColor(.ne_darkText, for: .normal) + sureBtn = customNavigationView.moreButton + } + } + + open func sureClick(_ sender: UIButton) { + if selectArray.count <= 0 { + showToast(localizable("select_contact")) + return + } + + if !NEChatDetectNetworkTool.shareInstance.isNetworkRecahability() { + showToast(localizable("network_error")) + return + } + + if let completion = callBack { + completion(selectArray) + } + var accids = [String]() + var names = [String]() + + names.append(viewModel.contactRepo.getUserName()) + + var users = [NIMUser]() + for c in selectArray { + accids.append(c.user?.userId ?? "") + if let name = c.user?.userInfo?.nickName { + names.append(name) + } else if let accid = c.user?.userId { + names.append(accid) + } + if let user = c.user?.imUser { + users.append(user) + } + } + + if let uid = userId { + accids.append(uid) + } + let nameString = names.joined(separator: "、") + print("name string : ", nameString) + Router.shared.use( + ContactSelectedUsersRouter, + parameters: ["accids": accids, "names": nameString, "im_user": users], + closure: nil + ) + navigationController?.popViewController(animated: true) + } + + // MARK: - Table View DataSource And Delegate + + open func numberOfSections(in tableView: UITableView) -> Int { + viewModel.contacts.count + } + + open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + viewModel.contacts[section].contacts.count + } + + open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let info = viewModel.contacts[indexPath.section].contacts[indexPath.row] + if let cellClass = customCells[info.contactCellType] { + let anyCell = tableView.dequeueReusableCell( + withIdentifier: "\(NSStringFromClass(cellClass))", + for: indexPath + ) as? NEBaseContactTableViewCell + anyCell?.setModel(info) + if let cell = anyCell { + return cell + } + } + return UITableViewCell() + } + + open func tableView(_ tableView: UITableView, + viewForHeaderInSection section: Int) -> UIView? { + nil + } + + open func tableView(_ tableView: UITableView, + heightForHeaderInSection section: Int) -> CGFloat { + if viewModel.contacts[section].initial.count > 0 { + return 40 + } + return 0 + } + + open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let info = viewModel.contacts[indexPath.section].contacts[indexPath.row] + let cell = tableView.cellForRow(at: indexPath) as? NEBaseContactSelectedCell + if info.isSelected == true { + didUnselectContact(info) + cell?.setSelect() + } else { + if selectArray.count >= limit { + view.makeToast("超出\(limit)人限制") + return + } + didSelectContact(info) + cell?.setUnselect() + } + } + + open func sectionIndexTitles(for tableView: UITableView) -> [String]? { + viewModel.indexs + } + + open func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int { + for (i, t) in viewModel.contacts.enumerated() { + if t.initial == title { + lastTitleIndex = i + return i + } + } + return lastTitleIndex + } + + // MARK: Collection View DataSource And Delegate + + open func collectionView(_ collectionView: UICollectionView, + numberOfItemsInSection section: Int) -> Int { + selectArray.count + } + + open func collectionView(_ collectionView: UICollectionView, + didSelectItemAt indexPath: IndexPath) { + let contactInfo = selectArray[indexPath.row] + didUnselectContact(contactInfo) + } + + open func collectionView(_ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + UICollectionViewCell() + } + + open func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + sizeForItemAt indexPath: IndexPath) -> CGSize { + CGSize(width: 46, height: collectionBackViewHeight) + } + + func didSelectContact(_ contact: ContactInfo) { + contact.isSelected = true + if selectArray.contains(where: { c in + contact === c + }) == false { + selectArray.append(contact) + if let height = collectionBackViewHeightAnchor?.constant, height <= 0 { + collectionBackViewHeightAnchor?.constant = collectionBackViewHeight + tableViewTopAnchor?.constant += collectionBackViewHeight + collectionBackViewTopMargin * 2 + } + } + collection.reloadData() + tableView.reloadData() + refreshSelectCount() + } + + func didUnselectContact(_ contact: ContactInfo) { + contact.isSelected = false + selectArray.removeAll { c in + contact === c + } + if selectArray.count <= 0 { + collection.reloadData() + collectionBackViewHeightAnchor?.constant = 0 + tableViewTopAnchor?.constant -= collectionBackViewHeight + collectionBackViewTopMargin * 2 + } + collection.reloadData() + tableView.reloadData() + refreshSelectCount() + } + + func refreshSelectCount() { + if selectArray.count > 0 { + sureBtn.setTitle("确定(\(selectArray.count))", for: .normal) + } else { + sureBtn.setTitle(localizable("alert_sure"), for: .normal) + } + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseContactsViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseContactsViewController.swift new file mode 100644 index 00000000..f1db284f --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseContactsViewController.swift @@ -0,0 +1,285 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit +import NECoreKit + +@objc +public protocol ContactsViewControllerDelegate { + func onDataLoaded() +} + +@objcMembers +open class NEBaseContactsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, + SystemMessageProviderDelegate, FriendProviderDelegate, TabNavigationViewDelegate { + public var delegate: ContactsViewControllerDelegate? + + // custom ui cell + public var customCells = [Int: NEBaseContactTableViewCell.Type]() + + public var clickCallBacks = [Int: ContactClickCallBack]() + var lastTitleIndex = 0 + + public lazy var navView: TabNavigationView = { + let nav = TabNavigationView(frame: CGRect.zero) + nav.translatesAutoresizingMaskIntoConstraints = false + nav.delegate = self + return nav + }() + + public var topConstant: CGFloat = 0 + + public var topViewHeight: CGFloat = 0 { + didSet { + topViewHeightAnchor?.constant = topViewHeight + topView.isHidden = topViewHeight <= 0 + } + } + + public var topViewHeightAnchor: NSLayoutConstraint? + public lazy var topView: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = .clear + return view + }() + + public lazy var tableView: UITableView = { + let tableView = UITableView(frame: .zero, style: .grouped) + tableView.translatesAutoresizingMaskIntoConstraints = false + tableView.separatorStyle = .none + tableView.delegate = self + tableView.dataSource = self + tableView.backgroundColor = UIColor.ne_backgroundColor + tableView.rowHeight = 52 + tableView.sectionHeaderHeight = 40 + tableView.sectionFooterHeight = 0 + tableView.sectionIndexColor = .ne_greyText + + tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 0.1)) + return tableView + }() + + lazy var emptyView: NEEmptyDataView = { + let view = NEEmptyDataView(imageName: "user_empty", content: localizable("no_friend"), frame: .zero) + view.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = .clear + view.isHidden = true + return view + }() + + public var viewModel = ContactViewModel(contactHeaders: nil) + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nil, bundle: nil) + viewModel.contactRepo.addNotificationDelegate(delegate: self) + viewModel.contactRepo.addContactDelegate(delegate: self) + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + override open func viewDidLoad() { + super.viewDidLoad() + if let useSystemNav = NEConfigManager.instance.getParameter(key: useSystemNav) as? Bool, useSystemNav { + navigationController?.isNavigationBarHidden = false + topConstant = 0 + } else { + navigationController?.isNavigationBarHidden = true + topConstant = NEConstant.navigationAndStatusHeight + view.addSubview(navView) + NSLayoutConstraint.activate([ + navView.topAnchor.constraint(equalTo: view.topAnchor), + navView.leftAnchor.constraint(equalTo: view.leftAnchor), + navView.rightAnchor.constraint(equalTo: view.rightAnchor), + navView.heightAnchor + .constraint(equalToConstant: NEConstant.navigationAndStatusHeight), + ]) + } + commonUI() + viewModel.refresh = { [weak self] in + self?.tableView.reloadData() + } + } + + override open func viewWillAppear(_ animated: Bool) { + // 刷新数据 + viewModel.reLoadData { [weak self] error, userSectionCount in + self?.emptyView.isHidden = userSectionCount > 0 + if error == nil { + self?.delegate?.onDataLoaded() + self?.tableView.reloadData() + } + } + } + + open func commonUI() { + initSystemNav() + + view.addSubview(topView) + topViewHeightAnchor = topView.heightAnchor.constraint(equalToConstant: topViewHeight) + topViewHeightAnchor?.isActive = true + + view.addSubview(tableView) + NSLayoutConstraint.activate([ + tableView.leftAnchor.constraint(equalTo: view.leftAnchor), + tableView.rightAnchor.constraint(equalTo: view.rightAnchor), + tableView.topAnchor.constraint(equalTo: topView.bottomAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + + view.addSubview(emptyView) + NSLayoutConstraint.activate([ + emptyView.leftAnchor.constraint(equalTo: view.leftAnchor), + emptyView.rightAnchor.constraint(equalTo: view.rightAnchor), + emptyView.topAnchor.constraint(equalTo: view.topAnchor, constant: NEConstant.screenHeight / 2), + emptyView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + } + + open func loadData() { + viewModel.loadData { [weak self] error, userSectionCount in + self?.emptyView.isHidden = userSectionCount > 0 + if error == nil { + self?.delegate?.onDataLoaded() + self?.tableView.reloadData() + } + } + } + + // UITableViewDataSource + open func numberOfSections(in tableView: UITableView) -> Int { + viewModel.contacts.count + } + + open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + NELog.infoLog(ModuleName + " " + className(), desc: "contact section: \(section), count:\(viewModel.contacts[section].contacts.count)") + + return viewModel.contacts[section].contacts.count + } + + open func configCell(info: ContactInfo, _ cell: NEBaseContactTableViewCell, _ indexPath: IndexPath) -> UITableViewCell { + cell.setModel(info) + if indexPath.section == 0, indexPath.row == 0, viewModel.unreadCount > 0 { + cell.redAngleView.isHidden = false + cell.redAngleView.text = viewModel.unreadCount > 99 ? "99+" : "\(viewModel.unreadCount)" + } else { + cell.redAngleView.isHidden = true + } + return cell + } + + // 具体逻辑在子类实现 + open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + UITableViewCell() + } + + open func tableView(_ tableView: UITableView, + viewForHeaderInSection section: Int) -> UIView? { + let sectionView: ContactSectionView = tableView + .dequeueReusableHeaderFooterView( + withIdentifier: "\(NSStringFromClass(ContactSectionView.self))" + ) as! ContactSectionView + sectionView.titleLabel.text = viewModel.contacts[section].initial + return sectionView + } + + open func tableView(_ tableView: UITableView, + heightForHeaderInSection section: Int) -> CGFloat { + if viewModel.contacts[section].initial.count > 0 { + return 40 + } + return 0 + } + + open func sectionIndexTitles(for tableView: UITableView) -> [String]? { + viewModel.indexs + } + + open func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, + at index: Int) -> Int { + for (i, t) in viewModel.contacts.enumerated() { + if t.initial == title { + lastTitleIndex = i + return i + } + } + return lastTitleIndex + } + + open func tableView(_ tableView: UITableView, + heightForRowAt indexPath: IndexPath) -> CGFloat { + 52 + } + + open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {} + +// MARK: SystemMessageProviderDelegate + + open func onRecieveNotification(notification: XNotification) { + print("onRecieveNotification type:\(notification.type)") + if notification.type == .addFriendDirectly { + loadData() + } + } + + open func onNotificationUnreadCountChanged(count: Int) { + print("unread count:\(count)") + } + +// MARK: FriendProviderDelegate + + open func onFriendChanged(user: User) { + print("onFriendChanged:\(user.userId)") + loadData() + } + + open func onBlackListChanged() { + print("onBlackListChanged") + loadData() + } + + open func onUserInfoChanged(user: User) { + print("onUserInfoChanged:\(user.userId)") + loadData() + } + + open func onReceive(_ notification: NIMCustomSystemNotification) {} +} + +extension NEBaseContactsViewController { + open func initSystemNav() { + edgesForExtendedLayout = [] + } + + open func getFindFriendViewController() -> NEBaseFindFriendViewController { + NEBaseFindFriendViewController() + } + + @objc open func goToFindFriend() { + let findFriendController = getFindFriendViewController() + findFriendController.hidesBottomBarWhenPushed = true + navigationController?.pushViewController(findFriendController, animated: true) + } + + @objc open func searchContact() { + Router.shared.use( + SearchContactPageRouter, + parameters: ["nav": navigationController as Any], + closure: nil + ) + } + + // MARK: TabNavigationViewDelegate + + public func searchAction() { + searchContact() + } + + public func didClickAddBtn() { + goToFindFriend() + } +} diff --git a/NEContactUIKit/NEContactUIKit/Classes/Views/FindFriendViewController.swift b/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseFindFriendViewController.swift similarity index 81% rename from NEContactUIKit/NEContactUIKit/Classes/Views/FindFriendViewController.swift rename to NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseFindFriendViewController.swift index 4c1af9b4..f80df012 100644 --- a/NEContactUIKit/NEContactUIKit/Classes/Views/FindFriendViewController.swift +++ b/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseFindFriendViewController.swift @@ -6,26 +6,22 @@ import UIKit import NECoreKit import NECoreIMKit + @objcMembers -public class FindFriendViewController: ContactBaseViewController, UITextFieldDelegate { - let viewModel = FindFriendViewModel() - let noResultView = UIView() - let hasRequest = false - let searchInput = UITextField() +open class NEBaseFindFriendViewController: NEBaseContactViewController, UITextFieldDelegate { + public let viewModel = FindFriendViewModel() + public let hasRequest = false + public let searchInput = UITextField() - override public func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() title = localizable("add_friend") - emptyView.setttingContent(content: localizable("user_not_exist")) + customNavigationView.navTitle.text = title + emptyView.settingContent(content: localizable("user_not_exist")) setupUI() } - override public func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - navigationController?.isNavigationBarHidden = false - } - - func setupUI() { + open func setupUI() { let searchBack = UIView() view.addSubview(searchBack) searchBack.backgroundColor = UIColor(hexString: "F2F4F5") @@ -35,7 +31,7 @@ public class FindFriendViewController: ContactBaseViewController, UITextFieldDel NSLayoutConstraint.activate([ searchBack.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20), searchBack.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), - searchBack.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), + searchBack.topAnchor.constraint(equalTo: view.topAnchor, constant: 20 + topConstant), searchBack.heightAnchor.constraint(equalToConstant: 32), ]) @@ -99,18 +95,30 @@ public class FindFriendViewController: ContactBaseViewController, UITextFieldDel } } - func startSearch(_ text: String) { + open func startSearch(_ text: String) { + if IMKitClient.instance.isMySelf(text) { + Router.shared.use( + MeSettingRouter, + parameters: ["nav": navigationController as Any], + closure: nil + ) + return + } + weak var weakSelf = self viewModel.searchFriend(text) { users, error in NELog.infoLog( - "FindFriendViewController", + "NEBaseFindFriendViewController", desc: "CALLBACK searchFriend " + (error?.localizedDescription ?? "no error") ) if error == nil { if let user = users?.first { // go to detail - let userController = ContactUserViewController(user: user) - self.navigationController?.pushViewController(userController, animated: true) + Router.shared.use( + ContactUserInfoPageRouter, + parameters: ["nav": weakSelf?.navigationController as Any, "nim_user": user], + closure: nil + ) weakSelf?.emptyView.isHidden = true } else { weakSelf?.emptyView.isHidden = false diff --git a/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseUserInfoHeaderView.swift b/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseUserInfoHeaderView.swift new file mode 100644 index 00000000..31b0d863 --- /dev/null +++ b/NEContactUIKit/NEContactUIKit/Classes/Views/NEBaseUserInfoHeaderView.swift @@ -0,0 +1,162 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreIMKit + +@objcMembers +open class NEBaseUserInfoHeaderView: UIView { + public var labelConstraints = [NSLayoutConstraint]() + public lazy var avatarImage: UIImageView = { + let avatarImage = UIImageView() + avatarImage.backgroundColor = UIColor(hexString: "#537FF4") + avatarImage.translatesAutoresizingMaskIntoConstraints = false + avatarImage.contentMode = .scaleAspectFill + avatarImage.clipsToBounds = true + return avatarImage + }() + + public lazy var nameLabel: UILabel = { + let nameLabel = UILabel() + nameLabel.textAlignment = .center + nameLabel.translatesAutoresizingMaskIntoConstraints = false + nameLabel.font = UIFont.systemFont(ofSize: 22) + nameLabel.textColor = .white + return nameLabel + }() + + public lazy var titleLabel: UILabel = { + let titleLabel = UILabel() + titleLabel.translatesAutoresizingMaskIntoConstraints = false + titleLabel.font = UIFont.boldSystemFont(ofSize: 22) + titleLabel.textColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1.0) + return titleLabel + }() + + public lazy var detailLabel: UILabel = { + let detailLabel = UILabel() + detailLabel.translatesAutoresizingMaskIntoConstraints = false + detailLabel.font = UIFont.systemFont(ofSize: 16) + detailLabel.textColor = .ne_greyText + return detailLabel + }() + + public lazy var detailLabel2: UILabel = { + let detailLabel = UILabel() + detailLabel.translatesAutoresizingMaskIntoConstraints = false + detailLabel.font = UIFont.systemFont(ofSize: 16) + detailLabel.textColor = .ne_greyText + return detailLabel + }() + + lazy var lineView: UIView = { + let view = UIView() + view.backgroundColor = .ne_greyLine + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + + override init(frame: CGRect) { + super.init(frame: frame) + commonUI() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open func commonUI() { + backgroundColor = .white + addSubview(avatarImage) + addSubview(nameLabel) + addSubview(titleLabel) + addSubview(detailLabel) + addSubview(lineView) + + NSLayoutConstraint.activate([ + avatarImage.leftAnchor.constraint(equalTo: leftAnchor, constant: 20), + avatarImage.widthAnchor.constraint(equalToConstant: 60), + avatarImage.heightAnchor.constraint(equalToConstant: 60), + avatarImage.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 0), + ]) + + NSLayoutConstraint.activate([ + nameLabel.leftAnchor.constraint(equalTo: avatarImage.leftAnchor), + nameLabel.rightAnchor.constraint(equalTo: avatarImage.rightAnchor), + nameLabel.topAnchor.constraint(equalTo: avatarImage.topAnchor), + nameLabel.bottomAnchor.constraint(equalTo: avatarImage.bottomAnchor), + ]) + + commonUI(showDetail: false) + } + + func commonUI(showDetail: Bool) { + NSLayoutConstraint.deactivate(labelConstraints) + var titleConstraint = [NSLayoutConstraint]() + var detailConstraint = [NSLayoutConstraint]() + var detail2Constraint = [NSLayoutConstraint]() + if showDetail { + titleConstraint = [ + titleLabel.leftAnchor.constraint(equalTo: avatarImage.rightAnchor, constant: 20), + titleLabel.rightAnchor.constraint(equalTo: rightAnchor, constant: -35), + titleLabel.topAnchor.constraint(equalTo: avatarImage.topAnchor, constant: -2), + titleLabel.heightAnchor.constraint(equalToConstant: 22), + ] + + detailConstraint = [ + detailLabel.leftAnchor.constraint(equalTo: titleLabel.leftAnchor), + detailLabel.rightAnchor.constraint(equalTo: titleLabel.rightAnchor), + detailLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 8), + detailLabel.heightAnchor.constraint(equalToConstant: 16), + ] + + addSubview(detailLabel2) + detail2Constraint = [ + detailLabel2.leftAnchor.constraint(equalTo: titleLabel.leftAnchor), + detailLabel2.rightAnchor.constraint(equalTo: titleLabel.rightAnchor), + detailLabel2.topAnchor.constraint(equalTo: detailLabel.bottomAnchor), + detailLabel.heightAnchor.constraint(equalToConstant: 16), + ] + } else { + titleConstraint = [ + titleLabel.leftAnchor.constraint(equalTo: avatarImage.rightAnchor, constant: 16), + titleLabel.rightAnchor.constraint(equalTo: rightAnchor, constant: -20), + titleLabel.topAnchor.constraint(equalTo: avatarImage.topAnchor, constant: 7), + titleLabel.heightAnchor.constraint(equalToConstant: 22), + ] + + detailConstraint = [ + detailLabel.leftAnchor.constraint(equalTo: titleLabel.leftAnchor), + detailLabel.rightAnchor.constraint(equalTo: titleLabel.rightAnchor), + detailLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 8), + detailLabel.heightAnchor.constraint(equalToConstant: 16), + ] + + detailLabel2.removeFromSuperview() + detail2Constraint = [] + } + labelConstraints = titleConstraint + detailConstraint + detail2Constraint + NSLayoutConstraint.activate(labelConstraints) + updateConstraintsIfNeeded() + } + + open func setData(user: User?) { + guard let user = user else { + return + } + + // avatar + if let imageUrl = user.userInfo?.avatarUrl, !imageUrl.isEmpty { + avatarImage.sd_setImage(with: URL(string: imageUrl), completed: nil) + avatarImage.backgroundColor = .clear + nameLabel.isHidden = true + } else { + avatarImage.sd_setImage(with: nil) + avatarImage.backgroundColor = UIColor.colorWithString(string: user.userId) + nameLabel.text = user.shortName(showAlias: false, count: 2) + nameLabel.isHidden = false + } + } +} diff --git a/NEConversationUIKit/NEConversationUIKit.podspec b/NEConversationUIKit/NEConversationUIKit.podspec index 30805f11..931edef2 100644 --- a/NEConversationUIKit/NEConversationUIKit.podspec +++ b/NEConversationUIKit/NEConversationUIKit.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'NEConversationUIKit' - s.version = '9.5.0' + s.version = '9.6.0' s.summary = 'Netease XKit' # This description is used to generate tags and improve search results. @@ -27,7 +27,7 @@ TODO: Add long description of the pod here. s.source = { :git => 'ssh://git@g.hz.netease.com:22222/yunxin-app/xkit-ios.git', :tag => s.version.to_s } # s.social_media_url = 'https://twitter.com/' - s.ios.deployment_target = '9.0' + s.ios.deployment_target = '10.0' s.swift_version = '5.0' s.source_files = 'NEConversationUIKit/Classes/**/*' @@ -39,7 +39,5 @@ TODO: Add long description of the pod here. } s.dependency 'NECommonUIKit' - s.dependency 'NEConversationKit' - s.dependency 'YXAlog' - s.dependency 'NIMSDK_LITE' + s.dependency 'NEChatKit' end diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/Contents.json b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funAddFriend.imageset/Contents.json b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funAddFriend.imageset/Contents.json new file mode 100644 index 00000000..de895b12 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funAddFriend.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "funAddFriend@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "funAddFriend@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funAddFriend.imageset/funAddFriend@2x.png b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funAddFriend.imageset/funAddFriend@2x.png new file mode 100644 index 00000000..c90f77b6 Binary files /dev/null and b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funAddFriend.imageset/funAddFriend@2x.png differ diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funAddFriend.imageset/funAddFriend@3x.png b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funAddFriend.imageset/funAddFriend@3x.png new file mode 100644 index 00000000..9e66e07c Binary files /dev/null and b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funAddFriend.imageset/funAddFriend@3x.png differ diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funCreateTeam.imageset/Contents.json b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funCreateTeam.imageset/Contents.json new file mode 100644 index 00000000..4944d582 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funCreateTeam.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "funCreateTeam@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "funCreateTeam@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funCreateTeam.imageset/funCreateTeam@2x.png b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funCreateTeam.imageset/funCreateTeam@2x.png new file mode 100644 index 00000000..2145e9d8 Binary files /dev/null and b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funCreateTeam.imageset/funCreateTeam@2x.png differ diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funCreateTeam.imageset/funCreateTeam@3x.png b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funCreateTeam.imageset/funCreateTeam@3x.png new file mode 100644 index 00000000..7e4d2e44 Binary files /dev/null and b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funCreateTeam.imageset/funCreateTeam@3x.png differ diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funSearch.imageset/Contents.json b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funSearch.imageset/Contents.json new file mode 100644 index 00000000..4a62afc6 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funSearch.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "search@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "search@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funSearch.imageset/search@2x.png b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funSearch.imageset/search@2x.png new file mode 100644 index 00000000..e2ce7a50 Binary files /dev/null and b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funSearch.imageset/search@2x.png differ diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funSearch.imageset/search@3x.png b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funSearch.imageset/search@3x.png new file mode 100644 index 00000000..36a33195 Binary files /dev/null and b/NEConversationUIKit/NEConversationUIKit/Assets/FunConversationUIKit.xcassets/funSearch.imageset/search@3x.png differ diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/Contents.json b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/Contents.json b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/backArrow.imageset/Contents.json b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/backArrow.imageset/Contents.json similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/backArrow.imageset/Contents.json rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/backArrow.imageset/Contents.json diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/backArrow.imageset/backArrow@2x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/backArrow.imageset/backArrow@2x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/backArrow.imageset/backArrow@2x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/backArrow.imageset/backArrow@2x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/backArrow.imageset/backArrow@3x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/backArrow.imageset/backArrow@3x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/backArrow.imageset/backArrow@3x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/backArrow.imageset/backArrow@3x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/brand_yunxin.imageset/Contents.json b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/brand_yunxin.imageset/Contents.json similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/brand_yunxin.imageset/Contents.json rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/brand_yunxin.imageset/Contents.json diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/brand_yunxin.imageset/brand_yunxin@2x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/brand_yunxin.imageset/brand_yunxin@2x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/brand_yunxin.imageset/brand_yunxin@2x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/brand_yunxin.imageset/brand_yunxin@2x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/brand_yunxin.imageset/brand_yunxin@3x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/brand_yunxin.imageset/brand_yunxin@3x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/brand_yunxin.imageset/brand_yunxin@3x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/brand_yunxin.imageset/brand_yunxin@3x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/chat_add.imageset/Contents.json b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/chat_add.imageset/Contents.json similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/chat_add.imageset/Contents.json rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/chat_add.imageset/Contents.json diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/chat_add.imageset/chat_add@2x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/chat_add.imageset/chat_add@2x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/chat_add.imageset/chat_add@2x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/chat_add.imageset/chat_add@2x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/chat_add.imageset/chat_add@3x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/chat_add.imageset/chat_add@3x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/chat_add.imageset/chat_add@3x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/chat_add.imageset/chat_add@3x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/chat_search.imageset/Contents.json b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/chat_search.imageset/Contents.json similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/chat_search.imageset/Contents.json rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/chat_search.imageset/Contents.json diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/chat_search.imageset/chat_search@2x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/chat_search.imageset/chat_search@2x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/chat_search.imageset/chat_search@2x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/chat_search.imageset/chat_search@2x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/chat_search.imageset/chat_search@3x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/chat_search.imageset/chat_search@3x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/chat_search.imageset/chat_search@3x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/chat_search.imageset/chat_search@3x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/conversation_search_icon.imageset/Contents.json b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/conversation_search_icon.imageset/Contents.json similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/conversation_search_icon.imageset/Contents.json rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/conversation_search_icon.imageset/Contents.json diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/conversation_search_icon.imageset/conversation_search_icon@2x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/conversation_search_icon.imageset/conversation_search_icon@2x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/conversation_search_icon.imageset/conversation_search_icon@2x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/conversation_search_icon.imageset/conversation_search_icon@2x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/conversation_search_icon.imageset/conversation_search_icon@3x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/conversation_search_icon.imageset/conversation_search_icon@3x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/conversation_search_icon.imageset/conversation_search_icon@3x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/conversation_search_icon.imageset/conversation_search_icon@3x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/noNeed_notify.imageset/Contents.json b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/noNeed_notify.imageset/Contents.json similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/noNeed_notify.imageset/Contents.json rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/noNeed_notify.imageset/Contents.json diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/noNeed_notify.imageset/noNeed_notify@2x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/noNeed_notify.imageset/noNeed_notify@2x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/noNeed_notify.imageset/noNeed_notify@2x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/noNeed_notify.imageset/noNeed_notify@2x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/noNeed_notify.imageset/noNeed_notify@3x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/noNeed_notify.imageset/noNeed_notify@3x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/noNeed_notify.imageset/noNeed_notify@3x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NEBaseConversationUIKit.xcassets/conversation/noNeed_notify.imageset/noNeed_notify@3x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/Contents.json b/NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/add_friend.imageset/Contents.json b/NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/add_friend.imageset/Contents.json similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/add_friend.imageset/Contents.json rename to NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/add_friend.imageset/Contents.json diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/add_friend.imageset/Group 139@2x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/add_friend.imageset/Group 139@2x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/add_friend.imageset/Group 139@2x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/add_friend.imageset/Group 139@2x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/add_friend.imageset/Group 139@3x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/add_friend.imageset/Group 139@3x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/add_friend.imageset/Group 139@3x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/add_friend.imageset/Group 139@3x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/create_discussion.imageset/Contents.json b/NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/create_discussion.imageset/Contents.json similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/create_discussion.imageset/Contents.json rename to NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/create_discussion.imageset/Contents.json diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/create_discussion.imageset/Group 140@2x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/create_discussion.imageset/Group 140@2x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/create_discussion.imageset/Group 140@2x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/create_discussion.imageset/Group 140@2x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/create_discussion.imageset/Group 140@3x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/create_discussion.imageset/Group 140@3x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/create_discussion.imageset/Group 140@3x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/create_discussion.imageset/Group 140@3x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/create_group.imageset/Contents.json b/NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/create_group.imageset/Contents.json similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/create_group.imageset/Contents.json rename to NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/create_group.imageset/Contents.json diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/create_group.imageset/Frame 53@2x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/create_group.imageset/Frame 53@2x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/create_group.imageset/Frame 53@2x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/create_group.imageset/Frame 53@2x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/create_group.imageset/Frame 53@3x.png b/NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/create_group.imageset/Frame 53@3x.png similarity index 100% rename from NEConversationUIKit/NEConversationUIKit/Assets/NEKitConversationUI.xcassets/conversation/create_group.imageset/Frame 53@3x.png rename to NEConversationUIKit/NEConversationUIKit/Assets/NormalConversationUIKit.xcassets/create_group.imageset/Frame 53@3x.png diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/en.lproj/Localizable.strings b/NEConversationUIKit/NEConversationUIKit/Assets/en.lproj/Localizable.strings index 8f6c02ff..15eea0dc 100644 --- a/NEConversationUIKit/NEConversationUIKit/Assets/en.lproj/Localizable.strings +++ b/NEConversationUIKit/NEConversationUIKit/Assets/en.lproj/Localizable.strings @@ -9,11 +9,14 @@ "create_senior_group"="Create Group"; "cancel_stickTop"="Cancel topping"; "stickTop"="Sticky on Top"; -"delete"="Cancel"; +"delete"="Delete"; "friend"="Contact"; +"contact"="Contact"; +"group"="Group"; "discussion_group"="Temp Group"; "senior_group"="Group"; "search"="Search"; +"cancel"="Cancel"; "search_keyword"="Enter the key words"; "user_not_exist"="Not Exist"; "session_empty"="No Session"; @@ -35,13 +38,5 @@ "you_were_mentioned"="[You were mentioned]"; - - - - - - - - - - +// error toast +"network_error"="Network is not available, please check"; diff --git a/NEConversationUIKit/NEConversationUIKit/Assets/zh-Hans.lproj/Localizable.strings b/NEConversationUIKit/NEConversationUIKit/Assets/zh-Hans.lproj/Localizable.strings index dd37bead..26c79f20 100644 --- a/NEConversationUIKit/NEConversationUIKit/Assets/zh-Hans.lproj/Localizable.strings +++ b/NEConversationUIKit/NEConversationUIKit/Assets/zh-Hans.lproj/Localizable.strings @@ -11,9 +11,12 @@ "stickTop"="置顶"; "delete"="删除"; "friend"="好友"; +"contact"="联系人"; +"group"="群聊"; "discussion_group"="讨论组"; "senior_group"="高级群"; "search"="搜索"; +"cancel"="取消"; "search_keyword"="请输入你要搜索的关键字"; "user_not_exist"="该用户不存在"; "session_empty"="暂无会话"; @@ -28,9 +31,13 @@ "file"="[文件消息]"; "internet_phone"="[音频通话]"; "video_chat"="[视频通话]"; -"unknown"="[未知消息]"; +"unknown"="[未知消息体]"; "appName"="云信IM"; "message_recalled"="此消息已撤回"; "you_were_mentioned"="[有人@我]"; + + +// error toast +"network_error"="当前网络不可用,请检查你的网络设置"; diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/Common/ConversationColorExtension.swift b/NEConversationUIKit/NEConversationUIKit/Classes/Common/ConversationColorExtension.swift index 9972743a..3b5932e5 100644 --- a/NEConversationUIKit/NEConversationUIKit/Classes/Common/ConversationColorExtension.swift +++ b/NEConversationUIKit/NEConversationUIKit/Classes/Common/ConversationColorExtension.swift @@ -18,7 +18,7 @@ public extension UIColor { // MARK: view background color - static let ne_lightBackgroundColor = UIColor(hexString: "#F1F1F6") + static let ne_lightBackgroundColor = UIColor(hexString: "#EFF1F4") static let ne_defautAvatarColor = UIColor(hexString: "#537FF4") static let ne_greenColor = UIColor(hexString: "#42C294") diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/Common/ConversationConstant.swift b/NEConversationUIKit/NEConversationUIKit/Classes/Common/ConversationConstant.swift index ad7580f9..53a2f356 100644 --- a/NEConversationUIKit/NEConversationUIKit/Classes/Common/ConversationConstant.swift +++ b/NEConversationUIKit/NEConversationUIKit/Classes/Common/ConversationConstant.swift @@ -6,9 +6,12 @@ import Foundation import NECoreKit -let coreLoader = CoreLoader() +let coreLoader = CoreLoader() func localizable(_ key: String) -> String { coreLoader.localizable(key) } public let ModuleName = "NEConversationUIKit" + +// 创建群聊 选择人数限制 +public var inviteNumberLimit: Int = 200 diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/Common/ConversationUI.swift b/NEConversationUIKit/NEConversationUIKit/Classes/Common/ConversationUI.swift index ad36ddf4..648369f1 100644 --- a/NEConversationUIKit/NEConversationUIKit/Classes/Common/ConversationUI.swift +++ b/NEConversationUIKit/NEConversationUIKit/Classes/Common/ConversationUI.swift @@ -7,8 +7,7 @@ import Foundation @_exported import NECommonKit @_exported import NECommonUIKit -@_exported import NEConversationKit +@_exported import NEChatKit @_exported import NIMSDK @_exported import NECoreKit -// @_exported @_exported import NECoreIMKit diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/View/ConversationListCell.swift b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Cell/NEBaseConversationListCell.swift similarity index 80% rename from NEConversationUIKit/NEConversationUIKit/Classes/Conversation/View/ConversationListCell.swift rename to NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Cell/NEBaseConversationListCell.swift index d6d18514..2b569775 100644 --- a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/View/ConversationListCell.swift +++ b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Cell/NEBaseConversationListCell.swift @@ -6,21 +6,12 @@ import UIKit import NIMSDK -open class ConversationListCell: UITableViewCell { +@objcMembers +open class NEBaseConversationListCell: UITableViewCell { // private var viewModel = ConversationViewModel() public var topStickInfos = [NIMSession: NIMStickTopSessionInfo]() private let repo = ConversationRepo() private var timeWidth: NSLayoutConstraint? - override open func awakeFromNib() { - super.awakeFromNib() - // Initialization code - } - - override open func setSelected(_ selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - - // Configure the view for the selected state - } override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -32,7 +23,7 @@ open class ConversationListCell: UITableViewCell { fatalError("init(coder:) has not been implemented") } - func setupSubviews() { + open func setupSubviews() { selectionStyle = .none contentView.addSubview(headImge) contentView.addSubview(redAngleView) @@ -41,16 +32,6 @@ open class ConversationListCell: UITableViewCell { contentView.addSubview(timeLabel) contentView.addSubview(notifyMsg) - NSLayoutConstraint.activate([ - headImge.leftAnchor.constraint( - equalTo: contentView.leftAnchor, - constant: NEConstant.screenInterval - ), - headImge.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - headImge.widthAnchor.constraint(equalToConstant: 42), - headImge.heightAnchor.constraint(equalToConstant: 42), - ]) - NSLayoutConstraint.activate([ redAngleView.centerXAnchor.constraint(equalTo: headImge.rightAnchor, constant: -8), redAngleView.centerYAnchor.constraint(equalTo: headImge.topAnchor, constant: 8), @@ -66,33 +47,14 @@ open class ConversationListCell: UITableViewCell { timeLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 17), ]) - NSLayoutConstraint.activate([ - title.leftAnchor.constraint(equalTo: headImge.rightAnchor, constant: 12), - title.rightAnchor.constraint(equalTo: timeLabel.leftAnchor, constant: -5), - title.topAnchor.constraint(equalTo: headImge.topAnchor), - ]) - NSLayoutConstraint.activate([ subTitle.leftAnchor.constraint(equalTo: headImge.rightAnchor, constant: 12), subTitle.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -50), subTitle.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 6), ]) - - NSLayoutConstraint.activate([ - notifyMsg.rightAnchor.constraint(equalTo: timeLabel.rightAnchor), - notifyMsg.topAnchor.constraint(equalTo: timeLabel.bottomAnchor, constant: 5), - notifyMsg.widthAnchor.constraint(equalToConstant: 13), - notifyMsg.heightAnchor.constraint(equalToConstant: 13), - ]) } - func initSubviewsLayout() { - if NEKitConversationConfig.shared.ui.avatarType == .rectangle { - headImge.layer.cornerRadius = NEKitConversationConfig.shared.ui.avatarCornerRadius - } else if NEKitConversationConfig.shared.ui.avatarType == .cycle { - headImge.layer.cornerRadius = 21.0 - } - } + func initSubviewsLayout() {} open func configData(sessionModel: ConversationListModel?) { guard let conversationModel = sessionModel else { return } @@ -102,8 +64,9 @@ open class ConversationListCell: UITableViewCell { if let imageName = conversationModel.userInfo?.userInfo?.avatarUrl { headImge.setTitle("") headImge.sd_setImage(with: URL(string: imageName), completed: nil) + headImge.backgroundColor = .clear } else { - headImge.setTitle(conversationModel.userInfo?.showName(false) ?? "") + headImge.setTitle(conversationModel.userInfo?.shortName(showAlias: false, count: 2) ?? "") headImge.sd_setImage(with: nil, completed: nil) headImge.backgroundColor = UIColor .colorWithString(string: conversationModel.userInfo?.userId) @@ -122,6 +85,7 @@ open class ConversationListCell: UITableViewCell { if let imageName = conversationModel.teamInfo?.avatarUrl { headImge.setTitle("") headImge.sd_setImage(with: URL(string: imageName), completed: nil) + headImge.backgroundColor = .clear } else { headImge.setTitle(conversationModel.teamInfo?.getShowName() ?? "") headImge.sd_setImage(with: nil, completed: nil) @@ -179,16 +143,6 @@ open class ConversationListCell: UITableViewCell { timeWidth?.constant = labelSize.width + 1 // ceil() } } - - // backgroundColor - if let session = conversationModel.recentSession?.session { - let isTop = topStickInfos[session] != nil - if isTop { - contentView.backgroundColor = UIColor(hexString: "0xF3F5F7") - } else { - contentView.backgroundColor = .white - } - } } func timestampDescriptionForRecentSession(recentSession: NIMRecentSession) -> TimeInterval { @@ -254,7 +208,7 @@ open class ConversationListCell: UITableViewCell { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.textColor = NEKitConversationConfig.shared.ui.titleColor - label.font = NEKitConversationConfig.shared.ui.titleFont + label.font = NEKitConversationConfig.shared.ui.titleFont ?? UIFont.systemFont(ofSize: 16) label.text = "Oliver" return label }() diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/View/ConversationSearchCell.swift b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Cell/NEBaseConversationSearchCell.swift similarity index 64% rename from NEConversationUIKit/NEConversationUIKit/Classes/Conversation/View/ConversationSearchCell.swift rename to NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Cell/NEBaseConversationSearchCell.swift index ed5c2e23..97e115e9 100644 --- a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/View/ConversationSearchCell.swift +++ b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Cell/NEBaseConversationSearchCell.swift @@ -6,16 +6,26 @@ import UIKit @objcMembers -public class ConversationSearchCell: TextBaseCell { +open class NEBaseConversationSearchCell: TextBaseCell { + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + public var searchModel: ConversationSearchListModel? { didSet { if let _ = searchModel { if let userInfo = searchModel?.userInfo { titleLabel.text = userInfo.showName() + subTitleLabel.text = userInfo.userId if let imageName = userInfo.userInfo?.avatarUrl { headImge.setTitle("") headImge.sd_setImage(with: URL(string: imageName), completed: nil) + headImge.backgroundColor = .clear } else { headImge.setTitle(userInfo.showName() ?? "") headImge.sd_setImage(with: nil, completed: nil) @@ -24,9 +34,11 @@ public class ConversationSearchCell: TextBaseCell { } if let teamInfo = searchModel?.teamInfo { titleLabel.text = teamInfo.getShowName() + subTitleLabel.text = nil if let imageName = teamInfo.avatarUrl { headImge.setTitle("") headImge.sd_setImage(with: URL(string: imageName), completed: nil) + headImge.backgroundColor = .clear } else { headImge.setTitle(teamInfo.getShowName()) headImge.sd_setImage(with: nil, completed: nil) @@ -45,19 +57,32 @@ public class ConversationSearchCell: TextBaseCell { // range必须要加,参数分别表示从索引几开始取几个字符 attributedStr.addAttribute( .foregroundColor, - value: UIColor.ne_blueText, + value: getRangeTextColor(), range: range ) titleLabel.attributedText = attributedStr + titleLabelCenterYAnchor?.isActive = true + titleLabelTopAnchor?.isActive = false + subTitleLabel.isHidden = true + } + if let subTitleText = subTitleLabel.text, + let range = subTitleText.findAllIndex(searchText).first { + let attributedStr = NSMutableAttributedString(string: subTitleText) + // range必须要加,参数分别表示从索引几开始取几个字符 + attributedStr.addAttribute( + .foregroundColor, + value: getRangeTextColor(), + range: range + ) + subTitleLabel.attributedText = attributedStr + subTitleLabel.isHidden = false + titleLabelTopAnchor?.isActive = true + titleLabelCenterYAnchor?.isActive = false } } } - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") + func getRangeTextColor() -> UIColor { + UIColor.ne_blueText } } diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/ConversationBaseViewController.swift b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/ConversationBaseViewController.swift deleted file mode 100644 index 3010619e..00000000 --- a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/ConversationBaseViewController.swift +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NECoreKit - -@objc open class ConversationBaseViewController: UIViewController { - override open func viewDidLoad() { - super.viewDidLoad() - view.backgroundColor = .white - setupBackUI() - } - - private func setupBackUI() { - let image = UIImage.ne_imageNamed(name: "backArrow")?.withRenderingMode(.alwaysOriginal) - navigationItem.leftBarButtonItem = UIBarButtonItem( - image: image, - style: .plain, - target: self, - action: #selector(backEvent) - ) - } - - @objc func backEvent() { - navigationController?.popViewController(animated: true) - } -} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/ConversationController.swift b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/NEBaseConversationController.swift similarity index 54% rename from NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/ConversationController.swift rename to NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/NEBaseConversationController.swift index d1356088..c811a6fd 100644 --- a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/ConversationController.swift +++ b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/NEBaseConversationController.swift @@ -9,13 +9,17 @@ import NECoreKit import NIMSDK @objcMembers -open class ConversationController: UIViewController, NIMChatManagerDelegate { +open class NEBaseConversationController: UIViewController, NIMChatManagerDelegate { public let viewmodel = ConversationViewModel() - public var listCtrl = ConversationListViewController() + public var listCtrl = NEBaseConversationListViewController() - override public func viewWillAppear(_ animated: Bool) { + override open func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - navigationController?.isNavigationBarHidden = true + if let useSystemNav = NEConfigManager.instance.getParameter(key: useSystemNav) as? Bool, useSystemNav { + navigationController?.isNavigationBarHidden = NEKitConversationConfig.shared.ui.hiddenNav + } else { + navigationController?.isNavigationBarHidden = true + } } override open func viewDidLoad() { @@ -24,115 +28,62 @@ open class ConversationController: UIViewController, NIMChatManagerDelegate { NIMSDK.shared().chatManager.add(self) } - func setupSubviews() { -// NEKitConversationConfig.shared.ui.avatarType = .rectangle + func initSystemNav() { + let brandBarBtn = UIButton() + brandBarBtn.setTitle(localizable("appName"), for: .normal) + brandBarBtn.setImage(UIImage.ne_imageNamed(name: "brand_yunxin"), for: .normal) + brandBarBtn.layoutButtonImage(style: .left, space: 12) + brandBarBtn.setTitleColor(UIColor.black, for: .normal) + brandBarBtn.titleLabel?.font = NEConstant.textFont("PingFangSC-Medium", 20) + let brandBtn = UIBarButtonItem(customView: brandBarBtn) + navigationItem.leftBarButtonItem = brandBtn + } - listCtrl.view.translatesAutoresizingMaskIntoConstraints = false - addChild(listCtrl) + open func setupSubviews() { + initSystemNav() view.addSubview(navView) - view.addSubview(listCtrl.view) - NSLayoutConstraint.activate([ navView.topAnchor.constraint(equalTo: view.topAnchor), navView.leftAnchor.constraint(equalTo: view.leftAnchor), navView.rightAnchor.constraint(equalTo: view.rightAnchor), navView.heightAnchor - .constraint(equalToConstant: NEConstant.navigationHeight + NEConstant - .statusBarHeight + 16), + .constraint(equalToConstant: NEConstant.navigationAndStatusHeight), ]) - NSLayoutConstraint.activate([ - listCtrl.view.topAnchor.constraint(equalTo: navView.bottomAnchor), - listCtrl.view.leftAnchor.constraint(equalTo: view.leftAnchor), - listCtrl.view.rightAnchor.constraint(equalTo: view.rightAnchor), - listCtrl.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), - ]) + listCtrl.view.translatesAutoresizingMaskIntoConstraints = false + addChild(listCtrl) + view.addSubview(listCtrl.view) + } + + deinit { + NIMSDK.shared().chatManager.remove(self) } // MARK: lazyMethod - public lazy var navView: ConversationNavView = { - let nav = ConversationNavView(frame: CGRect.zero) + public lazy var navView: TabNavigationView = { + let nav = TabNavigationView(frame: CGRect.zero) nav.translatesAutoresizingMaskIntoConstraints = false - nav.backgroundColor = .white nav.delegate = self nav.isHidden = NEKitConversationConfig.shared.ui.hiddenNav return nav }() - - public lazy var popListController: PopListViewController = { - let popController = PopListViewController() - return popController - }() } -extension ConversationController: ConversationNavViewDelegate { - open func searchAction() { - Router.shared.use( - SearchContactPageRouter, - parameters: ["nav": navigationController as Any], - closure: nil - ) - } - - open func didClickAddBtn() { - print("add click") - - if children.contains(popListController) == false { - popListController.itemDatas = getPopListItems() - addChild(popListController) - popListController.view.frame = listCtrl.view.frame - } - if popListController.view.superview != nil { - popListController.removeSelf() - } else { - view.addSubview(popListController.view) - } - } - - func getPopListItems() -> [PopListItem] { - weak var weakSelf = self - var items = [PopListItem]() - let addFriend = PopListItem() - addFriend.showName = localizable("add_friend") - addFriend.image = UIImage.ne_imageNamed(name: "add_friend") - addFriend.completion = { - Router.shared.use( - ContactAddFriendRouter, - parameters: ["nav": self.navigationController as Any] - ) { obj, routerState, str in - } - } - items.append(addFriend) +extension NEBaseConversationController: TabNavigationViewDelegate { + open func searchAction() {} - let createGroup = PopListItem() - createGroup.showName = localizable("create_discussion_group") - createGroup.image = UIImage.ne_imageNamed(name: "create_discussion") - createGroup.completion = { - weakSelf?.createDiscussGroup() - } - items.append(createGroup) - - let createDicuss = PopListItem() - createDicuss.showName = localizable("create_senior_group") - createDicuss.image = UIImage.ne_imageNamed(name: "create_group") - createDicuss.completion = { - weakSelf?.createSeniorGroup() - } - items.append(createDicuss) + open func didClickAddBtn() {} - return items - } - - func createDiscussGroup() { + open func createDiscussGroup() { Router.shared.register(ContactSelectedUsersRouter) { param in print("user setting accids : ", param) Router.shared.use(TeamCreateDisuss, parameters: param, closure: nil) } Router.shared.use( ContactUserSelectRouter, - parameters: ["nav": navigationController as Any, "limit": 200], + parameters: ["nav": navigationController as Any, "limit": inviteNumberLimit], closure: nil ) weak var weakSelf = self @@ -153,7 +104,7 @@ extension ConversationController: ConversationNavViewDelegate { } } - func createSeniorGroup() { + open func createSeniorGroup() { Router.shared.register(ContactSelectedUsersRouter) { param in Router.shared.use(TeamCreateSenior, parameters: param, closure: nil) } @@ -182,7 +133,7 @@ extension ConversationController: ConversationNavViewDelegate { // MARK: =========================NIMChatManagerDelegate======================== - public func onRecvRevokeMessageNotification(_ notification: NIMRevokeMessageNotification) { + open func onRecvRevokeMessageNotification(_ notification: NIMRevokeMessageNotification) { guard let msg = notification.message else { return } @@ -190,14 +141,14 @@ extension ConversationController: ConversationNavViewDelegate { } } - public func saveRevokeMessage(_ message: NIMMessage, _ completion: @escaping (Error?) -> Void) { + open func saveRevokeMessage(_ message: NIMMessage, _ completion: @escaping (Error?) -> Void) { let messageNew = NIMMessage() messageNew.text = localizable("message_recalled") var muta = [String: Any]() muta[revokeLocalMessage] = true - if message.messageType == .text { - muta[revokeLocalMessageContent] = message.text - } +// if message.messageType == .text { +// muta[revokeLocalMessageContent] = message.text +// } messageNew.timestamp = message.timestamp messageNew.from = message.from messageNew.localExt = muta diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/ConversationListViewController.swift b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/NEBaseConversationListViewController.swift similarity index 90% rename from NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/ConversationListViewController.swift rename to NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/NEBaseConversationListViewController.swift index 71ea94ed..51296cf7 100644 --- a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/ConversationListViewController.swift +++ b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/NEBaseConversationListViewController.swift @@ -1,4 +1,3 @@ - // Copyright (c) 2022 NetEase, Inc. All rights reserved. // Use of this source code is governed by a MIT license that can be // found in the LICENSE file. @@ -6,26 +5,28 @@ import UIKit import NIMSDK +@objc public protocol ConversationListViewControllerDelegate { func onDataLoaded() } @objcMembers -open class ConversationListViewController: UIViewController { +open class NEBaseConversationListViewController: UIViewController { public var viewModel = ConversationViewModel() - private let className = "ConversationListViewController" - + var className = "ConversationListViewController" + public var networkToolHeight: CGFloat = 36 public var topViewHeight: CGFloat = 0 { didSet { - topViewHeightAnchor?.constant = topViewHeight + topViewHeightAnchor?.constant = brokenNetworkView.isHidden ? topViewHeight : networkToolHeight topView.isHidden = topViewHeight <= 0 } } + public var deleteBottonColor: UIColor = NEConstant.hexRGB(0xA8ABB6) public var topViewHeightAnchor: NSLayoutConstraint? public var delegate: ConversationListViewControllerDelegate? - public var registerCellDic = [0: ConversationListCell.self] + public var registerCellDic = [0: NEBaseConversationListCell.self] override open func viewDidLoad() { super.viewDidLoad() @@ -36,6 +37,19 @@ open class ConversationListViewController: UIViewController { override open func viewWillAppear(_ animated: Bool) { weak var weakSelf = self + + NEChatDetectNetworkTool.shareInstance.netWorkReachability { status in + if status == .notReachable { + weakSelf?.brokenNetworkView.isHidden = false + weakSelf?.topView.isHidden = true + weakSelf?.topViewHeightAnchor?.constant = weakSelf?.networkToolHeight ?? 0 + } else { + weakSelf?.brokenNetworkView.isHidden = true + weakSelf?.topView.isHidden = false + weakSelf?.topViewHeightAnchor?.constant = weakSelf?.topViewHeight ?? 0 + } + } + viewModel.loadStickTopSessionInfos { error, sessionInfos in NELog.infoLog( ModuleName + " " + self.className, @@ -51,18 +65,6 @@ open class ConversationListViewController: UIViewController { open func initialConfig() { viewModel.delegate = self - weak var weakSelf = self - NEChatDetectNetworkTool.shareInstance.netWorkReachability { status in - if status == .notReachable { - weakSelf?.brokenNetworkView.isHidden = false - weakSelf?.topView.isHidden = true - weakSelf?.topViewHeightAnchor?.constant = 36 - } else { - weakSelf?.brokenNetworkView.isHidden = true - weakSelf?.topView.isHidden = false - weakSelf?.topViewHeightAnchor?.constant = weakSelf?.topViewHeight ?? 0 - } - } } open func setupSubviews() { @@ -87,7 +89,7 @@ open class ConversationListViewController: UIViewController { tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) - registerCellDic.forEach { (key: Int, value: ConversationListCell.Type) in + registerCellDic.forEach { (key: Int, value: NEBaseConversationListCell.Type) in tableView.register(value, forCellReuseIdentifier: "\(key)") } @@ -144,15 +146,13 @@ open class ConversationListViewController: UIViewController { tableView.separatorStyle = .none tableView.delegate = self tableView.dataSource = self - tableView.rowHeight = 62 tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 0.1)) - tableView.backgroundColor = .white return tableView }() public lazy var brokenNetworkView: NEBrokenNetworkView = { let view = - NEBrokenNetworkView(frame: CGRect(x: 0, y: 0, width: NEConstant.screenWidth, height: 36)) + NEBrokenNetworkView(frame: CGRect(x: 0, y: 0, width: NEConstant.screenWidth, height: networkToolHeight)) view.isHidden = true return view }() @@ -165,6 +165,7 @@ open class ConversationListViewController: UIViewController { ) view.translatesAutoresizingMaskIntoConstraints = false view.isHidden = true + view.backgroundColor = .clear return view }() @@ -172,7 +173,7 @@ open class ConversationListViewController: UIViewController { // MARK: ====================== private method=========================== -extension ConversationListViewController { +extension NEBaseConversationListViewController { private func onTopRecentAtIndexPath(rencent: NIMRecentSession, indexPath: IndexPath, isTop: Bool, _ completion: @escaping (NSError?, NIMStickTopSessionInfo?) @@ -230,7 +231,7 @@ extension ConversationListViewController { } } -extension ConversationListViewController: UITableViewDelegate, UITableViewDataSource { +extension NEBaseConversationListViewController: UITableViewDelegate, UITableViewDataSource { open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { let count = viewModel.conversationListArray?.count ?? 0 NELog.infoLog(ModuleName + " " + "ConversationListViewController", @@ -241,10 +242,10 @@ extension ConversationListViewController: UITableViewDelegate, UITableViewDataSo open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let model = viewModel.conversationListArray?[indexPath.row] - var reusedId = "\(model?.customType ?? 0)" + let reusedId = "\(model?.customType ?? 0)" let cell = tableView.dequeueReusableCell(withIdentifier: reusedId, for: indexPath) - if let c = cell as? ConversationListCell { + if let c = cell as? NEBaseConversationListCell { c.topStickInfos = viewModel.stickTopInfos c.configData(sessionModel: model) } @@ -287,7 +288,7 @@ extension ConversationListViewController: UITableViewDelegate, UITableViewDataSo NEKitConversationConfig.shared.ui.stickTopBottonTitle) { action, indexPath in weakSelf?.topActionHandler(action: action, indexPath: indexPath, isTop: isTop) } - deleteAction.backgroundColor = NEKitConversationConfig.shared.ui.deleteBottonColor + deleteAction.backgroundColor = NEKitConversationConfig.shared.ui.deleteBottonColor ?? deleteBottonColor topAction.backgroundColor = NEKitConversationConfig.shared.ui.stickTopBottonColor rowActions.append(deleteAction) rowActions.append(topAction) @@ -328,7 +329,7 @@ extension ConversationListViewController: UITableViewDelegate, UITableViewDataSo } */ - open func deleteActionHandler(action: UITableViewRowAction, indexPath: IndexPath) { + open func deleteActionHandler(action: UITableViewRowAction?, indexPath: IndexPath) { let conversationModel = viewModel.conversationListArray?[indexPath.row] if let recentSession = conversationModel?.recentSession { viewModel.deleteRecentSession(recentSession: recentSession) @@ -339,7 +340,11 @@ extension ConversationListViewController: UITableViewDelegate, UITableViewDataSo } } - open func topActionHandler(action: UITableViewRowAction, indexPath: IndexPath, isTop: Bool) { + open func topActionHandler(action: UITableViewRowAction?, indexPath: IndexPath, isTop: Bool) { + if !NEChatDetectNetworkTool.shareInstance.isNetworkRecahability() { + showToast(localizable("network_error")) + return + } let conversationModel = viewModel.conversationListArray?[indexPath.row] if let recentSession = conversationModel?.recentSession { onTopRecentAtIndexPath( @@ -367,7 +372,7 @@ extension ConversationListViewController: UITableViewDelegate, UITableViewDataSo // MARK: UI UIKit提供的重写方法 -extension ConversationListViewController { +extension NEBaseConversationListViewController { /// cell点击事件,可重写该事件处理自己的逻辑业务,例如跳转到指定的会话页面 /// - Parameters: /// - sessionType: 会话类型 @@ -413,24 +418,24 @@ extension ConversationListViewController { // MARK: ================= ConversationViewModelDelegate=================== -extension ConversationListViewController: ConversationViewModelDelegate { - public func didAddRecentSession() { +extension NEBaseConversationListViewController: ConversationViewModelDelegate { + open func didAddRecentSession() { NELog.infoLog("ConversationListViewController", desc: "didAddRecentSession") emptyView.isHidden = (viewModel.conversationListArray?.count ?? 0) > 0 viewModel.sortRecentSession() tableView.reloadData() } - public func didUpdateRecentSession(index: Int) { + open func didUpdateRecentSession(index: Int) { let indexPath = IndexPath(row: index, section: 0) tableView.reloadRows(at: [indexPath], with: .none) } - public func reloadData() { + open func reloadData() { delegate?.onDataLoaded() } - public func reloadTableView() { + open func reloadTableView() { emptyView.isHidden = (viewModel.conversationListArray?.count ?? 0) > 0 viewModel.sortRecentSession() tableView.reloadData() diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/NEBaseConversationNavigationController.swift b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/NEBaseConversationNavigationController.swift new file mode 100644 index 00000000..d66ad2c2 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/NEBaseConversationNavigationController.swift @@ -0,0 +1,61 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreKit + +@objcMembers +open class NEBaseConversationNavigationController: UIViewController, UIGestureRecognizerDelegate { + var topConstant: CGFloat = 0 + public let customNavigationView = NENavigationView() + + override open var title: String? { + get { + super.title + } + + set { + super.title = newValue + customNavigationView.navTitle.text = newValue + } + } + + override open func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .white + navigationController?.interactivePopGestureRecognizer?.delegate = self + setupBackUI() + + if let useSystemNav = NEConfigManager.instance.getParameter(key: useSystemNav) as? Bool, useSystemNav { + navigationController?.isNavigationBarHidden = false + } else { + navigationController?.isNavigationBarHidden = true + topConstant = NEConstant.navigationAndStatusHeight + customNavigationView.translatesAutoresizingMaskIntoConstraints = false + customNavigationView.addBackButtonTarget(target: self, selector: #selector(backEvent)) + customNavigationView.moreButton.isHidden = true + view.addSubview(customNavigationView) + NSLayoutConstraint.activate([ + customNavigationView.leftAnchor.constraint(equalTo: view.leftAnchor), + customNavigationView.rightAnchor.constraint(equalTo: view.rightAnchor), + customNavigationView.topAnchor.constraint(equalTo: view.topAnchor), + customNavigationView.heightAnchor.constraint(equalToConstant: topConstant), + ]) + } + } + + open func setupBackUI() { + let image = UIImage.ne_imageNamed(name: "backArrow")?.withRenderingMode(.alwaysOriginal) + navigationItem.leftBarButtonItem = UIBarButtonItem( + image: image, + style: .plain, + target: self, + action: #selector(backEvent) + ) + } + + open func backEvent() { + navigationController?.popViewController(animated: true) + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/ConversationSearchController.swift b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/NEBaseConversationSearchController.swift similarity index 60% rename from NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/ConversationSearchController.swift rename to NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/NEBaseConversationSearchController.swift index c959a9db..badacc99 100644 --- a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/ConversationSearchController.swift +++ b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/NEBaseConversationSearchController.swift @@ -7,96 +7,28 @@ import UIKit import NIMSDK @objcMembers -open class SearchSessionHeaderView: UITableViewHeaderFooterView { - override init(reuseIdentifier: String?) { - super.init(reuseIdentifier: reuseIdentifier) - - addSubview(title) - addSubview(bottomLine) - - NSLayoutConstraint.activate([ - title.topAnchor.constraint(equalTo: topAnchor), - title.leftAnchor.constraint(equalTo: leftAnchor, constant: 20), - ]) - - NSLayoutConstraint.activate([ - bottomLine.rightAnchor.constraint(equalTo: rightAnchor, constant: -20), - bottomLine.leftAnchor.constraint(equalTo: title.leftAnchor), - bottomLine.bottomAnchor.constraint(equalTo: bottomAnchor), - bottomLine.heightAnchor.constraint(equalToConstant: 1), - ]) - } - - public required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func setUpTitle(title: String) { - self.title.text = title - } - - private lazy var title: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.textColor = UIColor.ne_emptyTitleColor - label.font = NEConstant.defaultTextFont(14) - label.textAlignment = .left - return label - }() - - private lazy var bottomLine: UIView = { - let view = UIView() - view.translatesAutoresizingMaskIntoConstraints = false - view.backgroundColor = UIColor(hexString: "0xDBE0E8") - return view - }() -} - -@objcMembers -open class ConversationSearchController: ConversationBaseViewController, UITableViewDelegate, +open class NEBaseConversationSearchController: NEBaseConversationNavigationController, UITableViewDelegate, UITableViewDataSource { - private var viewModel = ConversationSearchViewModel() - private let tag = "ConversationSearchController" - private var searchStr = "" - private let headTitleArr = [ + var viewModel = ConversationSearchViewModel() + var tag = "ConversationSearchBaseController" + var searchStr = "" + var headTitleArr = [ localizable("friend"), localizable("discussion_group"), localizable("senior_group"), ] - override public func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() setupSubviews() initialConfig() } - override public func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - navigationController?.isNavigationBarHidden = false - } - - func setupSubviews() { + open func setupSubviews() { view.addSubview(tableView) view.addSubview(searchTextField) view.addSubview(emptyView) - NSLayoutConstraint.activate([ - searchTextField.topAnchor.constraint( - equalTo: view.topAnchor, - constant: NEConstant.navigationHeight + NEConstant.statusBarHeight + 20 - ), - searchTextField.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20), - searchTextField.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), - searchTextField.heightAnchor.constraint(equalToConstant: 32), - ]) - - NSLayoutConstraint.activate([ - tableView.rightAnchor.constraint(equalTo: view.rightAnchor), - tableView.leftAnchor.constraint(equalTo: view.leftAnchor), - tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), - tableView.topAnchor.constraint(equalTo: searchTextField.bottomAnchor, constant: 20), - ]) - NSLayoutConstraint.activate([ emptyView.rightAnchor.constraint(equalTo: tableView.rightAnchor), emptyView.leftAnchor.constraint(equalTo: tableView.leftAnchor), @@ -105,13 +37,13 @@ open class ConversationSearchController: ConversationBaseViewController, UITable ]) } - func initialConfig() { + open func initialConfig() { title = localizable("search") } // MARK: private method - func searchTextFieldChange(textfield: SearchTextField) { + open func searchTextFieldChange(textfield: SearchTextField) { guard let searchText = textfield.text else { return } @@ -147,30 +79,22 @@ open class ConversationSearchController: ConversationBaseViewController, UITable // MARK: lazy method - private lazy var tableView: UITableView = { + public lazy var tableView: UITableView = { let tableView = UITableView(frame: .zero, style: .plain) tableView.translatesAutoresizingMaskIntoConstraints = false tableView.separatorStyle = .none tableView.keyboardDismissMode = .onDrag tableView.delegate = self tableView.dataSource = self - tableView.register( - ConversationSearchCell.self, - forCellReuseIdentifier: "\(NSStringFromClass(ConversationSearchCell.self))" - ) tableView.rowHeight = 60 tableView.backgroundColor = .white - tableView.register( - SearchSessionHeaderView.self, - forHeaderFooterViewReuseIdentifier: "\(NSStringFromClass(SearchSessionHeaderView.self))" - ) tableView.sectionHeaderHeight = 30 tableView.sectionFooterHeight = 0 tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 0.1)) return tableView }() - private lazy var searchTextField: SearchTextField = { + public lazy var searchTextField: SearchTextField = { let textField = SearchTextField() let leftImageView = UIImageView(image: UIImage .ne_imageNamed(name: "conversation_search_icon")) @@ -182,15 +106,15 @@ open class ConversationSearchController: ConversationBaseViewController, UITable textField.textColor = UIColor.ne_greyText textField.translatesAutoresizingMaskIntoConstraints = false textField.layer.cornerRadius = 8 - textField.backgroundColor = UIColor(hexString: "0xEFF1F4") - textField.clearButtonMode = .whileEditing + textField.backgroundColor = .ne_lightBackgroundColor + textField.clearButtonMode = .always textField.returnKeyType = .search textField.addTarget(self, action: #selector(searchTextFieldChange), for: .editingChanged) - textField.placeholder = localizable("search_keyword") + textField.placeholder = localizable("search") return textField }() - private lazy var emptyView: NEEmptyDataView = { + public lazy var emptyView: NEEmptyDataView = { let view = NEEmptyDataView( imageName: "user_empty", content: localizable("user_not_exist"), @@ -198,17 +122,17 @@ open class ConversationSearchController: ConversationBaseViewController, UITable ) view.translatesAutoresizingMaskIntoConstraints = false view.isHidden = true + view.backgroundColor = .clear return view - }() // MARK: UITableViewDelegate, UITableViewDataSource - public func numberOfSections(in tableView: UITableView) -> Int { + open func numberOfSections(in tableView: UITableView) -> Int { 3 } - public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if let friend = viewModel.searchResult?.friend, section == 0 { return friend.count } else if let contactGroup = viewModel.searchResult?.contactGroup, section == 1 { @@ -220,12 +144,12 @@ open class ConversationSearchController: ConversationBaseViewController, UITable } } - public func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { + open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell( - withIdentifier: "\(NSStringFromClass(ConversationSearchCell.self))", + withIdentifier: "\(NSStringFromClass(NEBaseConversationSearchCell.self))", for: indexPath - ) as! ConversationSearchCell + ) as! NEBaseConversationSearchCell if indexPath.section == 0 { cell.searchModel = viewModel.searchResult?.friend[indexPath.row] } else if indexPath.section == 1 { @@ -237,7 +161,7 @@ open class ConversationSearchController: ConversationBaseViewController, UITable return cell } - public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if indexPath.section == 0 { let searchModel = viewModel.searchResult?.friend[indexPath.row] if let userId = searchModel?.userInfo?.userId { @@ -272,20 +196,20 @@ open class ConversationSearchController: ConversationBaseViewController, UITable } } - public func tableView(_ tableView: UITableView, - viewForHeaderInSection section: Int) -> UIView? { + open func tableView(_ tableView: UITableView, + viewForHeaderInSection section: Int) -> UIView? { let sectionView = tableView .dequeueReusableHeaderFooterView( - withIdentifier: "\(NSStringFromClass(SearchSessionHeaderView.self))" - ) as! SearchSessionHeaderView + withIdentifier: "\(NSStringFromClass(SearchSessionBaseView.self))" + ) as! SearchSessionBaseView sectionView.setUpTitle(title: headTitleArr[section]) sectionView.backgroundView = UIView() sectionView.backgroundView?.backgroundColor = .white return sectionView } - public func tableView(_ tableView: UITableView, - heightForHeaderInSection section: Int) -> CGFloat { + open func tableView(_ tableView: UITableView, + heightForHeaderInSection section: Int) -> CGFloat { if let friend = viewModel.searchResult?.friend, friend.count > 0, section == 0 { return 30 diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/NEBasePopListViewController.swift b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/NEBasePopListViewController.swift new file mode 100644 index 00000000..0d688337 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/Controller/NEBasePopListViewController.swift @@ -0,0 +1,112 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import UIKit +import NECommonKit + +@objcMembers +open class PopListItem: NSObject { + public typealias PopListClick = () -> Void + public var image: UIImage? + public var showName: String? + public var showNameColor: UIColor = NEConstant.hexRGB(0x333333) + public var completion: PopListClick? + + override public init() {} +} + +@objcMembers +open class NEBasePopListViewController: UIViewController { + public var itemDatas = [PopListItem]() + public let shadowView = UIView() + public var buttonHeight: CGFloat = 32.0 + let popView = UIView() + public var popViewWidth: CGFloat = 122.0 + public var popViewRadius: CGFloat = 8.0 + + override public func viewDidLoad() { + super.viewDidLoad() + setupUI() + } + + override public func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + removeSelf() + } + + func setupUI() { + view.backgroundColor = .clear + + shadowView.translatesAutoresizingMaskIntoConstraints = false + shadowView.backgroundColor = .clear + view.addSubview(shadowView) + shadowView.clipsToBounds = false + shadowView.layer.shadowOffset = CGSize(width: 0, height: 4) + shadowView.layer.shadowColor = NEConstant.hexRGB(0x85888C).cgColor + shadowView.layer.shadowOpacity = 0.25 + shadowView.layer.shadowRadius = 7 + + shadowView.addSubview(popView) + popView.clipsToBounds = true + popView.layer.cornerRadius = popViewRadius + popView.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + popView.topAnchor.constraint(equalTo: shadowView.topAnchor), + popView.rightAnchor.constraint(equalTo: shadowView.rightAnchor), + popView.leftAnchor.constraint(equalTo: shadowView.leftAnchor), + popView.bottomAnchor.constraint(equalTo: shadowView.bottomAnchor), + ]) + + let offset: CGFloat = 8 + for index in 0 ..< itemDatas.count { + let item = itemDatas[index] + let itemBtn = UIButton() + itemBtn.tag = index + itemBtn.translatesAutoresizingMaskIntoConstraints = false + if let image = item.image { + itemBtn.setImage(image, for: .normal) + itemBtn.layoutButtonImage(style: .left, space: 6) + } + itemBtn.setTitle(item.showName, for: .normal) + itemBtn.setTitleColor(item.showNameColor, for: .normal) + itemBtn.titleLabel?.font = NEConstant.defaultTextFont(14.0) + itemBtn.layoutButtonImage(style: .left, space: 6) + itemBtn.addTarget(self, action: #selector(itemClick(_:)), for: .touchUpInside) + itemBtn.contentHorizontalAlignment = .left + + popView.addSubview(itemBtn) + NSLayoutConstraint.activate([ + itemBtn.topAnchor.constraint( + equalTo: popView.topAnchor, + constant: offset + CGFloat(index * 32) + ), + itemBtn.leftAnchor.constraint(equalTo: popView.leftAnchor, constant: 15), + itemBtn.rightAnchor.constraint(equalTo: popView.rightAnchor, constant: -4), + itemBtn.heightAnchor.constraint(equalToConstant: 32), + ]) + } + } + + func itemClick(_ sender: UIButton) { + print("item click") + let index = sender.tag + let item = itemDatas[index] + if let block = item.completion { + block() + } + removeSelf() + } + + public func removeSelf() { + view.removeFromSuperview() + } + + override public func touchesBegan(_ touches: Set, with event: UIEvent?) { + print("pop list view touchesBegan") + removeSelf() + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/ConversationRouter/NEBaseConversationRouter.swift b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/ConversationRouter/NEBaseConversationRouter.swift new file mode 100644 index 00000000..ae111007 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/ConversationRouter/NEBaseConversationRouter.swift @@ -0,0 +1,9 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation + +@objcMembers +open class ConversationRouter: NSObject {} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/View/ConversationNavView.swift b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/View/ConversationNavView.swift deleted file mode 100644 index 61565fc1..00000000 --- a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/View/ConversationNavView.swift +++ /dev/null @@ -1,126 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NECoreKit - -public protocol ConversationNavViewDelegate: AnyObject { - func didClickAddBtn() - func searchAction() -} - -@objcMembers -public class ConversationNavView: UIView { - public weak var delegate: ConversationNavViewDelegate? - - override init(frame: CGRect) { - super.init(frame: frame) - setupSubviews() - initSubviewsLayout() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func setupSubviews() { - addSubview(brandBtn) - addSubview(searchBtn) - addSubview(addBtn) - addSubview(bottomLine) - - NSLayoutConstraint.activate([ - brandBtn.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8), - brandBtn.leftAnchor.constraint( - equalTo: leftAnchor, - constant: NEConstant.screenInterval - ), - ]) - - NSLayoutConstraint.activate([ - addBtn.centerYAnchor.constraint(equalTo: brandBtn.centerYAnchor), - addBtn.rightAnchor.constraint( - equalTo: rightAnchor, - constant: -NEConstant.screenInterval - ), - addBtn.widthAnchor.constraint(equalToConstant: 20), - addBtn.heightAnchor.constraint(equalToConstant: 20), - ]) - - NSLayoutConstraint.activate([ - searchBtn.centerYAnchor.constraint(equalTo: brandBtn.centerYAnchor), - searchBtn.rightAnchor.constraint( - equalTo: addBtn.leftAnchor, - constant: -NEConstant.screenInterval - ), - searchBtn.widthAnchor.constraint(equalToConstant: 20), - searchBtn.heightAnchor.constraint(equalToConstant: 20), - ]) - - NSLayoutConstraint.activate([ - bottomLine.leftAnchor.constraint(equalTo: leftAnchor), - bottomLine.rightAnchor.constraint(equalTo: rightAnchor), - bottomLine.bottomAnchor.constraint(equalTo: bottomAnchor), - bottomLine.heightAnchor.constraint(equalToConstant: 0.5), - ]) - } - - func initSubviewsLayout() { - if NEKitConversationConfig.shared.ui.hiddenRightBtns { - searchBtn.isHidden = true - addBtn.isHidden = true - } else { - if NEKitConversationConfig.shared.ui.hiddenSearchBtn { - searchBtn.isHidden = true - } - } - } - - // MARK: lazy method - - public lazy var brandBtn: UIButton = { - let button = UIButton() - button.setTitle(localizable("appName"), for: .normal) - button.setImage(UIImage.ne_imageNamed(name: "brand_yunxin"), for: .normal) - button.layoutButtonImage(style: .left, space: 12) - button.translatesAutoresizingMaskIntoConstraints = false - button.setTitleColor(UIColor.black, for: .normal) - button.titleLabel?.font = NEConstant.textFont("PingFangSC-Medium", 20) - return button - }() - - public lazy var searchBtn: UIButton = { - let button = UIButton() - button.setImage(UIImage.ne_imageNamed(name: "chat_search"), for: .normal) - button.translatesAutoresizingMaskIntoConstraints = false - button.addTarget(self, action: #selector(searchBtnClick), for: .touchUpInside) - return button - }() - - public lazy var addBtn: ExpandButton = { - let button = ExpandButton() - button.setImage(UIImage.ne_imageNamed(name: "chat_add"), for: .normal) - button.translatesAutoresizingMaskIntoConstraints = false - button.addTarget(self, action: #selector(addBtnClick), for: .touchUpInside) - return button - }() - - public lazy var bottomLine: UIView = { - let view = UIView() - view.translatesAutoresizingMaskIntoConstraints = false - view.backgroundColor = UIColor(hexString: "0xDBE0E8") - return view - }() -} - -extension ConversationNavView { - @objc func searchBtnClick(sender: UIButton) { - delegate?.searchAction() - } - - @objc func addBtnClick(sender: UIButton) { - delegate?.didClickAddBtn() - } -} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/ViewModel/ConversationViewModel.swift b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/ViewModel/ConversationViewModel.swift index 61c9f5dd..bc740892 100644 --- a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/ViewModel/ConversationViewModel.swift +++ b/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/ViewModel/ConversationViewModel.swift @@ -3,12 +3,13 @@ // found in the LICENSE file. import Foundation -import NEConversationKit +import NEChatKit import NIMSDK let revokeLocalMessage = "revoke_message_local" let revokeLocalMessageContent = "revoke_message_local_content" +@objc public protocol ConversationViewModelDelegate: NSObjectProtocol { func didAddRecentSession() func didUpdateRecentSession(index: Int) @@ -99,7 +100,12 @@ public class ConversationViewModel: NSObject, ConversationRepoDelegate, ModuleName + " " + className, desc: #function + ", sessionId:" + (recentSession.session?.sessionId ?? "nil") ) - repo.deleteLocalSession(recentSession: recentSession) + weak var weakSelf = self + let option = NIMDeleteRecentSessionOption() + option.isDeleteRoamMessage = true + repo.deleteRecentConversation(recentSession, option) { error in + weakSelf?.repo.deleteLocalSession(recentSession: recentSession) + } } public func stickTopInfoForSession(session: NIMSession) -> NIMStickTopSessionInfo? { @@ -336,9 +342,9 @@ public class ConversationViewModel: NSObject, ConversationRepoDelegate, public func didUpdate(_ recentSession: NIMRecentSession, totalUnreadCount: Int) { NELog.infoLog( ModuleName + " " + className, - desc: #function + "recentSession, didUpdate sessionId:" + (recentSession.session?.sessionId ?? "nil") + desc: #function + "recentSession, didUpdate sessionId: " + (recentSession.session?.sessionId ?? "nil" + " unread count : \(totalUnreadCount)") ) - if let sessionId = recentSession.session?.sessionId { + if let sessionId = recentSession.session?.sessionId, recentSession.unreadCount <= 0 { if NEAtMessageManager.instance.isAtCurrentUser(sessionId: sessionId) == true { NEAtMessageManager.instance.clearAtRecord(sessionId) } @@ -475,6 +481,20 @@ public class ConversationViewModel: NSObject, ConversationRepoDelegate, } } + public func onTeamMemberChanged(_ team: NIMTeam) { + NELog.infoLog(ModuleName + " " + className, desc: #function + ", teamId:" + (team.teamId ?? "nil")) + guard let conversationArr = conversationListArray else { + return + } + for (i, listModel) in conversationArr.enumerated() { + if listModel.recentSession?.session?.sessionId == team.teamId { + listModel.teamInfo = team + delegate?.didUpdateRecentSession(index: i) + break + } + } + } + private func sessionIsExist(_ model: ConversationListModel) -> ConversationListModel? { if let array = conversationListArray { for index in 0 ..< array.count { @@ -486,4 +506,8 @@ public class ConversationViewModel: NSObject, ConversationRepoDelegate, } return nil } + + public func onMuteListChanged() { + delegate?.reloadTableView() + } } diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/ConversationConfig/ConversationUIConfig.swift b/NEConversationUIKit/NEConversationUIKit/Classes/ConversationConfig/ConversationUIConfig.swift index ef933b89..0db27d38 100644 --- a/NEConversationUIKit/NEConversationUIKit/Classes/ConversationConfig/ConversationUIConfig.swift +++ b/NEConversationUIKit/NEConversationUIKit/Classes/ConversationConfig/ConversationUIConfig.swift @@ -18,7 +18,7 @@ public class ConversationUIConfig: NSObject { public var avatarCornerRadius = 4.0 /// 头像类型 - public var avatarType: NEConversationAvatarType = .cycle + public var avatarType: NEConversationAvatarType? /// 是否隐藏导航栏 public var hiddenNav = false @@ -30,7 +30,7 @@ public class ConversationUIConfig: NSObject { public var hiddenRightBtns = false // 主标题字体大小 - public var titleFont = UIFont.systemFont(ofSize: 16) + public var titleFont: UIFont? // 副标题字体大小 public var subTitleFont = UIFont.systemFont(ofSize: 13) @@ -57,5 +57,5 @@ public class ConversationUIConfig: NSObject { /// 会话列表 cell 左划删除按钮文案内容 public var deleteBottonTitle = localizable("delete") /// 会话列表 cell 左划删除按钮文案颜色 - public var deleteBottonColor = NEConstant.hexRGB(0xA8ABB6) + public var deleteBottonColor: UIColor? } diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Cell/FunConversationListCell.swift b/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Cell/FunConversationListCell.swift new file mode 100644 index 00000000..9d499b73 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Cell/FunConversationListCell.swift @@ -0,0 +1,74 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class FunConversationListCell: NEBaseConversationListCell { + var contentModel: ConversationListModel? + + override open func setupSubviews() { + super.setupSubviews() + NSLayoutConstraint.activate([ + headImge.leftAnchor.constraint( + equalTo: contentView.leftAnchor, + constant: NEConstant.screenInterval + ), + headImge.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + headImge.widthAnchor.constraint(equalToConstant: 48), + headImge.heightAnchor.constraint(equalToConstant: 48), + ]) + + title.font = NEKitConversationConfig.shared.ui.titleFont ?? UIFont.systemFont(ofSize: 17) + NSLayoutConstraint.activate([ + title.leftAnchor.constraint(equalTo: headImge.rightAnchor, constant: 12), + title.rightAnchor.constraint(equalTo: timeLabel.leftAnchor, constant: -5), + title.topAnchor.constraint(equalTo: headImge.topAnchor, constant: 4), + ]) + + let bottomLine = UIView() + bottomLine.translatesAutoresizingMaskIntoConstraints = false + bottomLine.backgroundColor = .funConversationListLineBorderColor + contentView.addSubview(bottomLine) + NSLayoutConstraint.activate([ + bottomLine.leftAnchor.constraint(equalTo: title.leftAnchor), + bottomLine.rightAnchor.constraint(equalTo: contentView.rightAnchor), + bottomLine.heightAnchor.constraint(equalToConstant: 0.5), + bottomLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + ]) + + NSLayoutConstraint.activate([ + notifyMsg.rightAnchor.constraint(equalTo: timeLabel.rightAnchor, constant: -2), + notifyMsg.topAnchor.constraint(equalTo: timeLabel.bottomAnchor, constant: 10), + notifyMsg.widthAnchor.constraint(equalToConstant: 14), + notifyMsg.heightAnchor.constraint(equalToConstant: 14), + ]) + } + + override func initSubviewsLayout() { + if NEKitConversationConfig.shared.ui.avatarType == .rectangle { + headImge.layer.cornerRadius = NEKitConversationConfig.shared.ui.avatarCornerRadius + } else if NEKitConversationConfig.shared.ui.avatarType == .cycle { + headImge.layer.cornerRadius = 24.0 + } else { + headImge.layer.cornerRadius = 4.0 + } + } + + override open func configData(sessionModel: ConversationListModel?) { + super.configData(sessionModel: sessionModel) + contentModel = sessionModel + + // backgroundColor + if let session = sessionModel?.recentSession?.session { + let isTop = topStickInfos[session] != nil + if isTop { + contentView.backgroundColor = .funConversationBackgroundColor + } else { + contentView.backgroundColor = .white + } + } + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Cell/FunConversationSearchCell.swift b/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Cell/FunConversationSearchCell.swift new file mode 100644 index 00000000..a1618580 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Cell/FunConversationSearchCell.swift @@ -0,0 +1,32 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FunConversationSearchCell: NEBaseConversationSearchCell { + override open func setupSubviews() { + super.setupSubviews() + headImge.layer.cornerRadius = 4.0 + + headImge.updateLayoutConstraint(firstItem: headImge, seconedItem: nil, attribute: .width, constant: 40) + headImge.updateLayoutConstraint(firstItem: headImge, seconedItem: nil, attribute: .height, constant: 40) + + let bottomLine = UIView() + bottomLine.translatesAutoresizingMaskIntoConstraints = false + bottomLine.backgroundColor = .funConversationLineBorderColor + contentView.addSubview(bottomLine) + NSLayoutConstraint.activate([ + bottomLine.leftAnchor.constraint(equalTo: headImge.leftAnchor), + bottomLine.rightAnchor.constraint(equalTo: contentView.rightAnchor), + bottomLine.heightAnchor.constraint(equalToConstant: 1), + bottomLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + ]) + } + + override func getRangeTextColor() -> UIColor { + UIColor.funConversationThemeColor + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Controller/FunConversationController.swift b/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Controller/FunConversationController.swift new file mode 100644 index 00000000..436c3be3 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Controller/FunConversationController.swift @@ -0,0 +1,147 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonUIKit +import NECoreKit +import NIMSDK + +@objcMembers +open class FunConversationController: NEBaseConversationController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + listCtrl = FunConversationListViewController() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public lazy var searchView: FunSearchView = { + let view = FunSearchView() + view.translatesAutoresizingMaskIntoConstraints = false + view.searchBotton.setImage(UIImage.ne_imageNamed(name: "funSearch"), for: .normal) + view.searchBotton.setTitle(localizable("search"), for: .normal) + return view + }() + + override open func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .funConversationBackgroundColor + navView.backgroundColor = .funConversationBackgroundColor + navView.bottomLine.isHidden = true + } + + deinit { + if let searchViewGestures = searchView.gestureRecognizers { + searchViewGestures.forEach { gesture in + searchView.removeGestureRecognizer(gesture) + } + } + } + + override func initSystemNav() { + super.initSystemNav() + let addBarButton = UIButton() + addBarButton.setImage(UIImage.ne_imageNamed(name: "chat_add"), for: .normal) + addBarButton.addTarget(self, action: #selector(didClickAddBtn), for: .touchUpInside) + let addBarItem = UIBarButtonItem(customView: addBarButton) + + navigationItem.rightBarButtonItems = [addBarItem] + + navView.searchBtn.isHidden = true + if NEKitConversationConfig.shared.ui.hiddenRightBtns { + navigationItem.rightBarButtonItems = [] + navView.addBtn.isHidden = true + } + } + + override open func setupSubviews() { + super.setupSubviews() + let tap = UITapGestureRecognizer(target: self, action: #selector(searchAction)) + tap.cancelsTouchesInView = false + searchView.addGestureRecognizer(tap) + view.addSubview(searchView) + NSLayoutConstraint.activate([ + searchView.topAnchor.constraint(equalTo: navView.bottomAnchor, constant: 12), + searchView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8), + searchView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8), + searchView.heightAnchor.constraint(equalToConstant: 36), + ]) + + NSLayoutConstraint.activate([ + listCtrl.view.topAnchor.constraint(equalTo: searchView.bottomAnchor, constant: 12), + listCtrl.view.leftAnchor.constraint(equalTo: view.leftAnchor), + listCtrl.view.rightAnchor.constraint(equalTo: view.rightAnchor), + listCtrl.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + } + + // MARK: lazyMethod + + public lazy var popListController: FunPopListViewController = { + let popController = FunPopListViewController() + popController.popView.backgroundColor = UIColor.funConversationPopViewBg + return popController + }() +} + +extension FunConversationController { + override open func searchAction() { + let searchVC = FunConversationSearchController() + navigationController?.pushViewController(searchVC, animated: true) + } + + override open func didClickAddBtn() { + print("add click") + + if children.contains(popListController) == false { + popListController.itemDatas = getPopListItems() + addChild(popListController) + popListController.view.frame = view.frame + } + if popListController.view.superview != nil { + popListController.removeSelf() + } else { + view.addSubview(popListController.view) + } + } + + open func getPopListItems() -> [PopListItem] { + weak var weakSelf = self + var items = [PopListItem]() + let addFriend = PopListItem() + addFriend.showName = localizable("add_friend") + addFriend.showNameColor = .white + addFriend.image = UIImage.ne_imageNamed(name: "funAddFriend") + addFriend.completion = { + Router.shared.use( + ContactAddFriendRouter, + parameters: ["nav": self.navigationController as Any] + ) { obj, routerState, str in + } + } + items.append(addFriend) + + let createGroup = PopListItem() + createGroup.showName = localizable("create_discussion_group") + createGroup.showNameColor = .white + createGroup.image = UIImage.ne_imageNamed(name: "funCreateTeam") + createGroup.completion = { + weakSelf?.createDiscussGroup() + } + items.append(createGroup) + + let createDicuss = PopListItem() + createDicuss.showName = localizable("create_senior_group") + createDicuss.showNameColor = .white + createDicuss.image = UIImage.ne_imageNamed(name: "funCreateTeam") + createDicuss.completion = { + weakSelf?.createSeniorGroup() + } + items.append(createDicuss) + + return items + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Controller/FunConversationListViewController.swift b/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Controller/FunConversationListViewController.swift new file mode 100644 index 00000000..211ad1cd --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Controller/FunConversationListViewController.swift @@ -0,0 +1,85 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class FunConversationListViewController: NEBaseConversationListViewController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + className = "FunConversationListViewController" + deleteBottonColor = .funConversationdeleteActionColor + registerCellDic = [0: FunConversationListCell.self] + networkToolHeight = 48 + brokenNetworkView.errorIcon.isHidden = false + brokenNetworkView.backgroundColor = .funConversationNetworkBrokenBackgroundColor + brokenNetworkView.content.textColor = .funConversationNetworkBrokenTitleColor + emptyView.setEmptyImage(name: "fun_user_empty") + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func setupSubviews() { + super.setupSubviews() + tableView.rowHeight = 72 + tableView.backgroundColor = .funConversationBackgroundColor + } +} + +// MARK: ==========FunConversationListCellDelegate============ + +extension FunConversationListViewController { + open func getPopListItems(cell: UITableViewCell, contentModel: ConversationListModel?) -> [PopListItem] { + weak var weakSelf = self + var items = [PopListItem]() + + guard let recentSession = contentModel?.recentSession, + let session = recentSession.session, + let cellIndex = tableView.indexPath(for: cell) else { + return [PopListItem]() + } + let isTop = viewModel.stickTopInfos[session] != nil + + let stickTopItem = PopListItem() + stickTopItem.showName = isTop ? NEKitConversationConfig.shared.ui.stickTopBottonCancelTitle : + NEKitConversationConfig.shared.ui.stickTopBottonTitle + stickTopItem.showNameColor = .black + stickTopItem.completion = { + weakSelf?.topActionHandler(action: nil, indexPath: cellIndex, isTop: isTop) + } + items.append(stickTopItem) + + let deleteItem = PopListItem() + deleteItem.showName = NEKitConversationConfig.shared.ui.deleteBottonTitle + deleteItem.showNameColor = .black + deleteItem.completion = { + weakSelf?.deleteActionHandler(action: nil, indexPath: cellIndex) + } + items.append(deleteItem) + + return items + } + +// public func didLongPressConversationView(_ cell: UITableViewCell, _ longPress: UILongPressGestureRecognizer, _ contentModel: ConversationListModel?) { +// let popListController = FunPopListViewController() +// popListController.popView.backgroundColor = .white +// popListController.itemDatas = getPopListItems(cell: cell, contentModel: contentModel) +// addChild(popListController) +// view.addSubview(popListController.view) +// popListController.view.bounds = UIScreen.main.bounds +// +// if let cellIndexPath = tableView.indexPath(for: cell) { +// let y = longPress.location(in: view).y +// let shadowHeight = popListController.shadowView.frame.size.height +// if (y + shadowHeight) > (NEConstant.screenHeight - NEConstant.navigationAndStatusHeight - 123) { +// popListController.shadowViewTopAnchor?.constant = y - shadowHeight +// } else { +// popListController.shadowViewTopAnchor?.constant = y +// } +// } +// } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Controller/FunConversationSearchController.swift b/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Controller/FunConversationSearchController.swift new file mode 100644 index 00000000..fe6d6b44 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Controller/FunConversationSearchController.swift @@ -0,0 +1,109 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class FunConversationSearchController: NEBaseConversationSearchController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + tag = "FunConversationSearchController" + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .funConversationBackgroundColor + navigationController?.isNavigationBarHidden = true + customNavigationView.isHidden = true + emptyView.setEmptyImage(name: "fun_user_empty") + } + + override open func setupSubviews() { + super.setupSubviews() + let leftImageView = UIImageView(image: UIImage + .ne_imageNamed(name: "funSearch")) + searchTextField.leftView = leftImageView + searchTextField.font = UIFont.systemFont(ofSize: 16) + searchTextField.textColor = .black + searchTextField.layer.cornerRadius = 4 + searchTextField.backgroundColor = .white + NSLayoutConstraint.activate([ + searchTextField.topAnchor.constraint(equalTo: view.topAnchor, constant: NEConstant.statusBarHeight + 12), + searchTextField.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8), + searchTextField.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -72), + searchTextField.heightAnchor.constraint(equalToConstant: 36), + ]) + + let cancelButton = UIButton() + cancelButton.translatesAutoresizingMaskIntoConstraints = false + cancelButton.setTitle(localizable("cancel"), for: .normal) + cancelButton.setTitleColor(.ne_greyText, for: .normal) + cancelButton.addTarget(self, action: #selector(backEvent), for: .touchUpInside) + cancelButton.titleLabel?.adjustsFontSizeToFitWidth = true + cancelButton.contentHorizontalAlignment = .center + view.addSubview(cancelButton) + NSLayoutConstraint.activate([ + cancelButton.centerYAnchor.constraint(equalTo: searchTextField.centerYAnchor), + cancelButton.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -5), + cancelButton.widthAnchor.constraint(equalToConstant: 55), + ]) + + tableView.sectionHeaderHeight = 38 + NSLayoutConstraint.activate([ + tableView.rightAnchor.constraint(equalTo: view.rightAnchor), + tableView.leftAnchor.constraint(equalTo: view.leftAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + tableView.topAnchor.constraint(equalTo: searchTextField.bottomAnchor, constant: 12), + ]) + tableView.register( + FunConversationSearchCell.self, + forCellReuseIdentifier: "\(NSStringFromClass(FunConversationSearchCell.self))" + ) + tableView.register( + FunSearchSessionHeaderView.self, + forHeaderFooterViewReuseIdentifier: "\(NSStringFromClass(FunSearchSessionHeaderView.self))" + ) + tableView.backgroundColor = .funConversationBackgroundColor + if #available(iOS 15.0, *) { + tableView.sectionHeaderTopPadding = 0 + } + searchTextField.becomeFirstResponder() + } + + // MARK: UITableViewDelegate, UITableViewDataSource + +// override open func tableView(_ tableView: UITableView, +// cellForRowAt indexPath: IndexPath) -> UITableViewCell { +// let cell = tableView.dequeueReusableCell( +// withIdentifier: "\(NSStringFromClass(FunConversationSearchCell.self))", +// for: indexPath +// ) as! FunConversationSearchCell +// if indexPath.section == 0 { +// cell.searchModel = viewModel.searchResult?.friend[indexPath.row] +// } else if indexPath.section == 1 { +// cell.searchModel = viewModel.searchResult?.contactGroup[indexPath.row] +// } else { +// cell.searchModel = viewModel.searchResult?.seniorGroup[indexPath.row] +// } +// cell.searchText = searchStr +// return cell +// } + + override open func tableView(_ tableView: UITableView, + viewForHeaderInSection section: Int) -> UIView? { + let sectionView = tableView + .dequeueReusableHeaderFooterView( + withIdentifier: "\(NSStringFromClass(FunSearchSessionHeaderView.self))" + ) as! FunSearchSessionHeaderView + sectionView.title.textColor = .funConversationSearchHeaderViewTitleColor + sectionView.bottomLine.backgroundColor = .funConversationLineBorderColor + sectionView.setUpTitle(title: headTitleArr[section]) + return sectionView + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Controller/FunPopListViewController.swift b/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Controller/FunPopListViewController.swift new file mode 100644 index 00000000..48db6966 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/Controller/FunPopListViewController.swift @@ -0,0 +1,44 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import UIKit +import NECommonKit + +@objcMembers +open class FunPopListViewController: NEBasePopListViewController { + public var shadowViewTopAnchor: NSLayoutConstraint? + + public var triangleView: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = UIColor.funConversationPopViewBg + view.transform = CGAffineTransform(rotationAngle: CGFloat.pi / 4) + return view + }() + + override func setupUI() { + super.setupUI() + + let popViewHeight = CGFloat(itemDatas.count) * 32 + 16 + + NSLayoutConstraint.activate([ + shadowView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8), + shadowView.widthAnchor.constraint(equalToConstant: popViewWidth), + shadowView.heightAnchor.constraint(equalToConstant: popViewHeight), + ]) + shadowViewTopAnchor = shadowView.topAnchor.constraint(equalTo: view.topAnchor, constant: NEConstant.navigationAndStatusHeight) + shadowViewTopAnchor?.isActive = true + + view.insertSubview(triangleView, aboveSubview: shadowView) + NSLayoutConstraint.activate([ + triangleView.widthAnchor.constraint(equalToConstant: 11), + triangleView.heightAnchor.constraint(equalToConstant: 11), + triangleView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -25), + triangleView.topAnchor.constraint(equalTo: popView.topAnchor, constant: -5), + + ]) + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/FunConversationRouter.swift b/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/FunConversationRouter.swift new file mode 100644 index 00000000..88d7dfaa --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/FunConversationRouter.swift @@ -0,0 +1,28 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation + +public extension ConversationRouter { + static func registerFun() { + Router.shared.register(SearchContactPageRouter) { param in + let nav = param["nav"] as? UINavigationController + let searchCtrl = FunConversationSearchController() + nav?.pushViewController(searchCtrl, animated: true) + } + + Router.shared.register(ConversationPageRouter) { param in + let nav = param["nav"] as? UINavigationController + let conversation = FunConversationController() + nav?.pushViewController(conversation, animated: true) + } + + Router.shared.register("ClearAtMessageRemind") { param in + if let sessionId = param["sessionId"] as? String { + NEAtMessageManager.instance.clearAtRecord(sessionId) + } + } + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/FunConversationUIColor.swift b/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/FunConversationUIColor.swift new file mode 100644 index 00000000..14a39f79 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Classes/FunUI/FunConversationUIColor.swift @@ -0,0 +1,18 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import NECommonKit + +extension UIColor { + static let funConversationPopViewBg = UIColor(hexString: "#4C4C4C") + static let funConversationThemeColor = UIColor(hexString: "#58BE6B") + static let funConversationBackgroundColor = UIColor(hexString: "#EDEDED") + static let funConversationLineBorderColor = UIColor(hexString: "#E5E5E5") + static let funConversationListLineBorderColor = UIColor(hexString: "#D8D8D8") + static let funConversationdeleteActionColor = UIColor(hexString: "#E75E58") + static let funConversationSearchHeaderViewTitleColor = UIColor(hexString: "#737373") + static let funConversationNetworkBrokenBackgroundColor = UIColor(hexString: "#FCEEEE") + static let funConversationNetworkBrokenTitleColor = UIColor(white: 0, alpha: 0.5) +} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Cell/ConversationListCell.swift b/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Cell/ConversationListCell.swift new file mode 100644 index 00000000..2beb0ac8 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Cell/ConversationListCell.swift @@ -0,0 +1,61 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class ConversationListCell: NEBaseConversationListCell { + override open func setupSubviews() { + super.setupSubviews() + + NSLayoutConstraint.activate([ + headImge.leftAnchor.constraint( + equalTo: contentView.leftAnchor, + constant: NEConstant.screenInterval + ), + headImge.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + headImge.widthAnchor.constraint(equalToConstant: 42), + headImge.heightAnchor.constraint(equalToConstant: 42), + ]) + + NSLayoutConstraint.activate([ + title.leftAnchor.constraint(equalTo: headImge.rightAnchor, constant: 12), + title.rightAnchor.constraint(equalTo: timeLabel.leftAnchor, constant: -5), + title.topAnchor.constraint(equalTo: headImge.topAnchor), + ]) + + NSLayoutConstraint.activate([ + notifyMsg.rightAnchor.constraint(equalTo: timeLabel.rightAnchor), + notifyMsg.topAnchor.constraint(equalTo: timeLabel.bottomAnchor, constant: 5), + notifyMsg.widthAnchor.constraint(equalToConstant: 13), + notifyMsg.heightAnchor.constraint(equalToConstant: 13), + ]) + } + + override func initSubviewsLayout() { + if NEKitConversationConfig.shared.ui.avatarType == .rectangle { + headImge.layer.cornerRadius = NEKitConversationConfig.shared.ui.avatarCornerRadius + } else if NEKitConversationConfig.shared.ui.avatarType == .cycle { + headImge.layer.cornerRadius = 21.0 + } else { + headImge.layer.cornerRadius = 21.0 + } + } + + override open func configData(sessionModel: ConversationListModel?) { + super.configData(sessionModel: sessionModel) + + // backgroundColor + if let session = sessionModel?.recentSession?.session { + let isTop = topStickInfos[session] != nil + if isTop { + contentView.backgroundColor = UIColor(hexString: "0xF3F5F7") + } else { + contentView.backgroundColor = .white + } + } + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Cell/ConversationSearchCell.swift b/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Cell/ConversationSearchCell.swift new file mode 100644 index 00000000..25471943 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Cell/ConversationSearchCell.swift @@ -0,0 +1,9 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class ConversationSearchCell: NEBaseConversationSearchCell {} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Controller/ConversationController.swift b/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Controller/ConversationController.swift new file mode 100644 index 00000000..24f0b511 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Controller/ConversationController.swift @@ -0,0 +1,131 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonUIKit +import NECoreKit +import NIMSDK + +@objcMembers +open class ConversationController: NEBaseConversationController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + listCtrl = ConversationListViewController() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = UIColor(hexString: "#e9eff5") + } + + override func initSystemNav() { + super.initSystemNav() + let searchBarButton = UIButton() + searchBarButton.setImage(UIImage.ne_imageNamed(name: "chat_search"), for: .normal) + searchBarButton.addTarget(self, action: #selector(searchAction), for: .touchUpInside) + let searchBarItem = UIBarButtonItem(customView: searchBarButton) + + let addBarButton = UIButton() + addBarButton.setImage(UIImage.ne_imageNamed(name: "chat_add"), for: .normal) + addBarButton.addTarget(self, action: #selector(didClickAddBtn), for: .touchUpInside) + let addBarItem = UIBarButtonItem(customView: addBarButton) + + let spaceBarItem = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil) + spaceBarItem.width = NEConstant.screenInterval + + navigationItem.rightBarButtonItems = [addBarItem, spaceBarItem, searchBarItem] + if NEKitConversationConfig.shared.ui.hiddenSearchBtn { + navView.searchBtn.isHidden = true + navigationItem.rightBarButtonItems = [addBarItem] + } + if NEKitConversationConfig.shared.ui.hiddenRightBtns { + navigationItem.rightBarButtonItems = [] + navView.searchBtn.isHidden = true + navView.addBtn.isHidden = true + } + } + + override open func setupSubviews() { + super.setupSubviews() + NSLayoutConstraint.activate([ + listCtrl.view.topAnchor.constraint(equalTo: navView.bottomAnchor), + listCtrl.view.leftAnchor.constraint(equalTo: view.leftAnchor), + listCtrl.view.rightAnchor.constraint(equalTo: view.rightAnchor), + listCtrl.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + } + + deinit {} + + // MARK: lazyMethod + + public lazy var popListController: PopListViewController = { + let popController = PopListViewController() + return popController + }() +} + +extension ConversationController { + override open func searchAction() { + Router.shared.use( + SearchContactPageRouter, + parameters: ["nav": navigationController as Any], + closure: nil + ) + } + + override open func didClickAddBtn() { + print("add click") + + if children.contains(popListController) == false { + popListController.itemDatas = getPopListItems() + addChild(popListController) + popListController.view.frame = listCtrl.view.frame + } + if popListController.view.superview != nil { + popListController.removeSelf() + } else { + view.addSubview(popListController.view) + } + } + + open func getPopListItems() -> [PopListItem] { + weak var weakSelf = self + var items = [PopListItem]() + let addFriend = PopListItem() + addFriend.showName = localizable("add_friend") + addFriend.image = UIImage.ne_imageNamed(name: "add_friend") + addFriend.completion = { + Router.shared.use( + ContactAddFriendRouter, + parameters: ["nav": self.navigationController as Any] + ) { obj, routerState, str in + } + } + items.append(addFriend) + + let createGroup = PopListItem() + createGroup.showName = localizable("create_discussion_group") + createGroup.image = UIImage.ne_imageNamed(name: "create_discussion") + createGroup.completion = { + weakSelf?.createDiscussGroup() + } + items.append(createGroup) + + let createDicuss = PopListItem() + createDicuss.showName = localizable("create_senior_group") + createDicuss.image = UIImage.ne_imageNamed(name: "create_group") + createDicuss.completion = { + weakSelf?.createSeniorGroup() + } + items.append(createDicuss) + + return items + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Controller/ConversationListViewController.swift b/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Controller/ConversationListViewController.swift new file mode 100644 index 00000000..41473c01 --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Controller/ConversationListViewController.swift @@ -0,0 +1,26 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class ConversationListViewController: NEBaseConversationListViewController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + className = "ConversationListViewController" + registerCellDic = [0: ConversationListCell.self] + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func setupSubviews() { + super.setupSubviews() + + tableView.rowHeight = 62 + tableView.backgroundColor = .white + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Controller/ConversationSearchController.swift b/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Controller/ConversationSearchController.swift new file mode 100644 index 00000000..b98d095d --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Controller/ConversationSearchController.swift @@ -0,0 +1,69 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class SearchSessionHeaderView: SearchSessionBaseView { + override open func setupUI() { + super.setupUI() + NSLayoutConstraint.activate([ + title.topAnchor.constraint(equalTo: contentView.topAnchor), + title.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20), + ]) + + NSLayoutConstraint.activate([ + bottomLine.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20), + bottomLine.leftAnchor.constraint(equalTo: title.leftAnchor), + bottomLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + bottomLine.heightAnchor.constraint(equalToConstant: 1), + ]) + } +} + +@objcMembers +open class ConversationSearchController: NEBaseConversationSearchController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + tag = "ConversationSearchController" + customNavigationView.backgroundColor = .white + navigationController?.navigationBar.backgroundColor = .white + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func setupSubviews() { + super.setupSubviews() + + searchTextField.placeholder = localizable("search_keyword") + NSLayoutConstraint.activate([ + searchTextField.topAnchor.constraint( + equalTo: view.topAnchor, + constant: NEConstant.navigationHeight + NEConstant.statusBarHeight + 20 + ), + searchTextField.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20), + searchTextField.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), + searchTextField.heightAnchor.constraint(equalToConstant: 32), + ]) + + NSLayoutConstraint.activate([ + tableView.rightAnchor.constraint(equalTo: view.rightAnchor), + tableView.leftAnchor.constraint(equalTo: view.leftAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + tableView.topAnchor.constraint(equalTo: searchTextField.bottomAnchor, constant: 20), + ]) + tableView.register( + ConversationSearchCell.self, + forCellReuseIdentifier: "\(NSStringFromClass(ConversationSearchCell.self))" + ) + tableView.register( + SearchSessionHeaderView.self, + forHeaderFooterViewReuseIdentifier: "\(NSStringFromClass(SearchSessionHeaderView.self))" + ) + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Controller/PopListViewController.swift b/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Controller/PopListViewController.swift new file mode 100644 index 00000000..4103159c --- /dev/null +++ b/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/Controller/PopListViewController.swift @@ -0,0 +1,24 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import UIKit +import NECommonKit + +@objcMembers +open class PopListViewController: NEBasePopListViewController { + override func setupUI() { + super.setupUI() + let popViewHeight = CGFloat(itemDatas.count) * 32 + 16 + NSLayoutConstraint.activate([ + shadowView.topAnchor.constraint(equalTo: view.topAnchor, constant: 2), + shadowView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), + shadowView.widthAnchor.constraint(equalToConstant: popViewWidth), + shadowView.heightAnchor.constraint(equalToConstant: popViewHeight), + ]) + + popView.backgroundColor = NEConstant.hexRGB(0xFFFFFF) + } +} diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/ConversationRouter/ConversationRouter.swift b/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/NormalConversationRouter.swift similarity index 90% rename from NEConversationUIKit/NEConversationUIKit/Classes/Conversation/ConversationRouter/ConversationRouter.swift rename to NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/NormalConversationRouter.swift index b8b8d639..c5aa931e 100644 --- a/NEConversationUIKit/NEConversationUIKit/Classes/Conversation/ConversationRouter/ConversationRouter.swift +++ b/NEConversationUIKit/NEConversationUIKit/Classes/NormalUI/NormalConversationRouter.swift @@ -5,9 +5,8 @@ import Foundation -@objcMembers -public class ConversationRouter: NSObject { - public static func register() { +public extension ConversationRouter { + static func register() { Router.shared.register(SearchContactPageRouter) { param in let nav = param["nav"] as? UINavigationController let searchCtrl = ConversationSearchController() diff --git a/NEConversationUIKit/NEConversationUIKit/Classes/Util/NEMessageUtil.swift b/NEConversationUIKit/NEConversationUIKit/Classes/Util/NEMessageUtil.swift index ece6b873..a8727ada 100644 --- a/NEConversationUIKit/NEConversationUIKit/Classes/Util/NEMessageUtil.swift +++ b/NEConversationUIKit/NEConversationUIKit/Classes/Util/NEMessageUtil.swift @@ -9,7 +9,7 @@ public class NEMessageUtil { /// last message /// - Parameter message: message /// - Returns: result - class func messageContent(message: NIMMessage) -> String { + public class func messageContent(message: NIMMessage) -> String { var text = "" switch message.messageType { case .text: diff --git a/NEMapKit/NEMapKit.podspec b/NEMapKit/NEMapKit.podspec index 72191f52..a92bbc1b 100644 --- a/NEMapKit/NEMapKit.podspec +++ b/NEMapKit/NEMapKit.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'NEMapKit' - s.version = '9.5.0' + s.version = '9.6.0' s.summary = 'Netease XKit' # This description is used to generate tags and improve search results. @@ -28,7 +28,7 @@ TODO: Add long description of the pod here. s.source = { :git => 'ssh://git@g.hz.netease.com:22222/yunxin-app/xkit-ios.git', :tag => s.version.to_s } # s.social_media_url = 'https://twitter.com/' - s.ios.deployment_target = '9.0' + s.ios.deployment_target = '10.0' s.source_files = 'NEMapKit/Classes/**/*' # s.resource = 'NEMapKit/Assets/**/*' diff --git a/NETeamUIKit/NETeamUIKit.podspec b/NETeamUIKit/NETeamUIKit.podspec index d23b9064..ec446186 100644 --- a/NETeamUIKit/NETeamUIKit.podspec +++ b/NETeamUIKit/NETeamUIKit.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'NETeamUIKit' - s.version = '9.2.10' + s.version = '9.6.0' s.summary = 'Netease XKit' # This description is used to generate tags and improve search results. @@ -31,20 +31,13 @@ TODO: Add long description of the pod here. 'BUILD_LIBRARY_FOR_DISTRIBUTION' => 'YES' } - s.ios.deployment_target = '9.0' + s.ios.deployment_target = '10.0' s.swift_version = '5.0' s.source_files = 'NETeamUIKit/Classes/**/*' s.resource = 'NETeamUIKit/Assets/**/*' - # s.resource_bundles = { - # 'NEKitGroupUI' => ['NEKitGroupUI/Assets/*.png'] - # } - - # s.public_header_files = 'Pod/Classes/**/*.h' - # s.frameworks = 'UIKit', 'MapKit' s.dependency 'NECommonUIKit' - s.dependency 'NETeamKit' - s.dependency 'NIMSDK_LITE' - s.dependency 'YXAlog' + s.dependency 'NECommonKit' + s.dependency 'NEChatKit' end diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/funSearch.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/funSearch.imageset/Contents.json new file mode 100644 index 00000000..4a62afc6 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/funSearch.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "search@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "search@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/funSearch.imageset/search@2x.png b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/funSearch.imageset/search@2x.png new file mode 100644 index 00000000..e2ce7a50 Binary files /dev/null and b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/funSearch.imageset/search@2x.png differ diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/funSearch.imageset/search@3x.png b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/funSearch.imageset/search@3x.png new file mode 100644 index 00000000..36a33195 Binary files /dev/null and b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/funSearch.imageset/search@3x.png differ diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_add.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_add.imageset/Contents.json new file mode 100644 index 00000000..05adce49 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_add.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "fun_add@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "fun_add@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_add.imageset/fun_add@2x.png b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_add.imageset/fun_add@2x.png new file mode 100644 index 00000000..1c1634e5 Binary files /dev/null and b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_add.imageset/fun_add@2x.png differ diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_add.imageset/fun_add@3x.png b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_add.imageset/fun_add@3x.png new file mode 100644 index 00000000..acdef079 Binary files /dev/null and b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_add.imageset/fun_add@3x.png differ diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_0.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_0.imageset/Contents.json new file mode 100644 index 00000000..98bb2f25 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_0.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "fun_icon_0@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "fun_icon_0@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_0.imageset/fun_icon_0@2x.png b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_0.imageset/fun_icon_0@2x.png new file mode 100644 index 00000000..edff5753 Binary files /dev/null and b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_0.imageset/fun_icon_0@2x.png differ diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_0.imageset/fun_icon_0@3x.png b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_0.imageset/fun_icon_0@3x.png new file mode 100644 index 00000000..923767a8 Binary files /dev/null and b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_0.imageset/fun_icon_0@3x.png differ diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_1.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_1.imageset/Contents.json new file mode 100644 index 00000000..ea7728a8 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_1.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "fun_icon_1@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "fun_icon_1@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_1.imageset/fun_icon_1@2x.png b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_1.imageset/fun_icon_1@2x.png new file mode 100644 index 00000000..87389eca Binary files /dev/null and b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_1.imageset/fun_icon_1@2x.png differ diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_1.imageset/fun_icon_1@3x.png b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_1.imageset/fun_icon_1@3x.png new file mode 100644 index 00000000..2de3aef7 Binary files /dev/null and b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_1.imageset/fun_icon_1@3x.png differ diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_2.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_2.imageset/Contents.json new file mode 100644 index 00000000..30d540b2 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_2.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "fun_icon_2@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "fun_icon_2@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_2.imageset/fun_icon_2@2x.png b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_2.imageset/fun_icon_2@2x.png new file mode 100644 index 00000000..632365f1 Binary files /dev/null and b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_2.imageset/fun_icon_2@2x.png differ diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_2.imageset/fun_icon_2@3x.png b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_2.imageset/fun_icon_2@3x.png new file mode 100644 index 00000000..96786264 Binary files /dev/null and b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_2.imageset/fun_icon_2@3x.png differ diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_3.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_3.imageset/Contents.json new file mode 100644 index 00000000..986214d0 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_3.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "fun_icon_3@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "fun_icon_3@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_3.imageset/fun_icon_3@2x.png b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_3.imageset/fun_icon_3@2x.png new file mode 100644 index 00000000..24666684 Binary files /dev/null and b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_3.imageset/fun_icon_3@2x.png differ diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_3.imageset/fun_icon_3@3x.png b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_3.imageset/fun_icon_3@3x.png new file mode 100644 index 00000000..7a32bb93 Binary files /dev/null and b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_3.imageset/fun_icon_3@3x.png differ diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_4.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_4.imageset/Contents.json new file mode 100644 index 00000000..6b59e29c --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_4.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "fun_icon_4@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "fun_icon_4@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_4.imageset/fun_icon_4@2x.png b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_4.imageset/fun_icon_4@2x.png new file mode 100644 index 00000000..694df353 Binary files /dev/null and b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_4.imageset/fun_icon_4@2x.png differ diff --git a/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_4.imageset/fun_icon_4@3x.png b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_4.imageset/fun_icon_4@3x.png new file mode 100644 index 00000000..26b375d3 Binary files /dev/null and b/NETeamUIKit/NETeamUIKit/Assets/FunTeamUIKit.xcassets/fun_icon_4.imageset/fun_icon_4@3x.png differ diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/arrowRight.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/arrowRight.imageset/Contents.json similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/arrowRight.imageset/Contents.json rename to NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/arrowRight.imageset/Contents.json diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/arrowRight.imageset/Vector 87@2x.png b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/arrowRight.imageset/Vector 87@2x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/arrowRight.imageset/Vector 87@2x.png rename to NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/arrowRight.imageset/Vector 87@2x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/arrowRight.imageset/Vector 87@3x.png b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/arrowRight.imageset/Vector 87@3x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/arrowRight.imageset/Vector 87@3x.png rename to NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/arrowRight.imageset/Vector 87@3x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/clear_btn.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/clear_btn.imageset/Contents.json new file mode 100644 index 00000000..0a902295 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/clear_btn.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "fun_clear_btn@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "fun_clear_btn@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/clear_btn.imageset/fun_clear_btn@2x.png b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/clear_btn.imageset/fun_clear_btn@2x.png new file mode 100644 index 00000000..1c514035 Binary files /dev/null and b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/clear_btn.imageset/fun_clear_btn@2x.png differ diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/clear_btn.imageset/fun_clear_btn@3x.png b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/clear_btn.imageset/fun_clear_btn@3x.png new file mode 100644 index 00000000..0d88f22f Binary files /dev/null and b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/clear_btn.imageset/fun_clear_btn@3x.png differ diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/copy_icon.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/copy_icon.imageset/Contents.json similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/copy_icon.imageset/Contents.json rename to NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/copy_icon.imageset/Contents.json diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/copy_icon.imageset/copy_icon.png b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/copy_icon.imageset/copy_icon.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/copy_icon.imageset/copy_icon.png rename to NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/copy_icon.imageset/copy_icon.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/photo.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/photo.imageset/Contents.json similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/photo.imageset/Contents.json rename to NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/photo.imageset/Contents.json diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/photo.imageset/team_photo@2x.png b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/photo.imageset/team_photo@2x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/photo.imageset/team_photo@2x.png rename to NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/photo.imageset/team_photo@2x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/photo.imageset/team_photo@3x.png b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/photo.imageset/team_photo@3x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/photo.imageset/team_photo@3x.png rename to NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/photo.imageset/team_photo@3x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/search_icon.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/search_icon.imageset/Contents.json similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/search_icon.imageset/Contents.json rename to NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/search_icon.imageset/Contents.json diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/search_icon.imageset/search_icon@2x.png b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/search_icon.imageset/search_icon@2x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/search_icon.imageset/search_icon@2x.png rename to NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/search_icon.imageset/search_icon@2x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/search_icon.imageset/search_icon@3x.png b/NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/search_icon.imageset/search_icon@3x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/search_icon.imageset/search_icon@3x.png rename to NETeamUIKit/NETeamUIKit/Assets/NEBaseTeamUIKit.xcassets/common/search_icon.imageset/search_icon@3x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/add.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/add.imageset/Contents.json similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/add.imageset/Contents.json rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/add.imageset/Contents.json diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/add.imageset/add@2x.png b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/add.imageset/add@2x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/add.imageset/add@2x.png rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/add.imageset/add@2x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/add.imageset/add@3x.png b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/add.imageset/add@3x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/add.imageset/add@3x.png rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/add.imageset/add@3x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/contact_search.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/contact_search.imageset/Contents.json similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/contact_search.imageset/Contents.json rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/contact_search.imageset/Contents.json diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/contact_search.imageset/contact_search@2x.png b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/contact_search.imageset/contact_search@2x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/contact_search.imageset/contact_search@2x.png rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/contact_search.imageset/contact_search@2x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/contact_search.imageset/contact_search@3x.png b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/contact_search.imageset/contact_search@3x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/contact_search.imageset/contact_search@3x.png rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/contact_search.imageset/contact_search@3x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_0.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_0.imageset/Contents.json similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_0.imageset/Contents.json rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_0.imageset/Contents.json diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_0.imageset/icon_1@2x.png b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_0.imageset/icon_1@2x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_0.imageset/icon_1@2x.png rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_0.imageset/icon_1@2x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_0.imageset/icon_1@3x.png b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_0.imageset/icon_1@3x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_0.imageset/icon_1@3x.png rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_0.imageset/icon_1@3x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_1.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_1.imageset/Contents.json similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_1.imageset/Contents.json rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_1.imageset/Contents.json diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_1.imageset/icon_2@2x.png b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_1.imageset/icon_2@2x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_1.imageset/icon_2@2x.png rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_1.imageset/icon_2@2x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_1.imageset/icon_2@3x.png b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_1.imageset/icon_2@3x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_1.imageset/icon_2@3x.png rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_1.imageset/icon_2@3x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_2.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_2.imageset/Contents.json similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_2.imageset/Contents.json rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_2.imageset/Contents.json diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_2.imageset/icon_3@2x.png b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_2.imageset/icon_3@2x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_2.imageset/icon_3@2x.png rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_2.imageset/icon_3@2x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_2.imageset/icon_3@3x.png b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_2.imageset/icon_3@3x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_2.imageset/icon_3@3x.png rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_2.imageset/icon_3@3x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_3.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_3.imageset/Contents.json similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_3.imageset/Contents.json rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_3.imageset/Contents.json diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_3.imageset/icon_4@2x.png b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_3.imageset/icon_4@2x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_3.imageset/icon_4@2x.png rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_3.imageset/icon_4@2x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_3.imageset/icon_4@3x.png b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_3.imageset/icon_4@3x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_3.imageset/icon_4@3x.png rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_3.imageset/icon_4@3x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_4.imageset/Contents.json b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_4.imageset/Contents.json similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_4.imageset/Contents.json rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_4.imageset/Contents.json diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_4.imageset/icon_5@2x.png b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_4.imageset/icon_5@2x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_4.imageset/icon_5@2x.png rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_4.imageset/icon_5@2x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_4.imageset/icon_5@3x.png b/NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_4.imageset/icon_5@3x.png similarity index 100% rename from NETeamUIKit/NETeamUIKit/Assets/NEKitTeam.xcassets/common/icon_4.imageset/icon_5@3x.png rename to NETeamUIKit/NETeamUIKit/Assets/NormalTeamUIKit.xcassets/icon_4.imageset/icon_5@3x.png diff --git a/NETeamUIKit/NETeamUIKit/Assets/en.lproj/Localizable.strings b/NETeamUIKit/NETeamUIKit/Assets/en.lproj/Localizable.strings index d7f568bd..eb3b7786 100644 --- a/NETeamUIKit/NETeamUIKit/Assets/en.lproj/Localizable.strings +++ b/NETeamUIKit/NETeamUIKit/Assets/en.lproj/Localizable.strings @@ -37,6 +37,7 @@ "group_info"="Group Info"; "discuss_introduce"="Temp Group Introduce"; "search_friend"="Search Contact"; +"no_result"="No Result"; "discuss_name"="Temp Group Name"; "dissolute_team_chat"="Wether to disband Group"; "quit_team_chat"="Wether to leave Group"; diff --git a/NETeamUIKit/NETeamUIKit/Assets/zh-Hans.lproj/Localizable.strings b/NETeamUIKit/NETeamUIKit/Assets/zh-Hans.lproj/Localizable.strings index 6301cf68..1390f5af 100644 --- a/NETeamUIKit/NETeamUIKit/Assets/zh-Hans.lproj/Localizable.strings +++ b/NETeamUIKit/NETeamUIKit/Assets/zh-Hans.lproj/Localizable.strings @@ -36,7 +36,8 @@ "discuss_info"="讨论组信息"; "group_info"="群信息"; "discuss_introduce"="讨论组介绍"; -"search_friend"="搜索好友"; +"search_friend"="搜索"; +"no_result"="暂无结果"; "discuss_name"="讨论组名称"; "dissolute_team_chat"="是否解散群聊?"; "quit_team_chat"="是否退出群聊?"; diff --git a/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunHistoryMessageCell.swift b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunHistoryMessageCell.swift new file mode 100644 index 00000000..b63ff224 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunHistoryMessageCell.swift @@ -0,0 +1,50 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. +import UIKit +import NIMSDK + +@objcMembers +open class FunHistoryMessageCell: NEBaseHistoryMessageCell { + override func setupSubviews() { + super.setupSubviews() + rangeTextColor = .funTeamThemeColor + + headImge.layer.cornerRadius = 4 + NSLayoutConstraint.activate([ + headImge.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16), + headImge.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 18), + headImge.widthAnchor.constraint(equalToConstant: 32), + headImge.heightAnchor.constraint(equalToConstant: 32), + ]) + + title.font = .systemFont(ofSize: 12) + title.textColor = .funTeamHistoryCellTitleTextColor + NSLayoutConstraint.activate([ + title.leftAnchor.constraint(equalTo: headImge.rightAnchor, constant: 12), + title.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -50), + title.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16), + ]) + + subTitle.font = .systemFont(ofSize: 15) + subTitle.textColor = .ne_darkText + NSLayoutConstraint.activate([ + subTitle.leftAnchor.constraint(equalTo: title.leftAnchor), + subTitle.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -50), + subTitle.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 6), + ]) + + NSLayoutConstraint.activate([ + bottomLine.rightAnchor.constraint(equalTo: contentView.rightAnchor), + bottomLine.leftAnchor.constraint(equalTo: headImge.leftAnchor), + bottomLine.bottomAnchor.constraint(equalTo: bottomAnchor), + bottomLine.heightAnchor.constraint(equalToConstant: 0.5), + ]) + + NSLayoutConstraint.activate([ + timeLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16), + timeLabel.centerYAnchor.constraint(equalTo: title.centerYAnchor), + ]) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamArrowSettingCell.swift b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamArrowSettingCell.swift similarity index 61% rename from NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamArrowSettingCell.swift rename to NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamArrowSettingCell.swift index 8e837267..1a5ab805 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamArrowSettingCell.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamArrowSettingCell.swift @@ -1,4 +1,3 @@ - // Copyright (c) 2022 NetEase, Inc. All rights reserved. // Use of this source code is governed by a MIT license that can be // found in the LICENSE file. @@ -6,33 +5,30 @@ import UIKit @objcMembers -public class TeamArrowSettingCell: BaseTeamSettingCell { +open class FunTeamArrowSettingCell: NEBaseTeamArrowSettingCell { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) - selectionStyle = .none - setupUI() + edgeInset = .zero } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } - override public func configure(_ anyModel: Any) { - super.configure(anyModel) - } + override public func setupUI() { + super.setupUI() + contentView.updateLayoutConstraint(firstItem: dividerLine, seconedItem: contentView, attribute: .left, constant: 16) + contentView.updateLayoutConstraint(firstItem: dividerLine, seconedItem: contentView, attribute: .right, constant: 0) - func setupUI() { - contentView.addSubview(titleLabel) NSLayoutConstraint.activate([ - titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 36), + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16), titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -84), + titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -56), ]) - contentView.addSubview(arrow) NSLayoutConstraint.activate([ arrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - arrow.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -36), + arrow.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16), ]) } } diff --git a/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamDefaultIconCell.swift b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamDefaultIconCell.swift new file mode 100644 index 00000000..cb55a47e --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamDefaultIconCell.swift @@ -0,0 +1,26 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonKit + +@objcMembers +open class FunTeamDefaultIconCell: NEBaseTeamDefaultIconCell { + override func setupUI() { + super.setupUI() + NSLayoutConstraint.activate([ + selectBack.rightAnchor.constraint(equalTo: contentView.rightAnchor), + selectBack.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + selectBack.widthAnchor.constraint(equalToConstant: 56.0), + selectBack.heightAnchor.constraint(equalToConstant: 56.0), + ]) + + NSLayoutConstraint.activate([ + iconImage.centerXAnchor.constraint(equalTo: selectBack.centerXAnchor), + iconImage.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + iconImage.heightAnchor.constraint(equalToConstant: 40), + iconImage.widthAnchor.constraint(equalToConstant: 40), + ]) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamMemberCell.swift b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamMemberCell.swift new file mode 100644 index 00000000..49732ccc --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamMemberCell.swift @@ -0,0 +1,52 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objc +open class FunTeamMemberCell: NEBaseTeamMemberCell { + public var dividerLine: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = UIColor.funTeamMemberDividerLine + return view + }() + + override open func setupUI() { + contentView.addSubview(headerView) + NSLayoutConstraint.activate([ + headerView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 21), + headerView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + headerView.widthAnchor.constraint(equalToConstant: 40), + headerView.heightAnchor.constraint(equalToConstant: 40), + ]) + headerView.layer.cornerRadius = 4.0 + + contentView.addSubview(ownerLabel) + NSLayoutConstraint.activate([ + ownerLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20), + ownerLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + ownerLabel.heightAnchor.constraint(equalToConstant: 25.0), + ownerLabel.widthAnchor.constraint(equalToConstant: 48.0), + ]) + + contentView.addSubview(nameLabel) + NSLayoutConstraint.activate([ + nameLabel.leftAnchor.constraint(equalTo: headerView.rightAnchor, constant: 14.0), + nameLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + nameLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -70), + ]) + ownerLabel.textColor = UIColor.funTeamMemberOwnerFlagColor + ownerLabel.backgroundColor = UIColor.funTeamMemberOwnerFlagColor.withAlphaComponent(0.1) + ownerLabel.layer.borderColor = UIColor.funTeamMemberOwnerFlagColor.cgColor + + contentView.addSubview(dividerLine) + NSLayoutConstraint.activate([ + dividerLine.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20), + dividerLine.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20), + dividerLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + dividerLine.heightAnchor.constraint(equalToConstant: 1), + ]) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamSettingHeaderCell.swift b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamSettingHeaderCell.swift similarity index 54% rename from NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamSettingHeaderCell.swift rename to NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamSettingHeaderCell.swift index 75af29de..3c72007a 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamSettingHeaderCell.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamSettingHeaderCell.swift @@ -1,4 +1,3 @@ - // Copyright (c) 2022 NetEase, Inc. All rights reserved. // Use of this source code is governed by a MIT license that can be // found in the LICENSE file. @@ -7,55 +6,37 @@ import UIKit import NECommonUIKit @objcMembers -public class TeamSettingHeaderCell: BaseTeamSettingCell { - lazy var headerView: NEUserHeaderView = { - let header = NEUserHeaderView(frame: .zero) - header.translatesAutoresizingMaskIntoConstraints = false - header.clipsToBounds = true - header.layer.cornerRadius = 21.0 - return header - }() - +open class FunTeamSettingHeaderCell: NEBaseTeamSettingHeaderCell { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) - selectionStyle = .none - setupUI() + edgeInset = .zero } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) setupUI() } - override public func configure(_ anyModel: Any) { - super.configure(anyModel) - if let url = model?.headerUrl { - headerView.sd_setImage(with: URL(string: url), completed: nil) - headerView.setTitle("") - } else { - headerView.setTitle(model?.defaultHeadData ?? "") - headerView.backgroundColor = UIColor.colorWithString(string: model?.defaultHeadData) - } - } + override open func setupUI() { + super.setupUI() + headerView.layer.cornerRadius = 3.36 + contentView.updateLayoutConstraint(firstItem: dividerLine, seconedItem: contentView, attribute: .left, constant: 16) + contentView.updateLayoutConstraint(firstItem: dividerLine, seconedItem: contentView, attribute: .right, constant: 0) - func setupUI() { - contentView.addSubview(titleLabel) NSLayoutConstraint.activate([ - titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 36), + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16), titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -84), ]) - contentView.addSubview(arrow) NSLayoutConstraint.activate([ arrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - arrow.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -36), + arrow.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16), ]) - contentView.addSubview(headerView) NSLayoutConstraint.activate([ headerView.centerYAnchor.constraint(equalTo: arrow.centerYAnchor), - headerView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -64.0), + headerView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -44.0), headerView.widthAnchor.constraint(equalToConstant: 42.0), headerView.heightAnchor.constraint(equalToConstant: 42.0), ]) diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamSettingSelectCell.swift b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamSettingSelectCell.swift similarity index 51% rename from NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamSettingSelectCell.swift rename to NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamSettingSelectCell.swift index 90ac7f89..77fc90ee 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamSettingSelectCell.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamSettingSelectCell.swift @@ -1,4 +1,3 @@ - // Copyright (c) 2022 NetEase, Inc. All rights reserved. // Use of this source code is governed by a MIT license that can be // found in the LICENSE file. @@ -6,60 +5,36 @@ import UIKit @objcMembers -public class TeamSettingSelectCell: BaseTeamSettingCell { - lazy var subTitleLabel: UILabel = { - let label = UILabel() - label.textColor = NEConstant.hexRGB(0x999999) - label.font = NEConstant.defaultTextFont(14.0) - label.translatesAutoresizingMaskIntoConstraints = false - return label - }() - - override public func awakeFromNib() { - super.awakeFromNib() - // Initialization code - } - - override public func setSelected(_ selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - - // Configure the view for the selected state - } - +open class FunTeamSettingSelectCell: NEBaseTeamSettingSelectCell { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) - selectionStyle = .none - setupUI() + edgeInset = .zero } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } - override public func configure(_ anyModel: Any) { - super.configure(anyModel) - subTitleLabel.text = model?.subTitle - } + override func setupUI() { + super.setupUI() + contentView.updateLayoutConstraint(firstItem: dividerLine, seconedItem: contentView, attribute: .left, constant: 16) + contentView.updateLayoutConstraint(firstItem: dividerLine, seconedItem: contentView, attribute: .right, constant: 0) - func setupUI() { - contentView.addSubview(titleLabel) NSLayoutConstraint.activate([ - titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 36), + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16), titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16), - titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -84), + titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -56), ]) - contentView.addSubview(subTitleLabel) NSLayoutConstraint.activate([ subTitleLabel.leftAnchor.constraint(equalTo: titleLabel.leftAnchor), subTitleLabel.rightAnchor.constraint(equalTo: titleLabel.rightAnchor), - subTitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 6.0), + subTitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4.0), ]) - contentView.addSubview(arrow) NSLayoutConstraint.activate([ arrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - arrow.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -36), + arrow.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16), ]) } } diff --git a/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamSettingSwitchCell.swift b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamSettingSwitchCell.swift new file mode 100644 index 00000000..681ad4ca --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamSettingSwitchCell.swift @@ -0,0 +1,35 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class FunTeamSettingSwitchCell: NEBaseTeamSettingSwitchCell { + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + edgeInset = .zero + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + override open func setupUI() { + super.setupUI() + contentView.updateLayoutConstraint(firstItem: dividerLine, seconedItem: contentView, attribute: .left, constant: 16) + contentView.updateLayoutConstraint(firstItem: dividerLine, seconedItem: contentView, attribute: .right, constant: 0) + + NSLayoutConstraint.activate([ + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16), + titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -74), + ]) + + tSwitch.onTintColor = .funTeamThemeColor + NSLayoutConstraint.activate([ + tSwitch.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + tSwitch.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -14), + ]) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamUserCell.swift b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamUserCell.swift new file mode 100644 index 00000000..596b0506 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Cell/FunTeamUserCell.swift @@ -0,0 +1,23 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonKit +import NIMSDK +import NECoreIMKit +import NECoreKit + +@objcMembers +open class FunTeamUserCell: NEBaseTeamUserCell { + override func setupUI() { + super.setupUI() + userHeader.layer.cornerRadius = 4 + NSLayoutConstraint.activate([ + userHeader.rightAnchor.constraint(equalTo: contentView.rightAnchor), + userHeader.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + userHeader.widthAnchor.constraint(equalToConstant: 36.0), + userHeader.heightAnchor.constraint(equalToConstant: 36.0), + ]) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamAvatarViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamAvatarViewController.swift new file mode 100644 index 00000000..9d05ba32 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamAvatarViewController.swift @@ -0,0 +1,103 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonUIKit +import NIMSDK + +@objcMembers +open class FunTeamAvatarViewController: NEBaseTeamAvatarViewController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + iconUrls = TeamRouter.iconUrlsFun + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func setupUI() { + super.setupUI() + headerView.layer.cornerRadius = 6.4 + + addRightAction(localizable("save"), #selector(savePhoto), self, .funTeamThemeColor) + navigationController?.navigationBar.backgroundColor = .white + customNavigationView.backgroundColor = .white + customNavigationView.moreButton.setTitleColor(.funTeamThemeColor, for: .normal) + + view.backgroundColor = .funTeamBackgroundColor + + NSLayoutConstraint.activate([ + headerBack.topAnchor.constraint(equalTo: view.topAnchor, constant: NEConstant.navigationAndStatusHeight), + headerBack.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0), + headerBack.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0), + headerBack.heightAnchor.constraint(equalToConstant: 128.0), + ]) + + NSLayoutConstraint.activate([ + photoImage.centerXAnchor.constraint(equalTo: headerView.rightAnchor), + photoImage.bottomAnchor.constraint(equalTo: headerView.bottomAnchor), + ]) + + NSLayoutConstraint.activate([ + defaultHeaderBack.leftAnchor.constraint(equalTo: headerBack.leftAnchor), + defaultHeaderBack.rightAnchor.constraint(equalTo: headerBack.rightAnchor), + defaultHeaderBack.topAnchor.constraint( + equalTo: headerBack.bottomAnchor, + constant: 8.0 + ), + defaultHeaderBack.heightAnchor.constraint(equalToConstant: 124.0), + ]) + + NSLayoutConstraint.activate([ + tag.leftAnchor.constraint(equalTo: defaultHeaderBack.leftAnchor, constant: 16.0), + tag.topAnchor.constraint(equalTo: defaultHeaderBack.topAnchor, constant: 16.0), + tag.heightAnchor.constraint(equalToConstant: 18), + ]) + + iconCollection.register( + FunTeamDefaultIconCell.self, + forCellWithReuseIdentifier: "\(FunTeamDefaultIconCell.self)" + ) + NSLayoutConstraint.activate([ + iconCollection.topAnchor.constraint(equalTo: tag.bottomAnchor, constant: 0), + iconCollection.leftAnchor.constraint( + equalTo: defaultHeaderBack.leftAnchor, + constant: 16 + ), + iconCollection.rightAnchor.constraint( + equalTo: defaultHeaderBack.rightAnchor, + constant: -16 + ), + iconCollection.heightAnchor.constraint(equalToConstant: 90.0), + ]) + } + + override open func uploadPhoto() { + showCustomBottomAlert(self) + } + + override open func collectionView(_ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + if let cell = collectionView.dequeueReusableCell( + withReuseIdentifier: "\(FunTeamDefaultIconCell.self)", + for: indexPath + ) as? FunTeamDefaultIconCell { + cell.iconImage.image = coreLoader.loadImage("fun_icon_\(indexPath.row)") + + return cell + } + return UICollectionViewCell() + } + + override open func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + sizeForItemAt indexPath: IndexPath) -> CGSize { + let space = (NEConstant.screenWidth - 312.0) / 4.0 + if indexPath.row == 0 { + return CGSize(width: 56, height: 56) + } + return CGSize(width: 56.0 + space, height: 56) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamHistoryMessageController.swift b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamHistoryMessageController.swift new file mode 100644 index 00000000..47dc718c --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamHistoryMessageController.swift @@ -0,0 +1,93 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class FunTeamHistoryMessageController: NEBaseTeamHistoryMessageController { + public lazy var searchView: FunSearchView = { + let view = FunSearchView() + view.translatesAutoresizingMaskIntoConstraints = false + view.searchBotton.setImage(UIImage.ne_imageNamed(name: "funSearch"), for: .normal) + view.searchBotton.setTitle(localizable("search"), for: .normal) + return view + }() + + override public init(session: NIMSession?) { + super.init(session: session) + tag = "FunTeamHistoryMessageController" + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .funTeamBackgroundColor + navigationController?.isNavigationBarHidden = true + customNavigationView.isHidden = true + emptyView.backgroundColor = .clear + emptyView.setEmptyImage(name: "fun_emptyView") + } + + override open func setupSubviews() { + super.setupSubviews() + let leftImageView = UIImageView(image: coreLoader.loadImage("funSearch")) + searchTextField.leftView = leftImageView + searchTextField.font = UIFont.systemFont(ofSize: 16) + searchTextField.textColor = .black + searchTextField.layer.cornerRadius = 4 + searchTextField.backgroundColor = .white + NSLayoutConstraint.activate([ + searchTextField.topAnchor.constraint(equalTo: view.topAnchor, constant: NEConstant.statusBarHeight + 12), + searchTextField.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8), + searchTextField.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -72), + searchTextField.heightAnchor.constraint(equalToConstant: 36), + ]) + + let cancelButton = UIButton() + cancelButton.translatesAutoresizingMaskIntoConstraints = false + cancelButton.setTitle(localizable("cancel"), for: .normal) + cancelButton.setTitleColor(.ne_greyText, for: .normal) + cancelButton.addTarget(self, action: #selector(backEvent), for: .touchUpInside) + + view.addSubview(cancelButton) + NSLayoutConstraint.activate([ + cancelButton.centerYAnchor.constraint(equalTo: searchTextField.centerYAnchor), + cancelButton.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), + cancelButton.widthAnchor.constraint(equalToConstant: 40), + ]) + + tableView.backgroundColor = .funTeamBackgroundColor + NSLayoutConstraint.activate([ + tableView.rightAnchor.constraint(equalTo: view.rightAnchor), + tableView.leftAnchor.constraint(equalTo: view.leftAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + tableView.topAnchor.constraint(equalTo: searchTextField.bottomAnchor, constant: 12), + ]) + tableView.register( + FunHistoryMessageCell.self, + forCellReuseIdentifier: "\(NSStringFromClass(FunHistoryMessageCell.self))" + ) + + tableView.register( + FunSearchSessionHeaderView.self, + forHeaderFooterViewReuseIdentifier: "\(NSStringFromClass(FunSearchSessionHeaderView.self))" + ) + } + + override open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell( + withIdentifier: "\(NSStringFromClass(FunHistoryMessageCell.self))", + for: indexPath + ) as! NEBaseHistoryMessageCell + let cellModel = viewmodel.searchResultInfos?[indexPath.row] + cell.searchText = searchStr + cell.configData(message: cellModel) + return cell + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamInfoViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamInfoViewController.swift new file mode 100644 index 00000000..902aa66d --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamInfoViewController.swift @@ -0,0 +1,82 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class FunTeamInfoViewController: NEBaseTeamInfoViewController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + cellClassDic = [ + SettingCellType.SettingArrowCell.rawValue: FunTeamArrowSettingCell.self, + SettingCellType.SettingHeaderCell.rawValue: FunTeamSettingHeaderCell.self, + ] + view.backgroundColor = .funTeamBackgroundColor + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func viewDidLoad() { + super.viewDidLoad() + viewmodel.cellDatas.forEach { cellModel in + cellModel.cornerType = .none + if cellModel.type == SettingCellType.SettingArrowCell.rawValue { + cellModel.rowHeight = 56 + } + } + } + + override open func setupUI() { + super.setupUI() + navigationController?.navigationBar.backgroundColor = .white + customNavigationView.backgroundColor = .white + customNavigationView.bottomLine.isHidden = false + view.backgroundColor = .funTeamBackgroundColor + } + + // MARK: UITableViewDelegate, UITableViewDataSource + + override open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let model = viewmodel.cellDatas[indexPath.row] + if let cell = tableView.dequeueReusableCell( + withIdentifier: "\(model.type)", + for: indexPath + ) as? NEBaseTeamSettingCell { + cell.configure(model) + return cell + } + return UITableViewCell() + } + + override open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let model = viewmodel.cellDatas[indexPath.row] + if indexPath.row == 0 { + let avatar = FunTeamAvatarViewController() + avatar.team = team + weak var weakSelf = self + avatar.block = { + if let t = weakSelf?.team { + weakSelf?.viewmodel.getData(t) + weakSelf?.contentTable.reloadData() + } + } + navigationController?.pushViewController(avatar, animated: true) + + } else if indexPath.row == 1 { + let nameController = FunTeamNameViewController() + nameController.team = team + nameController.title = model.cellName + navigationController?.pushViewController(nameController, animated: true) + } else if indexPath.row == 2 { + let intr = FunTeamIntroduceViewController() + intr.team = team + intr.title = model.cellName + navigationController?.pushViewController(intr, animated: true) + } + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamIntroduceViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamIntroduceViewController.swift new file mode 100644 index 00000000..16a556bf --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamIntroduceViewController.swift @@ -0,0 +1,40 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonKit +import NIMSDK + +@objcMembers +open class FunTeamIntroduceViewController: NEBaseTeamIntroduceViewController { + override open func setupUI() { + super.setupUI() + view.backgroundColor = .funTeamBackgroundColor + addRightAction(localizable("save"), #selector(saveIntr), self, .funTeamThemeColor) + navigationController?.navigationBar.backgroundColor = .funTeamBackgroundColor + customNavigationView.backgroundColor = .funTeamBackgroundColor + customNavigationView.moreButton.setTitleColor(.funTeamThemeColor, for: .normal) + + NSLayoutConstraint.activate([ + backView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0), + backView.topAnchor.constraint(equalTo: view.topAnchor, constant: NEConstant.navigationAndStatusHeight), + backView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0), + backView.heightAnchor.constraint(equalToConstant: 142), + ]) + + NSLayoutConstraint.activate([ + textView.leftAnchor.constraint(equalTo: backView.leftAnchor, constant: 16.0), + textView.rightAnchor.constraint(equalTo: backView.rightAnchor, constant: -32.0), + textView.topAnchor.constraint(equalTo: backView.topAnchor, constant: 16.0), + textView.heightAnchor.constraint(equalToConstant: 110), + ]) + + NSLayoutConstraint.activate([ + clearButton.rightAnchor.constraint(equalTo: backView.rightAnchor, constant: -16), + clearButton.bottomAnchor.constraint(equalTo: countLabel.topAnchor, constant: -6), + clearButton.widthAnchor.constraint(equalToConstant: 16), + clearButton.heightAnchor.constraint(equalToConstant: 16), + ]) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamMembersController.swift b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamMembersController.swift new file mode 100644 index 00000000..cb3683fc --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamMembersController.swift @@ -0,0 +1,76 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonKit +open class FunTeamMembersController: NEBaseTeamMembersController { + let searchGrayBackView: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = UIColor.funTeamBackgroundColor + return view + }() + + override open func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .funTeamBackgroundColor + contentTable.register(FunTeamMemberCell.self, forCellReuseIdentifier: "\(FunTeamMemberCell.self)") + view.insertSubview(searchGrayBackView, belowSubview: back) + NSLayoutConstraint.activate([ + searchGrayBackView.leftAnchor.constraint(equalTo: view.leftAnchor), + searchGrayBackView.rightAnchor.constraint(equalTo: view.rightAnchor), + searchGrayBackView.topAnchor.constraint(equalTo: customNavigationView.bottomAnchor), + searchGrayBackView.bottomAnchor.constraint(equalTo: contentTable.topAnchor), + ]) + back.backgroundColor = UIColor.white + searchTextField.backgroundColor = UIColor.white + + emptyView.setEmptyImage(name: "fun_user_empty") + } + + override open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + if let cell = tableView.dequeueReusableCell( + withIdentifier: "\(FunTeamMemberCell.self)", + for: indexPath + ) as? FunTeamMemberCell { + if let model = getRealModel(indexPath.row) { + cell.configure(model) + cell.ownerLabel.isHidden = !isOwner(model.nimUser?.userId) + } + if isLastRow(indexPath.row) { + cell.dividerLine.isHidden = true + } else { + cell.dividerLine.isHidden = false + } + return cell + } + return UITableViewCell() + } + + override open func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + 64.0 + } + + func isLastRow(_ index: Int) -> Bool { + if let text = searchTextField.text, text.count > 0 { + if searchDatas.count - 1 == index { + return true + } + } + if let originDatas = datas, originDatas.count - 1 == index { + return true + } + return false + } + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamNameViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamNameViewController.swift new file mode 100644 index 00000000..8b0b3d65 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamNameViewController.swift @@ -0,0 +1,54 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK +import NECommonKit + +@objcMembers +open class FunTeamNameViewController: NEBaseTeamNameViewController { + override open func setupUI() { + super.setupUI() + view.backgroundColor = .funTeamBackgroundColor + navigationController?.navigationBar.backgroundColor = .funTeamBackgroundColor + addRightAction(localizable("save"), #selector(saveName), self, .funTeamThemeColor) + customNavigationView.backgroundColor = .funTeamBackgroundColor + customNavigationView.moreButton.setTitleColor(.funTeamThemeColor, for: .normal) + + NSLayoutConstraint.activate([ + backView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0), + backView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -0), + backView.topAnchor.constraint(equalTo: view.topAnchor, constant: NEConstant.navigationAndStatusHeight), + backView.heightAnchor.constraint(equalToConstant: 60), + ]) + + NSLayoutConstraint.activate([ + textView.leftAnchor.constraint(equalTo: backView.leftAnchor, constant: 16), + textView.rightAnchor.constraint(equalTo: backView.rightAnchor, constant: -32), + textView.centerYAnchor.constraint(equalTo: backView.centerYAnchor, constant: 0), + textView.heightAnchor.constraint(equalToConstant: 60), + ]) + + NSLayoutConstraint.activate([ + clearButton.rightAnchor.constraint(equalTo: backView.rightAnchor, constant: -16), + clearButton.topAnchor.constraint(equalTo: backView.topAnchor, constant: 16), + clearButton.widthAnchor.constraint(equalToConstant: 16), + clearButton.heightAnchor.constraint(equalToConstant: 16), + ]) + } + + override open func disableSubmit() { + rightNavBtn.setTitleColor(.funTeamThemeDisableColor, for: .normal) + rightNavBtn.isEnabled = false + customNavigationView.moreButton.setTitleColor(.funTeamThemeDisableColor, for: .normal) + customNavigationView.moreButton.isEnabled = false + } + + override open func enableSubmit() { + rightNavBtn.setTitleColor(.funTeamThemeColor, for: .normal) + rightNavBtn.isEnabled = true + customNavigationView.moreButton.setTitleColor(.funTeamThemeColor, for: .normal) + customNavigationView.moreButton.isEnabled = true + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamSettingViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamSettingViewController.swift new file mode 100644 index 00000000..26c9e00e --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/FunUI/Controller/FunTeamSettingViewController.swift @@ -0,0 +1,332 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonUIKit +import NECoreIMKit +import NIMSDK + +@objcMembers +open class FunTeamSettingViewController: NEBaseTeamSettingViewController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + className = "FunTeamSettingViewController" + cellClassDic = [ + SettingCellType.SettingArrowCell.rawValue: FunTeamArrowSettingCell.self, + SettingCellType.SettingSwitchCell.rawValue: FunTeamSettingSwitchCell.self, + SettingCellType.SettingSelectCell.rawValue: FunTeamSettingSelectCell.self, + ] + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func reloadSectionData() { + viewmodel.sectionData.forEach { setionModel in + setionModel.cellModels.forEach { cellModel in + cellModel.cornerType = .none + if cellModel.type == SettingCellType.SettingSelectCell.rawValue { + cellModel.rowHeight = 78 + } else if cellModel.type == SettingCellType.SettingArrowCell.rawValue || cellModel.type == SettingCellType.SettingSwitchCell.rawValue { + cellModel.rowHeight = 56 + } + } + } + } + + override open func setupUI() { + super.setupUI() + view.backgroundColor = .funTeamBackgroundColor + teamHeader.layer.cornerRadius = 4.0 + addBtn.setImage(coreLoader.loadImage("fun_add"), for: .normal) + navigationController?.navigationBar.backgroundColor = .white + customNavigationView.backgroundColor = .white + customNavigationView.bottomLine.isHidden = false + } + + override open func getHeaderView() -> UIView { + let back = UIView() + back.frame = CGRect(x: 0, y: 0, width: NEConstant.screenWidth, height: 188) + let cornerView = UIView() + back.addSubview(cornerView) + cornerView.backgroundColor = .white + cornerView.clipsToBounds = true + cornerView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + cornerView.leftAnchor.constraint(equalTo: back.leftAnchor, constant: 0), + cornerView.rightAnchor.constraint(equalTo: back.rightAnchor, constant: 0), + cornerView.topAnchor.constraint(equalTo: back.topAnchor), + cornerView.bottomAnchor.constraint(equalTo: back.bottomAnchor), + ]) + + cornerView.addSubview(teamHeader) + NSLayoutConstraint.activate([ + teamHeader.leftAnchor.constraint(equalTo: cornerView.leftAnchor, constant: 16), + teamHeader.topAnchor.constraint(equalTo: cornerView.topAnchor, constant: 16), + teamHeader.widthAnchor.constraint(equalToConstant: 50), + teamHeader.heightAnchor.constraint(equalToConstant: 50), + ]) + if let url = viewmodel.teamInfoModel?.team?.avatarUrl { + print("icon url : ", url) + teamHeader.sd_setImage(with: URL(string: url), completed: nil) + } else { + if let tid = teamId { + if let name = viewmodel.teamInfoModel?.team?.getShowName() { + teamHeader.setTitle(name) + } + teamHeader.backgroundColor = UIColor.colorWithString(string: "\(tid)") + } + } + + teamNameLabel.text = viewmodel.teamInfoModel?.team?.getShowName() + + cornerView.addSubview(teamNameLabel) + NSLayoutConstraint.activate([ + teamNameLabel.leftAnchor.constraint(equalTo: teamHeader.rightAnchor, constant: 16), + teamNameLabel.centerYAnchor.constraint(equalTo: teamHeader.centerYAnchor), + teamNameLabel.rightAnchor.constraint(equalTo: cornerView.rightAnchor, constant: -50), + ]) + + let arrow = UIImageView() + arrow.translatesAutoresizingMaskIntoConstraints = false + arrow.image = coreLoader.loadImage("arrowRight") + cornerView.addSubview(arrow) + NSLayoutConstraint.activate([ + arrow.centerYAnchor.constraint(equalTo: teamHeader.centerYAnchor), + arrow.rightAnchor.constraint(equalTo: cornerView.rightAnchor, constant: -16), + ]) + + let line = UIView() + line.translatesAutoresizingMaskIntoConstraints = false + line.backgroundColor = NEConstant.hexRGB(0xF5F8FC) + cornerView.addSubview(line) + NSLayoutConstraint.activate([ + line.heightAnchor.constraint(equalToConstant: 1.0), + line.rightAnchor.constraint(equalTo: cornerView.rightAnchor), + line.leftAnchor.constraint(equalTo: teamHeader.leftAnchor, constant: 0), + line.topAnchor.constraint(equalTo: teamHeader.bottomAnchor, constant: 16.0), + ]) + + let memberLabel = UILabel() + cornerView.addSubview(memberLabel) + memberLabel.translatesAutoresizingMaskIntoConstraints = false + memberLabel.textColor = NEConstant.hexRGB(0x333333) + memberLabel.font = NEConstant.defaultTextFont(16.0) + cornerView.addSubview(memberLabel) + NSLayoutConstraint.activate([ + memberLabel.leftAnchor.constraint(equalTo: line.leftAnchor), + memberLabel.topAnchor.constraint(equalTo: line.bottomAnchor, constant: 16), + ]) + + if teamSettingType == .Senior { + memberLabel.text = localizable("group_memmber") + } else { + memberLabel.text = localizable("discuss_mebmer") + } + + let memberArrow = UIImageView() + cornerView.addSubview(memberArrow) + memberArrow.translatesAutoresizingMaskIntoConstraints = false + memberArrow.image = coreLoader.loadImage("arrowRight") + NSLayoutConstraint.activate([ + memberArrow.rightAnchor.constraint(equalTo: arrow.rightAnchor, constant: 0), + memberArrow.centerYAnchor.constraint(equalTo: memberLabel.centerYAnchor), + ]) + + let memberListBtn = UIButton() + cornerView.addSubview(memberListBtn) + memberListBtn.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + memberListBtn.leftAnchor.constraint(equalTo: memberLabel.leftAnchor), + memberListBtn.rightAnchor.constraint(equalTo: memberArrow.rightAnchor), + memberListBtn.centerYAnchor.constraint(equalTo: memberLabel.centerYAnchor), + memberListBtn.heightAnchor.constraint(equalToConstant: 50), + ]) + memberListBtn.addTarget(self, action: #selector(toMemberList), for: .touchUpInside) + + cornerView.addSubview(memberCountLabel) + NSLayoutConstraint.activate([ + memberCountLabel.rightAnchor.constraint(equalTo: memberArrow.leftAnchor, constant: -8), + memberCountLabel.centerYAnchor.constraint(equalTo: memberArrow.centerYAnchor), + ]) + memberCountLabel.text = "\(viewmodel.teamInfoModel?.team?.memberNumber ?? 0)" + + cornerView.addSubview(addBtn) + addBtnWidth = addBtn.widthAnchor.constraint(equalToConstant: 36) + addBtnWidth?.isActive = true + addBtnLeftMargin = addBtn.leftAnchor.constraint(equalTo: cornerView.leftAnchor, constant: 16.0) + NSLayoutConstraint.activate([ + addBtnLeftMargin!, + addBtn.topAnchor.constraint(equalTo: memberListBtn.bottomAnchor, constant: 0), + ]) + addBtn.addTarget(self, action: #selector(addUser), for: .touchUpInside) + + if viewmodel.isNormalTeam() == false, viewmodel.isOwner() == false, + let inviteMode = viewmodel.teamInfoModel?.team?.inviteMode, inviteMode == .manager { + addBtnWidth?.constant = 0 + addBtn.isHidden = true + } + + setupUserInfoCollection(cornerView) + + let infoBtn = UIButton() + infoBtn.translatesAutoresizingMaskIntoConstraints = false + cornerView.addSubview(infoBtn) + NSLayoutConstraint.activate([ + infoBtn.leftAnchor.constraint(equalTo: teamHeader.leftAnchor), + infoBtn.topAnchor.constraint(equalTo: teamHeader.topAnchor), + infoBtn.bottomAnchor.constraint(equalTo: teamHeader.bottomAnchor), + infoBtn.rightAnchor.constraint(equalTo: arrow.rightAnchor), + ]) + infoBtn.addTarget(self, action: #selector(toInfoView), for: .touchUpInside) + + return back + } + + override open func getFooterView() -> UIView? { + guard let title = getBottomText() else { + return nil + } + let footer = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 64.0)) + let button = UIButton() + button.translatesAutoresizingMaskIntoConstraints = false + footer.addSubview(button) + button.backgroundColor = .white + button.clipsToBounds = true + button.setTitleColor(NEConstant.hexRGB(0xE6605C), for: .normal) + button.titleLabel?.font = NEConstant.defaultTextFont(16.0) + button.setTitle(title, for: .normal) + button.addTarget(self, action: #selector(removeTeamForMyself), for: .touchUpInside) + NSLayoutConstraint.activate([ + button.leftAnchor.constraint(equalTo: footer.leftAnchor, constant: 0), + button.rightAnchor.constraint(equalTo: footer.rightAnchor, constant: 0), + button.topAnchor.constraint(equalTo: footer.topAnchor, constant: 12), + button.heightAnchor.constraint(equalToConstant: 56), + ]) + return footer + } + + override open func setupUserInfoCollection(_ cornerView: UIView) { + cornerView.addSubview(userinfoCollection) + NSLayoutConstraint.activate([ + userinfoCollection.leftAnchor.constraint(equalTo: addBtn.rightAnchor, constant: 16), + userinfoCollection.centerYAnchor.constraint(equalTo: addBtn.centerYAnchor), + userinfoCollection.rightAnchor.constraint( + equalTo: cornerView.rightAnchor, + constant: -16 + ), + userinfoCollection.heightAnchor.constraint(equalToConstant: 36), + ]) + + userinfoCollection.register( + FunTeamUserCell.self, + forCellWithReuseIdentifier: "\(FunTeamUserCell.self)" + ) + } + + override open func checkoutAddShowOrHide() { + if viewmodel.isNormalTeam() == false, viewmodel.isOwner() == false, + let inviteMode = viewmodel.teamInfoModel?.team?.inviteMode, inviteMode == .manager { + return + } + if viewmodel.teamInfoModel?.team?.level == viewmodel.teamInfoModel?.team?.memberNumber { + addBtn.isHidden = true + addBtnWidth?.constant = 0 + addBtnLeftMargin?.constant = 0 + } else { + addBtn.isHidden = false + addBtnWidth?.constant = 36.0 + addBtnLeftMargin?.constant = 16 + } + } + + // MARK: objc 方法 + + override open func toInfoView() { + let info = FunTeamInfoViewController() + info.team = viewmodel.teamInfoModel?.team + navigationController?.pushViewController(info, animated: true) + } + + override open func didClickChangeNick() { + let nick = FunTeamNameViewController() + nick.type = .NickName + nick.team = viewmodel.teamInfoModel?.team + nick.teamMember = viewmodel.memberInTeam + navigationController?.pushViewController(nick, animated: true) + } + + override open func didChangeInviteModeClick(_ model: SettingCellModel) { + weak var weakSelf = self + + let allAction = NECustomAlertAction(title: localizable("team_all")) { + weakSelf?.updateInviteModeAllAction(model) + } + + let ownerAction = NECustomAlertAction(title: localizable("team_owner")) { + weakSelf?.updateInviteModeOwnerAction(model) + } + + showCustomActionSheet([ownerAction, allAction]) + } + + override open func didUpdateTeamInfoClick(_ model: SettingCellModel) { + weak var weakSelf = self + + let allAction = NECustomAlertAction(title: localizable("team_all")) { + weakSelf?.updateTeamInfoAllAction(model) + } + + let ownerAction = NECustomAlertAction(title: localizable("team_owner")) { + weakSelf?.updateTeamInfoOwnerAction(model) + } + + showCustomActionSheet([ownerAction, allAction]) + } + + override open func didClickHistoryMessage() { + guard let tid = teamId else { + return + } + Router.shared.use( + SearchMessageRouter, + parameters: ["nav": navigationController as Any, "teamId": tid], + closure: nil + ) + } + + override open func collectionView(_ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + if let cell = collectionView.dequeueReusableCell( + withReuseIdentifier: "\(FunTeamUserCell.self)", + for: indexPath + ) as? FunTeamUserCell { + if let user = viewmodel.teamInfoModel?.users[indexPath.row] { + cell.user = user + } + return cell + } + return UICollectionViewCell() + } + + override open func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + sizeForItemAt indexPath: IndexPath) -> CGSize { + if indexPath.row == 0 { + return CGSize(width: 36, height: 36) + } + return CGSize(width: 36 + 16, height: 36) + } + + override open func toMemberList() { + let memberController = FunTeamMembersController(viewmodel: viewmodel) + memberController.datas = viewmodel.teamInfoModel?.users + if teamSettingType == .Senior { + memberController.isSenior = true + } + memberController.ownerId = viewmodel.teamInfoModel?.team?.owner + navigationController?.pushViewController(memberController, animated: true) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/FunUI/FunTeamRouter.swift b/NETeamUIKit/NETeamUIKit/Classes/FunUI/FunTeamRouter.swift new file mode 100644 index 00000000..0f88fe97 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/FunUI/FunTeamRouter.swift @@ -0,0 +1,32 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import NECoreKit +import NECoreIMKit +import NIMSDK + +public extension TeamRouter { + static func registerFun() { + registerCommon(icUrls: iconUrlsFun) + + Router.shared.register(TeamSettingViewRouter) { param in + let nav = param["nav"] as? UINavigationController + let teamId = param["teamid"] as? String + let teamSetting = FunTeamSettingViewController() + teamSetting.teamId = teamId + nav?.pushViewController(teamSetting, animated: true) + } + + Router.shared.register(SearchMessageRouter) { param in + + let nav = param["nav"] as? UINavigationController + if let tid = param["teamId"] as? String { + let session = NIMSession(tid, type: .team) + let searchMsgCtrl = FunTeamHistoryMessageController(session: session) + nav?.pushViewController(searchMsgCtrl, animated: true) + } + } + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/FunUI/FunTeamUIColor.swift b/NETeamUIKit/NETeamUIKit/Classes/FunUI/FunTeamUIColor.swift new file mode 100644 index 00000000..64ca64df --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/FunUI/FunTeamUIColor.swift @@ -0,0 +1,18 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import NECommonKit + +extension UIColor { + static let funTeamMemberDividerLine = UIColor(hexString: "#E4E9F2") + static let funTeamMemberOwnerFlagColor = UIColor(hexString: "#58BE6B") + static let funTeamMebmerSearchBg = UIColor(hexString: "0xF1F1F6") + + static let funTeamThemeColor = UIColor(hexString: "#58BE6B") + static let funTeamThemeDisableColor = UIColor(hexString: "#58BE6B", 0.5) + static let funTeamBackgroundColor = UIColor(hexString: "#EDEDED") + static let funTeamLineBorderColor = UIColor(hexString: "#E5E5E5") + static let funTeamHistoryCellTitleTextColor = UIColor(hexString: "#737373") +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/TeamRouter.swift b/NETeamUIKit/NETeamUIKit/Classes/NEBaseTeamRouter.swift similarity index 80% rename from NETeamUIKit/NETeamUIKit/Classes/TeamRouter.swift rename to NETeamUIKit/NETeamUIKit/Classes/NEBaseTeamRouter.swift index 7c3fcf07..3af68f83 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/TeamRouter.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/NEBaseTeamRouter.swift @@ -3,30 +3,26 @@ // found in the LICENSE file. import Foundation -import NETeamKit import NECoreKit import NECoreIMKit import NIMSDK @objcMembers public class TeamRouter: NSObject { + public static let repo = TeamRepo() public static var iconUrls = ["https://s.netease.im/safe/ABg8YjWQWvcqO6sAAAAAAAAAAAA?_im_url=1", "https://s.netease.im/safe/ABg8YjmQWvcqO6sAAAAAAAABAAA?_im_url=1", "https://s.netease.im/safe/ABg8YjyQWvcqO6sAAAAAAAABAAA?_im_url=1", "https://s.netease.im/safe/ABg8YkCQWvcqO6sAAAAAAAABAAA?_im_url=1", "https://s.netease.im/safe/ABg8YkSQWvcqO6sAAAAAAAABAAA?_im_url=1"] - public static let repo = TeamRepo() - - public static func register() { - Router.shared.register(TeamSettingViewRouter) { param in - let nav = param["nav"] as? UINavigationController - let teamId = param["teamid"] as? String - let teamSetting = TeamSettingViewController() - teamSetting.teamId = teamId - nav?.pushViewController(teamSetting, animated: true) - } + public static var iconUrlsFun = ["https://nim-nosdn.netease.im/MjYxNDkzNzE=/bmltYV8xNDIxMTk0NzAzMzhfMTY4NDgyNzc0MTczNV8yY2FlMjczZS01MDk0LTQ5NWMtODMzMS1mYTBmMTE1NmEyNDQ=", + "https://nim-nosdn.netease.im/MjYxNDkzNzE=/bmltYV8xNDIxMTk0NzAzMzhfMTY4NDgyNzc0MTczNV9jYWJmNjViNy1kMGM3LTRiNDEtYmVmMi1jYjhiNzRjY2EwY2M=", + "https://nim-nosdn.netease.im/MjYxNDkzNzE=/bmltYV8xNDIxMTk0NzAzMzhfMTY4NDgyNzc0MTczNV8yMzY1YmY5YS0xNGE1LTQxYTctYTg2My1hMzMyZWE5YzhhOTQ=", + "https://nim-nosdn.netease.im/MjYxNDkzNzE=/bmltYV8xNDIxMTk0NzAzMzhfMTY4NDgyNzc0MTczNV80NTQxMDhhNy1mNWMzLTQxMzMtOWU3NS1hNThiN2FiNjI5MWY=", + "https://nim-nosdn.netease.im/MjYxNDkzNzE=/bmltYV8xNDIxMTk0NzAzMzhfMTY4NDgyNzc0MTczNV8wMGVlNWUyOS0wYzg3LTQxMzUtYmVjOS00YjI1MjcxMDhhNTM="] + public static func registerCommon(icUrls: [String]) { Router.shared.register(TeamCreateDisuss) { param in if let accids = param["accids"] as? [String] { var name = (param["names"] as? String) ?? localizable("normal_team") @@ -46,7 +42,6 @@ public class TeamRouter: NSObject { option.beInviteMode = .noAuth option.updateInfoMode = .all option.updateClientCustomMode = .all - option.maxMemberCountLimitation = peopleNumberLimit repo.createAdvanceTeam(accids, option) { error, teamid, failedIds in var result = [String: Any]() @@ -92,7 +87,6 @@ public class TeamRouter: NSObject { option.avatarUrl = iconUrl option.name = name option.beInviteMode = .noAuth - option.maxMemberCountLimitation = peopleNumberLimit repo.createAdvanceTeam(accids, option) { error, teamid, failedIds in var result = [String: Any]() @@ -116,15 +110,5 @@ public class TeamRouter: NSObject { } } } - - Router.shared.register(SearchMessageRouter) { param in - - let nav = param["nav"] as? UINavigationController - if let tid = param["teamId"] as? String { - let session = NIMSession(tid, type: .team) - let searchMsgCtrl = TeamHistoryMessageController(session: session) - nav?.pushViewController(searchMsgCtrl, animated: true) - } - } } } diff --git a/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/HistoryMessageCell.swift b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/HistoryMessageCell.swift new file mode 100644 index 00000000..2470b0cc --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/HistoryMessageCell.swift @@ -0,0 +1,49 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. +import UIKit +import NIMSDK + +@objcMembers +open class HistoryMessageCell: NEBaseHistoryMessageCell { + override func setupSubviews() { + super.setupSubviews() + NSLayoutConstraint.activate([ + headImge.leftAnchor.constraint( + equalTo: contentView.leftAnchor, + constant: NEConstant.screenInterval + ), + headImge.centerYAnchor.constraint(equalTo: contentView.centerYAnchor, constant: -5), + headImge.widthAnchor.constraint(equalToConstant: 36), + headImge.heightAnchor.constraint(equalToConstant: 36), + ]) + + NSLayoutConstraint.activate([ + title.leftAnchor.constraint(equalTo: headImge.rightAnchor, constant: 12), + title.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20), + title.topAnchor.constraint(equalTo: headImge.topAnchor), + ]) + + NSLayoutConstraint.activate([ + subTitle.leftAnchor.constraint(equalTo: headImge.rightAnchor, constant: 12), + subTitle.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -50), + subTitle.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 6), + ]) + + NSLayoutConstraint.activate([ + bottomLine.rightAnchor.constraint(equalTo: contentView.rightAnchor), + bottomLine.leftAnchor.constraint(equalTo: headImge.leftAnchor), + bottomLine.bottomAnchor.constraint(equalTo: bottomAnchor), + bottomLine.heightAnchor.constraint(equalToConstant: 0.5), + ]) + + NSLayoutConstraint.activate([ + timeLabel.rightAnchor.constraint( + equalTo: contentView.rightAnchor, + constant: -NEConstant.screenInterval + ), + timeLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + ]) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamArrowSettingCell.swift b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamArrowSettingCell.swift new file mode 100644 index 00000000..e14d218a --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamArrowSettingCell.swift @@ -0,0 +1,23 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class TeamArrowSettingCell: NEBaseTeamArrowSettingCell { + override open func setupUI() { + super.setupUI() + NSLayoutConstraint.activate([ + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 36), + titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -84), + ]) + + NSLayoutConstraint.activate([ + arrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + arrow.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -36), + ]) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamDefaultIconCell.swift b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamDefaultIconCell.swift new file mode 100644 index 00000000..0061fa4a --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamDefaultIconCell.swift @@ -0,0 +1,27 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonKit + +@objcMembers +open class TeamDefaultIconCell: NEBaseTeamDefaultIconCell { + override func setupUI() { + super.setupUI() + NSLayoutConstraint.activate([ + selectBack.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), + selectBack.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + selectBack.widthAnchor.constraint(equalToConstant: 48.0), + selectBack.heightAnchor.constraint(equalToConstant: 48.0), + ]) + + NSLayoutConstraint.activate([ + iconImage.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), + iconImage.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + iconImage.heightAnchor.constraint(equalToConstant: 32), + iconImage.widthAnchor.constraint(equalToConstant: 32), + ]) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamMemberCell.swift b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamMemberCell.swift new file mode 100644 index 00000000..3405292b --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamMemberCell.swift @@ -0,0 +1,8 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class TeamMemberCell: NEBaseTeamMemberCell {} diff --git a/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamSettingHeaderCell.swift b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamSettingHeaderCell.swift new file mode 100644 index 00000000..5298abc4 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamSettingHeaderCell.swift @@ -0,0 +1,33 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonUIKit + +@objcMembers +open class TeamSettingHeaderCell: NEBaseTeamSettingHeaderCell { + override open func setupUI() { + super.setupUI() + headerView.layer.cornerRadius = 21.0 + + NSLayoutConstraint.activate([ + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 36), + titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -84), + ]) + + NSLayoutConstraint.activate([ + arrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + arrow.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -36), + ]) + + NSLayoutConstraint.activate([ + headerView.centerYAnchor.constraint(equalTo: arrow.centerYAnchor), + headerView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -64.0), + headerView.widthAnchor.constraint(equalToConstant: 42.0), + headerView.heightAnchor.constraint(equalToConstant: 42.0), + ]) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamSettingSelectCell.swift b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamSettingSelectCell.swift new file mode 100644 index 00000000..e5273e3a --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamSettingSelectCell.swift @@ -0,0 +1,29 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class TeamSettingSelectCell: NEBaseTeamSettingSelectCell { + override func setupUI() { + super.setupUI() + NSLayoutConstraint.activate([ + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 36), + titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16), + titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -84), + ]) + + NSLayoutConstraint.activate([ + subTitleLabel.leftAnchor.constraint(equalTo: titleLabel.leftAnchor), + subTitleLabel.rightAnchor.constraint(equalTo: titleLabel.rightAnchor), + subTitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 6.0), + ]) + + NSLayoutConstraint.activate([ + arrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + arrow.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -36), + ]) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamSettingSwitchCell.swift b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamSettingSwitchCell.swift new file mode 100644 index 00000000..0c342fc7 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamSettingSwitchCell.swift @@ -0,0 +1,24 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class TeamSettingSwitchCell: NEBaseTeamSettingSwitchCell { + override open func setupUI() { + super.setupUI() + tSwitch.onTintColor = NEConstant.hexRGB(0x337EFF) + NSLayoutConstraint.activate([ + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 36), + titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -84), + ]) + + NSLayoutConstraint.activate([ + tSwitch.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + tSwitch.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -36), + ]) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamUserCell.swift b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamUserCell.swift new file mode 100644 index 00000000..e3046fa1 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Cell/TeamUserCell.swift @@ -0,0 +1,24 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonKit +import NIMSDK +import NECoreIMKit +import NECoreKit + +@objcMembers +open class TeamUserCell: NEBaseTeamUserCell { + override func setupUI() { + super.setupUI() + userHeader.layer.cornerRadius = 16.0 + NSLayoutConstraint.activate([ + userHeader.leftAnchor.constraint(equalTo: contentView.leftAnchor), + userHeader.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + userHeader.widthAnchor.constraint(equalToConstant: 32.0), + userHeader.heightAnchor.constraint(equalToConstant: 32.0), + ]) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamAvatarViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamAvatarViewController.swift new file mode 100644 index 00000000..c151f210 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamAvatarViewController.swift @@ -0,0 +1,98 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonUIKit +import NIMSDK + +@objcMembers +open class TeamAvatarViewController: NEBaseTeamAvatarViewController { + override open func setupUI() { + super.setupUI() + headerView.layer.cornerRadius = 40 + + addRightAction(localizable("save"), #selector(savePhoto), self) + + view.backgroundColor = .ne_lightBackgroundColor + customNavigationView.backgroundColor = .ne_lightBackgroundColor + customNavigationView.setBackButtonTitle(localizable("cancel")) + customNavigationView.backButton.setTitleColor(.ne_greyText, for: .normal) + navigationController?.navigationBar.backgroundColor = .ne_lightBackgroundColor + + headerBack.layer.cornerRadius = 8.0 + + NSLayoutConstraint.activate([ + headerBack.topAnchor.constraint(equalTo: view.topAnchor, constant: 12.0 + NEConstant.navigationAndStatusHeight), + headerBack.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20), + headerBack.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), + headerBack.heightAnchor.constraint(equalToConstant: 128.0), + ]) + + NSLayoutConstraint.activate([ + photoImage.rightAnchor.constraint(equalTo: headerView.rightAnchor), + photoImage.bottomAnchor.constraint(equalTo: headerView.bottomAnchor), + ]) + + let gesture = UITapGestureRecognizer() + headerView.addGestureRecognizer(gesture) + gesture.addTarget(self, action: #selector(uploadPhoto)) + + defaultHeaderBack.layer.cornerRadius = 8.0 + NSLayoutConstraint.activate([ + defaultHeaderBack.leftAnchor.constraint(equalTo: headerBack.leftAnchor), + defaultHeaderBack.rightAnchor.constraint(equalTo: headerBack.rightAnchor), + defaultHeaderBack.topAnchor.constraint( + equalTo: headerBack.bottomAnchor, + constant: 12.0 + ), + defaultHeaderBack.heightAnchor.constraint(equalToConstant: 114.0), + ]) + + NSLayoutConstraint.activate([ + tag.leftAnchor.constraint(equalTo: defaultHeaderBack.leftAnchor, constant: 16.0), + tag.topAnchor.constraint(equalTo: defaultHeaderBack.topAnchor, constant: 15.0), + ]) + + iconCollection.register( + TeamDefaultIconCell.self, + forCellWithReuseIdentifier: "\(TeamDefaultIconCell.self)" + ) + NSLayoutConstraint.activate([ + iconCollection.topAnchor.constraint(equalTo: tag.bottomAnchor, constant: 16.0), + iconCollection.leftAnchor.constraint( + equalTo: defaultHeaderBack.leftAnchor, + constant: 18 + ), + iconCollection.rightAnchor.constraint( + equalTo: defaultHeaderBack.rightAnchor, + constant: -18.0 + ), + iconCollection.heightAnchor.constraint(equalToConstant: 48.0), + ]) + } + + override open func collectionView(_ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + if let cell = collectionView.dequeueReusableCell( + withReuseIdentifier: "\(TeamDefaultIconCell.self)", + for: indexPath + ) as? TeamDefaultIconCell { + cell.iconImage.image = coreLoader.loadImage("icon_\(indexPath.row)") + + return cell + } + return UICollectionViewCell() + } + + override open func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + sizeForItemAt indexPath: IndexPath) -> CGSize { + let space = (NEConstant.screenWidth - 297.0) / 4.0 + if indexPath.row == 0 { + return CGSize(width: 48, height: 48) + } + return CGSize(width: 48.0 + space, height: 48) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamHistoryMessageController.swift b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamHistoryMessageController.swift new file mode 100644 index 00000000..881b2e69 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamHistoryMessageController.swift @@ -0,0 +1,57 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class TeamHistoryMessageController: NEBaseTeamHistoryMessageController { + override public init(session: NIMSession?) { + super.init(session: session) + tag = "TeamHistoryMessageController" + customNavigationView.backgroundColor = .white + navigationController?.navigationBar.backgroundColor = .white + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func setupSubviews() { + super.setupSubviews() + NSLayoutConstraint.activate([ + searchTextField.topAnchor.constraint( + equalTo: view.topAnchor, + constant: NEConstant.navigationHeight + NEConstant.statusBarHeight + 20 + ), + searchTextField.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20), + searchTextField.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), + searchTextField.heightAnchor.constraint(equalToConstant: 32), + ]) + + NSLayoutConstraint.activate([ + tableView.rightAnchor.constraint(equalTo: view.rightAnchor), + tableView.leftAnchor.constraint(equalTo: view.leftAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + tableView.topAnchor.constraint(equalTo: searchTextField.bottomAnchor, constant: 20), + ]) + + tableView.register( + HistoryMessageCell.self, + forCellReuseIdentifier: "\(NSStringFromClass(HistoryMessageCell.self))" + ) + } + + override open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell( + withIdentifier: "\(NSStringFromClass(HistoryMessageCell.self))", + for: indexPath + ) as! NEBaseHistoryMessageCell + let cellModel = viewmodel.searchResultInfos?[indexPath.row] + cell.searchText = searchStr + cell.configData(message: cellModel) + return cell + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamInfoViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamInfoViewController.swift new file mode 100644 index 00000000..c664cd49 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamInfoViewController.swift @@ -0,0 +1,78 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class TeamInfoViewController: NEBaseTeamInfoViewController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + cellClassDic = [ + SettingCellType.SettingArrowCell.rawValue: TeamArrowSettingCell.self, + SettingCellType.SettingHeaderCell.rawValue: TeamSettingHeaderCell.self, + ] + view.backgroundColor = .ne_lightBackgroundColor + customNavigationView.backgroundColor = .ne_lightBackgroundColor + navigationController?.navigationBar.backgroundColor = .ne_lightBackgroundColor + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func setupUI() { + super.setupUI() + view.backgroundColor = .ne_lightBackgroundColor + } + + // MARK: UITableViewDelegate, UITableViewDataSource + + override open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let model = viewmodel.cellDatas[indexPath.row] + if let cell = tableView.dequeueReusableCell( + withIdentifier: "\(model.type)", + for: indexPath + ) as? NEBaseTeamSettingCell { + cell.configure(model) + return cell + } + return UITableViewCell() + } + + override open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let model = viewmodel.cellDatas[indexPath.row] + if indexPath.row == 0 { + let avatar = TeamAvatarViewController() + avatar.team = team + weak var weakSelf = self + avatar.block = { + if let t = weakSelf?.team { + weakSelf?.viewmodel.getData(t) + weakSelf?.contentTable.reloadData() + } + } + navigationController?.pushViewController(avatar, animated: true) + + } else if indexPath.row == 1 { + let nameController = TeamNameViewController() + nameController.team = team + nameController.title = model.cellName + navigationController?.pushViewController(nameController, animated: true) + } else if indexPath.row == 2 { + let intr = TeamIntroduceViewController() + intr.team = team + intr.title = model.cellName + navigationController?.pushViewController(intr, animated: true) + } + } + + override open func tableView(_ tableView: UITableView, + heightForRowAt indexPath: IndexPath) -> CGFloat { + let model = viewmodel.cellDatas[indexPath.row] + return model.rowHeight + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamIntroduceViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamIntroduceViewController.swift new file mode 100644 index 00000000..4ce17bf9 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamIntroduceViewController.swift @@ -0,0 +1,43 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonKit +import NIMSDK + +@objcMembers +open class TeamIntroduceViewController: NEBaseTeamIntroduceViewController { + override open func setupUI() { + super.setupUI() + view.backgroundColor = .ne_lightBackgroundColor + customNavigationView.backgroundColor = .ne_lightBackgroundColor + navigationController?.navigationBar.backgroundColor = .ne_lightBackgroundColor + addRightAction(localizable("save"), #selector(saveIntr), self) + customNavigationView.setBackButtonTitle(localizable("cancel")) + customNavigationView.backButton.setTitleColor(.ne_greyText, for: .normal) + + backView.layer.cornerRadius = 8.0 + NSLayoutConstraint.activate([ + backView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20), + backView.topAnchor.constraint(equalTo: view.topAnchor, constant: 12.0 + NEConstant.navigationAndStatusHeight), + backView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), + backView.heightAnchor.constraint(equalToConstant: 170), + ]) + + NSLayoutConstraint.activate([ + textView.leftAnchor.constraint(equalTo: backView.leftAnchor, constant: 16.0), + textView.rightAnchor.constraint(equalTo: backView.rightAnchor, constant: -32.0), + textView.topAnchor.constraint(equalTo: backView.topAnchor, constant: 16.0), + textView.heightAnchor.constraint(equalToConstant: 120), + ]) + + NSLayoutConstraint.activate([ + clearButton.rightAnchor.constraint(equalTo: backView.rightAnchor, constant: -16), + clearButton.bottomAnchor.constraint(equalTo: countLabel.topAnchor, constant: -6), + clearButton.widthAnchor.constraint(equalToConstant: 16), + clearButton.heightAnchor.constraint(equalToConstant: 16), + ]) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamMembersController.swift b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamMembersController.swift new file mode 100644 index 00000000..54ddd082 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamMembersController.swift @@ -0,0 +1,44 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class TeamMembersController: NEBaseTeamMembersController { + override open func viewDidLoad() { + super.viewDidLoad() + customNavigationView.backgroundColor = .white + navigationController?.navigationBar.backgroundColor = .white + back.backgroundColor = .ne_backcolor + contentTable.register(TeamMemberCell.self, forCellReuseIdentifier: "\(TeamMemberCell.self)") + } + + override open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + if let cell = tableView.dequeueReusableCell( + withIdentifier: "\(TeamMemberCell.self)", + for: indexPath + ) as? TeamMemberCell { + if let model = getRealModel(indexPath.row) { + cell.configure(model) + cell.ownerLabel.isHidden = !isOwner(model.nimUser?.userId) + } + return cell + } + return UITableViewCell() + } + + override open func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + 64.0 + } + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamNameViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamNameViewController.swift new file mode 100644 index 00000000..072b4140 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamNameViewController.swift @@ -0,0 +1,43 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK +import NECommonKit + +@objcMembers +open class TeamNameViewController: NEBaseTeamNameViewController { + override open func setupUI() { + super.setupUI() + view.backgroundColor = .ne_lightBackgroundColor + customNavigationView.backgroundColor = .ne_lightBackgroundColor + navigationController?.navigationBar.backgroundColor = .ne_lightBackgroundColor + addRightAction(localizable("save"), #selector(saveName), self) + customNavigationView.setBackButtonTitle(localizable("cancel")) + customNavigationView.backButton.setTitleColor(.ne_greyText, for: .normal) + + backView.layer.cornerRadius = 8.0 + NSLayoutConstraint.activate([ + backView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20.0), + backView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), + backView.topAnchor.constraint(equalTo: view.topAnchor, constant: 12 + NEConstant.navigationAndStatusHeight), + backView.heightAnchor.constraint(equalToConstant: 60), + ]) + + NSLayoutConstraint.activate([ + textView.leftAnchor.constraint(equalTo: backView.leftAnchor, constant: 16), + textView.rightAnchor.constraint(equalTo: backView.rightAnchor, constant: -32), + textView.topAnchor.constraint(equalTo: backView.topAnchor, constant: 0), + textView.heightAnchor.constraint(equalToConstant: 44), + ]) + + NSLayoutConstraint.activate([ + clearButton.rightAnchor.constraint(equalTo: backView.rightAnchor, constant: -32), + clearButton.topAnchor.constraint(equalTo: backView.topAnchor, constant: 16), + clearButton.widthAnchor.constraint(equalToConstant: 16), + clearButton.heightAnchor.constraint(equalToConstant: 16), + ]) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamSettingViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamSettingViewController.swift new file mode 100644 index 00000000..a0ab6627 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/Controller/TeamSettingViewController.swift @@ -0,0 +1,289 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonUIKit +import NECoreIMKit +import NIMSDK + +@objcMembers +open class TeamSettingViewController: NEBaseTeamSettingViewController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + customNavigationView.backgroundColor = .ne_lightBackgroundColor + navigationController?.navigationBar.backgroundColor = .ne_lightBackgroundColor + className = "TeamSettingViewController" + cellClassDic = [ + SettingCellType.SettingArrowCell.rawValue: TeamArrowSettingCell.self, + SettingCellType.SettingSwitchCell.rawValue: TeamSettingSwitchCell.self, + SettingCellType.SettingSelectCell.rawValue: TeamSettingSelectCell.self, + ] + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func setupUI() { + super.setupUI() + teamHeader.layer.cornerRadius = 21.0 + addBtn.setImage(coreLoader.loadImage("add"), for: .normal) + } + + override open func getHeaderView() -> UIView { + let back = UIView() + back.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: 172) + let cornerView = UIView() + back.addSubview(cornerView) + cornerView.backgroundColor = .white + cornerView.clipsToBounds = true + cornerView.translatesAutoresizingMaskIntoConstraints = false + cornerView.layer.cornerRadius = 8.0 + NSLayoutConstraint.activate([ + cornerView.leftAnchor.constraint(equalTo: back.leftAnchor, constant: 20), + cornerView.rightAnchor.constraint(equalTo: back.rightAnchor, constant: -20), + cornerView.bottomAnchor.constraint(equalTo: back.bottomAnchor), + cornerView.heightAnchor.constraint(equalToConstant: 160), + ]) + + cornerView.addSubview(teamHeader) + NSLayoutConstraint.activate([ + teamHeader.leftAnchor.constraint(equalTo: cornerView.leftAnchor, constant: 16), + teamHeader.topAnchor.constraint(equalTo: cornerView.topAnchor, constant: 16), + teamHeader.widthAnchor.constraint(equalToConstant: 42), + teamHeader.heightAnchor.constraint(equalToConstant: 42), + ]) + if let url = viewmodel.teamInfoModel?.team?.avatarUrl { + print("icon url : ", url) + teamHeader.sd_setImage(with: URL(string: url), completed: nil) + } else { + if let tid = teamId { + if let name = viewmodel.teamInfoModel?.team?.getShowName() { + teamHeader.setTitle(name) + } + teamHeader.backgroundColor = UIColor.colorWithString(string: "\(tid)") + } + } + + teamNameLabel.text = viewmodel.teamInfoModel?.team?.getShowName() + + cornerView.addSubview(teamNameLabel) + NSLayoutConstraint.activate([ + teamNameLabel.leftAnchor.constraint(equalTo: teamHeader.rightAnchor, constant: 11), + teamNameLabel.centerYAnchor.constraint(equalTo: teamHeader.centerYAnchor), + teamNameLabel.rightAnchor.constraint(equalTo: cornerView.rightAnchor, constant: -34), + ]) + + let arrow = UIImageView() + arrow.translatesAutoresizingMaskIntoConstraints = false + arrow.image = coreLoader.loadImage("arrowRight") + cornerView.addSubview(arrow) + NSLayoutConstraint.activate([ + arrow.centerYAnchor.constraint(equalTo: teamHeader.centerYAnchor), + arrow.rightAnchor.constraint(equalTo: cornerView.rightAnchor, constant: -16), + ]) + + let line = UIView() + line.translatesAutoresizingMaskIntoConstraints = false + line.backgroundColor = NEConstant.hexRGB(0xF5F8FC) + cornerView.addSubview(line) + NSLayoutConstraint.activate([ + line.heightAnchor.constraint(equalToConstant: 1.0), + line.rightAnchor.constraint(equalTo: cornerView.rightAnchor), + line.leftAnchor.constraint(equalTo: cornerView.leftAnchor, constant: 16.0), + line.topAnchor.constraint(equalTo: teamHeader.bottomAnchor, constant: 12.0), + ]) + + let memberLabel = UILabel() + cornerView.addSubview(memberLabel) + memberLabel.translatesAutoresizingMaskIntoConstraints = false + memberLabel.textColor = NEConstant.hexRGB(0x333333) + memberLabel.font = NEConstant.defaultTextFont(16.0) + cornerView.addSubview(memberLabel) + NSLayoutConstraint.activate([ + memberLabel.leftAnchor.constraint(equalTo: line.leftAnchor), + memberLabel.topAnchor.constraint(equalTo: line.bottomAnchor, constant: 12), + ]) + + if teamSettingType == .Senior { + memberLabel.text = localizable("group_memmber") + } else { + memberLabel.text = localizable("discuss_mebmer") + } + + let memberArrow = UIImageView() + cornerView.addSubview(memberArrow) + memberArrow.translatesAutoresizingMaskIntoConstraints = false + memberArrow.image = coreLoader.loadImage("arrowRight") + NSLayoutConstraint.activate([ + memberArrow.rightAnchor.constraint(equalTo: arrow.rightAnchor), + memberArrow.centerYAnchor.constraint(equalTo: memberLabel.centerYAnchor), + ]) + + let memberListBtn = UIButton() + cornerView.addSubview(memberListBtn) + memberListBtn.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + memberListBtn.leftAnchor.constraint(equalTo: memberLabel.leftAnchor), + memberListBtn.rightAnchor.constraint(equalTo: memberArrow.rightAnchor), + memberListBtn.centerYAnchor.constraint(equalTo: memberLabel.centerYAnchor), + memberListBtn.heightAnchor.constraint(equalToConstant: 40), + ]) + memberListBtn.addTarget(self, action: #selector(toMemberList), for: .touchUpInside) + + cornerView.addSubview(memberCountLabel) + NSLayoutConstraint.activate([ + memberCountLabel.rightAnchor.constraint(equalTo: memberArrow.leftAnchor, constant: -2), + memberCountLabel.centerYAnchor.constraint(equalTo: memberArrow.centerYAnchor), + ]) + memberCountLabel.text = "\(viewmodel.teamInfoModel?.team?.memberNumber ?? 0)" + + cornerView.addSubview(addBtn) + addBtnWidth = addBtn.widthAnchor.constraint(equalToConstant: 32) + addBtnWidth?.isActive = true + addBtnLeftMargin = addBtn.leftAnchor.constraint(equalTo: cornerView.leftAnchor, constant: 16.0) + NSLayoutConstraint.activate([ + addBtnLeftMargin!, + addBtn.topAnchor.constraint(equalTo: memberLabel.bottomAnchor, constant: 12), + ]) + addBtn.addTarget(self, action: #selector(addUser), for: .touchUpInside) + + if viewmodel.isNormalTeam() == false, viewmodel.isOwner() == false, + let inviteMode = viewmodel.teamInfoModel?.team?.inviteMode, inviteMode == .manager { + addBtnWidth?.constant = 0 + addBtn.isHidden = true + } + + setupUserInfoCollection(cornerView) + + let infoBtn = UIButton() + infoBtn.translatesAutoresizingMaskIntoConstraints = false + cornerView.addSubview(infoBtn) + NSLayoutConstraint.activate([ + infoBtn.leftAnchor.constraint(equalTo: teamHeader.leftAnchor), + infoBtn.topAnchor.constraint(equalTo: teamHeader.topAnchor), + infoBtn.bottomAnchor.constraint(equalTo: teamHeader.bottomAnchor), + infoBtn.rightAnchor.constraint(equalTo: arrow.rightAnchor), + ]) + infoBtn.addTarget(self, action: #selector(toInfoView), for: .touchUpInside) + + return back + } + + override open func checkoutAddShowOrHide() { + if viewmodel.isNormalTeam() == false, viewmodel.isOwner() == false, + let inviteMode = viewmodel.teamInfoModel?.team?.inviteMode, inviteMode == .manager { + return + } + if viewmodel.teamInfoModel?.team?.level == viewmodel.teamInfoModel?.team?.memberNumber { + addBtn.isHidden = true + addBtnWidth?.constant = 0 + addBtnLeftMargin?.constant = 0 + } else { + addBtn.isHidden = false + addBtnWidth?.constant = 36.0 + addBtnLeftMargin?.constant = 16 + } + } + + override open func getFooterView() -> UIView? { + guard let title = getBottomText() else { + return nil + } + let footer = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 64.0)) + let button = UIButton() + button.translatesAutoresizingMaskIntoConstraints = false + footer.addSubview(button) + button.backgroundColor = .white + button.clipsToBounds = true + button.setTitleColor(NEConstant.hexRGB(0xE6605C), for: .normal) + button.titleLabel?.font = NEConstant.defaultTextFont(16.0) + button.setTitle(title, for: .normal) + button.addTarget(self, action: #selector(removeTeamForMyself), for: .touchUpInside) + button.layer.cornerRadius = 8.0 + NSLayoutConstraint.activate([ + button.leftAnchor.constraint(equalTo: footer.leftAnchor, constant: 20), + button.rightAnchor.constraint(equalTo: footer.rightAnchor, constant: -20), + button.topAnchor.constraint(equalTo: footer.topAnchor, constant: 12), + button.heightAnchor.constraint(equalToConstant: 40), + ]) + return footer + } + + override open func setupUserInfoCollection(_ cornerView: UIView) { + cornerView.addSubview(userinfoCollection) + NSLayoutConstraint.activate([ + userinfoCollection.leftAnchor.constraint(equalTo: addBtn.rightAnchor, constant: 15), + userinfoCollection.centerYAnchor.constraint(equalTo: addBtn.centerYAnchor), + userinfoCollection.rightAnchor.constraint( + equalTo: cornerView.rightAnchor, + constant: -15 + ), + userinfoCollection.heightAnchor.constraint(equalToConstant: 32), + ]) + + userinfoCollection.register( + TeamUserCell.self, + forCellWithReuseIdentifier: "\(TeamUserCell.self)" + ) + } + + // MARK: objc 方法 + + override open func toInfoView() { + let info = TeamInfoViewController() + info.team = viewmodel.teamInfoModel?.team + navigationController?.pushViewController(info, animated: true) + } + + override open func didClickChangeNick() { + let nick = TeamNameViewController() + nick.type = .NickName + nick.team = viewmodel.teamInfoModel?.team + nick.teamMember = viewmodel.memberInTeam + navigationController?.pushViewController(nick, animated: true) + } + + override open func didClickHistoryMessage() { + guard let tid = teamId else { + return + } + Router.shared.use( + SearchMessageRouter, + parameters: ["nav": navigationController as Any, "teamId": tid], + closure: nil + ) + } + + override open func collectionView(_ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + if let cell = collectionView.dequeueReusableCell( + withReuseIdentifier: "\(TeamUserCell.self)", + for: indexPath + ) as? TeamUserCell { + if let user = viewmodel.teamInfoModel?.users[indexPath.row] { + cell.user = user + } + return cell + } + return UICollectionViewCell() + } + + override open func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + sizeForItemAt indexPath: IndexPath) -> CGSize { + CGSize(width: 47.0, height: 32) + } + + override open func toMemberList() { + let memberController = TeamMembersController(viewmodel: viewmodel) + memberController.datas = viewmodel.teamInfoModel?.users + if teamSettingType == .Senior { + memberController.isSenior = true + } + memberController.ownerId = viewmodel.teamInfoModel?.team?.owner + navigationController?.pushViewController(memberController, animated: true) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/NormalUI/NormalTeamRouter.swift b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/NormalTeamRouter.swift new file mode 100644 index 00000000..110cdaf0 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/NormalUI/NormalTeamRouter.swift @@ -0,0 +1,32 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import NECoreKit +import NECoreIMKit +import NIMSDK + +public extension TeamRouter { + static func register() { + registerCommon(icUrls: iconUrls) + + Router.shared.register(TeamSettingViewRouter) { param in + let nav = param["nav"] as? UINavigationController + let teamId = param["teamid"] as? String + let teamSetting = TeamSettingViewController() + teamSetting.teamId = teamId + nav?.pushViewController(teamSetting, animated: true) + } + + Router.shared.register(SearchMessageRouter) { param in + + let nav = param["nav"] as? UINavigationController + if let tid = param["teamId"] as? String { + let session = NIMSession(tid, type: .team) + let searchMsgCtrl = TeamHistoryMessageController(session: session) + nav?.pushViewController(searchMsgCtrl, animated: true) + } + } + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/Model/SettingCellModel.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/Model/SettingCellModel.swift index dbaa8807..b901d018 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/Model/SettingCellModel.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/Model/SettingCellModel.swift @@ -16,6 +16,7 @@ public enum SettingCellType: Int { case SettingSubtitleCustomCell } +@objcMembers public class SettingCellModel: NSObject { public typealias SwitchChangeCompletion = (Bool) -> Void public typealias CellClick = () -> Void diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/TeamHistoryMessageController.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/NEBaseTeamHistoryMessageController.swift similarity index 66% rename from NETeamUIKit/NETeamUIKit/Classes/Setting/TeamHistoryMessageController.swift rename to NETeamUIKit/NETeamUIKit/Classes/Setting/NEBaseTeamHistoryMessageController.swift index 2697d836..df172b13 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/TeamHistoryMessageController.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/NEBaseTeamHistoryMessageController.swift @@ -7,50 +7,33 @@ import UIKit import NIMSDK @objcMembers -public class TeamHistoryMessageController: NEBaseViewController, UITextFieldDelegate, +open class NEBaseTeamHistoryMessageController: NEBaseViewController, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource { - private let viewmodel = TeamSettingViewModel() - private var teamSession: NIMSession? - private var searchStr = "" - private var tag = "TeamHistoryMessageController" + public let viewmodel = TeamSettingViewModel() + public var teamSession: NIMSession? + public var searchStr = "" + var tag = "TeamHistoryMessageController" public init(session: NIMSession?) { super.init(nibName: nil, bundle: nil) teamSession = session } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - override public func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() setupSubviews() initialConfig() } - func setupSubviews() { + open func setupSubviews() { view.addSubview(tableView) view.addSubview(searchTextField) view.addSubview(emptyView) - NSLayoutConstraint.activate([ - searchTextField.topAnchor.constraint( - equalTo: view.topAnchor, - constant: NEConstant.navigationHeight + NEConstant.statusBarHeight + 20 - ), - searchTextField.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20), - searchTextField.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), - searchTextField.heightAnchor.constraint(equalToConstant: 32), - ]) - - NSLayoutConstraint.activate([ - tableView.rightAnchor.constraint(equalTo: view.rightAnchor), - tableView.leftAnchor.constraint(equalTo: view.leftAnchor), - tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), - tableView.topAnchor.constraint(equalTo: searchTextField.bottomAnchor, constant: 20), - ]) - NSLayoutConstraint.activate([ emptyView.rightAnchor.constraint(equalTo: tableView.rightAnchor), emptyView.leftAnchor.constraint(equalTo: tableView.leftAnchor), @@ -59,21 +42,22 @@ public class TeamHistoryMessageController: NEBaseViewController, UITextFieldDele ]) } - func initialConfig() { + open func initialConfig() { title = localizable("historical_record") } // MARK: lazy method - private lazy var tableView: UITableView = { + public lazy var tableView: UITableView = { let tableView = UITableView(frame: .zero, style: .plain) tableView.translatesAutoresizingMaskIntoConstraints = false tableView.separatorStyle = .none + tableView.keyboardDismissMode = .onDrag tableView.delegate = self tableView.dataSource = self tableView.register( - HistoryMessageCell.self, - forCellReuseIdentifier: "\(NSStringFromClass(HistoryMessageCell.self))" + NEBaseHistoryMessageCell.self, + forCellReuseIdentifier: "\(NSStringFromClass(NEBaseHistoryMessageCell.self))" ) tableView.rowHeight = 65 tableView.backgroundColor = .white @@ -82,7 +66,7 @@ public class TeamHistoryMessageController: NEBaseViewController, UITextFieldDele return tableView }() - private lazy var searchTextField: SearchTextField = { + public lazy var searchTextField: SearchTextField = { let textField = SearchTextField() let leftImageView = UIImageView(image: coreLoader.loadImage("search_icon")) textField.contentMode = .center @@ -94,7 +78,7 @@ public class TeamHistoryMessageController: NEBaseViewController, UITextFieldDele textField.translatesAutoresizingMaskIntoConstraints = false textField.layer.cornerRadius = 8 textField.backgroundColor = UIColor(hexString: "0xF2F4F5") - textField.clearButtonMode = .whileEditing + textField.clearButtonMode = .always textField.returnKeyType = .search textField.addTarget(self, action: #selector(searchTextFieldChange), for: .editingChanged) textField.delegate = self @@ -102,7 +86,7 @@ public class TeamHistoryMessageController: NEBaseViewController, UITextFieldDele }() - private lazy var emptyView: NEEmptyDataView = { + public lazy var emptyView: NEEmptyDataView = { let view = NEEmptyDataView( imageName: "emptyView", content: localizable("no_search_results"), @@ -126,7 +110,7 @@ public class TeamHistoryMessageController: NEBaseViewController, UITextFieldDele // MARK: UITextFieldDelegate - public func textFieldShouldReturn(_ textField: UITextField) -> Bool { + open func textFieldShouldReturn(_ textField: UITextField) -> Bool { guard let searchText = textField.text else { return false } @@ -165,23 +149,16 @@ public class TeamHistoryMessageController: NEBaseViewController, UITextFieldDele // MARK: UITableViewDelegate, UITableViewDataSource - public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { viewmodel.searchResultInfos?.count ?? 0 } - public func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell( - withIdentifier: "\(NSStringFromClass(HistoryMessageCell.self))", - for: indexPath - ) as! HistoryMessageCell - let cellModel = viewmodel.searchResultInfos?[indexPath.row] - cell.searchText = searchStr - cell.configData(message: cellModel) - return cell + open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + UITableViewCell() } - public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let cellModel = viewmodel.searchResultInfos?[indexPath.row] if cellModel?.imMessage?.session?.sessionType == .team { if let sid = cellModel?.imMessage?.session?.sessionId, diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/TeamMembersController.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/NEBaseTeamMembersController.swift similarity index 68% rename from NETeamUIKit/NETeamUIKit/Classes/Setting/TeamMembersController.swift rename to NETeamUIKit/NETeamUIKit/Classes/Setting/NEBaseTeamMembersController.swift index 48f7d03a..eccc9f32 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/TeamMembersController.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/NEBaseTeamMembersController.swift @@ -4,37 +4,38 @@ // found in the LICENSE file. import UIKit -import NETeamKit import NECoreKit @objcMembers -public class TeamMembersController: NEBaseViewController, UITableViewDelegate, +open class NEBaseTeamMembersController: NEBaseViewController, UITableViewDelegate, UITableViewDataSource { - var viewmodel: TeamSettingViewModel? + public var viewmodel: TeamSettingViewModel? - var datas: [TeamMemberInfoModel]? + public var datas: [TeamMemberInfoModel]? - var ownerId: String? + public var ownerId: String? - var isSenior = false + public var isSenior = false - var searchDatas = [TeamMemberInfoModel]() + public var searchDatas = [TeamMemberInfoModel]() - lazy var searchTextField: UITextField = { + public let back = UIView() + + public lazy var searchTextField: UITextField = { let field = UITextField() field.translatesAutoresizingMaskIntoConstraints = false field.placeholder = localizable("search_friend") + field.clearButtonMode = .always field.textColor = .ne_greyText field.font = UIFont.systemFont(ofSize: 14.0) field.backgroundColor = UIColor.ne_backcolor return field }() - lazy var contentTable: UITableView = { + public lazy var contentTable: UITableView = { let table = UITableView() table.translatesAutoresizingMaskIntoConstraints = false -// table.backgroundColor = NEConstant.hexRGB(0xF1F1F6) - table.backgroundColor = .white + table.backgroundColor = .clear table.dataSource = self table.delegate = self table.separatorColor = .clear @@ -47,20 +48,26 @@ public class TeamMembersController: NEBaseViewController, UITableViewDelegate, table.sectionHeaderTopPadding = 0.0 } table.keyboardDismissMode = .onDrag -// table.bounces = false return table }() + lazy var emptyView: NEEmptyDataView = { + let view = NEEmptyDataView(imageName: "user_empty", content: localizable("no_result"), frame: .zero) + view.translatesAutoresizingMaskIntoConstraints = false + view.isHidden = true + return view + }() + init(viewmodel: TeamSettingViewModel? = nil) { super.init(nibName: nil, bundle: nil) self.viewmodel = viewmodel } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - override public func viewWillAppear(_ animated: Bool) { + override open func viewWillAppear(_ animated: Bool) { viewmodel?.getTeamInfo(viewmodel?.teamInfoModel?.team?.teamId ?? "") { [weak self] error in if let err = error as? NSError { if err.code == 803 || err.code == 1 { @@ -75,47 +82,32 @@ public class TeamMembersController: NEBaseViewController, UITableViewDelegate, } } - override public func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. setupUI() } - func setupUI() { + open func setupUI() { if isSenior { title = localizable("group_memmber") } else { title = localizable("discuss_mebmer") } - let back = UIView() - back.backgroundColor = .ne_backcolor + back.backgroundColor = .clear back.translatesAutoresizingMaskIntoConstraints = false back.clipsToBounds = true back.layer.cornerRadius = 4.0 view.addSubview(back) - - if #available(iOS 11.0, *) { - NSLayoutConstraint.activate([ - back.topAnchor.constraint( - equalTo: view.safeAreaLayoutGuide.topAnchor, - constant: 4.0 - ), - back.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20), - back.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), - back.heightAnchor.constraint(equalToConstant: 32), - ]) - } else { - // Fallback on earlier versions - NSLayoutConstraint.activate([ - back.topAnchor.constraint(equalTo: view.topAnchor, constant: 4.0), - back.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20), - back.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), - back.heightAnchor.constraint(equalToConstant: 32), - ]) - } + NSLayoutConstraint.activate([ + back.topAnchor.constraint(equalTo: view.topAnchor, constant: 4.0 + NEConstant.navigationAndStatusHeight), + back.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20), + back.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), + back.heightAnchor.constraint(equalToConstant: 32), + ]) let searchIcon = UIImageView() searchIcon.image = coreLoader.loadImage("search_icon") @@ -142,7 +134,15 @@ public class TeamMembersController: NEBaseViewController, UITableViewDelegate, contentTable.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) - contentTable.register(TeamMemberCell.self, forCellReuseIdentifier: "\(TeamMemberCell.self)") + contentTable.register(NEBaseTeamMemberCell.self, forCellReuseIdentifier: "\(NEBaseTeamMemberCell.self)") + + view.addSubview(emptyView) + NSLayoutConstraint.activate([ + emptyView.leftAnchor.constraint(equalTo: contentTable.leftAnchor), + emptyView.rightAnchor.constraint(equalTo: contentTable.rightAnchor), + emptyView.topAnchor.constraint(equalTo: contentTable.topAnchor), + emptyView.bottomAnchor.constraint(equalTo: contentTable.bottomAnchor), + ]) NotificationCenter.default.addObserver( self, @@ -186,6 +186,9 @@ public class TeamMembersController: NEBaseViewController, UITableViewDelegate, searchDatas.append(model) } } + emptyView.isHidden = searchDatas.count > 0 + } else { + emptyView.isHidden = true } contentTable.reloadData() } @@ -203,19 +206,19 @@ public class TeamMembersController: NEBaseViewController, UITableViewDelegate, // MARK: UITableViewDelegate, UITableViewDataSource - public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if let text = searchTextField.text, text.count > 0 { return searchDatas.count } return datas?.count ?? 0 } - public func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { + open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { if let cell = tableView.dequeueReusableCell( - withIdentifier: "\(TeamMemberCell.self)", + withIdentifier: "\(NEBaseTeamMemberCell.self)", for: indexPath - ) as? TeamMemberCell { + ) as? NEBaseTeamMemberCell { if let model = getRealModel(indexPath.row) { cell.configure(model) cell.ownerLabel.isHidden = !isOwner(model.nimUser?.userId) @@ -225,14 +228,14 @@ public class TeamMembersController: NEBaseViewController, UITableViewDelegate, return UITableViewCell() } - public func tableView(_ tableView: UITableView, - heightForRowAt indexPath: IndexPath) -> CGFloat { + open func tableView(_ tableView: UITableView, + heightForRowAt indexPath: IndexPath) -> CGFloat { 62.0 } - public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if let model = getRealModel(indexPath.row), let user = model.nimUser { - if IMKitEngine.instance.isMySelf(user.userId) { + if IMKitClient.instance.isMySelf(user.userId) { Router.shared.use( MeSettingRouter, parameters: ["nav": navigationController as Any], @@ -240,15 +243,11 @@ public class TeamMembersController: NEBaseViewController, UITableViewDelegate, ) } else { if let uid = user.userId { - UserInfoProvider.shared.fetchUserInfo([uid]) { [weak self] error, users in - if let u = users?.first { - Router.shared.use( - ContactUserInfoPageRouter, - parameters: ["nav": self?.navigationController as Any, "nim_user": u], - closure: nil - ) - } - } + Router.shared.use( + ContactUserInfoPageRouter, + parameters: ["nav": navigationController as Any, "uid": uid], + closure: nil + ) } } } diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/TeamInfoViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/TeamInfoViewController.swift deleted file mode 100644 index 6d167e69..00000000 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/TeamInfoViewController.swift +++ /dev/null @@ -1,126 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NIMSDK - -@objcMembers -public class TeamInfoViewController: NEBaseViewController, UITableViewDelegate, - UITableViewDataSource { - let viewmodel = TeamInfoViewModel() - - var team: NIMTeam? - - public var cellClassDic = [ - SettingCellType.SettingArrowCell.rawValue: TeamArrowSettingCell.self, - SettingCellType.SettingHeaderCell.rawValue: TeamSettingHeaderCell.self, - ] - - lazy var contentTable: UITableView = { - let table = UITableView() - table.translatesAutoresizingMaskIntoConstraints = false - table.backgroundColor = NEConstant.hexRGB(0xF1F1F6) - table.dataSource = self - table.delegate = self - table.separatorColor = .clear - table.separatorStyle = .none - table.sectionHeaderHeight = 12.0 - table - .tableFooterView = - UIView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 12)) - return table - }() - - override public func viewDidLoad() { - super.viewDidLoad() - - // Do any additional setup after loading the view. - if let type = team?.type, type == .normal { - title = localizable("discuss_info") - } else { - title = localizable("group_info") - } - viewmodel.getData(team) - setupUI() - } - - func setupUI() { - view.backgroundColor = NEConstant.hexRGB(0xF1F1F6) - view.addSubview(contentTable) - NSLayoutConstraint.activate([ - contentTable.leftAnchor.constraint(equalTo: view.leftAnchor), - contentTable.rightAnchor.constraint(equalTo: view.rightAnchor), - contentTable.topAnchor.constraint(equalTo: view.topAnchor), - contentTable.bottomAnchor.constraint(equalTo: view.bottomAnchor), - ]) - cellClassDic.forEach { (key: Int, value: BaseTeamSettingCell.Type) in - contentTable.register(value, forCellReuseIdentifier: "\(key)") - } - } - - /* - // MARK: - Navigation - - // In a storyboard-based application, you will often want to do a little preparation before navigation - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - // Get the new view controller using segue.destination. - // Pass the selected object to the new view controller. - } - */ - - // MARK: UITableViewDelegate, UITableViewDataSource - - public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - viewmodel.cellDatas.count - } - - public func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let model = viewmodel.cellDatas[indexPath.row] - if let cell = tableView.dequeueReusableCell( - withIdentifier: "\(model.type)", - for: indexPath - ) as? BaseTeamSettingCell { - cell.configure(model) - return cell - } - return UITableViewCell() - } - - public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - if indexPath.row == 0 { - let avatar = TeamAvatarViewController() - avatar.team = team - weak var weakSelf = self - avatar.block = { - if let t = weakSelf?.team { - weakSelf?.viewmodel.getData(t) - weakSelf?.contentTable.reloadData() - } - } - navigationController?.pushViewController(avatar, animated: true) - - } else if indexPath.row == 1 { - let nameController = TeamNameViewController() - nameController.team = team - navigationController?.pushViewController(nameController, animated: true) - } else if indexPath.row == 2 { - let intr = TeamIntroduceViewController() - intr.team = team - navigationController?.pushViewController(intr, animated: true) - } - } - - public func tableView(_ tableView: UITableView, - heightForRowAt indexPath: IndexPath) -> CGFloat { - let model = viewmodel.cellDatas[indexPath.row] - return model.rowHeight - } - - public func tableView(_ tableView: UITableView, - heightForHeaderInSection section: Int) -> CGFloat { - 12.0 - } -} diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/TeamIntroduceViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/TeamIntroduceViewController.swift deleted file mode 100644 index fd2364ae..00000000 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/TeamIntroduceViewController.swift +++ /dev/null @@ -1,178 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NECommonKit -import NIMSDK -import NETeamKit - -@objcMembers -public class TeamIntroduceViewController: NEBaseViewController, UITextViewDelegate { -// typealias SaveCompletion = () -> Void -// -// var block: SaveCompletion? - - var team: NIMTeam? - let textLimit = 100 - let repo = TeamRepo() - - lazy var textView: UITextView = { - let text = UITextView() - text.translatesAutoresizingMaskIntoConstraints = false - text.textColor = NEConstant.hexRGB(0x333333) - text.font = NEConstant.defaultTextFont(14.0) - text.delegate = self - text.textContainerInset = UIEdgeInsets.zero - text.layoutManager.allowsNonContiguousLayout = false - return text - }() - - lazy var countLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.textColor = NEConstant.hexRGB(0xB3B7BC) - label.font = NEConstant.defaultTextFont(12.0) - return label - }() - - override public func viewDidLoad() { - super.viewDidLoad() - - // Do any additional setup after loading the view. - setupUI() - } - - func setupUI() { - addRightAction(localizable("save"), #selector(saveIntr), self) - - if let type = team?.type, type == .advanced { - title = localizable("team_intr") - } else { - title = localizable("discuss_introduce") - } - - view.backgroundColor = NEConstant.hexRGB(0xF1F1F6) - let backView = UIView() - backView.backgroundColor = .white - backView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(backView) - backView.clipsToBounds = false - backView.layer.cornerRadius = 8.0 - if #available(iOS 11.0, *) { - NSLayoutConstraint.activate([ - backView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20), - backView.topAnchor.constraint( - equalTo: view.safeAreaLayoutGuide.topAnchor, - constant: 12.0 - ), - backView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), - backView.heightAnchor.constraint(equalToConstant: 170), - ]) - } else { - NSLayoutConstraint.activate([ - backView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20), - backView.topAnchor.constraint(equalTo: view.topAnchor, constant: 12.0), - backView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), - backView.heightAnchor.constraint(equalToConstant: 170), - ]) - } - - backView.addSubview(textView) - NSLayoutConstraint.activate([ - textView.leftAnchor.constraint(equalTo: backView.leftAnchor, constant: 16.0), - textView.rightAnchor.constraint(equalTo: backView.rightAnchor, constant: -16.0), - textView.topAnchor.constraint(equalTo: backView.topAnchor, constant: 16.0), - textView.heightAnchor.constraint(equalToConstant: 120), - ]) - - textView.text = team?.intro - - backView.addSubview(countLabel) - NSLayoutConstraint.activate([ - countLabel.rightAnchor.constraint(equalTo: backView.rightAnchor, constant: -16), - countLabel.bottomAnchor.constraint(equalTo: backView.bottomAnchor, constant: -8.0), - ]) - - if let intr = team?.intro { - countLabel.text = "\(intr.count)/\(textLimit)" - } else { - countLabel.text = "0/\(textLimit)" - } - - if changePermission() == false { - textView.isEditable = false - rightNavBtn.isHidden = true - } - } - - func disableSubmit() { - rightNavBtn.setTitleColor(NEConstant.hexRGBAlpha(0x337EFF, 0.5), for: .normal) - rightNavBtn.isEnabled = false - } - - func enableSubmit() { - rightNavBtn.setTitleColor(NEConstant.hexRGB(0x337EFF), for: .normal) - rightNavBtn.isEnabled = true - } - - /* - // MARK: - Navigation - - // In a storyboard-based application, you will often want to do a little preparation before navigation - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - // Get the new view controller using segue.destination. - // Pass the selected object to the new view controller. - } - */ - - func changePermission() -> Bool { - if let ownerId = team?.owner, IMKitEngine.instance.isMySelf(ownerId) { - return true - } - if let mode = team?.updateInfoMode, mode == .all { - return true - } - return false - } - - func saveIntr() { - textView.resignFirstResponder() - if let teamid = team?.teamId { - let text = textView.text ?? "" - weak var weakSelf = self - view.makeToastActivity(.center) - repo.updateTeamIntroduce(text, teamid) { error in - NELog.infoLog( - ModuleName + " " + self.className(), - desc: "CALLBACK updateTeamIntroduce " + (error?.localizedDescription ?? "no error") - ) - weakSelf?.view.hideToastActivity() - if let err = error { - weakSelf?.showToast(err.localizedDescription) - } else { - weakSelf?.team?.intro = text - weakSelf?.navigationController?.popViewController(animated: true) - } - } - } - } - - // MARK: UITextViewDelegate - - public func textViewDidChange(_ textView: UITextView) { - if let _ = textView.markedTextRange { - return - } - if var text = textView.text { - if let lang = textView.textInputMode?.primaryLanguage, lang == "zh-Hans" { - if text.count > textLimit { - text = String(text.prefix(textLimit)) - textView.text = String(text) - } - countLabel.text = "\(text.count)/\(textLimit)" - } - } - } -} diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/TeamSettingViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/TeamSettingViewController.swift deleted file mode 100644 index 754d2c64..00000000 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/TeamSettingViewController.swift +++ /dev/null @@ -1,833 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit -import NECommonUIKit -import NECoreIMKit -import NIMSDK - -@objc -public enum TeamSettingType: Int { - case Discuss = 0 - case Senior = 1 -} - -@objcMembers -public class TeamSettingViewController: NEBaseViewController, UICollectionViewDelegate, - UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UITableViewDataSource, - UITableViewDelegate { - public let viewmodel = TeamSettingViewModel() - - public var teamId: String? - - var addBtnWidth: NSLayoutConstraint? - - public var teamSettingType: TeamSettingType = .Discuss - - public var isSeniorDiscuss = false // 是否是高级群扩展的讨论组 - - private let className = "TeamSettingViewController" - - public var cellClassDic = [ - SettingCellType.SettingArrowCell.rawValue: TeamArrowSettingCell.self, - SettingCellType.SettingSwitchCell.rawValue: TeamSettingSwitchCell.self, - SettingCellType.SettingSelectCell.rawValue: TeamSettingSelectCell.self, - ] - - lazy var contentTable: UITableView = { - let table = UITableView() - table.translatesAutoresizingMaskIntoConstraints = false - table.backgroundColor = NEConstant.hexRGB(0xF1F1F6) - table.dataSource = self - table.delegate = self - table.separatorColor = .clear - table.separatorStyle = .none - table.sectionHeaderHeight = 12.0 - table - .tableFooterView = - UIView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 12)) - if #available(iOS 15.0, *) { - table.sectionHeaderTopPadding = 0.0 - } - return table - }() - - lazy var teamHeader: NEUserHeaderView = { - let imageView = NEUserHeaderView(frame: .zero) - imageView.translatesAutoresizingMaskIntoConstraints = false - imageView.clipsToBounds = true - imageView.titleLabel.font = NEConstant.defaultTextFont(16.0) - imageView.layer.cornerRadius = 21.0 - return imageView - }() - - lazy var teamNameLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.font = NEConstant.defaultTextFont(16.0) - label.textColor = NEConstant.hexRGB(0x333333) - return label - }() - - lazy var memberCountLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.font = NEConstant.defaultTextFont(16.0) - label.textColor = NEConstant.hexRGB(0x999999) - return label - }() - - lazy var userinfoCollection: UICollectionView = { - let flow = UICollectionViewFlowLayout() - flow.scrollDirection = .horizontal - flow.minimumLineSpacing = 0 - flow.minimumInteritemSpacing = 0 - let collection = UICollectionView(frame: .zero, collectionViewLayout: flow) - collection.translatesAutoresizingMaskIntoConstraints = false - collection.delegate = self - collection.dataSource = self - collection.backgroundColor = .clear - collection.showsHorizontalScrollIndicator = false - return collection - }() - - lazy var addBtn: ExpandButton = { - let button = ExpandButton() - button.translatesAutoresizingMaskIntoConstraints = false - button.setImage(coreLoader.loadImage("add"), for: .normal) - return button - }() - - override public func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - if let model = viewmodel.teamInfoModel { - if let url = model.team?.avatarUrl { - teamHeader.sd_setImage(with: URL(string: url)) - } - if let name = model.team?.teamName { - teamNameLabel.text = name - } - } - } - - override public func viewDidLoad() { - super.viewDidLoad() - - title = localizable("setting") - weak var weakSelf = self - viewmodel.delegate = self - if let tid = teamId { - viewmodel.getTeamInfo(tid) { error in - NELog.infoLog( - ModuleName + " " + self.className, - desc: "CALLBACK getTeamInfo " + (error?.localizedDescription ?? "no error") - ) - if let err = error { - weakSelf?.showToast(err.localizedDescription) - } else { - if let type = weakSelf?.viewmodel.teamInfoModel?.team?.type { - if type == .normal { - weakSelf?.teamSettingType = .Discuss - } else if type == .advanced { - if let custom = weakSelf?.viewmodel.teamInfoModel?.team?.clientCustomInfo, custom.contains(discussTeamKey) { - weakSelf?.teamSettingType = .Discuss - weakSelf?.isSeniorDiscuss = true - } else { - weakSelf?.teamSettingType = .Senior - } - } - } - weakSelf?.contentTable.tableHeaderView = weakSelf?.getHeaderView() - weakSelf?.contentTable.tableFooterView = weakSelf?.getFooterView() - weakSelf?.contentTable.reloadData() - weakSelf?.userinfoCollection.reloadData() - } - } - } - // Do any additional setup after loading the view. - setupUI() - } - - func setupUI() { - view.backgroundColor = NEConstant.hexRGB(0xF1F1F6) - view.addSubview(contentTable) - NSLayoutConstraint.activate([ - contentTable.leftAnchor.constraint(equalTo: view.leftAnchor), - contentTable.rightAnchor.constraint(equalTo: view.rightAnchor), - contentTable.topAnchor.constraint(equalTo: view.topAnchor), - contentTable.bottomAnchor.constraint(equalTo: view.bottomAnchor), - ]) - cellClassDic.forEach { (key: Int, value: BaseTeamSettingCell.Type) in - contentTable.register(value, forCellReuseIdentifier: "\(key)") - } - } - - func getHeaderView() -> UIView { - let back = UIView() - back.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: 172) - let cornerView = UIView() - back.addSubview(cornerView) - cornerView.backgroundColor = .white - cornerView.clipsToBounds = true - cornerView.translatesAutoresizingMaskIntoConstraints = false - cornerView.layer.cornerRadius = 8.0 - NSLayoutConstraint.activate([ - cornerView.leftAnchor.constraint(equalTo: back.leftAnchor, constant: 20), - cornerView.rightAnchor.constraint(equalTo: back.rightAnchor, constant: -20), - cornerView.bottomAnchor.constraint(equalTo: back.bottomAnchor), - cornerView.heightAnchor.constraint(equalToConstant: 160), - ]) - - cornerView.addSubview(teamHeader) - NSLayoutConstraint.activate([ - teamHeader.leftAnchor.constraint(equalTo: cornerView.leftAnchor, constant: 16), - teamHeader.topAnchor.constraint(equalTo: cornerView.topAnchor, constant: 16), - teamHeader.widthAnchor.constraint(equalToConstant: 42), - teamHeader.heightAnchor.constraint(equalToConstant: 42), - ]) - if let url = viewmodel.teamInfoModel?.team?.avatarUrl { - print("icon url : ", url) - teamHeader.sd_setImage(with: URL(string: url), completed: nil) - } else { - if let tid = teamId { - if let name = viewmodel.teamInfoModel?.team?.getShowName() { - teamHeader.setTitle(name) - } - teamHeader.backgroundColor = UIColor.colorWithString(string: "\(tid)") - } - } - - teamNameLabel.text = viewmodel.teamInfoModel?.team?.getShowName() - - cornerView.addSubview(teamNameLabel) - NSLayoutConstraint.activate([ - teamNameLabel.leftAnchor.constraint(equalTo: teamHeader.rightAnchor, constant: 11), - teamNameLabel.centerYAnchor.constraint(equalTo: teamHeader.centerYAnchor), - teamNameLabel.rightAnchor.constraint(equalTo: cornerView.rightAnchor, constant: -34), - ]) - - let arrow = UIImageView() - arrow.translatesAutoresizingMaskIntoConstraints = false - arrow.image = coreLoader.loadImage("arrowRight") - cornerView.addSubview(arrow) - NSLayoutConstraint.activate([ - arrow.centerYAnchor.constraint(equalTo: teamHeader.centerYAnchor), - arrow.rightAnchor.constraint(equalTo: cornerView.rightAnchor, constant: -16), - ]) - - let line = UIView() - line.translatesAutoresizingMaskIntoConstraints = false - line.backgroundColor = NEConstant.hexRGB(0xF5F8FC) - cornerView.addSubview(line) - NSLayoutConstraint.activate([ - line.heightAnchor.constraint(equalToConstant: 1.0), - line.rightAnchor.constraint(equalTo: cornerView.rightAnchor), - line.leftAnchor.constraint(equalTo: cornerView.leftAnchor, constant: 16.0), - line.topAnchor.constraint(equalTo: teamHeader.bottomAnchor, constant: 12.0), - ]) - - let memberLabel = UILabel() - cornerView.addSubview(memberLabel) - memberLabel.translatesAutoresizingMaskIntoConstraints = false - memberLabel.textColor = NEConstant.hexRGB(0x333333) - memberLabel.font = NEConstant.defaultTextFont(16.0) - cornerView.addSubview(memberLabel) - NSLayoutConstraint.activate([ - memberLabel.leftAnchor.constraint(equalTo: line.leftAnchor), - memberLabel.topAnchor.constraint(equalTo: line.bottomAnchor, constant: 12), - ]) - - if teamSettingType == .Senior { - memberLabel.text = localizable("group_memmber") - } else { - memberLabel.text = localizable("discuss_mebmer") - } - - let memberArrow = UIImageView() - cornerView.addSubview(memberArrow) - memberArrow.translatesAutoresizingMaskIntoConstraints = false - memberArrow.image = coreLoader.loadImage("arrowRight") - NSLayoutConstraint.activate([ - memberArrow.rightAnchor.constraint(equalTo: arrow.rightAnchor), - memberArrow.centerYAnchor.constraint(equalTo: memberLabel.centerYAnchor), - ]) - - let memberListBtn = UIButton() - cornerView.addSubview(memberListBtn) - memberListBtn.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - memberListBtn.leftAnchor.constraint(equalTo: memberLabel.leftAnchor), - memberListBtn.rightAnchor.constraint(equalTo: memberArrow.rightAnchor), - memberListBtn.centerYAnchor.constraint(equalTo: memberLabel.centerYAnchor), - memberListBtn.heightAnchor.constraint(equalToConstant: 40), - ]) - memberListBtn.addTarget(self, action: #selector(toMemberList), for: .touchUpInside) - - cornerView.addSubview(memberCountLabel) - NSLayoutConstraint.activate([ - memberCountLabel.rightAnchor.constraint(equalTo: memberArrow.leftAnchor, constant: -2), - memberCountLabel.centerYAnchor.constraint(equalTo: memberArrow.centerYAnchor), - ]) - memberCountLabel.text = "\(viewmodel.teamInfoModel?.team?.memberNumber ?? 0)" - - cornerView.addSubview(addBtn) - addBtnWidth = addBtn.widthAnchor.constraint(equalToConstant: 32) - addBtnWidth?.isActive = true - NSLayoutConstraint.activate([ - addBtn.leftAnchor.constraint(equalTo: line.leftAnchor), - addBtn.topAnchor.constraint(equalTo: memberLabel.bottomAnchor, constant: 12), - ]) - addBtn.addTarget(self, action: #selector(addUser), for: .touchUpInside) - - if viewmodel.isNormalTeam() == false, viewmodel.isOwner() == false, - let inviteMode = viewmodel.teamInfoModel?.team?.inviteMode, inviteMode == .manager { - addBtnWidth?.constant = 0 - addBtn.isHidden = true - } - - setupUserInfoCollection(cornerView) - - let infoBtn = UIButton() - infoBtn.translatesAutoresizingMaskIntoConstraints = false - cornerView.addSubview(infoBtn) - NSLayoutConstraint.activate([ - infoBtn.leftAnchor.constraint(equalTo: teamHeader.leftAnchor), - infoBtn.topAnchor.constraint(equalTo: teamHeader.topAnchor), - infoBtn.bottomAnchor.constraint(equalTo: teamHeader.bottomAnchor), - infoBtn.rightAnchor.constraint(equalTo: arrow.rightAnchor), - ]) - infoBtn.addTarget(self, action: #selector(toInfoView), for: .touchUpInside) - - return back - } - - func getFooterView() -> UIView? { - guard let title = getBottomText() else { - return nil - } - let footer = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 64.0)) - let button = UIButton() - button.translatesAutoresizingMaskIntoConstraints = false - footer.addSubview(button) - button.backgroundColor = .white - button.clipsToBounds = true - button.setTitleColor(NEConstant.hexRGB(0xE6605C), for: .normal) - button.titleLabel?.font = NEConstant.defaultTextFont(16.0) - button.setTitle(title, for: .normal) - button.addTarget(self, action: #selector(removeTeamForMyself), for: .touchUpInside) - button.layer.cornerRadius = 8.0 - NSLayoutConstraint.activate([ - button.leftAnchor.constraint(equalTo: footer.leftAnchor, constant: 20), - button.rightAnchor.constraint(equalTo: footer.rightAnchor, constant: -20), - button.topAnchor.constraint(equalTo: footer.topAnchor, constant: 12), - button.heightAnchor.constraint(equalToConstant: 40), - ]) - return footer - } - - func getBottomText() -> String? { - if teamSettingType == .Discuss { - return localizable("leave_discuss") - } else if teamSettingType == .Senior { - return viewmodel.isOwner() ? localizable("dismiss_team") : localizable("leave_team") - } - return nil - } - - func setupUserInfoCollection(_ cornerView: UIView) { - cornerView.addSubview(userinfoCollection) - NSLayoutConstraint.activate([ - userinfoCollection.leftAnchor.constraint(equalTo: addBtn.rightAnchor, constant: 15), - userinfoCollection.centerYAnchor.constraint(equalTo: addBtn.centerYAnchor), - userinfoCollection.rightAnchor.constraint( - equalTo: cornerView.rightAnchor, - constant: -15 - ), - userinfoCollection.heightAnchor.constraint(equalToConstant: 32), - ]) - - userinfoCollection.register( - TeamUserCell.self, - forCellWithReuseIdentifier: "\(TeamUserCell.self)" - ) - } - - // MARK: objc 方法 - - func addUser() { - weak var weakSelf = self - Router.shared.register(ContactSelectedUsersRouter) { param in - print("addUser weak self ", weakSelf as Any) - if let accids = param["accids"] as? [String], - let tid = self.viewmodel.teamInfoModel?.team?.teamId, - let beInviteMode = self.viewmodel.teamInfoModel?.team?.beInviteMode, - let type = self.viewmodel.teamInfoModel?.team?.type { - if beInviteMode == .noAuth || type == .normal { - self.didAddUserAndRefreshUI(accids, tid) - } else { - self.didAddUser(accids, tid) - } - } - } - var param = [String: Any]() - param["nav"] = navigationController as Any - var filters = Set() - viewmodel.teamInfoModel?.users.forEach { model in - if let uid = model.nimUser?.userId { - filters.insert(uid) - } - } - if filters.count > 0 { - param["filters"] = filters - } - - param["limit"] = 200 - filters.count - Router.shared.use(ContactUserSelectRouter, parameters: param, closure: nil) - } - - func removeTeamForMyself() { - weak var weakSelf = self - if teamSettingType == .Senior { - showAlert(message: viewmodel.isOwner() ? localizable("dissolute_team_chat") : localizable("quit_team_chat")) { - if weakSelf?.viewmodel.isOwner() == true { - weakSelf?.dismissTeam() - } else { - weakSelf?.leaveTeam() - } - } - } else if teamSettingType == .Discuss { - showAlert(message: localizable("quit_discuss_chat")) { - weakSelf?.leaveDiscuss() - } - } - /* - if viewmodel.isOwner(), let type = viewmodel.teamInfoModel?.team?.type, type == .advanced { - showAlert(message: localizable("dissolute_team_chat")) { - weakSelf?.dismissTeam() - } - } else { - if let type = viewmodel.teamInfoModel?.team?.type { - if let custom = viewmodel.teamInfoModel?.team?.clientCustomInfo, type == .normal || (type == .advanced && custom.contains(discussTeamKey)) { - showAlert(message: localizable("quit_discuss_chat")) { - weakSelf?.leveaTeam() - } - }else if type == .advanced { - showAlert(message: localizable("quit_team_chat")) { - weakSelf?.leveaTeam() - } - } - } - } */ - } - - func leaveDiscuss() { - weak var weakSelf = self - if isSeniorDiscuss == true, viewmodel.isOwner() { - view.makeToastActivity(.center) - viewmodel.transferTeamOwner { error in - weakSelf?.view.hideToastActivity() - if let err = error { - weakSelf?.showToast(err.localizedDescription) - } - weakSelf?.navigationController?.popViewController(animated: true) - } - return - } - leaveTeam() - } - - func toInfoView() { - let info = TeamInfoViewController() - info.team = viewmodel.teamInfoModel?.team - navigationController?.pushViewController(info, animated: true) - } - - func toMemberList() { - let memberController = TeamMembersController(viewmodel: viewmodel) - memberController.datas = viewmodel.teamInfoModel?.users - if teamSettingType == .Senior { - memberController.isSenior = true - } - memberController.ownerId = viewmodel.teamInfoModel?.team?.owner - navigationController?.pushViewController(memberController, animated: true) - } - - // MARK: UICollectionViewDelegate, UICollectionViewDataSource,UICollectionViewDelegateFlowLayout - - public func collectionView(_ collectionView: UICollectionView, - numberOfItemsInSection section: Int) -> Int { - print("numberOfItemsInSection ", viewmodel.teamInfoModel?.users.count as Any) - return viewmodel.teamInfoModel?.users.count ?? 0 - } - - public func collectionView(_ collectionView: UICollectionView, - cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - if let cell = collectionView.dequeueReusableCell( - withReuseIdentifier: "\(TeamUserCell.self)", - for: indexPath - ) as? TeamUserCell { - if let user = viewmodel.teamInfoModel?.users[indexPath.row] { - cell.user = user - } - return cell - } - return UICollectionViewCell() - } - - public func collectionView(_ collectionView: UICollectionView, - layout collectionViewLayout: UICollectionViewLayout, - sizeForItemAt indexPath: IndexPath) -> CGSize { - CGSize(width: 47.0, height: 32) - } - - public func collectionView(_ collectionView: UICollectionView, - didSelectItemAt indexPath: IndexPath) { - if let member = viewmodel.teamInfoModel?.users[indexPath.row], - let nimUser = member.nimUser { - if IMKitEngine.instance.isMySelf(nimUser.userId) { - Router.shared.use( - MeSettingRouter, - parameters: ["nav": navigationController as Any], - closure: nil - ) - } else { - if let uid = nimUser.userId { - UserInfoProvider.shared.fetchUserInfo([uid]) { [weak self] error, users in - if let u = users?.first { - Router.shared.use( - ContactUserInfoPageRouter, - parameters: ["nav": self?.navigationController as Any, "user": u], - closure: nil - ) - } - } - } - } - } - } - - // MARK: UITableViewDataSource, UITableViewDelegate - - public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - if viewmodel.sectionData.count > section { - let model = viewmodel.sectionData[section] - return model.cellModels.count - } - return 0 - } - - public func numberOfSections(in tableView: UITableView) -> Int { - viewmodel.sectionData.count - } - - public func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let model = viewmodel.sectionData[indexPath.section].cellModels[indexPath.row] - if let cell = tableView.dequeueReusableCell( - withIdentifier: "\(model.type)", - for: indexPath - ) as? BaseTeamSettingCell { - cell.configure(model) - return cell - } - return UITableViewCell() - } - - public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let model = viewmodel.sectionData[indexPath.section].cellModels[indexPath.row] - if let block = model.cellClick { - block() - } - } - - public func tableView(_ tableView: UITableView, - heightForRowAt indexPath: IndexPath) -> CGFloat { - let model = viewmodel.sectionData[indexPath.section].cellModels[indexPath.row] - return model.rowHeight - } - - public func tableView(_ tableView: UITableView, - heightForHeaderInSection section: Int) -> CGFloat { - if viewmodel.sectionData.count > section { - let model = viewmodel.sectionData[section] - if model.cellModels.count > 0 { - return 12.0 - } - } - return 0 - } - - public func tableView(_ tableView: UITableView, - viewForHeaderInSection section: Int) -> UIView? { - let header = UIView() - header.backgroundColor = NEConstant.hexRGB(0xF1F1F6) - return header - } - - public func tableView(_ tableView: UITableView, - heightForFooterInSection section: Int) -> CGFloat { - if section == viewmodel.sectionData.count - 1 { - return 12.0 - } - return 0 - } -} - -extension TeamSettingViewController { - func didAddUserAndRefreshUI(_ accids: [String], _ tid: String) { - weak var weakSelf = self - view.makeToastActivity(.center) - viewmodel.repo.inviteUser(accids, tid, nil, nil) { error, members in - if let err = error { - weakSelf?.view.hideToastActivity() - weakSelf?.showToast(err.localizedDescription) - } else { - print("add users success : ", members as Any) - if let ms = members, let model = weakSelf?.viewmodel.teamInfoModel { - weakSelf?.viewmodel.repo.splitGroupMember(ms, model) { error, team in - weakSelf?.view.hideToastActivity() - if let e = error { - weakSelf?.showToast(e.localizedDescription) - } else { - weakSelf?.refreshMemberCount() - weakSelf?.userinfoCollection.reloadData() - } - } - } else { - weakSelf?.view.hideToastActivity() - } - } - } - } - - func didAddUser(_ accids: [String], _ tid: String) { - weak var weakSelf = self - view.makeToastActivity(.center) - viewmodel.repo.inviteUser(accids, tid, nil, nil) { error, members in - NELog.infoLog( - ModuleName + " " + self.className(), - desc: "CALLBACK inviteUser " + (error?.localizedDescription ?? "no error") - ) - weakSelf?.view.hideToastActivity() - if let err = error { - weakSelf?.showToast(err.localizedDescription) - } else { - weakSelf?.showToast(localizable("invite_has_send")) - } - } - } - - func dismissTeam() { - if let tid = teamId { - weak var weakSelf = self - view.makeToastActivity(.center) - viewmodel.dismissTeam(tid) { error in - NELog.infoLog( - ModuleName + " " + self.className, - desc: "CALLBACK dismissTeam " + (error?.localizedDescription ?? "no error") - ) - weakSelf?.view.hideToastActivity() - if let err = error { - weakSelf?.showToast(err.localizedDescription) - } - weakSelf?.navigationController?.popViewController(animated: true) - } - } - } - - func refreshMemberCount() { - if let count = viewmodel.teamInfoModel?.users.count { - memberCountLabel.text = "\(count)" - } - } - - func leaveTeam() { - if let tid = teamId { - // 需要先于 SDK 回调进行通知 - NotificationCenter.default.post(name: NotificationName.leaveTeamBySelf, object: true) - - view.makeToastActivity(.center) - viewmodel.quitTeam(tid) { [weak self] error in - NELog.infoLog( - ModuleName + " " + (self?.className ?? "TeamSettingViewController"), - desc: "CALLBACK quitTeam " + (error?.localizedDescription ?? "no error") - ) - self?.view.hideToastActivity() - if let err = error as? NSError { - // 退出群聊失败则需要重置通知 - NotificationCenter.default.post(name: NotificationName.leaveTeamBySelf, object: false) - if err.code == 803 { - self?.navigationController?.popViewController(animated: true) - } - self?.showToast(err.localizedDescription) - } else { - // 会话列表中移除该群聊 - let session = NIMSession(tid, type: .team) - if let stickInfo = self?.viewmodel.getTopSessionInfo(session) { - self?.viewmodel.removeStickTop(params: stickInfo) { err, _ in - NELog.infoLog( - ModuleName + " " + (self?.className ?? "TeamSettingViewController"), - desc: "CALLBACK removeStickTop " + (error?.localizedDescription ?? "no error") - ) - } - } - self?.navigationController?.popViewController(animated: true) - } - } - } - } -} - -extension TeamSettingViewController: TeamSettingViewModelDelegate { - func didClickMark() { - if let tid = teamId { - let session = NIMSession(tid, type: .team) - Router.shared.use(PushPinMessageVCRouter, parameters: ["nav": navigationController as Any, "session": session as Any], closure: nil) - } - } - - func didError(_ error: Error) { - showToast(error.localizedDescription) - } - - func didNeedRefreshUI() { - contentTable.reloadData() - refreshMemberCount() - userinfoCollection.reloadData() - } - - func didChangeInviteModeClick(_ model: SettingCellModel) { - weak var weakSelf = self - - let actionSheetController = UIAlertController( - title: nil, - message: nil, - preferredStyle: .actionSheet - ) - - let cancelActionButton = UIAlertAction(title: localizable("cancel"), style: .cancel) { _ in - print("Cancel") - } - cancelActionButton.setValue(UIColor.ne_darkText, forKey: "_titleTextColor") - actionSheetController.addAction(cancelActionButton) - - let manager = UIAlertAction(title: localizable("team_owner"), style: .default) { _ in - weakSelf?.view.makeToastActivity(.center) - weakSelf?.viewmodel.repo.updateInviteMode(.manager, weakSelf?.teamId ?? "") { error in - NELog.infoLog( - ModuleName + " " + self.className(), - desc: "CALLBACK updateInviteMode " + (error?.localizedDescription ?? "no error") - ) - weakSelf?.view.hideToastActivity() - if let err = error { - weakSelf?.showToast(err.localizedDescription) - } else { - weakSelf?.viewmodel.teamInfoModel?.team?.inviteMode = .manager - model.subTitle = localizable("team_owner") - weakSelf?.contentTable.reloadData() - } - } - } - manager.setValue(UIColor.ne_darkText, forKey: "_titleTextColor") - actionSheetController.addAction(manager) - - let deleteActionButton = UIAlertAction(title: localizable("team_all"), style: .default) { _ in - weakSelf?.view.makeToastActivity(.center) - weakSelf?.viewmodel.repo.updateInviteMode(.all, weakSelf?.teamId ?? "") { error in - NELog.infoLog( - ModuleName + " " + self.className(), - desc: "CALLBACK updateInviteMode " + (error?.localizedDescription ?? "no error") - ) - weakSelf?.view.hideToastActivity() - if let err = error { - weakSelf?.showToast(err.localizedDescription) - } else { - weakSelf?.viewmodel.teamInfoModel?.team?.inviteMode = .all - model.subTitle = localizable("team_all") - weakSelf?.contentTable.reloadData() - } - } - } - - deleteActionButton.setValue(UIColor.ne_darkText, forKey: "_titleTextColor") - actionSheetController.addAction(deleteActionButton) - - navigationController?.present(actionSheetController, animated: true, completion: nil) - } - - func didUpdateTeamInfoClick(_ model: SettingCellModel) { - let actionSheetController = UIAlertController( - title: localizable("remind"), - message: nil, - preferredStyle: .actionSheet - ) - weak var weakSelf = self - let cancelActionButton = UIAlertAction(title: localizable("cancel"), style: .cancel) { _ in - print("Cancel") - } - actionSheetController.addAction(cancelActionButton) - - let manager = UIAlertAction(title: localizable("team_owner"), style: .default) { _ in - weakSelf?.view.makeToastActivity(.center) - weakSelf?.viewmodel.repo - .updateTeamInfoPrivilege(.manager, weakSelf?.teamId ?? "") { error in - NELog.infoLog( - ModuleName + " " + self.className(), - desc: "CALLBACK updateTeamInfoPrivilege " + (error?.localizedDescription ?? "no error") - ) - weakSelf?.view.hideToastActivity() - if let err = error { - weakSelf?.showToast(err.localizedDescription) - } else { - weakSelf?.viewmodel.teamInfoModel?.team?.updateInfoMode = .manager - model.subTitle = localizable("team_owner") - weakSelf?.contentTable.reloadData() - } - } - } - actionSheetController.addAction(manager) - - let all = UIAlertAction(title: localizable("team_all"), style: .default) { _ in - weakSelf?.view.makeToastActivity(.center) - weakSelf?.viewmodel.repo - .updateTeamInfoPrivilege(.all, weakSelf?.teamId ?? "") { error in - NELog.infoLog( - ModuleName + " " + self.className(), - desc: "CALLBACK updateTeamInfoPrivilege " + (error?.localizedDescription ?? "no error") - ) - weakSelf?.view.hideToastActivity() - if let err = error { - weakSelf?.showToast(err.localizedDescription) - } else { - weakSelf?.viewmodel.teamInfoModel?.team?.updateInfoMode = .all - model.subTitle = localizable("team_all") - weakSelf?.contentTable.reloadData() - } - } - } - actionSheetController.addAction(all) - - navigationController?.present(actionSheetController, animated: true, completion: nil) - } - - func didClickChangeNick() { - let nick = TeamNameViewController() - nick.type = .NickName - nick.team = viewmodel.teamInfoModel?.team - nick.teamMember = viewmodel.memberInTeam - navigationController?.pushViewController(nick, animated: true) - } - - func didClickHistoryMessage() { - guard let tid = teamId else { - return - } - Router.shared.use( - SearchMessageRouter, - parameters: ["nav": navigationController as Any, "teamId": tid], - closure: nil - ) - } -} diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/HistoryMessageCell.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseHistoryMessageCell.swift similarity index 62% rename from NETeamUIKit/NETeamUIKit/Classes/Setting/View/HistoryMessageCell.swift rename to NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseHistoryMessageCell.swift index a1ad2967..4519b101 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/HistoryMessageCell.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseHistoryMessageCell.swift @@ -6,8 +6,9 @@ import UIKit import NIMSDK @objcMembers -public class HistoryMessageCell: UITableViewCell { +open class NEBaseHistoryMessageCell: UITableViewCell { public var searchText: String? + public var rangeTextColor = UIColor.ne_blueText override public func awakeFromNib() { super.awakeFromNib() @@ -25,7 +26,7 @@ public class HistoryMessageCell: UITableViewCell { setupSubviews() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -36,43 +37,6 @@ public class HistoryMessageCell: UITableViewCell { contentView.addSubview(subTitle) contentView.addSubview(bottomLine) contentView.addSubview(timeLabel) - - NSLayoutConstraint.activate([ - headImge.leftAnchor.constraint( - equalTo: contentView.leftAnchor, - constant: NEConstant.screenInterval - ), - headImge.centerYAnchor.constraint(equalTo: contentView.centerYAnchor, constant: -5), - headImge.widthAnchor.constraint(equalToConstant: 36), - headImge.heightAnchor.constraint(equalToConstant: 36), - ]) - - NSLayoutConstraint.activate([ - title.leftAnchor.constraint(equalTo: headImge.rightAnchor, constant: 12), - title.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20), - title.topAnchor.constraint(equalTo: headImge.topAnchor), - ]) - - NSLayoutConstraint.activate([ - subTitle.leftAnchor.constraint(equalTo: headImge.rightAnchor, constant: 12), - subTitle.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -50), - subTitle.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 6), - ]) - - NSLayoutConstraint.activate([ - bottomLine.rightAnchor.constraint(equalTo: contentView.rightAnchor), - bottomLine.leftAnchor.constraint(equalTo: headImge.leftAnchor), - bottomLine.bottomAnchor.constraint(equalTo: bottomAnchor), - bottomLine.heightAnchor.constraint(equalToConstant: 0.5), - ]) - - NSLayoutConstraint.activate([ - timeLabel.rightAnchor.constraint( - equalTo: contentView.rightAnchor, - constant: -NEConstant.screenInterval - ), - timeLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - ]) } func configData(message: HistoryMessageModel?) { @@ -85,7 +49,7 @@ public class HistoryMessageCell: UITableViewCell { // range必须要加,参数分别表示从索引几开始取几个字符 attributedStr.addAttribute( .foregroundColor, - value: UIColor.ne_blueText, + value: rangeTextColor, range: range ) subTitle.attributedText = attributedStr @@ -106,7 +70,7 @@ public class HistoryMessageCell: UITableViewCell { // MARK: lazy Method - lazy var headImge: NEUserHeaderView = { + public lazy var headImge: NEUserHeaderView = { let headView = NEUserHeaderView(frame: .zero) headView.titleLabel.textColor = .white headView.titleLabel.font = NEConstant.defaultTextFont(14) @@ -116,30 +80,32 @@ public class HistoryMessageCell: UITableViewCell { return headView }() - private lazy var title: UILabel = { + public lazy var title: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.textColor = UIColor.ne_darkText label.font = NEConstant.defaultTextFont(14) + label.textAlignment = .left return label }() - private lazy var subTitle: UILabel = { + public lazy var subTitle: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.textColor = UIColor.ne_lightText label.font = NEConstant.defaultTextFont(12) + label.textAlignment = .left return label }() - private lazy var bottomLine: UIView = { + public lazy var bottomLine: UIView = { let view = UIView() view.translatesAutoresizingMaskIntoConstraints = false view.backgroundColor = UIColor(hexString: "0xDBE0E8") return view }() - private lazy var timeLabel: UILabel = { + public lazy var timeLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.textColor = NEConstant.hexRGB(0xCCCCCC) diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamArrowSettingCell.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamArrowSettingCell.swift new file mode 100644 index 00000000..78ed7443 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamArrowSettingCell.swift @@ -0,0 +1,28 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class NEBaseTeamArrowSettingCell: NEBaseTeamSettingCell { + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + selectionStyle = .none + setupUI() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + override public func configure(_ anyModel: Any) { + super.configure(anyModel) + } + + open func setupUI() { + contentView.addSubview(titleLabel) + contentView.addSubview(arrow) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/TeamAvatarViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamAvatarViewController.swift similarity index 50% rename from NETeamUIKit/NETeamUIKit/Classes/Setting/TeamAvatarViewController.swift rename to NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamAvatarViewController.swift index 9eb04eba..ca9af7c3 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/TeamAvatarViewController.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamAvatarViewController.swift @@ -6,81 +6,66 @@ import UIKit import NECommonUIKit import NIMSDK -import NETeamKit @objcMembers -public class TeamAvatarViewController: NEBaseViewController, UICollectionViewDelegate, +open class NEBaseTeamAvatarViewController: NEBaseViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UINavigationControllerDelegate { - typealias SaveCompletion = () -> Void - - var block: SaveCompletion? - - var team: NIMTeam? - - let repo = TeamRepo() - - lazy var headerView: NEUserHeaderView = { + public typealias SaveCompletion = () -> Void + public var block: SaveCompletion? + public var team: NIMTeam? + public let repo = TeamRepo() + + public let headerBack = UIView() + public let photoImage = UIImageView() + public let defaultHeaderBack = UIView() + public let tag = UILabel() + public var iconUrls = TeamRouter.iconUrls + + public lazy var headerView: NEUserHeaderView = { let header = NEUserHeaderView(frame: .zero) header.translatesAutoresizingMaskIntoConstraints = false header.clipsToBounds = true - header.layer.cornerRadius = 40 header.isUserInteractionEnabled = true return header }() - var headerUrl = "" + public var headerUrl = "" - lazy var iconCollection: UICollectionView = { + public lazy var iconCollection: UICollectionView = { let flow = UICollectionViewFlowLayout() flow.scrollDirection = .horizontal flow.minimumLineSpacing = 0 + flow.minimumInteritemSpacing = 0 let collection = UICollectionView(frame: .zero, collectionViewLayout: flow) collection.translatesAutoresizingMaskIntoConstraints = false collection.delegate = self collection.dataSource = self collection.backgroundColor = .clear collection.showsHorizontalScrollIndicator = false + collection.showsVerticalScrollIndicator = false collection.clipsToBounds = false collection.isScrollEnabled = false return collection }() - override public func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() setupUI() } - func setupUI() { + open func setupUI() { title = localizable("modify_headImage") addRightAction(localizable("save"), #selector(savePhoto), self) + customNavigationView.setMoreButtonTitle(localizable("save")) + customNavigationView.addMoreButtonTarget(target: self, selector: #selector(savePhoto)) + + view.backgroundColor = .ne_lightBackgroundColor - view.backgroundColor = NEConstant.hexRGB(0xF1F1F6) - let headerBack = UIView() headerBack.backgroundColor = .white headerBack.clipsToBounds = true - headerBack.layer.cornerRadius = 8.0 headerBack.translatesAutoresizingMaskIntoConstraints = false view.addSubview(headerBack) - if #available(iOS 11.0, *) { - NSLayoutConstraint.activate([ - headerBack.topAnchor.constraint( - equalTo: view.safeAreaLayoutGuide.topAnchor, - constant: 12.0 - ), - headerBack.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20), - headerBack.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), - headerBack.heightAnchor.constraint(equalToConstant: 128.0), - ]) - } else { - NSLayoutConstraint.activate([ - headerBack.topAnchor.constraint(equalTo: view.topAnchor, constant: 12.0), - headerBack.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20), - headerBack.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), - headerBack.heightAnchor.constraint(equalToConstant: 128.0), - ]) - } - headerBack.addSubview(headerView) NSLayoutConstraint.activate([ headerView.centerXAnchor.constraint(equalTo: headerBack.centerXAnchor), @@ -93,66 +78,29 @@ public class TeamAvatarViewController: NEBaseViewController, UICollectionViewDel headerUrl = url } - let photoImage = UIImageView() photoImage.translatesAutoresizingMaskIntoConstraints = false - headerBack.addSubview(photoImage) - NSLayoutConstraint.activate([ - photoImage.rightAnchor.constraint(equalTo: headerView.rightAnchor), - photoImage.bottomAnchor.constraint(equalTo: headerView.bottomAnchor), - ]) photoImage.image = coreLoader.loadImage("photo") + headerBack.addSubview(photoImage) let gesture = UITapGestureRecognizer() headerView.addGestureRecognizer(gesture) gesture.addTarget(self, action: #selector(uploadPhoto)) - let defaultHeaderBack = UIView() defaultHeaderBack.translatesAutoresizingMaskIntoConstraints = false view.addSubview(defaultHeaderBack) defaultHeaderBack.clipsToBounds = true - defaultHeaderBack.layer.cornerRadius = 8.0 defaultHeaderBack.backgroundColor = .white - NSLayoutConstraint.activate([ - defaultHeaderBack.leftAnchor.constraint(equalTo: headerBack.leftAnchor), - defaultHeaderBack.rightAnchor.constraint(equalTo: headerBack.rightAnchor), - defaultHeaderBack.topAnchor.constraint( - equalTo: headerBack.bottomAnchor, - constant: 12.0 - ), - defaultHeaderBack.heightAnchor.constraint(equalToConstant: 114.0), - ]) - let tag = UILabel() tag.translatesAutoresizingMaskIntoConstraints = false tag.text = localizable("default_icon") tag.font = NEConstant.defaultTextFont(16.0) tag.textColor = NEConstant.hexRGB(0x333333) defaultHeaderBack.addSubview(tag) - NSLayoutConstraint.activate([ - tag.leftAnchor.constraint(equalTo: defaultHeaderBack.leftAnchor, constant: 16.0), - tag.topAnchor.constraint(equalTo: defaultHeaderBack.topAnchor, constant: 15.0), - ]) defaultHeaderBack.addSubview(iconCollection) - iconCollection.register( - TeamDefaultIconCell.self, - forCellWithReuseIdentifier: "\(TeamDefaultIconCell.self)" - ) - NSLayoutConstraint.activate([ - iconCollection.topAnchor.constraint(equalTo: tag.bottomAnchor, constant: 16.0), - iconCollection.leftAnchor.constraint( - equalTo: defaultHeaderBack.leftAnchor, - constant: 18 - ), - iconCollection.rightAnchor.constraint( - equalTo: defaultHeaderBack.rightAnchor, - constant: -18.0 - ), - iconCollection.heightAnchor.constraint(equalToConstant: 48.0), - ]) - for index in 0 ..< TeamRouter.iconUrls.count { - let url = TeamRouter.iconUrls[index] + for index in 0 ..< iconUrls.count { + let url = iconUrls[index] if url == headerUrl { let indexPath = IndexPath(row: index, section: 0) iconCollection.selectItem(at: indexPath, animated: false, scrollPosition: .right) @@ -161,6 +109,9 @@ public class TeamAvatarViewController: NEBaseViewController, UICollectionViewDel if changePermission() == false { rightNavBtn.isHidden = true + customNavigationView.moreButton.isHidden = true + photoImage.isHidden = true + defaultHeaderBack.isHidden = true } } @@ -168,7 +119,7 @@ public class TeamAvatarViewController: NEBaseViewController, UICollectionViewDel if let type = team?.type, type == .normal { return true } - if let ownerId = team?.owner, IMKitEngine.instance.isMySelf(ownerId) { + if let ownerId = team?.owner, IMKitClient.instance.isMySelf(ownerId) { return true } if let mode = team?.updateInfoMode, mode == .all { @@ -177,24 +128,14 @@ public class TeamAvatarViewController: NEBaseViewController, UICollectionViewDel return false } - /* - // MARK: - Navigation - - // In a storyboard-based application, you will often want to do a little preparation before navigation - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - // Get the new view controller using segue.destination. - // Pass the selected object to the new view controller. - } - */ - // MARK: objc 方法 - func uploadPhoto() { + open func uploadPhoto() { print("upload photo") showBottomAlert(self) } - func savePhoto() { + open func savePhoto() { print("save photo") if let tid = team?.teamId { view.makeToastActivity(.center) @@ -202,8 +143,12 @@ public class TeamAvatarViewController: NEBaseViewController, UICollectionViewDel weakSelf?.repo.updateTeamIcon(headerUrl, tid) { error in NELog.infoLog(ModuleName + " " + self.className(), desc: #function + "CALLBACK " + (error?.localizedDescription ?? "no error")) weakSelf?.view.hideToastActivity() - if let err = error { - weakSelf?.showToast(err.localizedDescription) + if let err = error as? NSError { + if err.code == 408 { + weakSelf?.showToast(commonLocalizable("network_error")) + } else { + weakSelf?.showToast(err.localizedDescription) + } } else { weakSelf?.team?.avatarUrl = weakSelf?.headerUrl if let completion = weakSelf?.block { @@ -216,36 +161,26 @@ public class TeamAvatarViewController: NEBaseViewController, UICollectionViewDel } // MAKR: UICollectionViewDelegate, UICollectionViewDataSource,UICollectionViewDelegateFlowLayout - public func collectionView(_ collectionView: UICollectionView, - numberOfItemsInSection section: Int) -> Int { + open func collectionView(_ collectionView: UICollectionView, + numberOfItemsInSection section: Int) -> Int { 5 } - public func collectionView(_ collectionView: UICollectionView, - cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - if let cell = collectionView.dequeueReusableCell( - withReuseIdentifier: "\(TeamDefaultIconCell.self)", - for: indexPath - ) as? TeamDefaultIconCell { - cell.iconImage.image = coreLoader.loadImage("icon_\(indexPath.row)") - - return cell - } - return UICollectionViewCell() + open func collectionView(_ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + UICollectionViewCell() } - public func collectionView(_ collectionView: UICollectionView, - layout collectionViewLayout: UICollectionViewLayout, - minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { - let space = (view.width - 297.0) / 4.0 - print("mini inter : ", space) - return space + open func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + sizeForItemAt indexPath: IndexPath) -> CGSize { + .zero } - public func collectionView(_ collectionView: UICollectionView, - didSelectItemAt indexPath: IndexPath) { - if TeamRouter.iconUrls.count > indexPath.row { - headerUrl = TeamRouter.iconUrls[indexPath.row] + open func collectionView(_ collectionView: UICollectionView, + didSelectItemAt indexPath: IndexPath) { + if iconUrls.count > indexPath.row { + headerUrl = iconUrls[indexPath.row] // headerView.image = coreLoader.loadImage("icon_\(indexPath.row)") headerView.sd_setImage(with: URL(string: headerUrl), completed: nil) } @@ -253,21 +188,25 @@ public class TeamAvatarViewController: NEBaseViewController, UICollectionViewDel // MARK: UINavigationControllerDelegate - func imagePickerController(_ picker: UIImagePickerController, - didFinishPickingMediaWithInfo info: [UIImagePickerController - .InfoKey: Any]) { + open func imagePickerController(_ picker: UIImagePickerController, + didFinishPickingMediaWithInfo info: [UIImagePickerController + .InfoKey: Any]) { let image: UIImage = info[UIImagePickerController.InfoKey.editedImage] as! UIImage uploadHeadImage(image: image) picker.dismiss(animated: true, completion: nil) } - public func uploadHeadImage(image: UIImage) { + open func uploadHeadImage(image: UIImage) { + weak var weakSelf = self + if NEChatDetectNetworkTool.shareInstance.manager?.isReachable == false { + weakSelf?.showToast(commonLocalizable("network_error")) + return + } view.makeToastActivity(.center) if let imageData = image.jpegData(compressionQuality: 0.6) as NSData? { let filePath = NSHomeDirectory().appending("/Documents/") - .appending(IMKitEngine.instance.imAccid) + .appending(IMKitClient.instance.imAccid) let succcess = imageData.write(toFile: filePath, atomically: true) - weak var weakSelf = self if succcess { NIMSDK.shared().resourceManager .upload(filePath, progress: nil) { urlString, error in diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamDefaultIconCell.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamDefaultIconCell.swift similarity index 57% rename from NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamDefaultIconCell.swift rename to NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamDefaultIconCell.swift index 8698f009..3aebf550 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamDefaultIconCell.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamDefaultIconCell.swift @@ -7,7 +7,7 @@ import UIKit import NECommonKit @objcMembers -public class TeamDefaultIconCell: UICollectionViewCell { +open class NEBaseTeamDefaultIconCell: UICollectionViewCell { override public init(frame: CGRect) { super.init(frame: frame) setupUI() @@ -23,6 +23,7 @@ public class TeamDefaultIconCell: UICollectionViewCell { lazy var iconImage: UIImageView = { let image = UIImageView() image.translatesAutoresizingMaskIntoConstraints = false + image.contentMode = .scaleAspectFill return image }() @@ -36,25 +37,12 @@ public class TeamDefaultIconCell: UICollectionViewCell { return view }() - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } func setupUI() { contentView.addSubview(selectBack) - NSLayoutConstraint.activate([ - selectBack.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), - selectBack.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - selectBack.widthAnchor.constraint(equalToConstant: 48.0), - selectBack.heightAnchor.constraint(equalToConstant: 48.0), - ]) - contentView.addSubview(iconImage) - NSLayoutConstraint.activate([ - iconImage.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), - iconImage.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - iconImage.heightAnchor.constraint(equalToConstant: 32), - iconImage.widthAnchor.constraint(equalToConstant: 32), - ]) } } diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamInfoViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamInfoViewController.swift new file mode 100644 index 00000000..3b75caa9 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamInfoViewController.swift @@ -0,0 +1,75 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK + +@objcMembers +open class NEBaseTeamInfoViewController: NEBaseViewController, UITableViewDelegate, + UITableViewDataSource { + public let viewmodel = TeamInfoViewModel() + + public var team: NIMTeam? + + public var cellClassDic = [Int: NEBaseTeamSettingCell.Type]() + + public lazy var contentTable: UITableView = { + let table = UITableView() + table.translatesAutoresizingMaskIntoConstraints = false + table.backgroundColor = .clear + table.dataSource = self + table.delegate = self + table.separatorStyle = .none + table.sectionHeaderHeight = 0 + return table + }() + + override open func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + if let type = team?.type, type == .normal { + title = localizable("discuss_info") + } else { + title = localizable("group_info") + } + viewmodel.getData(team) + } + + override open func viewDidLoad() { + super.viewDidLoad() + setupUI() + } + + open func setupUI() { + view.addSubview(contentTable) + NSLayoutConstraint.activate([ + contentTable.leftAnchor.constraint(equalTo: view.leftAnchor), + contentTable.rightAnchor.constraint(equalTo: view.rightAnchor), + contentTable.topAnchor.constraint(equalTo: view.topAnchor, constant: topConstant + 12), + contentTable.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + cellClassDic.forEach { (key: Int, value: NEBaseTeamSettingCell.Type) in + contentTable.register(value, forCellReuseIdentifier: "\(key)") + } + } + + // MARK: UITableViewDelegate, UITableViewDataSource + + open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + viewmodel.cellDatas.count + } + + open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + UITableViewCell() + } + + open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {} + + open func tableView(_ tableView: UITableView, + heightForRowAt indexPath: IndexPath) -> CGFloat { + let model = viewmodel.cellDatas[indexPath.row] + return model.rowHeight + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamIntroduceViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamIntroduceViewController.swift new file mode 100644 index 00000000..81201dd7 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamIntroduceViewController.swift @@ -0,0 +1,146 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonKit +import NIMSDK + +@objcMembers +open class NEBaseTeamIntroduceViewController: NEBaseViewController, UITextViewDelegate { +// typealias SaveCompletion = () -> Void +// +// var block: SaveCompletion? + + public var team: NIMTeam? + public let textLimit = 100 + public let repo = TeamRepo() + public let backView = UIView() + + public lazy var textView: UITextView = { + let text = UITextView() + text.translatesAutoresizingMaskIntoConstraints = false + text.textColor = NEConstant.hexRGB(0x333333) + text.font = NEConstant.defaultTextFont(14.0) + text.delegate = self + text.textContainerInset = UIEdgeInsets.zero + text.layoutManager.allowsNonContiguousLayout = false + return text + }() + + public lazy var clearButton: UIButton = { + let text = UIButton() + text.translatesAutoresizingMaskIntoConstraints = false + text.setImage(coreLoader.loadImage("clear_btn"), for: .normal) + text.addTarget(self, action: #selector(clearText), for: .touchUpInside) + return text + }() + + public lazy var countLabel: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = NEConstant.hexRGB(0xB3B7BC) + label.font = NEConstant.defaultTextFont(12.0) + return label + }() + + override open func viewDidLoad() { + super.viewDidLoad() + setupUI() + } + + open func setupUI() { + customNavigationView.setMoreButtonTitle(localizable("save")) + customNavigationView.addMoreButtonTarget(target: self, selector: #selector(saveIntr)) + + if let type = team?.type, type == .advanced { + title = localizable("team_intr") + } else { + title = localizable("discuss_introduce") + } + + backView.backgroundColor = .white + backView.translatesAutoresizingMaskIntoConstraints = false + backView.clipsToBounds = false + + view.addSubview(backView) + backView.addSubview(textView) + backView.addSubview(clearButton) + backView.addSubview(countLabel) + + NSLayoutConstraint.activate([ + countLabel.rightAnchor.constraint(equalTo: backView.rightAnchor, constant: -16), + countLabel.bottomAnchor.constraint(equalTo: backView.bottomAnchor, constant: -8.0), + ]) + + figureTextCount(team?.intro ?? "") + + if changePermission() == false { + textView.isEditable = false + rightNavBtn.isHidden = true + customNavigationView.moreButton.isHidden = true + } + } + + func changePermission() -> Bool { + if let ownerId = team?.owner, IMKitClient.instance.isMySelf(ownerId) { + return true + } + if let mode = team?.updateInfoMode, mode == .all { + return true + } + return false + } + + func saveIntr() { + textView.resignFirstResponder() + weak var weakSelf = self + if NEChatDetectNetworkTool.shareInstance.manager?.isReachable == false { + weakSelf?.showToast(commonLocalizable("network_error")) + return + } + + if let teamid = team?.teamId { + let text = textView.text ?? "" + view.makeToastActivity(.center) + repo.updateTeamIntroduce(text, teamid) { error in + NELog.infoLog( + ModuleName + " " + self.className(), + desc: "CALLBACK updateTeamIntroduce " + (error?.localizedDescription ?? "no error") + ) + weakSelf?.view.hideToastActivity() + if let err = error { + weakSelf?.showToast(err.localizedDescription) + } else { + weakSelf?.team?.intro = text + weakSelf?.navigationController?.popViewController(animated: true) + } + } + } + } + + func figureTextCount(_ text: String) { + textView.text = text + countLabel.text = "\(text.count)/\(textLimit)" + clearButton.isHidden = !changePermission() || text.count <= 0 + } + + func clearText() { + figureTextCount("") + } + + // MARK: UITextViewDelegate + + open func textViewDidChange(_ textView: UITextView) { + if let _ = textView.markedTextRange { + return + } + if var text = textView.text { + if text.count > textLimit { + text = String(text.prefix(textLimit)) + } + figureTextCount(text) + } + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamMemberCell.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamMemberCell.swift similarity index 96% rename from NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamMemberCell.swift rename to NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamMemberCell.swift index 374c7989..7a1a4194 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamMemberCell.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamMemberCell.swift @@ -4,11 +4,10 @@ // found in the LICENSE file. import UIKit -import NETeamKit import NECommonUIKit @objcMembers -public class TeamMemberCell: UITableViewCell { +open class NEBaseTeamMemberCell: UITableViewCell { lazy var headerView: NEUserHeaderView = { let header = NEUserHeaderView(frame: .zero) header.titleLabel.font = NEConstant.defaultTextFont(14) @@ -25,9 +24,9 @@ public class TeamMemberCell: UITableViewCell { label.font = NEConstant.defaultTextFont(12.0) label.textColor = NEConstant.hexRGB(0x337EFF) label.backgroundColor = NEConstant.hexRGB(0xE0ECFF) + label.layer.borderColor = NEConstant.hexRGB(0xB9D3FF).cgColor label.clipsToBounds = true label.layer.cornerRadius = 4.0 - label.layer.borderColor = NEConstant.hexRGB(0xB9D3FF).cgColor label.layer.borderWidth = 1.0 label.text = localizable("team_owner") label.textAlignment = .center @@ -59,11 +58,11 @@ public class TeamMemberCell: UITableViewCell { setupUI() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } - func setupUI() { + open func setupUI() { contentView.addSubview(headerView) NSLayoutConstraint.activate([ headerView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 21), diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/TeamNameViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamNameViewController.swift similarity index 53% rename from NETeamUIKit/NETeamUIKit/Classes/Setting/TeamNameViewController.swift rename to NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamNameViewController.swift index cc8cd9f6..a8544e71 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/TeamNameViewController.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamNameViewController.swift @@ -6,83 +6,62 @@ import UIKit import NIMSDK import NECommonKit -import NETeamKit - -@objc public enum ChangeType: Int { - case TeamName = 0 - case NickName -} @objcMembers -public class TeamNameViewController: NEBaseViewController, UITextFieldDelegate { - var team: NIMTeam? +open class NEBaseTeamNameViewController: NEBaseViewController, UITextViewDelegate { + public var team: NIMTeam? // var user: NIMUser? - var type = ChangeType.TeamName - var teamMember: NIMTeamMember? - var repo = TeamRepo() - let textLimit = 30 + public var type = ChangeType.TeamName + public var teamMember: NIMTeamMember? + public var repo = TeamRepo() + public let textLimit = 30 - lazy var countLabel: UILabel = { + public let backView = UIView() + + public lazy var countLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.textColor = NEConstant.hexRGB(0xB3B7BC) label.font = NEConstant.defaultTextFont(12.0) + label.isUserInteractionEnabled = false return label }() - lazy var textField: UITextField = { - let text = UITextField() + public lazy var textView: UITextView = { + let text = UITextView() text.translatesAutoresizingMaskIntoConstraints = false text.textColor = NEConstant.hexRGB(0x333333) text.font = NEConstant.defaultTextFont(14.0) text.delegate = self - text.clearButtonMode = .always + return text + }() + public lazy var clearButton: UIButton = { + let text = UIButton() + text.translatesAutoresizingMaskIntoConstraints = false + text.setImage(coreLoader.loadImage("clear_btn"), for: .normal) + text.addTarget(self, action: #selector(clearText), for: .touchUpInside) return text }() - override public func viewDidLoad() { + override open func viewDidLoad() { super.viewDidLoad() setupUI() } - func setupUI() { - view.backgroundColor = NEConstant.hexRGB(0xF1F1F6) - let backView = UIView() + open func setupUI() { + customNavigationView.setMoreButtonTitle(localizable("save")) + customNavigationView.addMoreButtonTarget(target: self, selector: #selector(saveName)) + + view.addSubview(backView) + backView.addSubview(textView) + backView.addSubview(clearButton) + backView.addSubview(countLabel) + backView.backgroundColor = .white backView.clipsToBounds = true - backView.layer.cornerRadius = 8.0 backView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(backView) - if #available(iOS 11.0, *) { - NSLayoutConstraint.activate([ - backView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20.0), - backView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), - backView.topAnchor.constraint( - equalTo: view.safeAreaLayoutGuide.topAnchor, - constant: 12 - ), - backView.heightAnchor.constraint(equalToConstant: 60), - ]) - } else { - NSLayoutConstraint.activate([ - backView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20.0), - backView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), - backView.topAnchor.constraint(equalTo: view.topAnchor, constant: 12), - backView.heightAnchor.constraint(equalToConstant: 60), - ]) - } - backView.addSubview(textField) - NSLayoutConstraint.activate([ - textField.leftAnchor.constraint(equalTo: backView.leftAnchor, constant: 16), - textField.rightAnchor.constraint(equalTo: backView.rightAnchor, constant: -12), - textField.topAnchor.constraint(equalTo: backView.topAnchor, constant: 0), - textField.heightAnchor.constraint(equalToConstant: 44), -// textField.bottomAnchor.constraint(equalTo: backView.bottomAnchor, constant: 0) - ]) - - backView.addSubview(countLabel) NSLayoutConstraint.activate([ countLabel.rightAnchor.constraint(equalTo: backView.rightAnchor, constant: -16), countLabel.bottomAnchor.constraint(equalTo: backView.bottomAnchor, constant: -8.0), @@ -91,39 +70,23 @@ public class TeamNameViewController: NEBaseViewController, UITextFieldDelegate { var name = "" if type == .TeamName, let n = team?.teamName { name = n - if changePermission() == false { -// disableSubmit() rightNavBtn.isHidden = true - textField.clearButtonMode = .never - textField.isEnabled = false - } - if let teamType = team?.type, teamType == .normal { - title = localizable("discuss_name") - } else { - title = localizable("team_name") + customNavigationView.moreButton.isHidden = true + textView.isEditable = false } - - } else if type == .NickName, let n = teamMember?.nickname { + } else if type == .NickName { title = localizable("team_nick") - name = n + if let n = teamMember?.nickname { + name = n + } } - countLabel.text = "\(name.count)/\(textLimit)" - textField.text = name + figureTextCount(name) if name.count <= 0, type != .NickName { disableSubmit() } - - NotificationCenter.default.addObserver( - self, - selector: #selector(textFieldChange), - name: UITextField.textDidChangeNotification, - object: textField - ) - - addRightAction(localizable("save"), #selector(saveName), self) } /* @@ -137,11 +100,15 @@ public class TeamNameViewController: NEBaseViewController, UITextFieldDelegate { */ func changePermission() -> Bool { + if type == .NickName { + return true + } + if let type = team?.type, type == .normal { return true } - if let ownerId = team?.owner, IMKitEngine.instance.isMySelf(ownerId) { + if let ownerId = team?.owner, IMKitClient.instance.isMySelf(ownerId) { return true } if let mode = team?.updateInfoMode, mode == .all { @@ -150,54 +117,45 @@ public class TeamNameViewController: NEBaseViewController, UITextFieldDelegate { return false } - func disableSubmit() { + open func disableSubmit() { rightNavBtn.setTitleColor(NEConstant.hexRGBAlpha(0x337EFF, 0.5), for: .normal) rightNavBtn.isEnabled = false + customNavigationView.moreButton.setTitleColor(NEConstant.hexRGBAlpha(0x337EFF, 0.5), for: .normal) + customNavigationView.moreButton.isEnabled = false } - func enableSubmit() { + open func enableSubmit() { rightNavBtn.setTitleColor(NEConstant.hexRGB(0x337EFF), for: .normal) rightNavBtn.isEnabled = true + customNavigationView.moreButton.setTitleColor(NEConstant.hexRGB(0x337EFF), for: .normal) + customNavigationView.moreButton.isEnabled = true } - // MARK: objc 方法 - - func textFieldChange() { - if let _ = textField.markedTextRange { - return - } - if var text = textField.text { - if let lang = textField.textInputMode?.primaryLanguage, lang == "zh-Hans" { - if text.count > textLimit { - text = String(text.prefix(textLimit)) - textField.text = String(text) - } - figureTextCount(text) - } - } - } - - func saveName() { + open func saveName() { guard let tid = team?.teamId else { showToast(localizable("team_not_exist")) return } - if let text = textField.text, + if let text = textView.text, !text.isEmpty { let trimText = text.trimmingCharacters(in: .whitespaces) if trimText.isEmpty { view.makeToast(localizable("space_not_support"), duration: 2, position: .center) - textField.text = trimText figureTextCount(trimText) return } } weak var weakSelf = self - textField.resignFirstResponder() + if NEChatDetectNetworkTool.shareInstance.manager?.isReachable == false { + weakSelf?.showToast(commonLocalizable("network_error")) + return + } + + textView.resignFirstResponder() if type == .TeamName { - let n = textField.text ?? "" + let n = textView.text ?? "" view.makeToastActivity(.center) repo.updateTeamName(tid, n) { error in weakSelf?.view.hideToastActivity() @@ -209,7 +167,7 @@ public class TeamNameViewController: NEBaseViewController, UITextFieldDelegate { } } } else if type == .NickName, let uid = teamMember?.userId { - let n = textField.text ?? "" + let n = textView.text ?? "" view.makeToastActivity(.center) repo.updateMemberNick(tid, uid, n) { error in @@ -222,11 +180,15 @@ public class TeamNameViewController: NEBaseViewController, UITextFieldDelegate { } } } -} -extension TeamNameViewController { + func clearText() { + figureTextCount("") + } + func figureTextCount(_ text: String) { + textView.text = text countLabel.text = "\(text.count)/\(textLimit)" + clearButton.isHidden = !changePermission() || text.count <= 0 if type == .NickName { return } @@ -236,4 +198,18 @@ extension TeamNameViewController { disableSubmit() } } + + // MARK: UITextViewDelegate + + public func textViewDidChange(_ textView: UITextView) { + if let _ = textView.markedTextRange { + return + } + if var text = textView.text { + if text.count > textLimit { + text = String(text.prefix(textLimit)) + } + figureTextCount(text) + } + } } diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/BaseTeamSettingCell.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamSettingCell.swift similarity index 80% rename from NETeamUIKit/NETeamUIKit/Classes/Setting/View/BaseTeamSettingCell.swift rename to NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamSettingCell.swift index 32e9b419..e2bbbd6c 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/BaseTeamSettingCell.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamSettingCell.swift @@ -5,11 +5,22 @@ import UIKit +@objc public enum ChangeType: Int { + case TeamName = 0 + case NickName +} + +@objc +public enum TeamSettingType: Int { + case Discuss = 0 + case Senior = 1 +} + @objcMembers -public class BaseTeamSettingCell: CornerCell { +open class NEBaseTeamSettingCell: CornerCell { var model: SettingCellModel? - lazy var titleLabel: UILabel = { + public lazy var titleLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.textColor = NEConstant.hexRGB(0x333333) @@ -26,10 +37,11 @@ public class BaseTeamSettingCell: CornerCell { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) selectionStyle = .none + contentView.backgroundColor = .clear showDefaultLine = true } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamSettingHeaderCell.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamSettingHeaderCell.swift new file mode 100644 index 00000000..0bb20ad7 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamSettingHeaderCell.swift @@ -0,0 +1,45 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonUIKit + +@objcMembers +open class NEBaseTeamSettingHeaderCell: NEBaseTeamSettingCell { + public lazy var headerView: NEUserHeaderView = { + let header = NEUserHeaderView(frame: .zero) + header.translatesAutoresizingMaskIntoConstraints = false + header.clipsToBounds = true + return header + }() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + selectionStyle = .none + setupUI() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + setupUI() + } + + override public func configure(_ anyModel: Any) { + super.configure(anyModel) + if let url = model?.headerUrl { + headerView.sd_setImage(with: URL(string: url), completed: nil) + headerView.setTitle("") + } else { + headerView.setTitle(model?.defaultHeadData ?? "") + headerView.backgroundColor = UIColor.colorWithString(string: model?.defaultHeadData) + } + } + + open func setupUI() { + contentView.addSubview(titleLabel) + contentView.addSubview(arrow) + contentView.addSubview(headerView) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamSettingSelectCell.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamSettingSelectCell.swift new file mode 100644 index 00000000..aed0c9e2 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamSettingSelectCell.swift @@ -0,0 +1,38 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class NEBaseTeamSettingSelectCell: NEBaseTeamSettingCell { + lazy var subTitleLabel: UILabel = { + let label = UILabel() + label.textColor = NEConstant.hexRGB(0x999999) + label.font = NEConstant.defaultTextFont(14.0) + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + selectionStyle = .none + setupUI() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + override public func configure(_ anyModel: Any) { + super.configure(anyModel) + subTitleLabel.text = model?.subTitle + } + + func setupUI() { + contentView.addSubview(titleLabel) + contentView.addSubview(subTitleLabel) + contentView.addSubview(arrow) + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamSettingSwitchCell.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamSettingSwitchCell.swift new file mode 100644 index 00000000..6584ee5e --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamSettingSwitchCell.swift @@ -0,0 +1,44 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +@objcMembers +open class NEBaseTeamSettingSwitchCell: NEBaseTeamSettingCell { + public var tSwitch: UISwitch = { + let q = UISwitch() + q.translatesAutoresizingMaskIntoConstraints = false + return q + }() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + selectionStyle = .none + setupUI() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + override public func configure(_ anyModel: Any) { + super.configure(anyModel) + if let open = model?.switchOpen { + tSwitch.isOn = open + } + } + + open func setupUI() { + contentView.addSubview(titleLabel) + contentView.addSubview(tSwitch) + tSwitch.addTarget(self, action: #selector(switchChange(_:)), for: .touchUpInside) + } + + public func switchChange(_ s: UISwitch) { + if let block = model?.swichChange { + block(s.isOn) + } + } +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamSettingViewController.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamSettingViewController.swift new file mode 100644 index 00000000..fe1af1b4 --- /dev/null +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamSettingViewController.swift @@ -0,0 +1,667 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonUIKit +import NECoreIMKit +import NIMSDK + +@objcMembers +open class NEBaseTeamSettingViewController: NEBaseViewController, UICollectionViewDelegate, + UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UITableViewDataSource, + UITableViewDelegate, TeamSettingViewModelDelegate { + public let viewmodel = TeamSettingViewModel() + + public var teamId: String? + + public var addBtnWidth: NSLayoutConstraint? + + public var addBtnLeftMargin: NSLayoutConstraint? + + public var teamSettingType: TeamSettingType = .Discuss + + public var isSeniorDiscuss = false // 是否是高级群扩展的讨论组 + + var className = "TeamSettingViewController" + + public var cellClassDic = [Int: NEBaseTeamSettingCell.Type]() + + public lazy var contentTable: UITableView = { + let table = UITableView() + table.translatesAutoresizingMaskIntoConstraints = false + table.backgroundColor = .clear + table.dataSource = self + table.delegate = self + table.separatorColor = .clear + table.separatorStyle = .none + table.sectionHeaderHeight = 12.0 + table + .tableFooterView = + UIView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 12)) + if #available(iOS 15.0, *) { + table.sectionHeaderTopPadding = 0.0 + } + return table + }() + + public lazy var teamHeader: NEUserHeaderView = { + let imageView = NEUserHeaderView(frame: .zero) + imageView.translatesAutoresizingMaskIntoConstraints = false + imageView.clipsToBounds = true + imageView.titleLabel.font = NEConstant.defaultTextFont(16.0) + return imageView + }() + + public lazy var teamNameLabel: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.font = NEConstant.defaultTextFont(16.0) + label.textColor = NEConstant.hexRGB(0x333333) + return label + }() + + public lazy var memberCountLabel: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.font = NEConstant.defaultTextFont(16.0) + label.textColor = NEConstant.hexRGB(0x999999) + return label + }() + + public lazy var userinfoCollection: UICollectionView = { + let flow = UICollectionViewFlowLayout() + flow.scrollDirection = .horizontal + flow.minimumLineSpacing = 0 + flow.minimumInteritemSpacing = 0 + let collection = UICollectionView(frame: .zero, collectionViewLayout: flow) + collection.translatesAutoresizingMaskIntoConstraints = false + collection.delegate = self + collection.dataSource = self + collection.backgroundColor = .clear + collection.showsHorizontalScrollIndicator = false + return collection + }() + + public lazy var addBtn: ExpandButton = { + let button = ExpandButton() + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + override open func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + if let model = viewmodel.teamInfoModel { + if let url = model.team?.avatarUrl { + teamHeader.sd_setImage(with: URL(string: url)) + } + if let name = model.team?.teamName { + teamNameLabel.text = name + } + } + } + + override open func viewDidLoad() { + super.viewDidLoad() + + title = localizable("setting") + weak var weakSelf = self + viewmodel.delegate = self + if let tid = teamId { + viewmodel.getTeamInfo(tid) { error in + NELog.infoLog( + ModuleName + " " + self.className, + desc: "CALLBACK getTeamInfo " + (error?.localizedDescription ?? "no error") + ) + if let err = error { + weakSelf?.showToast(err.localizedDescription) + } else { + if let type = weakSelf?.viewmodel.teamInfoModel?.team?.type { + if type == .normal { + weakSelf?.teamSettingType = .Discuss + } else if type == .advanced { + if let custom = weakSelf?.viewmodel.teamInfoModel?.team?.clientCustomInfo, custom.contains(discussTeamKey) { + weakSelf?.teamSettingType = .Discuss + weakSelf?.isSeniorDiscuss = true + } else { + weakSelf?.teamSettingType = .Senior + } + } + } + weakSelf?.reloadSectionData() + weakSelf?.contentTable.tableHeaderView = weakSelf?.getHeaderView() + weakSelf?.contentTable.tableFooterView = weakSelf?.getFooterView() + weakSelf?.contentTable.reloadData() + weakSelf?.userinfoCollection.reloadData() + weakSelf?.checkoutAddShowOrHide() + } + } + } + // Do any additional setup after loading the view. + setupUI() + } + + open func reloadSectionData() {} + + open func setupUI() { + view.backgroundColor = .ne_lightBackgroundColor + view.addSubview(contentTable) + NSLayoutConstraint.activate([ + contentTable.leftAnchor.constraint(equalTo: view.leftAnchor), + contentTable.rightAnchor.constraint(equalTo: view.rightAnchor), + contentTable.topAnchor.constraint(equalTo: view.topAnchor, constant: topConstant), + contentTable.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + cellClassDic.forEach { (key: Int, value: NEBaseTeamSettingCell.Type) in + contentTable.register(value, forCellReuseIdentifier: "\(key)") + } + if let pan = navigationController?.interactivePopGestureRecognizer { + contentTable.panGestureRecognizer.require(toFail: pan) + } + } + + open func getHeaderView() -> UIView { + UIView() + } + + open func getFooterView() -> UIView? { + nil + } + + open func getBottomText() -> String? { + if teamSettingType == .Discuss { + return localizable("leave_discuss") + } else if teamSettingType == .Senior { + return viewmodel.isOwner() ? localizable("dismiss_team") : localizable("leave_team") + } + return nil + } + + open func setupUserInfoCollection(_ cornerView: UIView) {} + + // MARK: objc 方法 + + open func addUser() { + weak var weakSelf = self + Router.shared.register(ContactSelectedUsersRouter) { param in + print("addUser weak self ", weakSelf as Any) + if let accids = param["accids"] as? [String], + let tid = self.viewmodel.teamInfoModel?.team?.teamId, + let beInviteMode = self.viewmodel.teamInfoModel?.team?.beInviteMode, + let type = self.viewmodel.teamInfoModel?.team?.type { + if beInviteMode == .noAuth || type == .normal { + self.didAddUserAndRefreshUI(accids, tid) + } else { + self.didAddUser(accids, tid) + } + } + } + var param = [String: Any]() + param["nav"] = navigationController as Any + var filters = Set() + viewmodel.teamInfoModel?.users.forEach { model in + if let uid = model.nimUser?.userId { + filters.insert(uid) + } + } + if filters.count > 0 { + param["filters"] = filters + } + + param["limit"] = inviteNumberLimit - filters.count + Router.shared.use(ContactUserSelectRouter, parameters: param, closure: nil) + } + + open func removeTeamForMyself() { + weak var weakSelf = self + if teamSettingType == .Senior { + showAlert(message: viewmodel.isOwner() ? localizable("dissolute_team_chat") : localizable("quit_team_chat")) { + if weakSelf?.viewmodel.isOwner() == true { + weakSelf?.dismissTeam() + } else { + weakSelf?.leaveTeam() + } + } + } else if teamSettingType == .Discuss { + showAlert(message: localizable("quit_discuss_chat")) { + weakSelf?.leaveDiscuss() + } + } + } + + open func leaveDiscuss() { + weak var weakSelf = self + if isSeniorDiscuss == true, viewmodel.isOwner() { + view.makeToastActivity(.center) + viewmodel.transferTeamOwner { error in + weakSelf?.view.hideToastActivity() + if let err = error as? NSError { + if err.code == 408 { + weakSelf?.showToast(commonLocalizable("network_error")) + } else { + weakSelf?.showToast(err.localizedDescription) + } + } else { + weakSelf?.navigationController?.popViewController(animated: true) + } + } + return + } + leaveTeam() + } + + open func toInfoView() {} + + open func toMemberList() { + let memberController = NEBaseTeamMembersController(viewmodel: viewmodel) + memberController.datas = viewmodel.teamInfoModel?.users + if teamSettingType == .Senior { + memberController.isSenior = true + } + memberController.ownerId = viewmodel.teamInfoModel?.team?.owner + navigationController?.pushViewController(memberController, animated: true) + } + + // MARK: UICollectionViewDelegate, UICollectionViewDataSource,UICollectionViewDelegateFlowLayout + + open func collectionView(_ collectionView: UICollectionView, + numberOfItemsInSection section: Int) -> Int { + print("numberOfItemsInSection ", viewmodel.teamInfoModel?.users.count as Any) + return viewmodel.teamInfoModel?.users.count ?? 0 + } + + open func collectionView(_ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + UICollectionViewCell() + } + + open func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + sizeForItemAt indexPath: IndexPath) -> CGSize { + .zero + } + + open func collectionView(_ collectionView: UICollectionView, + didSelectItemAt indexPath: IndexPath) { + if let member = viewmodel.teamInfoModel?.users[indexPath.row], + let nimUser = member.nimUser { + if IMKitClient.instance.isMySelf(nimUser.userId) { + Router.shared.use( + MeSettingRouter, + parameters: ["nav": navigationController as Any], + closure: nil + ) + } else { + if let uid = nimUser.userId { + Router.shared.use( + ContactUserInfoPageRouter, + parameters: ["nav": navigationController as Any, "uid": uid], + closure: nil + ) + } + } + } + } + + // MARK: UITableViewDataSource, UITableViewDelegate + + open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if viewmodel.sectionData.count > section { + let model = viewmodel.sectionData[section] + return model.cellModels.count + } + return 0 + } + + open func numberOfSections(in tableView: UITableView) -> Int { + viewmodel.sectionData.count + } + + open func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let model = viewmodel.sectionData[indexPath.section].cellModels[indexPath.row] + if let cell = tableView.dequeueReusableCell( + withIdentifier: "\(model.type)", + for: indexPath + ) as? NEBaseTeamSettingCell { + cell.configure(model) + return cell + } + return UITableViewCell() + } + + open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let model = viewmodel.sectionData[indexPath.section].cellModels[indexPath.row] + if let block = model.cellClick { + block() + } + } + + open func tableView(_ tableView: UITableView, + heightForRowAt indexPath: IndexPath) -> CGFloat { + let model = viewmodel.sectionData[indexPath.section].cellModels[indexPath.row] + return model.rowHeight + } + + open func tableView(_ tableView: UITableView, + heightForHeaderInSection section: Int) -> CGFloat { + if viewmodel.sectionData.count > section { + let model = viewmodel.sectionData[section] + if model.cellModels.count > 0 { + return 12.0 + } + } + return 0 + } + + open func tableView(_ tableView: UITableView, + viewForHeaderInSection section: Int) -> UIView? { + let header = UIView() + header.backgroundColor = .ne_lightBackgroundColor + return header + } + + open func tableView(_ tableView: UITableView, + heightForFooterInSection section: Int) -> CGFloat { + if section == viewmodel.sectionData.count - 1 { + return 12.0 + } + return 0 + } + + func didAddUserAndRefreshUI(_ accids: [String], _ tid: String) { + weak var weakSelf = self + view.makeToastActivity(.center) + viewmodel.repo.inviteUser(accids, tid, nil, nil) { error, members in + if let err = error { + weakSelf?.view.hideToastActivity() + weakSelf?.showToast(err.localizedDescription) + } else { + print("add users success : ", members as Any) + if let ms = members, let model = weakSelf?.viewmodel.teamInfoModel { + weakSelf?.viewmodel.repo.splitGroupMember(ms, model) { error, team in + weakSelf?.view.hideToastActivity() + if let e = error { + weakSelf?.showToast(e.localizedDescription) + } else { + weakSelf?.refreshMemberCount() + weakSelf?.userinfoCollection.reloadData() + weakSelf?.checkoutAddShowOrHide() + } + } + } else { + weakSelf?.view.hideToastActivity() + } + } + } + } + + func didAddUser(_ accids: [String], _ tid: String) { + weak var weakSelf = self + view.makeToastActivity(.center) + viewmodel.repo.inviteUser(accids, tid, nil, nil) { error, members in + NELog.infoLog( + ModuleName + " " + self.className(), + desc: "CALLBACK inviteUser " + (error?.localizedDescription ?? "no error") + ) + weakSelf?.view.hideToastActivity() + if let err = error { + weakSelf?.showToast(err.localizedDescription) + } else { + weakSelf?.showToast(localizable("invite_has_send")) + } + } + } + + func dismissTeam() { + if let tid = teamId { + weak var weakSelf = self + view.makeToastActivity(.center) + viewmodel.dismissTeam(tid) { error in + NELog.infoLog( + ModuleName + " " + self.className, + desc: "CALLBACK dismissTeam " + (error?.localizedDescription ?? "no error") + ) + weakSelf?.view.hideToastActivity() + if let err = error as? NSError { + if err.code == 408 { + weakSelf?.showToast(commonLocalizable("network_error")) + } else { + weakSelf?.showToast(err.localizedDescription) + } + } else { + weakSelf?.navigationController?.popViewController(animated: true) + } + } + } + } + + func refreshMemberCount() { + if let count = viewmodel.teamInfoModel?.users.count { + memberCountLabel.text = "\(count)" + } + } + + func leaveTeam() { + if let tid = teamId { + // 需要先于 SDK 回调进行通知 + NotificationCenter.default.post(name: NotificationName.leaveTeamBySelf, object: true) + + view.makeToastActivity(.center) + viewmodel.quitTeam(tid) { [weak self] error in + NELog.infoLog( + ModuleName + " " + (self?.className ?? "TeamSettingViewController"), + desc: "CALLBACK quitTeam " + (error?.localizedDescription ?? "no error") + ) + self?.view.hideToastActivity() + if let err = error as? NSError { + // 退出群聊失败则需要重置通知 + NotificationCenter.default.post(name: NotificationName.leaveTeamBySelf, object: false) + if err.code == 803 { + self?.navigationController?.popViewController(animated: true) + } else if err.code == 408 { + self?.showToast(commonLocalizable("network_error")) + } else { + self?.showToast(err.localizedDescription) + } + } else { + // 会话列表中移除该群聊 + let session = NIMSession(tid, type: .team) + if let stickInfo = self?.viewmodel.getTopSessionInfo(session) { + self?.viewmodel.removeStickTop(params: stickInfo) { err, _ in + NELog.infoLog( + ModuleName + " " + (self?.className ?? "TeamSettingViewController"), + desc: "CALLBACK removeStickTop " + (error?.localizedDescription ?? "no error") + ) + } + } + self?.navigationController?.popViewController(animated: true) + } + } + } + } + + func didClickMark() { + if let tid = teamId { + let session = NIMSession(tid, type: .team) + Router.shared.use(PushPinMessageVCRouter, parameters: ["nav": navigationController as Any, "session": session as Any], closure: nil) + } + } + + func didError(_ error: NSError) { + if error.code == 408 { + showToast(commonLocalizable("network_error")) + } else { + showToast(error.localizedDescription) + } + } + + func didNeedRefreshUI() { + contentTable.reloadData() + refreshMemberCount() + userinfoCollection.reloadData() + checkoutAddShowOrHide() + } + + open func checkoutAddShowOrHide() {} + + func updateInviteModeOwnerAction(_ model: SettingCellModel) { + weak var weakSelf = self + weakSelf?.view.makeToastActivity(.center) + weakSelf?.viewmodel.repo.updateInviteMode(.manager, weakSelf?.teamId ?? "") { error in + NELog.infoLog( + ModuleName + " " + self.className(), + desc: "CALLBACK updateInviteMode " + (error?.localizedDescription ?? "no error") + ) + weakSelf?.view.hideToastActivity() + if let err = error as? NSError { + if err.code == 408 { + weakSelf?.showToast(commonLocalizable("network_error")) + } else { + weakSelf?.showToast(err.localizedDescription) + } + } else { + weakSelf?.viewmodel.teamInfoModel?.team?.inviteMode = .manager + model.subTitle = localizable("team_owner") + weakSelf?.contentTable.reloadData() + } + } + } + + func updateInviteModeAllAction(_ model: SettingCellModel) { + weak var weakSelf = self + weakSelf?.view.makeToastActivity(.center) + weakSelf?.viewmodel.repo.updateInviteMode(.all, weakSelf?.teamId ?? "") { error in + NELog.infoLog( + ModuleName + " " + self.className(), + desc: "CALLBACK updateInviteMode " + (error?.localizedDescription ?? "no error") + ) + weakSelf?.view.hideToastActivity() + if let err = error as? NSError { + if err.code == 408 { + weakSelf?.showToast(commonLocalizable("network_error")) + } else { + weakSelf?.showToast(err.localizedDescription) + } + } else { + weakSelf?.viewmodel.teamInfoModel?.team?.inviteMode = .all + model.subTitle = localizable("team_all") + weakSelf?.contentTable.reloadData() + } + } + } + + open func didChangeInviteModeClick(_ model: SettingCellModel) { + weak var weakSelf = self + + let actionSheetController = UIAlertController( + title: nil, + message: nil, + preferredStyle: .actionSheet + ) + + let cancelActionButton = UIAlertAction(title: localizable("cancel"), style: .cancel) { _ in + print("Cancel") + } + cancelActionButton.setValue(UIColor.ne_darkText, forKey: "_titleTextColor") + actionSheetController.addAction(cancelActionButton) + + let ownerActionButton = UIAlertAction(title: localizable("team_owner"), style: .default) { _ in + weakSelf?.updateInviteModeOwnerAction(model) + } + ownerActionButton.setValue(UIColor.ne_darkText, forKey: "_titleTextColor") + actionSheetController.addAction(ownerActionButton) + + let allActionButton = UIAlertAction(title: localizable("team_all"), style: .default) { _ in + weakSelf?.updateInviteModeAllAction(model) + } + + allActionButton.setValue(UIColor.ne_darkText, forKey: "_titleTextColor") + actionSheetController.addAction(allActionButton) + + navigationController?.present(actionSheetController, animated: true, completion: nil) + } + + func updateTeamInfoOwnerAction(_ model: SettingCellModel) { + weak var weakSelf = self + weakSelf?.view.makeToastActivity(.center) + weakSelf?.viewmodel.repo + .updateTeamInfoPrivilege(.manager, weakSelf?.teamId ?? "") { error in + NELog.infoLog( + ModuleName + " " + self.className(), + desc: "CALLBACK updateTeamInfoPrivilege " + (error?.localizedDescription ?? "no error") + ) + weakSelf?.view.hideToastActivity() + if let err = error as? NSError { + if err.code == 408 { + weakSelf?.showToast(commonLocalizable("network_error")) + } else { + weakSelf?.showToast(err.localizedDescription) + } + } else { + weakSelf?.viewmodel.teamInfoModel?.team?.updateInfoMode = .manager + model.subTitle = localizable("team_owner") + weakSelf?.contentTable.reloadData() + } + } + } + + func updateTeamInfoAllAction(_ model: SettingCellModel) { + weak var weakSelf = self + weakSelf?.view.makeToastActivity(.center) + weakSelf?.viewmodel.repo + .updateTeamInfoPrivilege(.all, weakSelf?.teamId ?? "") { error in + NELog.infoLog( + ModuleName + " " + self.className(), + desc: "CALLBACK updateTeamInfoPrivilege " + (error?.localizedDescription ?? "no error") + ) + weakSelf?.view.hideToastActivity() + if let err = error as? NSError { + if err.code == 408 { + weakSelf?.showToast(commonLocalizable("network_error")) + } else { + weakSelf?.showToast(err.localizedDescription) + } + } else { + weakSelf?.viewmodel.teamInfoModel?.team?.updateInfoMode = .all + model.subTitle = localizable("team_all") + weakSelf?.contentTable.reloadData() + } + } + } + + open func didUpdateTeamInfoClick(_ model: SettingCellModel) { + weak var weakSelf = self + + let actionSheetController = UIAlertController( + title: nil, + message: nil, + preferredStyle: .actionSheet + ) + + let cancelActionButton = UIAlertAction(title: localizable("cancel"), style: .cancel) { _ in + print("Cancel") + } + cancelActionButton.setValue(UIColor.ne_darkText, forKey: "_titleTextColor") + actionSheetController.addAction(cancelActionButton) + + let manager = UIAlertAction(title: localizable("team_owner"), style: .default) { _ in + weakSelf?.updateTeamInfoOwnerAction(model) + } + manager.setValue(UIColor.ne_darkText, forKey: "_titleTextColor") + actionSheetController.addAction(manager) + + let all = UIAlertAction(title: localizable("team_all"), style: .default) { _ in + weakSelf?.updateTeamInfoAllAction(model) + } + all.setValue(UIColor.ne_darkText, forKey: "_titleTextColor") + actionSheetController.addAction(all) + + navigationController?.present(actionSheetController, animated: true, completion: nil) + } + + open func didClickChangeNick() {} + + open func didClickHistoryMessage() {} +} diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamUserCell.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamUserCell.swift similarity index 71% rename from NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamUserCell.swift rename to NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamUserCell.swift index e19a306a..27d04fa8 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamUserCell.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/NEBaseTeamUserCell.swift @@ -8,10 +8,9 @@ import NECommonKit import NIMSDK import NECoreIMKit import NECoreKit -import NETeamKit @objcMembers -public class TeamUserCell: UICollectionViewCell { +open class NEBaseTeamUserCell: UICollectionViewCell { var user: TeamMemberInfoModel? { didSet { if let name = user?.showNickInTeam() { @@ -32,7 +31,6 @@ public class TeamUserCell: UICollectionViewCell { header.translatesAutoresizingMaskIntoConstraints = false header.titleLabel.font = NEConstant.defaultTextFont(11.0) header.clipsToBounds = true - header.layer.cornerRadius = 16.0 return header }() @@ -41,17 +39,11 @@ public class TeamUserCell: UICollectionViewCell { setupUI() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) } func setupUI() { contentView.addSubview(userHeader) - NSLayoutConstraint.activate([ - userHeader.leftAnchor.constraint(equalTo: contentView.leftAnchor), - userHeader.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - userHeader.widthAnchor.constraint(equalToConstant: 32.0), - userHeader.heightAnchor.constraint(equalToConstant: 32.0), - ]) } } diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamSettingRightCustomCell.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamSettingRightCustomCell.swift index ff594ded..a1dd0039 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamSettingRightCustomCell.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamSettingRightCustomCell.swift @@ -6,7 +6,7 @@ import UIKit @objcMembers -public class TeamSettingRightCustomCell: TeamSettingSubtitleCell { +open class TeamSettingRightCustomCell: TeamSettingSubtitleCell { override public func awakeFromNib() { super.awakeFromNib() // Initialization code @@ -30,7 +30,7 @@ public class TeamSettingRightCustomCell: TeamSettingSubtitleCell { } } - override func setupUI() { + override open func setupUI() { super.setupUI() contentView.addSubview(customRightView) @@ -47,13 +47,13 @@ public class TeamSettingRightCustomCell: TeamSettingSubtitleCell { ) } - lazy var customRightView: UIButton = { + public lazy var customRightView: UIButton = { let btn = UIButton() btn.translatesAutoresizingMaskIntoConstraints = false return btn }() - func customRightViewClick() { + public func customRightViewClick() { if let block = model?.customViewClick { block() } diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamSettingSubtitleCell.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamSettingSubtitleCell.swift index 4ae2cc12..80fdf2f4 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamSettingSubtitleCell.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamSettingSubtitleCell.swift @@ -6,8 +6,8 @@ import UIKit @objcMembers -public class TeamSettingSubtitleCell: BaseTeamSettingCell { - var titleWidthAnchor: NSLayoutConstraint? +open class TeamSettingSubtitleCell: NEBaseTeamSettingCell { + public var titleWidthAnchor: NSLayoutConstraint? override public func awakeFromNib() { super.awakeFromNib() @@ -26,11 +26,11 @@ public class TeamSettingSubtitleCell: BaseTeamSettingCell { setupUI() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - func setupUI() { + open func setupUI() { contentView.addSubview(titleLabel) contentView.addSubview(subTitleLabel) contentView.addSubview(arrow) @@ -64,7 +64,7 @@ public class TeamSettingSubtitleCell: BaseTeamSettingCell { } } - lazy var subTitleLabel: UILabel = { + public lazy var subTitleLabel: UILabel = { let label = UILabel() label.textColor = UIColor(hexString: "0xA6ADB6") label.font = NEConstant.defaultTextFont(12.0) diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamSettingSwitchCell.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamSettingSwitchCell.swift deleted file mode 100644 index 9f6d3d3e..00000000 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/View/TeamSettingSwitchCell.swift +++ /dev/null @@ -1,66 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit - -@objcMembers -public class TeamSettingSwitchCell: BaseTeamSettingCell { - var tSwitch: UISwitch = { - let q = UISwitch() - q.translatesAutoresizingMaskIntoConstraints = false - q.onTintColor = NEConstant.hexRGB(0x337EFF) - return q - }() - - override public func awakeFromNib() { - super.awakeFromNib() - // Initialization code - } - - override public func setSelected(_ selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - - // Configure the view for the selected state - } - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - selectionStyle = .none - setupUI() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - - override public func configure(_ anyModel: Any) { - super.configure(anyModel) - if let open = model?.switchOpen { - tSwitch.isOn = open - } - } - - func setupUI() { - contentView.addSubview(titleLabel) - NSLayoutConstraint.activate([ - titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 36), - titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -84), - ]) - - contentView.addSubview(tSwitch) - NSLayoutConstraint.activate([ - tSwitch.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), - tSwitch.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -36), - ]) - tSwitch.addTarget(self, action: #selector(switchChange(_:)), for: .touchUpInside) - } - - func switchChange(_ s: UISwitch) { - if let block = model?.swichChange { - block(s.isOn) - } - } -} diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/ViewModel/TeamInfoViewModel.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/ViewModel/TeamInfoViewModel.swift index 8e8a0519..1d40b38a 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/ViewModel/TeamInfoViewModel.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/ViewModel/TeamInfoViewModel.swift @@ -3,7 +3,6 @@ // found in the LICENSE file. import Foundation -import NETeamKit import NIMSDK import NECoreIMKit diff --git a/NETeamUIKit/NETeamUIKit/Classes/Setting/ViewModel/TeamSettingViewModel.swift b/NETeamUIKit/NETeamUIKit/Classes/Setting/ViewModel/TeamSettingViewModel.swift index e237bdb4..9cba9d16 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/Setting/ViewModel/TeamSettingViewModel.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/Setting/ViewModel/TeamSettingViewModel.swift @@ -3,7 +3,6 @@ // found in the LICENSE file. import Foundation -import NETeamKit import NIMSDK import UIKit import NECoreIMKit @@ -14,7 +13,7 @@ protocol TeamSettingViewModelDelegate: NSObjectProtocol { func didUpdateTeamInfoClick(_ model: SettingCellModel) func didClickHistoryMessage() func didNeedRefreshUI() - func didError(_ error: Error) + func didError(_ error: NSError) func didClickMark() } @@ -101,7 +100,7 @@ public class TeamSettingViewModel: NSObject, NIMTeamManagerDelegate { if isOpen == true { // weakSelf?.repo.updateNoti(.all, tid) weakSelf?.repo.setTeamNotify(.all, tid) { error in - if let err = error { + if let err = error as? NSError { weakSelf?.delegate?.didNeedRefreshUI() weakSelf?.delegate?.didError(err) } else { @@ -111,7 +110,7 @@ public class TeamSettingViewModel: NSObject, NIMTeamManagerDelegate { } else { // weakSelf?.repo.updateNoti(.none, tid) weakSelf?.repo.setTeamNotify(.none, tid) { error in - if let err = error { + if let err = error as? NSError { weakSelf?.delegate?.didNeedRefreshUI() weakSelf?.delegate?.didError(err) } else { @@ -191,7 +190,7 @@ public class TeamSettingViewModel: NSObject, NIMTeamManagerDelegate { if let tid = weakSelf?.teamInfoModel?.team?.teamId { weakSelf?.repo.muteAllMembers(isOpen, tid) { error in print("update mute error : ", error as Any) - if let err = error { + if let err = error as? NSError { forbiddenWords.switchOpen = !isOpen weakSelf?.delegate?.didNeedRefreshUI() weakSelf?.delegate?.didError(err) diff --git a/NETeamUIKit/NETeamUIKit/Classes/TeamConstant.swift b/NETeamUIKit/NETeamUIKit/Classes/TeamConstant.swift index 63b196b1..3bcdcebd 100644 --- a/NETeamUIKit/NETeamUIKit/Classes/TeamConstant.swift +++ b/NETeamUIKit/NETeamUIKit/Classes/TeamConstant.swift @@ -7,17 +7,17 @@ import Foundation @_exported import NECoreKit @_exported import NECommonUIKit @_exported import NECommonKit -@_exported import NETeamKit +@_exported import NEChatKit @_exported import NECoreIMKit -let coreLoader = CoreLoader() +let coreLoader = CoreLoader() func localizable(_ key: String) -> String { coreLoader.localizable(key) } public let ModuleName = "NETeamUIKit" -// 创建群/邀请入群 人数限制 -public var peopleNumberLimit: UInt = 200 +// 邀请入群 选择人数限制 +public var inviteNumberLimit: Int = 200 enum NotificationName { static let leaveTeamBySelf = Notification.Name(rawValue: "team.leaveTeamBySelf") diff --git a/Podfile b/Podfile index a1d696fd..9700b56f 100644 --- a/Podfile +++ b/Podfile @@ -1,5 +1,5 @@ # Uncomment the next line to define a global platform for your project -# platform :ios, '9.0' + platform :ios, '11.0' source 'https://github.com/CocoaPods/Specs.git' target 'app' do @@ -10,31 +10,28 @@ target 'app' do pod 'YXLogin', '1.0.0' #可选UI库 - pod 'NEContactUIKit', '9.5.0' - pod 'NEConversationUIKit', '9.5.0' - pod 'NEChatUIKit', '9.5.0' - pod 'NETeamUIKit', '9.5.0' - - - #可选Kit库(和UIKit对应) - pod 'NEContactKit', '9.5.0' - pod 'NEConversationKit', '9.5.0' - pod 'NEChatKit', '9.5.0' - pod 'NETeamKit', '9.5.0' - - #基础kit库 - pod 'NECommonUIKit', '9.5.0' - pod 'NECommonKit', '9.5.0' - pod 'NECoreIMKit', '9.5.0' - pod 'NECoreKit', '9.5.0' - - #扩展库 - pod 'NEMapKit', '9.5.0' + pod 'NEContactUIKit', '9.6.0' + pod 'NEConversationUIKit', '9.6.0' + pod 'NEChatUIKit', '9.6.0' + pod 'NETeamUIKit', '9.6.0' + +# #可选Kit库(和UIKit对应) + pod 'NEChatKit', '9.6.0' + +# #基础kit库 + pod 'NECommonUIKit', '9.6.0' + pod 'NECommonKit', '9.6.0' + pod 'NECoreIMKit', '9.6.0' + pod 'NECoreKit', '9.6.0' + +# #扩展库 + pod 'NEMapKit', '9.6.0' #呼叫组件,音视频通话能力,需要开通 音视频2.0,可选,聊天一面会根据依赖初始化自动显示音视频通话入口 pod 'NERtcCallUIKit', '1.8.2' pod 'NERtcCallKit', '1.8.2' - pod 'NERtcSDK', '4.6.29' + pod 'NERtcSDK', '4.6.50' + # 如果需要查看UI部分源码请注释掉以上在线依赖,打开下面的本地依赖 # pod 'NEContactUIKit', :path => 'NEContactUIKit/NEContactUIKit.podspec' diff --git a/app.xcodeproj/project.pbxproj b/app.xcodeproj/project.pbxproj index f6c52f85..7fbb2d71 100644 --- a/app.xcodeproj/project.pbxproj +++ b/app.xcodeproj/project.pbxproj @@ -9,32 +9,50 @@ /* Begin PBXBuildFile section */ 39E9E27728D87E9800A11820 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 39E9E27528D87E9800A11820 /* Localizable.strings */; }; 4B3B9BE6277AFEE50091A74E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4B3B9BE4277AFEE50091A74E /* Main.storyboard */; }; - 4B3B9BE8277AFEE70091A74E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4B3B9BE7277AFEE70091A74E /* Assets.xcassets */; }; 4B3B9BEB277AFEE70091A74E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4B3B9BE9277AFEE70091A74E /* LaunchScreen.storyboard */; }; 8D94D1BFC1723D94D352756A /* Pods_app.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8ECED9A11CC9DB62207FC66 /* Pods_app.framework */; }; - 9EA2014127BE4B4800F8BBD0 /* AppKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EA2014027BE4B4800F8BBD0 /* AppKey.swift */; }; - DDFAAE8029BACE0B00834C08 /* NodeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE6229BACE0B00834C08 /* NodeViewModel.swift */; }; - DDFAAE8129BACE0B00834C08 /* MineSettingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE6329BACE0B00834C08 /* MineSettingViewModel.swift */; }; - DDFAAE8229BACE0B00834C08 /* PersonInfoViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE6429BACE0B00834C08 /* PersonInfoViewModel.swift */; }; - DDFAAE8329BACE0B00834C08 /* MessageRemindViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE6529BACE0B00834C08 /* MessageRemindViewModel.swift */; }; - DDFAAE8429BACE0B00834C08 /* IntroduceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE6629BACE0B00834C08 /* IntroduceViewModel.swift */; }; - DDFAAE8529BACE0B00834C08 /* MeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE6829BACE0B00834C08 /* MeViewController.swift */; }; - DDFAAE8629BACE0B00834C08 /* NEAboutWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE6929BACE0B00834C08 /* NEAboutWebViewController.swift */; }; - DDFAAE8829BACE0B00834C08 /* InputPersonInfoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE6B29BACE0B00834C08 /* InputPersonInfoController.swift */; }; - DDFAAE8929BACE0B00834C08 /* MineSettingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE6C29BACE0B00834C08 /* MineSettingViewController.swift */; }; - DDFAAE8A29BACE0B00834C08 /* MessageRemindViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE6D29BACE0B00834C08 /* MessageRemindViewController.swift */; }; - DDFAAE8B29BACE0B00834C08 /* NENodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE6E29BACE0B00834C08 /* NENodeViewController.swift */; }; - DDFAAE8C29BACE0B00834C08 /* PersonInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE6F29BACE0B00834C08 /* PersonInfoViewController.swift */; }; - DDFAAE8D29BACE0C00834C08 /* IntroduceBrandViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE7029BACE0B00834C08 /* IntroduceBrandViewController.swift */; }; - DDFAAE8E29BACE0C00834C08 /* MineTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE7229BACE0B00834C08 /* MineTableViewCell.swift */; }; - DDFAAE8F29BACE0C00834C08 /* BirthdayDatePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE7329BACE0B00834C08 /* BirthdayDatePickerView.swift */; }; - DDFAAE9029BACE0C00834C08 /* NodeSelectCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE7429BACE0B00834C08 /* NodeSelectCell.swift */; }; - DDFAAE9129BACE0C00834C08 /* VersionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE7529BACE0B00834C08 /* VersionCell.swift */; }; - DDFAAE9329BACE0C00834C08 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE7929BACE0B00834C08 /* ViewController.swift */; }; - DDFAAE9529BACE0C00834C08 /* NENavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE7B29BACE0B00834C08 /* NENavigationController.swift */; }; - DDFAAE9729BACE0C00834C08 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE7D29BACE0B00834C08 /* AppDelegate.swift */; }; - DDFAAE9829BACE0C00834C08 /* NETabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE7E29BACE0B00834C08 /* NETabBarController.swift */; }; - DDFAAE9F29BAFD1500834C08 /* NEUserHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDFAAE9E29BAFD1500834C08 /* NEUserHeaderView.swift */; }; + DD141DFC2A56ABFD0091318F /* Constant.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DC82A56ABFD0091318F /* Constant.swift */; }; + DD141DFD2A56ABFE0091318F /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DC92A56ABFD0091318F /* ViewController.swift */; }; + DD141DFF2A56ABFE0091318F /* NENavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DCB2A56ABFD0091318F /* NENavigationController.swift */; }; + DD141E012A56ABFE0091318F /* UIStyleManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DCD2A56ABFD0091318F /* UIStyleManager.swift */; }; + DD141E032A56ABFE0091318F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DCF2A56ABFD0091318F /* AppDelegate.swift */; }; + DD141E042A56ABFE0091318F /* NETabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DD02A56ABFD0091318F /* NETabBarController.swift */; }; + DD141E052A56ABFE0091318F /* AppKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DD12A56ABFD0091318F /* AppKey.swift */; }; + DD141E062A56ABFE0091318F /* CustomP2PChatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DD32A56ABFD0091318F /* CustomP2PChatViewController.swift */; }; + DD141E072A56ABFE0091318F /* CustomConversationListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DD42A56ABFD0091318F /* CustomConversationListViewController.swift */; }; + DD141E082A56ABFE0091318F /* CustomContactsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DD52A56ABFD0091318F /* CustomContactsViewController.swift */; }; + DD141E092A56ABFE0091318F /* CustomConversationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DD62A56ABFD0091318F /* CustomConversationController.swift */; }; + DD141E0A2A56ABFE0091318F /* CustomAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DD72A56ABFD0091318F /* CustomAttachment.swift */; }; + DD141E0B2A56ABFE0091318F /* CustomContactTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DD82A56ABFD0091318F /* CustomContactTableViewCell.swift */; }; + DD141E0C2A56ABFE0091318F /* CustomChatCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DD92A56ABFD0091318F /* CustomChatCell.swift */; }; + DD141E0D2A56ABFE0091318F /* CustomTopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DDA2A56ABFD0091318F /* CustomTopView.swift */; }; + DD141E0E2A56ABFE0091318F /* CustomConversationListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DDB2A56ABFD0091318F /* CustomConversationListCell.swift */; }; + DD141E102A56ABFE0091318F /* NodeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DE02A56ABFD0091318F /* NodeViewModel.swift */; }; + DD141E112A56ABFE0091318F /* MineSettingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DE12A56ABFD0091318F /* MineSettingViewModel.swift */; }; + DD141E122A56ABFE0091318F /* PersonInfoViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DE22A56ABFD0091318F /* PersonInfoViewModel.swift */; }; + DD141E132A56ABFE0091318F /* MessageRemindViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DE32A56ABFD0091318F /* MessageRemindViewModel.swift */; }; + DD141E142A56ABFE0091318F /* IntroduceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DE42A56ABFD0091318F /* IntroduceViewModel.swift */; }; + DD141E152A56ABFE0091318F /* MeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DE62A56ABFD0091318F /* MeViewController.swift */; }; + DD141E162A56ABFE0091318F /* StyleSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DE72A56ABFD0091318F /* StyleSelectionViewController.swift */; }; + DD141E172A56ABFE0091318F /* NEAboutWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DE82A56ABFD0091318F /* NEAboutWebViewController.swift */; }; + DD141E182A56ABFE0091318F /* NELoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DE92A56ABFD0091318F /* NELoginViewController.swift */; }; + DD141E192A56ABFE0091318F /* InputPersonInfoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DEA2A56ABFD0091318F /* InputPersonInfoController.swift */; }; + DD141E1A2A56ABFE0091318F /* MineSettingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DEB2A56ABFD0091318F /* MineSettingViewController.swift */; }; + DD141E1B2A56ABFE0091318F /* MessageRemindViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DEC2A56ABFD0091318F /* MessageRemindViewController.swift */; }; + DD141E1C2A56ABFE0091318F /* NENodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DED2A56ABFD0091318F /* NENodeViewController.swift */; }; + DD141E1D2A56ABFE0091318F /* PersonInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DEE2A56ABFD0091318F /* PersonInfoViewController.swift */; }; + DD141E1E2A56ABFE0091318F /* IntroduceBrandViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DEF2A56ABFD0091318F /* IntroduceBrandViewController.swift */; }; + DD141E1F2A56ABFE0091318F /* MineTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DF12A56ABFD0091318F /* MineTableViewCell.swift */; }; + DD141E202A56ABFE0091318F /* StyleSelectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DF22A56ABFD0091318F /* StyleSelectionCell.swift */; }; + DD141E212A56ABFE0091318F /* BirthdayDatePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DF32A56ABFD0091318F /* BirthdayDatePickerView.swift */; }; + DD141E222A56ABFE0091318F /* CustomTeamSettingRightCustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DF52A56ABFD0091318F /* CustomTeamSettingRightCustomCell.swift */; }; + DD141E232A56ABFE0091318F /* CustomTeamSettingSubtitleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DF62A56ABFD0091318F /* CustomTeamSettingSubtitleCell.swift */; }; + DD141E242A56ABFE0091318F /* CustomTeamArrowSettingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DF72A56ABFD0091318F /* CustomTeamArrowSettingCell.swift */; }; + DD141E252A56ABFE0091318F /* CustomTeamSettingHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DF82A56ABFD0091318F /* CustomTeamSettingHeaderCell.swift */; }; + DD141E262A56ABFE0091318F /* CustomTeamSettingSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DF92A56ABFD0091318F /* CustomTeamSettingSwitchCell.swift */; }; + DD141E272A56ABFE0091318F /* NodeSelectCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DFA2A56ABFD0091318F /* NodeSelectCell.swift */; }; + DD141E282A56ABFE0091318F /* VersionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD141DFB2A56ABFD0091318F /* VersionCell.swift */; }; + DDCE2A652A56BDB800E17751 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DDCE2A642A56BDB800E17751 /* Assets.xcassets */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -60,34 +78,52 @@ 39E9E27828D87EA000A11820 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; 4B3B9BDB277AFEE50091A74E /* app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = app.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4B3B9BE5277AFEE50091A74E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 4B3B9BE7277AFEE70091A74E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 4B3B9BEA277AFEE70091A74E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 9EA2014027BE4B4800F8BBD0 /* AppKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppKey.swift; sourceTree = ""; }; A9E4316D70F3EF2E6BD5E5CB /* Pods-app.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app.release.xcconfig"; path = "Target Support Files/Pods-app/Pods-app.release.xcconfig"; sourceTree = ""; }; B831F1EC5F2E309A7BB5582D /* Pods-app.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app.debug.xcconfig"; path = "Target Support Files/Pods-app/Pods-app.debug.xcconfig"; sourceTree = ""; }; D8ECED9A11CC9DB62207FC66 /* Pods_app.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_app.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - DDFAAE6229BACE0B00834C08 /* NodeViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NodeViewModel.swift; sourceTree = ""; }; - DDFAAE6329BACE0B00834C08 /* MineSettingViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MineSettingViewModel.swift; sourceTree = ""; }; - DDFAAE6429BACE0B00834C08 /* PersonInfoViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonInfoViewModel.swift; sourceTree = ""; }; - DDFAAE6529BACE0B00834C08 /* MessageRemindViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRemindViewModel.swift; sourceTree = ""; }; - DDFAAE6629BACE0B00834C08 /* IntroduceViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntroduceViewModel.swift; sourceTree = ""; }; - DDFAAE6829BACE0B00834C08 /* MeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeViewController.swift; sourceTree = ""; }; - DDFAAE6929BACE0B00834C08 /* NEAboutWebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NEAboutWebViewController.swift; sourceTree = ""; }; - DDFAAE6B29BACE0B00834C08 /* InputPersonInfoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputPersonInfoController.swift; sourceTree = ""; }; - DDFAAE6C29BACE0B00834C08 /* MineSettingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MineSettingViewController.swift; sourceTree = ""; }; - DDFAAE6D29BACE0B00834C08 /* MessageRemindViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRemindViewController.swift; sourceTree = ""; }; - DDFAAE6E29BACE0B00834C08 /* NENodeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NENodeViewController.swift; sourceTree = ""; }; - DDFAAE6F29BACE0B00834C08 /* PersonInfoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonInfoViewController.swift; sourceTree = ""; }; - DDFAAE7029BACE0B00834C08 /* IntroduceBrandViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntroduceBrandViewController.swift; sourceTree = ""; }; - DDFAAE7229BACE0B00834C08 /* MineTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MineTableViewCell.swift; sourceTree = ""; }; - DDFAAE7329BACE0B00834C08 /* BirthdayDatePickerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BirthdayDatePickerView.swift; sourceTree = ""; }; - DDFAAE7429BACE0B00834C08 /* NodeSelectCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NodeSelectCell.swift; sourceTree = ""; }; - DDFAAE7529BACE0B00834C08 /* VersionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionCell.swift; sourceTree = ""; }; - DDFAAE7929BACE0B00834C08 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; - DDFAAE7B29BACE0B00834C08 /* NENavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NENavigationController.swift; sourceTree = ""; }; - DDFAAE7D29BACE0B00834C08 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - DDFAAE7E29BACE0B00834C08 /* NETabBarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NETabBarController.swift; sourceTree = ""; }; - DDFAAE9E29BAFD1500834C08 /* NEUserHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NEUserHeaderView.swift; sourceTree = ""; }; + DD141DC82A56ABFD0091318F /* Constant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constant.swift; sourceTree = ""; }; + DD141DC92A56ABFD0091318F /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + DD141DCB2A56ABFD0091318F /* NENavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NENavigationController.swift; sourceTree = ""; }; + DD141DCD2A56ABFD0091318F /* UIStyleManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIStyleManager.swift; sourceTree = ""; }; + DD141DCF2A56ABFD0091318F /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + DD141DD02A56ABFD0091318F /* NETabBarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NETabBarController.swift; sourceTree = ""; }; + DD141DD12A56ABFD0091318F /* AppKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppKey.swift; sourceTree = ""; }; + DD141DD32A56ABFD0091318F /* CustomP2PChatViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomP2PChatViewController.swift; sourceTree = ""; }; + DD141DD42A56ABFD0091318F /* CustomConversationListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomConversationListViewController.swift; sourceTree = ""; }; + DD141DD52A56ABFD0091318F /* CustomContactsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomContactsViewController.swift; sourceTree = ""; }; + DD141DD62A56ABFD0091318F /* CustomConversationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomConversationController.swift; sourceTree = ""; }; + DD141DD72A56ABFD0091318F /* CustomAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomAttachment.swift; sourceTree = ""; }; + DD141DD82A56ABFD0091318F /* CustomContactTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomContactTableViewCell.swift; sourceTree = ""; }; + DD141DD92A56ABFD0091318F /* CustomChatCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomChatCell.swift; sourceTree = ""; }; + DD141DDA2A56ABFD0091318F /* CustomTopView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomTopView.swift; sourceTree = ""; }; + DD141DDB2A56ABFD0091318F /* CustomConversationListCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomConversationListCell.swift; sourceTree = ""; }; + DD141DE02A56ABFD0091318F /* NodeViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NodeViewModel.swift; sourceTree = ""; }; + DD141DE12A56ABFD0091318F /* MineSettingViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MineSettingViewModel.swift; sourceTree = ""; }; + DD141DE22A56ABFD0091318F /* PersonInfoViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonInfoViewModel.swift; sourceTree = ""; }; + DD141DE32A56ABFD0091318F /* MessageRemindViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRemindViewModel.swift; sourceTree = ""; }; + DD141DE42A56ABFD0091318F /* IntroduceViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntroduceViewModel.swift; sourceTree = ""; }; + DD141DE62A56ABFD0091318F /* MeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeViewController.swift; sourceTree = ""; }; + DD141DE72A56ABFD0091318F /* StyleSelectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StyleSelectionViewController.swift; sourceTree = ""; }; + DD141DE82A56ABFD0091318F /* NEAboutWebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NEAboutWebViewController.swift; sourceTree = ""; }; + DD141DE92A56ABFD0091318F /* NELoginViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NELoginViewController.swift; sourceTree = ""; }; + DD141DEA2A56ABFD0091318F /* InputPersonInfoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputPersonInfoController.swift; sourceTree = ""; }; + DD141DEB2A56ABFD0091318F /* MineSettingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MineSettingViewController.swift; sourceTree = ""; }; + DD141DEC2A56ABFD0091318F /* MessageRemindViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRemindViewController.swift; sourceTree = ""; }; + DD141DED2A56ABFD0091318F /* NENodeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NENodeViewController.swift; sourceTree = ""; }; + DD141DEE2A56ABFD0091318F /* PersonInfoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonInfoViewController.swift; sourceTree = ""; }; + DD141DEF2A56ABFD0091318F /* IntroduceBrandViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntroduceBrandViewController.swift; sourceTree = ""; }; + DD141DF12A56ABFD0091318F /* MineTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MineTableViewCell.swift; sourceTree = ""; }; + DD141DF22A56ABFD0091318F /* StyleSelectionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StyleSelectionCell.swift; sourceTree = ""; }; + DD141DF32A56ABFD0091318F /* BirthdayDatePickerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BirthdayDatePickerView.swift; sourceTree = ""; }; + DD141DF52A56ABFD0091318F /* CustomTeamSettingRightCustomCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomTeamSettingRightCustomCell.swift; sourceTree = ""; }; + DD141DF62A56ABFD0091318F /* CustomTeamSettingSubtitleCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomTeamSettingSubtitleCell.swift; sourceTree = ""; }; + DD141DF72A56ABFD0091318F /* CustomTeamArrowSettingCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomTeamArrowSettingCell.swift; sourceTree = ""; }; + DD141DF82A56ABFD0091318F /* CustomTeamSettingHeaderCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomTeamSettingHeaderCell.swift; sourceTree = ""; }; + DD141DF92A56ABFD0091318F /* CustomTeamSettingSwitchCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomTeamSettingSwitchCell.swift; sourceTree = ""; }; + DD141DFA2A56ABFD0091318F /* NodeSelectCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NodeSelectCell.swift; sourceTree = ""; }; + DD141DFB2A56ABFD0091318F /* VersionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionCell.swift; sourceTree = ""; }; + DDCE2A642A56BDB800E17751 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -131,13 +167,13 @@ 4B3B9BDD277AFEE50091A74E /* app */ = { isa = PBXGroup; children = ( - DDFAAE7829BACE0B00834C08 /* Main */, - DDFAAE6029BACE0B00834C08 /* Mine */, + DDCE2A642A56BDB800E17751 /* Assets.xcassets */, + DD141DD22A56ABFD0091318F /* Custom */, + DD141DC62A56ABFD0091318F /* Main */, + DD141DDE2A56ABFD0091318F /* Mine */, 01B0A28E2816CF41009065C5 /* app.entitlements */, - 9EA2014027BE4B4800F8BBD0 /* AppKey.swift */, 39E9E27528D87E9800A11820 /* Localizable.strings */, 4B3B9BE4277AFEE50091A74E /* Main.storyboard */, - 4B3B9BE7277AFEE70091A74E /* Assets.xcassets */, 4B3B9BE9277AFEE70091A74E /* LaunchScreen.storyboard */, ); path = app; @@ -152,64 +188,98 @@ path = Pods; sourceTree = ""; }; - DDFAAE6029BACE0B00834C08 /* Mine */ = { + DD141DC62A56ABFD0091318F /* Main */ = { isa = PBXGroup; children = ( - DDFAAE6129BACE0B00834C08 /* ViewModel */, - DDFAAE6729BACE0B00834C08 /* Controller */, - DDFAAE7129BACE0B00834C08 /* View */, + DD141DC82A56ABFD0091318F /* Constant.swift */, + DD141DC92A56ABFD0091318F /* ViewController.swift */, + DD141DCB2A56ABFD0091318F /* NENavigationController.swift */, + DD141DCD2A56ABFD0091318F /* UIStyleManager.swift */, + DD141DCF2A56ABFD0091318F /* AppDelegate.swift */, + DD141DD02A56ABFD0091318F /* NETabBarController.swift */, + DD141DD12A56ABFD0091318F /* AppKey.swift */, + ); + path = Main; + sourceTree = ""; + }; + DD141DD22A56ABFD0091318F /* Custom */ = { + isa = PBXGroup; + children = ( + DD141DD32A56ABFD0091318F /* CustomP2PChatViewController.swift */, + DD141DD42A56ABFD0091318F /* CustomConversationListViewController.swift */, + DD141DD52A56ABFD0091318F /* CustomContactsViewController.swift */, + DD141DD62A56ABFD0091318F /* CustomConversationController.swift */, + DD141DD72A56ABFD0091318F /* CustomAttachment.swift */, + DD141DD82A56ABFD0091318F /* CustomContactTableViewCell.swift */, + DD141DD92A56ABFD0091318F /* CustomChatCell.swift */, + DD141DDA2A56ABFD0091318F /* CustomTopView.swift */, + DD141DDB2A56ABFD0091318F /* CustomConversationListCell.swift */, + ); + path = Custom; + sourceTree = ""; + }; + DD141DDE2A56ABFD0091318F /* Mine */ = { + isa = PBXGroup; + children = ( + DD141DDF2A56ABFD0091318F /* ViewModel */, + DD141DE52A56ABFD0091318F /* Controller */, + DD141DF02A56ABFD0091318F /* View */, ); path = Mine; sourceTree = ""; }; - DDFAAE6129BACE0B00834C08 /* ViewModel */ = { + DD141DDF2A56ABFD0091318F /* ViewModel */ = { isa = PBXGroup; children = ( - DDFAAE6229BACE0B00834C08 /* NodeViewModel.swift */, - DDFAAE6329BACE0B00834C08 /* MineSettingViewModel.swift */, - DDFAAE6429BACE0B00834C08 /* PersonInfoViewModel.swift */, - DDFAAE6529BACE0B00834C08 /* MessageRemindViewModel.swift */, - DDFAAE6629BACE0B00834C08 /* IntroduceViewModel.swift */, + DD141DE02A56ABFD0091318F /* NodeViewModel.swift */, + DD141DE12A56ABFD0091318F /* MineSettingViewModel.swift */, + DD141DE22A56ABFD0091318F /* PersonInfoViewModel.swift */, + DD141DE32A56ABFD0091318F /* MessageRemindViewModel.swift */, + DD141DE42A56ABFD0091318F /* IntroduceViewModel.swift */, ); path = ViewModel; sourceTree = ""; }; - DDFAAE6729BACE0B00834C08 /* Controller */ = { + DD141DE52A56ABFD0091318F /* Controller */ = { isa = PBXGroup; children = ( - DDFAAE6829BACE0B00834C08 /* MeViewController.swift */, - DDFAAE6929BACE0B00834C08 /* NEAboutWebViewController.swift */, - DDFAAE6B29BACE0B00834C08 /* InputPersonInfoController.swift */, - DDFAAE6C29BACE0B00834C08 /* MineSettingViewController.swift */, - DDFAAE6D29BACE0B00834C08 /* MessageRemindViewController.swift */, - DDFAAE6E29BACE0B00834C08 /* NENodeViewController.swift */, - DDFAAE6F29BACE0B00834C08 /* PersonInfoViewController.swift */, - DDFAAE7029BACE0B00834C08 /* IntroduceBrandViewController.swift */, + DD141DE62A56ABFD0091318F /* MeViewController.swift */, + DD141DE72A56ABFD0091318F /* StyleSelectionViewController.swift */, + DD141DE82A56ABFD0091318F /* NEAboutWebViewController.swift */, + DD141DE92A56ABFD0091318F /* NELoginViewController.swift */, + DD141DEA2A56ABFD0091318F /* InputPersonInfoController.swift */, + DD141DEB2A56ABFD0091318F /* MineSettingViewController.swift */, + DD141DEC2A56ABFD0091318F /* MessageRemindViewController.swift */, + DD141DED2A56ABFD0091318F /* NENodeViewController.swift */, + DD141DEE2A56ABFD0091318F /* PersonInfoViewController.swift */, + DD141DEF2A56ABFD0091318F /* IntroduceBrandViewController.swift */, ); path = Controller; sourceTree = ""; }; - DDFAAE7129BACE0B00834C08 /* View */ = { + DD141DF02A56ABFD0091318F /* View */ = { isa = PBXGroup; children = ( - DDFAAE9E29BAFD1500834C08 /* NEUserHeaderView.swift */, - DDFAAE7229BACE0B00834C08 /* MineTableViewCell.swift */, - DDFAAE7329BACE0B00834C08 /* BirthdayDatePickerView.swift */, - DDFAAE7429BACE0B00834C08 /* NodeSelectCell.swift */, - DDFAAE7529BACE0B00834C08 /* VersionCell.swift */, + DD141DF12A56ABFD0091318F /* MineTableViewCell.swift */, + DD141DF22A56ABFD0091318F /* StyleSelectionCell.swift */, + DD141DF32A56ABFD0091318F /* BirthdayDatePickerView.swift */, + DD141DF42A56ABFD0091318F /* Theme */, + DD141DFA2A56ABFD0091318F /* NodeSelectCell.swift */, + DD141DFB2A56ABFD0091318F /* VersionCell.swift */, ); path = View; sourceTree = ""; }; - DDFAAE7829BACE0B00834C08 /* Main */ = { + DD141DF42A56ABFD0091318F /* Theme */ = { isa = PBXGroup; children = ( - DDFAAE7929BACE0B00834C08 /* ViewController.swift */, - DDFAAE7B29BACE0B00834C08 /* NENavigationController.swift */, - DDFAAE7D29BACE0B00834C08 /* AppDelegate.swift */, - DDFAAE7E29BACE0B00834C08 /* NETabBarController.swift */, + DD141DF52A56ABFD0091318F /* CustomTeamSettingRightCustomCell.swift */, + DD141DF62A56ABFD0091318F /* CustomTeamSettingSubtitleCell.swift */, + DD141DF72A56ABFD0091318F /* CustomTeamArrowSettingCell.swift */, + DD141DF82A56ABFD0091318F /* CustomTeamSettingHeaderCell.swift */, + DD141DF92A56ABFD0091318F /* CustomTeamSettingSwitchCell.swift */, ); - path = Main; + path = Theme; sourceTree = ""; }; /* End PBXGroup section */ @@ -279,7 +349,7 @@ files = ( 4B3B9BEB277AFEE70091A74E /* LaunchScreen.storyboard in Resources */, 39E9E27728D87E9800A11820 /* Localizable.strings in Resources */, - 4B3B9BE8277AFEE70091A74E /* Assets.xcassets in Resources */, + DDCE2A652A56BDB800E17751 /* Assets.xcassets in Resources */, 4B3B9BE6277AFEE50091A74E /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -350,29 +420,47 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - DDFAAE8129BACE0B00834C08 /* MineSettingViewModel.swift in Sources */, - DDFAAE8A29BACE0B00834C08 /* MessageRemindViewController.swift in Sources */, - DDFAAE8529BACE0B00834C08 /* MeViewController.swift in Sources */, - DDFAAE8929BACE0B00834C08 /* MineSettingViewController.swift in Sources */, - DDFAAE8D29BACE0C00834C08 /* IntroduceBrandViewController.swift in Sources */, - DDFAAE8029BACE0B00834C08 /* NodeViewModel.swift in Sources */, - DDFAAE9829BACE0C00834C08 /* NETabBarController.swift in Sources */, - DDFAAE8C29BACE0B00834C08 /* PersonInfoViewController.swift in Sources */, - DDFAAE8F29BACE0C00834C08 /* BirthdayDatePickerView.swift in Sources */, - DDFAAE8B29BACE0B00834C08 /* NENodeViewController.swift in Sources */, - 9EA2014127BE4B4800F8BBD0 /* AppKey.swift in Sources */, - DDFAAE8829BACE0B00834C08 /* InputPersonInfoController.swift in Sources */, - DDFAAE9729BACE0C00834C08 /* AppDelegate.swift in Sources */, - DDFAAE8629BACE0B00834C08 /* NEAboutWebViewController.swift in Sources */, - DDFAAE9129BACE0C00834C08 /* VersionCell.swift in Sources */, - DDFAAE8229BACE0B00834C08 /* PersonInfoViewModel.swift in Sources */, - DDFAAE8429BACE0B00834C08 /* IntroduceViewModel.swift in Sources */, - DDFAAE9F29BAFD1500834C08 /* NEUserHeaderView.swift in Sources */, - DDFAAE8E29BACE0C00834C08 /* MineTableViewCell.swift in Sources */, - DDFAAE9329BACE0C00834C08 /* ViewController.swift in Sources */, - DDFAAE8329BACE0B00834C08 /* MessageRemindViewModel.swift in Sources */, - DDFAAE9029BACE0C00834C08 /* NodeSelectCell.swift in Sources */, - DDFAAE9529BACE0C00834C08 /* NENavigationController.swift in Sources */, + DD141E1A2A56ABFE0091318F /* MineSettingViewController.swift in Sources */, + DD141E142A56ABFE0091318F /* IntroduceViewModel.swift in Sources */, + DD141E262A56ABFE0091318F /* CustomTeamSettingSwitchCell.swift in Sources */, + DD141E222A56ABFE0091318F /* CustomTeamSettingRightCustomCell.swift in Sources */, + DD141E062A56ABFE0091318F /* CustomP2PChatViewController.swift in Sources */, + DD141E092A56ABFE0091318F /* CustomConversationController.swift in Sources */, + DD141E1E2A56ABFE0091318F /* IntroduceBrandViewController.swift in Sources */, + DD141E182A56ABFE0091318F /* NELoginViewController.swift in Sources */, + DD141E202A56ABFE0091318F /* StyleSelectionCell.swift in Sources */, + DD141E1D2A56ABFE0091318F /* PersonInfoViewController.swift in Sources */, + DD141E162A56ABFE0091318F /* StyleSelectionViewController.swift in Sources */, + DD141DFD2A56ABFE0091318F /* ViewController.swift in Sources */, + DD141E082A56ABFE0091318F /* CustomContactsViewController.swift in Sources */, + DD141E0B2A56ABFE0091318F /* CustomContactTableViewCell.swift in Sources */, + DD141E192A56ABFE0091318F /* InputPersonInfoController.swift in Sources */, + DD141DFF2A56ABFE0091318F /* NENavigationController.swift in Sources */, + DD141E0C2A56ABFE0091318F /* CustomChatCell.swift in Sources */, + DD141E242A56ABFE0091318F /* CustomTeamArrowSettingCell.swift in Sources */, + DD141E0A2A56ABFE0091318F /* CustomAttachment.swift in Sources */, + DD141E172A56ABFE0091318F /* NEAboutWebViewController.swift in Sources */, + DD141E132A56ABFE0091318F /* MessageRemindViewModel.swift in Sources */, + DD141E032A56ABFE0091318F /* AppDelegate.swift in Sources */, + DD141E102A56ABFE0091318F /* NodeViewModel.swift in Sources */, + DD141E122A56ABFE0091318F /* PersonInfoViewModel.swift in Sources */, + DD141E1B2A56ABFE0091318F /* MessageRemindViewController.swift in Sources */, + DD141E282A56ABFE0091318F /* VersionCell.swift in Sources */, + DD141E052A56ABFE0091318F /* AppKey.swift in Sources */, + DD141E0D2A56ABFE0091318F /* CustomTopView.swift in Sources */, + DD141E232A56ABFE0091318F /* CustomTeamSettingSubtitleCell.swift in Sources */, + DD141E152A56ABFE0091318F /* MeViewController.swift in Sources */, + DD141E252A56ABFE0091318F /* CustomTeamSettingHeaderCell.swift in Sources */, + DD141E0E2A56ABFE0091318F /* CustomConversationListCell.swift in Sources */, + DD141E012A56ABFE0091318F /* UIStyleManager.swift in Sources */, + DD141E212A56ABFE0091318F /* BirthdayDatePickerView.swift in Sources */, + DD141E042A56ABFE0091318F /* NETabBarController.swift in Sources */, + DD141E1C2A56ABFE0091318F /* NENodeViewController.swift in Sources */, + DD141E1F2A56ABFE0091318F /* MineTableViewCell.swift in Sources */, + DD141DFC2A56ABFD0091318F /* Constant.swift in Sources */, + DD141E112A56ABFE0091318F /* MineSettingViewModel.swift in Sources */, + DD141E072A56ABFE0091318F /* CustomConversationListViewController.swift in Sources */, + DD141E272A56ABFE0091318F /* NodeSelectCell.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -464,7 +552,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -521,7 +609,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -562,7 +650,7 @@ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UIUserInterfaceStyle = Light; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -611,7 +699,7 @@ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UIUserInterfaceStyle = Light; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/app/Assets.xcassets/Mine/clicked_fun.imageset/Contents.json b/app/Assets.xcassets/Mine/clicked_fun.imageset/Contents.json new file mode 100644 index 00000000..ea2e4827 --- /dev/null +++ b/app/Assets.xcassets/Mine/clicked_fun.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "clicked_we@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "clicked_we@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/app/Assets.xcassets/Mine/clicked_fun.imageset/clicked_we@2x.png b/app/Assets.xcassets/Mine/clicked_fun.imageset/clicked_we@2x.png new file mode 100644 index 00000000..f69ac913 Binary files /dev/null and b/app/Assets.xcassets/Mine/clicked_fun.imageset/clicked_we@2x.png differ diff --git a/app/Assets.xcassets/Mine/clicked_fun.imageset/clicked_we@3x.png b/app/Assets.xcassets/Mine/clicked_fun.imageset/clicked_we@3x.png new file mode 100644 index 00000000..75777604 Binary files /dev/null and b/app/Assets.xcassets/Mine/clicked_fun.imageset/clicked_we@3x.png differ diff --git a/app/Assets.xcassets/Mine/clicked_normal.imageset/Contents.json b/app/Assets.xcassets/Mine/clicked_normal.imageset/Contents.json new file mode 100644 index 00000000..96d9d42e --- /dev/null +++ b/app/Assets.xcassets/Mine/clicked_normal.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "clicked_feishu@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "clicked_feishu@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/app/Assets.xcassets/Mine/clicked_normal.imageset/clicked_feishu@2x.png b/app/Assets.xcassets/Mine/clicked_normal.imageset/clicked_feishu@2x.png new file mode 100644 index 00000000..c17da8fd Binary files /dev/null and b/app/Assets.xcassets/Mine/clicked_normal.imageset/clicked_feishu@2x.png differ diff --git a/app/Assets.xcassets/Mine/clicked_normal.imageset/clicked_feishu@3x.png b/app/Assets.xcassets/Mine/clicked_normal.imageset/clicked_feishu@3x.png new file mode 100644 index 00000000..c82c3c6c Binary files /dev/null and b/app/Assets.xcassets/Mine/clicked_normal.imageset/clicked_feishu@3x.png differ diff --git a/app/Assets.xcassets/Mine/style_fun.imageset/Contents.json b/app/Assets.xcassets/Mine/style_fun.imageset/Contents.json new file mode 100644 index 00000000..258ad124 --- /dev/null +++ b/app/Assets.xcassets/Mine/style_fun.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "style_wechat@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "style_wechat@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/app/Assets.xcassets/Mine/style_fun.imageset/style_wechat@2x.png b/app/Assets.xcassets/Mine/style_fun.imageset/style_wechat@2x.png new file mode 100644 index 00000000..2a79612f Binary files /dev/null and b/app/Assets.xcassets/Mine/style_fun.imageset/style_wechat@2x.png differ diff --git a/app/Assets.xcassets/Mine/style_fun.imageset/style_wechat@3x.png b/app/Assets.xcassets/Mine/style_fun.imageset/style_wechat@3x.png new file mode 100644 index 00000000..e1f2cc9d Binary files /dev/null and b/app/Assets.xcassets/Mine/style_fun.imageset/style_wechat@3x.png differ diff --git a/app/Assets.xcassets/Mine/style_normal.imageset/Contents.json b/app/Assets.xcassets/Mine/style_normal.imageset/Contents.json new file mode 100644 index 00000000..601e29f1 --- /dev/null +++ b/app/Assets.xcassets/Mine/style_normal.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "style_feishu@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "style_feishu@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/app/Assets.xcassets/Mine/style_normal.imageset/style_feishu@2x.png b/app/Assets.xcassets/Mine/style_normal.imageset/style_feishu@2x.png new file mode 100644 index 00000000..b3442e7a Binary files /dev/null and b/app/Assets.xcassets/Mine/style_normal.imageset/style_feishu@2x.png differ diff --git a/app/Assets.xcassets/Mine/style_normal.imageset/style_feishu@3x.png b/app/Assets.xcassets/Mine/style_normal.imageset/style_feishu@3x.png new file mode 100644 index 00000000..883b00bb Binary files /dev/null and b/app/Assets.xcassets/Mine/style_normal.imageset/style_feishu@3x.png differ diff --git a/app/Assets.xcassets/Mine/unclicked.imageset/Contents.json b/app/Assets.xcassets/Mine/unclicked.imageset/Contents.json new file mode 100644 index 00000000..ee3cdf0b --- /dev/null +++ b/app/Assets.xcassets/Mine/unclicked.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "unclicked_we@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "unclicked_we@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/app/Assets.xcassets/Mine/unclicked.imageset/unclicked_we@2x.png b/app/Assets.xcassets/Mine/unclicked.imageset/unclicked_we@2x.png new file mode 100644 index 00000000..3db25bad Binary files /dev/null and b/app/Assets.xcassets/Mine/unclicked.imageset/unclicked_we@2x.png differ diff --git a/app/Assets.xcassets/Mine/unclicked.imageset/unclicked_we@3x.png b/app/Assets.xcassets/Mine/unclicked.imageset/unclicked_we@3x.png new file mode 100644 index 00000000..c737ba13 Binary files /dev/null and b/app/Assets.xcassets/Mine/unclicked.imageset/unclicked_we@3x.png differ diff --git a/app/Assets.xcassets/Tabbar/funChat.imageset/Contents.json b/app/Assets.xcassets/Tabbar/funChat.imageset/Contents.json new file mode 100644 index 00000000..5c4d3b18 --- /dev/null +++ b/app/Assets.xcassets/Tabbar/funChat.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/app/Assets.xcassets/Tabbar/funChat.imageset/Frame@2x.png b/app/Assets.xcassets/Tabbar/funChat.imageset/Frame@2x.png new file mode 100644 index 00000000..d12d4c26 Binary files /dev/null and b/app/Assets.xcassets/Tabbar/funChat.imageset/Frame@2x.png differ diff --git a/app/Assets.xcassets/Tabbar/funChat.imageset/Frame@3x.png b/app/Assets.xcassets/Tabbar/funChat.imageset/Frame@3x.png new file mode 100644 index 00000000..8d9b46d3 Binary files /dev/null and b/app/Assets.xcassets/Tabbar/funChat.imageset/Frame@3x.png differ diff --git a/app/Assets.xcassets/Tabbar/funChatSelect.imageset/Contents.json b/app/Assets.xcassets/Tabbar/funChatSelect.imageset/Contents.json new file mode 100644 index 00000000..5c4d3b18 --- /dev/null +++ b/app/Assets.xcassets/Tabbar/funChatSelect.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/app/Assets.xcassets/Tabbar/funChatSelect.imageset/Frame@2x.png b/app/Assets.xcassets/Tabbar/funChatSelect.imageset/Frame@2x.png new file mode 100644 index 00000000..fe856088 Binary files /dev/null and b/app/Assets.xcassets/Tabbar/funChatSelect.imageset/Frame@2x.png differ diff --git a/app/Assets.xcassets/Tabbar/funChatSelect.imageset/Frame@3x.png b/app/Assets.xcassets/Tabbar/funChatSelect.imageset/Frame@3x.png new file mode 100644 index 00000000..9578ffae Binary files /dev/null and b/app/Assets.xcassets/Tabbar/funChatSelect.imageset/Frame@3x.png differ diff --git a/app/Assets.xcassets/Tabbar/funContact.imageset/Contents.json b/app/Assets.xcassets/Tabbar/funContact.imageset/Contents.json new file mode 100644 index 00000000..16f6ffc9 --- /dev/null +++ b/app/Assets.xcassets/Tabbar/funContact.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2X.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3X.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/app/Assets.xcassets/Tabbar/funContact.imageset/Frame@2X.png b/app/Assets.xcassets/Tabbar/funContact.imageset/Frame@2X.png new file mode 100644 index 00000000..6b2cbaa2 Binary files /dev/null and b/app/Assets.xcassets/Tabbar/funContact.imageset/Frame@2X.png differ diff --git a/app/Assets.xcassets/Tabbar/funContact.imageset/Frame@3X.png b/app/Assets.xcassets/Tabbar/funContact.imageset/Frame@3X.png new file mode 100644 index 00000000..e9196574 Binary files /dev/null and b/app/Assets.xcassets/Tabbar/funContact.imageset/Frame@3X.png differ diff --git a/app/Assets.xcassets/Tabbar/funContactSelect.imageset/Contents.json b/app/Assets.xcassets/Tabbar/funContactSelect.imageset/Contents.json new file mode 100644 index 00000000..5c4d3b18 --- /dev/null +++ b/app/Assets.xcassets/Tabbar/funContactSelect.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/app/Assets.xcassets/Tabbar/funContactSelect.imageset/Frame@2x.png b/app/Assets.xcassets/Tabbar/funContactSelect.imageset/Frame@2x.png new file mode 100644 index 00000000..394d6b37 Binary files /dev/null and b/app/Assets.xcassets/Tabbar/funContactSelect.imageset/Frame@2x.png differ diff --git a/app/Assets.xcassets/Tabbar/funContactSelect.imageset/Frame@3x.png b/app/Assets.xcassets/Tabbar/funContactSelect.imageset/Frame@3x.png new file mode 100644 index 00000000..c2eb45aa Binary files /dev/null and b/app/Assets.xcassets/Tabbar/funContactSelect.imageset/Frame@3x.png differ diff --git a/app/Assets.xcassets/Tabbar/funPerson.imageset/Contents.json b/app/Assets.xcassets/Tabbar/funPerson.imageset/Contents.json new file mode 100644 index 00000000..4a327cc7 --- /dev/null +++ b/app/Assets.xcassets/Tabbar/funPerson.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3X.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/app/Assets.xcassets/Tabbar/funPerson.imageset/Frame@2x.png b/app/Assets.xcassets/Tabbar/funPerson.imageset/Frame@2x.png new file mode 100644 index 00000000..3e18a349 Binary files /dev/null and b/app/Assets.xcassets/Tabbar/funPerson.imageset/Frame@2x.png differ diff --git a/app/Assets.xcassets/Tabbar/funPerson.imageset/Frame@3X.png b/app/Assets.xcassets/Tabbar/funPerson.imageset/Frame@3X.png new file mode 100644 index 00000000..c439fa99 Binary files /dev/null and b/app/Assets.xcassets/Tabbar/funPerson.imageset/Frame@3X.png differ diff --git a/app/Assets.xcassets/Tabbar/funPersonSelect.imageset/Contents.json b/app/Assets.xcassets/Tabbar/funPersonSelect.imageset/Contents.json new file mode 100644 index 00000000..5c4d3b18 --- /dev/null +++ b/app/Assets.xcassets/Tabbar/funPersonSelect.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/app/Assets.xcassets/Tabbar/funPersonSelect.imageset/Frame@2x.png b/app/Assets.xcassets/Tabbar/funPersonSelect.imageset/Frame@2x.png new file mode 100644 index 00000000..1a8ca455 Binary files /dev/null and b/app/Assets.xcassets/Tabbar/funPersonSelect.imageset/Frame@2x.png differ diff --git a/app/Assets.xcassets/Tabbar/funPersonSelect.imageset/Frame@3x.png b/app/Assets.xcassets/Tabbar/funPersonSelect.imageset/Frame@3x.png new file mode 100644 index 00000000..fb921248 Binary files /dev/null and b/app/Assets.xcassets/Tabbar/funPersonSelect.imageset/Frame@3x.png differ diff --git a/app/Custom/CustomAttachment.swift b/app/Custom/CustomAttachment.swift new file mode 100644 index 00000000..b56b869e --- /dev/null +++ b/app/Custom/CustomAttachment.swift @@ -0,0 +1,70 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NIMSDK +import NEChatUIKit +public class CustomAttachment: NSObject, NIMCustomAttachment, NECustomAttachmentProtocol { + public var customType: Int = 0 + + public var cellHeight: CGFloat = 0 + + public var type = 0 + + public var goodsName = "name" + + public var goodsURL = "url" + + public func encode() -> String { + let info = ["goodsName": goodsName, "goodsURL": goodsURL, "type": type] as [String: Any] + + let jsonData = try? JSONSerialization.data(withJSONObject: info, options: .prettyPrinted) + var content = "" + if let data = jsonData { + content = String(data: data, encoding: .utf8) ?? "" + } + return content + } +} + +public class CustomAttachmentDecoder: NSObject, NIMCustomAttachmentCoding { + public func decodeAttachment(_ content: String?) -> NIMCustomAttachment? { + var attachment: NIMCustomAttachment? + let data = content?.data(using: .utf8) + guard let dataInfo = data else { + return attachment + } + + let infoDict = try? JSONSerialization.jsonObject( + with: dataInfo, + options: .mutableContainers + ) + let infoResult = infoDict as? [String: Any] + let type = infoResult?["type"] as? Int + + switch type { + case 0: + attachment = + decodeCustomMessage(info: infoDict as? [String: Any] ?? [String(): String()]) + default: + print("test") + } + + return attachment + } + + func decodeCustomMessage(info: [String: Any]) -> CustomAttachment { + let customAttachment = CustomAttachment() + customAttachment.goodsName = info["goodsName"] as? String ?? "" + customAttachment.goodsURL = info["goodsURL"] as? String ?? "" + if let type = info["type"] as? Int { + customAttachment.type = type + } + customAttachment.customType = 20 + customAttachment.cellHeight = 50 + + return customAttachment + } +} diff --git a/app/Custom/CustomChatCell.swift b/app/Custom/CustomChatCell.swift new file mode 100644 index 00000000..f70da02b --- /dev/null +++ b/app/Custom/CustomChatCell.swift @@ -0,0 +1,43 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NEChatUIKit +class CustomChatCell: NEChatBaseCell { + public var testLabel = UILabel() + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + selectionStyle = .none + backgroundColor = .clear + testLabel.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(testLabel) + NSLayoutConstraint.activate([ + testLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), + testLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + ]) + testLabel.font = UIFont.systemFont(ofSize: 14) + testLabel.textColor = UIColor.black + } + + override func setModel(_ model: MessageContentModel) { + print("this is custom message") + testLabel.text = "this is custom message" + } +} diff --git a/app/Custom/CustomContactTableViewCell.swift b/app/Custom/CustomContactTableViewCell.swift new file mode 100644 index 00000000..ee4da8ff --- /dev/null +++ b/app/Custom/CustomContactTableViewCell.swift @@ -0,0 +1,36 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import NEContactUIKit + +public class CustomContactTableViewCell: ContactTableViewCell { + private lazy var onlineView: UIImageView = { + let notify = UIImageView() + notify.translatesAutoresizingMaskIntoConstraints = false + notify.image = UIImage(named: "about_yunxin") + notify.isHidden = true + return notify + }() + + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + contentView.addSubview(onlineView) + NSLayoutConstraint.activate([ + onlineView.rightAnchor.constraint(equalTo: avatarImage.rightAnchor), + onlineView.bottomAnchor.constraint(equalTo: avatarImage.bottomAnchor), + onlineView.widthAnchor.constraint(equalToConstant: 12), + onlineView.heightAnchor.constraint(equalToConstant: 12), + ]) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override public func setModel(_ model: ContactInfo) { + super.setModel(model) + onlineView.isHidden = false + } +} diff --git a/app/Custom/CustomContactsViewController.swift b/app/Custom/CustomContactsViewController.swift new file mode 100644 index 00000000..be658e57 --- /dev/null +++ b/app/Custom/CustomContactsViewController.swift @@ -0,0 +1,70 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import NEContactUIKit + +public class CustomContactsViewController: ContactsViewController, ContactsViewControllerDelegate { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + delegate = self + customCells[ContactCellType.ContactCutom.rawValue] = CustomContactTableViewCell.self + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override public func viewDidLoad() { + // 通过配置项实现自定义 + configCustom() + + super.viewDidLoad() + let view = UIView(frame: CGRect(x: 0, y: 0, width: NEConstant.screenWidth, height: 40)) + view.backgroundColor = .blue + topView.addSubview(view) + } + + func configCustom() { + /// 头像圆角大小 + NEKitContactConfig.shared.ui.avatarCornerRadius = 4.0 + + /// 头像类型 + NEKitContactConfig.shared.ui.avatarType = .rectangle + + // 通讯录标题大小 + NEKitContactConfig.shared.ui.titleFont = .systemFont(ofSize: 28) + + /// 通讯录标题颜色 + NEKitContactConfig.shared.ui.titleColor = UIColor.red + + /// 是否隐藏通讯录搜索按钮 + NEKitContactConfig.shared.ui.hiddenSearchBtn = true + + /// 是否把顶部添加好友和搜索按钮都隐藏 + NEKitContactConfig.shared.ui.hiddenRightBtns = false + + /// 通讯录间隔线颜色 + NEKitContactConfig.shared.ui.divideLineColor = UIColor.blue + + /// 检索标题字体颜色 + NEKitContactConfig.shared.ui.indexTitleColor = .green + } + + @objc private func addItemAction() { + print("addItemAction") + topViewHeight = 80 + } + + @objc private func searchItemAction() { + print("searchItemAction") + topViewHeight = 0 + } + + public func onDataLoaded() { + viewModel.contacts[1].contacts.forEach { info in + info.contactCellType = ContactCellType.ContactCutom.rawValue + } + } +} diff --git a/app/Custom/CustomConversationController.swift b/app/Custom/CustomConversationController.swift new file mode 100644 index 00000000..2b188701 --- /dev/null +++ b/app/Custom/CustomConversationController.swift @@ -0,0 +1,106 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import NEConversationUIKit + +open class CustomConversationController: ConversationController { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + listCtrl = CustomConversationListViewController() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override public func viewDidLoad() { + // 通过配置项实现自定义 + configCustom() + + // 实现协议(重写tabbar点击事件) + navView.delegate = self + + // 自定义会话列表标题、图标、间距 + navView.brandBtn.setTitle("消息", for: .normal) + navView.brandBtn.setImage(nil, for: .normal) + navView.brandBtn.layoutButtonImage(style: .left, space: 0) + + // 自定义tabbar图标 + navView.addBtn.setImage(UIImage.ne_imageNamed(name: "noNeed_notify"), for: .normal) + + // 顶部topView中添加自定义view(需要设置topView的高度) + let view = CustomTopView(frame: CGRect(x: 0, y: 0, width: NEConstant.screenWidth, height: 40)) + view.backgroundColor = .blue +// listCtrl.topViewHeight = 40 + listCtrl.topView.addSubview(view) + + // 自定义占位图文案、背景图片 + listCtrl.emptyView.setEmptyImage(image: UIImage()) + listCtrl.emptyView.settingContent(content: "") + + viewmodel.repo.clearAllUnreadCount() + + super.viewDidLoad() + } + + open func configCustom() { + /// 头像圆角大小 + NEKitConversationConfig.shared.ui.avatarCornerRadius = 4.0 + + /// 头像类型 + NEKitConversationConfig.shared.ui.avatarType = .rectangle + + /// 是否隐藏导航栏 +// NEKitConversationConfig.shared.ui.hiddenNav = true + + /// 是否隐藏搜索按钮 + NEKitConversationConfig.shared.ui.hiddenSearchBtn = true + +// / 是否把顶部添加按钮和搜索按钮都隐藏 +// NEKitConversationConfig.shared.ui.hiddenRightBtns = true + + // 主标题字体大小 + NEKitConversationConfig.shared.ui.titleFont = .systemFont(ofSize: 24) + + // 副标题字体大小 + NEKitConversationConfig.shared.ui.subTitleFont = .systemFont(ofSize: 18) + + // 主标题字体颜色 + NEKitConversationConfig.shared.ui.titleColor = UIColor.red + + // 副标题字体颜色 + NEKitConversationConfig.shared.ui.subTitleColor = UIColor.blue + + /// 时间字体颜色 + NEKitConversationConfig.shared.ui.timeColor = UIColor.green + + /// 时间字体大小 + NEKitConversationConfig.shared.ui.timeFont = UIFont.systemFont(ofSize: 14) + + /// 会话列表 cell 左划置顶按钮文案内容 + NEKitConversationConfig.shared.ui.stickTopBottonTitle = "文案" + /// 会话列表 cell 左划取消置顶按钮文案内容 + NEKitConversationConfig.shared.ui.stickTopBottonCancelTitle = "文案1" + /// 会话列表 cell 左划置顶按钮文案颜色 + NEKitConversationConfig.shared.ui.stickTopBottonColor = UIColor.yellow + + /// 会话列表 cell 左划删除按钮文案内容 + NEKitConversationConfig.shared.ui.deleteBottonTitle = "文案2" + /// 会话列表 cell 左划删除按钮文案颜色 + NEKitConversationConfig.shared.ui.deleteBottonColor = UIColor.gray + } + + // 重写搜索按钮点击事件 + override open func searchAction() { + listCtrl.topViewHeight = 80 + } + + // 重写添加按钮点击事件 + override open func didClickAddBtn() { + showSingleAlert(message: "override didClickAddBtn") { + self.listCtrl.topViewHeight = 0 + } + } +} diff --git a/app/Custom/CustomConversationListCell.swift b/app/Custom/CustomConversationListCell.swift new file mode 100644 index 00000000..1d171be7 --- /dev/null +++ b/app/Custom/CustomConversationListCell.swift @@ -0,0 +1,36 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NEConversationUIKit + +open class CustomConversationListCell: ConversationListCell { + private lazy var onlineView: UIImageView = { + let notify = UIImageView() + notify.translatesAutoresizingMaskIntoConstraints = false + notify.image = UIImage(named: "about_yunxin") + return notify + }() + + override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + contentView.addSubview(onlineView) + NSLayoutConstraint.activate([ + onlineView.rightAnchor.constraint(equalTo: headImge.rightAnchor), + onlineView.bottomAnchor.constraint(equalTo: headImge.bottomAnchor), + onlineView.widthAnchor.constraint(equalToConstant: 12), + onlineView.heightAnchor.constraint(equalToConstant: 12), + ]) + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func configData(sessionModel: ConversationListModel?) { + super.configData(sessionModel: sessionModel) +// subTitle.text = "[自定义类型文案]" + } +} diff --git a/app/Custom/CustomConversationListViewController.swift b/app/Custom/CustomConversationListViewController.swift new file mode 100644 index 00000000..840bb128 --- /dev/null +++ b/app/Custom/CustomConversationListViewController.swift @@ -0,0 +1,44 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import NEConversationUIKit + +open class CustomConversationListViewController: ConversationListViewController, ConversationListViewControllerDelegate { + override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + delegate = self + + // 自定义cell, [ConversationListModel.customType: 需要注册的自定义cell] + registerCellDic[1] = CustomConversationListCell.self + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override open func viewDidLoad() { + super.viewDidLoad() + } + + override open func deleteActionHandler(action: UITableViewRowAction?, indexPath: IndexPath) { + showSingleAlert(message: "override deleteActionHandler") {} + } + + override open func topActionHandler(action: UITableViewRowAction?, indexPath: IndexPath, isTop: Bool) { + showSingleAlert(message: "override topActionHandler") { + super.topActionHandler(action: action, indexPath: indexPath, isTop: isTop) + } + } + + // 可自行处理数据 + public func onDataLoaded() { + guard let conversationList = viewModel.conversationListArray else { return + } + conversationList.forEach { model in + model.customType = 1 + } + tableView.reloadData() + } +} diff --git a/app/Custom/CustomP2PChatViewController.swift b/app/Custom/CustomP2PChatViewController.swift new file mode 100644 index 00000000..6452dfa4 --- /dev/null +++ b/app/Custom/CustomP2PChatViewController.swift @@ -0,0 +1,214 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NEChatUIKit +import NIMSDK +class CustomP2PChatViewController: P2PChatViewController { + override func viewDidLoad() { +// NEKitChatConfig.shared.ui.avatarType = .rectangle +// NEKitChatConfig.shared.ui.avatarCornerRadius = 8.0 +// NEKitChatConfig.shared.ui.signalBgColor = UIColor.ne_backcolor +// NEKitChatConfig.shared.ui.selfMessageBg = UIColor.ne_greenText +// NEKitChatConfig.shared.ui.receiveMessageBg = UIColor.ne_greenText +// NEKitChatConfig.shared.ui.timeTextColor = UIColor.ne_redText +// NEKitChatConfig.shared.ui.timeTextSize = 18 +// NEKitChatConfig.shared.ui.userNickColor = UIColor.ne_redText +// NEKitChatConfig.shared.ui.userNickTextSize = 8.0 +// NEKitChatConfig.shared.ui.messageTextColor = UIColor.ne_redColor +// NEKitChatConfig.shared.ui.messageTextSize = UIFont.systemFont(ofSize: 12) +// NEKitChatConfig.shared.ui.rightBubbleBg = UIImage(named: "copy_right") +// NEKitChatConfig.shared.ui.leftBubbleBg = UIImage(named: "copy_right") +// NEKitChatConfig.shared.ui.showP2pMessageStatus = false +// NEKitChatConfig.shared.ui.showTeamMessageStatus = false +// NEKitChatConfig.shared.ui.showTitleBar = false +// NEKitChatConfig.shared.ui.showTitleBarRightIcon = false +// NEKitChatConfig.shared.ui.titleBarRightRes = UIImage(named: "copy_right") +// NEKitChatConfig.shared.ui.titleBarRightClick = {[weak self] in +// self?.showToast("dfnaskfnas") +// } +// NEKitChatConfig.shared.ui.chatViewBackground = UIColor.ne_redText + + /* + // 聊天面板外部扩展示例 + // 新增未知类型 + let itemNew = NEMoreItemModel() + itemNew.customImage = UIImage(named: "mine_collection") + itemNew.customDelegate = self + itemNew.action = #selector(testLog) + itemNew.title = "新增" + NEChatUIKitClient.instance.moreAction.append(itemNew) + + // 覆盖已有类型 + // 遍历 NEChatUIKitClient.instance.moreAction, 根据type 覆盖已有类型 + for (i, item) in NEChatUIKitClient.instance.moreAction.enumerated() { + if item.type == .rtc { + let itemReplace = NEChatUIKitClient.instance.moreAction[i] + itemReplace.customImage = UIImage(named: "mine_setting") + itemReplace.customDelegate = self + itemReplace.action = #selector(testLog) + itemReplace.type = .rtc + itemReplace.title = "覆盖" + } + } + + // 移除已有类型 + // 遍历 NEChatUIKitClient.instance.moreAction, 根据type 移除已有类型 + for (i, item) in NEChatUIKitClient.instance.moreAction.enumerated() { + if item.type == .file { + NEChatUIKitClient.instance.moreAction.remove(at: i) + } + } + @objc func testLog() { + print("聊天面板外部扩展示例") + } + + */ + + // 输入框上区域扩展视图示例 + /* + inputTopExtendHeight = 20 + let topCustom = UIView() + topCustom.translatesAutoresizingMaskIntoConstraints = false + topCustom.backgroundColor = UIColor.yellow + inputTopExtendView.addSubview(topCustom) + NSLayoutConstraint.activate([ + topCustom.leftAnchor.constraint(equalTo: inputTopExtendView.leftAnchor), + topCustom.rightAnchor.constraint(equalTo: inputTopExtendView.rightAnchor), + topCustom.topAnchor.constraint(equalTo: inputTopExtendView.topAnchor), + topCustom.bottomAnchor.constraint(equalTo: inputTopExtendView.bottomAnchor) + ]) + */ + + // 聊天页顶部导航栏下方扩展视图示例 + /* + navigationBarBottomExtendHeight = 20 + let bottomCustom = UIView() + bottomCustom.translatesAutoresizingMaskIntoConstraints = false + bottomCustom.backgroundColor = UIColor.yellow + navigationBarBottomExtendView.addSubview(bottomCustom) + NSLayoutConstraint.activate([ + bottomCustom.leftAnchor.constraint(equalTo: navigationBarBottomExtendView.leftAnchor), + bottomCustom.rightAnchor.constraint(equalTo: navigationBarBottomExtendView.rightAnchor), + bottomCustom.topAnchor.constraint(equalTo: navigationBarBottomExtendView.topAnchor), + bottomCustom.bottomAnchor.constraint(equalTo: navigationBarBottomExtendView.bottomAnchor), + ]) */ + + // 自定义消息以及外部扩展 覆盖cell UI 样式示例 + // 注册自定义消息的解析器 + /* + NIMCustomObject.registerCustomDecoder(CustomAttachmentDecoder()) + NEChatUIKitClient.instance.regsiterCustomCell(["20": CustomChatCell.self]) + + // 测试自定义消息发送按钮 + let testBtn = UIButton() + testBtn.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(testBtn) + NSLayoutConstraint.activate([ + testBtn.widthAnchor.constraint(equalToConstant: 100), + testBtn.heightAnchor.constraint(equalToConstant: 40), + testBtn.centerXAnchor.constraint(equalTo: view.centerXAnchor), + testBtn.centerYAnchor.constraint(equalTo: view.centerYAnchor), + ]) + testBtn.backgroundColor = UIColor.red + testBtn.addTarget(self, action: #selector(sendCustomButton), for: .touchUpInside) + */ + + super.viewDidLoad() + + // 聊天页输入框左右间距自定义 + /* + menuView.textviewLeftConstraint?.constant = 100 + menuView.textviewRightConstraint?.constant = -100 + */ + + // 自定义底部工具条(未点击更多状态) + /* + customBottomBar() + */ + + // 长按消息功能弹窗过滤列表(过滤列表中的能力会在整个页面中禁用) + /* + operationCellFilter = [.delete, .copy] + */ + + // Do any additional setup after loading the view. + } + + // 自定义标题 +// override func getSessionInfo(session: NIMSession) { +// super.getSessionInfo(session: session) +// title = "小易助手" +// } + + // 长按消息功能弹窗列表自定义(可针对不同 type 消息自定义长按功能项) +// override func setOperationItems(items: inout [OperationItem], model: MessageContentModel?) { +// if model?.type == .rtcCallRecord { +// items.append(OperationItem.deleteItem()) +// } +// } + + @objc func testLog() { + print("聊天面板外部扩展示例") + } + + func customBottomBar() { + let subviews = menuView.stackView.subviews + subviews.forEach { view in + view.removeFromSuperview() + menuView.stackView.removeArrangedSubview(view) + } + + let titles = ["表情", "语音", "照片", "更多"] + for i in 0 ..< titles.count { + let button = UIButton(type: .custom) + let title = titles[i] + button.translatesAutoresizingMaskIntoConstraints = false + button.addTarget(self, action: #selector(buttonEvent), for: .touchUpInside) + button.tag = i + button.setTitle(title, for: .normal) + button.setTitleColor(.blue, for: .normal) + menuView.stackView.addArrangedSubview(button) + } + } + + @objc func buttonEvent(_ btn: UIButton) { + if btn.tag == 0 { // 表情 + layoutInputView(offset: bottomExanpndHeight) + menuView.addEmojiView() + } else if btn.tag == 1 { // 语音 + layoutInputView(offset: bottomExanpndHeight) + menuView.addRecordView() + } else if btn.tag == 2 { // 照片 + goPhotoAlbumWithVideo(self) + } else if btn.tag == 3 { // 更多 + layoutInputView(offset: bottomExanpndHeight) + menuView.addMoreActionView() + } + } + + @objc func sendCustomButton() { + let attachment = CustomAttachment() + attachment.customType = 20 + attachment.cellHeight = 50 + let message = NIMMessage() + let object = NIMCustomObject() + object.attachment = attachment + message.messageObject = object + + NIMSDK.shared().chatManager.send(message, to: viewmodel.session) { error in + print("send custom message error : ", error?.localizedDescription as Any) + } + } + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destination. + // Pass the selected object to the new view controller. + } + */ +} diff --git a/app/Custom/CustomTopView.swift b/app/Custom/CustomTopView.swift new file mode 100644 index 00000000..c52747f6 --- /dev/null +++ b/app/Custom/CustomTopView.swift @@ -0,0 +1,31 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import UIKit + +public class CustomTopView: UIView { + override public init(frame: CGRect) { + super.init(frame: frame) +// let tap = UITapGestureRecognizer(target: self, action: #selector(tapView)) +// addGestureRecognizer(tap) + let btn = UIButton() + btn.translatesAutoresizingMaskIntoConstraints = false + btn.addTarget(self, action: #selector(tapView), for: .touchUpInside) + btn.backgroundColor = .red + addSubview(btn) + NSLayoutConstraint.activate([ + btn.topAnchor.constraint(equalTo: topAnchor), + btn.leftAnchor.constraint(equalTo: leftAnchor), + btn.rightAnchor.constraint(equalTo: rightAnchor), + btn.bottomAnchor.constraint(equalTo: bottomAnchor), + ]) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc func tapView() {} +} diff --git a/app/Main/AppDelegate.swift b/app/Main/AppDelegate.swift index cfab6d18..641ee855 100644 --- a/app/Main/AppDelegate.swift +++ b/app/Main/AppDelegate.swift @@ -22,10 +22,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD private var tabbarCtrl = UITabBarController() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - window?.backgroundColor = .white setupInit() NotificationCenter.default.addObserver(self, selector: #selector(refreshRoot), name: Notification.Name("logout"), object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(refreshUIStyle), name: Notification.Name(CHANGE_UI), object: nil) registerAPNS() return true } @@ -38,27 +38,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD option.appKey = AppKey.appKey option.apnsCername = AppKey.pushCerName IMKitClient.instance.setupCoreKitIM(option) - - NEKeyboardManager.shared.enable = true - NEKeyboardManager.shared.shouldResignOnTouchOutside = true - // 登录IM之前先初始化 @ 消息监听mananger - let _ = NEAtMessageManager.instance + let account = "<#account#>" + let token = "<#token#>" weak var weakSelf = self - IMKitClient.instance.loginIM("<#accid#>", "<#token#>") { error in + IMKitClient.instance.loginIM(account, token) { error in if let err = error { - print("NEKitCore login error : ", err) + print("login error in app : ", err.localizedDescription) }else { + let _ = NEAtMessageManager.instance ChatRouter.setupInit() weakSelf?.initializePage() } } + } @objc func refreshRoot(){ print("refresh root") - + //loginWithUI() + } + + @objc func refreshUIStyle(){ + initializePage() } func registerAPNS(){ @@ -100,34 +103,55 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD // regist router func loadService() { - //TODO: service + ContactRouter.register() ChatRouter.register() TeamRouter.register() ConversationRouter.register() + if NEStyleManager.instance.isNormalStyle() == false { + ContactRouter.registerFun() + ChatRouter.registerFun() + TeamRouter.registerFun() + ConversationRouter.registerFun() + } + + // 自定义示例 + customVerification() //地图map初始化 NEMapClient.shared().setupMapClient(withAppkey: AppKey.gaodeMapAppkey) /* 聊天面板外部扩展示例 + // 新增未知类型 let item = NEMoreItemModel() item.customDelegate = self item.action = #selector(testLog) item.customImage = UIImage(named: "chatSelect") NEChatUIKitClient.instance.moreAction.append(item) + + // 覆盖已有类型 + let item = NEMoreItemModel() + item.customImage = UIImage(named: "chatSelect") + item.type = .rtc + item.title = "测试" + NEChatUIKitClient.instance.moreAction.append(item) + + // 移除已有类型 + // 遍历 NEChatUIKitClient.instance.moreAction, 根据type 移除已有类型 */ //呼叫组件初始化 let option = NERtcCallOptions() option.apnsCerName = AppKey.pushCerName option.isDisableLog = true + option.supportAutoJoinWhenCalled = false let uiConfig = NERtcCallUIConfig() uiConfig.option = option uiConfig.appKey = AppKey.appKey uiConfig.uiConfig.showCallingSwitchCallType = option.supportAutoJoinWhenCalled NERtcCallKit.sharedInstance().timeOutSeconds = 30 NERtcCallUIKit.sharedInstance().setup(with: uiConfig) - + Router.shared.register(MeSettingRouter) { param in if let nav = param["nav"] as? UINavigationController { let me = PersonInfoViewController() @@ -140,5 +164,44 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD return .portrait } + func customVerification(){ + if NEStyleManager.instance.isNormalStyle() { + Router.shared.register(PushP2pChatVCRouter) { param in + print("param:\(param)") + let nav = param["nav"] as? UINavigationController + guard let session = param["session"] as? NIMSession else { + return + } + let anchor = param["anchor"] as? NIMMessage + var p2pChatVC = P2PChatViewController(session: session, anchor: anchor) + for (i, vc) in (nav?.viewControllers ?? []).enumerated() { + if vc.isKind(of: ChatViewController.self) { + nav?.viewControllers[i] = p2pChatVC + nav?.popToViewController(p2pChatVC, animated: true) + return + } + } + nav?.pushViewController(p2pChatVC, animated: true) + } + } else { + Router.shared.register(PushP2pChatVCRouter) { param in + print("param:\(param)") + let nav = param["nav"] as? UINavigationController + guard let session = param["session"] as? NIMSession else { + return + } + let anchor = param["anchor"] as? NIMMessage + var p2pChatVC = FunP2PChatViewController(session: session, anchor: anchor) + for (i, vc) in (nav?.viewControllers ?? []).enumerated() { + if vc.isKind(of: ChatViewController.self) { + nav?.viewControllers[i] = p2pChatVC + nav?.popToViewController(p2pChatVC, animated: true) + return + } + } + nav?.pushViewController(p2pChatVC, animated: true) + } + } + } } diff --git a/app/AppKey.swift b/app/Main/AppKey.swift similarity index 82% rename from app/AppKey.swift rename to app/Main/AppKey.swift index 7270e7bb..234281af 100644 --- a/app/AppKey.swift +++ b/app/Main/AppKey.swift @@ -1,8 +1,8 @@ -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be found in the LICENSE file. +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. -import Foundation public struct AppKey { #if DEBUG public static let pushCerName = "<#请输入推送证书#>" diff --git a/app/Main/Constant.swift b/app/Main/Constant.swift new file mode 100644 index 00000000..4e903734 --- /dev/null +++ b/app/Main/Constant.swift @@ -0,0 +1,8 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation + +let IMUIKit_Style_Key = "imuikit_style_key" +let CHANGE_UI = "change_ui" diff --git a/app/Main/NETabBarController.swift b/app/Main/NETabBarController.swift index ba6c56a8..bb20aca2 100644 --- a/app/Main/NETabBarController.swift +++ b/app/Main/NETabBarController.swift @@ -26,39 +26,85 @@ class NETabBarController: UITabBarController { } func setUpControllers() { - // chat - let chat = ConversationController() - chat.view.backgroundColor = UIColor(hexString: "#e9eff5") - chat.tabBarItem = UITabBarItem( - title: NSLocalizedString("message", comment: ""), - image: UIImage(named: "chat"), - selectedImage: UIImage(named: "chatSelect")?.withRenderingMode(.alwaysOriginal) - ) - let chatNav = NENavigationController(rootViewController: chat) - - // Contacts - let contactVC = ContactsViewController() - contactVC.tabBarItem = UITabBarItem( - title: NSLocalizedString("contact", comment: ""), - image: UIImage(named: "contact"), - selectedImage: UIImage(named: "contactSelect")?.withRenderingMode(.alwaysOriginal) - ) - contactVC.title = NSLocalizedString("contact", comment: "") - let contactsNav = NENavigationController(rootViewController: contactVC) - - // Me - let meVC = MeViewController() - meVC.view.backgroundColor = UIColor.white - meVC.tabBarItem = UITabBarItem( - title: NSLocalizedString("mine", comment: ""), - image: UIImage(named: "person"), - selectedImage: UIImage(named: "personSelect")?.withRenderingMode(.alwaysOriginal) - ) - let meNav = NENavigationController(rootViewController: meVC) - - tabBar.backgroundColor = .white - viewControllers = [chatNav, contactsNav, meNav] - selectedIndex = 0 + if NEStyleManager.instance.isNormalStyle() { + // chat + let chat = ConversationController() + chat.tabBarItem = UITabBarItem( + title: NSLocalizedString("message", comment: ""), + image: UIImage(named: "chat"), + selectedImage: UIImage(named: "chatSelect")?.withRenderingMode(.alwaysOriginal) + ) + let chatNav = NENavigationController(rootViewController: chat) + + // Contacts + let contactVC = ContactsViewController() + contactVC.tabBarItem = UITabBarItem( + title: NSLocalizedString("contact", comment: ""), + image: UIImage(named: "contact"), + selectedImage: UIImage(named: "contactSelect")?.withRenderingMode(.alwaysOriginal) + ) + let contactsNav = NENavigationController(rootViewController: contactVC) + + // Me + let meVC = MeViewController() + meVC.view.backgroundColor = UIColor.white + meVC.tabBarItem = UITabBarItem( + title: NSLocalizedString("mine", comment: ""), + image: UIImage(named: "person"), + selectedImage: UIImage(named: "personSelect")?.withRenderingMode(.alwaysOriginal) + ) + let meNav = NENavigationController(rootViewController: meVC) + + tabBar.backgroundColor = .white + viewControllers = [chatNav, contactsNav, meNav] + selectedIndex = 0 + + if #available(iOS 13.0, *) { + let appearance = UITabBarAppearance() + appearance.stackedLayoutAppearance.selected.titleTextAttributes = [.foregroundColor: UIColor(hexString: "#337EFF")] + tabBar.standardAppearance = appearance + } + } else { + // chat + let chat = FunConversationController() + chat.tabBarItem = UITabBarItem( + title: NSLocalizedString("message", comment: ""), + image: UIImage(named: "funChat"), + selectedImage: UIImage(named: "funChatSelect")?.withRenderingMode(.alwaysOriginal) + ) + setFunStyleColor(chat.tabBarItem) + let chatNav = NENavigationController(rootViewController: chat) + + // Contacts + let contactVC = FunContactsViewController() + contactVC.tabBarItem = UITabBarItem( + title: NSLocalizedString("contact", comment: ""), + image: UIImage(named: "funContact"), + selectedImage: UIImage(named: "funContactSelect")?.withRenderingMode(.alwaysOriginal) + ) + setFunStyleColor(contactVC.tabBarItem) + let contactsNav = NENavigationController(rootViewController: contactVC) + + // Me + let meVC = MeViewController() + meVC.tabBarItem = UITabBarItem( + title: NSLocalizedString("mine", comment: ""), + image: UIImage(named: "funPerson"), + selectedImage: UIImage(named: "funPersonSelect")?.withRenderingMode(.alwaysOriginal) + ) + setFunStyleColor(meVC.tabBarItem) + let meNav = NENavigationController(rootViewController: meVC) + + tabBar.backgroundColor = .white + viewControllers = [chatNav, contactsNav, meNav] + selectedIndex = 0 + + if #available(iOS 13.0, *) { + let appearance = UITabBarAppearance() + appearance.stackedLayoutAppearance.selected.titleTextAttributes = [.foregroundColor: UIColor(hexString: "#58BE6B")] + tabBar.standardAppearance = appearance + } + } } func setUpSessionBadgeValue() { @@ -83,6 +129,10 @@ class NETabBarController: UITabBarController { setUpSessionBadgeValue() } + private func setFunStyleColor(_ item: UITabBarItem) { + item.setTitleTextAttributes([.foregroundColor: UIColor(hexString: "#58BE6B")], for: .selected) + } + deinit { NIMSDK.shared().systemNotificationManager.remove(self) NIMSDK.shared().conversationManager.remove(self) diff --git a/app/Main/UIStyleManager.swift b/app/Main/UIStyleManager.swift new file mode 100644 index 00000000..898cccea --- /dev/null +++ b/app/Main/UIStyleManager.swift @@ -0,0 +1,27 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import Foundation +import NEChatUIKit + +class NEStyleManager { + static let instance = NEStyleManager() + let userDefault = UserDefaults.standard + public func isNormalStyle() -> Bool { + if let style = userDefault.object(forKey: IMUIKit_Style_Key) as? NSNumber, style.intValue == 2 { + return false + } + return true + } + + public func setNormalStyle() { + userDefault.set(NSNumber(integerLiteral: 1), forKey: IMUIKit_Style_Key) + userDefault.synchronize() + } + + public func setFunStyle() { + userDefault.set(NSNumber(integerLiteral: 2), forKey: IMUIKit_Style_Key) + userDefault.synchronize() + } +} diff --git a/app/Mine/Controller/InputPersonInfoController.swift b/app/Mine/Controller/InputPersonInfoController.swift index de711202..3e40695c 100644 --- a/app/Mine/Controller/InputPersonInfoController.swift +++ b/app/Mine/Controller/InputPersonInfoController.swift @@ -28,54 +28,66 @@ class InputPersonInfoController: NEBaseViewController, UITextFieldDelegate { super.viewDidLoad() setupSubviews() initialConfig() + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: DispatchWorkItem(block: { [weak self] in + self?.textField.becomeFirstResponder() + })) } func setupSubviews() { view.addSubview(textfieldBgView) - if #available(iOS 11.0, *) { + textfieldBgView.addSubview(textField) + + if NEStyleManager.instance.isNormalStyle() { NSLayoutConstraint.activate([ textfieldBgView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20.0), textfieldBgView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), - textfieldBgView.topAnchor.constraint( - equalTo: view.safeAreaLayoutGuide.topAnchor, - constant: 12 - ), + textfieldBgView.topAnchor.constraint(equalTo: view.topAnchor, constant: 12 + kNavigationHeight + KStatusBarHeight), textfieldBgView.heightAnchor.constraint(equalToConstant: 50), ]) + } else { - if #available(iOS 10.0, *) { - NSLayoutConstraint.activate([ - textfieldBgView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20.0), - textfieldBgView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), - textfieldBgView.topAnchor.constraint(equalTo: view.topAnchor, constant: 12), - textfieldBgView.heightAnchor.constraint(equalToConstant: 50), - ]) - } else { - NSLayoutConstraint.activate([ - textfieldBgView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20.0), - textfieldBgView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), - textfieldBgView.topAnchor.constraint(equalTo: view.topAnchor, constant: 12 + kNavigationHeight + KStatusBarHeight), - textfieldBgView.heightAnchor.constraint(equalToConstant: 50), - ]) - } + NSLayoutConstraint.activate([ + textfieldBgView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0), + textfieldBgView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0), + textfieldBgView.topAnchor.constraint(equalTo: view.topAnchor, constant: 12 + kNavigationHeight + KStatusBarHeight), + textfieldBgView.heightAnchor.constraint(equalToConstant: 50), + ]) + textfieldBgView.layer.cornerRadius = 0 } - - textfieldBgView.addSubview(textField) NSLayoutConstraint.activate([ textField.leftAnchor.constraint(equalTo: textfieldBgView.leftAnchor, constant: 16), textField.rightAnchor.constraint(equalTo: textfieldBgView.rightAnchor, constant: -12), - textField.topAnchor.constraint(equalTo: textfieldBgView.topAnchor, constant: 0), - textField.heightAnchor.constraint(equalToConstant: 44), + textField.centerYAnchor.constraint(equalTo: textfieldBgView.centerYAnchor), ]) } func initialConfig() { addRightAction(NSLocalizedString("save", comment: ""), #selector(saveName), self) - view.backgroundColor = UIColor(hexString: "0xF1F1F6") + + view.backgroundColor = NEStyleManager.instance.isNormalStyle() ? UIColor(hexString: "#EFF1F4") : UIColor(hexString: "#EDEDED") + customNavigationView.setMoreButtonTitle(NSLocalizedString("save", comment: "")) + customNavigationView.addMoreButtonTarget(target: self, selector: #selector(saveName)) + + if NEStyleManager.instance.isNormalStyle() { + view.backgroundColor = .ne_backgroundColor + customNavigationView.backgroundColor = .ne_backgroundColor + navigationController?.navigationBar.backgroundColor = .ne_backgroundColor + customNavigationView.moreButton.setTitleColor(.ne_greyText, for: .normal) + } else { + view.backgroundColor = .funChatBackgroundColor + customNavigationView.moreButton.setTitleColor(.funChatThemeColor, for: .normal) + customNavigationView.moreButton.titleLabel?.font = .systemFont(ofSize: 17) + } } @objc func saveName() { weak var weakSelf = self + if NEChatDetectNetworkTool.shareInstance.manager?.isReachable == false { + weakSelf?.showToast(commonLocalizable("network_error")) + return + } + if let block = callBack { block(textField.text ?? "") // weakSelf?.navigationController?.popViewController(animated: true) @@ -86,10 +98,11 @@ class InputPersonInfoController: NEBaseViewController, UITextFieldDelegate { switch editType { case .nickName: title = NSLocalizedString("nickname", comment: "") - limitNumberCount = 30 + limitNumberCount = 15 case .cellphone: title = NSLocalizedString("phone", comment: "") limitNumberCount = 11 + textField.keyboardType = .numberPad case .email: title = NSLocalizedString("email", comment: "") limitNumberCount = 30 @@ -108,7 +121,6 @@ class InputPersonInfoController: NEBaseViewController, UITextFieldDelegate { text.font = UIFont.systemFont(ofSize: 14) text.delegate = self text.clearButtonMode = .always - text.becomeFirstResponder() text.addTarget(self, action: #selector(textFieldChange), for: .editingChanged) return text }() diff --git a/app/Mine/Controller/IntroduceBrandViewController.swift b/app/Mine/Controller/IntroduceBrandViewController.swift index 66ad1621..74d80d8c 100644 --- a/app/Mine/Controller/IntroduceBrandViewController.swift +++ b/app/Mine/Controller/IntroduceBrandViewController.swift @@ -17,16 +17,12 @@ class IntroduceBrandViewController: NEBaseViewController, UITableViewDelegate, setupSubviews() } - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - navigationController?.setNavigationBarHidden(false, animated: false) - } - func setupSubviews() { view.addSubview(headImage) view.addSubview(headLabel) - view.addSubview(tableView) + navigationController?.navigationBar.backgroundColor = .white + customNavigationView.backgroundColor = .white NSLayoutConstraint.activate([ headImage.centerXAnchor.constraint(equalTo: view.centerXAnchor), diff --git a/app/Mine/Controller/MeViewController.swift b/app/Mine/Controller/MeViewController.swift index 7e103ffc..17ef0ad9 100644 --- a/app/Mine/Controller/MeViewController.swift +++ b/app/Mine/Controller/MeViewController.swift @@ -8,15 +8,23 @@ import YXLogin import NECoreKit import NIMSDK import NECoreIMKit +import NECommonUIKit class MeViewController: UIViewController { private let mineData = [ - [NSLocalizedString("about_yunxin", comment: ""): "about_yunxin"], [NSLocalizedString("setting", comment: ""): "mine_setting"], + [NSLocalizedString("about_yunxin", comment: ""): "about_yunxin"], ] private let userProvider = UserInfoProvider.shared + lazy var headerView: UIView = { + let view = UIView(frame: .zero) + view.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = .white + return view + }() + lazy var header: NEUserHeaderView = { let view = NEUserHeaderView(frame: .zero) view.titleLabel.font = UIFont.systemFont(ofSize: 22.0) @@ -42,6 +50,7 @@ class MeViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + view.backgroundColor = NEStyleManager.instance.isNormalStyle() ? UIColor(hexString: "#EFF1F4") : UIColor(hexString: "#EDEDED") setupSubviews() } @@ -73,12 +82,16 @@ class MeViewController: UIViewController { ]) } header.clipsToBounds = true - header.layer.cornerRadius = 30 + if NEStyleManager.instance.isNormalStyle() { + header.layer.cornerRadius = 30 + } else { + header.layer.cornerRadius = 4 + } view.addSubview(nameLabel) NSLayoutConstraint.activate([ nameLabel.leftAnchor.constraint(equalTo: header.rightAnchor, constant: 15), - nameLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20), + nameLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -30), nameLabel.topAnchor.constraint(equalTo: header.topAnchor), ]) @@ -93,10 +106,9 @@ class MeViewController: UIViewController { updateUserInfo() let divider = UIView() - divider.backgroundColor = UIColor(hexString: "0xEFF1F4") view.addSubview(divider) divider.translatesAutoresizingMaskIntoConstraints = false - divider.backgroundColor = UIColor(hexString: "EFF1F4") + divider.backgroundColor = .clear NSLayoutConstraint.activate([ divider.leftAnchor.constraint(equalTo: view.leftAnchor), divider.heightAnchor.constraint(equalToConstant: 6), @@ -108,6 +120,7 @@ class MeViewController: UIViewController { view.addSubview(arrow) view.addSubview(personInfoBtn) + tableView.backgroundColor = NEStyleManager.instance.isNormalStyle() ? UIColor.white : UIColor.clear NSLayoutConstraint.activate([ tableView.topAnchor.constraint(equalTo: divider.bottomAnchor), tableView.leftAnchor.constraint(equalTo: view.leftAnchor), @@ -126,13 +139,23 @@ class MeViewController: UIViewController { personInfoBtn.rightAnchor.constraint(equalTo: view.rightAnchor), personInfoBtn.bottomAnchor.constraint(equalTo: divider.topAnchor), ]) + + view.insertSubview(headerView, belowSubview: header) + NSLayoutConstraint.activate([ + headerView.topAnchor.constraint(equalTo: view.topAnchor), + headerView.leftAnchor.constraint(equalTo: view.leftAnchor), + headerView.rightAnchor.constraint(equalTo: view.rightAnchor), + headerView.bottomAnchor.constraint(equalTo: divider.topAnchor), + ]) } func updateUserInfo() { - let user = userProvider.getUserInfo(userId: IMKitEngine.instance.imAccid) + let user = userProvider.getUserInfo(userId: IMKitClient.instance.imAccid) idLabel.text = "\(NSLocalizedString("account", comment: "")):\(user?.userId ?? "")" - nameLabel.text = user?.userInfo?.nickName - header.configHeadData(headUrl: user?.userInfo?.avatarUrl, name: user?.showName() ?? "") + nameLabel.text = user?.showName(false) + header.configHeadData(headUrl: user?.userInfo?.avatarUrl, + name: user?.showName(false) ?? "", + uid: user?.userId ?? "") } // MAKR: lazy method @@ -147,7 +170,6 @@ class MeViewController: UIViewController { forCellReuseIdentifier: "\(NSStringFromClass(MineTableViewCell.self))" ) tableView.rowHeight = 52 - tableView.backgroundColor = .white return tableView }() @@ -162,7 +184,6 @@ class MeViewController: UIViewController { btn.translatesAutoresizingMaskIntoConstraints = false btn.addTarget(self, action: #selector(personInfoBtnClick), for: .touchUpInside) return btn - }() @objc func personInfoBtnClick(sender: UIButton) { @@ -198,10 +219,10 @@ extension MeViewController: UITableViewDelegate, UITableViewDataSource { // } if indexPath.row == 0 { - let ctrl = IntroduceBrandViewController() + let ctrl = MineSettingViewController() navigationController?.pushViewController(ctrl, animated: true) } else if indexPath.row == 1 { - let ctrl = MineSettingViewController() + let ctrl = IntroduceBrandViewController() navigationController?.pushViewController(ctrl, animated: true) } else if indexPath.row == 2 {} } diff --git a/app/Mine/Controller/MessageRemindViewController.swift b/app/Mine/Controller/MessageRemindViewController.swift index 0265f257..a5537f24 100644 --- a/app/Mine/Controller/MessageRemindViewController.swift +++ b/app/Mine/Controller/MessageRemindViewController.swift @@ -11,7 +11,7 @@ import NEChatUIKit class MessageRemindViewController: NEBaseViewController, UITableViewDelegate, UITableViewDataSource { public var cellClassDic = - [SettingCellType.SettingSwitchCell.rawValue: TeamSettingSwitchCell.self] + [SettingCellType.SettingSwitchCell.rawValue: CustomTeamSettingSwitchCell.self] private var viewModel = MessageRemindViewModel() override func viewDidLoad() { @@ -23,18 +23,28 @@ class MessageRemindViewController: NEBaseViewController, UITableViewDelegate, func initialConfig() { title = NSLocalizedString("message_remind", comment: "") + if NEStyleManager.instance.isNormalStyle() { + view.backgroundColor = .ne_backgroundColor + customNavigationView.backgroundColor = .ne_backgroundColor + navigationController?.navigationBar.backgroundColor = .ne_backgroundColor + } else { + view.backgroundColor = .funChatBackgroundColor + } } func setupSubviews() { view.addSubview(tableView) + if NEStyleManager.instance.isNormalStyle() { + topConstant += 12 + } NSLayoutConstraint.activate([ tableView.leftAnchor.constraint(equalTo: view.leftAnchor), tableView.rightAnchor.constraint(equalTo: view.rightAnchor), - tableView.topAnchor.constraint(equalTo: view.topAnchor), + tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: topConstant), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) - cellClassDic.forEach { (key: Int, value: BaseTeamSettingCell.Type) in + cellClassDic.forEach { (key: Int, value: NEBaseTeamSettingCell.Type) in tableView.register(value, forCellReuseIdentifier: "\(key)") } } @@ -42,7 +52,7 @@ class MessageRemindViewController: NEBaseViewController, UITableViewDelegate, lazy var tableView: UITableView = { let table = UITableView() table.translatesAutoresizingMaskIntoConstraints = false - table.backgroundColor = UIColor(hexString: "0xF1F1F6") + table.backgroundColor = .clear table.dataSource = self table.delegate = self table.separatorColor = .clear @@ -73,7 +83,7 @@ class MessageRemindViewController: NEBaseViewController, UITableViewDelegate, if let cell = tableView.dequeueReusableCell( withIdentifier: "\(model.type)", for: indexPath - ) as? BaseTeamSettingCell { + ) as? NEBaseTeamSettingCell { cell.configure(model) return cell } @@ -93,6 +103,9 @@ class MessageRemindViewController: NEBaseViewController, UITableViewDelegate, } func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + if section == 0 { + return 0 + } if viewModel.sectionData.count > section { let model = viewModel.sectionData[section] if model.cellModels.count > 0 { @@ -104,7 +117,7 @@ class MessageRemindViewController: NEBaseViewController, UITableViewDelegate, func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let header = UIView() - header.backgroundColor = UIColor(hexString: "0xF1F1F6") + header.backgroundColor = .ne_lightBackgroundColor return header } } diff --git a/app/Mine/Controller/MineSettingViewController.swift b/app/Mine/Controller/MineSettingViewController.swift index 6268af24..a61a3a76 100644 --- a/app/Mine/Controller/MineSettingViewController.swift +++ b/app/Mine/Controller/MineSettingViewController.swift @@ -12,18 +12,23 @@ import NIMSDK class MineSettingViewController: NEBaseViewController, UITableViewDataSource, UITableViewDelegate { private var viewModel = MineSettingViewModel() public var cellClassDic = [ - SettingCellType.SettingArrowCell.rawValue: TeamArrowSettingCell.self, - SettingCellType.SettingSwitchCell.rawValue: TeamSettingSwitchCell.self, + SettingCellType.SettingArrowCell.rawValue: CustomTeamArrowSettingCell.self, + SettingCellType.SettingSwitchCell.rawValue: CustomTeamSettingSwitchCell.self, ] private var tag = "MineSettingViewController" - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - navigationController?.setNavigationBarHidden(false, animated: false) - } + private let userDefault = UserDefaults.standard override func viewDidLoad() { super.viewDidLoad() + if userDefault.value(forKey: "HandSetModeKey") == nil { + SettingProvider.shared.setHandSetMode(true) + } + + if userDefault.value(forKey: "MessageHasRead") == nil { + SettingProvider.shared.setMessageRead(true) + } + + viewModel.delegate = self viewModel.getData() setupSubviews() initialConfig() @@ -31,19 +36,29 @@ class MineSettingViewController: NEBaseViewController, UITableViewDataSource, UI func initialConfig() { title = NSLocalizedString("setting", comment: "") - viewModel.delegate = self + + if NEStyleManager.instance.isNormalStyle() { + view.backgroundColor = .ne_backgroundColor + customNavigationView.backgroundColor = .ne_backgroundColor + navigationController?.navigationBar.backgroundColor = .ne_backgroundColor + } else { + view.backgroundColor = .funChatBackgroundColor + } } func setupSubviews() { view.addSubview(tableView) + if NEStyleManager.instance.isNormalStyle() { + topConstant += 12 + } NSLayoutConstraint.activate([ tableView.leftAnchor.constraint(equalTo: view.leftAnchor), tableView.rightAnchor.constraint(equalTo: view.rightAnchor), - tableView.topAnchor.constraint(equalTo: view.topAnchor), + tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: topConstant), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) - cellClassDic.forEach { (key: Int, value: BaseTeamSettingCell.Type) in + cellClassDic.forEach { (key: Int, value: NEBaseTeamSettingCell.Type) in tableView.register(value, forCellReuseIdentifier: "\(key)") } } @@ -51,12 +66,11 @@ class MineSettingViewController: NEBaseViewController, UITableViewDataSource, UI lazy var tableView: UITableView = { let table = UITableView() table.translatesAutoresizingMaskIntoConstraints = false - table.backgroundColor = UIColor(hexString: "0xF1F1F6") + table.backgroundColor = .clear table.dataSource = self table.delegate = self table.separatorColor = .clear table.separatorStyle = .none - table.sectionHeaderHeight = 12.0 table.tableFooterView = getFooterView() if #available(iOS 15.0, *) { table.sectionHeaderTopPadding = 0.0 @@ -65,12 +79,8 @@ class MineSettingViewController: NEBaseViewController, UITableViewDataSource, UI }() func getFooterView() -> UIView? { -// guard let title = getBottomText() else { -// return nil -// } let footer = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 64.0)) let button = UIButton() - button.translatesAutoresizingMaskIntoConstraints = false footer.addSubview(button) button.backgroundColor = .white button.clipsToBounds = true @@ -78,19 +88,56 @@ class MineSettingViewController: NEBaseViewController, UITableViewDataSource, UI button.titleLabel?.font = UIFont.systemFont(ofSize: 16) button.setTitle(title, for: .normal) button.addTarget(self, action: #selector(loginOutAction), for: .touchUpInside) - button.layer.cornerRadius = 8.0 button.setTitle(NSLocalizedString("logout", comment: ""), for: .normal) - NSLayoutConstraint.activate([ - button.leftAnchor.constraint(equalTo: footer.leftAnchor, constant: 20), - button.rightAnchor.constraint(equalTo: footer.rightAnchor, constant: -20), - button.topAnchor.constraint(equalTo: footer.topAnchor, constant: 12), - button.heightAnchor.constraint(equalToConstant: 40), - ]) + + if NEStyleManager.instance.isNormalStyle() { + button.layer.cornerRadius = 8.0 + button.frame = CGRect(x: 20, y: 12, width: view.frame.size.width - 40, height: 40) + } else { + button.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + button.leftAnchor.constraint(equalTo: footer.leftAnchor, constant: 0), + button.rightAnchor.constraint(equalTo: footer.rightAnchor, constant: 0), + button.topAnchor.constraint(equalTo: footer.topAnchor, constant: 12), + button.heightAnchor.constraint(equalToConstant: 40), + ]) + } + return footer } @objc func loginOutAction() { - view.makeToast("demo not support logout") + AuthorManager.shareInstance()? + .logout( + withConfirm: NSLocalizedString("want_to_logout", comment: ""), + withCompletion: { [weak self] user, error in + if error != nil { + self?.view.makeToast(error?.localizedDescription) + } else { + weak var weakSelf = self + NotificationCenter.default.post( + name: Notification.Name("logout"), + object: nil + ) + IMKitEngine.instance.logout { error in + if error == nil { + NIMSDK.shared().qchatManager.logout { chatError in + if chatError != nil { + self?.view.makeToast(chatError?.localizedDescription) + } else { + print("logout success") + } + } + } else { + NELog.errorLog( + weakSelf?.tag ?? "", + desc: "❌CALLBACK logout failed,error = \(error!)" + ) + } + } + } + } + ) } // MARK: UITableViewDataSource, UITableViewDelegate @@ -112,7 +159,7 @@ class MineSettingViewController: NEBaseViewController, UITableViewDataSource, UI if let cell = tableView.dequeueReusableCell( withIdentifier: "\(model.type)", for: indexPath - ) as? BaseTeamSettingCell { + ) as? NEBaseTeamSettingCell { cell.configure(model) return cell } @@ -132,6 +179,9 @@ class MineSettingViewController: NEBaseViewController, UITableViewDataSource, UI } func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + if section == 0 { + return 0 + } if viewModel.sectionData.count > section { let model = viewModel.sectionData[section] if model.cellModels.count > 0 { @@ -143,7 +193,7 @@ class MineSettingViewController: NEBaseViewController, UITableViewDataSource, UI func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let header = UIView() - header.backgroundColor = UIColor(hexString: "0xF1F1F6") + header.backgroundColor = .clear return header } @@ -161,5 +211,10 @@ extension MineSettingViewController: MineSettingViewModelDelegate { navigationController?.pushViewController(messageRemindCtrl, animated: true) } + func didStyleClick() { + let styleSelectionCtrl = StyleSelectionViewController() + navigationController?.pushViewController(styleSelectionCtrl, animated: true) + } + func didClickCleanCache() {} } diff --git a/app/Mine/Controller/NEAboutWebViewController.swift b/app/Mine/Controller/NEAboutWebViewController.swift index 0196ce4d..eebbc59c 100644 --- a/app/Mine/Controller/NEAboutWebViewController.swift +++ b/app/Mine/Controller/NEAboutWebViewController.swift @@ -27,6 +27,9 @@ class NEAboutWebViewController: NEBaseViewController { func setUpSubViews() { title = NSLocalizedString("product_intro", comment: "") + customNavigationView.backgroundColor = .white + navigationController?.navigationBar.backgroundColor = .white + guard let requestUrl = URL(string: loadUrl) else { return } @@ -40,7 +43,7 @@ class NEAboutWebViewController: NEBaseViewController { NSLayoutConstraint.activate([ webview.leftAnchor.constraint(equalTo: view.leftAnchor), webview.rightAnchor.constraint(equalTo: view.rightAnchor), - webview.topAnchor.constraint(equalTo: view.topAnchor), + webview.topAnchor.constraint(equalTo: view.topAnchor, constant: topConstant), webview.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) } diff --git a/app/Mine/Controller/NELoginViewController.swift b/app/Mine/Controller/NELoginViewController.swift new file mode 100644 index 00000000..9dd4ae8a --- /dev/null +++ b/app/Mine/Controller/NELoginViewController.swift @@ -0,0 +1,202 @@ + +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECommonKit +import YXLogin +import NECoreIMKit +import NEChatUIKit + +public class NELoginViewController: UIViewController { + // 登录成功 + public typealias LoginBlock = () -> Void + + public var successLogin: LoginBlock? + + override public func viewDidLoad() { + super.viewDidLoad() + setupUI() + } + + override public func viewWillAppear(_ animated: Bool) { + navigationController?.navigationBar.isHidden = true + } + + override public func viewWillDisappear(_ animated: Bool) { + navigationController?.navigationBar.isHidden = false + } + + func setupUI() { + view.addSubview(launchIcon) + view.addSubview(launchIconLabel) + view.addSubview(loginBtn) + view.addSubview(emailLoginBtn) + view.addSubview(divideView) + view.addSubview(nodeBtn) + + if #available(iOS 11.0, *) { + NSLayoutConstraint.activate([ + launchIcon.centerXAnchor.constraint(equalTo: view.centerXAnchor), + launchIcon.topAnchor.constraint( + equalTo: view.safeAreaLayoutGuide.topAnchor, + constant: 145.0 + ), + ]) + } else { + NSLayoutConstraint.activate([ + launchIcon.centerXAnchor.constraint(equalTo: view.centerXAnchor), + launchIcon.topAnchor.constraint(equalTo: view.topAnchor, constant: 145.0), + ]) + } + NSLayoutConstraint.activate([ + launchIconLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), + launchIconLabel.topAnchor.constraint(equalTo: launchIcon.bottomAnchor, constant: -12.0), + ]) + + NSLayoutConstraint.activate([ + loginBtn.centerXAnchor.constraint(equalTo: view.centerXAnchor), + loginBtn.topAnchor.constraint(equalTo: launchIconLabel.bottomAnchor, constant: 20), + loginBtn.widthAnchor.constraint(equalToConstant: NEConstant.screenWidth - 80), + loginBtn.heightAnchor.constraint(equalToConstant: 44), + ]) + + NSLayoutConstraint.activate([ + divideView.bottomAnchor.constraint( + equalTo: view.bottomAnchor, + constant: -10 - NEConstant.statusBarHeight + ), + divideView.centerXAnchor.constraint(equalTo: view.centerXAnchor), + divideView.widthAnchor.constraint(equalToConstant: 1), + divideView.heightAnchor.constraint(equalToConstant: 10), + ]) + + NSLayoutConstraint.activate([ + emailLoginBtn.centerYAnchor.constraint(equalTo: divideView.centerYAnchor), + emailLoginBtn.rightAnchor.constraint(equalTo: divideView.leftAnchor, constant: -8), + ]) + + NSLayoutConstraint.activate([ + nodeBtn.centerYAnchor.constraint(equalTo: divideView.centerYAnchor), + nodeBtn.leftAnchor.constraint(equalTo: divideView.rightAnchor, constant: 8), + ]) + } + + @objc func loginBtnClick(sender: UIButton) { + weak var weakSelf = self + AuthorManager.shareInstance()?.startLogin(completion: { user, error in + if let err = error { + print("login error : ", err) + } else { + weakSelf?.setupSuccessLogic(user) + } + }) + } + + @objc func emailLoginBtnClick(sender: UIButton) { + // login to business server + let config = YXConfig() + config.appKey = AppKey.appKey + config.parentScope = NSNumber(integerLiteral: 2) + config.scope = NSNumber(integerLiteral: 7) + config.supportInternationalize = false + config.type = .email + #if DEBUG + config.isOnline = false + print("debug") + #else + config.isOnline = true + print("release") + #endif + AuthorManager.shareInstance()?.initAuthor(with: config) + weak var weakSelf = self + AuthorManager.shareInstance()?.startLogin(completion: { user, error in + if let err = error { + print("login error : ", err) + } else { + weakSelf?.setupSuccessLogic(user) + } + }) + } + + @objc func nodeBtnClick(sender: UIButton) { + let ctrl = NENodeViewController() + navigationController?.pushViewController(ctrl, animated: true) + } + + private func setupSuccessLogic(_ user: YXUserInfo?) { + if let token = user?.imToken, let account = user?.imAccid { + weak var weakSelf = self + IMKitClient.instance.loginIM(account, token) { error in + if let err = error { + print("loginIM error : ", err) + UIApplication.shared.keyWindow?.makeToast(err.localizedDescription) + } else { + ChatRouter.setupInit() + if let block = weakSelf?.successLogin { + block() + } + } + } + } + } + + // lazy method + lazy var launchIcon: UIImageView = { + let imageView = UIImageView() + imageView.translatesAutoresizingMaskIntoConstraints = false + imageView.image = UIImage(named: "launchIcon") + return imageView + }() + + lazy var launchIconLabel: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.text = NSLocalizedString("appName", comment: "") + label.font = UIFont.systemFont(ofSize: 24.0) + label.textColor = UIColor(hexString: "333333") + return label + }() + + lazy var loginBtn: UIButton = { + let btn = UIButton() + btn.translatesAutoresizingMaskIntoConstraints = false + btn.layer.cornerRadius = 8 + btn.backgroundColor = UIColor.ne_blueText + btn.setTitleColor(UIColor.white, for: .normal) + btn.titleLabel?.font = UIFont.systemFont(ofSize: 15.0) + btn.setTitle(NSLocalizedString("register_login", comment: ""), for: .normal) + btn.addTarget(self, action: #selector(loginBtnClick), for: .touchUpInside) + return btn + }() + + lazy var emailLoginBtn: UIButton = { + let btn = UIButton() + btn.translatesAutoresizingMaskIntoConstraints = false + btn.setTitleColor(UIColor.ne_lightText, for: .normal) + btn.titleLabel?.font = UIFont.systemFont(ofSize: 12.0) + btn.setTitle(NSLocalizedString("email_login", comment: ""), for: .normal) + btn.addTarget(self, action: #selector(emailLoginBtnClick), for: .touchUpInside) + + return btn + }() + + lazy var divideView: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = UIColor.ne_lightText + return view + }() + + lazy var nodeBtn: UIButton = { + let btn = UIButton() + btn.translatesAutoresizingMaskIntoConstraints = false + btn.setTitleColor(UIColor.ne_lightText, for: .normal) + btn.titleLabel?.font = UIFont.systemFont(ofSize: 12.0) + btn.setTitle(NSLocalizedString("node_select", comment: ""), for: .normal) + btn.addTarget(self, action: #selector(nodeBtnClick), for: .touchUpInside) + + return btn + }() +} diff --git a/app/Mine/Controller/NENodeViewController.swift b/app/Mine/Controller/NENodeViewController.swift index b053108e..ab97a43c 100644 --- a/app/Mine/Controller/NENodeViewController.swift +++ b/app/Mine/Controller/NENodeViewController.swift @@ -56,7 +56,7 @@ class NENodeViewController: NEBaseViewController, UITableViewDataSource, UITable lazy var tableView: UITableView = { let table = UITableView() table.translatesAutoresizingMaskIntoConstraints = false - table.backgroundColor = UIColor(hexString: "0xF1F1F6") + table.backgroundColor = .ne_lightBackgroundColor table.dataSource = self table.delegate = self table.separatorColor = .clear @@ -117,7 +117,7 @@ class NENodeViewController: NEBaseViewController, UITableViewDataSource, UITable func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let header = UIView() - header.backgroundColor = UIColor(hexString: "0xF1F1F6") + header.backgroundColor = .ne_lightBackgroundColor return header } } diff --git a/app/Mine/Controller/PersonInfoViewController.swift b/app/Mine/Controller/PersonInfoViewController.swift index bcbac4e4..b1ec2fab 100644 --- a/app/Mine/Controller/PersonInfoViewController.swift +++ b/app/Mine/Controller/PersonInfoViewController.swift @@ -13,9 +13,9 @@ class PersonInfoViewController: NEBaseViewController, NIMUserManagerDelegate, UINavigationControllerDelegate, PersonInfoViewModelDelegate, UITableViewDelegate, UITableViewDataSource { public var cellClassDic = [ - SettingCellType.SettingSubtitleCell.rawValue: TeamSettingSubtitleCell.self, - SettingCellType.SettingHeaderCell.rawValue: TeamSettingHeaderCell.self, - SettingCellType.SettingSubtitleCustomCell.rawValue: TeamSettingRightCustomCell.self, + SettingCellType.SettingSubtitleCell.rawValue: CustomTeamSettingSubtitleCell.self, + SettingCellType.SettingHeaderCell.rawValue: CustomTeamSettingHeaderCell.self, + SettingCellType.SettingSubtitleCustomCell.rawValue: CustomTeamSettingRightCustomCell.self, ] private var viewModel = PersonInfoViewModel() private var className = "PersonInfoViewController" @@ -27,28 +27,34 @@ class PersonInfoViewController: NEBaseViewController, NIMUserManagerDelegate, initialConfig() } - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - navigationController?.setNavigationBarHidden(false, animated: false) - } - func initialConfig() { title = NSLocalizedString("person_info", comment: "") - view.backgroundColor = UIColor(hexString: "0xF1F1F6") + customNavigationView.navTitle.text = title + + if NEStyleManager.instance.isNormalStyle() { + view.backgroundColor = .ne_backgroundColor + customNavigationView.backgroundColor = .ne_backgroundColor + navigationController?.navigationBar.backgroundColor = .ne_backgroundColor + } else { + view.backgroundColor = .funChatBackgroundColor + } viewModel.delegate = self NIMSDK.shared().userManager.add(self) } func setupSubviews() { view.addSubview(tableView) + if NEStyleManager.instance.isNormalStyle() { + topConstant += 12 + } NSLayoutConstraint.activate([ tableView.leftAnchor.constraint(equalTo: view.leftAnchor), tableView.rightAnchor.constraint(equalTo: view.rightAnchor), - tableView.topAnchor.constraint(equalTo: view.topAnchor), + tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: topConstant), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) - cellClassDic.forEach { (key: Int, value: BaseTeamSettingCell.Type) in + cellClassDic.forEach { (key: Int, value: NEBaseTeamSettingCell.Type) in tableView.register(value, forCellReuseIdentifier: "\(key)") } } @@ -76,10 +82,23 @@ class PersonInfoViewController: NEBaseViewController, NIMUserManagerDelegate, alert.addAction(first) alert.addAction(second) alert.addAction(cancel) - + fixAlertOnIpad(alert) present(alert, animated: true, completion: nil) } + func showCustomAlert(firstContent: String, secondContent: String, + selectValue: @escaping ((_ value: NSInteger) -> Void)) { + let first = NECustomAlertAction(title: firstContent) { + selectValue(0) + } + + let second = NECustomAlertAction(title: secondContent) { + selectValue(1) + } + + showCustomActionSheet([first, second]) + } + func showDatePicker() { view.addSubview(pickerView) @@ -88,7 +107,11 @@ class PersonInfoViewController: NEBaseViewController, NIMUserManagerDelegate, if let t = time { weakSelf?.viewModel.updateBirthday(birthDay: t) { error in if error != nil { - weakSelf?.showToast(NSLocalizedString("setting_birthday_failure", comment: "")) + if error?.code == 408 { + weakSelf?.showToast(commonLocalizable("network_error")) + } else { + weakSelf?.showToast(NSLocalizedString("setting_birthday_failure", comment: "")) + } } } } @@ -96,7 +119,7 @@ class PersonInfoViewController: NEBaseViewController, NIMUserManagerDelegate, NSLayoutConstraint.activate([ pickerView.leftAnchor.constraint(equalTo: view.leftAnchor), pickerView.rightAnchor.constraint(equalTo: view.rightAnchor), - pickerView.heightAnchor.constraint(equalToConstant: 229), + pickerView.topAnchor.constraint(equalTo: view.topAnchor), pickerView.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) } @@ -104,12 +127,11 @@ class PersonInfoViewController: NEBaseViewController, NIMUserManagerDelegate, lazy var tableView: UITableView = { let table = UITableView() table.translatesAutoresizingMaskIntoConstraints = false - table.backgroundColor = UIColor(hexString: "0xF1F1F6") + table.backgroundColor = .clear table.dataSource = self table.delegate = self table.separatorColor = .clear table.separatorStyle = .none - table.sectionHeaderHeight = 12.0 if #available(iOS 15.0, *) { table.sectionHeaderTopPadding = 0.0 } @@ -118,7 +140,6 @@ class PersonInfoViewController: NEBaseViewController, NIMUserManagerDelegate, private lazy var pickerView: BirthdayDatePickerView = { let picker = BirthdayDatePickerView() - picker.backgroundColor = .white picker.translatesAutoresizingMaskIntoConstraints = false return picker }() @@ -130,7 +151,7 @@ class PersonInfoViewController: NEBaseViewController, NIMUserManagerDelegate, // MARK: NIMUserManagerDelegate func onUserInfoChanged(_ user: NIMUser) { - if user.userId == IMKitEngine.instance.imAccid { + if user.userId == IMKitClient.instance.imAccid { viewModel.getData() tableView.reloadData() } @@ -147,11 +168,16 @@ class PersonInfoViewController: NEBaseViewController, NIMUserManagerDelegate, } public func uploadHeadImage(image: UIImage) { - view.makeToastActivity(.center) weak var weakSelf = self + if NEChatDetectNetworkTool.shareInstance.manager?.isReachable == false { + weakSelf?.showToast(commonLocalizable("network_error")) + return + } + + view.makeToastActivity(.center) if let imageData = image.jpegData(compressionQuality: 0.6) as NSData? { let filePath = NSHomeDirectory().appending("/Documents/") - .appending(IMKitEngine.instance.imAccid) + .appending(IMKitClient.instance.imAccid) let succcess = imageData.write(toFile: filePath, atomically: true) if succcess { NIMSDK.shared().resourceManager @@ -179,7 +205,11 @@ class PersonInfoViewController: NEBaseViewController, NIMUserManagerDelegate, // MARK: PersonInfoViewModelDelegate func didClickHeadImage() { - showBottomAlert(self) + if NEStyleManager.instance.isNormalStyle() { + showBottomAlert(self) + } else { + showCustomBottomAlert(self) + } } func didClickNickName(name: String) { @@ -202,20 +232,36 @@ class PersonInfoViewController: NEBaseViewController, NIMUserManagerDelegate, func didClickGender() { var sex = NIMUserGender.unknown weak var weakSelf = self - showAlert( - firstContent: NSLocalizedString("male", comment: ""), - secondContent: NSLocalizedString("female", comment: "") - ) { value in + let block: ((_ value: NSInteger) -> Void) = { + value in sex = value == 0 ? .male : .female weakSelf?.viewModel.updateSex(sex: sex) { error in if error != nil { - weakSelf?.showToast(NSLocalizedString("change_gender_failure", comment: "")) + if error?.code == 408 { + weakSelf?.showToast(commonLocalizable("network_error")) + } else { + weakSelf?.showToast(NSLocalizedString("change_gender_failure", comment: "")) + } } } } + if NEStyleManager.instance.isNormalStyle() { + showAlert(firstContent: NSLocalizedString("male", comment: ""), + secondContent: NSLocalizedString("female", comment: ""), + selectValue: block) + } else { + showCustomAlert(firstContent: NSLocalizedString("male", comment: ""), + secondContent: NSLocalizedString("female", comment: ""), + selectValue: block) + } } - func didClickBirthday() { + func didClickBirthday(birth: String) { + let formatter = DateFormatter() + formatter.dateFormat = "yyyy-MM-dd" + if let selectDate = formatter.date(from: birth) { + pickerView.picker.setDate(selectDate, animated: true) + } showDatePicker() } @@ -294,7 +340,7 @@ class PersonInfoViewController: NEBaseViewController, NIMUserManagerDelegate, if let cell = tableView.dequeueReusableCell( withIdentifier: "\(model.type)", for: indexPath - ) as? BaseTeamSettingCell { + ) as? NEBaseTeamSettingCell { cell.configure(model) return cell } @@ -314,6 +360,9 @@ class PersonInfoViewController: NEBaseViewController, NIMUserManagerDelegate, } func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + if section == 0 { + return 0 + } if viewModel.sectionData.count > section { let model = viewModel.sectionData[section] if model.cellModels.count > 0 { @@ -325,7 +374,7 @@ class PersonInfoViewController: NEBaseViewController, NIMUserManagerDelegate, func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let header = UIView() - header.backgroundColor = UIColor(hexString: "0xF1F1F6") + header.backgroundColor = .ne_lightBackgroundColor return header } } diff --git a/app/Mine/Controller/StyleSelectionViewController.swift b/app/Mine/Controller/StyleSelectionViewController.swift new file mode 100644 index 00000000..1a84a933 --- /dev/null +++ b/app/Mine/Controller/StyleSelectionViewController.swift @@ -0,0 +1,150 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NECoreKit +import NECommonKit +import NECommonUIKit +import NEConversationUIKit + +open class StyleCellModel: NSObject { + public var styleName: String + public var styleImageName: String + public var styleTitle: String + public var selected: Bool = false + public var selectedImageName: String + + init(styleName: String, styleImageName: String, styleTitle: String, selected: Bool, selectedImageName: String) { + self.styleName = styleName + self.styleImageName = styleImageName + self.styleTitle = styleTitle + self.selected = selected + self.selectedImageName = selectedImageName + } +} + +open class StyleSelectionViewController: NEBaseViewController, UICollectionViewDataSource, UICollectionViewDelegate { + private var sectionCount: Int = 1 + private var itemsInSection: Int = 2 + private var topMargin: CGFloat = 40 + private var cellSize = StyleSelectionCell.getSize() + private var currentStyle: StyleSelectionCell? + public var styleData = [StyleCellModel]() + + public lazy var collectionView: UICollectionView = { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .vertical + layout.itemSize = CGSize(width: NEConstant.screenWidth / 2, height: cellSize.height) + layout.minimumLineSpacing = 0 + layout.minimumInteritemSpacing = 0 + layout.sectionInset = UIEdgeInsets(top: topMargin, left: 0, bottom: topMargin, right: 0) + let collect = UICollectionView(frame: .zero, collectionViewLayout: layout) + collect.translatesAutoresizingMaskIntoConstraints = false + collect.dataSource = self + collect.delegate = self + collect.isUserInteractionEnabled = true + collect.backgroundColor = .white + collect.contentMode = .center + collect.register(StyleSelectionCell.self, forCellWithReuseIdentifier: "\(StyleSelectionCell.self)") + + return collect + }() + + override open func viewDidLoad() { + super.viewDidLoad() + title = NSLocalizedString("style_selection", comment: "") + + if NEStyleManager.instance.isNormalStyle() { + view.backgroundColor = .ne_backgroundColor + customNavigationView.backgroundColor = .ne_backgroundColor + navigationController?.navigationBar.backgroundColor = .ne_backgroundColor + } else { + view.backgroundColor = .funChatBackgroundColor + } + getData() + setupSubviews() + } + + func getData() { + styleData.append(contentsOf: [ + StyleCellModel(styleName: "default", + styleImageName: "style_normal", + styleTitle: NSLocalizedString("style_default", comment: ""), + selected: NEStyleManager.instance.isNormalStyle(), + selectedImageName: "clicked_normal"), + StyleCellModel(styleName: "fun", + styleImageName: "style_fun", + styleTitle: NSLocalizedString("style_fun", comment: ""), + selected: !NEStyleManager.instance.isNormalStyle(), + selectedImageName: "clicked_fun"), + ]) + sectionCount = Int(ceil(Double(styleData.count) / Double(itemsInSection))) + } + + func setupSubviews() { + view.addSubview(collectionView) + NSLayoutConstraint.activate([ + collectionView.topAnchor.constraint(equalTo: view.topAnchor, constant: NEConstant.navigationAndStatusHeight), + collectionView.leftAnchor.constraint(equalTo: view.leftAnchor), + collectionView.rightAnchor.constraint(equalTo: view.rightAnchor), + ]) + + let collectionViewHeight: CGFloat = (cellSize.height + topMargin * 2.0) * CGFloat(sectionCount) + if collectionViewHeight > NEConstant.screenHeight { + collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true + } else { + collectionView.heightAnchor.constraint(equalToConstant: collectionViewHeight).isActive = true + } + } + + public func numberOfSections(in collectionView: UICollectionView) -> Int { + sectionCount + } + + public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + if section == sectionCount - 1 { + return styleData.count - itemsInSection * (sectionCount - 1) + } + return itemsInSection + } + + public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "\(StyleSelectionCell.self)", for: indexPath) as? StyleSelectionCell + let itemModel = styleData[indexPath.section * itemsInSection + indexPath.row] + cell?.configData(model: itemModel) + return cell ?? UICollectionViewCell() + } + + public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + if indexPath.row == 0 { + if NEStyleManager.instance.isNormalStyle() == false { + removeConversationDelegate() + NEStyleManager.instance.setNormalStyle() + NotificationCenter.default.post( + name: Notification.Name(CHANGE_UI), + object: nil + ) + } + } else if indexPath.row == 1 { + if NEStyleManager.instance.isNormalStyle() == true { + removeConversationDelegate() + NEStyleManager.instance.setFunStyle() + NotificationCenter.default.post( + name: Notification.Name(CHANGE_UI), + object: nil + ) + } + } + } + + public func removeConversationDelegate() { + if let tabcontroller = UIApplication.shared.keyWindow?.rootViewController as? NETabBarController { + tabcontroller.viewControllers?.forEach { controller in + if let nav = controller as? NENavigationController, let conversationController = nav.topViewController as? NEBaseConversationController { + NIMSDK.shared().chatManager.remove(conversationController) + } + } + } + } +} diff --git a/app/Mine/View/BirthdayDatePickerView.swift b/app/Mine/View/BirthdayDatePickerView.swift index 8e6b376f..5867a251 100644 --- a/app/Mine/View/BirthdayDatePickerView.swift +++ b/app/Mine/View/BirthdayDatePickerView.swift @@ -11,16 +11,33 @@ public class BirthdayDatePickerView: UIView { public typealias SelectTimeCallBack = (String?) -> Void public var timeCallBack: SelectTimeCallBack? + lazy var cancelBtn: UIButton = { + let button = UIButton() + button.translatesAutoresizingMaskIntoConstraints = false + button.setTitle(NSLocalizedString("cancel", comment: ""), for: .normal) + button.setTitleColor(UIColor.ne_blueText, for: .normal) + button.titleLabel?.font = UIFont.systemFont(ofSize: 14) + + return button + }() + lazy var sureBtn: UIButton = { let button = UIButton(type: .custom) button.translatesAutoresizingMaskIntoConstraints = false button.setTitle(NSLocalizedString("confirm", comment: ""), for: .normal) button.setTitleColor(UIColor.ne_blueText, for: .normal) - button.titleLabel?.font = UIFont.systemFont(ofSize: 13) + button.titleLabel?.font = UIFont.systemFont(ofSize: 14) button.addTarget(self, action: #selector(sureBtnClick), for: .touchUpInside) return button }() + private lazy var bottomLine: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = UIColor(hexString: "0xDBE0E8") + return view + }() + lazy var picker: UIDatePicker = { let datePicker = UIDatePicker(frame: CGRect.zero) datePicker.translatesAutoresizingMaskIntoConstraints = false @@ -39,19 +56,11 @@ public class BirthdayDatePickerView: UIView { return datePicker }() - lazy var cancelBtn: UIButton = { - let button = UIButton() - button.translatesAutoresizingMaskIntoConstraints = false - button.setTitle(NSLocalizedString("cancel", comment: ""), for: .normal) - button.setTitleColor(UIColor.ne_blueText, for: .normal) - button.titleLabel?.font = UIFont.systemFont(ofSize: 13) - button.addTarget(self, action: #selector(cancelBtnClick), for: .touchUpInside) - - return button - }() - override init(frame: CGRect) { super.init(frame: frame) + backgroundColor = UIColor(white: 0, alpha: 0.25) + let tap = UITapGestureRecognizer(target: self, action: #selector(pickerBackViewClicked)) + addGestureRecognizer(tap) setupSubviews() } @@ -60,39 +69,56 @@ public class BirthdayDatePickerView: UIView { } func setupSubviews() { - // 创建日期选择器 - addSubview(cancelBtn) - addSubview(sureBtn) - addSubview(bottomLine) - addSubview(picker) + let pickerBackView = UIView() + pickerBackView.translatesAutoresizingMaskIntoConstraints = false + pickerBackView.backgroundColor = .white + addSubview(pickerBackView) NSLayoutConstraint.activate([ - cancelBtn.leftAnchor.constraint(equalTo: leftAnchor, constant: 15), - cancelBtn.topAnchor.constraint(equalTo: topAnchor, constant: 8), + pickerBackView.leftAnchor.constraint(equalTo: leftAnchor), + pickerBackView.rightAnchor.constraint(equalTo: rightAnchor), + pickerBackView.bottomAnchor.constraint(equalTo: bottomAnchor), + pickerBackView.heightAnchor.constraint(equalToConstant: 229), + ]) + + pickerBackView.addSubview(cancelBtn) + pickerBackView.addSubview(sureBtn) + pickerBackView.addSubview(bottomLine) + pickerBackView.addSubview(picker) + + NSLayoutConstraint.activate([ + cancelBtn.leftAnchor.constraint(equalTo: pickerBackView.leftAnchor, constant: 15), + cancelBtn.topAnchor.constraint(equalTo: pickerBackView.topAnchor, constant: 8), cancelBtn.widthAnchor.constraint(equalToConstant: 45), + cancelBtn.heightAnchor.constraint(equalToConstant: 20), ]) NSLayoutConstraint.activate([ - sureBtn.rightAnchor.constraint(equalTo: rightAnchor, constant: -15), - sureBtn.topAnchor.constraint(equalTo: topAnchor, constant: 8), + sureBtn.rightAnchor.constraint(equalTo: pickerBackView.rightAnchor, constant: -15), + sureBtn.topAnchor.constraint(equalTo: pickerBackView.topAnchor, constant: 8), sureBtn.widthAnchor.constraint(equalToConstant: 45), + sureBtn.heightAnchor.constraint(equalToConstant: 20), ]) NSLayoutConstraint.activate([ - bottomLine.leftAnchor.constraint(equalTo: leftAnchor), - bottomLine.rightAnchor.constraint(equalTo: rightAnchor), - bottomLine.topAnchor.constraint(equalTo: cancelBtn.bottomAnchor), + bottomLine.leftAnchor.constraint(equalTo: pickerBackView.leftAnchor), + bottomLine.rightAnchor.constraint(equalTo: pickerBackView.rightAnchor), + bottomLine.topAnchor.constraint(equalTo: cancelBtn.bottomAnchor, constant: 8), bottomLine.heightAnchor.constraint(equalToConstant: 0.5), ]) NSLayoutConstraint.activate([ - picker.leftAnchor.constraint(equalTo: leftAnchor), - picker.rightAnchor.constraint(equalTo: rightAnchor), - picker.bottomAnchor.constraint(equalTo: bottomAnchor), + picker.leftAnchor.constraint(equalTo: pickerBackView.leftAnchor), + picker.rightAnchor.constraint(equalTo: pickerBackView.rightAnchor), + picker.bottomAnchor.constraint(equalTo: pickerBackView.bottomAnchor), picker.topAnchor.constraint(equalTo: bottomLine.bottomAnchor), ]) } + @objc func pickerBackViewClicked() { + removeFromSuperview() + } + @objc func dateChanged(datePicker: UIDatePicker) { // 更新提醒时间文本框 let formatter = DateFormatter() @@ -118,15 +144,4 @@ public class BirthdayDatePickerView: UIView { } } } - - @objc func cancelBtnClick(sender: UIButton) { - removeFromSuperview() - } - - private lazy var bottomLine: UIView = { - let view = UIView() - view.translatesAutoresizingMaskIntoConstraints = false - view.backgroundColor = UIColor(hexString: "0xDBE0E8") - return view - }() } diff --git a/app/Mine/View/NEUserHeaderView.swift b/app/Mine/View/NEUserHeaderView.swift deleted file mode 100644 index 19ce8eb2..00000000 --- a/app/Mine/View/NEUserHeaderView.swift +++ /dev/null @@ -1,54 +0,0 @@ - -// Copyright (c) 2022 NetEase, Inc. All rights reserved. -// Use of this source code is governed by a MIT license that can be -// found in the LICENSE file. - -import UIKit - -public class NEUserHeaderView: UIImageView { - public lazy var titleLabel: UILabel = { - let label = UILabel() - label.font = UIFont.systemFont(ofSize: 12) - label.textColor = .white - label.translatesAutoresizingMaskIntoConstraints = false - return label - }() - - override public init(frame: CGRect) { - super.init(frame: frame) - setupUI() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - - func setupUI() { - contentMode = .scaleAspectFill - isUserInteractionEnabled = true - clipsToBounds = false - addSubview(titleLabel) - NSLayoutConstraint.activate([ - titleLabel.centerYAnchor - .constraint(equalTo: centerYAnchor), - titleLabel.centerXAnchor.constraint(equalTo: centerXAnchor), - ]) - backgroundColor = .clear - } - - public func configHeadData(headUrl: String?, name: String) { - if let avatar = headUrl, !avatar.isEmpty { - setTitle("") - sd_setImage(with: URL(string: avatar), completed: nil) - } else { - setTitle(name) - sd_setImage(with: nil, completed: nil) - backgroundColor = UIColor.colorWithString(string: name) - } - } - - public func setTitle(_ name: String) { - titleLabel.text = name - .count > 2 ? String(name[name.index(name.endIndex, offsetBy: -2)...]) : name - } -} diff --git a/app/Mine/View/StyleSelectionCell.swift b/app/Mine/View/StyleSelectionCell.swift new file mode 100644 index 00000000..d14baed1 --- /dev/null +++ b/app/Mine/View/StyleSelectionCell.swift @@ -0,0 +1,71 @@ +// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit + +open class StyleSelectionCell: UICollectionViewCell { + var styleName = "default" + var stylePreview = UIImageView() + var styleTitle = UILabel() + var selectButton = UIButton() + + override public init(frame: CGRect) { + super.init(frame: frame) + self.frame = CGRect(x: 0, y: 0, width: 102, height: 252) + setupSubviews() + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func setupSubviews() { + stylePreview.translatesAutoresizingMaskIntoConstraints = false + stylePreview.layer.cornerRadius = 8 + addSubview(stylePreview) + + styleTitle.translatesAutoresizingMaskIntoConstraints = false + addSubview(styleTitle) + + selectButton.translatesAutoresizingMaskIntoConstraints = false + selectButton.setImage(UIImage(named: "unclicked"), for: .normal) + // 交互在外部 cell 中处理,避免内部拦截点击事件 + selectButton.isUserInteractionEnabled = false + addSubview(selectButton) + + NSLayoutConstraint.activate([ + stylePreview.topAnchor.constraint(equalTo: topAnchor), + stylePreview.centerXAnchor.constraint(equalTo: centerXAnchor), + stylePreview.widthAnchor.constraint(equalToConstant: 102), + stylePreview.heightAnchor.constraint(equalToConstant: 180), + ]) + + NSLayoutConstraint.activate([ + styleTitle.topAnchor.constraint(equalTo: stylePreview.bottomAnchor, constant: 16), + styleTitle.centerXAnchor.constraint(equalTo: centerXAnchor), + styleTitle.heightAnchor.constraint(equalToConstant: 18), + ]) + + NSLayoutConstraint.activate([ + selectButton.topAnchor.constraint(equalTo: styleTitle.bottomAnchor, constant: 16), + selectButton.centerXAnchor.constraint(equalTo: centerXAnchor), + selectButton.widthAnchor.constraint(equalToConstant: 22), + selectButton.heightAnchor.constraint(equalToConstant: 22), + ]) + } + + func configData(model: StyleCellModel) { + styleName = model.styleName + stylePreview.image = UIImage(named: model.styleImageName) + styleTitle.text = model.styleTitle + selectButton.setImage(UIImage(named: model.selectedImageName), for: .selected) + selectButton.isSelected = model.selected + } + + /// 获取大小 + /// - Returns: 返回单元大小 + public static func getSize() -> CGSize { + CGSize(width: 102, height: 252) + } +} diff --git a/app/Mine/View/Theme/CustomTeamArrowSettingCell.swift b/app/Mine/View/Theme/CustomTeamArrowSettingCell.swift new file mode 100644 index 00000000..4c9b5ced --- /dev/null +++ b/app/Mine/View/Theme/CustomTeamArrowSettingCell.swift @@ -0,0 +1,40 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NETeamUIKit + +class CustomTeamArrowSettingCell: TeamArrowSettingCell { + override func setupUI() { + if NEStyleManager.instance.isNormalStyle() { + super.setupUI() + } else { + let whiteBgView = UIView() + whiteBgView.backgroundColor = UIColor.white + whiteBgView.translatesAutoresizingMaskIntoConstraints = false + contentView.insertSubview(whiteBgView, belowSubview: dividerLine) + NSLayoutConstraint.activate([ + whiteBgView.leftAnchor.constraint(equalTo: contentView.leftAnchor), + whiteBgView.rightAnchor.constraint(equalTo: contentView.rightAnchor), + whiteBgView.topAnchor.constraint(equalTo: contentView.topAnchor), + whiteBgView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + ]) + + contentView.addSubview(titleLabel) + NSLayoutConstraint.activate([ + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20), + titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -68), + ]) + + contentView.addSubview(arrow) + NSLayoutConstraint.activate([ + arrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + arrow.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20), + ]) + dividerLineLeftMargin?.constant = 20 + dividerLineRightMargin?.constant = 0 + } + } +} diff --git a/app/Mine/View/Theme/CustomTeamSettingHeaderCell.swift b/app/Mine/View/Theme/CustomTeamSettingHeaderCell.swift new file mode 100644 index 00000000..26f5d910 --- /dev/null +++ b/app/Mine/View/Theme/CustomTeamSettingHeaderCell.swift @@ -0,0 +1,49 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NETeamUIKit + +class CustomTeamSettingHeaderCell: TeamSettingHeaderCell { + override func setupUI() { + if NEStyleManager.instance.isNormalStyle() { + super.setupUI() + } else { + let whiteBgView = UIView() + whiteBgView.backgroundColor = UIColor.white + whiteBgView.translatesAutoresizingMaskIntoConstraints = false + contentView.insertSubview(whiteBgView, belowSubview: dividerLine) + NSLayoutConstraint.activate([ + whiteBgView.leftAnchor.constraint(equalTo: contentView.leftAnchor), + whiteBgView.rightAnchor.constraint(equalTo: contentView.rightAnchor), + whiteBgView.topAnchor.constraint(equalTo: contentView.topAnchor), + whiteBgView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + ]) + + contentView.addSubview(titleLabel) + NSLayoutConstraint.activate([ + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20), + titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -68), + ]) + + contentView.addSubview(arrow) + NSLayoutConstraint.activate([ + arrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + arrow.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20), + ]) + + contentView.addSubview(headerView) + NSLayoutConstraint.activate([ + headerView.centerYAnchor.constraint(equalTo: arrow.centerYAnchor), + headerView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -48.0), + headerView.widthAnchor.constraint(equalToConstant: 42.0), + headerView.heightAnchor.constraint(equalToConstant: 42.0), + ]) + headerView.layer.cornerRadius = 4.0 + dividerLineLeftMargin?.constant = 20 + dividerLineRightMargin?.constant = 0 + } + } +} diff --git a/app/Mine/View/Theme/CustomTeamSettingRightCustomCell.swift b/app/Mine/View/Theme/CustomTeamSettingRightCustomCell.swift new file mode 100644 index 00000000..e254caa8 --- /dev/null +++ b/app/Mine/View/Theme/CustomTeamSettingRightCustomCell.swift @@ -0,0 +1,65 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NETeamUIKit + +class CustomTeamSettingRightCustomCell: TeamSettingRightCustomCell { + override func setupUI() { + if NEStyleManager.instance.isNormalStyle() { + super.setupUI() + } else { + let whiteBgView = UIView() + whiteBgView.backgroundColor = UIColor.white + whiteBgView.translatesAutoresizingMaskIntoConstraints = false + contentView.insertSubview(whiteBgView, belowSubview: dividerLine) + NSLayoutConstraint.activate([ + whiteBgView.leftAnchor.constraint(equalTo: contentView.leftAnchor), + whiteBgView.rightAnchor.constraint(equalTo: contentView.rightAnchor), + whiteBgView.topAnchor.constraint(equalTo: contentView.topAnchor), + whiteBgView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + ]) + + contentView.addSubview(titleLabel) + contentView.addSubview(subTitleLabel) + contentView.addSubview(arrow) + + NSLayoutConstraint.activate([ + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20), + titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16), + titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + ]) + titleWidthAnchor = titleLabel.widthAnchor.constraint(equalToConstant: 0) + titleWidthAnchor?.isActive = true + + NSLayoutConstraint.activate([ + arrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + arrow.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20), + arrow.widthAnchor.constraint(equalToConstant: 7), + ]) + + NSLayoutConstraint.activate([ + subTitleLabel.leftAnchor.constraint(equalTo: titleLabel.rightAnchor, constant: 10), + subTitleLabel.rightAnchor.constraint(equalTo: arrow.leftAnchor, constant: -10), + subTitleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + ]) + + contentView.addSubview(customRightView) + NSLayoutConstraint.activate([ + customRightView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + customRightView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20), + customRightView.widthAnchor.constraint(equalToConstant: 15), + customRightView.heightAnchor.constraint(equalToConstant: 15), + ]) + customRightView.addTarget( + self, + action: #selector(customRightViewClick), + for: .touchUpInside + ) + + dividerLineLeftMargin?.constant = 20 + dividerLineRightMargin?.constant = 0 + } + } +} diff --git a/app/Mine/View/Theme/CustomTeamSettingSubtitleCell.swift b/app/Mine/View/Theme/CustomTeamSettingSubtitleCell.swift new file mode 100644 index 00000000..d8b35ed0 --- /dev/null +++ b/app/Mine/View/Theme/CustomTeamSettingSubtitleCell.swift @@ -0,0 +1,52 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NETeamUIKit + +class CustomTeamSettingSubtitleCell: TeamSettingSubtitleCell { + override func setupUI() { + if NEStyleManager.instance.isNormalStyle() { + super.setupUI() + } else { + let whiteBgView = UIView() + whiteBgView.backgroundColor = UIColor.white + whiteBgView.translatesAutoresizingMaskIntoConstraints = false + contentView.insertSubview(whiteBgView, belowSubview: dividerLine) + NSLayoutConstraint.activate([ + whiteBgView.leftAnchor.constraint(equalTo: contentView.leftAnchor), + whiteBgView.rightAnchor.constraint(equalTo: contentView.rightAnchor), + whiteBgView.topAnchor.constraint(equalTo: contentView.topAnchor), + whiteBgView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + ]) + + contentView.addSubview(titleLabel) + contentView.addSubview(subTitleLabel) + contentView.addSubview(arrow) + + NSLayoutConstraint.activate([ + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20), + titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16), + titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + ]) + titleWidthAnchor = titleLabel.widthAnchor.constraint(equalToConstant: 0) + titleWidthAnchor?.isActive = true + + NSLayoutConstraint.activate([ + arrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + arrow.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20), + arrow.widthAnchor.constraint(equalToConstant: 7), + ]) + + NSLayoutConstraint.activate([ + subTitleLabel.leftAnchor.constraint(equalTo: titleLabel.rightAnchor, constant: 10), + subTitleLabel.rightAnchor.constraint(equalTo: arrow.leftAnchor, constant: -10), + subTitleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + ]) + + dividerLineLeftMargin?.constant = 20 + dividerLineRightMargin?.constant = 0 + } + } +} diff --git a/app/Mine/View/Theme/CustomTeamSettingSwitchCell.swift b/app/Mine/View/Theme/CustomTeamSettingSwitchCell.swift new file mode 100644 index 00000000..d7466456 --- /dev/null +++ b/app/Mine/View/Theme/CustomTeamSettingSwitchCell.swift @@ -0,0 +1,44 @@ +//// Copyright (c) 2022 NetEase, Inc. All rights reserved. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +import UIKit +import NETeamUIKit + +class CustomTeamSettingSwitchCell: TeamSettingSwitchCell { + override func setupUI() { + if NEStyleManager.instance.isNormalStyle() { + super.setupUI() + } else { + let whiteBgView = UIView() + whiteBgView.backgroundColor = UIColor.white + whiteBgView.translatesAutoresizingMaskIntoConstraints = false + contentView.insertSubview(whiteBgView, belowSubview: dividerLine) + NSLayoutConstraint.activate([ + whiteBgView.leftAnchor.constraint(equalTo: contentView.leftAnchor), + whiteBgView.rightAnchor.constraint(equalTo: contentView.rightAnchor), + whiteBgView.topAnchor.constraint(equalTo: contentView.topAnchor), + whiteBgView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + ]) + + contentView.addSubview(titleLabel) + NSLayoutConstraint.activate([ + titleLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20), + titleLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + titleLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -68), + ]) + + contentView.addSubview(tSwitch) + NSLayoutConstraint.activate([ + tSwitch.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), + tSwitch.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20), + ]) + tSwitch.onTintColor = UIColor(hexString: "#58BE6B") + + tSwitch.addTarget(self, action: #selector(switchChange(_:)), for: .touchUpInside) + + dividerLineLeftMargin?.constant = 20 + dividerLineRightMargin?.constant = 0 + } + } +} diff --git a/app/Mine/ViewModel/MessageRemindViewModel.swift b/app/Mine/ViewModel/MessageRemindViewModel.swift index 175e0f0e..154ff535 100644 --- a/app/Mine/ViewModel/MessageRemindViewModel.swift +++ b/app/Mine/ViewModel/MessageRemindViewModel.swift @@ -72,7 +72,8 @@ public class MessageRemindViewModel: NSObject { let messageDetailItem = SettingCellModel() messageDetailItem.cellName = NSLocalizedString("display_message_detail", comment: "") messageDetailItem.type = SettingCellType.SettingSwitchCell.rawValue - messageDetailItem.cornerType = .bottomLeft.union(.bottomRight) +// messageDetailItem.cornerType = .bottomLeft.union(.bottomRight) + messageDetailItem.cornerType = .topLeft.union(.topRight).union(.bottomLeft).union(.bottomRight) messageDetailItem.switchOpen = repo.getPushShowDetail() messageDetailItem.swichChange = { isOpen in weakSelf?.repo.setPushShowDetail(isOpen) diff --git a/app/Mine/ViewModel/MineSettingViewModel.swift b/app/Mine/ViewModel/MineSettingViewModel.swift index 0b20346f..da8a5c14 100644 --- a/app/Mine/ViewModel/MineSettingViewModel.swift +++ b/app/Mine/ViewModel/MineSettingViewModel.swift @@ -8,6 +8,7 @@ import NETeamUIKit public protocol MineSettingViewModelDelegate: NSObjectProtocol { func didMessageRemindClick() + func didStyleClick() func didClickCleanCache() } @@ -24,14 +25,27 @@ public class MineSettingViewModel: NSObject { private func getFirstSection() -> SettingSectionModel { let model = SettingSectionModel() weak var weakSelf = self + + // 消息提醒 let remind = SettingCellModel() remind.cellName = NSLocalizedString("message_remind", comment: "") remind.type = SettingCellType.SettingArrowCell.rawValue -// remind.cornerType = .topLeft.union(.topRight) - remind.cornerType = .topLeft.union(.topRight).union(.bottomLeft).union(.bottomRight) + remind.cornerType = .topLeft.union(.topRight) +// remind.cornerType = .topLeft.union(.topRight).union(.bottomLeft).union(.bottomRight) remind.cellClick = { weakSelf?.delegate?.didMessageRemindClick() } + model.cellModels.append(remind) + + // 外观 + let style = SettingCellModel() + style.cellName = NSLocalizedString("style_selection", comment: "") + style.type = SettingCellType.SettingArrowCell.rawValue + style.cornerType = .bottomLeft.union(.bottomRight) + style.cellClick = { + weakSelf?.delegate?.didStyleClick() + } + model.cellModels.append(style) // let cleanCache = SettingCellModel() // cleanCache.cellName = "清理缓存" @@ -40,9 +54,7 @@ public class MineSettingViewModel: NSObject { // cleanCache.cellClick = { // weakSelf?.delegate?.didClickCleanCache() // } -// model.cellModels.append(contentsOf: [remind, cleanCache]) - - model.cellModels.append(contentsOf: [remind]) +// model.cellModels.append(cleanCache) return model } diff --git a/app/Mine/ViewModel/PersonInfoViewModel.swift b/app/Mine/ViewModel/PersonInfoViewModel.swift index d607a482..d9cae709 100644 --- a/app/Mine/ViewModel/PersonInfoViewModel.swift +++ b/app/Mine/ViewModel/PersonInfoViewModel.swift @@ -11,7 +11,7 @@ protocol PersonInfoViewModelDelegate: AnyObject { func didClickHeadImage() func didClickNickName(name: String) func didClickGender() - func didClickBirthday() + func didClickBirthday(birth: String) func didClickMobile(mobile: String) func didClickEmail(email: String) func didClickSign(sign: String) @@ -100,7 +100,7 @@ public class PersonInfoViewModel: NSObject { birthdayItem.subTitle = mineInfo.userInfo?.birth birthdayItem.rowHeight = 46.0 birthdayItem.cellClick = { - weakSelf?.delegate?.didClickBirthday() + weakSelf?.delegate?.didClickBirthday(birth: mineInfo.userInfo?.birth ?? "") } // 手机 let telephoneItem = SettingCellModel() diff --git a/app/en.lproj/Localizable.strings b/app/en.lproj/Localizable.strings index 751c0445..71da2335 100644 --- a/app/en.lproj/Localizable.strings +++ b/app/en.lproj/Localizable.strings @@ -29,9 +29,10 @@ "email"="E-mail"; "sign_remind"="sign remind"; -"message_remind"="Message Notification"; +"message_remind"="Notification"; +"style_selection"="Skin"; "product_intro"="Product introduction"; -"receiver_mode"="Handset mode"; +"receiver_mode"="Handset Mode"; "delete_friend"="删除好友是否同步删除备注";//功能移除可删除 "message_read_function"="Read/Unread"; "version"="Version"; @@ -60,4 +61,11 @@ "domestic_node"="China"; "overseas_node"="Singapore"; "restart"="OK"; +"text_count_limit"="limit %d characters"; +// style +"style_default"="Base Skin"; +"style_fun"="Common Skin"; + +"change_normal_style"="是否切换基础版?"; +"change_fun_style"="是否切换娱乐版?"; diff --git a/app/zh-Hans.lproj/Localizable.strings b/app/zh-Hans.lproj/Localizable.strings index 933b0bad..0fcda6ac 100644 --- a/app/zh-Hans.lproj/Localizable.strings +++ b/app/zh-Hans.lproj/Localizable.strings @@ -30,6 +30,7 @@ "sign_remind"="个性签名消息提醒"; "message_remind"="消息提醒"; +"style_selection"="外观"; "product_intro"="产品介绍"; "receiver_mode"="听筒模式"; "delete_friend"="删除好友是否同步删除备注"; @@ -60,5 +61,11 @@ "domestic_node"="国内节点配置"; "overseas_node"="海外节点配置"; "restart"="重启"; +"text_count_limit"="最多只能输入 %d 个字符哦"; +// style +"style_default"="基础皮肤"; +"style_fun"="通用皮肤"; +"change_normal_style"="是否切换基础版?"; +"change_fun_style"="是否切换娱乐版?";