| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472 |
- //
- // SecureFolderView.swift
- // NexilisLite
- //
- // Created by Maronakins on 06/12/24.
- //
- import UIKit
- import AVFoundation
- import AVKit
- import QuickLook
- public class SecureFolderViewController: UIViewController, UISearchBarDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, QLPreviewControllerDataSource {
-
- var directoryPath: URL!
- var files: [SecureFolderItem] = []
- var filteredFiles: [SecureFolderItem] = []
- var previewItem: NSURL?
- var isGridView: Bool = true
- var isTab = true
-
- public init(isTab: Bool = false) {
- self.isTab = isTab
- super.init(nibName: nil, bundle: nil)
- }
-
- required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- let searchBar: UISearchBar = {
- let sb = UISearchBar()
- sb.placeholder = "Search files"
- return sb
- }()
- let toggleButton: UIButton = {
- let button = UIButton(type: .system)
- button.setTitle("Grid", for: .normal)
- button.addTarget(nil, action: #selector(toggleViewMode), for: .touchUpInside)
- return button
- }()
- let collectionView: UICollectionView = {
- let layout = UICollectionViewFlowLayout()
- layout.minimumLineSpacing = 10
- layout.minimumInteritemSpacing = 10
-
- let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
- cv.backgroundColor = .clear
- cv.register(FileCell.self, forCellWithReuseIdentifier: "FileCell")
- return cv
- }()
-
- public override func viewDidLoad() {
- super.viewDidLoad()
- let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
- tapGesture.cancelsTouchesInView = false
- view.addGestureRecognizer(tapGesture)
- setupSubviews()
- loadFiles()
- filteredFiles = files
- }
-
- @objc func dismissKeyboard() {
- searchBar.resignFirstResponder()
- }
- @objc func toggleViewMode() {
- isGridView.toggle()
- toggleButton.setTitle(isGridView ? "Grid" : "List", for: .normal)
- collectionView.collectionViewLayout.invalidateLayout()
- collectionView.reloadData()
- }
-
- public override func viewWillAppear(_ animated: Bool) {
- // self.navigationController?.navigationController?.setNavigationBarHidden(false, animated: false)
- self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: self.traitCollection.userInterfaceStyle == .dark ? .white : UIColor.black]
- let attributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: self.traitCollection.userInterfaceStyle == .dark ? .white : UIColor.black, NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 16)]
- let navBarAppearance = UINavigationBarAppearance()
- navBarAppearance.configureWithTransparentBackground()
- navBarAppearance.titleTextAttributes = attributes
- navigationController?.navigationBar.standardAppearance = navBarAppearance
- navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
- let cancelButtonAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.foregroundColor: self.traitCollection.userInterfaceStyle == .dark ? .white : UIColor.black, NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
- UIBarButtonItem.appearance().setTitleTextAttributes(cancelButtonAttributes, for: .normal)
- navigationController?.navigationBar.backgroundColor = .clear
- navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
- navigationController?.navigationBar.shadowImage = UIImage()
- navigationController?.navigationBar.isTranslucent = true
- navigationController?.setNavigationBarHidden(false, animated: false)
- navigationController?.navigationBar.overrideUserInterfaceStyle = self.traitCollection.userInterfaceStyle == .dark ? .dark : .light
- navigationController?.navigationBar.barStyle = .default
- navigationController?.navigationBar.tintColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
- // tabBarController?.navigationItem.leftBarButtonItem = nil
- tabBarController?.navigationItem.searchController = nil
- if !isTab {
- navigationItem.leftBarButtonItem = UIBarButtonItem(
- title: "Back",
- style: .plain,
- target: self,
- action: #selector(dismissSelf)
- )
- }
- }
-
- @objc func dismissSelf() {
- dismiss(animated: true)
- }
-
- public override func viewDidAppear(_ animated: Bool) {
- // self.title = "Secure Folder".localized()
- self.navigationController?.navigationBar.topItem?.title = "Secure Folder".localized()
- self.navigationController?.navigationBar.setNeedsLayout()
- }
-
- @objc func cancel(sender: Any) {
- navigationController?.dismiss(animated: true, completion: nil)
- }
-
- func getThumbnail(for fileName: String) -> UIImage? {
- // Logic to get the file thumbnail if it exists.
- // This could include generating a thumbnail from the actual file.
- // Placeholder image is used here as an example.
- let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
- let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
- let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
- if let dirPath = paths.first {
- let thumbURL = URL(fileURLWithPath: dirPath).appendingPathComponent(fileName)
- return UIImage(contentsOfFile: thumbURL.path) ?? UIImage(systemName: "photo")?.withTintColor(.black)
- }
- return UIImage(systemName: "text.document.fill")?.withTintColor(.black) // Replace with actual thumbnail logic
- }
- func setupSubviews() {
- // Add search bar
- searchBar.delegate = self
- view.addSubview(searchBar)
- searchBar.translatesAutoresizingMaskIntoConstraints = false
- toggleButton.translatesAutoresizingMaskIntoConstraints = false
- view.addSubview(toggleButton)
- collectionView.dataSource = self
- collectionView.delegate = self
- view.addSubview(collectionView)
- collectionView.translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
- searchBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
- searchBar.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- searchBar.trailingAnchor.constraint(equalTo: toggleButton.leadingAnchor),
- toggleButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
- toggleButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8),
- toggleButton.widthAnchor.constraint(equalToConstant: 60),
- toggleButton.heightAnchor.constraint(equalTo: searchBar.heightAnchor),
- collectionView.topAnchor.constraint(equalTo: searchBar.bottomAnchor),
- collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
- ])
- }
-
- func loadFiles() {
- do {
- var query = "SELECT audio_id, video_id, image_id, thumb_id, file_id, attachment_flag, status, server_date FROM MESSAGE where (video_id IS NOT NULL AND video_id != '') OR (image_id IS NOT NULL AND image_id != '') OR (file_id IS NOT NULL AND file_id != '') order by server_date asc"
- Database.shared.database?.inTransaction({ (fmdb, rollback) in
- do {
- if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: query) {
- while cursorData.next() {
- var fileName = ""
- let audioId = cursorData.string(forColumn: "audio_id") ?? ""
- let videoId = cursorData.string(forColumn: "video_id") ?? ""
- let imageId = cursorData.string(forColumn: "image_id") ?? ""
- let thumbId = cursorData.string(forColumn: "thumb_id") ?? ""
- let fileId = cursorData.string(forColumn: "file_id") ?? ""
- let attachmentFlag = cursorData.string(forColumn: "attachment_flag") ?? ""
- let status = cursorData.string(forColumn: "status") ?? ""
- let serverDate = cursorData.string(forColumn: "server_date") ?? ""
- if imageId != "" {
- fileName = imageId
- }
- else if videoId != "" {
- fileName = videoId
- }
- else if fileId != "" {
- fileName = fileId
- }
- else if audioId != "" {
- fileName = audioId
- }
- if FileEncryption.shared.isSecureExists(filename: fileName) {
- let secureFolderItem = SecureFolderItem(audioId: audioId, videoId: videoId, imageId: imageId, fileId: fileId, thumbId: thumbId, attachmentFlag: attachmentFlag, serverDate: serverDate, status: status, filename: fileName)
- files.append(secureFolderItem)
- }
- }
- cursorData.close()
- }
- }
- catch {
- rollback.pointee = true
- print("Access database error: \(error.localizedDescription)")
- }
- })
- } catch {
- print("Error loading files: \(error.localizedDescription)")
- }
- }
- // MARK: Search Bar Delegate
-
- public func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
- filteredFiles = searchText.isEmpty ? files : files.filter { $0.filename.lowercased().contains(searchText.lowercased()) }
- collectionView.reloadData()
- }
-
- // MARK: Collection View Data Source
-
- public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
- return filteredFiles.count
- }
-
- public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
- let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FileCell", for: indexPath) as! FileCell
- let fileItem = filteredFiles[indexPath.item]
- cell.label.text = fileItem.filename
- cell.isGrid = isGridView
- if !isGridView {
- if let timestamp = Double(fileItem.serverDate) {
- let date = Date(timeIntervalSince1970: timestamp / 1000)
- let formatter = DateFormatter()
- formatter.dateFormat = "dd/MM/yy HH:mm"
- cell.dateLabel.text = formatter.string(from: date)
- } else {
- cell.dateLabel.text = fileItem.serverDate
- }
- } else {
- cell.dateLabel.text = nil
- }
- cell.dateLabel.isHidden = isGridView == true
- cell.imageView.tintColor = .black
- // cell.imageView.sizeThatFits(CGSize(width: 200.0, height: 200.0))
- var thumbnailImage = UIImage(systemName: "doc.text")?.withTintColor(.black)
- if fileItem.thumbId != "" {
- thumbnailImage = getThumbnail(for: fileItem.thumbId)
- } else if fileItem.audioId != "" {
- thumbnailImage = UIImage(systemName: "speaker.wave.3")?.withTintColor(.black)
- }
- cell.imageView.image = thumbnailImage
- return cell
- }
-
- // MARK: Collection View Delegate Flow Layout
-
- public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
- let padding: CGFloat = 10
- // let collectionViewSize = collectionView.frame.size.width - padding
- // let width = collectionViewSize / 2
- // return CGSize(width: width, height: width)
- let width = collectionView.frame.width
- if isGridView {
- let itemWidth = (width - padding * 3) / 2
- return CGSize(width: itemWidth, height: itemWidth)
- } else {
- return CGSize(width: width - padding * 2, height: 90)
- }
- }
-
- public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
- let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FileCell", for: indexPath) as! FileCell
- let fileItem = filteredFiles[indexPath.item]
- if fileItem.imageId != "" {
- print("this image")
- do {
- if var data = try FileEncryption.shared.readSecure(filename: fileItem.filename) {
- let dataDecrypt = FileEncryption.shared.decryptFileFromServer(data: data)
- if dataDecrypt != nil {
- data = dataDecrypt!
- }
- APIS.openImageNexilis(imageView: cell.imageView, data: data, isGIF: true)
- }
- }
- catch {
- print("Error reading secure file")
- }
- }
- else if fileItem.videoId != "" {
- print("this video")
- do {
- if var secureData = try FileEncryption.shared.readSecure(filename: fileItem.filename) {
- let dataDecrypt = FileEncryption.shared.decryptFileFromServer(data: secureData)
- if dataDecrypt != nil {
- secureData = dataDecrypt!
- }
- let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
- let tempPath = cachesDirectory.appendingPathComponent(fileItem.filename)
- try secureData.write(to: tempPath)
- let player = AVPlayer(url: tempPath as URL)
- let playerVC = AVPlayerViewController()
- playerVC.modalPresentationStyle = .custom
- playerVC.player = player
- self.present(playerVC, animated: true, completion: nil)
- }
- } catch {
-
- }
- }
- else if fileItem.fileId != "" {
- print("this file")
- do {
- if var docData = try FileEncryption.shared.readSecure(filename: fileItem.filename) {
- let dataDecrypt = FileEncryption.shared.decryptFileFromServer(data: docData)
- if dataDecrypt != nil {
- docData = dataDecrypt!
- }
- let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
- let tempPath = cachesDirectory.appendingPathComponent(fileItem.filename)
- try docData.write(to: tempPath)
- self.previewItem = tempPath as NSURL
- let previewController = QLPreviewController()
- let rightBarButton = UIBarButtonItem()
- previewController.navigationItem.rightBarButtonItem = rightBarButton
- previewController.dataSource = self
- previewController.modalPresentationStyle = .custom
- self.present(previewController,animated: true)
- }
- }
- catch {
-
- }
- }
- }
-
- public func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
- return self.previewItem != nil ? 1 : 0
- }
-
- public func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
- return self.previewItem!
- }
-
- }
-
- struct SecureFolderItem {
- let audioId: String
- let videoId: String
- let imageId: String
- let fileId: String
- let thumbId: String
- let attachmentFlag: String
- let serverDate: String
- let status: String
- let filename: String
-
- init(audioId: String, videoId: String, imageId: String, fileId: String, thumbId: String, attachmentFlag: String, serverDate: String, status: String, filename: String) {
- self.audioId = audioId
- self.videoId = videoId
- self.imageId = imageId
- self.fileId = fileId
- self.thumbId = thumbId
- self.attachmentFlag = attachmentFlag
- self.serverDate = serverDate
- self.status = status
- self.filename = filename
- }
- }
- // Custom UICollectionViewCell
- class FileCell: UICollectionViewCell {
-
- let imageView: UIImageView = {
- let iv = UIImageView()
- iv.contentMode = .scaleAspectFill
- iv.clipsToBounds = true
- iv.image = UIImage(systemName: "doc")
- iv.translatesAutoresizingMaskIntoConstraints = false
- iv.layer.cornerRadius = 6
- iv.layer.masksToBounds = true
- return iv
- }()
-
- let label: UILabel = {
- let lbl = UILabel()
- lbl.font = UIFont.systemFont(ofSize: 14)
- lbl.numberOfLines = 1
- lbl.translatesAutoresizingMaskIntoConstraints = false
- return lbl
- }()
- let dateLabel: UILabel = {
- let lbl = UILabel()
- lbl.font = UIFont.systemFont(ofSize: 12)
- lbl.textColor = .gray
- lbl.translatesAutoresizingMaskIntoConstraints = false
- return lbl
- }()
- var isGrid: Bool = true {
- didSet {
- updateLayout()
- }
- }
- private var gridConstraints: [NSLayoutConstraint] = []
- private var listConstraints: [NSLayoutConstraint] = []
- override init(frame: CGRect) {
- super.init(frame: frame)
-
- contentView.addSubview(imageView)
- contentView.addSubview(label)
- contentView.addSubview(dateLabel)
- setupConstraints()
- }
- private func setupConstraints() {
- // Grid layout constraints
- gridConstraints = [
- imageView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),
- imageView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
- imageView.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.6),
- imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor),
- label.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 4),
- label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 4),
- label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -4),
- dateLabel.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 2),
- dateLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 4),
- dateLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -4),
- dateLabel.bottomAnchor.constraint(lessThanOrEqualTo: contentView.bottomAnchor, constant: -4)
- ]
- // List layout constraints
- listConstraints = [
- imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8),
- imageView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
- imageView.widthAnchor.constraint(equalToConstant: 60),
- imageView.heightAnchor.constraint(equalToConstant: 60),
- label.topAnchor.constraint(equalTo: imageView.topAnchor),
- label.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: 10),
- label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -8),
- dateLabel.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 4),
- dateLabel.leadingAnchor.constraint(equalTo: label.leadingAnchor),
- dateLabel.trailingAnchor.constraint(equalTo: label.trailingAnchor)
- ]
- }
- private func updateLayout() {
- NSLayoutConstraint.deactivate(gridConstraints + listConstraints)
- if isGrid {
- NSLayoutConstraint.activate(gridConstraints)
- label.textAlignment = .center
- dateLabel.textAlignment = .center
- } else {
- NSLayoutConstraint.activate(listConstraints)
- label.textAlignment = .left
- dateLabel.textAlignment = .left
- }
- }
-
- required init?(coder: NSCoder) {
- super.init(coder: coder)
- }
- }
|