Merge pull request #2 from rock-n-code/feature/browse-files

Feature: Browse files UI
This commit is contained in:
Javier Cicchelli 2022-12-03 09:44:16 +01:00 committed by GitHub
commit a77e866ded
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 407 additions and 15 deletions

View File

@ -76,13 +76,6 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
027F60592937662300467238 /* Login */ = {
isa = PBXGroup;
children = (
);
path = Login;
sourceTree = "<group>";
};
02AE64E229363DBF005A4AF3 = {
isa = PBXGroup;
children = (
@ -109,7 +102,6 @@
isa = PBXGroup;
children = (
02FFFD7929395DBF00306533 /* Extensions */,
027F60592937662300467238 /* Login */,
02AE64EE29363DBF005A4AF3 /* BeRealApp.swift */,
02AE64F029363DBF005A4AF3 /* ContentView.swift */,
02AE64F229363DC1005A4AF3 /* Assets.xcassets */,

View File

@ -7,17 +7,14 @@
//
import SwiftUI
import Browse
import Login
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
NavigationView {
BrowseView()
}
.padding()
.sheet(isPresented: .constant(true)) {
LoginView()
}

View File

@ -12,7 +12,8 @@ let package = Package(
.library(
name: "Modules",
targets: [
"Login"
"Login",
"Browse"
]
),
],
@ -21,5 +22,9 @@ let package = Package(
name: "Login",
resources: [.process("Resources")]
),
.target(
name: "Browse",
resources: [.process("Resources")]
)
]
)

View File

@ -0,0 +1,14 @@
/*
Localizable.strings
Browse
Created by Javier Cicchelli on 03/12/2022.
Copyright © 2022 Röck+Cöde. All rights reserved.
*/
"browse.toolbar_item.menu.add_actions.text" = "Add file and/or folder";
"browse.toolbar_item.button.add_folder.text" = "Create a new folder";
"browse.toolbar_item.button.add_file.text" = "Upload a file";
"browse.toolbar_item.button.show_profile.text" = "Show profile";
"browse.swipe_action.delete_item.text" = "Delete item";
"browse.swipe_action.download_item.text" = "Download item";

View File

@ -0,0 +1,71 @@
//
// DocumentItem.swift
// Browse
//
// Created by Javier Cicchelli on 03/12/2022.
// Copyright © 2022 Röck+Cöde. All rights reserved.
//
import SwiftUI
struct DocumentItem: View {
// MARK: Properties
let name: String
let lastModified: String
let fileSize: String
// MARK: Body
var body: some View {
HStack(spacing: 16) {
Image.document
.icon(size: 32)
.foregroundColor(.red)
VStack {
Text(name)
.itemName()
HStack {
Text(lastModified)
Spacer()
Text(fileSize)
}
.font(.subheadline)
.foregroundColor(.secondary)
}
}
.padding(.vertical, 8)
}
}
// MARK: - Image+Constants
private extension Image {
static let document = Image(systemName: "doc.fill")
}
// MARK: - Previews
struct DocumentItem_Previews: PreviewProvider {
static var previews: some View {
DocumentItem(
name: "Some document name goes in here...",
lastModified: "Some few hours ago",
fileSize: "23,5 Mbytes"
)
.previewDisplayName("Document item")
DocumentItem(
name: "Some very, extremely long document name goes in here...",
lastModified: "Yesterday",
fileSize: "235,6 Kbytes"
)
.previewDisplayName("Document item with long name")
}
}

View File

@ -0,0 +1,55 @@
//
// FolderItem.swift
// Browse
//
// Created by Javier Cicchelli on 02/12/2022.
// Copyright © 2022 Röck+Cöde. All rights reserved.
//
import SwiftUI
struct FolderItem: View {
// MARK: Properties
let name: String
// MARK: Body
var body: some View {
HStack(spacing: 16) {
Image.folder
.icon(size: 32)
.foregroundColor(.red)
Text(name)
.itemName()
Image.chevronRight
.icon(size: 16)
.foregroundColor(.secondary)
.font(.headline)
}
.padding(.vertical, 8)
}
}
// MARK: - Image+Constants
private extension Image {
static let folder = Image(systemName: "folder.fill")
static let chevronRight = Image(systemName: "chevron.right")
}
// MARK: - Previews
struct BrowseItem_Previews: PreviewProvider {
static var previews: some View {
FolderItem(name: "Some folder name goes in here...")
.previewDisplayName("Folder item")
FolderItem(name: "Some very, extremely long folder name goes in here...")
.previewDisplayName("Folder item with long name")
}
}

View File

@ -0,0 +1,24 @@
//
// Image+Helpers.swift
// Browse
//
// Created by Javier Cicchelli on 03/12/2022.
// Copyright © 2022 Röck+Cöde. All rights reserved.
//
import SwiftUI
extension Image {
/// Resizes an image to a given size.
/// - Parameter size: A size to which an image will be resized.
/// - Returns: An resized image rendered as an erasured view.
func icon(size: CGFloat) -> some View {
self
.resizable()
.renderingMode(.template)
.scaledToFit()
.frame(width: size, height: size)
}
}

View File

@ -0,0 +1,23 @@
//
// Text+Helpers.swift
// Browse
//
// Created by Javier Cicchelli on 03/12/2022.
// Copyright © 2022 Röck+Cöde. All rights reserved.
//
import SwiftUI
extension Text {
/// Renders a text for the name of a folder or document item.
/// - Returns: A formatted text rendered as an erasured view.
func itemName() -> some View {
self
.font(.headline)
.lineLimit(1)
.truncationMode(.middle)
.foregroundColor(.primary)
.frame(maxWidth: .infinity, alignment: .leading)
}
}

View File

@ -0,0 +1,82 @@
//
// BrowseToolbar.swift
// BeReal
//
// Created by Javier Cicchelli on 03/12/2022.
// Copyright © 2022 Röck+Cöde. All rights reserved.
//
import SwiftUI
struct BrowseToolbar: ToolbarContent {
var body: some ToolbarContent {
ToolbarItem(placement: .primaryAction) {
Menu {
Button {
// TODO: Implement the creation of a new folder.
} label: {
Label {
Text(
"browse.toolbar_item.button.add_folder.text",
bundle: .module,
comment: "Add folder button text."
)
} icon: {
Image.newFolder
}
}
Button {
// TODO: Implement the upload of a file from the device to the API.
} label: {
Label {
Text(
"browse.toolbar_item.button.add_file.text",
bundle: .module,
comment: "Add file button text."
)
} icon: {
Image.newFile
}
}
} label: {
Label {
Text(
"browse.toolbar_item.menu.add_actions.text",
bundle: .module,
comment: "Add actions menu text."
)
} icon: {
Image.add
.foregroundColor(.red)
}
}
}
ToolbarItem(placement: .navigationBarTrailing) {
Button {
// TODO: Implement the show of the user profile.
} label: {
Label {
Text(
"browse.toolbar_item.button.show_profile.text",
bundle: .module,
comment: "Show profile button text."
)
} icon: {
Image.profile
.foregroundColor(.red)
}
}
}
}
}
// MARK: - Image+Constants
private extension Image {
static let profile = Image(systemName: "person.crop.circle.fill")
static let add = Image(systemName: "plus.circle.fill")
static let newFolder = Image(systemName: "folder.badge.plus")
static let newFile = Image(systemName: "doc.badge.plus")
}

View File

@ -0,0 +1,129 @@
//
// BrowseView.swift
// Browse
//
// Created by Javier Cicchelli on 03/12/2022.
// Copyright © 2022 Röck+Cöde. All rights reserved.
//
import SwiftUI
public struct BrowseView: View {
// MARK: Initialisers
public init() {}
// MARK: Body
public var body: some View {
List {
Group {
Group {
FolderItem(name: "Some folder #1 name")
FolderItem(name: "Some folder #2 name")
FolderItem(name: "Some folder #3 name")
FolderItem(name: "Some folder #4 name")
FolderItem(name: "Some folder #5 name")
FolderItem(name: "Some folder #6 name")
FolderItem(name: "Some folder #7 name")
}
Group {
DocumentItem(
name: "Some document #1 name",
lastModified: "3 months ago",
fileSize: "1,23 Mbytes"
)
DocumentItem(
name: "Some document #2 name",
lastModified: "2 years ago",
fileSize: "123 Kbytes"
)
DocumentItem(
name: "Some document #3 name",
lastModified: "13 days ago",
fileSize: "12 bytes"
)
DocumentItem(
name: "Some document #4 name",
lastModified: "13 hours ago",
fileSize: "12,3 Gbytes"
)
DocumentItem(
name: "Some document #5 name",
lastModified: "13 minutes ago",
fileSize: "123 Tbytes"
)
DocumentItem(
name: "Some document #6 name",
lastModified: "13 seconds ago",
fileSize: "123 Tbytes"
)
DocumentItem(
name: "Some document #7 name",
lastModified: "13 nanoseconds ago",
fileSize: "123 Tbytes"
)
}
}
.swipeActions(
edge: .trailing,
allowsFullSwipe: true
) {
Button {
// TODO: Implement the removal of the item from the API.
} label: {
Label {
Text(
"browse.swipe_action.delete_item.text",
bundle: .module,
comment: "Delete item swipe action text."
)
} icon: {
Image.trash
}
}
.tint(.red)
// TODO: allow download only if item is a file.
Button {
// TODO: Implement the downloading of the data of the item from the API into the device.
} label: {
Label {
Text(
"browse.swipe_action.download_item.text",
bundle: .module,
comment: "Download item swipe action text."
)
} icon: {
Image.download
}
}
.tint(.orange)
}
}
.listStyle(.inset)
.background(Color.red)
.navigationTitle("Folder name")
.toolbar {
BrowseToolbar()
}
}
}
// MARK: - Image+Constants
private extension Image {
static let trash = Image(systemName: "trash")
static let download = Image(systemName: "arrow.down.doc")
}
// MARK: - Previews
struct BrowseView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
BrowseView()
}
}
}