Skip to content

Commit

Permalink
Merge branch 'dev' into sjmarf/glide-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
Sjmarf authored Dec 17, 2024
2 parents 7930852 + 20a92ec commit 44098c5
Show file tree
Hide file tree
Showing 18 changed files with 182 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 @@ -286,6 +286,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 @@ -707,6 +708,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 @@ -1666,13 +1668,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 @@ -2338,6 +2341,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()
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)
}
}
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
3 changes: 2 additions & 1 deletion Mlem/App/Views/Root/Tabs/Feeds/Feed Posts/TilePostView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import NukeUI
import SwiftUI

struct TilePostView: View {
@Environment(CommentTreeTracker.self) private var commentTreeTracker: CommentTreeTracker?
@Environment(Palette.self) var palette: Palette
@Environment(\.communityContext) var communityContext: (any Community1Providing)?
@Environment(\.parentFrameWidth) var parentFrameWidth: CGFloat
Expand Down Expand Up @@ -93,7 +94,7 @@ struct TilePostView: View {

var score: some View {
Menu {
ForEach(post.allMenuActions(), id: \.id) { action in
ForEach(post.allMenuActions(showAllActions: false, commentTreeTracker: commentTreeTracker), id: \.id) { action in
MenuButton(action: action)
}
} label: {
Expand Down
22 changes: 21 additions & 1 deletion Mlem/App/Views/Root/Tabs/Settings/ModeratorSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import SwiftUI

struct ModeratorSettingsView: View {
@Setting(\.moderatorActionGrouping) var moderatorActionGrouping
@Setting(\.showAllModActions) var showAllModActions

var body: some View {
Form {
Expand All @@ -27,11 +28,30 @@ struct ModeratorSettingsView: View {
Text("Separate moderator actions using...")
.textCase(nil)
}
Section {
Toggle("Show All Actions in Feed", isOn: $showAllModActions)
} footer: {
Text("When disabled, some moderator actions will only be accessible from the post page.")
}
}
.navigationTitle("Moderation")
}
}

enum ModeratorActionGrouping: String {
enum ModeratorActionGrouping: String, Codable {
case divider, disclosureGroup, separateMenu

init?(rawValue: String) {
switch rawValue {
// Decode v1 case
case "none", "divider":
self = .divider
case "disclosureGroup":
self = .disclosureGroup
case "separateMenu":
self = .separateMenu
default:
return nil
}
}
}
2 changes: 1 addition & 1 deletion Mlem/App/Views/Shared/ExpandedPost/ExpandedPostView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ struct ExpandedPostView<Content: View>: View {
}
.contentShape(.contextMenuPreview, .rect(cornerRadius: Constants.main.standardSpacing))
.quickSwipes(post.swipeActions(behavior: .standard, commentTreeTracker: tracker))
.contextMenu { post.allMenuActions() }
.contextMenu { post.allMenuActions(showAllActions: false, commentTreeTracker: tracker) }
.paletteBorder(cornerRadius: PostSize.large.swipeBehavior.cornerRadius)
.onTapGesture {
withAnimation {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ private struct AnimationControlLayer: ViewModifier {
}
}
}
.overlay(alignment: .topTrailing) {
.overlay(alignment: .bottomTrailing) {
if let muted {
Image(systemName: muted.wrappedValue ? Icons.muted : Icons.unmuted)
.resizable()
Expand Down
9 changes: 3 additions & 6 deletions Mlem/App/Views/Shared/Images/Wrappers/LargeImageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import SwiftUI
// and anything else that can't go in thumbnail views etc.

struct LargeImageView: View {
@Environment(MediaState.self) var mediaState

@Environment(NavigationLayer.self) private var navigation
@Setting(\.blurNsfw) var blurNsfw

Expand Down Expand Up @@ -55,12 +57,7 @@ struct LargeImageView: View {
onTapActions()
}
if let loading, loading == .done, let url {
// Sheets don't cover the whole screen on iPad, so use a fullScreenCover instead
if UIDevice.isPad {
navigation.showFullScreenCover(.imageViewer(url))
} else {
navigation.openSheet(.imageViewer(url))
}
mediaState.url = url
}
}
.onPreferenceChange(MediaLoadingPreferenceKey.self, perform: { loading = $0 })
Expand Down
Loading

0 comments on commit 44098c5

Please sign in to comment.