Skip to content

Commit

Permalink
Merge branch 'dev' into sjmarf/remove-community2
Browse files Browse the repository at this point in the history
  • Loading branch information
Sjmarf authored Dec 17, 2024
2 parents 9c97a8d + 35f9def commit cc685c1
Show file tree
Hide file tree
Showing 23 changed files with 239 additions and 36 deletions.
6 changes: 5 additions & 1 deletion Mlem.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@
CD09BA7F2CB4698E00C93926 /* OledPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD09BA7E2CB4698600C93926 /* OledPalette.swift */; };
CD0E06F72C0E739F00445849 /* PostType+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD0E06F62C0E739F00445849 /* PostType+Extensions.swift */; };
CD0F280A2C6CEFBE00C1F65B /* View+IsAtTopSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD0F28092C6CEFBE00C1F65B /* View+IsAtTopSubscriber.swift */; };
CD10CC182D0A0A650006C20F /* MediaState.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD10CC172D0A0A5C0006C20F /* MediaState.swift */; };
CD10FA772C7A8622008985AD /* ImageSaver.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD10FA762C7A8622008985AD /* ImageSaver.swift */; };
CD13CC572C582DD8001AF428 /* DynamicMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD13CC562C582DD8001AF428 /* DynamicMediaView.swift */; };
CD13CC592C583C7A001AF428 /* WebsitePreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD13CC582C583C7A001AF428 /* WebsitePreviewView.swift */; };
Expand Down Expand Up @@ -709,6 +710,7 @@
CD0E06F62C0E739F00445849 /* PostType+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PostType+Extensions.swift"; sourceTree = "<group>"; };
CD0E07002C12707700445849 /* ToolbarEllipsisMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarEllipsisMenu.swift; sourceTree = "<group>"; };
CD0F28092C6CEFBE00C1F65B /* View+IsAtTopSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+IsAtTopSubscriber.swift"; sourceTree = "<group>"; };
CD10CC172D0A0A5C0006C20F /* MediaState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaState.swift; sourceTree = "<group>"; };
CD10FA762C7A8622008985AD /* ImageSaver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageSaver.swift; sourceTree = "<group>"; };
CD13CC562C582DD8001AF428 /* DynamicMediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicMediaView.swift; sourceTree = "<group>"; };
CD13CC582C583C7A001AF428 /* WebsitePreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebsitePreviewView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1668,13 +1670,14 @@
CD4D59212B87BD0800B82964 /* Definitions */ = {
isa = PBXGroup;
children = (
CDCA44AE2C17672900C092B3 /* HapticManager */,
CD4D58B22B86BFD400B82964 /* AccountsTracker.swift */,
036CC3AE2B8145C30098B6A1 /* AppState.swift */,
0380965E2C10AA80003ED1D8 /* AppState+Transition.swift */,
CD10CC172D0A0A5C0006C20F /* MediaState.swift */,
CD317D4B2BE97FED008F63E2 /* Palette.swift */,
CD4D58A42B86BD1B00B82964 /* PersistenceRepository.swift */,
CD4ED8462BF110FA00EFA0A2 /* TabReselectTracker.swift */,
CDCA44AE2C17672900C092B3 /* HapticManager */,
);
path = Definitions;
sourceTree = "<group>";
Expand Down Expand Up @@ -2342,6 +2345,7 @@
CD7DB9762C4D6C0A00DCC542 /* FeedCommentView.swift in Sources */,
03D3A1EF2BB9CA1D009DE55E /* MenuButton.swift in Sources */,
CD0507732C6AA0C8008B1505 /* FeedSelection.swift in Sources */,
CD10CC182D0A0A650006C20F /* MediaState.swift in Sources */,
039F58862C7A810100C61658 /* ExpandedPostView+Logic.swift in Sources */,
031E2D512BEF961D0003BC45 /* SubscriptionListView.swift in Sources */,
CDD4A09E2C8B69FC0001AD1A /* Button.swift in Sources */,
Expand Down
8 changes: 4 additions & 4 deletions Mlem/App/Configuration/User Settings/CodableSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ struct CodableSettings: Codable {
var links_readerMode: Bool
var links_tappableLinksDisplayMode: TappableLinksDisplayMode
var menus_allModActions: Bool
var menus_modActionGrouping: String // TODO: pending mod actions
var menus_modActionGrouping: ModeratorActionGrouping
var post_defaultSort: ApiSortType
var post_fallbackSort: ApiSortType
var post_limitImageHeight: Bool
Expand Down Expand Up @@ -132,7 +132,7 @@ struct CodableSettings: Codable {
self.links_readerMode = try container.decodeIfPresent(Bool.self, forKey: .links_readerMode) ?? false
self.links_tappableLinksDisplayMode = try container.decodeIfPresent(TappableLinksDisplayMode.self, forKey: .links_tappableLinksDisplayMode) ?? .contextual
self.menus_allModActions = try container.decodeIfPresent(Bool.self, forKey: .menus_allModActions) ?? false
self.menus_modActionGrouping = try container.decodeIfPresent(String.self, forKey: .menus_modActionGrouping) ?? "none"
self.menus_modActionGrouping = try container.decodeIfPresent(ModeratorActionGrouping.self, forKey: .menus_modActionGrouping) ?? .divider
self.post_defaultSort = try container.decodeIfPresent(ApiSortType.self, forKey: .post_defaultSort) ?? .hot
self.post_fallbackSort = try container.decodeIfPresent(ApiSortType.self, forKey: .post_fallbackSort) ?? .hot
self.post_limitImageHeight = try container.decodeIfPresent(Bool.self, forKey: .post_limitImageHeight) ?? true
Expand Down Expand Up @@ -209,8 +209,8 @@ struct CodableSettings: Codable {
self.links_openInBrowser = settings.openLinksInBrowser
self.links_readerMode = settings.openLinksInReaderMode
self.links_tappableLinksDisplayMode = settings.tappableLinksDisplayMode
self.menus_allModActions = false
self.menus_modActionGrouping = "none"
self.menus_allModActions = settings.showAllModActions
self.menus_modActionGrouping = settings.moderatorActionGrouping
self.post_defaultSort = settings.defaultPostSort
self.post_fallbackSort = settings.fallbackPostSort
self.post_limitImageHeight = true
Expand Down
3 changes: 3 additions & 0 deletions Mlem/App/Configuration/User Settings/Settings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class Settings: ObservableObject {
@AppStorage("navigation.swipeAnywhere") var swipeAnywhereToNavigate: Bool = false

@AppStorage("menus.moderatorActionGrouping") var moderatorActionGrouping: ModeratorActionGrouping = .divider
@AppStorage("menus.allModActions") var showAllModActions: Bool = false

var codable: CodableSettings { .init(from: self) }

Expand Down Expand Up @@ -149,5 +150,7 @@ class Settings: ObservableObject {
autoBypassImageProxy = settings.privacy_autoBypassImageProxy
sidebarVisibleByDefault = settings.navigation_sidebarVisibleByDefault
swipeAnywhereToNavigate = settings.navigation_swipeAnywhere
moderatorActionGrouping = settings.menus_modActionGrouping
showAllModActions = settings.menus_allModActions
}
}
13 changes: 13 additions & 0 deletions Mlem/App/Globals/Definitions/MediaState.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// MediaState.swift
// Mlem
//
// Created by Eric Andrews on 2024-12-11.
//

import SwiftUI

@Observable
class MediaState {
var url: URL?
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ extension Post1Providing {
func allMenuActions(
expanded: Bool = false,
feedback: Set<FeedbackType> = [.haptic, .toast],
showAllActions: Bool = true,
commentTreeTracker: CommentTreeTracker? = nil
) -> [any Action] {
basicMenuActions(feedback: feedback, commentTreeTracker: commentTreeTracker)
Expand All @@ -139,7 +140,7 @@ extension Post1Providing {
appearance: .init(label: "Moderation...", color: Palette.main.moderation, icon: Icons.moderation),
displayMode: Settings.main.moderatorActionGrouping == .divider || expanded ? .section : .disclosure
) {
moderatorMenuActions(feedback: feedback)
moderatorMenuActions(feedback: feedback, showAllActions: showAllActions)
}
}
}
Expand Down Expand Up @@ -178,12 +179,17 @@ extension Post1Providing {
}

@ActionBuilder
func moderatorMenuActions(feedback: Set<FeedbackType> = [.haptic, .toast]) -> [any Action] {
pinToCommunityAction(feedback: feedback, verboseTitle: api.isAdmin)
if api.isAdmin {
pinToInstanceAction(feedback: feedback)
func moderatorMenuActions(
feedback: Set<FeedbackType> = [.haptic, .toast],
showAllActions: Bool = true
) -> [any Action] {
if showAllActions || Settings.main.showAllModActions {
pinToCommunityAction(feedback: feedback, verboseTitle: api.isAdmin)
if api.isAdmin {
pinToInstanceAction(feedback: feedback)
}
lockAction(feedback: feedback)
}
lockAction(feedback: feedback)
if let self2, !isOwnPost {
self2.removeAction().disabled(!canModerate)
banActions()
Expand Down
93 changes: 87 additions & 6 deletions Mlem/App/Views/Pages/ImageViewer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,106 @@ import SwiftUI

struct ImageViewer: View {
@Environment(Palette.self) var palette
@Environment(MediaState.self) var mediaState

let url: URL

let duration: CGFloat = 0.25
let screenHeight: CGFloat = UIScreen.main.bounds.height

@GestureState var dragState: Bool = false

@State var isZoomed: Bool = false
@State var offset: CGFloat = 0
@State var isDismissing: Bool = false
@State var opacity: CGFloat = 0

init(url: URL) {
var components = URLComponents(url: url, resolvingAgainstBaseURL: false)!
components.queryItems = components.queryItems?.filter { $0.name != "thumbnail" }
self.url = components.url!
}

var body: some View {
ZoomableContainer {
DynamicMediaView(url: url, playImmediately: true)
ZoomableContainer(isZoomed: $isZoomed) {
DynamicMediaView(url: url, cornerRadius: 0, playImmediately: true)
}
.offset(y: offset)
.background(.black)
.opacity(opacity)
.overlay(alignment: .topTrailing) {
if offset == 0 {
Button {
fadeDismiss()
} label: {
Image(systemName: Icons.close)
.resizable()
.frame(width: 15, height: 15)
.foregroundStyle(.white)
.padding([.top, .trailing], Constants.main.standardSpacing)
.padding([.bottom, .leading], Constants.main.doubleSpacing)
.contentShape(.rect)
}
.padding(Constants.main.standardSpacing)
}
}
.simultaneousGesture(DragGesture(minimumDistance: 0.0)
.updating($dragState) { value, state, _ in
state = true
if !isZoomed, !isDismissing {
offset = value.translation.height
opacity = 1.0 - (abs(value.translation.height) / screenHeight)
}
}
)
.onAppear {
updateOpacity(1.0)
}
.onChange(of: dragState) {
if !dragState {
if abs(offset) > 100 {
swipeDismiss(finalOffset: offset > 0 ? screenHeight : -screenHeight)
} else {
updateDragDistance(0)
}
}
}
}

private func fadeDismiss() {
isDismissing = true
updateOpacity(0) {
mediaState.url = nil
}
}

private func swipeDismiss(finalOffset: CGFloat = UIScreen.main.bounds.height) {
isDismissing = true
updateDragDistance(finalOffset) {
mediaState.url = nil
}
}

private func updateOpacity(_ newOpacity: CGFloat, callback: (() -> Void)? = nil) {
withAnimation(.easeOut(duration: duration)) {
opacity = newOpacity
}
if let callback {
DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
callback()
}
}
}

private func updateDragDistance(_ newDistance: CGFloat, callback: (() -> Void)? = nil) {
withAnimation(.easeOut(duration: duration)) {
offset = newDistance
opacity = 1.0 - (abs(newDistance) / screenHeight)
}
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
CloseButtonView()
if let callback {
DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
callback()
}
}
.background(palette.background)
}
}
48 changes: 48 additions & 0 deletions Mlem/App/Views/Pages/Person/PersonView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Created by Sjmarf on 30/05/2024.
//

import Flow
import LemmyMarkdownUI
import MlemMiddleware
import SwiftUI
Expand Down Expand Up @@ -36,10 +37,12 @@ struct PersonView: View {
@State private var selectedContentType: PersonContentType = .all
@State private var isAtTop: Bool = true
@State var feedLoader: PersonContentFeedLoader?
@State var isAdmin: Bool
let isProfileTab: Bool

init(person: AnyPerson, isProfileTab: Bool = false) {
self._person = .init(wrappedValue: person)
self._isAdmin = .init(wrappedValue: person.wrappedValue.isAdmin_ ?? false)
self.isProfileTab = isProfileTab

if let person1 = person.wrappedValue as? any Person1Providing, person1.api === AppState.main.firstApi {
Expand Down Expand Up @@ -114,6 +117,12 @@ struct PersonView: View {
}
return try await entity.upgrade()
}
// This prevents the admin flair from disappearing if the `ContentLoader`
// switches from an external ApiClient to the active ApiClient, e.g. when
// navigating to `PersonView` from the administrator list in `InstanceView`.
if model.wrappedValue.isAdmin_ ?? false {
isAdmin = true
}
}
.navigationTitle(isAtTop ? "" : (person.wrappedValue.displayName_ ?? person.wrappedValue.name))
.navigationBarTitleDisplayMode(.inline)
Expand All @@ -125,6 +134,7 @@ struct PersonView: View {
VStack(spacing: 0) {
VStack(spacing: Constants.main.standardSpacing) {
ProfileHeaderView(person, fallback: .person)
flairsView(person: person)
bio(person: person)
}
.padding([.horizontal], Constants.main.standardSpacing)
Expand Down Expand Up @@ -175,6 +185,27 @@ struct PersonView: View {
}
}

@ViewBuilder
func flairsView(person: any Person) -> some View {
if person.isBot || person.isMlemDeveloper || isAdmin {
HFlow(spacing: Constants.main.halfSpacing) {
if person.isMlemDeveloper {
Label("Mlem Developer", systemImage: Icons.developerFlair)
.tint(palette.colorfulAccent(4))
}
if isAdmin {
Label("\(person.host ?? "") Administrator", systemImage: Icons.adminFlair)
.tint(palette.administration)
}
if person.isBot {
Label("Bot Account", systemImage: Icons.botFlair)
.tint(palette.colorfulAccent(5))
}
}
.labelStyle(FlairLabelStyle())
}
}

@ViewBuilder
func dateLabel(person: any Person) -> some View {
ProfileDateView(profilable: person)
Expand Down Expand Up @@ -233,3 +264,20 @@ struct PersonView: View {
.padding([.horizontal, .bottom], Constants.main.standardSpacing)
}
}

private struct FlairLabelStyle: LabelStyle {
@Environment(Palette.self) private var palette

func makeBody(configuration: Configuration) -> some View {
HStack(spacing: 5) {
configuration.icon
.imageScale(.small)
configuration.title
}
.font(.footnote)
.padding(.vertical, 2)
.padding(.horizontal, 8)
.foregroundStyle(.tint)
.background(.tint.opacity(0.2), in: .capsule)
}
}
11 changes: 11 additions & 0 deletions Mlem/App/Views/Root/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct ContentView: View {
var palette: Palette { .main }
var tabReselectTracker: TabReselectTracker { .main }
var navigationModel: NavigationModel { .main }
var mediaState: MediaState = .init()

@State var avatarImage: UIImage?
@State var selectedAvatarImage: UIImage?
Expand Down Expand Up @@ -102,6 +103,7 @@ struct ContentView: View {
}
}
}
.environment(mediaState)
.environment(AppState.main)
}
}
Expand Down Expand Up @@ -170,5 +172,14 @@ struct ContentView: View {
location: .top
)
}
.overlay {
if let url = mediaState.url {
NavigationLayerView(
layer: .init(root: .imageViewer(url),
model: navigationModel,
hasNavigationStack: false),
hasSheetModifiers: false)
}
}
}
}
3 changes: 2 additions & 1 deletion Mlem/App/Views/Root/Tabs/Feeds/Feed Posts/FeedPostView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import SwiftUI
struct FeedPostView: View {
@Setting(\.postSize) private var postSize

@Environment(CommentTreeTracker.self) private var commentTreeTracker: CommentTreeTracker?
@Environment(Palette.self) private var palette

let post: any Post1Providing
Expand All @@ -23,7 +24,7 @@ struct FeedPostView: View {
.contentShape(.interaction, .rect)
.contentShape(.contextMenuPreview, .rect(cornerRadius: Constants.main.standardSpacing))
.quickSwipes(post.swipeActions(behavior: postSize.swipeBehavior))
.contextMenu { post.allMenuActions() }
.contextMenu { post.allMenuActions(showAllActions: false, commentTreeTracker: commentTreeTracker) }
.paletteBorder(cornerRadius: postSize.swipeBehavior.cornerRadius)
}

Expand Down
Loading

0 comments on commit cc685c1

Please sign in to comment.