feat: implement pick server view category select

This commit is contained in:
jk234ert 2021-02-23 22:14:10 +08:00
parent 738ba832a9
commit eb7a33932e
14 changed files with 650 additions and 7 deletions

View File

@ -11,6 +11,11 @@
0FAA101225E105390017CCDE /* PrimaryActionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FAA101125E105390017CCDE /* PrimaryActionButton.swift */; };
0FAA101C25E10E760017CCDE /* UIFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FAA101B25E10E760017CCDE /* UIFont.swift */; };
0FAA102725E1126A0017CCDE /* PickServerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FAA102625E1126A0017CCDE /* PickServerViewController.swift */; };
0FB3D2F725E4C24D00AAD544 /* PickServerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB3D2F625E4C24D00AAD544 /* PickServerViewModel.swift */; };
0FB3D2FE25E4CB6400AAD544 /* PickServerTitleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB3D2FD25E4CB6400AAD544 /* PickServerTitleCell.swift */; };
0FB3D30825E524C600AAD544 /* PickServerCategoriesCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB3D30725E524C600AAD544 /* PickServerCategoriesCell.swift */; };
0FB3D30F25E525CD00AAD544 /* PickServerCategoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB3D30E25E525CD00AAD544 /* PickServerCategoryView.swift */; };
0FB3D31E25E534C700AAD544 /* PickServerCategoryCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB3D31D25E534C700AAD544 /* PickServerCategoryCollectionViewCell.swift */; };
18BC7629F65E6DB12CB8416D /* Pods_Mastodon_MastodonUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */; };
2D04F42525C255B9003F936F /* APIService+PublicTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D04F42425C255B9003F936F /* APIService+PublicTimeline.swift */; };
2D152A8C25C295CC009AA50C /* StatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D152A8B25C295CC009AA50C /* StatusView.swift */; };
@ -204,6 +209,11 @@
0FAA101125E105390017CCDE /* PrimaryActionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrimaryActionButton.swift; sourceTree = "<group>"; };
0FAA101B25E10E760017CCDE /* UIFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIFont.swift; sourceTree = "<group>"; };
0FAA102625E1126A0017CCDE /* PickServerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerViewController.swift; sourceTree = "<group>"; };
0FB3D2F625E4C24D00AAD544 /* PickServerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerViewModel.swift; sourceTree = "<group>"; };
0FB3D2FD25E4CB6400AAD544 /* PickServerTitleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerTitleCell.swift; sourceTree = "<group>"; };
0FB3D30725E524C600AAD544 /* PickServerCategoriesCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerCategoriesCell.swift; sourceTree = "<group>"; };
0FB3D30E25E525CD00AAD544 /* PickServerCategoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerCategoryView.swift; sourceTree = "<group>"; };
0FB3D31D25E534C700AAD544 /* PickServerCategoryCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerCategoryCollectionViewCell.swift; sourceTree = "<group>"; };
2D04F42425C255B9003F936F /* APIService+PublicTimeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+PublicTimeline.swift"; sourceTree = "<group>"; };
2D152A8B25C295CC009AA50C /* StatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusView.swift; sourceTree = "<group>"; };
2D152A9125C2980C009AA50C /* UIFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIFont.swift; sourceTree = "<group>"; };
@ -414,11 +424,40 @@
0FAA102525E1125D0017CCDE /* PickServer */ = {
isa = PBXGroup;
children = (
0FB3D31825E525DE00AAD544 /* CollectionViewCell */,
0FB3D30D25E525C000AAD544 /* View */,
0FB3D2FC25E4CB4B00AAD544 /* TableViewCell */,
0FAA102625E1126A0017CCDE /* PickServerViewController.swift */,
0FB3D2F625E4C24D00AAD544 /* PickServerViewModel.swift */,
);
path = PickServer;
sourceTree = "<group>";
};
0FB3D2FC25E4CB4B00AAD544 /* TableViewCell */ = {
isa = PBXGroup;
children = (
0FB3D2FD25E4CB6400AAD544 /* PickServerTitleCell.swift */,
0FB3D30725E524C600AAD544 /* PickServerCategoriesCell.swift */,
);
path = TableViewCell;
sourceTree = "<group>";
};
0FB3D30D25E525C000AAD544 /* View */ = {
isa = PBXGroup;
children = (
0FB3D30E25E525CD00AAD544 /* PickServerCategoryView.swift */,
);
path = View;
sourceTree = "<group>";
};
0FB3D31825E525DE00AAD544 /* CollectionViewCell */ = {
isa = PBXGroup;
children = (
0FB3D31D25E534C700AAD544 /* PickServerCategoryCollectionViewCell.swift */,
);
path = CollectionViewCell;
sourceTree = "<group>";
};
1EBA4F56E920856A3FC84ACB /* Pods */ = {
isa = PBXGroup;
children = (
@ -1328,6 +1367,7 @@
0FAA0FDF25E0B57E0017CCDE /* WelcomeViewController.swift in Sources */,
DB45FB1D25CA9D23005A8AC7 /* APIService+HomeTimeline.swift in Sources */,
2D7631B325C159F700929FB9 /* Item.swift in Sources */,
0FB3D2F725E4C24D00AAD544 /* PickServerViewModel.swift in Sources */,
2D61335E25C1894B00CAE157 /* APIService.swift in Sources */,
2D38F1F725CD47AC00561493 /* HomeTimelineViewModel+LoadOldestState.swift in Sources */,
2D5A3D3825CF8D9F002347D6 /* ScrollViewContainer.swift in Sources */,
@ -1361,6 +1401,7 @@
DB5086A525CC0B7000C2C187 /* AvatarBarButtonItem.swift in Sources */,
2D38F1E525CD46C100561493 /* HomeTimelineViewModel.swift in Sources */,
2D76316B25C14D4C00929FB9 /* PublicTimelineViewModel.swift in Sources */,
0FB3D2FE25E4CB6400AAD544 /* PickServerTitleCell.swift in Sources */,
2D38F1DF25CD46A400561493 /* HomeTimelineViewController+StatusProvider.swift in Sources */,
2D46975E25C2A54100CF4AA9 /* NSLayoutConstraint.swift in Sources */,
2D45E5BF25C9549700A6D639 /* PublicTimelineViewModel+State.swift in Sources */,
@ -1375,6 +1416,7 @@
DB8AF55025C13703002E6C99 /* MainTabBarController.swift in Sources */,
DB9D6BE925E4F5340051B173 /* SearchViewController.swift in Sources */,
2D38F1C625CD37F400561493 /* ContentOffsetAdjustableTimelineViewControllerDelegate.swift in Sources */,
0FB3D30F25E525CD00AAD544 /* PickServerCategoryView.swift in Sources */,
DB8AF54525C13647002E6C99 /* NeedsDependency.swift in Sources */,
DB9D6BF825E4F5690051B173 /* NotificationViewController.swift in Sources */,
DB45FADD25CA6F6B005A8AC7 /* APIService+CoreData+MastodonUser.swift in Sources */,
@ -1417,7 +1459,10 @@
2D32EAAC25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift in Sources */,
2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */,
DB9D6BFF25E4F5940051B173 /* ProfileViewController.swift in Sources */,
0FB3D30825E524C600AAD544 /* PickServerCategoriesCell.swift in Sources */,
2D38F1FE25CD481700561493 /* StatusProvider.swift in Sources */,
2D5A3D1125CF87AA002347D6 /* AvatarBarButtonItem.swift in Sources */,
0FB3D31E25E534C700AAD544 /* PickServerCategoryCollectionViewCell.swift in Sources */,
DB45FB0F25CA87D0005A8AC7 /* AuthenticationService.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -39,6 +39,7 @@ extension SceneCoordinator {
enum Scene {
case welcome
case pickServer(viewMode: PickServerViewModel)
case authentication(viewModel: AuthenticationViewModel)
case mastodonPinBasedAuthentication(viewModel: MastodonPinBasedAuthenticationViewModel)
case mastodonRegister(viewModel: MastodonRegisterViewModel)
@ -136,6 +137,10 @@ private extension SceneCoordinator {
case .welcome:
let _viewController = WelcomeViewController()
viewController = _viewController
case .pickServer(let viewModel):
let _viewController = PickServerViewController()
_viewController.viewModel = viewModel
viewController = _viewController
case .authentication(let viewModel):
let _viewController = AuthenticationViewController()
_viewController.viewModel = viewModel

View File

@ -2,7 +2,7 @@
// UIFont.swift
// Mastodon
//
// Created by on 2021/2/20.
// Created by BradGao on 2021/2/20.
//
import UIKit

View File

@ -35,4 +35,28 @@ extension UIView {
layer.cornerCurve = .continuous
return self
}
@discardableResult
func applyShadow(
color: UIColor,
alpha: Float,
x: CGFloat,
y: CGFloat,
blur: CGFloat,
spread: CGFloat = 0) -> Self
{
layer.masksToBounds = false
layer.shadowColor = color.cgColor
layer.shadowOpacity = alpha
layer.shadowOffset = CGSize(width: x, height: y)
layer.shadowRadius = blur / 2.0
if spread == 0 {
layer.shadowPath = nil
} else {
let dx = -spread
let rect = bounds.insetBy(dx: dx, dy: dx)
layer.shadowPath = UIBezierPath(rect: rect).cgPath
}
return self
}
}

View File

@ -110,6 +110,12 @@ internal enum L10n {
internal enum ServerPicker {
/// Pick a Server,\nany server.
internal static let title = L10n.tr("Localizable", "Scene.ServerPicker.Title")
internal enum Button {
internal enum Category {
/// All
internal static let all = L10n.tr("Localizable", "Scene.ServerPicker.Button.Category.All")
}
}
internal enum Input {
/// Find a server or join your own...
internal static let placeholder = L10n.tr("Localizable", "Scene.ServerPicker.Input.Placeholder")

View File

@ -32,6 +32,7 @@
"Scene.ServerPicker.Input.Placeholder" = "Find a server or join your own...";
"Scene.ServerPicker.Title" = "Pick a Server,
any server.";
"Scene.ServerPicker.Button.Category.All" = "All";
"Scene.ServerRules.Button.Confirm" = "I Agree";
"Scene.ServerRules.Prompt" = "By continuing, you're subject to the terms of service and privacy policy for %@.";
"Scene.ServerRules.Subtitle" = "These rules are set by the admins of %@.";

View File

@ -0,0 +1,52 @@
//
// PickServerCategoryCollectionViewCell.swift
// Mastodon
//
// Created by BradGao on 2021/2/23.
//
import UIKit
class PickServerCategoryCollectionViewCell: UICollectionViewCell {
var category: PickServerViewModel.Category? {
didSet {
categoryView.category = category
}
}
var categoryView: PickServerCategoryView = {
let view = PickServerCategoryView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override var isSelected: Bool {
didSet {
categoryView.selected = isSelected
}
}
override init(frame: CGRect) {
super.init(frame: .zero)
configure()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
configure()
}
}
extension PickServerCategoryCollectionViewCell {
private func configure() {
contentView.addSubview(categoryView)
NSLayoutConstraint.activate([
categoryView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
categoryView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
categoryView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
contentView.bottomAnchor.constraint(equalTo: categoryView.bottomAnchor, constant: 10),
])
}
}

View File

@ -2,12 +2,21 @@
// PickServerViewController.swift
// Mastodon
//
// Created by on 2021/2/20.
// Created by BradGao on 2021/2/20.
//
import UIKit
import Combine
class PickServerViewController: UIViewController {
final class PickServerViewController: UIViewController, NeedsDependency {
private var disposeBag = Set<AnyCancellable>()
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
var viewModel: PickServerViewModel!
let titleLabel: UILabel = {
let label = UILabel()
label.font = .boldSystemFont(ofSize: 34)
@ -18,4 +27,63 @@ class PickServerViewController: UIViewController {
label.numberOfLines = 0
return label
}()
let tableView: UITableView = {
let tableView = ControlContainableTableView()
tableView.register(PickServerTitleCell.self, forCellReuseIdentifier: String(describing: PickServerTitleCell.self))
tableView.register(PickServerCategoriesCell.self, forCellReuseIdentifier: String(describing: PickServerCategoriesCell.self))
// tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self))
tableView.rowHeight = UITableView.automaticDimension
tableView.separatorStyle = .none
tableView.backgroundColor = .clear
tableView.translatesAutoresizingMaskIntoConstraints = false
return tableView
}()
let nextStepButton: PrimaryActionButton = {
let button = PrimaryActionButton(type: .system)
button.setTitle(L10n.Button.signUp, for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
}
extension PickServerViewController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .darkContent
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = Asset.Colors.Background.onboardingBackground.color
view.addSubview(nextStepButton)
NSLayoutConstraint.activate([
nextStepButton.leadingAnchor.constraint(equalTo: view.readableContentGuide.leadingAnchor, constant: 12),
view.readableContentGuide.trailingAnchor.constraint(equalTo: nextStepButton.trailingAnchor, constant: 12),
view.bottomAnchor.constraint(equalTo: nextStepButton.bottomAnchor, constant: 34),
])
view.addSubview(tableView)
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
nextStepButton.topAnchor.constraint(equalTo: tableView.bottomAnchor, constant: 7)
])
switch viewModel.mode {
case .SignIn:
nextStepButton.setTitle(L10n.Common.Controls.Actions.signIn, for: .normal)
case .SignUp:
nextStepButton.setTitle(L10n.Common.Controls.Actions.continue, for: .normal)
}
tableView.delegate = viewModel
tableView.dataSource = viewModel
}
}

View File

@ -0,0 +1,165 @@
//
// PickServerViewModel.swift
// Mastodon
//
// Created by BradGao on 2021/2/23.
//
import UIKit
import Combine
import MastodonSDK
class PickServerViewModel: NSObject {
enum PickServerMode {
case SignUp
case SignIn
}
enum Section: CaseIterable {
case title
case categories
case serverList
}
enum Category {
// `All` means search for all categories
case All
// `Some` means search for specific category
case Some(Mastodon.Entity.Category)
var title: String {
switch self {
case .All:
return L10n.Scene.ServerPicker.Button.Category.all
case .Some(let masCategory):
switch masCategory.category {
case .academia:
return "AC"
case .activism:
return "AT"
case .food:
return "F"
case .furry:
return "FU"
case .games:
return "G"
case .general:
return "GE"
case .journalism:
return "JO"
case .lgbt:
return "LG"
case .regional:
return "📍"
case .art:
return "🎨"
case .music:
return "🎼"
case .tech:
return "📱"
case ._other:
return "UN"
}
}
}
}
let mode: PickServerMode
let context: AppContext
var categories = [Category]()
let selectCategoryIndex = CurrentValueSubject<Int, Never>(0)
let searchText = CurrentValueSubject<String?, Never>(nil)
let allServers = CurrentValueSubject<[Mastodon.Entity.Instance], Error>([])
let searchedServers = CurrentValueSubject<[Mastodon.Entity.Instance], Error>([])
let nextButtonEnable = CurrentValueSubject<Bool, Never>(false)
init(context: AppContext, mode: PickServerMode) {
self.context = context
self.mode = mode
super.init()
configure()
}
private func configure() {
let masCategories = context.apiService.stubCategories()
categories.append(.All)
categories.append(contentsOf: masCategories.map { Category.Some($0) })
}
}
extension PickServerViewModel: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if section == 0 {
return 20
}
else if section == 1 {
return 10
}
else {
return 10
}
}
}
extension PickServerViewModel: UITableViewDataSource {
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return UIView()
}
func numberOfSections(in tableView: UITableView) -> Int {
return Self.Section.allCases.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let section = Self.Section.allCases[section]
switch section {
case .title,
.categories:
return 1
case .serverList:
return searchedServers.value.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let section = Self.Section.allCases[indexPath.section]
switch section {
case .title:
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PickServerTitleCell.self), for: indexPath) as! PickServerTitleCell
return cell
case .categories:
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PickServerCategoriesCell.self), for: indexPath) as! PickServerCategoriesCell
cell.dataSource = self
cell.delegate = self
return cell
case .serverList:
return UITableViewCell(style: .default, reuseIdentifier: "1")
}
}
}
extension PickServerViewModel: PickServerCategoriesDataSource, PickServerCategoriesDelegate {
func numberOfCategories() -> Int {
return categories.count
}
func category(at index: Int) -> Category {
return categories[index]
}
func selectedIndex() -> Int {
return selectCategoryIndex.value
}
func pickServerCategoriesCell(didSelect index: Int) {
selectCategoryIndex.send(index)
}
}

View File

@ -0,0 +1,110 @@
//
// PickServerCategoriesCell.swift
// Mastodon
//
// Created by BradGao on 2021/2/23.
//
import UIKit
import MastodonSDK
protocol PickServerCategoriesDataSource: class {
func numberOfCategories() -> Int
func category(at index: Int) -> PickServerViewModel.Category
func selectedIndex() -> Int
}
protocol PickServerCategoriesDelegate: class {
func pickServerCategoriesCell(didSelect index: Int)
}
final class PickServerCategoriesCell: UITableViewCell {
weak var dataSource: PickServerCategoriesDataSource!
weak var delegate: PickServerCategoriesDelegate!
let collectionView: UICollectionView = {
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .horizontal
let view = ControlContainableCollectionView(frame: .zero, collectionViewLayout: flowLayout)
view.backgroundColor = .clear
view.showsHorizontalScrollIndicator = false
view.register(PickServerCategoryCollectionViewCell.self, forCellWithReuseIdentifier: String(describing: PickServerCategoryCollectionViewCell.self))
view.showsVerticalScrollIndicator = false
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
_init()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
_init()
}
}
extension PickServerCategoriesCell {
private func _init() {
self.selectionStyle = .none
backgroundColor = .clear
contentView.addSubview(collectionView)
NSLayoutConstraint.activate([
collectionView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
collectionView.topAnchor.constraint(equalTo: contentView.topAnchor),
collectionView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
collectionView.heightAnchor.constraint(equalToConstant: 80),
])
collectionView.delegate = self
collectionView.dataSource = self
}
}
extension PickServerCategoriesCell: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredHorizontally)
delegate.pickServerCategoriesCell(didSelect: indexPath.row)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 16
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 60, height: 80)
}
}
extension PickServerCategoriesCell: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataSource.numberOfCategories()
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let category = dataSource.category(at: indexPath.row)
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: PickServerCategoryCollectionViewCell.self), for: indexPath) as! PickServerCategoryCollectionViewCell
cell.category = category
// Select the default category by default
if indexPath.row == dataSource.selectedIndex() {
// Use `[]` as the scrollPosition to avoid contentOffset change
collectionView.selectItem(at: indexPath, animated: false, scrollPosition: [])
cell.isSelected = true
}
return cell
}
}

View File

@ -0,0 +1,48 @@
//
// PickServerTitleCell.swift
// Mastodon
//
// Created by BradGao on 2021/2/23.
//
import UIKit
final class PickServerTitleCell: UITableViewCell {
let titleLabel: UILabel = {
let label = UILabel()
label.font = UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: UIFont.boldSystemFont(ofSize: 34))
label.textColor = Asset.Colors.Label.black.color
label.text = L10n.Scene.ServerPicker.title
label.adjustsFontForContentSizeCategory = true
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
_init()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
_init()
}
}
extension PickServerTitleCell {
private func _init() {
self.selectionStyle = .none
backgroundColor = .clear
contentView.addSubview(titleLabel)
NSLayoutConstraint.activate([
titleLabel.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor),
contentView.readableContentGuide.trailingAnchor.constraint(equalTo: titleLabel.trailingAnchor),
titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor),
titleLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
])
}
}

View File

@ -0,0 +1,107 @@
//
// PickServerCategoryView.swift
// Mastodon
//
// Created by BradGao on 2021/2/23.
//
import UIKit
import MastodonSDK
class PickServerCategoryView: UIView {
var category: PickServerViewModel.Category? {
didSet {
updateCategory()
}
}
var selected: Bool = false {
didSet {
updateSelectStatus()
}
}
var bgShadowView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
var bgView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.masksToBounds = true
view.layer.cornerRadius = 30
return view
}()
var titleLabel: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
init() {
super.init(frame: .zero)
configure()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
configure()
}
}
extension PickServerCategoryView {
private func configure() {
// bgShadowView.backgroundColor = nil
// addSubview(bgShadowView)
// bgShadowView.addSubview(bgView)
addSubview(bgView)
addSubview(titleLabel)
bgView.backgroundColor = .white
NSLayoutConstraint.activate([
// bgShadowView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
// bgShadowView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
// bgShadowView.topAnchor.constraint(equalTo: self.topAnchor),
// bgShadowView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
bgView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
bgView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
bgView.topAnchor.constraint(equalTo: self.topAnchor),
bgView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
titleLabel.centerXAnchor.constraint(equalTo: self.centerXAnchor),
titleLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor),
])
}
private func updateCategory() {
guard let category = category else { return }
titleLabel.text = category.title
switch category {
case .All:
titleLabel.font = UIFont.systemFont(ofSize: 17)
case .Some:
titleLabel.font = UIFont.systemFont(ofSize: 28)
}
}
private func updateSelectStatus() {
if selected {
bgView.backgroundColor = Asset.Colors.lightBrandBlue.color
bgView.applyShadow(color: Asset.Colors.lightBrandBlue.color, alpha: 1, x: 0, y: 0, blur: 4.0)
if case .All = category {
titleLabel.textColor = .white
}
} else {
bgView.backgroundColor = .white
bgView.applyShadow(color: Asset.Colors.lightBrandBlue.color, alpha: 0, x: 0, y: 0, blur: 0.0)
if case .All = category {
titleLabel.textColor = Asset.Colors.lightBackground.color
}
}
}
}

View File

@ -2,7 +2,7 @@
// PrimaryActionButton.swift
// Mastodon
//
// Created by on 2021/2/20.
// Created by BradGao on 2021/2/20.
//
import UIKit

View File

@ -2,7 +2,7 @@
// WelcomeViewController.swift
// Mastodon
//
// Created by on 2021/2/20.
// Created by BradGao on 2021/2/20.
//
import os.log
@ -88,8 +88,8 @@ extension WelcomeViewController {
signInButton.topAnchor.constraint(equalTo: signUpButton.bottomAnchor, constant: 5)
])
signInButton.addTarget(self, action: #selector(WelcomeViewController.signInButtonPressed(_:)), for: .touchUpInside)
signUpButton.addTarget(self, action: #selector(WelcomeViewController.signUpButtonPressed(_:)), for: .touchUpInside)
signUpButton.addTarget(self, action: #selector(signUpButtonDidClicked(_:)), for: .touchUpInside)
signInButton.addTarget(self, action: #selector(signInButtonDidClicked(_:)), for: .touchUpInside)
}
override func viewWillAppear(_ animated: Bool) {
@ -119,3 +119,15 @@ extension WelcomeViewController {
}
}
extension WelcomeViewController {
@objc
private func signUpButtonDidClicked(_ sender: UIButton) {
coordinator.present(scene: .pickServer(viewMode: PickServerViewModel(context: context, mode: .SignUp)), from: self, transition: .show)
}
@objc
private func signInButtonDidClicked(_ sender: UIButton) {
coordinator.present(scene: .pickServer(viewMode: PickServerViewModel(context: context, mode: .SignIn)), from: self, transition: .show)
}
}