mirror of
https://github.com/lumaa-dev/BubbleApp.git
synced 2025-02-03 03:47:43 +01:00
Fixes and optimisation
This commit is contained in:
parent
0e6e63ea23
commit
b524188790
@ -20,23 +20,11 @@ struct CompactPostView: View {
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
VStack(alignment: .leading) {
|
||||
if pinned {
|
||||
pinnedNotice
|
||||
.padding(.leading, 35)
|
||||
statusPost(status)
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {
|
||||
navigator.navigate(to: .post(status: status))
|
||||
}
|
||||
|
||||
if status.reblog != nil {
|
||||
repostNotice
|
||||
.padding(.leading, 30)
|
||||
}
|
||||
|
||||
if detailed {
|
||||
detailedStatusPost(status.reblog ?? status)
|
||||
} else {
|
||||
statusPost(status.reblog ?? status)
|
||||
}
|
||||
}
|
||||
|
||||
if !quoted {
|
||||
Rectangle()
|
||||
@ -133,13 +121,25 @@ struct CompactPostView: View {
|
||||
VStack(alignment: .leading) {
|
||||
// MARK: Status main content
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
Text(status.account.username)
|
||||
.font(quoted ? .callout : .body)
|
||||
.multilineTextAlignment(.leading)
|
||||
.bold()
|
||||
.onTapGesture {
|
||||
navigator.navigate(to: .account(acc: status.account))
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(status.account.username)
|
||||
.font(quoted ? .callout : .body)
|
||||
.multilineTextAlignment(.leading)
|
||||
.bold()
|
||||
.onTapGesture {
|
||||
navigator.navigate(to: .account(acc: status.account))
|
||||
}
|
||||
|
||||
if status.inReplyToAccountId != nil {
|
||||
if let user = status.mentions.first(where: { $0.id == status.inReplyToAccountId }) {
|
||||
Text("status.replied-to.\(user.username)")
|
||||
.multilineTextAlignment(.leading)
|
||||
.lineLimit(1)
|
||||
.font(.caption)
|
||||
.foregroundStyle(Color(uiColor: UIColor.label).opacity(0.3))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !status.content.asRawText.isEmpty {
|
||||
TextEmoji(status.content, emojis: status.emojis, language: status.language)
|
||||
@ -184,21 +184,20 @@ struct CompactPostView: View {
|
||||
HStack(spacing: 13) {
|
||||
asyncActionButton(isLiked ? "heart.fill" : "heart") {
|
||||
do {
|
||||
try await likePost()
|
||||
HapticManager.playHaptics(haptics: Haptic.tap)
|
||||
try await likePost()
|
||||
} catch {
|
||||
HapticManager.playHaptics(haptics: Haptic.error)
|
||||
print("Error: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
actionButton("bubble.right") {
|
||||
print("reply")
|
||||
navigator.presentedSheet = .post()
|
||||
navigator.presentedSheet = .post(content: "@\(status.account.acct)", replyId: status.id)
|
||||
}
|
||||
asyncActionButton(isReposted ? "bolt.horizontal.fill" : "bolt.horizontal") {
|
||||
do {
|
||||
try await repostPost()
|
||||
HapticManager.playHaptics(haptics: Haptic.tap)
|
||||
try await repostPost()
|
||||
} catch {
|
||||
HapticManager.playHaptics(haptics: Haptic.error)
|
||||
print("Error: \(error.localizedDescription)")
|
||||
@ -219,116 +218,38 @@ struct CompactPostView: View {
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func detailedStatusPost(_ status: AnyStatus) -> some View {
|
||||
VStack {
|
||||
HStack {
|
||||
profilePicture
|
||||
|
||||
Text(status.account.username)
|
||||
.multilineTextAlignment(.leading)
|
||||
.bold()
|
||||
}
|
||||
.onTapGesture {
|
||||
navigator.navigate(to: .account(acc: status.account))
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
// MARK: Status main content
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
if !status.content.asRawText.isEmpty {
|
||||
TextEmoji(status.content, emojis: status.emojis, language: status.language)
|
||||
.multilineTextAlignment(.leading)
|
||||
.frame(width: 300, alignment: .topLeading)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.font(.callout)
|
||||
}
|
||||
var notices: some View {
|
||||
ZStack {
|
||||
if pinned {
|
||||
HStack (alignment:.center, spacing: 5) {
|
||||
Image(systemName: "pin.fill")
|
||||
|
||||
if status.card != nil && status.mediaAttachments.isEmpty {
|
||||
PostCardView(card: status.card!)
|
||||
}
|
||||
|
||||
if !status.mediaAttachments.isEmpty {
|
||||
ForEach(status.mediaAttachments) { attachment in
|
||||
PostAttachment(attachment: attachment)
|
||||
}
|
||||
}
|
||||
|
||||
if hasQuote {
|
||||
if quoteStatus != nil {
|
||||
QuotePostView(status: quoteStatus!)
|
||||
} else {
|
||||
ProgressView()
|
||||
.progressViewStyle(.circular)
|
||||
}
|
||||
}
|
||||
Text("status.pinned")
|
||||
}
|
||||
|
||||
//MARK: Action buttons
|
||||
HStack(spacing: 13) {
|
||||
asyncActionButton(isLiked ? "heart.fill" : "heart") {
|
||||
do {
|
||||
try await likePost()
|
||||
HapticManager.playHaptics(haptics: Haptic.tap)
|
||||
} catch {
|
||||
HapticManager.playHaptics(haptics: Haptic.error)
|
||||
print("Error: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
actionButton("bubble.right") {
|
||||
print("reply")
|
||||
navigator.presentedSheet = .post()
|
||||
}
|
||||
asyncActionButton(isReposted ? "bolt.horizontal.fill" : "bolt.horizontal") {
|
||||
do {
|
||||
try await repostPost()
|
||||
HapticManager.playHaptics(haptics: Haptic.tap)
|
||||
} catch {
|
||||
HapticManager.playHaptics(haptics: Haptic.error)
|
||||
print("Error: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
ShareLink(item: URL(string: status.url ?? "https://joinmastodon.org/")!) {
|
||||
Image(systemName: "square.and.arrow.up")
|
||||
.font(.title2)
|
||||
}
|
||||
.tint(Color(uiColor: UIColor.label))
|
||||
.padding(.leading, 20)
|
||||
.multilineTextAlignment(.leading)
|
||||
.lineLimit(1)
|
||||
.font(.caption)
|
||||
.foregroundStyle(Color(uiColor: UIColor.label).opacity(0.3))
|
||||
.padding(.leading, 35)
|
||||
}
|
||||
|
||||
if status.reblog != nil {
|
||||
HStack (alignment:.center, spacing: 5) {
|
||||
Image(systemName: "bolt.horizontal")
|
||||
|
||||
Text("status.reposted-by.\(status.account.username)")
|
||||
}
|
||||
.padding(.top)
|
||||
|
||||
// MARK: Status stats
|
||||
stats.padding(.top, 5)
|
||||
.padding(.leading, 20)
|
||||
.multilineTextAlignment(.leading)
|
||||
.lineLimit(1)
|
||||
.font(.caption)
|
||||
.foregroundStyle(Color(uiColor: UIColor.label).opacity(0.3))
|
||||
.padding(.leading, 30)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var pinnedNotice: some View {
|
||||
HStack (alignment:.center, spacing: 5) {
|
||||
Image(systemName: "pin.fill")
|
||||
|
||||
Text("status.pinned")
|
||||
}
|
||||
.padding(.leading, 20)
|
||||
.multilineTextAlignment(.leading)
|
||||
.lineLimit(1)
|
||||
.font(.caption)
|
||||
.foregroundStyle(Color(uiColor: UIColor.label).opacity(0.3))
|
||||
}
|
||||
|
||||
var repostNotice: some View {
|
||||
HStack (alignment:.center, spacing: 5) {
|
||||
Image(systemName: "bolt.horizontal")
|
||||
|
||||
Text("status.reposted-by.\(status.account.username)")
|
||||
}
|
||||
.padding(.leading, 20)
|
||||
.multilineTextAlignment(.leading)
|
||||
.lineLimit(1)
|
||||
.font(.caption)
|
||||
.foregroundStyle(Color(uiColor: UIColor.label).opacity(0.3))
|
||||
}
|
||||
|
||||
var profilePicture: some View {
|
||||
if status.reblog != nil {
|
||||
OnlineImage(url: status.reblog!.account.avatar, size: 50, useNuke: true)
|
||||
|
@ -38,7 +38,7 @@ public enum TabDestination: Identifiable {
|
||||
public enum SheetDestination: Identifiable {
|
||||
case welcome
|
||||
case mastodonLogin(logged: Binding<Bool>)
|
||||
case post(content: String = "")
|
||||
case post(content: String = "", replyId: String? = nil)
|
||||
|
||||
public var id: String {
|
||||
switch self {
|
||||
@ -70,6 +70,7 @@ public enum RouterDestination: Hashable {
|
||||
case privacy
|
||||
case appearence
|
||||
case account(acc: Account)
|
||||
case post(status: Status)
|
||||
case about
|
||||
}
|
||||
|
||||
@ -85,6 +86,8 @@ extension View {
|
||||
AppearenceView()
|
||||
case .account(let acc):
|
||||
AccountView(account: acc, navigator: navigator)
|
||||
case .post(let status):
|
||||
PostDetailsView(status: status)
|
||||
case .about:
|
||||
AboutView()
|
||||
}
|
||||
@ -114,9 +117,9 @@ extension View {
|
||||
}
|
||||
} else {
|
||||
switch destination {
|
||||
case .post(let content):
|
||||
case .post(let content, let replyId):
|
||||
NavigationStack {
|
||||
PostingView(initialString: content)
|
||||
PostingView(initialString: content, replyId: replyId)
|
||||
.tint(Color(uiColor: UIColor.label))
|
||||
}
|
||||
case let .mastodonLogin(logged):
|
||||
|
@ -355,7 +355,14 @@
|
||||
}
|
||||
},
|
||||
"setting.experimental.activate" : {
|
||||
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Show experimental features"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"setting.privacy" : {
|
||||
"localizations" : {
|
||||
@ -519,6 +526,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"status.replied-to.%@" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Replied to @%@"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"status.replies-%lld" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@ -588,4 +605,4 @@
|
||||
}
|
||||
},
|
||||
"version" : "1.0"
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ struct PostingView: View {
|
||||
@Environment(Navigator.self) private var navigator: Navigator
|
||||
|
||||
public var initialString: String = ""
|
||||
public var replyId: String? = nil
|
||||
|
||||
@State private var viewModel: PostingView.ViewModel = PostingView.ViewModel()
|
||||
|
||||
@ -43,7 +44,7 @@ struct PostingView: View {
|
||||
viewModel.textView = textView
|
||||
})
|
||||
.placeholder(String(localized: "status.posting.placeholder"))
|
||||
.keyboardType(.twitter)
|
||||
.setKeyboardType(.twitter)
|
||||
.multilineTextAlignment(.leading)
|
||||
.font(.callout)
|
||||
.foregroundStyle(Color(uiColor: UIColor.label))
|
||||
@ -91,12 +92,11 @@ struct PostingView: View {
|
||||
Task {
|
||||
if let client = accountManager.getClient() {
|
||||
postingStatus = true
|
||||
let postedStatus: Status = try await client.post(endpoint: Statuses.postStatus(json: .init(status: viewModel.postText.string, visibility: visibility)))
|
||||
let newStatus: Status = try await client.post(endpoint: Statuses.postStatus(json: .init(status: viewModel.postText.string, visibility: visibility, inReplyToId: replyId)))
|
||||
postingStatus = false
|
||||
HapticManager.playHaptics(haptics: Haptic.success)
|
||||
dismiss()
|
||||
|
||||
// navigate to account until PostDetailsView is fully finished
|
||||
navigator.navigate(to: .account(acc: accountManager.forceAccount()))
|
||||
navigator.navigate(to: .post(status: newStatus))
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
@ -127,9 +127,7 @@ struct PostingView: View {
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
let newTxt = NSMutableAttributedString(string: "abc")
|
||||
viewModel.postText.append(newTxt)
|
||||
|
||||
viewModel.append(text: initialString)
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,7 +148,7 @@ struct PostingView: View {
|
||||
|
||||
actionButton("number") {
|
||||
DispatchQueue.main.async {
|
||||
viewModel.postText.append(NSMutableAttributedString(string: "#"))
|
||||
viewModel.append(text: "#")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -187,21 +185,42 @@ struct PostingView: View {
|
||||
.clipShape(.circle)
|
||||
}
|
||||
|
||||
public class ViewModel: NSObject, UITextPasteDelegate {
|
||||
init(postText: NSMutableAttributedString = .init(string: ""), textView: UITextView? = nil) {
|
||||
self.postText = postText
|
||||
self.textView = textView
|
||||
@Observable public class ViewModel: NSObject {
|
||||
init(text: String = "") {
|
||||
self.postText = NSMutableAttributedString(string: text)
|
||||
}
|
||||
|
||||
@State var postText: NSMutableAttributedString {
|
||||
didSet {
|
||||
textView?.attributedText = postText
|
||||
var selectedRange: NSRange {
|
||||
get {
|
||||
guard let textView else {
|
||||
return .init(location: 0, length: 0)
|
||||
}
|
||||
return textView.selectedRange
|
||||
}
|
||||
set {
|
||||
textView?.selectedRange = newValue
|
||||
}
|
||||
}
|
||||
var textView: UITextView? {
|
||||
|
||||
var postText: NSMutableAttributedString {
|
||||
didSet {
|
||||
textView?.pasteDelegate = self
|
||||
let range = selectedRange
|
||||
formatText()
|
||||
textView?.attributedText = postText
|
||||
selectedRange = range
|
||||
}
|
||||
}
|
||||
var textView: UITextView?
|
||||
|
||||
func append(text: String) {
|
||||
let string = postText
|
||||
string.mutableString.insert(text, at: selectedRange.location)
|
||||
postText = string
|
||||
selectedRange = NSRange(location: selectedRange.location + text.utf16.count, length: 0)
|
||||
}
|
||||
|
||||
func formatText() {
|
||||
postText.addAttributes([.foregroundColor : UIColor.label, .font: UIFont.preferredFont(forTextStyle: .callout), .backgroundColor: UIColor.clear, .underlineColor: UIColor.clear], range: NSMakeRange(0, postText.string.utf16.count))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user