Skip to content

Commit

Permalink
Redesign Package Structure. Added BorderStyleModifier via BezierPathS…
Browse files Browse the repository at this point in the history
…hape (#19)

* Background Style

* Color Style

* Theme model and Background, Color Styles

* Re-design Package Structure. Added BorderStyleModifier via BezierPathShape

---------

Co-authored-by: PraveenP <ppraveetr@gmail.com>
  • Loading branch information
ppraveentr and PraveenP committed Oct 9, 2023
1 parent 5197267 commit b8a961d
Show file tree
Hide file tree
Showing 24 changed files with 552 additions and 89 deletions.
18 changes: 10 additions & 8 deletions ExampleApp/ExampleApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 55;
objectVersion = 56;
objects = {

/* Begin PBXBuildFile section */
Expand All @@ -12,7 +12,7 @@
DE00F3D328C457C3009C7AE5 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DE00F3D228C457C3009C7AE5 /* Preview Assets.xcassets */; };
DE28812228D566E6009E632C /* Theme.json in Resources */ = {isa = PBXBuildFile; fileRef = DE28812028D566E6009E632C /* Theme.json */; };
DE28812328D566E6009E632C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DE28812128D566E6009E632C /* Assets.xcassets */; };
DE4E0FE529D8A1FA00CD1AA8 /* MobileTheme in Frameworks */ = {isa = PBXBuildFile; productRef = DE4E0FE429D8A1FA00CD1AA8 /* MobileTheme */; };
DE99544229D9196D00F0C2A8 /* MobileTheme in Frameworks */ = {isa = PBXBuildFile; productRef = DE99544129D9196D00F0C2A8 /* MobileTheme */; };
DE9F65F328D6BB2C00DA9989 /* NavigationContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE9F65F228D6BB2C00DA9989 /* NavigationContentView.swift */; };
DED6F28728D6A88C00AB7E5D /* ExTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DED6F28628D6A88C00AB7E5D /* ExTextView.swift */; };
/* End PBXBuildFile section */
Expand All @@ -26,9 +26,9 @@
DE00F3FC28C48378009C7AE5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
DE28812028D566E6009E632C /* Theme.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Theme.json; sourceTree = "<group>"; };
DE28812128D566E6009E632C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
DE4E0FE329D8A14B00CD1AA8 /* MobileCore-SwiftUI */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "MobileCore-SwiftUI"; path = ..; sourceTree = "<group>"; };
DE4E0FE629D910FB00CD1AA8 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../../README.md; sourceTree = "<group>"; };
DE99543F29D9131800F0C2A8 /* ExampleApp.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = ExampleApp.xctestplan; sourceTree = "<group>"; };
DE99544029D9194200F0C2A8 /* MobileTheme */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = MobileTheme; path = ..; sourceTree = "<group>"; };
DE9F65F228D6BB2C00DA9989 /* NavigationContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationContentView.swift; sourceTree = "<group>"; };
DED6F28628D6A88C00AB7E5D /* ExTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExTextView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
Expand All @@ -38,7 +38,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
DE4E0FE529D8A1FA00CD1AA8 /* MobileTheme in Frameworks */,
DE99544229D9196D00F0C2A8 /* MobileTheme in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -90,7 +90,7 @@
DE00F3F628C457D5009C7AE5 /* Packages */ = {
isa = PBXGroup;
children = (
DE4E0FE329D8A14B00CD1AA8 /* MobileCore-SwiftUI */,
DE99544029D9194200F0C2A8 /* MobileTheme */,
);
name = Packages;
sourceTree = "<group>";
Expand Down Expand Up @@ -138,7 +138,7 @@
);
name = ExampleApp;
packageProductDependencies = (
DE4E0FE429D8A1FA00CD1AA8 /* MobileTheme */,
DE99544129D9196D00F0C2A8 /* MobileTheme */,
);
productName = ExampleApp;
productReference = DE00F3C828C457C1009C7AE5 /* ExampleApp.app */;
Expand All @@ -160,7 +160,7 @@
};
};
buildConfigurationList = DE00F3C328C457C1009C7AE5 /* Build configuration list for PBXProject "ExampleApp" */;
compatibilityVersion = "Xcode 13.0";
compatibilityVersion = "Xcode 14.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
Expand Down Expand Up @@ -357,6 +357,7 @@
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = ExampleApp/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
Expand Down Expand Up @@ -386,6 +387,7 @@
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = ExampleApp/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
Expand Down Expand Up @@ -424,7 +426,7 @@
/* End XCConfigurationList section */

/* Begin XCSwiftPackageProductDependency section */
DE4E0FE429D8A1FA00CD1AA8 /* MobileTheme */ = {
DE99544129D9196D00F0C2A8 /* MobileTheme */ = {
isa = XCSwiftPackageProductDependency;
productName = MobileTheme;
};
Expand Down
26 changes: 21 additions & 5 deletions ExampleApp/ExampleApp/Resources/Theme.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,35 @@
"version": "1.0",
"colors": {
"white": "#FFFFFF",
"red": "#EE4B2B",
"blue": "#004CFF"
"primayBlue": "#2673DD,,#EE2C4A",
"secondaryBlue": "#2673dd",
"red": "#EE2C4A,,#A82830",
"green": "#44CC77,,#309053",
"warning": "#FFBB00,,#B2B400",
"pink": "#F9DAE0,,#EC455B",
"whiteBackground": "#F0F2F5,,#121212",
"panel": "#FAFAFA,,#222222",
"border": "#E8E8E8,,#121212",
"black": "#000000,,#FFFFFF"
},
"fonts": {
"title": { "weight": "title" }
},
"styles": {
"TitleRW": {
"forgroundColor": {"light": "red", "dark": "white"},
"font": "title"
"forgroundColor": "black",
"font": "title",
"background": {
"color": "pink",
"border": {
"color": "green",
"radius": [10],
"thickness": 20
}
}
},
"BodyBR": {
"forgroundColor": {"light": "blue", "dark": "red"},
"forgroundColor": "primayBlue",
"font": "body"
}
}
Expand Down
6 changes: 3 additions & 3 deletions ExampleApp/ExampleApp/Views/ExTextView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
// Created by Praveen Prabhakar on 17/09/22.
//

import Core
import SwiftUI
import Theme

Expand All @@ -24,9 +23,10 @@ struct ExTextView: View {
.theme(Constants.themeFont)
Text("Font as 'title' in LightMode and 'headline' in DarkMode")
.theme(Constants.themeFont)
Text("'Red' in LightMode and 'White' in DarkMode")
Text("Text 'Black' in LightMode and 'White' in DarkMode")
.padding()
.style(Constants.rwTitleStyle)
Text("'Blue' in LightMode and 'Red' in DarkMode")
Text("Text 'Blue' in LightMode and 'Red' in DarkMode")
.style(Constants.brBodyStyle)
Spacer()
}
Expand Down
11 changes: 4 additions & 7 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,16 @@ import PackageDescription

let package = Package(
name: "MobileTheme",
platforms: [.iOS(.v13), .macOS(.v10_15)],
platforms: [.iOS(.v14), .macOS(.v11)],
products: [
.library(name: "MobileTheme", targets: ["Theme", "Core"])
.library(name: "MobileTheme", targets: ["Theme"])
],
dependencies: [
// .package(url: "https://github.com/apple/swift-docc-plugin", branch: "main")
],
targets: [
// Theme
.target(name: "Theme", dependencies: ["Core"]),
.testTarget(name: "ThemeTests", dependencies: ["Theme"]),
// Extensions
.target(name: "Core"),
.testTarget(name: "CoreTests", dependencies: ["Core"])
.target(name: "Theme"),
.testTarget(name: "ThemeTests", dependencies: ["Theme"])
]
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
import Foundation
import SwiftUI

public extension String {
func getColor() -> Color {
Color(hex: self)
}
}

public extension Color {
init(hex: String) {
let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// Data+Extension.swift
// Core
// Theme
//
// Created by Praveen Prabhakar on 16/09/22.
//
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// ColorSchemeValue.swift
// Core
// Theme
//
// Created by Praveen Prabhakar on 16/09/22.
//
Expand Down
20 changes: 20 additions & 0 deletions Sources/Theme/Models/RectCorner.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// RectCorner.swift
// Theme
//
// Created by Praveen P on 10/9/23.
//

import Foundation
import SwiftUI

struct RectCorner: OptionSet {
let rawValue: Int

static let topLeft = RectCorner(rawValue: 1 << 0)
static let topRight = RectCorner(rawValue: 1 << 1)
static let bottomRight = RectCorner(rawValue: 1 << 2)
static let bottomLeft = RectCorner(rawValue: 1 << 3)

static let allCorners: RectCorner = [.topLeft, topRight, .bottomLeft, .bottomRight]
}
60 changes: 60 additions & 0 deletions Sources/Theme/Models/ThemeJSONStructure.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// ThemeJSONStructure.swift
// Theme
//
// Created by Praveen Prabhakar on 16/09/22.
//

import Foundation
import SwiftUI

struct ThemeJSONStructure: Codable {
struct FontStyle: Codable {
var size: CGFloat?
/// Based on ``Font/Weight``
var weight: String?
/// Based on ``Font/TextStyle``
var styleName: String?
}

struct ColorStyle: Codable {
var light: String
var dark: String?
}

struct UserStyle: Codable {
var forgroundColor: String?
var font: String?
var background: BackgroundStyle?
}

struct BackgroundStyle: Codable {
var color: String?
var ignoringSafeArea: Bool?
var gradient: StyleGradient?
var border: StyleBorder?
}

struct StyleGradient: Codable {
var colors: [String]
var locations: [CGFloat]?
}

struct StyleBorder: Codable {
var radius: [CGFloat]?
var thickness: Int?
var color: String?

var borderColor: Color? {
color?.getColor()
}
}

var colors: [String: String]?
var fonts: [String: FontStyle]?
var styles: [String: UserStyle]?
}

enum Alignment: String, Codable {
case left, center, right
}
57 changes: 38 additions & 19 deletions Sources/Theme/Models/ThemeModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,31 @@
// Created by Praveen Prabhakar on 11/09/22.
//

import Core
import SwiftUI

public class ThemeModel {
var colors = [String: Color]()
var colors = [String: ColorSchemeValue<Color>]()
var fonts = [String: Font]()
var styles = [String: UserStyle]()

struct UserStyle {
var forgroundColor: ColorSchemeValue<Color>?
var backgroundColor: StyleBackground?
var font: ColorSchemeValue<Font>?
}

init(fcLight: Color? = nil, fcDark: Color? = nil, font: Font? = nil) {
if let fcLight = fcLight {
self.forgroundColor = ColorSchemeValue(fcLight, dark: fcDark)
}
if let fLight = font {
self.font = ColorSchemeValue(fLight, dark: nil)
}
}
struct StyleBackground {
var color: ColorSchemeValue<Color>?
var ignoringSafeArea: Bool?
var gradient: ThemeJSONStructure.StyleGradient?
var border: ThemeJSONStructure.StyleBorder?
}
}

/// Generate ``ThemeModel`` based on `json Data`
extension ThemeModel {
static func generateModel(_ jsonData: Data) throws -> ThemeModel {
let theme = try JSONDecoder().decode(ThemeStructure.self, from: jsonData)
let theme = try JSONDecoder().decode(ThemeJSONStructure.self, from: jsonData)
let model = ThemeModel()
// Generate Colors
theme.colors?.forEach { model.colors[$0] = Color.style($1) }
Expand All @@ -44,17 +42,30 @@ extension ThemeModel {

/// Generate ``ThemeModel/UserStyle`` based on ``ThemeStructure.UserStyle``
private static
func style(_ style: ThemeStructure.UserStyle, model: ThemeModel) -> UserStyle? {
let (fcLight, fcDark) = (model.colors[style.forgroundColor?.light ?? ""],
model.colors[style.forgroundColor?.dark ?? ""])
let font = model.fonts[style.font ?? ""]
return UserStyle(fcLight: fcLight, fcDark: fcDark, font: font)
func style(_ style: ThemeJSONStructure.UserStyle, model: ThemeModel) -> UserStyle? {
// Colors
let fgColor = model.colors[style.forgroundColor ?? ""]
let bgLight = model.colors[style.background?.color ?? ""]
// BackGround Style
let backgroundStyle = StyleBackground(
color: bgLight,
ignoringSafeArea: style.background?.ignoringSafeArea,
gradient: style.background?.gradient
)
// User Style Setup
var userStyleValue = UserStyle(forgroundColor: fgColor, backgroundColor: backgroundStyle)

// Fonts
if let font = model.fonts[style.font ?? ""] {
userStyleValue.font = ColorSchemeValue(font, dark: nil)
}
return userStyleValue
}
}

/// Generate ``Font`` based on ``ThemeStructure.FontStyle``
extension Font {
static func style(_ style: ThemeStructure.FontStyle) -> Font? {
static func style(_ style: ThemeJSONStructure.FontStyle) -> Font? {
/// Generate ``Font`` based on StyleName ``Font/TextStyle``
if let styleName = style.styleName,
let font = Font.fromStyleName(styleName: styleName) {
Expand All @@ -70,9 +81,17 @@ extension Font {

/// Generate ``Color`` based on `hex color`
extension Color {
static func style(_ name: String) -> Color? {
static func style(_ name: String) -> ColorSchemeValue<Color>? {
if name.hasPrefix("#") {
return Color(hex: name)
let colorNames = name.components(separatedBy: ",,")
guard let light = colorNames.first else {
return nil
}
var colors = ColorSchemeValue<Color>(Color(hex: light))
if let dark = colorNames.last {
colors.dark = Color(hex: dark)
}
return colors
}
return nil
}
Expand Down
Loading

0 comments on commit b8a961d

Please sign in to comment.