Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions iBox/Sources/Base/BaseViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ class BaseViewController<View: UIView>: UIViewController {
super.viewDidLoad()
view.addSubview(baseView)
}

}
163 changes: 163 additions & 0 deletions iBox/Sources/BoxList/BoxListView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
//
// BoxListView.swift
// iBox
//
// Created by 이지현 on 1/3/24.
//

import UIKit

import SnapKit

protocol BoxListViewDelegate: AnyObject {
func didSelectWeb(at url: String, withName name: String)
}

class BoxListView: UIView {
weak var delegate: BoxListViewDelegate?

var folderArr = [
Folder(name: "기본 폴더", color: .gray, webs: [
Web(name: "42 Intra", url: "https://profile.intra.42.fr/"),
Web(name: "42Where", url: "https://where42.kr/"),
Web(name: "42Stat", url: "https://stat.42seoul.kr/"),
Web(name: "집현전", url: "https://42library.kr/")
]),
Folder(name: "새 폴더", color: .green, webs: [Web(name: "Cabi", url: "https://cabi.42seoul.io/")], isOpened: false),
Folder(name: "새 폴더(2)", color: .yellow, webs: [Web(name: "24HANE", url: "https://24hoursarenotenough.42seoul.kr/")], isOpened: false)
]

private lazy var backgroundView = {
let view = UIView()
view.clipsToBounds = true
view.layer.cornerRadius = 20
view.backgroundColor = ColorPalette.tableViewBackgroundColor

view.addSubview(tableView)
tableView.snp.makeConstraints { make in
make.top.bottom.equalToSuperview().offset(10)
make.leading.trailing.equalToSuperview()
}
return view
}()

private lazy var tableView = {
let tableView = UITableView()
tableView.dataSource = self
tableView.delegate = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")

tableView.sectionHeaderTopPadding = 0
// tableView.separatorInset = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 15)
tableView.clipsToBounds = true
tableView.layer.cornerRadius = 20
tableView.backgroundColor = .clear
tableView.separatorColor = .clear
return tableView
}()

override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = ColorPalette.backgroundColor

setupLayout()
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

private func setupLayout() {
addSubview(backgroundView)
backgroundView.snp.makeConstraints { make in
make.top.equalTo(safeAreaLayoutGuide).inset(10)
make.leading.trailing.bottom.equalTo(safeAreaLayoutGuide).inset(20)
}
}
}

extension BoxListView: UITableViewDataSource {

func numberOfSections(in tableView: UITableView) -> Int {
return folderArr.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if !folderArr[section].isOpened {
return 0
}
return folderArr[section].webs.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.selectionStyle = .none
cell.backgroundColor = .clear
cell.textLabel?.text = folderArr[indexPath.section].webs[indexPath.row].name
cell.imageView?.image = UIImage(systemName: "ellipsis.rectangle.fill")
cell.imageView?.tintColor = ColorPalette.webIconColor
return cell
}

}

extension BoxListView: UITableViewDelegate {

public func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let view = UIView()
let line = UIView()
view.addSubview(line)
line.snp.makeConstraints { make in
make.top.bottom.equalToSuperview()
make.leading.trailing.equalToSuperview().inset(15)
}
view.backgroundColor = ColorPalette.tableViewBackgroundColor
line.backgroundColor = .tertiaryLabel
return view
}

public func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 0.3
}

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let button = FolderButton(isOpen: folderArr[section].isOpened)
button.setFolderName(folderArr[section].name)
button.setFolderColor(folderArr[section].color.toUIColor())
button.tag = section

button.addTarget(self, action: #selector(handleOpenClose), for: .touchUpInside)

return button
}

@objc private func handleOpenClose(button: FolderButton) {
let section = button.tag

var indexPaths = [IndexPath]()
for row in folderArr[section].webs.indices {
let indexPath = IndexPath(row: row, section: section)
indexPaths.append(indexPath)
}

folderArr[section].isOpened.toggle()
button.toggleStatus()

if folderArr[section].isOpened {
tableView.insertRows(at: indexPaths, with: .fade)
} else {
tableView.deleteRows(at: indexPaths, with: .fade)
}
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let webUrl = folderArr[indexPath.section].webs[indexPath.row].url
let webName = folderArr[indexPath.section].webs[indexPath.row].name
delegate?.didSelectWeb(at: webUrl, withName: webName)
}
}

29 changes: 29 additions & 0 deletions iBox/Sources/BoxList/BoxListViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// BoxListViewController.swift
// iBox
//
// Created by 이지현 on 12/27/23.
//

import UIKit

class BoxListViewController: BaseViewController<BoxListView> {

override func viewDidLoad() {
super.viewDidLoad()
baseView.delegate = self

title = "iBox"
navigationController?.navigationBar.prefersLargeTitles = true
}

}

extension BoxListViewController: BoxListViewDelegate {
func didSelectWeb(at url: String, withName name: String) {
let viewController = WebViewController()
viewController.title = name
viewController.selectedWebsite = url
navigationController?.pushViewController(viewController, animated: true)
}
}
81 changes: 81 additions & 0 deletions iBox/Sources/BoxList/FolderButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//
// FolderButton.swift
// iBox
//
// Created by 이지현 on 1/4/24.
//

import UIKit

import SnapKit

class FolderButton: UIButton {
private var isOpen: Bool = true

private lazy var folderImageView = {
let imageView = UIImageView()
imageView.image = UIImage(systemName: "folder.fill")
imageView.contentMode = .scaleAspectFit
return imageView
}()

private lazy var folderNameLabel = {
let label = UILabel()
label.textColor = .label
label.font = .systemFont(ofSize: 18, weight: .semibold)
return label
}()

private lazy var openCloseImageView = {
let imageView = UIImageView()
imageView.tintColor = .tertiaryLabel
imageView.image = isOpen ? UIImage(systemName: "chevron.up") : UIImage(systemName: "chevron.down")
return imageView
}()

init(isOpen: Bool) {
self.isOpen = isOpen
super.init(frame: .zero)
backgroundColor = .clear

setupLayout()
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

private func setupLayout() {
addSubview(folderImageView)
folderImageView.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.width.height.equalTo(30)
make.leading.equalToSuperview().offset(20)
}

addSubview(folderNameLabel)
folderNameLabel.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.leading.equalTo(folderImageView.snp.trailing).offset(10)
}

addSubview(openCloseImageView)
openCloseImageView.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.trailing.equalToSuperview().offset(-20)
}
}

func setFolderName(_ name: String) {
folderNameLabel.text = name
}

func setFolderColor(_ color: UIColor) {
folderImageView.tintColor = color
}

func toggleStatus() {
isOpen = !isOpen
openCloseImageView.image = isOpen ? UIImage(systemName: "chevron.up") : UIImage(systemName: "chevron.down")
}
}
20 changes: 20 additions & 0 deletions iBox/Sources/BoxList/Model/Folder.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// Folder.swift
// iBox
//
// Created by 이지현 on 1/4/24.
//

import Foundation

struct Folder {
let name: String
let color: ColorName
let webs: [Web]
var isOpened: Bool = true
}

struct Web {
let name: String
let url: String
}
76 changes: 76 additions & 0 deletions iBox/Sources/ColorPalette.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//
// ColorPalette.swift
// iBox
//
// Created by 이지현 on 1/3/24.
//

import UIKit

enum ColorName: String {
case gray
case green
case red
case blue
case yellow

func toUIColor() -> UIColor {
switch self {
case .gray:
return UIColor.systemGray2
case .green:
return UIColor.systemGreen
case .red:
return UIColor.systemRed
case .blue:
return UIColor.systemBlue
case .yellow:
return UIColor.systemYellow
}
}
}

struct ColorPalette {

public static var backgroundColor = {
return UIColor { (UITraitCollection: UITraitCollection) -> UIColor in
if UITraitCollection.userInterfaceStyle == .dark {
return .black
} else {
return .systemGray5
}
}
}()

public static var tableViewBackgroundColor = {
return UIColor { (UITraitCollection: UITraitCollection) -> UIColor in
if UITraitCollection.userInterfaceStyle == .dark {
return .systemGray5
} else {
return .white
}
}
}()

public static var folderGray = {
return UIColor { (UITraitCollection: UITraitCollection) -> UIColor in
if UITraitCollection.userInterfaceStyle == .dark {
return .systemGray2
} else {
return .systemGray3
}
}
}()

public static var webIconColor = {
return UIColor { (UITraitCollection: UITraitCollection) -> UIColor in
if UITraitCollection.userInterfaceStyle == .dark {
return .systemGray
} else {
return .black
}
}
}()

}

Loading