Skip to content

Commit

Permalink
Merge pull request #269 from mahee96/master
Browse files Browse the repository at this point in the history
-[Feature]: Multi-line input for adding bulk tracker URLs
  • Loading branch information
XITRIX authored Nov 7, 2023
2 parents 0ffb998 + e9a4d3e commit 3885d5e
Show file tree
Hide file tree
Showing 8 changed files with 463 additions and 13 deletions.
122 changes: 122 additions & 0 deletions iTorrent/CustomViews/EditTextView/EditTextView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//
// EditTextViewController.swift
// iTorrent
//
// Created by Magesh K on 17.10.2023.
// Copyright © 2023  Magesh K. All rights reserved.
//

import Foundation
import UIKit

// EditTextView - UI Control
class EditTextView: UITextView{

// Set margins using UIEdgeInsets
let defaultMargins = UIEdgeInsets(top: 4, left: 12, bottom: 12, right: 12)
let defaultPlaceholder = NSLocalizedString("PlaceHolder text", comment: "")

// Custom placeholder text
var placeholder: String? {
didSet { placeholderLabel.text = placeholder }
}

// Custom placeholder text color
var placeholderTextColor: UIColor = .lightGray {
didSet { placeholderLabel.textColor = placeholderTextColor }
}

// Private UILabel for the placeholder text
private let placeholderLabel: UILabel = {
let label = UILabel()
label.textColor = .lightGray
return label
}()


/* Override methods */
override init(frame: CGRect, textContainer: NSTextContainer?){
super.init(frame: frame, textContainer:textContainer)
performCustomizations()
}

required init?(coder: NSCoder){
super.init(coder:coder)
performCustomizations()
}


/* Helper methods */
private func performCustomizations() -> Void{
let textView = self
let theme = Themes.current

textView.keyboardAppearance = theme.keyboardAppearence
textView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
textView.font = UIFont.systemFont(ofSize: UIFont.systemFontSize * 1.0)
textView.contentInset.left = 2 //For left padding
textView.contentInset.right = 2 //For right padding
textView.contentInset.top = 2 //For top padding
textView.contentInset.bottom = 2 //For bottom padding

textView.layer.borderWidth = 0.5
textView.layer.cornerRadius = 8
textView.layer.borderColor = UIColor.lightGray.withAlphaComponent(0.5).cgColor
textView.layer.backgroundColor = nil
textView.returnKeyType = .default
textView.autocapitalizationType = .none

textView.translatesAutoresizingMaskIntoConstraints = false
setupPlaceholderLabel()
}

private func setupPlaceholderLabel() {
addSubview(placeholderLabel)

placeholder = self.defaultPlaceholder
placeholderLabel.font = UIFont.systemFont(ofSize: UIFont.systemFontSize * 1.0)
placeholderLabel.layer.borderColor = UIColor.lightGray.withAlphaComponent(0.5).cgColor

placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
// Set constraints for the placeholder label
NSLayoutConstraint.activate([
placeholderLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: self.contentInset.left+4),
placeholderLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -(self.contentInset.right+4)),
placeholderLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: self.contentInset.top+6),
placeholderLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -(self.contentInset.bottom+6))
])

// Hide the placeholder label when there is text
NotificationCenter.default.addObserver(self, selector: #selector(textDidChange), name: UITextView.textDidChangeNotification, object: nil)
}

@objc private func textDidChange() {
placeholderLabel.isHidden = !text.isEmpty
}

public func setDefaultMargins(){
setMargins(by: self.defaultMargins)
}


public func setMargins(by: UIEdgeInsets){
let margins = by
if let containerView = self.superview{
self.frame = containerView.frame
// Add constraints to the UITextView within the parent view
NSLayoutConstraint.activate([
self.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: margins.left),
self.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -margins.right),
self.topAnchor.constraint(equalTo: containerView.topAnchor, constant: margins.top),
self.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -margins.bottom)
])
}
}

// callback for superview changes
override func didMoveToSuperview() {
// attach superView's frame reference into this view
// and set margins if superView is present
self.setDefaultMargins()
}
}
84 changes: 84 additions & 0 deletions iTorrent/CustomViews/EditTextView/EditTextViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//
// EditTextViewController.swift
// iTorrent
//
// Created by Magesh K on 17.10.2023.
// Copyright © 2023  Magesh K. All rights reserved.
//

import Foundation
import UIKit

class EditTextViewController: UIViewController, UITextViewDelegate {

private let editTextView:EditTextView
private let SINGLE_LINE_HEIGHT:Double = 54.0

convenience init(){
self.init(editTextView: EditTextView())
}

init(editTextView: EditTextView){
self.editTextView = editTextView
super.init(nibName: nil, bundle: nil)
}

required init?(coder: NSCoder) {
self.editTextView = EditTextView()
super.init(coder: coder)
}

override func viewDidLoad() {
super.viewDidLoad()
// add the UITextView
self.view.addSubview(self.editTextView)
// register callback for textView changes
editTextView.delegate = self
// Create a height constraint for the view controller's view
viewControllerHeightConstraint = view.heightAnchor.constraint(equalToConstant: SINGLE_LINE_HEIGHT)
viewControllerHeightConstraint.isActive = true
}

var viewControllerHeightConstraint: NSLayoutConstraint!

func textViewDidChange(_ textView: UITextView) {

let maxLinesToShow:Double = 1.5
let maxContentSize:Double = SINGLE_LINE_HEIGHT * maxLinesToShow

var contentSize:Double = textView.contentSize.height + 17.0
if contentSize > maxContentSize{
contentSize = maxContentSize
}
if contentSize < SINGLE_LINE_HEIGHT{
contentSize = SINGLE_LINE_HEIGHT
}

if(contentSize != prevContentSize){
// Calculate the content height of the UITextView
// Update the height constraint of the view controller's view
viewControllerHeightConstraint.constant = contentSize

// Optionally, animate the constraint change
UIView.animate(
withDuration: 0.5,
delay: 0.0,
usingSpringWithDamping: 0.5, // Adjust this value (lower for more bounce, higher for less)
initialSpringVelocity: 0.0, //Adjust this value (higher for more initial velocity)
options: [.curveEaseInOut], // Use curveEaseInOut
animations: {
self.view.layoutIfNeeded()
},
completion: nil
)
}
prevContentSize = contentSize


// Optionally, you can scroll to the bottom as the user types
// let bottomOffset = CGPoint(x: 0, y: max(textView.contentSize.height - textView.bounds.size.height, 0))
// textView.setContentOffset(bottomOffset, animated: false)
}

private var prevContentSize: Double = 0.0
}
91 changes: 91 additions & 0 deletions iTorrent/CustomViews/ProgressView/ProgressViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
//
// ProgressViewController.swift
// iTorrent
//
// Created by Magesh K on 19/10/23.
// Copyright © 2023 Magesh K. All rights reserved.
//

import Foundation
import UIKit

class ProgressViewController: UIViewController {
private let progressView = UIActivityIndicatorView(style: .whiteLarge)
private let progressLabel = ThemedUILabel()
private var progress:Float = 0.0

override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(white: 0, alpha: 0.7) // Semi-transparent background

// Do not perform autolayout
progressView.translatesAutoresizingMaskIntoConstraints = false
progressLabel.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(progressView)
view.addSubview(progressLabel)

progressView.hidesWhenStopped = true

// explicit layout constraints
NSLayoutConstraint.activate([
// center the progressView on parent view
progressView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
progressView.centerYAnchor.constraint(equalTo: view.centerYAnchor),

// place the progress label below the progressView with constant space between the two
progressLabel.topAnchor.constraint(equalTo: progressView.bottomAnchor, constant: 8), // Adjust the spacing as needed
progressLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
])

progressLabel.textColor = .white
// progressLabel.font = UIFont.systemFont(ofSize: 16) // Adjust the size
// progressLabel.font = UIFont.boldSystemFont(ofSize: 16)
progressLabel.font = UIFont(name: "Helvetica-Bold", size: 16)
progressLabel.backgroundColor = .clear

progressView.startAnimating() // Start the activity indicator
}

public func runSyncOnUIThread(action: ()->Void){
if (Thread.isMainThread){ action() }
else { DispatchQueue.main.sync { action() } }
}

public func showProgress(presenter: UIViewController?, animated: Bool=true, action: (()->Void)? = nil) {
runSyncOnUIThread{
progressLabel.text = "0.00%"
modalPresentationStyle = .overFullScreen
modalTransitionStyle = .crossDissolve
presenter?.present(self, animated: animated, completion: action)
}
}

public func hideProgress(animated: Bool=true, action: (()->Void)? = nil) {
runSyncOnUIThread{
dismiss(animated: animated, completion: action)
}
}

public func setProgress(_ progress: Float) {
// Keep progress updates synchronously on UI Thread
runSyncOnUIThread {
self.progress = progress
// cap the progress at 100%
if(progress > 100.0){ self.progress = 100.0 }
self.progressLabel.text = String(format: "%.2f%%", self.progress)
}
}

public func getProgress()->Float{
return self.progress
}

public func consumeRemainingPercentage(){
var totalProgress = self.progress
let increment:Float = 1.0
while(totalProgress <= 100.0){
totalProgress += increment // increment the progress
setProgress(totalProgress)
}
}
}
29 changes: 29 additions & 0 deletions iTorrent/Utils/Dialog.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,35 @@ class Dialog {
presenter?.present(dialog, animated: true)
}

static func withTextView(_ presenter: UIViewController?,
title: String? = nil,
message: String? = nil,
textViewConfiguration: ((EditTextView) -> ())?,
cancelText: String = "Close",
okText: String = "OK",
okAction: @escaping (EditTextView) -> ()) {

let dialog = ThemedUIAlertController(title: Localize.get(key: title),
message: Localize.get(key: message),
preferredStyle: .alert)

let editTextView = EditTextView()
let editTextController = EditTextViewController(editTextView: editTextView)

textViewConfiguration!(editTextView)
dialog.setValue(editTextController, forKey: "contentViewController")

let cancel = UIAlertAction(title: Localize.get(cancelText), style: .cancel)
let ok = UIAlertAction(title: Localize.get(okText), style: .default) { _ in
okAction(editTextView)
}

dialog.addAction(cancel)
dialog.addAction(ok)

presenter?.present(dialog, animated: true)
}

static func withButton(_ presenter: UIViewController? = Utils.topViewController, title: String? = nil, message: String? = nil, okTitle: String, action: @escaping ()->()) {
let dialog = ThemedUIAlertController(title: Localize.get(key: title),
message: Localize.get(key: message),
Expand Down
Loading

0 comments on commit 3885d5e

Please sign in to comment.