Skip to content

Commit

Permalink
Basic profile (#1079)
Browse files Browse the repository at this point in the history
Co-authored-by: Eric Andrews <eric.b.andrews.auto@protonmail.com>
  • Loading branch information
Sjmarf and EricBAndrews committed Jun 5, 2024
1 parent c38727f commit 6cf19de
Show file tree
Hide file tree
Showing 29 changed files with 774 additions and 135 deletions.
112 changes: 89 additions & 23 deletions Mlem.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Mlem/App/Models/Account/GuestAccount.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Observation

@Observable
class GuestAccount: Account {
static let tierNumber: Int = 1
let actorId: URL
let api: ApiClient
var storedNickname: String?
Expand Down
1 change: 1 addition & 0 deletions Mlem/App/Models/Account/UserAccount.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Observation

@Observable
class UserAccount: Account, CommunityOrPersonStub {
static let tierNumber: Int = 1
static let identifierPrefix: String = "@"

let actorId: URL
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// CommunityOrPersonStub+Extensions.swift
// Mlem
//
// Created by Sjmarf on 30/05/2024.
//

import MlemMiddleware
import UIKit

extension CommunityOrPersonStub {
func copyFullNameWithPrefix() {
UIPasteboard.general.string = fullNameWithPrefix
ToastModel.main.add(.success("Copied"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ extension Post1Providing {
}

var linkHost: String? {
guard case .link = postType else {
guard case .link = type else {
return nil
}

Expand All @@ -45,7 +45,7 @@ extension Post1Providing {
}

var placeholderImageName: String {
switch postType {
switch type {
case .text:
Icons.textPost
case .image:
Expand Down
25 changes: 25 additions & 0 deletions Mlem/App/Utility/Extensions/Date+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// Date+Extensions.swift
// Mlem
//
// Created by Jake Shirley on 6/22/23.
//

import SwiftUI

extension Date {
// Returns strings like "3 seconds ago" and "10 days ago"
func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = unitsStyle

return formatter.localizedString(for: self, relativeTo: date)
}

// Returns strings like "5/10/2023"
var dateString: String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "ddMMYY", options: 0, locale: Locale.current)
return dateFormatter.string(from: self)
}
}
26 changes: 26 additions & 0 deletions Mlem/App/Utility/Extensions/Int+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// Int+Extensions.swift
// Mlem
//
// Created by Sjmarf on 13/04/2024.
//

import Foundation

extension Int {
var abbreviated: String {
if self >= 10_000_000 {
return "\(Int(floor(Double(self) / 1_000_000)))M"
}
if self >= 1_000_000 {
return "\(Double(floor(Double(self) / 100_000) / 10))M"
}
if self >= 10000 {
return "\(Int(floor(Double(self) / 1000)))K"
}
if self >= 1000 {
return "\(Double(floor(Double(self) / 100) / 10))K"
}
return String(self)
}
}
34 changes: 34 additions & 0 deletions Mlem/App/Utility/Extensions/MarkdownConfiguration+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// MarkdownConfiguration+Extensions.swift
// Mlem
//
// Created by Sjmarf on 30/05/2024.
//

import LemmyMarkdownUI
import Nuke
import SwiftUI

extension MarkdownConfiguration {
static let `default`: Self = .init(
inlineImageLoader: loadInlineImage,
imageBlockView: { AnyView(MarkdownImageView(image: $0)) }
)
}

private func loadInlineImage(inlineImage: InlineImage) async {
guard inlineImage.image == nil else { return }
let imageTask = ImagePipeline.shared.imageTask(with: inlineImage.url)
guard let image: UIImage = try? await imageTask.image else { return }
let height = inlineImage.fontSize
let width = image.size.width * (height / image.size.height)
UIGraphicsBeginImageContextWithOptions(CGSize(width: width, height: height), false, 2.0)
defer { UIGraphicsEndImageContext() }
image.draw(in: CGRect(x: 0, y: 0, width: width, height: height))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
if let newImage {
DispatchQueue.main.async {
inlineImage.image = Image(uiImage: newImage)
}
}
}
125 changes: 125 additions & 0 deletions Mlem/App/Views/Pages/PersonView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
//
// PersonView.swift
// Mlem
//
// Created by Sjmarf on 30/05/2024.
//

import LemmyMarkdownUI
import MlemMiddleware
import SwiftUI

struct PersonView: View {
enum Tab: String, CaseIterable, Identifiable {
case overview, comments, posts, communities

var id: Self { self }
var label: String { rawValue.capitalized }
}

@State var person: AnyPerson
@State var selectedTab: Tab = .overview
@State var isAtTop: Bool = true

var body: some View {
ContentLoader(model: person) { person in
content(person: person)
}
.navigationTitle(isAtTop ? "" : (person.wrappedValue.displayName_ ?? person.wrappedValue.name))
.navigationBarTitleDisplayMode(.inline)
}

@ViewBuilder
func content(person: any Person) -> some View {
FancyScrollView(isAtTop: $isAtTop) {
VStack(spacing: AppConstants.standardSpacing) {
ProfileHeaderView(person, type: .person)
.padding(.horizontal, AppConstants.standardSpacing)
bio(person: person)
if let person = person as? any Person3Providing {
VStack(spacing: 0) {
personContent(person: person)
}
.transition(.opacity)
} else {
VStack(spacing: 0) {
Divider()
ProgressView()
.padding(.top)
}
.transition(.opacity)
}
}
.animation(.easeOut(duration: 0.2), value: person is any Person3Providing)
}
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
// TODO:
ToolbarEllipsisMenu {}
}
}
}

@ViewBuilder
func bio(person: any Person) -> some View {
if let bio = person.description_ {
Divider()
VStack(spacing: AppConstants.standardSpacing) {
let blocks: [BlockNode] = .init(bio)
if blocks.isSimpleParagraphs, bio.count < 300 {
MarkdownText(blocks, configuration: .default)
.multilineTextAlignment(.center)
.padding(.horizontal, AppConstants.standardSpacing)
dateLabel(person: person)
.frame(maxWidth: .infinity, alignment: .center)
} else {
Markdown(blocks, configuration: .default)
.padding(.horizontal, AppConstants.standardSpacing)
dateLabel(person: person)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
.padding(.top, AppConstants.halfSpacing)
} else {
dateLabel(person: person)
.frame(maxWidth: .infinity, alignment: .center)
}
}

@ViewBuilder
func dateLabel(person: any Person) -> some View {
ProfileDateView(profilable: person)
.padding(.horizontal, AppConstants.standardSpacing)
.padding(.vertical, 2)
}

@ViewBuilder
func personContent(person: any Person3Providing) -> some View {
BubblePicker(
tabs(person: person),
selected: $selectedTab,
withDividers: [.top, .bottom],
label: \.label,
value: { tab in
switch tab {
case .posts:
person.postCount
case .comments:
person.commentCount
case .communities:
person.moderatedCommunities.count
default:
nil
}
}
)
}

func tabs(person: any Person3Providing) -> [Tab] {
var output: [Tab] = [.overview, .posts, .comments]
if !person.moderatedCommunities.isEmpty {
output.append(.communities)
}
return output
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ struct PostLinkHostView: View {
var body: some View {
content
.lineLimit(1)
.imageScale(.small)
.foregroundStyle(palette.secondary)
.imageScale(.small)
.foregroundStyle(palette.secondary)
}

var content: Text {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ struct ThumbnailImageView: View {
.foregroundStyle(palette.secondary)
.background(palette.thumbnailBackground)
.clipShape(RoundedRectangle(cornerRadius: AppConstants.smallItemCornerRadius))
.overlay(RoundedRectangle(cornerRadius: AppConstants.smallItemCornerRadius)
.stroke(palette.secondaryBackground, lineWidth: 1))
.overlay(
RoundedRectangle(cornerRadius: AppConstants.smallItemCornerRadius)
.stroke(palette.secondaryBackground, lineWidth: 1)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ struct HeadlinePostView: View {
}

if showCreator {
FullyQualifiedLabelView(entity: post.creator_, labelStyle: .medium, showAvatar: showUserAvatar)
FullyQualifiedLinkView(entity: post.creator_, labelStyle: .medium, showAvatar: showUserAvatar)
}
}
}
Expand Down
7 changes: 4 additions & 3 deletions Mlem/App/Views/Root/Tabs/Feeds/Feed Posts/LargePostView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import Foundation
import LemmyMarkdownUI
import MlemMiddleware
import SwiftUI

Expand Down Expand Up @@ -46,16 +47,16 @@ struct LargePostView: View {
postDetail

if showCreator {
FullyQualifiedLabelView(entity: post.creator_, labelStyle: .large, showAvatar: showUserAvatar)
FullyQualifiedLinkView(entity: post.creator_, labelStyle: .large, showAvatar: showUserAvatar)
}
}
}

@ViewBuilder
var postDetail: some View {
switch post.postType {
switch post.type {
case let .text(text):
Markdown(text)
Markdown(text, configuration: .default)
.lineLimit(8)
.foregroundStyle(palette.secondary)
case .image:
Expand Down
7 changes: 4 additions & 3 deletions Mlem/App/Views/Root/Tabs/Feeds/Feed Posts/TilePostView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import Foundation
import LemmyMarkdownUI
import MlemMiddleware
import NukeUI
import SwiftUI
Expand Down Expand Up @@ -60,7 +61,7 @@ struct TilePostView: View {

@ViewBuilder
var titleSection: some View {
if case .text = post.postType {
if case .text = post.type {
VStack(spacing: 2) {
Text(post.title)
.font(.footnote)
Expand Down Expand Up @@ -110,9 +111,9 @@ struct TilePostView: View {
var dimension: CGFloat { UIScreen.main.bounds.width / 2 - (AppConstants.standardSpacing * 1.5) }

var body: some View {
switch post.postType {
switch post.type {
case let .text(text):
Markdown(text)
Markdown(text, configuration: .default)
.font(.caption)
.foregroundStyle(palette.secondary)
.padding(AppConstants.standardSpacing)
Expand Down
2 changes: 1 addition & 1 deletion Mlem/App/Views/Root/Tabs/Feeds/FeedsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ struct MinimalPostFeedView: View {
ForEach(postTracker.items, id: \.uid) { post in
VStack(spacing: 0) { // this improves performance O_o
NavigationLink(value: NavigationPage.expandedPost(post)) {
FeedPostView(post: .init(post: post))
FeedPostView(post: .init(post))
.contentShape(.rect)
}
.buttonStyle(EmptyButtonStyle())
Expand Down
16 changes: 3 additions & 13 deletions Mlem/App/Views/Root/Tabs/Profile/Profile View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import Dependencies
import LemmyMarkdownUI
import MlemMiddleware
import SwiftUI

Expand All @@ -14,19 +15,8 @@ struct ProfileView: View {
@Environment(NavigationLayer.self) var navigation

var body: some View {
content
.navigationTitle("Profile")
}

var markdown: String {
// swiftlint:disable:next line_length
"# One\nLorem Ipsum [Link1](https://google.com)\nWorld\n::: spoiler Title!\n> Quote!\n\nCulpa nisi labore adipisicing ~tempor elit ut commodo~ magna mollit @sjmarf@lemmy.ml adipisicing magna. Irure aute deserunt *sit [Link2](https://google.com) voluptate eiusmod*. Sint sint do proident eiusmod dolore `qui est et dolor` dolor cillum dolor do. **Dolor tempor cillum** occaecat aliqua nisi sunt sunt ^dolor^ adipisicing. Excepteur sint ex dolore Lorem sunt nostrud dolor aliqua aute esse /c/memes@lemmy.world cupidatat. ~~Occaecat eu incididunt~~ commodo irure eiusmod et incididunt anim cillum qui ad nisi.\n:::\ndolor sit amet\n| Month | Savings |\n| ------------ | ------- |\n| January | $250 |\n| **February** | $80 |\n| March | $420 |\n---\n>Hello world\n\n![](https://lemmy.ml/pictrs/image/ed5f5ff0-0c0f-428e-a4e7-bb488e77fdaf.png?format=webp)\n\n- **Bold**\n- *Italic*\n- ***Bold and Italic***\n\n4) Image ![](https://lemmy.ml/pictrs/image/ed5f5ff0-0c0f-428e-a4e7-bb488e77fdaf.png?format=webp)\n5) ~~strikethrough~~\n6) `code`\n7) SUPER^SCRIPT^\n8) SUB~SCRIPT~\n9) [Link3](https://google.com)\n10) auto-link: www.google.com\n11) email@example.com\n\nAll Lemmy link types:\n- !mlemapp@lemmy.ml\n- @sjmarf@lemmy.ml\n- /c/memes@lemmy.ml\n- /u/FlyingSquid@lemmy.world\n```\nfor i in range(5): # This is a super long comment which you need to scroll for\n print(i)\n```\n"
}

var content: some View {
ScrollView {
Markdown(markdown)
.padding()
if let person = (appState.firstSession as? UserSession)?.person {
PersonView(person: .init(person))
}
}
}
Loading

0 comments on commit 6cf19de

Please sign in to comment.