| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- //
- // LNCreateFeedViewController.swift
- // Gami
- //
- // Created by OneeChan on 2026/2/27.
- //
- import Foundation
- import UIKit
- import SnapKit
- extension UIView {
- func pushToCreateFeed() {
- let vc = LNCreateFeedViewController()
- navigationController?.pushViewController(vc, animated: true)
- }
- }
- class LNCreateFeedViewController: LNViewController {
- private let saveButton = UIButton()
- private let maxPhotosCount = 6
- private let photosView = UIStackView()
- private var imageUrls: [String] {
- photosView.arrangedSubviews.compactMap { ($0 as? LNImageUploadView)?.imageUrl }
- }
- private let selectPhotoView = UIView()
- private let videoUploadView = LNVideoUploadView()
- private let textInputView = LNCommonTextView()
-
- override func viewDidLoad() {
- super.viewDidLoad()
-
- setupViews()
- }
- }
- extension LNCreateFeedViewController: LNImageUploadViewDelegate, LNVideoUploadViewDelegate {
- func onImageUploadViewDidClickDelete(view: LNImageUploadView) {
- photosView.removeArrangedSubview(view)
- view.removeFromSuperview()
- selectPhotoView.isHidden = false
- checkSaveButton()
- }
-
- func onImageUploadView(view: LNImageUploadView, didUploadImage url: String) {
- checkSaveButton()
- }
-
- func onVideoUploadViewDidClickDelete(view: LNVideoUploadView) {
- photosView.superview?.isHidden = false
- videoUploadView.superview?.isHidden = true
- checkSaveButton()
- }
-
- func onVideoUploadViewStartUpload(view: LNVideoUploadView) {
- showLoading()
- }
-
- func onVideoUploadViewUploadFailed(view: LNVideoUploadView) {
- dismissLoading()
- }
-
- func onVideoUploadView(view: LNVideoUploadView, didUploadVideo url: String, imageUrl: String) {
- let media = LNFeedMediaVO()
- media.type = .video
- media.url = url
- media.videoCover = imageUrl
- let item = LNPostFeedItem(text: textInputView.text, medias: [media])
- LNFeedManager.shared.postFeed(item: item) { [weak self] success in
- dismissLoading()
- guard let self else { return }
- if success {
- navigationController?.popViewController(animated: true)
- }
- }
- }
- }
- extension LNCreateFeedViewController: UITextViewDelegate {
- func textViewDidChange(_ textView: UITextView) {
- checkSaveButton()
- }
- }
- extension LNCreateFeedViewController {
- private func checkSaveButton() {
- let enable = !textInputView.text.isEmpty
- || !imageUrls.isEmpty
- || videoUploadView.superview?.isHidden == false
-
- if enable != saveButton.isEnabled {
- if enable {
- saveButton.setBackgroundImage(.primary_8, for: .normal)
- } else {
- saveButton.setBackgroundImage(nil, for: .normal)
- }
- saveButton.isEnabled = enable
- }
- }
-
- private func setupViews() {
- setupNavBar()
-
- view.onTap { [weak self] in
- guard let self else { return }
- view.endEditing(true)
- }
-
- let stackView = UIStackView()
- stackView.axis = .vertical
- stackView.spacing = 16
- stackView.clipsToBounds = false
- view.addSubview(stackView)
- stackView.snp.makeConstraints { make in
- make.horizontalEdges.equalToSuperview().inset(16)
- make.top.equalToSuperview().offset(16)
- }
-
- let photos = buildPhotos()
- stackView.addArrangedSubview(photos)
-
- let video = buildVideo()
- stackView.addArrangedSubview(video)
-
- let text = buildText()
- stackView.addArrangedSubview(text)
- }
-
- private func setupNavBar() {
- title = .init(key: "A00295")
-
- saveButton.setTitle(.init(key: "A00185"), for: .normal)
- saveButton.titleLabel?.font = .heading_h4
- saveButton.setTitleColor(.white, for: .normal)
- saveButton.backgroundColor = .fill_4
- saveButton.layer.cornerRadius = 16
- saveButton.clipsToBounds = true
- saveButton.contentEdgeInsets = .init(top: 0, left: 16, bottom: 0, right: 16)
- saveButton.addAction(UIAction(handler: { [weak self] _ in
- guard let self else { return }
- if videoUploadView.superview?.isHidden == false {
- videoUploadView.startUpload()
- } else {
- var medias: [LNFeedMediaVO] = []
- for url in self.imageUrls {
- let media = LNFeedMediaVO()
- media.type = .image
- media.url = url
- medias.append(media)
- }
- let item = LNPostFeedItem(text: textInputView.text, medias: medias)
- showLoading()
- LNFeedManager.shared.postFeed(item: item) { [weak self] success in
- dismissLoading()
- guard let self else { return }
- guard success else {
- return
- }
- showToast(.init(key: "A00306"))
- navigationController?.popViewController(animated: true)
- }
- }
- }), for: .touchUpInside)
- saveButton.snp.makeConstraints { make in
- make.height.equalTo(32)
- make.width.greaterThanOrEqualTo(67)
- }
- setRightButton(saveButton)
-
- saveButton.isEnabled = false
- }
-
- private func buildPhotos() -> UIView {
- let scrollView = UIScrollView()
- scrollView.showsHorizontalScrollIndicator = false
- scrollView.clipsToBounds = false
-
- photosView.axis = .horizontal
- photosView.spacing = 10
- scrollView.addSubview(photosView)
- photosView.snp.makeConstraints { make in
- make.edges.equalToSuperview()
- make.height.equalToSuperview()
- make.height.equalTo(90)
- }
-
- selectPhotoView.backgroundColor = .fill_1
- selectPhotoView.layer.cornerRadius = 8.33
- selectPhotoView.onTap { [weak self] in
- guard let self else { return }
- LNBottomSheetMenu.showImageSelectMenu(view: view, options: .init(allowVideo: photosView.arrangedSubviews.count == 1))
- { [weak self] image, videoUrl in
- guard let self else { return }
- if let image {
- let imageView = buildImageView()
- imageView.uploadImage(image: image)
- imageView.onTap { [weak self, weak imageView] in
- guard let self, let imageView else { return }
- guard let url = imageView.imageUrl else { return }
- view.presentImagePreview(imageUrls, imageUrls.firstIndex(of: url)!)
- }
- photosView.insertArrangedSubview(imageView, at: photosView.arrangedSubviews.count - 1)
- imageView.snp.makeConstraints { make in
- make.width.equalTo(imageView.snp.height)
- }
- selectPhotoView.isHidden = photosView.arrangedSubviews.count == maxPhotosCount + 1
- } else if let videoUrl {
- photosView.superview?.isHidden = true
- videoUploadView.superview?.isHidden = false
-
- let size = videoUploadView.preview(url: videoUrl)
- let previewSize: CGSize = size.width >= size.height ? .init(width: 173, height: 130) : .init(width: 130, height: 173)
- videoUploadView.snp.updateConstraints { make in
- make.size.equalTo(previewSize)
- }
- checkSaveButton()
- }
- }
- }
- selectPhotoView.snp.makeConstraints { make in
- make.width.equalTo(selectPhotoView.snp.height)
- }
- photosView.addArrangedSubview(selectPhotoView)
-
- let selectView = UIView()
- selectView.isUserInteractionEnabled = false
- selectPhotoView.addSubview(selectView)
- selectView.snp.makeConstraints { make in
- make.horizontalEdges.equalToSuperview()
- make.centerY.equalToSuperview()
- }
-
- let cameraIc = UIImageView(image: .icImChatCamera)
- selectView.addSubview(cameraIc)
- cameraIc.snp.makeConstraints { make in
- make.centerX.equalToSuperview()
- make.top.equalToSuperview()
- }
-
- let tipsLabel = UILabel()
- tipsLabel.text = .init(key: "A00296")
- tipsLabel.numberOfLines = 2
- tipsLabel.font = .body_xs
- tipsLabel.textColor = .text_4
- tipsLabel.textAlignment = .center
- selectView.addSubview(tipsLabel)
- tipsLabel.snp.makeConstraints { make in
- make.horizontalEdges.equalToSuperview().inset(10)
- make.top.equalTo(cameraIc.snp.bottom).offset(2)
- make.bottom.equalToSuperview()
- }
-
- return scrollView
- }
-
- private func buildImageView() -> LNImageUploadView {
- let imageView = LNImageUploadView()
- imageView.uploadType = .feedback
- imageView.layer.cornerRadius = 9
- imageView.clipsToBounds = true
- imageView.showClearButton = true
- imageView.delegate = self
-
- return imageView
- }
-
- private func buildVideo() -> UIView {
- let container = UIView()
- container.isHidden = true
-
- videoUploadView.delegate = self
- videoUploadView.onTap { [weak self] in
- guard let self else { return }
- guard let sourceUrl = videoUploadView.sourceUrl else { return }
- view.presentVideoPreview([sourceUrl.absoluteString], 0)
- }
- videoUploadView.snp.makeConstraints { make in
- make.size.equalTo(CGSize.zero)
- }
- container.addSubview(videoUploadView)
- videoUploadView.snp.makeConstraints { make in
- make.verticalEdges.equalToSuperview()
- make.leading.equalToSuperview()
- }
-
- return container
- }
-
- private func buildText() -> UIView {
- textInputView.maxInput = LNFeedManager.feedMaxIntput
- textInputView.placeholderLabel.text = .init(key: "A00297")
- textInputView.placeholderLabel.font = .body_m
- textInputView.placeholderLabel.textColor = .text_2
- textInputView.delegate = self
- textInputView.snp.makeConstraints { make in
- make.height.equalTo(229)
- }
-
- return textInputView
- }
- }
- #if DEBUG
- import SwiftUI
- struct LNCreateFeedViewControllerPreview: UIViewControllerRepresentable {
- func makeUIViewController(context: Context) -> some UIViewController {
- LNCreateFeedViewController()
- }
-
- func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
-
- }
- }
- #Preview(body: {
- LNCreateFeedViewControllerPreview()
- })
- #endif
|