Repository: VIkill33/SwiftUI-ContributionChart
Branch: main
Commit: 1a5456abe211
Files: 18
Total size: 40.0 KB
Directory structure:
gitextract_at9suabs/
├── .gitignore
├── .swiftpm/
│ └── xcode/
│ └── package.xcworkspace/
│ └── xcshareddata/
│ └── IDEWorkspaceChecks.plist
├── DemoApp/
│ └── DemoApp/
│ ├── DemoApp/
│ │ ├── Assets.xcassets/
│ │ │ ├── AccentColor.colorset/
│ │ │ │ └── Contents.json
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── ContentView.swift
│ │ ├── DemoAppApp.swift
│ │ └── Preview Content/
│ │ └── Preview Assets.xcassets/
│ │ └── Contents.json
│ ├── DemoApp.xcodeproj/
│ │ ├── project.pbxproj
│ │ └── project.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ └── IDEWorkspaceChecks.plist
│ ├── DemoAppTests/
│ │ └── DemoAppTests.swift
│ └── DemoAppUITests/
│ ├── DemoAppUITests.swift
│ └── DemoAppUITestsLaunchTests.swift
├── Package.swift
├── README.md
└── Sources/
└── ContributionChart/
├── ContributionChartTest.swift
└── ContributionChartView.swift
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
================================================
FILE: .swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
IDEDidComputeMac32BitWarning
================================================
FILE: DemoApp/DemoApp/DemoApp/Assets.xcassets/AccentColor.colorset/Contents.json
================================================
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: DemoApp/DemoApp/DemoApp/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: DemoApp/DemoApp/DemoApp/Assets.xcassets/Contents.json
================================================
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: DemoApp/DemoApp/DemoApp/ContentView.swift
================================================
//
// ContentView.swift
// DemoApp
//
// Created by Qu Tian on 2024/7/31.
//
import SwiftUI
import ContributionChart
struct ContentView: View {
@State private var data = [0.87, 0.17, 0.6, 0.21, 0.88, 0.41, 0.37, 0.39, 0.34, 0.91, 0.45, 0.51, 0.1, 0.97, 0.32, 0.72, 0.15, 0.2, 0.87, 0.86, 0.35, 0.12, 0.77, 0.56]
var body: some View {
RecordBlock {
ContributionChartView(data: data, rows: 3, columns: 8, targetValue: 1.0)
}
.frame(width: 210, height: 95)
.padding()
}
}
fileprivate struct RecordBlock: View {
@ViewBuilder var content:Content
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 16)
.fill(Color.white)
.shadow(color: Color.black.opacity(0.3), radius: 16.0, y: 16.0)
content
}
}
}
#Preview {
ContentView()
}
================================================
FILE: DemoApp/DemoApp/DemoApp/DemoAppApp.swift
================================================
//
// DemoAppApp.swift
// DemoApp
//
// Created by Qu Tian on 2024/7/31.
//
import SwiftUI
@main
struct DemoAppApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
================================================
FILE: DemoApp/DemoApp/DemoApp/Preview Content/Preview Assets.xcassets/Contents.json
================================================
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: DemoApp/DemoApp/DemoApp.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 56;
objects = {
/* Begin PBXBuildFile section */
C00592122C59D22F00FAE9E2 /* DemoAppApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C00592112C59D22F00FAE9E2 /* DemoAppApp.swift */; };
C00592142C59D22F00FAE9E2 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C00592132C59D22F00FAE9E2 /* ContentView.swift */; };
C00592162C59D23000FAE9E2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C00592152C59D23000FAE9E2 /* Assets.xcassets */; };
C00592192C59D23000FAE9E2 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C00592182C59D23000FAE9E2 /* Preview Assets.xcassets */; };
C00592232C59D23100FAE9E2 /* DemoAppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C00592222C59D23100FAE9E2 /* DemoAppTests.swift */; };
C005922D2C59D23100FAE9E2 /* DemoAppUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C005922C2C59D23100FAE9E2 /* DemoAppUITests.swift */; };
C005922F2C59D23100FAE9E2 /* DemoAppUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C005922E2C59D23100FAE9E2 /* DemoAppUITestsLaunchTests.swift */; };
C005923E2C59D5BC00FAE9E2 /* ContributionChart in Frameworks */ = {isa = PBXBuildFile; productRef = C005923D2C59D5BC00FAE9E2 /* ContributionChart */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
C005921F2C59D23000FAE9E2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = C00592062C59D22F00FAE9E2 /* Project object */;
proxyType = 1;
remoteGlobalIDString = C005920D2C59D22F00FAE9E2;
remoteInfo = DemoApp;
};
C00592292C59D23100FAE9E2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = C00592062C59D22F00FAE9E2 /* Project object */;
proxyType = 1;
remoteGlobalIDString = C005920D2C59D22F00FAE9E2;
remoteInfo = DemoApp;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
C005920E2C59D22F00FAE9E2 /* DemoApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DemoApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
C00592112C59D22F00FAE9E2 /* DemoAppApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoAppApp.swift; sourceTree = ""; };
C00592132C59D22F00FAE9E2 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
C00592152C59D23000FAE9E2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
C00592182C59D23000FAE9E2 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
C005921E2C59D23000FAE9E2 /* DemoAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DemoAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
C00592222C59D23100FAE9E2 /* DemoAppTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoAppTests.swift; sourceTree = ""; };
C00592282C59D23100FAE9E2 /* DemoAppUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DemoAppUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
C005922C2C59D23100FAE9E2 /* DemoAppUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoAppUITests.swift; sourceTree = ""; };
C005922E2C59D23100FAE9E2 /* DemoAppUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoAppUITestsLaunchTests.swift; sourceTree = ""; };
C005923C2C59D57200FAE9E2 /* SwiftUI-ContributionChart */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "SwiftUI-ContributionChart"; path = ../..; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
C005920B2C59D22F00FAE9E2 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C005923E2C59D5BC00FAE9E2 /* ContributionChart in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
C005921B2C59D23000FAE9E2 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
C00592252C59D23100FAE9E2 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
C00592052C59D22F00FAE9E2 = {
isa = PBXGroup;
children = (
C00592102C59D22F00FAE9E2 /* DemoApp */,
C00592212C59D23100FAE9E2 /* DemoAppTests */,
C005922B2C59D23100FAE9E2 /* DemoAppUITests */,
C005920F2C59D22F00FAE9E2 /* Products */,
C005923B2C59D57200FAE9E2 /* Frameworks */,
);
sourceTree = "";
};
C005920F2C59D22F00FAE9E2 /* Products */ = {
isa = PBXGroup;
children = (
C005920E2C59D22F00FAE9E2 /* DemoApp.app */,
C005921E2C59D23000FAE9E2 /* DemoAppTests.xctest */,
C00592282C59D23100FAE9E2 /* DemoAppUITests.xctest */,
);
name = Products;
sourceTree = "";
};
C00592102C59D22F00FAE9E2 /* DemoApp */ = {
isa = PBXGroup;
children = (
C00592112C59D22F00FAE9E2 /* DemoAppApp.swift */,
C00592132C59D22F00FAE9E2 /* ContentView.swift */,
C00592152C59D23000FAE9E2 /* Assets.xcassets */,
C00592172C59D23000FAE9E2 /* Preview Content */,
);
path = DemoApp;
sourceTree = "";
};
C00592172C59D23000FAE9E2 /* Preview Content */ = {
isa = PBXGroup;
children = (
C00592182C59D23000FAE9E2 /* Preview Assets.xcassets */,
);
path = "Preview Content";
sourceTree = "";
};
C00592212C59D23100FAE9E2 /* DemoAppTests */ = {
isa = PBXGroup;
children = (
C00592222C59D23100FAE9E2 /* DemoAppTests.swift */,
);
path = DemoAppTests;
sourceTree = "";
};
C005922B2C59D23100FAE9E2 /* DemoAppUITests */ = {
isa = PBXGroup;
children = (
C005922C2C59D23100FAE9E2 /* DemoAppUITests.swift */,
C005922E2C59D23100FAE9E2 /* DemoAppUITestsLaunchTests.swift */,
);
path = DemoAppUITests;
sourceTree = "";
};
C005923B2C59D57200FAE9E2 /* Frameworks */ = {
isa = PBXGroup;
children = (
C005923C2C59D57200FAE9E2 /* SwiftUI-ContributionChart */,
);
name = Frameworks;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
C005920D2C59D22F00FAE9E2 /* DemoApp */ = {
isa = PBXNativeTarget;
buildConfigurationList = C00592322C59D23100FAE9E2 /* Build configuration list for PBXNativeTarget "DemoApp" */;
buildPhases = (
C005920A2C59D22F00FAE9E2 /* Sources */,
C005920B2C59D22F00FAE9E2 /* Frameworks */,
C005920C2C59D22F00FAE9E2 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = DemoApp;
packageProductDependencies = (
C005923D2C59D5BC00FAE9E2 /* ContributionChart */,
);
productName = DemoApp;
productReference = C005920E2C59D22F00FAE9E2 /* DemoApp.app */;
productType = "com.apple.product-type.application";
};
C005921D2C59D23000FAE9E2 /* DemoAppTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = C00592352C59D23100FAE9E2 /* Build configuration list for PBXNativeTarget "DemoAppTests" */;
buildPhases = (
C005921A2C59D23000FAE9E2 /* Sources */,
C005921B2C59D23000FAE9E2 /* Frameworks */,
C005921C2C59D23000FAE9E2 /* Resources */,
);
buildRules = (
);
dependencies = (
C00592202C59D23000FAE9E2 /* PBXTargetDependency */,
);
name = DemoAppTests;
productName = DemoAppTests;
productReference = C005921E2C59D23000FAE9E2 /* DemoAppTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
C00592272C59D23100FAE9E2 /* DemoAppUITests */ = {
isa = PBXNativeTarget;
buildConfigurationList = C00592382C59D23100FAE9E2 /* Build configuration list for PBXNativeTarget "DemoAppUITests" */;
buildPhases = (
C00592242C59D23100FAE9E2 /* Sources */,
C00592252C59D23100FAE9E2 /* Frameworks */,
C00592262C59D23100FAE9E2 /* Resources */,
);
buildRules = (
);
dependencies = (
C005922A2C59D23100FAE9E2 /* PBXTargetDependency */,
);
name = DemoAppUITests;
productName = DemoAppUITests;
productReference = C00592282C59D23100FAE9E2 /* DemoAppUITests.xctest */;
productType = "com.apple.product-type.bundle.ui-testing";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
C00592062C59D22F00FAE9E2 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1540;
LastUpgradeCheck = 1540;
TargetAttributes = {
C005920D2C59D22F00FAE9E2 = {
CreatedOnToolsVersion = 15.4;
};
C005921D2C59D23000FAE9E2 = {
CreatedOnToolsVersion = 15.4;
TestTargetID = C005920D2C59D22F00FAE9E2;
};
C00592272C59D23100FAE9E2 = {
CreatedOnToolsVersion = 15.4;
TestTargetID = C005920D2C59D22F00FAE9E2;
};
};
};
buildConfigurationList = C00592092C59D22F00FAE9E2 /* Build configuration list for PBXProject "DemoApp" */;
compatibilityVersion = "Xcode 14.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = C00592052C59D22F00FAE9E2;
productRefGroup = C005920F2C59D22F00FAE9E2 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
C005920D2C59D22F00FAE9E2 /* DemoApp */,
C005921D2C59D23000FAE9E2 /* DemoAppTests */,
C00592272C59D23100FAE9E2 /* DemoAppUITests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
C005920C2C59D22F00FAE9E2 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C00592192C59D23000FAE9E2 /* Preview Assets.xcassets in Resources */,
C00592162C59D23000FAE9E2 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
C005921C2C59D23000FAE9E2 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
C00592262C59D23100FAE9E2 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
C005920A2C59D22F00FAE9E2 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C00592142C59D22F00FAE9E2 /* ContentView.swift in Sources */,
C00592122C59D22F00FAE9E2 /* DemoAppApp.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
C005921A2C59D23000FAE9E2 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C00592232C59D23100FAE9E2 /* DemoAppTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
C00592242C59D23100FAE9E2 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C005922D2C59D23100FAE9E2 /* DemoAppUITests.swift in Sources */,
C005922F2C59D23100FAE9E2 /* DemoAppUITestsLaunchTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
C00592202C59D23000FAE9E2 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = C005920D2C59D22F00FAE9E2 /* DemoApp */;
targetProxy = C005921F2C59D23000FAE9E2 /* PBXContainerItemProxy */;
};
C005922A2C59D23100FAE9E2 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = C005920D2C59D22F00FAE9E2 /* DemoApp */;
targetProxy = C00592292C59D23100FAE9E2 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
C00592302C59D23100FAE9E2 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 17.5;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
C00592312C59D23100FAE9E2 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 17.5;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
C00592332C59D23100FAE9E2 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"DemoApp/Preview Content\"";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.qutian.DemoApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
C00592342C59D23100FAE9E2 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"DemoApp/Preview Content\"";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.qutian.DemoApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
C00592362C59D23100FAE9E2 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 17.5;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.qutian.DemoAppTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DemoApp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/DemoApp";
};
name = Debug;
};
C00592372C59D23100FAE9E2 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 17.5;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.qutian.DemoAppTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DemoApp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/DemoApp";
};
name = Release;
};
C00592392C59D23100FAE9E2 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.qutian.DemoAppUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_TARGET_NAME = DemoApp;
};
name = Debug;
};
C005923A2C59D23100FAE9E2 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.qutian.DemoAppUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_TARGET_NAME = DemoApp;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
C00592092C59D22F00FAE9E2 /* Build configuration list for PBXProject "DemoApp" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C00592302C59D23100FAE9E2 /* Debug */,
C00592312C59D23100FAE9E2 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
C00592322C59D23100FAE9E2 /* Build configuration list for PBXNativeTarget "DemoApp" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C00592332C59D23100FAE9E2 /* Debug */,
C00592342C59D23100FAE9E2 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
C00592352C59D23100FAE9E2 /* Build configuration list for PBXNativeTarget "DemoAppTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C00592362C59D23100FAE9E2 /* Debug */,
C00592372C59D23100FAE9E2 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
C00592382C59D23100FAE9E2 /* Build configuration list for PBXNativeTarget "DemoAppUITests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C00592392C59D23100FAE9E2 /* Debug */,
C005923A2C59D23100FAE9E2 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCSwiftPackageProductDependency section */
C005923D2C59D5BC00FAE9E2 /* ContributionChart */ = {
isa = XCSwiftPackageProductDependency;
productName = ContributionChart;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = C00592062C59D22F00FAE9E2 /* Project object */;
}
================================================
FILE: DemoApp/DemoApp/DemoApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: DemoApp/DemoApp/DemoApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
IDEDidComputeMac32BitWarning
================================================
FILE: DemoApp/DemoApp/DemoAppTests/DemoAppTests.swift
================================================
//
// DemoAppTests.swift
// DemoAppTests
//
// Created by Qu Tian on 2024/7/31.
//
import XCTest
@testable import DemoApp
final class DemoAppTests: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
// Any test you write for XCTest can be annotated as throws and async.
// Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
// Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
}
func testPerformanceExample() throws {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
}
================================================
FILE: DemoApp/DemoApp/DemoAppUITests/DemoAppUITests.swift
================================================
//
// DemoAppUITests.swift
// DemoAppUITests
//
// Created by Qu Tian on 2024/7/31.
//
import XCTest
final class DemoAppUITests: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
// In UI tests it is usually best to stop immediately when a failure occurs.
continueAfterFailure = false
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
}
override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testExample() throws {
// UI tests must launch the application that they test.
let app = XCUIApplication()
app.launch()
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
func testLaunchPerformance() throws {
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
// This measures how long it takes to launch your application.
measure(metrics: [XCTApplicationLaunchMetric()]) {
XCUIApplication().launch()
}
}
}
}
================================================
FILE: DemoApp/DemoApp/DemoAppUITests/DemoAppUITestsLaunchTests.swift
================================================
//
// DemoAppUITestsLaunchTests.swift
// DemoAppUITests
//
// Created by Qu Tian on 2024/7/31.
//
import XCTest
final class DemoAppUITestsLaunchTests: XCTestCase {
override class var runsForEachTargetApplicationUIConfiguration: Bool {
true
}
override func setUpWithError() throws {
continueAfterFailure = false
}
func testLaunch() throws {
let app = XCUIApplication()
app.launch()
// Insert steps here to perform after app launch but before taking a screenshot,
// such as logging into a test account or navigating somewhere in the app
let attachment = XCTAttachment(screenshot: app.screenshot())
attachment.name = "Launch Screen"
attachment.lifetime = .keepAlways
add(attachment)
}
}
================================================
FILE: Package.swift
================================================
// swift-tools-version: 5.6
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "ContributionChart",
platforms: [
.iOS(.v13), .macOS(.v10_15), .tvOS(.v13), .watchOS(.v6)
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "ContributionChart",
targets: ["ContributionChart"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "ContributionChart",
dependencies: [])
]
)
================================================
FILE: README.md
================================================
# ContributionChart
A contribution chart (aka. heatmap, GitHub-like) library for iOS, macOS, and watchOS.
100% written in SwiftUI.


- [It Supports](#it-supports)
* [Custom Block Number](#custom-block-number)
* [Custom Block Color](#custom-block-color)
* [Dark mode](#dark-mode)
- [Installation](#installation)
- [Usage](#usage)
- [Demo Code](#demo-code)
Updates
- 7/31/24 Support input array with any length and add a demo app inside.
# It Supports
## Custom Block Number
Of course, you can also custom the **size** of blocks and **spacing** between blocks.
## Custom Block Color
Here are examples using **system colors** as below, and you can custom any color you like.
## Dark mode
Adjust to dark mode color automatically.
# Installation
Require iOS 13, macOS 10.15, watchOS 6 and Xcode 11 or higher.
In Xcode go to `File -> Swift Packages -> Add Package Dependency`
and paste in the repo's url:
`https://github.com/VIkill33/SwiftUI-ContributionChart.git`
Or you can download the code of this repo, then `Add Local...` in Xcode, and open the folder of the repo.
# Usage
- Import this package after you installed by `import ContributionChart`
- Use the chart like
```swift
ContributionChartView(data: yourData,
rows: yourRows,
columns: yourColumns,
targetValue: yourTargetValue,
blockColor: .green)
```
yourData is (**a double array**), and the targetValue is recommanded to set to the max value of the array.
The color of a block will appear as exactly the color as parameter `blockColor` when its value is equal to `targetValue`, and appears light gray when is equal to zero.
The top-Leading block represents the first value in array, while the bottom-trailing represents the last. And the order follows as below:
# Demo Code
```swift
import SwiftUI
import ContributionChart
struct ContentView: View {
var data: [Double]
let rows = 7
let columns = 14
init() {
data = [0.3, 0.4, 0.4, 0.4, 0.1, 0.5, 0.0, 0.1, 0.0, 0.2, 0.2, 0.2, 0.0, 0.2, 0.2, 0.5, 0.4, 0.2, 0.4, 0.5, 0.2, 0.2, 0.4, 0.3, 0.3, 0.2, 0.4, 0.0, 0.0, 0.5, 0.4, 0.3, 0.5, 0.3, 0.0, 0.0, 0.1, 0.0, 0.2, 0.3, 0.0, 0.0, 0.0, 0.5, 0.3, 0.3, 0.0, 0.3, 0.0, 0.5, 0.3, 0.3, 0.4, 0.5, 0.5, 0.3, 0.4, 0.1, 0.4, 0.2, 0.5, 0.1, 0.4, 0.2, 0.5, 0.4, 0.3, 0.5, 0.0, 0.4, 0.3, 0.2, 0.1, 0.5, 0.2, 0.0, 0.2, 0.5, 0.5, 0.3, 0.4, 0.0, 0.3, 0.3, 0.1, 0.2, 0.5, 0.2, 0.1, 0.4, 0.4, 0.0, 0.5, 0.3, 0.3, 0.5, 0.0, 0.2]
}
var body: some View {
ContributionChartView(data: data,
rows: rows,
columns: columns,
targetValue: 0.5,
blockColor: .green)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
```
================================================
FILE: Sources/ContributionChart/ContributionChartTest.swift
================================================
//
// SwiftUIView.swift
//
//
// Created by Vikill Blacks on 2023/2/2.
//
import SwiftUI
struct SwiftUIView: View {
var body: some View {
ContributionChartView(data: [0,3,4,2,4,2,5,1,3], rows: 3, columns: 3, targetValue: 5, RectangleRadius: 2.0)
}
}
struct SwiftUIView_Previews: PreviewProvider {
static var previews: some View {
SwiftUIView()
//.preferredColorScheme(.dark)
}
}
================================================
FILE: Sources/ContributionChart/ContributionChartView.swift
================================================
import SwiftUI
@available(iOS 13, macOS 10.15, watchOS 6, *)
public struct ContributionChartView: View {
var data: [Double]
var rows: Int
var columns: Int
var targetValue: Double
var blockColor: Color = Color.green
var blockBackgroundColor: Color = Color.background
var heatMapRectangleWidth: Double = 20.0
var heatMapRectangleSpacing: Double = 2.0
var heatMapRectangleRadius: Double = 5.0
public init(data: [Double], rows: Int, columns: Int, targetValue: Double, blockColor: Color = Color.green, blockBackgroundColor: Color, RectangleWidth: Double = 20.0, RectangleSpacing: Double = 2.0, RectangleRadius: Double = 5.0){
self.data = data
self.rows = rows
self.columns = columns
self.targetValue = targetValue
self.blockColor = blockColor
self.blockBackgroundColor = blockBackgroundColor
self.heatMapRectangleWidth = RectangleWidth
self.heatMapRectangleSpacing = RectangleSpacing
self.heatMapRectangleRadius = RectangleRadius
}
public init(data: [Double], rows: Int, columns: Int, targetValue: Double, blockColor: Color = Color.green, RectangleWidth: Double = 20.0, RectangleSpacing: Double = 2.0, RectangleRadius: Double = 5.0){
self.data = data
self.rows = rows
self.columns = columns
if data.count < rows * columns {
let elementsToAdd = Array(repeating: 0.0, count: rows * columns - data.count)
self.data.append(contentsOf: elementsToAdd)
}
self.targetValue = targetValue
self.blockColor = blockColor
self.heatMapRectangleWidth = RectangleWidth
self.heatMapRectangleSpacing = RectangleSpacing
self.heatMapRectangleRadius = RectangleRadius
}
public var body: some View {
VStack {
// Chart
GeometryReader { geo in
ZStack {
HStack(spacing: heatMapRectangleSpacing) {
ForEach(0.. Double {
let opacityRatio: Double = Double(rowData[index]) / Double(targetValue)
return opacityRatio > 1.0 ? 1.0 : opacityRatio
}
}
extension Color {
init(hexString: String) {
let hex = hexString.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
var int = UInt64()
Scanner(string: hex).scanHexInt64(&int)
let r, g, b: UInt64
switch hex.count {
case 3: // RGB (12-bit)
(r, g, b) = ((int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
case 6: // RGB (24-bit)
(r, g, b) = (int >> 16, int >> 8 & 0xFF, int & 0xFF)
case 8: // ARGB (32-bit)
(r, g, b) = (int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
default:
(r, g, b) = (0, 0, 0)
}
self.init(red: Double(r) / 255, green: Double(g) / 255, blue: Double(b) / 255)
}
#if os(macOS)
static let background = Color(NSColor.windowBackgroundColor)
static let secondaryBackground = Color(NSColor.underPageBackgroundColor)
static let tertiaryBackground = Color(NSColor.controlBackgroundColor)
#endif
#if os(iOS)
static let background = Color(UIColor.systemBackground)
static let secondaryBackground = Color(UIColor.secondarySystemBackground)
static let tertiaryBackground = Color(UIColor.tertiarySystemBackground)
#endif
#if os(watchOS)
static let background = Color.black
#endif
}