Skip to content

Commit ffd340b

Browse files
author
Programistich
committed
[UI] Redesign File Manager without new logic
1 parent e239d65 commit ffd340b

File tree

32 files changed

+1259
-361
lines changed

32 files changed

+1259
-361
lines changed

Flipper/Packages/Core/Sources/Storage/Patform/UserDefaultsStorage.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,5 +109,8 @@ public extension UserDefaults {
109109
case appsSortOrder = "appsSortOrder"
110110

111111
case todayWidgetUpdated = "todayWidgetUpdated"
112+
113+
case fileManagerDisplayType = "fileManagerDisplayType"
114+
case fileManagerShowHiddenFiles = "fileManagerShowHiddenFiles"
112115
}
113116
}

Flipper/Packages/Peripheral/Sources/RPC/Model/Storage.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ public struct StorageSpace: Equatable {
77
public var used: Int { total - free }
88
}
99

10-
public enum Element: Equatable {
10+
public enum Element: Equatable, Identifiable {
1111
case file(File)
1212
case directory(Directory)
1313

14+
public var id: String { name }
15+
1416
public var name: String {
1517
switch self {
1618
case .file(let file): return file.name

Flipper/Packages/UI/Sources/Archive/ArchiveView.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,19 @@ struct ArchiveView: View {
2626
case importing(URL)
2727
case category(ArchiveItem.Kind)
2828
case categoryDeleted
29+
case fileManager
2930
}
3031

3132
var canPullToRefresh: Bool {
3233
device.status == .connected ||
3334
device.status == .synchronized
3435
}
3536

37+
var isFileManagerAvailable: Bool {
38+
device.status == .connected ||
39+
device.status == .synchronized
40+
}
41+
3642
var items: [ArchiveItem] {
3743
archive.items
3844
}
@@ -70,6 +76,13 @@ struct ArchiveView: View {
7076
)
7177
.padding(14)
7278

79+
NavigationLink(value: Destination.fileManager) {
80+
FileManagerSection()
81+
.padding(.horizontal, 14)
82+
.padding(.bottom, 14)
83+
}
84+
.disabled(!isFileManagerAvailable)
85+
7386
if !favoriteItems.isEmpty {
7487
FavoritesSection(items: favoriteItems)
7588
.padding(.horizontal, 14)
@@ -134,6 +147,7 @@ struct ArchiveView: View {
134147
case .importing(let url): ImportView(url: url)
135148
case .category(let kind): CategoryView(kind: kind)
136149
case .categoryDeleted: CategoryDeletedView()
150+
case .fileManager: FileManagerView()
137151
}
138152
}
139153
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import SwiftUI
2+
3+
struct FileManagerSection: View {
4+
@Environment(\.isEnabled) var isEnabled
5+
6+
var body: some View {
7+
VStack(alignment: .leading, spacing: 12) {
8+
HStack(spacing: 12) {
9+
Image("FileManagerIcon")
10+
.resizable()
11+
.renderingMode(.template)
12+
.frame(width: 30, height: 30)
13+
.foregroundColor(.primary)
14+
15+
Text("File Manager")
16+
.font(.system(size: 16, weight: .bold))
17+
.foregroundColor(.primary)
18+
19+
Spacer()
20+
21+
Image("ChevronRight")
22+
.resizable()
23+
.frame(width: 14, height: 14)
24+
}
25+
26+
Text("Manage files and assets on your Flipper Zero")
27+
.font(.system(size: 14, weight: .medium))
28+
.multilineTextAlignment(.leading)
29+
.foregroundColor(.black30)
30+
}
31+
.padding(12)
32+
.opacity(isEnabled ? 1 : 0.4)
33+
.background(Color.groupedBackground)
34+
.cornerRadius(12)
35+
}
36+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import Core
2+
import Peripheral
3+
4+
import SwiftUI
5+
6+
extension FileManagerView.FileManagerListing {
7+
struct ElementRow: View {
8+
let element: Element
9+
let type: DisplayType
10+
11+
let onAction: () -> Void
12+
13+
var body: some View {
14+
Group {
15+
switch type {
16+
case .grid:
17+
VStack(alignment: .leading, spacing: 12) {
18+
HStack {
19+
Icon(for: element)
20+
Spacer()
21+
Action(onTap: onAction)
22+
}
23+
Title(for: element)
24+
}
25+
case .list:
26+
HStack(spacing: 12) {
27+
Icon(for: element)
28+
Title(for: element)
29+
Spacer()
30+
Action(onTap: onAction)
31+
}
32+
}
33+
}
34+
.padding(12)
35+
.background(Color.groupedBackground)
36+
.cornerRadius(12)
37+
}
38+
}
39+
}
40+
41+
fileprivate extension FileManagerView.FileManagerListing.ElementRow {
42+
struct Icon: View {
43+
let element: Element
44+
45+
private var image: Image {
46+
switch element {
47+
case .directory:
48+
return .init("Folder")
49+
case .file:
50+
if let item = try? ArchiveItem.Kind(filename: element.name) {
51+
return item.icon
52+
} else {
53+
return .init("File")
54+
}
55+
}
56+
}
57+
58+
init(for element: Element) {
59+
self.element = element
60+
}
61+
62+
var body: some View {
63+
image
64+
.resizable()
65+
.renderingMode(.template)
66+
.frame(width: 24, height: 24)
67+
.foregroundColor(.primary)
68+
}
69+
}
70+
71+
struct Title: View {
72+
let element: Element
73+
74+
init(for element: Element) {
75+
self.element = element
76+
}
77+
78+
var body: some View {
79+
VStack(alignment: .leading, spacing: 2) {
80+
Text(element.name)
81+
.font(.system(size: 16, weight: .medium))
82+
.foregroundColor(.primary)
83+
.lineLimit(1)
84+
85+
if case let .file(file) = element {
86+
Text(file.size.hr)
87+
.font(.system(size: 10, weight: .medium))
88+
.foregroundColor(.black30)
89+
}
90+
}
91+
.frame(height: 32)
92+
}
93+
}
94+
95+
struct Action: View {
96+
let onTap: () -> Void
97+
98+
var body: some View {
99+
Image(systemName: "ellipsis")
100+
.resizable()
101+
.renderingMode(.template)
102+
.aspectRatio(contentMode: .fit)
103+
.foregroundColor(.black30)
104+
.frame(width: 20)
105+
.padding([.vertical, .leading], 12)
106+
.contentShape(Rectangle())
107+
.onTapGesture { onTap() }
108+
}
109+
}
110+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import SwiftUI
2+
3+
extension FileManagerView.FileManagerListing {
4+
struct EmptyFolder: View {
5+
let onUpload: () -> Void
6+
7+
var body: some View {
8+
VStack(alignment: .center, spacing: 24) {
9+
Spacer()
10+
11+
Text("No Files Yet")
12+
.font(.system(size: 18, weight: .bold))
13+
.foregroundColor(.primary)
14+
15+
Image("ReportFailed")
16+
.renderingMode(.template)
17+
.foregroundColor(.primary)
18+
19+
Text("Upload Files")
20+
.font(.system(size: 14, weight: .medium))
21+
.foregroundColor(.a2)
22+
.onTapGesture {
23+
onUpload()
24+
}
25+
26+
Spacer()
27+
}
28+
.frame(maxWidth: .infinity)
29+
}
30+
}
31+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import SwiftUI
2+
3+
extension FileManagerView.FileManagerEditor {
4+
struct FileEditorOptions: View {
5+
@Binding var isPresented: Bool
6+
7+
let save: () -> Void
8+
let saveAs: () -> Void
9+
10+
var body: some View {
11+
HStack {
12+
Spacer()
13+
Card {
14+
VStack(alignment: .leading, spacing: 0) {
15+
Option(text: "Save") {
16+
isPresented = false
17+
save()
18+
}
19+
}
20+
}
21+
.frame(width: 150)
22+
}
23+
.padding(.horizontal, 14)
24+
.offset(y: 40)
25+
}
26+
}
27+
}
28+
29+
fileprivate extension FileManagerView.FileManagerEditor.FileEditorOptions {
30+
struct Option: View {
31+
let text: String
32+
let onTap: () -> Void
33+
34+
var body: some View {
35+
HStack {
36+
Text(text)
37+
.font(.system(size: 16, weight: .medium))
38+
.padding(.horizontal, 16)
39+
.padding(.vertical, 12)
40+
Spacer()
41+
}
42+
.onTapGesture { onTap() }
43+
}
44+
}
45+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import SwiftUI
2+
3+
extension FileManagerView.FileManagerListing {
4+
struct FileListingOptions: View {
5+
@Binding var isPresented: Bool
6+
7+
let upload: () -> Void
8+
let selectDisplayType: (DisplayType) -> Void
9+
let toggleHidenFiles: (Bool) -> Void
10+
11+
let isHiddenFilesShow: Bool
12+
13+
var body: some View {
14+
HStack {
15+
Spacer()
16+
Card {
17+
VStack(alignment: .leading, spacing: 0) {
18+
Option(title: "Upload", image: "Share") {
19+
isPresented = false
20+
upload()
21+
}
22+
23+
Divider()
24+
25+
Option(title: "List", image: "List") {
26+
isPresented = false
27+
selectDisplayType(.list)
28+
}
29+
30+
Option(title: "Grid", image: "Grid") {
31+
isPresented = false
32+
selectDisplayType(.grid)
33+
}
34+
35+
Divider()
36+
37+
ShowHiddenFilesOption(
38+
isHiddenFilesShow: isHiddenFilesShow
39+
) {
40+
isPresented = false
41+
toggleHidenFiles(!isHiddenFilesShow)
42+
}
43+
}
44+
}
45+
.frame(width: 200)
46+
}
47+
.padding(.horizontal, 14)
48+
.offset(y: 40)
49+
}
50+
}
51+
}
52+
53+
fileprivate extension FileManagerView.FileManagerListing.FileListingOptions {
54+
struct Option: View {
55+
let title: String
56+
let image: String
57+
let onTap: () -> Void
58+
59+
var body: some View {
60+
Button(action: onTap) {
61+
HStack(spacing: 8) {
62+
Image(image)
63+
.resizable()
64+
.renderingMode(.template)
65+
.frame(width: 24, height: 24)
66+
.foregroundColor(.primary)
67+
Text(title)
68+
.font(.system(size: 14, weight: .medium))
69+
.foregroundColor(.primary)
70+
Spacer()
71+
}
72+
}
73+
.padding(12)
74+
}
75+
}
76+
77+
struct ShowHiddenFilesOption: View {
78+
let isHiddenFilesShow: Bool
79+
let onTap: () -> Void
80+
81+
var body: some View {
82+
Button(action: onTap) {
83+
HStack(spacing: 8) {
84+
ZStack {
85+
Circle()
86+
.stroke(Color.black30, lineWidth: 2)
87+
88+
if isHiddenFilesShow {
89+
Circle()
90+
.fill(Color.a1)
91+
.padding(4)
92+
}
93+
}
94+
.frame(width: 20, height: 20)
95+
.padding(2)
96+
97+
Text("Show Hidden Files")
98+
.font(.system(size: 14, weight: .medium))
99+
.foregroundColor(.primary)
100+
Spacer()
101+
}
102+
}
103+
.padding(12)
104+
}
105+
}
106+
}

0 commit comments

Comments
 (0)