Init Gitea
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
||||
## User settings
|
||||
xcuserdata/
|
||||
|
||||
.DS_Store
|
||||
|
||||
BIN
etc/v-browser.png
Normal file
|
After Width: | Height: | Size: 865 KiB |
629
v-browser.xcodeproj/project.pbxproj
Normal file
@@ -0,0 +1,629 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 56;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
2550BFAA2C9AF8140033B562 /* VectorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2550BFA92C9AF80A0033B562 /* VectorManager.swift */; };
|
||||
2550BFAD2C9AFFFA0033B562 /* SimilaritySearchKit in Frameworks */ = {isa = PBXBuildFile; productRef = 2550BFAC2C9AFFFA0033B562 /* SimilaritySearchKit */; };
|
||||
DE4D74282C8D65BD0072A4A7 /* v_browserApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4D74272C8D65BD0072A4A7 /* v_browserApp.swift */; };
|
||||
DE4D742A2C8D65BD0072A4A7 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4D74292C8D65BD0072A4A7 /* ContentView.swift */; };
|
||||
DE4D742C2C8D65BF0072A4A7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DE4D742B2C8D65BF0072A4A7 /* Assets.xcassets */; };
|
||||
DE4D742F2C8D65BF0072A4A7 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DE4D742E2C8D65BF0072A4A7 /* Preview Assets.xcassets */; };
|
||||
DE4D743A2C8D65BF0072A4A7 /* v_browserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4D74392C8D65BF0072A4A7 /* v_browserTests.swift */; };
|
||||
DE4D74442C8D65BF0072A4A7 /* v_browserUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4D74432C8D65BF0072A4A7 /* v_browserUITests.swift */; };
|
||||
DE4D74462C8D65BF0072A4A7 /* v_browserUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4D74452C8D65BF0072A4A7 /* v_browserUITestsLaunchTests.swift */; };
|
||||
DE4D74532C8D6F860072A4A7 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE4D74522C8D6F860072A4A7 /* Logger.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
DE4D74362C8D65BF0072A4A7 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = DE4D741C2C8D65BD0072A4A7 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = DE4D74232C8D65BD0072A4A7;
|
||||
remoteInfo = "v-browser";
|
||||
};
|
||||
DE4D74402C8D65BF0072A4A7 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = DE4D741C2C8D65BD0072A4A7 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = DE4D74232C8D65BD0072A4A7;
|
||||
remoteInfo = "v-browser";
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
2550BFA92C9AF80A0033B562 /* VectorManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VectorManager.swift; sourceTree = "<group>"; };
|
||||
DE4D74242C8D65BD0072A4A7 /* v-browser.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "v-browser.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DE4D74272C8D65BD0072A4A7 /* v_browserApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = v_browserApp.swift; sourceTree = "<group>"; };
|
||||
DE4D74292C8D65BD0072A4A7 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
DE4D742B2C8D65BF0072A4A7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
DE4D742E2C8D65BF0072A4A7 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||
DE4D74302C8D65BF0072A4A7 /* v_browser.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = v_browser.entitlements; sourceTree = "<group>"; };
|
||||
DE4D74352C8D65BF0072A4A7 /* v-browserTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "v-browserTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DE4D74392C8D65BF0072A4A7 /* v_browserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = v_browserTests.swift; sourceTree = "<group>"; };
|
||||
DE4D743F2C8D65BF0072A4A7 /* v-browserUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "v-browserUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DE4D74432C8D65BF0072A4A7 /* v_browserUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = v_browserUITests.swift; sourceTree = "<group>"; };
|
||||
DE4D74452C8D65BF0072A4A7 /* v_browserUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = v_browserUITestsLaunchTests.swift; sourceTree = "<group>"; };
|
||||
DE4D74522C8D6F860072A4A7 /* Logger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
DE4D74212C8D65BD0072A4A7 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2550BFAD2C9AFFFA0033B562 /* SimilaritySearchKit in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DE4D74322C8D65BF0072A4A7 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DE4D743C2C8D65BF0072A4A7 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
DE4D741B2C8D65BD0072A4A7 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DE4D74262C8D65BD0072A4A7 /* v-browser */,
|
||||
DE4D74382C8D65BF0072A4A7 /* v-browserTests */,
|
||||
DE4D74422C8D65BF0072A4A7 /* v-browserUITests */,
|
||||
DE4D74252C8D65BD0072A4A7 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DE4D74252C8D65BD0072A4A7 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DE4D74242C8D65BD0072A4A7 /* v-browser.app */,
|
||||
DE4D74352C8D65BF0072A4A7 /* v-browserTests.xctest */,
|
||||
DE4D743F2C8D65BF0072A4A7 /* v-browserUITests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DE4D74262C8D65BD0072A4A7 /* v-browser */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2550BFA92C9AF80A0033B562 /* VectorManager.swift */,
|
||||
DE4D74522C8D6F860072A4A7 /* Logger.swift */,
|
||||
DE4D74272C8D65BD0072A4A7 /* v_browserApp.swift */,
|
||||
DE4D74292C8D65BD0072A4A7 /* ContentView.swift */,
|
||||
DE4D742B2C8D65BF0072A4A7 /* Assets.xcassets */,
|
||||
DE4D74302C8D65BF0072A4A7 /* v_browser.entitlements */,
|
||||
DE4D742D2C8D65BF0072A4A7 /* Preview Content */,
|
||||
);
|
||||
path = "v-browser";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DE4D742D2C8D65BF0072A4A7 /* Preview Content */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DE4D742E2C8D65BF0072A4A7 /* Preview Assets.xcassets */,
|
||||
);
|
||||
path = "Preview Content";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DE4D74382C8D65BF0072A4A7 /* v-browserTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DE4D74392C8D65BF0072A4A7 /* v_browserTests.swift */,
|
||||
);
|
||||
path = "v-browserTests";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DE4D74422C8D65BF0072A4A7 /* v-browserUITests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DE4D74432C8D65BF0072A4A7 /* v_browserUITests.swift */,
|
||||
DE4D74452C8D65BF0072A4A7 /* v_browserUITestsLaunchTests.swift */,
|
||||
);
|
||||
path = "v-browserUITests";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
DE4D74232C8D65BD0072A4A7 /* v-browser */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = DE4D74492C8D65BF0072A4A7 /* Build configuration list for PBXNativeTarget "v-browser" */;
|
||||
buildPhases = (
|
||||
DE4D74202C8D65BD0072A4A7 /* Sources */,
|
||||
DE4D74212C8D65BD0072A4A7 /* Frameworks */,
|
||||
DE4D74222C8D65BD0072A4A7 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "v-browser";
|
||||
packageProductDependencies = (
|
||||
2550BFAC2C9AFFFA0033B562 /* SimilaritySearchKit */,
|
||||
);
|
||||
productName = "v-browser";
|
||||
productReference = DE4D74242C8D65BD0072A4A7 /* v-browser.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
DE4D74342C8D65BF0072A4A7 /* v-browserTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = DE4D744C2C8D65BF0072A4A7 /* Build configuration list for PBXNativeTarget "v-browserTests" */;
|
||||
buildPhases = (
|
||||
DE4D74312C8D65BF0072A4A7 /* Sources */,
|
||||
DE4D74322C8D65BF0072A4A7 /* Frameworks */,
|
||||
DE4D74332C8D65BF0072A4A7 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
DE4D74372C8D65BF0072A4A7 /* PBXTargetDependency */,
|
||||
);
|
||||
name = "v-browserTests";
|
||||
productName = "v-browserTests";
|
||||
productReference = DE4D74352C8D65BF0072A4A7 /* v-browserTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
DE4D743E2C8D65BF0072A4A7 /* v-browserUITests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = DE4D744F2C8D65BF0072A4A7 /* Build configuration list for PBXNativeTarget "v-browserUITests" */;
|
||||
buildPhases = (
|
||||
DE4D743B2C8D65BF0072A4A7 /* Sources */,
|
||||
DE4D743C2C8D65BF0072A4A7 /* Frameworks */,
|
||||
DE4D743D2C8D65BF0072A4A7 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
DE4D74412C8D65BF0072A4A7 /* PBXTargetDependency */,
|
||||
);
|
||||
name = "v-browserUITests";
|
||||
productName = "v-browserUITests";
|
||||
productReference = DE4D743F2C8D65BF0072A4A7 /* v-browserUITests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.ui-testing";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
DE4D741C2C8D65BD0072A4A7 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = 1;
|
||||
LastSwiftUpdateCheck = 1540;
|
||||
LastUpgradeCheck = 1600;
|
||||
TargetAttributes = {
|
||||
DE4D74232C8D65BD0072A4A7 = {
|
||||
CreatedOnToolsVersion = 15.4;
|
||||
};
|
||||
DE4D74342C8D65BF0072A4A7 = {
|
||||
CreatedOnToolsVersion = 15.4;
|
||||
TestTargetID = DE4D74232C8D65BD0072A4A7;
|
||||
};
|
||||
DE4D743E2C8D65BF0072A4A7 = {
|
||||
CreatedOnToolsVersion = 15.4;
|
||||
TestTargetID = DE4D74232C8D65BD0072A4A7;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = DE4D741F2C8D65BD0072A4A7 /* Build configuration list for PBXProject "v-browser" */;
|
||||
compatibilityVersion = "Xcode 14.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = DE4D741B2C8D65BD0072A4A7;
|
||||
packageReferences = (
|
||||
2550BFAB2C9AFFFA0033B562 /* XCRemoteSwiftPackageReference "similarity-search-kit" */,
|
||||
);
|
||||
productRefGroup = DE4D74252C8D65BD0072A4A7 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
DE4D74232C8D65BD0072A4A7 /* v-browser */,
|
||||
DE4D74342C8D65BF0072A4A7 /* v-browserTests */,
|
||||
DE4D743E2C8D65BF0072A4A7 /* v-browserUITests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
DE4D74222C8D65BD0072A4A7 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DE4D742F2C8D65BF0072A4A7 /* Preview Assets.xcassets in Resources */,
|
||||
DE4D742C2C8D65BF0072A4A7 /* Assets.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DE4D74332C8D65BF0072A4A7 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DE4D743D2C8D65BF0072A4A7 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
DE4D74202C8D65BD0072A4A7 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DE4D742A2C8D65BD0072A4A7 /* ContentView.swift in Sources */,
|
||||
2550BFAA2C9AF8140033B562 /* VectorManager.swift in Sources */,
|
||||
DE4D74532C8D6F860072A4A7 /* Logger.swift in Sources */,
|
||||
DE4D74282C8D65BD0072A4A7 /* v_browserApp.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DE4D74312C8D65BF0072A4A7 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DE4D743A2C8D65BF0072A4A7 /* v_browserTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DE4D743B2C8D65BF0072A4A7 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DE4D74462C8D65BF0072A4A7 /* v_browserUITestsLaunchTests.swift in Sources */,
|
||||
DE4D74442C8D65BF0072A4A7 /* v_browserUITests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
DE4D74372C8D65BF0072A4A7 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = DE4D74232C8D65BD0072A4A7 /* v-browser */;
|
||||
targetProxy = DE4D74362C8D65BF0072A4A7 /* PBXContainerItemProxy */;
|
||||
};
|
||||
DE4D74412C8D65BF0072A4A7 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = DE4D74232C8D65BD0072A4A7 /* v-browser */;
|
||||
targetProxy = DE4D74402C8D65BF0072A4A7 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
DE4D74472C8D65BF0072A4A7 /* 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;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
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;
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.5;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
DE4D74482C8D65BF0072A4A7 /* 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;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
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;
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.5;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
DE4D744A2C8D65BF0072A4A7 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = "v-browser/v_browser.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"v-browser/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = RQQ6N82NA8;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "v-browser";
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "dqj.v-browser";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
DE4D744B2C8D65BF0072A4A7 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = "v-browser/v_browser.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"v-browser/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = RQQ6N82NA8;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "v-browser";
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "dqj.v-browser";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
DE4D744D2C8D65BF0072A4A7 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = RQQ6N82NA8;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.5;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "dqj.v-browserTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/v-browser.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/v-browser";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
DE4D744E2C8D65BF0072A4A7 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = RQQ6N82NA8;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.5;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "dqj.v-browserTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/v-browser.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/v-browser";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
DE4D74502C8D65BF0072A4A7 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = RQQ6N82NA8;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "dqj.v-browserUITests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_TARGET_NAME = "v-browser";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
DE4D74512C8D65BF0072A4A7 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = RQQ6N82NA8;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "dqj.v-browserUITests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_TARGET_NAME = "v-browser";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
DE4D741F2C8D65BD0072A4A7 /* Build configuration list for PBXProject "v-browser" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
DE4D74472C8D65BF0072A4A7 /* Debug */,
|
||||
DE4D74482C8D65BF0072A4A7 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
DE4D74492C8D65BF0072A4A7 /* Build configuration list for PBXNativeTarget "v-browser" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
DE4D744A2C8D65BF0072A4A7 /* Debug */,
|
||||
DE4D744B2C8D65BF0072A4A7 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
DE4D744C2C8D65BF0072A4A7 /* Build configuration list for PBXNativeTarget "v-browserTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
DE4D744D2C8D65BF0072A4A7 /* Debug */,
|
||||
DE4D744E2C8D65BF0072A4A7 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
DE4D744F2C8D65BF0072A4A7 /* Build configuration list for PBXNativeTarget "v-browserUITests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
DE4D74502C8D65BF0072A4A7 /* Debug */,
|
||||
DE4D74512C8D65BF0072A4A7 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
2550BFAB2C9AFFFA0033B562 /* XCRemoteSwiftPackageReference "similarity-search-kit" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/ZachNagengast/similarity-search-kit";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 0.0.15;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
2550BFAC2C9AFFFA0033B562 /* SimilaritySearchKit */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 2550BFAB2C9AFFFA0033B562 /* XCRemoteSwiftPackageReference "similarity-search-kit" */;
|
||||
productName = SimilaritySearchKit;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = DE4D741C2C8D65BD0072A4A7 /* Project object */;
|
||||
}
|
||||
7
v-browser.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"originHash" : "a351174101179e10377155e91d3d1a4a5648760804ce27142488847d1ca85286",
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "similarity-search-kit",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/ZachNagengast/similarity-search-kit.git",
|
||||
"state" : {
|
||||
"revision" : "9bec54706c8124bb9b20a3a06d566066a9f55712",
|
||||
"version" : "0.0.15"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 3
|
||||
}
|
||||
11
v-browser/Assets.xcassets/AccentColor.colorset/Contents.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
v-browser/Assets.xcassets/AppIcon.appiconset/1024.png
Normal file
|
After Width: | Height: | Size: 813 KiB |
BIN
v-browser/Assets.xcassets/AppIcon.appiconset/128.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
v-browser/Assets.xcassets/AppIcon.appiconset/16.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
v-browser/Assets.xcassets/AppIcon.appiconset/256.png
Normal file
|
After Width: | Height: | Size: 91 KiB |
BIN
v-browser/Assets.xcassets/AppIcon.appiconset/32.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
v-browser/Assets.xcassets/AppIcon.appiconset/512.png
Normal file
|
After Width: | Height: | Size: 280 KiB |
BIN
v-browser/Assets.xcassets/AppIcon.appiconset/64.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
@@ -0,0 +1 @@
|
||||
{"images":[{"size":"128x128","expected-size":"128","filename":"128.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"256x256","expected-size":"256","filename":"256.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"128x128","expected-size":"256","filename":"256.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"256x256","expected-size":"512","filename":"512.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"32x32","expected-size":"32","filename":"32.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"512x512","expected-size":"512","filename":"512.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"16x16","expected-size":"16","filename":"16.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"16x16","expected-size":"32","filename":"32.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"32x32","expected-size":"64","filename":"64.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"512x512","expected-size":"1024","filename":"1024.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"}]}
|
||||
6
v-browser/Assets.xcassets/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
344
v-browser/ContentView.swift
Normal file
@@ -0,0 +1,344 @@
|
||||
//
|
||||
// ContentView.swift
|
||||
// v-browser
|
||||
//
|
||||
// Created by Du Qingjie on 2024/09/08.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import WebKit
|
||||
import AppKit
|
||||
|
||||
// WebPage structure
|
||||
class WebPage: NSObject, ObservableObject, Identifiable, WKNavigationDelegate, WKUIDelegate {
|
||||
let id = UUID()
|
||||
var url: String
|
||||
var title: String
|
||||
var summary: String
|
||||
var wkWebView: WKWebView?
|
||||
var view: ContentView?
|
||||
|
||||
@Published var canGoBack = false
|
||||
@Published var canGoForward = false
|
||||
@Published var favicon: Image?
|
||||
@Published var showCloseIcon = false
|
||||
|
||||
init(view: ContentView, url: String, title: String, summary: String) {
|
||||
self.view = view
|
||||
self.url = url
|
||||
self.title = title
|
||||
self.summary = summary
|
||||
super.init()
|
||||
self.wkWebView = WebKit.WKWebView()
|
||||
self.wkWebView?.navigationDelegate = self
|
||||
self.wkWebView?.uiDelegate = self
|
||||
if let url = URL(string: url) {
|
||||
let request = URLRequest(url: url)
|
||||
self.wkWebView?.load(request)
|
||||
self.loadFavicon(for: url)
|
||||
}
|
||||
}
|
||||
|
||||
func loadFavicon(for url: URL) {
|
||||
let faviconURL = url.appendingPathComponent("favicon.ico")
|
||||
|
||||
URLSession.shared.dataTask(with: faviconURL) { data, response, error in
|
||||
if let data = data, let nsImage = NSImage(data: data) {
|
||||
DispatchQueue.main.async {
|
||||
self.favicon = Image(nsImage: nsImage) // Set the fetched favicon
|
||||
}
|
||||
} else {
|
||||
DispatchQueue.main.async {
|
||||
// Favicon not found, load the app icon instead
|
||||
self.favicon = Image(nsImage: NSApp.applicationIconImage)
|
||||
}
|
||||
}
|
||||
}.resume()
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
|
||||
if let url = navigationAction.request.url {
|
||||
// Instead of creating a new web view, loaod the URL in the current web view
|
||||
webView.load(URLRequest(url: url))
|
||||
canGoBack = true
|
||||
}
|
||||
return nil // Return nil to prevent creating a new window
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||
DispatchQueue.main.async {
|
||||
self.canGoBack = webView.canGoBack
|
||||
self.canGoForward = webView.canGoForward
|
||||
self.url = webView.url?.absoluteString ?? ""
|
||||
self.loadFavicon(for: URL(string: self.url)!)
|
||||
self.objectWillChange.send() // Notify SwiftUI that a change occurred
|
||||
let cur = self.view?.selectedTab
|
||||
self.view?.selectedTab = nil
|
||||
self.view?.selectedTab = cur
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct WebViewWrapper: NSViewRepresentable {
|
||||
var webView: WKWebView
|
||||
|
||||
func makeNSView(context: Context) -> WKWebView {
|
||||
return webView
|
||||
}
|
||||
|
||||
func updateNSView(_ nsView: WKWebView, context: Context) {
|
||||
// No need to update, as the WKWebView is already initialized and managed by WebPage
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView: View {
|
||||
@State private var tabs: [WebPage] = [
|
||||
//WebPage(url: "https://amipro.me", title: "amiPro", summary: "Search the web"),
|
||||
//WebPage(url: "https://apple.com", title: "Apple", summary: "Apple's official website.")
|
||||
]
|
||||
@State public var selectedTab: WebPage? = nil
|
||||
@State private var browsingHistory: [WebPage] = []
|
||||
@State private var currentURL: String = ""
|
||||
@State private var leftPanelWidth: CGFloat = 200
|
||||
@State private var rightPanelWidth: CGFloat = 200
|
||||
@State private var lastDragLocationX: CGFloat = -1000000
|
||||
|
||||
@State private var curHoverTab: WebPage?
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
// Address bar and navigation buttons
|
||||
HStack {
|
||||
TextField("Enter URL or Ask AI", text: $currentURL)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
.frame(maxWidth: .infinity)
|
||||
.onSubmit {
|
||||
openTab(urlTxt: currentURL)
|
||||
}
|
||||
Button("Go") {
|
||||
openTab(urlTxt: currentURL)
|
||||
}
|
||||
.padding(.leading, 5)
|
||||
|
||||
Button("<") {
|
||||
goBack()
|
||||
}
|
||||
.disabled(!(selectedTab?.canGoBack ?? false))
|
||||
|
||||
Button(">") {
|
||||
goForward()
|
||||
}
|
||||
.disabled(!(selectedTab?.canGoForward ?? false))
|
||||
}
|
||||
.padding()
|
||||
|
||||
// Main body with draggable panels
|
||||
HStack(spacing: 0) {
|
||||
// Left panel (Tabs)
|
||||
VStack(spacing: 0) {
|
||||
ScrollView {
|
||||
ForEach(tabs) { tab in
|
||||
HStack{
|
||||
if tab.showCloseIcon {
|
||||
Image(systemName: "xmark.circle.fill") // Show close icon on hover
|
||||
.onTapGesture {
|
||||
closeTab(tab: tab)
|
||||
}
|
||||
.frame(width: 16, height: 16)
|
||||
} else {
|
||||
tab.favicon?.resizable()
|
||||
.frame(width: 16, height: 16) // Show favicon
|
||||
}
|
||||
Button(action: { selectedTab = tab }) {
|
||||
Text(tab.title)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
.padding(6)
|
||||
.frame(width: leftPanelWidth - 32, alignment: .leading)
|
||||
.foregroundColor(tab == selectedTab ? Color.primary : Color.secondary) // Text color
|
||||
.background(
|
||||
tab == selectedTab ? Color.accentColor.opacity(0.2) : Color.gray.opacity(0.1) // Adaptive background color
|
||||
)
|
||||
}.buttonStyle(PlainButtonStyle()).frame(height: 21)
|
||||
}.onHover { hovering in
|
||||
if nil != curHoverTab{
|
||||
curHoverTab?.showCloseIcon = false
|
||||
}
|
||||
curHoverTab = tab
|
||||
tab.showCloseIcon = hovering // Toggle between favicon and close icon
|
||||
let cur = self.selectedTab
|
||||
self.selectedTab = nil
|
||||
self.selectedTab = cur
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(width: leftPanelWidth)
|
||||
.background(Color.gray.opacity(0.1))
|
||||
.gesture(DragGesture()
|
||||
.onChanged { value in
|
||||
let chg = (-1000000 == lastDragLocationX) ? value.location.x-value.startLocation.x: value.location.x-lastDragLocationX
|
||||
lastDragLocationX = value.location.x
|
||||
let newWidth = leftPanelWidth + chg //value.translation.width
|
||||
if newWidth > 30 && newWidth < 600 {
|
||||
leftPanelWidth = newWidth
|
||||
}
|
||||
}
|
||||
.onEnded { value in
|
||||
lastDragLocationX = -1000000
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// Draggable divider between tabs and WebView
|
||||
Rectangle()
|
||||
.frame(width: 1)
|
||||
.foregroundColor(.gray)
|
||||
.gesture(DragGesture()
|
||||
.onChanged { value in
|
||||
let chg = (-1000000 == lastDragLocationX) ? value.location.x-value.startLocation.x: value.location.x-lastDragLocationX
|
||||
lastDragLocationX = value.location.x
|
||||
let newWidth = leftPanelWidth + chg //value.translation.width
|
||||
if newWidth > 30 && newWidth < 600 {
|
||||
leftPanelWidth = newWidth
|
||||
}
|
||||
}
|
||||
.onEnded{value in
|
||||
lastDragLocationX = -1000000
|
||||
}
|
||||
)
|
||||
.onHover { hovering in
|
||||
if hovering {
|
||||
NSCursor.resizeLeftRight.set() // Set cursor to left-right resize
|
||||
} else {
|
||||
NSCursor.arrow.set() // Reset cursor when not hovering
|
||||
}
|
||||
}
|
||||
|
||||
// Center panel (WebView or AI result)
|
||||
VStack {
|
||||
if let selectedTab = selectedTab, let webView = selectedTab.wkWebView {
|
||||
WebViewWrapper(webView: webView)
|
||||
.id(selectedTab.id) // Force SwiftUI to reinitialize when the tab changes
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
} else {
|
||||
Text("No tab selected")
|
||||
.font(.headline)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle()
|
||||
.frame(width: 1)
|
||||
.foregroundColor(.gray)
|
||||
.gesture(DragGesture()
|
||||
.onChanged { value in
|
||||
let newWidth = rightPanelWidth - value.translation.width
|
||||
if newWidth > 100 && newWidth < 600 {
|
||||
rightPanelWidth = newWidth
|
||||
}
|
||||
}
|
||||
)
|
||||
.onHover { hovering in
|
||||
if hovering {
|
||||
NSCursor.resizeLeftRight.set() // Set cursor to left-right resize
|
||||
} else {
|
||||
NSCursor.arrow.set() // Reset cursor when not hovering
|
||||
}
|
||||
}
|
||||
|
||||
// Right panel (Browsing History)
|
||||
VStack {
|
||||
ScrollView {
|
||||
ForEach(browsingHistory) { page in
|
||||
Text(page.title)
|
||||
.padding(10)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.background(page == selectedTab ? Color.blue.opacity(0.2) : Color.clear)
|
||||
.cornerRadius(5)
|
||||
.onTapGesture {
|
||||
selectedTab = page
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(width: rightPanelWidth)
|
||||
.background(Color.gray.opacity(0.1))
|
||||
.gesture(DragGesture()
|
||||
.onChanged { value in
|
||||
let newWidth = rightPanelWidth - value.translation.width
|
||||
if newWidth > 100 && newWidth < 400 {
|
||||
rightPanelWidth = newWidth
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
|
||||
// Bottom bar with system status
|
||||
HStack {
|
||||
Text("System Status: OK")
|
||||
.font(.footnote)
|
||||
Spacer()
|
||||
}
|
||||
.padding([.leading, .bottom])
|
||||
.background(Color.gray.opacity(0.1))
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.onAppear {
|
||||
// Automatically open a tab when the view appears
|
||||
openTab(urlTxt: "https://amipro.me")
|
||||
}
|
||||
}
|
||||
|
||||
func isValidURL(_ urlString: String) -> Bool {
|
||||
if let url = URL(string: urlString) {
|
||||
// Check if the URL has a valid scheme (http, https, etc.)
|
||||
return ((url.scheme) != nil)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func openTab(urlTxt: String){
|
||||
if isValidURL(urlTxt){
|
||||
createTab(url: URL(string: urlTxt)?.absoluteString ?? "", title: "Loading...", summary: "Loading...")
|
||||
}else if isValidURL("https://"+urlTxt){
|
||||
createTab(url: URL(string: "https://"+urlTxt)?.absoluteString ?? "", title: "Loading...", summary: "Loading...")
|
||||
}else{
|
||||
createTab(url: "https://www.google.com/search?q="+urlTxt.replacingOccurrences(of: " ", with: "+"), title: "Loading...", summary: "Loading...")
|
||||
//try to ask AI
|
||||
}
|
||||
}
|
||||
|
||||
func createTab(url: String, title: String, summary: String) {
|
||||
let newPage = WebPage(view: self, url: url, title: title, summary: summary)
|
||||
tabs.append(newPage)
|
||||
selectedTab = newPage
|
||||
}
|
||||
|
||||
func closeTab(tab: WebPage) {
|
||||
if let index = tabs.firstIndex(where: { $0.id == tab.id }) {
|
||||
tabs.remove(at: index)
|
||||
if selectedTab?.id == tab.id {
|
||||
selectedTab = tabs.last
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func goBack() {
|
||||
if let selectedTab = selectedTab, selectedTab.canGoBack == true {
|
||||
selectedTab.wkWebView?.goBack()
|
||||
selectedTab.canGoForward = true
|
||||
}
|
||||
}
|
||||
|
||||
func goForward() {
|
||||
if let selectedTab = selectedTab, selectedTab.canGoForward == true {
|
||||
selectedTab.wkWebView?.goForward()
|
||||
selectedTab.canGoBack = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*Preview {
|
||||
ContentView()
|
||||
}*/
|
||||
28
v-browser/Logger.swift
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Logger.swift
|
||||
// vectorsearch
|
||||
//
|
||||
// Created by Du Qingjie on 2024/08/31.
|
||||
//
|
||||
|
||||
import os
|
||||
import Foundation
|
||||
|
||||
class Logger {
|
||||
static let shared = Logger()
|
||||
|
||||
// Correctly initialize with subsystem and category
|
||||
private let logger = os.Logger(subsystem: Bundle.main.bundleIdentifier ?? "dqj.vectorsearch", category: "VectorSearch")
|
||||
|
||||
func info(_ message: String) {
|
||||
logger.log("\(message, privacy: .public)")
|
||||
}
|
||||
|
||||
func err(_ message: String) {
|
||||
logger.error("\(message, privacy: .public)")
|
||||
}
|
||||
|
||||
func debug(_ message: String) {
|
||||
logger.debug("\(message, privacy: .public)")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
84
v-browser/VectorManager.swift
Normal file
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// AIRunner.swift
|
||||
// v-browser
|
||||
//
|
||||
// Created by dqj on 2024/09/18.
|
||||
//
|
||||
|
||||
import SimilaritySearchKit
|
||||
import Foundation
|
||||
|
||||
class VectorManager: ObservableObject {
|
||||
static let shared = VectorManager()
|
||||
|
||||
private var similarityIndex: SimilarityIndex?
|
||||
|
||||
init() {
|
||||
Task {
|
||||
await load()
|
||||
}
|
||||
}
|
||||
|
||||
func load() async {
|
||||
similarityIndex = await SimilarityIndex(
|
||||
model: NativeEmbeddings(),
|
||||
metric: CosineSimilarity()
|
||||
)
|
||||
if let data = UserDefaults.standard.data(forKey: "vector_db") {
|
||||
let items = try? JSONDecoder().decode([SimilarityIndex.IndexItem].self, from: data)
|
||||
similarityIndex?.indexItems = items ?? []
|
||||
}else{
|
||||
similarityIndex?.indexItems = []
|
||||
}
|
||||
}
|
||||
|
||||
func setFileItem(path: String, text: String, modify_time: Int) async{
|
||||
guard let index = similarityIndex else { return }
|
||||
|
||||
let curItem = index.getItem(id: path)
|
||||
if(curItem != nil && Int(curItem?.metadata["mt"] ?? String(Int.max)) ?? Int.max > Int(modify_time)){
|
||||
index.updateItem(id: path, text: text, embedding: nil, metadata: ["mt": String(modify_time)] )
|
||||
if let encoded = try? JSONEncoder().encode(index.indexItems) {
|
||||
UserDefaults.standard.set(encoded, forKey: "vector_db")
|
||||
}
|
||||
}else if(curItem == nil){
|
||||
await index.addItem(id: path, text: text, metadata: ["mt": String(modify_time)])
|
||||
if let encoded = try? JSONEncoder().encode(index.indexItems) {
|
||||
UserDefaults.standard.set(encoded, forKey: "vector_db")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func search(query: String) async -> [SimilarityIndex.SearchResult]{
|
||||
guard let index = similarityIndex else { return []}
|
||||
|
||||
let results = await index.search(query, top: 100)
|
||||
return results
|
||||
}
|
||||
|
||||
func deleteFileItem(path: String){
|
||||
guard let index = similarityIndex else { return }
|
||||
|
||||
index.removeItem(id: path)
|
||||
UserDefaults.standard.setValue(index.indexItems, forKey: "vector_db")
|
||||
}
|
||||
|
||||
func clear() {
|
||||
guard let index = similarityIndex else { return }
|
||||
|
||||
index.removeAll()
|
||||
UserDefaults.standard.setValue(index.indexItems, forKey: "vector_db")
|
||||
}
|
||||
|
||||
func getFileItem(id: String) -> SimilarityIndex.IndexItem?{
|
||||
guard let index = similarityIndex else { return nil }
|
||||
|
||||
return index.getItem(id: id)
|
||||
}
|
||||
}
|
||||
|
||||
class SummaryBot:ObservableObject{
|
||||
|
||||
}
|
||||
|
||||
|
||||
12
v-browser/v_browser.entitlements
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
17
v-browser/v_browserApp.swift
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// v_browserApp.swift
|
||||
// v-browser
|
||||
//
|
||||
// Created by Du Qingjie on 2024/09/08.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
@main
|
||||
struct v_browserApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
}
|
||||
36
v-browserTests/v_browserTests.swift
Normal file
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// v_browserTests.swift
|
||||
// v-browserTests
|
||||
//
|
||||
// Created by Du Qingjie on 2024/09/08.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import v_browser
|
||||
|
||||
final class v_browserTests: 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.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
41
v-browserUITests/v_browserUITests.swift
Normal file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// v_browserUITests.swift
|
||||
// v-browserUITests
|
||||
//
|
||||
// Created by Du Qingjie on 2024/09/08.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
final class v_browserUITests: 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
v-browserUITests/v_browserUITestsLaunchTests.swift
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// v_browserUITestsLaunchTests.swift
|
||||
// v-browserUITests
|
||||
//
|
||||
// Created by Du Qingjie on 2024/09/08.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
final class v_browserUITestsLaunchTests: 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)
|
||||
}
|
||||
}
|
||||