mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
441 lines
18 KiB
Swift
441 lines
18 KiB
Swift
import Foundation
|
|
import Display
|
|
import AsyncDisplayKit
|
|
import SwiftSignalKit
|
|
import TelegramCore
|
|
|
|
extension UISearchBar {
|
|
func setTextColor(_ color: UIColor) {
|
|
for view in self.subviews {
|
|
if let view = view as? UITextField {
|
|
view.textColor = color
|
|
return
|
|
} else {
|
|
for subview in view.subviews {
|
|
if let subview = subview as? UITextField {
|
|
subview.textColor = color
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private final class LanguageAccessoryView: UIView {
|
|
private let check: UIImageView
|
|
private let indicator: ActivityIndicator
|
|
|
|
init(theme: PresentationTheme) {
|
|
self.check = UIImageView()
|
|
self.check.image = PresentationResourcesItemList.checkIconImage(theme)
|
|
|
|
self.indicator = ActivityIndicator(type: .navigationAccent(theme))
|
|
|
|
super.init(frame: CGRect())
|
|
|
|
self.addSubview(self.check)
|
|
self.addSubnode(self.indicator)
|
|
}
|
|
|
|
required init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override func sizeToFit() {
|
|
self.frame = CGRect(origin: CGPoint(), size: self.check.image!.size)
|
|
|
|
let size = self.bounds.size
|
|
|
|
if let image = self.check.image {
|
|
let checkSize = image.size
|
|
self.check.frame = CGRect(origin: CGPoint(x: floor((size.width - checkSize.width) / 2.0), y: floor((size.height - checkSize.height) / 2.0)), size: checkSize)
|
|
}
|
|
|
|
let indicatorSize = self.indicator.measure(CGSize(width: 22.0, height: 22.0))
|
|
self.indicator.frame = CGRect(origin: CGPoint(x: floor((size.width - indicatorSize.width) / 2.0), y: floor((size.height - indicatorSize.height) / 2.0)), size: indicatorSize)
|
|
}
|
|
|
|
func setType(_ type: Int) {
|
|
switch type {
|
|
case 0:
|
|
self.check.isHidden = true
|
|
self.indicator.isHidden = true
|
|
case 1:
|
|
self.check.isHidden = false
|
|
self.indicator.isHidden = true
|
|
case 2:
|
|
self.check.isHidden = true
|
|
self.indicator.isHidden = false
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
private final class InnerCoutrySearchResultsController: UIViewController, UITableViewDelegate, UITableViewDataSource {
|
|
private let tableView: UITableView
|
|
|
|
var searchResults: [LocalizationInfo] = [] {
|
|
didSet {
|
|
self.tableView.reloadData()
|
|
}
|
|
}
|
|
|
|
var itemSelected: ((LocalizationInfo) -> Void)?
|
|
|
|
init() {
|
|
self.tableView = UITableView(frame: CGRect(), style: .plain)
|
|
|
|
super.init(nibName: nil, bundle: nil)
|
|
}
|
|
|
|
required init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
|
|
self.view.backgroundColor = .white
|
|
|
|
self.view.addSubview(self.tableView)
|
|
self.tableView.frame = self.view.bounds
|
|
self.tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
self.tableView.dataSource = self
|
|
self.tableView.delegate = self
|
|
}
|
|
|
|
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
|
return self.searchResults.count
|
|
}
|
|
|
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
|
let cell: UITableViewCell
|
|
if let currentCell = tableView.dequeueReusableCell(withIdentifier: "LanguageCell") {
|
|
cell = currentCell
|
|
} else {
|
|
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "LanguageCell")
|
|
}
|
|
cell.textLabel?.text = self.searchResults[indexPath.row].title
|
|
cell.detailTextLabel?.text = self.searchResults[indexPath.row].localizedTitle
|
|
|
|
return cell
|
|
}
|
|
|
|
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
|
self.itemSelected?(self.searchResults[indexPath.row])
|
|
}
|
|
}
|
|
|
|
private final class InnerLanguageSelectionController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating, UISearchBarDelegate {
|
|
private let account: Account
|
|
|
|
private let tableView: UITableView
|
|
|
|
private var languages: [LocalizationInfo]
|
|
|
|
private var searchController: UISearchController!
|
|
private var searchResultsController: InnerCoutrySearchResultsController!
|
|
|
|
var dismiss: (() -> Void)?
|
|
|
|
private var languagesDisposable: Disposable?
|
|
|
|
private var presentationData: PresentationData
|
|
private var presentationDataDisposable: Disposable?
|
|
|
|
private var applyingLanguage: (LocalizationInfo, Disposable)?
|
|
|
|
init(account: Account) {
|
|
self.account = account
|
|
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
|
|
|
self.tableView = UITableView(frame: CGRect(), style: .plain)
|
|
|
|
self.languages = []
|
|
|
|
super.init(nibName: nil, bundle: nil)
|
|
|
|
self.title = self.presentationData.strings.Settings_AppLanguage
|
|
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
|
|
|
|
self.definesPresentationContext = true
|
|
|
|
self.presentationDataDisposable = (account.telegramApplicationContext.presentationData
|
|
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
|
if let strongSelf = self {
|
|
let previousTheme = strongSelf.presentationData.theme
|
|
let previousStrings = strongSelf.presentationData.strings
|
|
|
|
strongSelf.presentationData = presentationData
|
|
|
|
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings {
|
|
strongSelf.updateThemeAndStrings()
|
|
}
|
|
}
|
|
})
|
|
|
|
self.languagesDisposable = (availableLocalizations(network: account.network)
|
|
|> deliverOnMainQueue).start(next: { [weak self] languages in
|
|
if let strongSelf = self {
|
|
strongSelf.languages = languages
|
|
if strongSelf.isViewLoaded {
|
|
strongSelf.tableView.reloadData()
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
required init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
deinit {
|
|
self.languagesDisposable?.dispose()
|
|
self.presentationDataDisposable?.dispose()
|
|
self.applyingLanguage?.1.dispose()
|
|
}
|
|
|
|
private func updateThemeAndStrings() {
|
|
self.title = self.presentationData.strings.Settings_AppLanguage
|
|
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
|
|
|
|
if self.isViewLoaded {
|
|
self.searchController.searchBar.placeholder = self.presentationData.strings.Common_Search
|
|
self.tableView.reloadData()
|
|
}
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
|
|
self.view.backgroundColor = .white
|
|
|
|
self.searchResultsController = InnerCoutrySearchResultsController()
|
|
self.searchResultsController.itemSelected = { [weak self] language in
|
|
if let strongSelf = self {
|
|
strongSelf.searchController.searchBar.resignFirstResponder()
|
|
strongSelf.applyLanguage(language)
|
|
}
|
|
}
|
|
|
|
self.searchController = UISearchController(searchResultsController: self.searchResultsController)
|
|
self.searchController.searchResultsUpdater = self
|
|
self.searchController.dimsBackgroundDuringPresentation = true
|
|
self.searchController.searchBar.delegate = self
|
|
|
|
self.tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
self.view.addSubview(self.tableView)
|
|
self.tableView.tableHeaderView = self.searchController.searchBar
|
|
self.tableView.dataSource = self
|
|
self.tableView.delegate = self
|
|
self.tableView.backgroundColor = self.presentationData.theme.chatList.backgroundColor
|
|
self.tableView.separatorColor = self.presentationData.theme.chatList.itemSeparatorColor
|
|
self.tableView.backgroundView = UIView()
|
|
|
|
self.tableView.frame = self.view.bounds
|
|
self.view.addSubview(self.tableView)
|
|
|
|
self.searchController.searchBar.placeholder = self.presentationData.strings.Common_Search
|
|
self.searchController.searchBar.barTintColor = self.presentationData.theme.chatList.backgroundColor
|
|
self.searchController.searchBar.tintColor = self.presentationData.theme.rootController.navigationBar.accentTextColor
|
|
self.searchController.searchBar.backgroundColor = self.presentationData.theme.chatList.backgroundColor
|
|
self.searchController.searchBar.setTextColor(self.presentationData.theme.chatList.titleColor)
|
|
|
|
let searchImage = generateImage(CGSize(width: 8.0, height: 28.0), rotatedContext: { size, context in
|
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
|
context.setFillColor(self.presentationData.theme.chatList.regularSearchBarColor.cgColor)
|
|
context.fillEllipse(in: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.width)))
|
|
context.fillEllipse(in: CGRect(origin: CGPoint(x: 0.0, y: size.height - size.width), size: CGSize(width: size.width, height: size.width)))
|
|
context.fill(CGRect(origin: CGPoint(x: 0.0, y: size.width / 2.0), size: CGSize(width: size.width, height: size.height - size.width)))
|
|
})
|
|
self.searchController.searchBar.setSearchFieldBackgroundImage(searchImage, for: [])
|
|
self.searchController.searchBar.backgroundImage = UIImage()
|
|
}
|
|
|
|
func numberOfSections(in tableView: UITableView) -> Int {
|
|
return 1
|
|
}
|
|
|
|
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
|
return self.languages.count
|
|
}
|
|
|
|
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
|
return nil
|
|
}
|
|
|
|
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
|
|
return nil
|
|
}
|
|
|
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
|
let cell: UITableViewCell
|
|
if let currentCell = tableView.dequeueReusableCell(withIdentifier: "LanguageCell") {
|
|
cell = currentCell
|
|
} else {
|
|
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "LanguageCell")
|
|
cell.selectedBackgroundView = UIView()
|
|
cell.accessoryView = LanguageAccessoryView(theme: self.presentationData.theme)
|
|
cell.accessoryView?.sizeToFit()
|
|
}
|
|
cell.textLabel?.text = self.languages[indexPath.row].title
|
|
cell.textLabel?.textColor = self.presentationData.theme.chatList.titleColor
|
|
cell.detailTextLabel?.text = self.languages[indexPath.row].localizedTitle
|
|
cell.detailTextLabel?.textColor = self.presentationData.theme.chatList.titleColor
|
|
cell.backgroundColor = self.presentationData.theme.chatList.itemBackgroundColor
|
|
cell.selectedBackgroundView?.backgroundColor = self.presentationData.theme.chatList.itemHighlightedBackgroundColor
|
|
|
|
var type: Int = 0
|
|
if let (info, _) = self.applyingLanguage, info.languageCode == self.languages[indexPath.row].languageCode {
|
|
type = 2
|
|
} else if self.presentationData.strings.languageCode == self.languages[indexPath.row].languageCode {
|
|
type = 1
|
|
}
|
|
|
|
(cell.accessoryView as? LanguageAccessoryView)?.setType(type)
|
|
|
|
return cell
|
|
}
|
|
|
|
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
|
tableView.deselectRow(at: indexPath, animated: true)
|
|
self.applyLanguage(self.languages[indexPath.row])
|
|
}
|
|
|
|
func updateSearchResults(for searchController: UISearchController) {
|
|
guard let normalizedQuery = searchController.searchBar.text?.lowercased() else {
|
|
self.searchResultsController.searchResults = []
|
|
return
|
|
}
|
|
|
|
var results: [LocalizationInfo] = []
|
|
for language in self.languages {
|
|
if language.title.lowercased().hasPrefix(normalizedQuery) || language.localizedTitle.lowercased().hasPrefix(normalizedQuery) {
|
|
results.append(language)
|
|
}
|
|
}
|
|
self.searchResultsController.searchResults = results
|
|
}
|
|
|
|
@objc func cancelPressed() {
|
|
self.dismiss?()
|
|
}
|
|
|
|
private func applyLanguage(_ language: LocalizationInfo) {
|
|
if let (info, disposable) = self.applyingLanguage {
|
|
if info.languageCode == language.languageCode {
|
|
return
|
|
} else {
|
|
disposable.dispose()
|
|
self.applyingLanguage = nil
|
|
self.tableView.reloadData()
|
|
}
|
|
}
|
|
if language.languageCode != self.presentationData.strings.languageCode {
|
|
self.applyingLanguage = (language, (downoadAndApplyLocalization(postbox: self.account.postbox, network: self.account.network, languageCode: language.languageCode) |> deliverOnMainQueue).start(completed: { [weak self] in
|
|
if let strongSelf = self {
|
|
strongSelf.applyingLanguage = nil
|
|
strongSelf.tableView.reloadData()
|
|
}
|
|
}))
|
|
self.tableView.reloadData()
|
|
}
|
|
}
|
|
}
|
|
|
|
final class LanguageSelectionController: ViewController {
|
|
private var controllerNode: LanguageSelectionControllerNode {
|
|
return self.displayNode as! LanguageSelectionControllerNode
|
|
}
|
|
|
|
private let innerNavigationController: UINavigationController
|
|
private let innerController: InnerLanguageSelectionController
|
|
|
|
private var presentationData: PresentationData
|
|
private var presentationDataDisposable: Disposable?
|
|
|
|
init(account: Account) {
|
|
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
|
|
|
self.innerController = InnerLanguageSelectionController(account: account)
|
|
self.innerNavigationController = UINavigationController(rootViewController: self.innerController)
|
|
|
|
super.init(navigationBarTheme: nil)
|
|
|
|
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBar.style.style
|
|
self.innerNavigationController.navigationBar.barTintColor = self.presentationData.theme.rootController.navigationBar.backgroundColor
|
|
self.innerNavigationController.navigationBar.tintColor = self.presentationData.theme.rootController.navigationBar.accentTextColor
|
|
self.innerNavigationController.navigationBar.shadowImage = generateImage(CGSize(width: 1.0, height: 1.0), rotatedContext: { size, context in
|
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
|
context.setFillColor(self.presentationData.theme.rootController.navigationBar.separatorColor.cgColor)
|
|
context.fill(CGRect(origin: CGPoint(), size: CGSize(width: 1.0, height: UIScreenPixel)))
|
|
})
|
|
self.innerNavigationController.navigationBar.isTranslucent = false
|
|
self.innerNavigationController.navigationBar.titleTextAttributes = [NSFontAttributeName: Font.semibold(17.0), NSForegroundColorAttributeName: self.presentationData.theme.rootController.navigationBar.primaryTextColor]
|
|
|
|
self.innerController.dismiss = { [weak self] in
|
|
self?.cancelPressed()
|
|
}
|
|
|
|
self.presentationDataDisposable = (account.telegramApplicationContext.presentationData
|
|
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
|
if let strongSelf = self {
|
|
let previousTheme = strongSelf.presentationData.theme
|
|
let previousStrings = strongSelf.presentationData.strings
|
|
|
|
strongSelf.presentationData = presentationData
|
|
|
|
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings {
|
|
strongSelf.updateThemeAndStrings()
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
required init(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
deinit {
|
|
self.presentationDataDisposable?.dispose()
|
|
}
|
|
|
|
private func updateThemeAndStrings() {
|
|
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBar.style.style
|
|
}
|
|
|
|
override public func loadDisplayNode() {
|
|
self.displayNode = LanguageSelectionControllerNode()
|
|
self.displayNodeDidLoad()
|
|
|
|
self.innerNavigationController.willMove(toParentViewController: self)
|
|
self.addChildViewController(self.innerNavigationController)
|
|
self.displayNode.view.addSubview(self.innerNavigationController.view)
|
|
self.innerNavigationController.didMove(toParentViewController: self)
|
|
|
|
self.controllerNode.dismiss = { [weak self] in
|
|
self?.presentingViewController?.dismiss(animated: true, completion: nil)
|
|
}
|
|
}
|
|
|
|
override func viewDidAppear(_ animated: Bool) {
|
|
super.viewDidAppear(animated)
|
|
|
|
self.innerNavigationController.viewWillAppear(false)
|
|
self.innerNavigationController.viewDidAppear(false)
|
|
|
|
self.controllerNode.animateIn()
|
|
}
|
|
|
|
override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
|
super.containerLayoutUpdated(layout, transition: transition)
|
|
|
|
self.innerNavigationController.view.frame = CGRect(origin: CGPoint(), size: layout.size)
|
|
}
|
|
|
|
private func cancelPressed() {
|
|
self.controllerNode.animateOut()
|
|
}
|
|
}
|