Skip to content

Commit a2f1920

Browse files
authored
Merge pull request #51 from SubvertDev/feature/common-attachments
Attachments model refactoring
2 parents 37e150d + e34e67e commit a2f1920

File tree

16 files changed

+236
-263
lines changed

16 files changed

+236
-263
lines changed

Modules/Sources/BBBuilder/Builder/BBBuilder.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public struct BBBuilder {
2020

2121
// MARK: - Build Interface
2222

23-
public static func build(text: String, attachments: [Post.Attachment] = []) -> [BBContainerNode] {
23+
public static func build(text: String, attachments: [Attachment] = []) -> [BBContainerNode] {
2424
let renderedText = AttributedString(BBRenderer().render(text: text))
2525
let builder = BBBuilder(attachments: attachments)
2626
let nodes = BBAttributedParser.parse(text: renderedText, attachments: attachments)
@@ -29,15 +29,15 @@ public struct BBBuilder {
2929

3030
// MARK: - Properties
3131

32-
private var attachments: [Post.Attachment]
32+
private var attachments: [Attachment]
3333

3434
// MARK: - Dependencies
3535

3636
@Dependency(\.logger[.bbbuilder, false]) private var logger
3737

3838
// MARK: - Init
3939

40-
private init(attachments: [Post.Attachment]) {
40+
private init(attachments: [Attachment]) {
4141
self.attachments = attachments
4242
}
4343

Modules/Sources/BBBuilder/Parser/Attributed/BBAttributedParser.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@ import Models
1010

1111
public struct BBAttributedParser {
1212

13-
public static func parse(text: AttributedString, attachments: [Post.Attachment]) -> [BBContainerNode] {
13+
public static func parse(text: AttributedString, attachments: [Attachment]) -> [BBContainerNode] {
1414
var parser = BBAttributedParser(text: text, attachments: attachments)
1515
return parser.parse()
1616
}
1717

1818
private var attributedTokenizer: BBAttributedTokenizer
19-
private var attachments: [Post.Attachment]
19+
private var attachments: [Attachment]
2020
private var openingTags: [(tag: BBTag, attribute: NSAttributedString?)] = []
2121

22-
private init(text: AttributedString, attachments: [Post.Attachment]) {
22+
private init(text: AttributedString, attachments: [Attachment]) {
2323
attributedTokenizer = BBAttributedTokenizer(string: text)
2424
self.attachments = attachments
2525
}

Modules/Sources/Models/Articles/Article.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,16 @@ public extension Article {
7676
title: "Enim amet excepteur consectetur quis velit id labore eiusmod.",
7777
description: "Occaecat enim duis dolor tempor nostrud ea veniam culpa magna incididunt nisi ut laborum amet.\n\n Игру можно [url=\"https://store.epicgames.com/ru/p/fist-forged-in-shadow-torch\"]забрать бесплатно[/url] до 1 августа. \n\n [quote] «Шесть лет назад Легион захватил и колонизировал город Светоч.\n\n [/quote]\n[center][attachment=\"1:dummy\"][/center]\n\n[center][attachment=\"1:dummy\"] [spoiler=\"ещё 9 фотографий\"][attachment=\"2:dummy\"] [attachment=\"3:dummy\"] [attachment=\"4:dummy\"] [attachment=\"5:dummy\"] [attachment=\"6:dummy\"] [attachment=\"7:dummy\"] [attachment=\"8:dummy\"] [attachment=\"9:dummy\"] [attachment=\"10:dummy\"] [/spoiler][/center]\n\n[center][youtube=eOqif3M_UFY:640:360:::0][/center]\n\n[list]\t[*]41 мм, GPS — $249\n\t[*]41 мм, LTE (или 5G) — $299\n\t[*]45 мм, GPS — $279\n\t[*]45 мм, LTE (или 5G) — $329\n [/list]\n",
7878
attachments: [
79-
Attachment(id: 1, smallUrl: URL(string: "https://4pda.to/static/img/news/60/601868t.jpg")!, width: 480, height: 269, description: "", fullUrl: URL(string: "https://4pda.to/static/img/news/60/601868.jpg")!),
80-
Attachment(id: 2, smallUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633614t.jpg")!, width: 480, height: 269, description: "", fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633614t.jpg")!),
81-
Attachment(id: 3, smallUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633619t.jpg")!, width: 480, height: 269, description: "", fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633619.jpg")!),
82-
Attachment(id: 4, smallUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633611t.jpg")!, width: 480, height: 269, description: "", fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633611.jpg")!),
83-
Attachment(id: 5, smallUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633612t.jpg")!, width: 480, height: 269, description: "", fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633612.jpg")!),
84-
Attachment(id: 6, smallUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633615t.jpg")!, width: 480, height: 269, description: "", fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633615.jpg")!),
85-
Attachment(id: 7, smallUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633617t.jpg")!, width: 480, height: 270, description: "", fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633617.jpg")!),
86-
Attachment(id: 8, smallUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633618t.jpg")!, width: 480, height: 270, description: "", fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633618.jpg")!),
87-
Attachment(id: 9, smallUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633616t.jpg")!, width: 480, height: 270, description: "", fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633616.jpg")!),
88-
Attachment(id: 10, smallUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633613t.jpg")!, width: 480, height: 270, description: "", fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633613.jpg")!)
79+
Attachment(id: 1, type: .image, name: "", size: 0, metadata: .init(width: 480, height: 269, url: URL(string: "https://4pda.to/static/img/news/60/601868t.jpg")!, fullUrl: URL(string: "https://4pda.to/static/img/news/60/601868.jpg")!), downloadCount: nil),
80+
Attachment(id: 2, type: .image, name: "", size: 0, metadata: .init(width: 480, height: 269, url: URL(string: "https://i.4pda.ws/static/img/news/63/633614t.jpg")!, fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633614t.jpg")!), downloadCount: nil),
81+
Attachment(id: 3, type: .image, name: "", size: 0, metadata: .init(width: 480, height: 269, url: URL(string: "https://i.4pda.ws/static/img/news/63/633619t.jpg")!, fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633619.jpg")!), downloadCount: nil),
82+
Attachment(id: 4, type: .image, name: "", size: 0, metadata: .init(width: 480, height: 269, url: URL(string: "https://i.4pda.ws/static/img/news/63/633611t.jpg")!, fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633611.jpg")!), downloadCount: nil),
83+
Attachment(id: 5, type: .image, name: "", size: 0, metadata: .init(width: 480, height: 269, url: URL(string: "https://i.4pda.ws/static/img/news/63/633612t.jpg")!, fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633612.jpg")!), downloadCount: nil),
84+
Attachment(id: 6, type: .image, name: "", size: 0, metadata: .init(width: 480, height: 269, url: URL(string: "https://i.4pda.ws/static/img/news/63/633615t.jpg")!, fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633615.jpg")!), downloadCount: nil),
85+
Attachment(id: 7, type: .image, name: "", size: 0, metadata: .init(width: 480, height: 270, url: URL(string: "https://i.4pda.ws/static/img/news/63/633617t.jpg")!, fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633617.jpg")!), downloadCount: nil),
86+
Attachment(id: 8, type: .image, name: "", size: 0, metadata: .init(width: 480, height: 270, url: URL(string: "https://i.4pda.ws/static/img/news/63/633618t.jpg")!, fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633618.jpg")!), downloadCount: nil),
87+
Attachment(id: 9, type: .image, name: "", size: 0, metadata: .init(width: 480, height: 270, url: URL(string: "https://i.4pda.ws/static/img/news/63/633616t.jpg")!, fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633616.jpg")!), downloadCount: nil),
88+
Attachment(id: 10, type: .image, name: "", size: 0, metadata: .init(width: 480, height: 270, url: URL(string: "https://i.4pda.ws/static/img/news/63/633613t.jpg")!, fullUrl: URL(string: "https://i.4pda.ws/static/img/news/63/633613.jpg")!), downloadCount: nil),
8989
],
9090
tags: [],
9191
comments: .mockArray,

Modules/Sources/Models/Articles/Attachment.swift

Lines changed: 0 additions & 33 deletions
This file was deleted.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//
2+
// Attachment.swift
3+
// ForPDA
4+
//
5+
// Created by Xialtal on 14.11.25.
6+
//
7+
8+
import Foundation
9+
10+
public struct Attachment: Sendable, Hashable, Codable {
11+
public let id: Int
12+
public let type: AttachmentType
13+
public let name: String
14+
public let size: Int
15+
public let metadata: Metadata?
16+
public let downloadCount: Int?
17+
18+
public var sizeString: String {
19+
let units = ["Б", "КБ", "МБ", "ГБ"]
20+
var size = Double(size)
21+
var unitIndex = 0
22+
23+
while size >= 1024 && unitIndex < units.count - 1 {
24+
size /= 1024
25+
unitIndex += 1
26+
}
27+
28+
let formatter = NumberFormatter()
29+
formatter.maximumFractionDigits = (size.truncatingRemainder(dividingBy: 1) == 0) ? 0 : 1
30+
formatter.numberStyle = .decimal
31+
32+
let formattedSize = formatter.string(from: NSNumber(value: size)) ?? "\(size)"
33+
return "\(formattedSize) \(units[unitIndex])"
34+
}
35+
36+
public enum AttachmentType: Int, Sendable, Hashable, Codable {
37+
case file = 0
38+
case image = 1
39+
}
40+
41+
public struct Metadata: Sendable, Hashable, Codable {
42+
public let url: URL
43+
public let fullUrl: URL?
44+
public let width: Int
45+
public let height: Int
46+
public let description: String
47+
48+
public init(
49+
width: Int,
50+
height: Int,
51+
url: URL,
52+
fullUrl: URL? = nil,
53+
description: String = ""
54+
) {
55+
self.url = url
56+
self.fullUrl = fullUrl
57+
self.width = width
58+
self.height = height
59+
self.description = description
60+
}
61+
}
62+
63+
public init(
64+
id: Int,
65+
type: AttachmentType,
66+
name: String,
67+
size: Int,
68+
metadata: Metadata?,
69+
downloadCount: Int?
70+
) {
71+
self.id = id
72+
self.type = type
73+
self.name = name
74+
self.size = size
75+
self.metadata = metadata
76+
self.downloadCount = downloadCount
77+
}
78+
}

Modules/Sources/Models/Forum/Post.swift

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -80,66 +80,6 @@ public struct Post: Sendable, Hashable, Identifiable, Codable {
8080

8181
// MARK: - Nested Structs
8282

83-
public struct Attachment: Sendable, Hashable, Codable {
84-
public let id: Int
85-
public let type: AttachmentType
86-
public let name: String
87-
public let size: Int
88-
public let metadata: Metadata?
89-
public let downloadCount: Int?
90-
91-
public var sizeString: String {
92-
let units = ["Б", "КБ", "МБ", "ГБ"]
93-
var size = Double(size)
94-
var unitIndex = 0
95-
96-
while size >= 1024 && unitIndex < units.count - 1 {
97-
size /= 1024
98-
unitIndex += 1
99-
}
100-
101-
let formatter = NumberFormatter()
102-
formatter.maximumFractionDigits = (size.truncatingRemainder(dividingBy: 1) == 0) ? 0 : 1
103-
formatter.numberStyle = .decimal
104-
105-
let formattedSize = formatter.string(from: NSNumber(value: size)) ?? "\(size)"
106-
return "\(formattedSize) \(units[unitIndex])"
107-
}
108-
109-
public enum AttachmentType: Int, Sendable, Hashable, Codable {
110-
case file = 0
111-
case image = 1
112-
}
113-
114-
public struct Metadata: Sendable, Hashable, Codable {
115-
public let url: URL
116-
public let width: Int
117-
public let height: Int
118-
119-
public init(width: Int, height: Int, url: URL) {
120-
self.url = url
121-
self.width = width
122-
self.height = height
123-
}
124-
}
125-
126-
public init(
127-
id: Int,
128-
type: AttachmentType,
129-
name: String,
130-
size: Int,
131-
metadata: Metadata?,
132-
downloadCount: Int?
133-
) {
134-
self.id = id
135-
self.type = type
136-
self.name = name
137-
self.size = size
138-
self.metadata = metadata
139-
self.downloadCount = downloadCount
140-
}
141-
}
142-
14383
public struct LastEdit: Sendable, Hashable, Codable {
14484
public let userId: Int
14585
public let username: String

Modules/Sources/Models/Parsing/TopicTypeUI.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import SwiftUI
99

1010
public indirect enum TopicTypeUI: Hashable, Equatable, Codable, Sendable {
1111
case text(AttributedString)
12-
case attachment(Post.Attachment)
12+
case attachment(Attachment)
1313
case image(URL)
1414
case left([TopicTypeUI])
1515
case center([TopicTypeUI])

Modules/Sources/Models/QMS/QMSMessage.swift

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,6 @@
88
import Foundation
99

1010
public struct QMSMessage: Sendable, Codable, Hashable, Identifiable {
11-
12-
public struct Attachment: Sendable, Codable, Hashable, Identifiable {
13-
public let id: Int
14-
public let flag: Int
15-
public let name: String
16-
public let size: Int
17-
public let downloadsCount: Int
18-
19-
public init(
20-
id: Int,
21-
flag: Int,
22-
name: String,
23-
size: Int,
24-
downloadsCount: Int
25-
) {
26-
self.id = id
27-
self.flag = flag
28-
self.name = name
29-
self.size = size
30-
self.downloadsCount = downloadsCount
31-
}
32-
}
33-
3411
public let id: Int
3512
public let senderId: Int
3613
public let date: Date

Modules/Sources/ParsingClient/Parsers/ArticleElementParser.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@ public struct ArticleElementParser {
138138
}
139139

140140
let attachment = attachments[id - 1]
141-
var url = attachment.smallUrl
142-
if let fullUrl = attachment.fullUrl { url = fullUrl }
143-
return ImageElement(url: url, width: attachment.width, height: attachment.height)
141+
var url = attachment.metadata!.url
142+
if let fullUrl = attachment.metadata!.fullUrl { url = fullUrl }
143+
return ImageElement(url: url, width: attachment.metadata!.width, height: attachment.metadata!.height)
144144
}
145145

146146
// MARK: - Images
@@ -153,9 +153,9 @@ public struct ArticleElementParser {
153153

154154
for match in text.matches(of: pattern) {
155155
let attachment = attachments[Int(match.output.1)! - 1]
156-
var url: URL = attachment.smallUrl
157-
if let fullUrl = attachment.fullUrl { url = fullUrl }
158-
let element = ImageElement(url: url, width: attachment.width, height: attachment.height)
156+
var url = attachment.metadata!.url
157+
if let fullUrl = attachment.metadata!.fullUrl { url = fullUrl }
158+
let element = ImageElement(url: url, width: attachment.metadata!.width, height: attachment.metadata!.height)
159159
imageElements.append(element)
160160
}
161161

Modules/Sources/ParsingClient/Parsers/ArticleParser.swift

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public struct ArticleParser {
4949
imageUrl: URL(string: (fields[10] as! String))!,
5050
title: (fields[11] as! String).convertHtmlCodes(),
5151
description: (fields[12] as! String).convertHtmlCodes(),
52-
attachments: extractAttachments(from: fields[13] as! [[Any]]),
52+
attachments: try AttachmentParser.parseArticleAttachment(from: fields[13] as! [[Any]]),
5353
tags: extractTags(from: fields[14] as! [[Any]]),
5454
comments: extractComments(from: fields[15] as! [[Any]]),
5555
poll: extractPoll(from: pollFields)
@@ -64,27 +64,6 @@ public struct ArticleParser {
6464

6565
// MARK: - Helpers
6666

67-
/**
68-
0. 1 - id
69-
1. "https..." - small image url
70-
2. 480 - width
71-
3. 300 - height
72-
4. "description" - description
73-
5. "https..." - (optional) full image url
74-
*/
75-
private static func extractAttachments(from array: [[Any]]) -> [Attachment] {
76-
return array.map { fields in
77-
return Attachment(
78-
id: fields[0] as! Int,
79-
smallUrl: URL(string: fields[1] as! String)!,
80-
width: fields[2] as! Int,
81-
height: fields[3] as! Int,
82-
description: fields[4] as! String,
83-
fullUrl: URL(string: fields[5] as! String)
84-
)
85-
}
86-
}
87-
8867
/**
8968
0. 24540 - id
9069
1. "!!технологии" - name

0 commit comments

Comments
 (0)