Skip to content

Commit

Permalink
Color Profiles (#1058)
Browse files Browse the repository at this point in the history
Co-authored-by: Sjmarf <[email protected]>
  • Loading branch information
EricBAndrews and Sjmarf authored May 11, 2024
1 parent 06ed65e commit 050053a
Show file tree
Hide file tree
Showing 17 changed files with 298 additions and 41 deletions.
54 changes: 51 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ With these steps completed each time you build your code will be linted, and eac

## Getting started

To avoid having multiple in-flight tasks working on the same part of the codebase, we have a set procedure for claiming and performing work. If you don't follow it, your PR will *probably* be rejected (unless it's really *that* good).
To avoid having multiple in-flight tasks working on the same part of the codebase, we have a set procedure for claiming and performing work. If you don't follow it, your PR will _probably_ be rejected (unless it's really _that_ good).

1. Go to our [project board](https://github.com/orgs/mlemgroup/projects/1/views/1).
2. Find an unassigned issue under the "Todo" section that you'd like to work on.
Expand All @@ -39,10 +39,58 @@ When your code is approved, it can be merged into the `dev` branch by a member o
## Conventions

Please develop according to the following principles:
- One View per file. A file containing a View struct must end in "View". We're yet to decide on an official naming scheme for files - feel free to offer your thoughts [here](https://github.com/mlemgroup/mlem/issues/55).

- Files should be named according to the following patterns:
- All files: `TitleCase`. If the file contains extensions, it should be named `BaseEntity+Extensions`.
- `View` files: file name must end in `View` (e.g., `FeedsView`)
- One View per file.
- Within reason, any complex of views that renders a single component of a larger view should be placed in a descriptively named function, computed property or `@ViewBuilder` variable beneath the body of the View. This keeps pyramids from piling up and makes our accessibility experts' work easier.
- If you can reuse code, do. Prefer abstracting common components to a generic struct and common logic to a generic function.

## View Structure

All `View` structs should be organized according to the following template:

```
struct SomeView: View {
@AppStorage values
@Environment entities
@Binding variables
@State variables
Normal variables
Computed properties
// if necessary
init() { ... }
var body: some View { ... }
// if necessary
var content: some View { ... }
Helper views
}
```

Further notes:

- If the view has modifiers that are attached to the entire body, place the view definition in `content` and attach these modifiers to it in `body` (see `ContentView.swift` for an example).
- Prefer `var helper: some View` to `func helper() -> some View` unless the helper view takes in parameters.
- Helper views should always appear lower in the file than the view they help.

## Global Objects

There are several objects (e.g., `AppState`) that need to be available anywhere in the app. Normally this is handled with `@Environment`, but this is not available outside of the context of a `View`. To address this, globals that need to be available outside of a `View` define a `static var main: GlobalObject = .init()`, allowing them to be referenced as `GlobalObject.main`. This definition should be placed immediately above the initializer.

This pattern should be used only where necessary, and should not be blindly applied to any global object. Likewise, if possible, these objects should be referenced via `@Environment(GlobalObject.self) var globalObject`; the static singleton should be considered a last resort.

## Colors

Colors are managed using the globally available `Palette` object, which enables color themes. The following conventions apply:

- Avoid referencing `Color` directly; always use a `Palette` color.
- Prefer semantic over literal colors (e.g., `.upvote` over `.blue`).

## Testing

We operate a Lemmy Instance at https://test-mlem.jo.wtf/ which you may use for testing purposes.
We operate a Lemmy Instance at https://test-mlem.jo.wtf/ which you may use for testing purposes. Please note that, as of 2024-05-10, it is running Lemmy v17, which is no longer used by any major Lemmy instance and thus we do not bother maintaining compatibility for. You may wish to use a local Lemmy instance instead.
40 changes: 35 additions & 5 deletions Mlem.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,14 @@
CD1446212A5B328E00610EF1 /* Privacy Policy.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1446202A5B328E00610EF1 /* Privacy Policy.swift */; };
CD1446252A5B357900610EF1 /* Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1446242A5B357900610EF1 /* Document.swift */; };
CD1446272A5B36DA00610EF1 /* EULA.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1446262A5B36DA00610EF1 /* EULA.swift */; };
CD317D4C2BE97FED008F63E2 /* Palette.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD317D4B2BE97FED008F63E2 /* Palette.swift */; };
CD317D4F2BE983ED008F63E2 /* MonochromePalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD317D4E2BE983ED008F63E2 /* MonochromePalette.swift */; };
CD4368C12AE23FD400BD8BD1 /* Semaphore in Frameworks */ = {isa = PBXBuildFile; productRef = CD4368C02AE23FD400BD8BD1 /* Semaphore */; };
CD4BAD352B4B2C0B00A1E726 /* FeedsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4BAD342B4B2C0B00A1E726 /* FeedsView.swift */; };
CD4D583F2B86855F00B82964 /* MlemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4D583E2B86855F00B82964 /* MlemTests.swift */; };
CD4D58412B86858100B82964 /* MlemUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4D58402B86858100B82964 /* MlemUITests.swift */; };
CD4D58742B86B4AA00B82964 /* AccountsTracker+Dependency.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4D58732B86B4AA00B82964 /* AccountsTracker+Dependency.swift */; };
CD4D58932B86BA5C00B82964 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4D58922B86BA5C00B82964 /* Colors.swift */; };
CD4D58932B86BA5C00B82964 /* StandardPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4D58922B86BA5C00B82964 /* StandardPalette.swift */; };
CD4D58972B86BAD900B82964 /* EnvironmentValues+TabReselectionHashValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4D58962B86BAD900B82964 /* EnvironmentValues+TabReselectionHashValue.swift */; };
CD4D58992B86BB0300B82964 /* EnvironmentValues+TabSelectionHashValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4D58982B86BB0300B82964 /* EnvironmentValues+TabSelectionHashValue.swift */; };
CD4D58A52B86BD1B00B82964 /* PersistenceRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4D58A42B86BD1B00B82964 /* PersistenceRepository.swift */; };
Expand Down Expand Up @@ -95,6 +97,8 @@
CDA1E8542B952C3D007953EF /* StateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA1E8532B952C3D007953EF /* StateManager.swift */; };
CDC199EA2BE449790077B4F1 /* Interactable1Providing+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC199E92BE449790077B4F1 /* Interactable1Providing+Extensions.swift */; };
CDC199EC2BE449EA0077B4F1 /* Post1Providing+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC199EB2BE449EA0077B4F1 /* Post1Providing+Extensions.swift */; };
CDC199EE2BE44A200077B4F1 /* Post2Providing+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC199ED2BE44A200077B4F1 /* Post2Providing+Extensions.swift */; };
CDEB38B42BED7CAE0059FBA7 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDEB38B32BED7CAE0059FBA7 /* SettingsView.swift */; };
CDF9EF332AB2845C003F885B /* Icons.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDF9EF322AB2845C003F885B /* Icons.swift */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -155,11 +159,13 @@
CD1446202A5B328E00610EF1 /* Privacy Policy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Privacy Policy.swift"; sourceTree = "<group>"; };
CD1446242A5B357900610EF1 /* Document.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Document.swift; sourceTree = "<group>"; };
CD1446262A5B36DA00610EF1 /* EULA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EULA.swift; sourceTree = "<group>"; };
CD317D4B2BE97FED008F63E2 /* Palette.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Palette.swift; sourceTree = "<group>"; };
CD317D4E2BE983ED008F63E2 /* MonochromePalette.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MonochromePalette.swift; sourceTree = "<group>"; };
CD4BAD342B4B2C0B00A1E726 /* FeedsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedsView.swift; sourceTree = "<group>"; };
CD4D583E2B86855F00B82964 /* MlemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MlemTests.swift; sourceTree = "<group>"; };
CD4D58402B86858100B82964 /* MlemUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MlemUITests.swift; sourceTree = "<group>"; };
CD4D58732B86B4AA00B82964 /* AccountsTracker+Dependency.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountsTracker+Dependency.swift"; sourceTree = "<group>"; };
CD4D58922B86BA5C00B82964 /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
CD4D58922B86BA5C00B82964 /* StandardPalette.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardPalette.swift; sourceTree = "<group>"; };
CD4D58962B86BAD900B82964 /* EnvironmentValues+TabReselectionHashValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "EnvironmentValues+TabReselectionHashValue.swift"; sourceTree = "<group>"; };
CD4D58982B86BB0300B82964 /* EnvironmentValues+TabSelectionHashValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "EnvironmentValues+TabSelectionHashValue.swift"; sourceTree = "<group>"; };
CD4D58A42B86BD1B00B82964 /* PersistenceRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersistenceRepository.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -197,6 +203,8 @@
CDA1E8532B952C3D007953EF /* StateManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateManager.swift; sourceTree = "<group>"; };
CDC199E92BE449790077B4F1 /* Interactable1Providing+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Interactable1Providing+Extensions.swift"; sourceTree = "<group>"; };
CDC199EB2BE449EA0077B4F1 /* Post1Providing+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Post1Providing+Extensions.swift"; sourceTree = "<group>"; };
CDC199ED2BE44A200077B4F1 /* Post2Providing+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Post2Providing+Extensions.swift"; sourceTree = "<group>"; };
CDEB38B32BED7CAE0059FBA7 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
CDF9EF322AB2845C003F885B /* Icons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Icons.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -347,6 +355,7 @@
6363D5F427EE1BAE00E34822 /* Tabs */ = {
isa = PBXGroup;
children = (
CDEB38B22BED7CA30059FBA7 /* Settings */,
CD4BAD382B4C6C1B00A1E726 /* Feeds */,
6DE1183A2A4A215F00810C7E /* Profile */,
);
Expand All @@ -373,6 +382,15 @@
path = Data;
sourceTree = "<group>";
};
CD317D4D2BE97FFB008F63E2 /* Colors */ = {
isa = PBXGroup;
children = (
CD4D58922B86BA5C00B82964 /* StandardPalette.swift */,
CD317D4E2BE983ED008F63E2 /* MonochromePalette.swift */,
);
path = Colors;
sourceTree = "<group>";
};
CD4BAD382B4C6C1B00A1E726 /* Feeds */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -414,9 +432,9 @@
CD4D583D2B867DA900B82964 /* Constants */ = {
isa = PBXGroup;
children = (
CD317D4D2BE97FFB008F63E2 /* Colors */,
63DF71F02A02999C002AC14E /* AppConstants.swift */,
CDF9EF322AB2845C003F885B /* Icons.swift */,
CD4D58922B86BA5C00B82964 /* Colors.swift */,
);
path = Constants;
sourceTree = "<group>";
Expand Down Expand Up @@ -578,11 +596,12 @@
isa = PBXGroup;
children = (
CD4D58B22B86BFD400B82964 /* AccountsTracker.swift */,
CDA1E8262B90EF24007953EF /* AppFlow.swift */,
036CC3AE2B8145C30098B6A1 /* AppState.swift */,
CD317D4B2BE97FED008F63E2 /* Palette.swift */,
CD4D58A42B86BD1B00B82964 /* PersistenceRepository.swift */,
CD4D58FB2B87B13B00B82964 /* ErrorHandler */,
CD4D59042B87B19100B82964 /* Notifier */,
CDA1E8262B90EF24007953EF /* AppFlow.swift */,
);
path = Definitions;
sourceTree = "<group>";
Expand Down Expand Up @@ -614,6 +633,14 @@
path = "Content Models";
sourceTree = "<group>";
};
CDEB38B22BED7CA30059FBA7 /* Settings */ = {
isa = PBXGroup;
children = (
CDEB38B32BED7CAE0059FBA7 /* SettingsView.swift */,
);
path = Settings;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXHeadersBuildPhase section */
Expand Down Expand Up @@ -821,14 +848,17 @@
CD1446272A5B36DA00610EF1 /* EULA.swift in Sources */,
CD4D58FF2B87B15700B82964 /* EquatableError.swift in Sources */,
CD4D58A52B86BD1B00B82964 /* PersistenceRepository.swift in Sources */,
CDEB38B42BED7CAE0059FBA7 /* SettingsView.swift in Sources */,
CD1446252A5B357900610EF1 /* Document.swift in Sources */,
CD4D58972B86BAD900B82964 /* EnvironmentValues+TabReselectionHashValue.swift in Sources */,
CD4D591C2B87B43D00B82964 /* Task+Extensions.swift in Sources */,
CD4D58AA2B86BE5900B82964 /* AccountListView.swift in Sources */,
CD4D58B92B86D9F800B82964 /* AccountButtonView.swift in Sources */,
CD4D58B32B86BFD400B82964 /* AccountsTracker.swift in Sources */,
CD317D4F2BE983ED008F63E2 /* MonochromePalette.swift in Sources */,
CD4D58B52B86BFFB00B82964 /* PersistenceRepository+Dependency.swift in Sources */,
CD4D58EB2B86E63300B82964 /* AssociatedColor.swift in Sources */,
CD317D4C2BE97FED008F63E2 /* Palette.swift in Sources */,
CD4D591A2B87B3D100B82964 /* ErrorHandler+Dependency.swift in Sources */,
03D3A1F32BB9D49B009DE55E /* ActionGroup.swift in Sources */,
CD4D58FD2B87B14D00B82964 /* ContextualError.swift in Sources */,
Expand Down Expand Up @@ -870,7 +900,7 @@
CD4D59202B87B63300B82964 /* SettingsOptions.swift in Sources */,
030FF67F2BC8544700F6BFAC /* CustomTabBarController.swift in Sources */,
CD4D58F82B87B0D100B82964 /* InternetSpeed.swift in Sources */,
CD4D58932B86BA5C00B82964 /* Colors.swift in Sources */,
CD4D58932B86BA5C00B82964 /* StandardPalette.swift in Sources */,
030FF6812BC859FD00F6BFAC /* CustomTabViewHostingController.swift in Sources */,
CD4D58AD2B86BE7100B82964 /* QuickSwitcherView.swift in Sources */,
6363D5C527EE196700E34822 /* MlemApp.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,22 @@
"revision" : "ecb18d8ce4d88277cc4fb103973352d91e18c535"
}
},
{
"identity" : "lemmymarkdownui",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mlemgroup/LemmyMarkdownUI",
"state" : {
"branch" : "main",
"revision" : "a5ef8e49e9db253afd49e9e38805fa2e89649b32"
}
},
{
"identity" : "mlemmiddleware",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mlemgroup/MlemMiddleware.git",
"state" : {
"branch" : "master",
"revision" : "82bae530b51ad208ae1fce11bab3276ec80c5b76"
"revision" : "3fc9bdebc74909dfdea2fcd51afb645d5d1ed2b6",
"version" : "0.1.0"
}
},
{
Expand Down
21 changes: 0 additions & 21 deletions Mlem/App/Constants/Colors.swift

This file was deleted.

23 changes: 23 additions & 0 deletions Mlem/App/Constants/Colors/MonochromePalette.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// MonochromePalette.swift
// Mlem
//
// Created by Eric Andrews on 2024-05-06.
//

import Foundation
import SwiftUI

extension ColorPalette {
static let monochrome: ColorPalette = .init(
primary: .primary,
background: Color(UIColor.systemBackground),
secondaryBackground: Color(UIColor.secondarySystemBackground),
tertiaryBackground: Color(UIColor.tertiarySystemBackground),
accent: .primary,
upvote: .primary,
downvote: .primary,
save: .primary,
selectedInteractionBarItem: Color(UIColor.systemBackground)
)
}
22 changes: 22 additions & 0 deletions Mlem/App/Constants/Colors/StandardPalette.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// DefaultColors.swift
// Mlem
//
// Created by Eric Andrews on 2024-05-06.
//

import SwiftUI

extension ColorPalette {
static let standard: ColorPalette = .init(
primary: .primary,
background: Color(UIColor.systemBackground),
secondaryBackground: Color(UIColor.secondarySystemBackground),
tertiaryBackground: Color(UIColor.tertiarySystemBackground),
accent: .accentColor,
upvote: .blue,
downvote: .red,
save: .green,
selectedInteractionBarItem: .white
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//
//

import Dependencies
import SwiftUI

/// A class responsible for displaying important notifications to the user
Expand Down Expand Up @@ -202,6 +203,8 @@ enum NotificationDisplayer {
/// A simple toast view
/// - Note: This view is private as it should only be created via the notification process
private struct Toast: View {
@Environment(Palette.self) var palette

enum Style {
case success
case error
Expand Down Expand Up @@ -242,7 +245,7 @@ private struct Toast: View {

@ViewBuilder
var background: some View {
Colors.secondarySystemBackground
palette.secondaryBackground
.clipShape(Capsule())
.overlay(Capsule().stroke(Color.gray.opacity(0.2), lineWidth: 1))
}
Expand Down
Loading

0 comments on commit 050053a

Please sign in to comment.