Compare commits
6 Commits
3.3.0+137
...
0106c08891
| Author | SHA1 | Date | |
|---|---|---|---|
|
0106c08891
|
|||
|
9697def808
|
|||
|
6572875229
|
|||
|
66590b9079
|
|||
|
08b9604b55
|
|||
|
0602bbd277
|
@@ -3,13 +3,14 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 54;
|
objectVersion = 77;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||||
|
7310A7DF2EB10963002C0FD3 /* WatchRunner Watch App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 7310A7D42EB10962002C0FD3 /* WatchRunner Watch App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
73ACDFAD2E3D0E6100B63535 /* ReplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73ACDFAC2E3D0E6100B63535 /* ReplayKit.framework */; };
|
73ACDFAD2E3D0E6100B63535 /* ReplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73ACDFAC2E3D0E6100B63535 /* ReplayKit.framework */; };
|
||||||
73ACDFC32E3D0E6100B63535 /* SolianBroadcastExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
73ACDFC32E3D0E6100B63535 /* SolianBroadcastExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
73C305D82E0BE878009035B9 /* SolianShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73C305CE2E0BE878009035B9 /* SolianShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
73C305D82E0BE878009035B9 /* SolianShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73C305CE2E0BE878009035B9 /* SolianShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
@@ -58,6 +59,17 @@
|
|||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
7310A7DE2EB10963002C0FD3 /* Embed Watch Content */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = "$(CONTENTS_FOLDER_PATH)/Watch";
|
||||||
|
dstSubfolderSpec = 16;
|
||||||
|
files = (
|
||||||
|
7310A7DF2EB10963002C0FD3 /* WatchRunner Watch App.app in Embed Watch Content */,
|
||||||
|
);
|
||||||
|
name = "Embed Watch Content";
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
73268D1D2DEAFD670076E970 /* Embed Foundation Extensions */ = {
|
73268D1D2DEAFD670076E970 /* Embed Foundation Extensions */ = {
|
||||||
isa = PBXCopyFilesBuildPhase;
|
isa = PBXCopyFilesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -100,6 +112,7 @@
|
|||||||
39FE4CC6223F0D3C0E1FFD04 /* Pods_SolianNotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolianNotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
39FE4CC6223F0D3C0E1FFD04 /* Pods_SolianNotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolianNotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
3A1C47BD29CC6AC2587D4DBE /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
3A1C47BD29CC6AC2587D4DBE /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
|
7310A7D42EB10962002C0FD3 /* WatchRunner Watch App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "WatchRunner Watch App.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
737E920B2DB6A9FF00BE9CDB /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
737E920B2DB6A9FF00BE9CDB /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||||
73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolianBroadcastExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolianBroadcastExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
73ACDFAC2E3D0E6100B63535 /* ReplayKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReplayKit.framework; path = System/Library/Frameworks/ReplayKit.framework; sourceTree = SDKROOT; };
|
73ACDFAC2E3D0E6100B63535 /* ReplayKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReplayKit.framework; path = System/Library/Frameworks/ReplayKit.framework; sourceTree = SDKROOT; };
|
||||||
@@ -162,6 +175,11 @@
|
|||||||
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||||
|
|
||||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||||
|
7310A7D52EB10962002C0FD3 /* WatchRunner Watch App */ = {
|
||||||
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
|
path = "WatchRunner Watch App";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
73268D272DEB012A0076E970 /* Services */ = {
|
73268D272DEB012A0076E970 /* Services */ = {
|
||||||
isa = PBXFileSystemSynchronizedRootGroup;
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
exceptions = (
|
exceptions = (
|
||||||
@@ -205,6 +223,13 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
7310A7D12EB10962002C0FD3 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
73ACDFA82E3D0E6100B63535 /* Frameworks */ = {
|
73ACDFA82E3D0E6100B63535 /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -303,6 +328,7 @@
|
|||||||
73CDD67B2DEC00480059D95D /* SolianNotificationService */,
|
73CDD67B2DEC00480059D95D /* SolianNotificationService */,
|
||||||
73C305CF2E0BE878009035B9 /* SolianShareExtension */,
|
73C305CF2E0BE878009035B9 /* SolianShareExtension */,
|
||||||
73ACDFAE2E3D0E6100B63535 /* SolianBroadcastExtension */,
|
73ACDFAE2E3D0E6100B63535 /* SolianBroadcastExtension */,
|
||||||
|
7310A7D52EB10962002C0FD3 /* WatchRunner Watch App */,
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||||
91E124CE95BCB4DCD890160D /* Pods */,
|
91E124CE95BCB4DCD890160D /* Pods */,
|
||||||
@@ -319,6 +345,7 @@
|
|||||||
73CDD67A2DEC00480059D95D /* SolianNotificationService.appex */,
|
73CDD67A2DEC00480059D95D /* SolianNotificationService.appex */,
|
||||||
73C305CE2E0BE878009035B9 /* SolianShareExtension.appex */,
|
73C305CE2E0BE878009035B9 /* SolianShareExtension.appex */,
|
||||||
73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */,
|
73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */,
|
||||||
|
7310A7D42EB10962002C0FD3 /* WatchRunner Watch App.app */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -363,6 +390,26 @@
|
|||||||
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
|
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
|
||||||
productType = "com.apple.product-type.bundle.unit-test";
|
productType = "com.apple.product-type.bundle.unit-test";
|
||||||
};
|
};
|
||||||
|
7310A7D32EB10962002C0FD3 /* WatchRunner Watch App */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 7310A7E32EB10963002C0FD3 /* Build configuration list for PBXNativeTarget "WatchRunner Watch App" */;
|
||||||
|
buildPhases = (
|
||||||
|
7310A7D02EB10962002C0FD3 /* Sources */,
|
||||||
|
7310A7D12EB10962002C0FD3 /* Frameworks */,
|
||||||
|
7310A7D22EB10962002C0FD3 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
fileSystemSynchronizedGroups = (
|
||||||
|
7310A7D52EB10962002C0FD3 /* WatchRunner Watch App */,
|
||||||
|
);
|
||||||
|
name = "WatchRunner Watch App";
|
||||||
|
productName = "WatchRunner Watch App";
|
||||||
|
productReference = 7310A7D42EB10962002C0FD3 /* WatchRunner Watch App.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
73ACDFAA2E3D0E6100B63535 /* SolianBroadcastExtension */ = {
|
73ACDFAA2E3D0E6100B63535 /* SolianBroadcastExtension */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 73ACDFCB2E3D0E6100B63535 /* Build configuration list for PBXNativeTarget "SolianBroadcastExtension" */;
|
buildConfigurationList = 73ACDFCB2E3D0E6100B63535 /* Build configuration list for PBXNativeTarget "SolianBroadcastExtension" */;
|
||||||
@@ -434,6 +481,7 @@
|
|||||||
97C146EA1CF9000F007C117D /* Sources */,
|
97C146EA1CF9000F007C117D /* Sources */,
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
73268D1D2DEAFD670076E970 /* Embed Foundation Extensions */,
|
73268D1D2DEAFD670076E970 /* Embed Foundation Extensions */,
|
||||||
|
7310A7DE2EB10963002C0FD3 /* Embed Watch Content */,
|
||||||
97C146EC1CF9000F007C117D /* Resources */,
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
@@ -463,7 +511,7 @@
|
|||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = YES;
|
BuildIndependentTargetsInParallel = YES;
|
||||||
LastSwiftUpdateCheck = 1640;
|
LastSwiftUpdateCheck = 2600;
|
||||||
LastUpgradeCheck = 1510;
|
LastUpgradeCheck = 1510;
|
||||||
ORGANIZATIONNAME = "";
|
ORGANIZATIONNAME = "";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
@@ -471,6 +519,9 @@
|
|||||||
CreatedOnToolsVersion = 14.0;
|
CreatedOnToolsVersion = 14.0;
|
||||||
TestTargetID = 97C146ED1CF9000F007C117D;
|
TestTargetID = 97C146ED1CF9000F007C117D;
|
||||||
};
|
};
|
||||||
|
7310A7D32EB10962002C0FD3 = {
|
||||||
|
CreatedOnToolsVersion = 26.0.1;
|
||||||
|
};
|
||||||
73ACDFAA2E3D0E6100B63535 = {
|
73ACDFAA2E3D0E6100B63535 = {
|
||||||
CreatedOnToolsVersion = 16.4;
|
CreatedOnToolsVersion = 16.4;
|
||||||
};
|
};
|
||||||
@@ -504,6 +555,7 @@
|
|||||||
73CDD6792DEC00480059D95D /* SolianNotificationService */,
|
73CDD6792DEC00480059D95D /* SolianNotificationService */,
|
||||||
73C305CD2E0BE878009035B9 /* SolianShareExtension */,
|
73C305CD2E0BE878009035B9 /* SolianShareExtension */,
|
||||||
73ACDFAA2E3D0E6100B63535 /* SolianBroadcastExtension */,
|
73ACDFAA2E3D0E6100B63535 /* SolianBroadcastExtension */,
|
||||||
|
7310A7D32EB10962002C0FD3 /* WatchRunner Watch App */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
@@ -516,6 +568,13 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
7310A7D22EB10962002C0FD3 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
73ACDFA92E3D0E6100B63535 /* Resources */ = {
|
73ACDFA92E3D0E6100B63535 /* Resources */ = {
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -598,10 +657,14 @@
|
|||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
name = "[CP] Copy Pods Resources";
|
name = "[CP] Copy Pods Resources";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||||
@@ -659,10 +722,14 @@
|
|||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
name = "[CP] Embed Pods Frameworks";
|
name = "[CP] Embed Pods Frameworks";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||||
@@ -734,6 +801,13 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
7310A7D02EB10962002C0FD3 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
73ACDFA72E3D0E6100B63535 /* Sources */ = {
|
73ACDFA72E3D0E6100B63535 /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -943,6 +1017,141 @@
|
|||||||
};
|
};
|
||||||
name = Profile;
|
name = Profile;
|
||||||
};
|
};
|
||||||
|
7310A7E02EB10963002C0FD3 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
||||||
|
ENABLE_PREVIEWS = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = WatchRunner;
|
||||||
|
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
||||||
|
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = dev.solsynth.solian;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.watchkitapp;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SDKROOT = watchos;
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = 4;
|
||||||
|
WATCHOS_DEPLOYMENT_TARGET = 26.0;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
7310A7E12EB10963002C0FD3 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
||||||
|
ENABLE_PREVIEWS = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = WatchRunner;
|
||||||
|
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
||||||
|
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = dev.solsynth.solian;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.watchkitapp;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SDKROOT = watchos;
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = 4;
|
||||||
|
WATCHOS_DEPLOYMENT_TARGET = 26.0;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
7310A7E22EB10963002C0FD3 /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
||||||
|
ENABLE_PREVIEWS = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = WatchRunner;
|
||||||
|
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
||||||
|
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = dev.solsynth.solian;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.watchkitapp;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SDKROOT = watchos;
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = 4;
|
||||||
|
WATCHOS_DEPLOYMENT_TARGET = 26.0;
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
73ACDFC42E3D0E6100B63535 /* Debug */ = {
|
73ACDFC42E3D0E6100B63535 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
@@ -1487,6 +1696,16 @@
|
|||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
|
7310A7E32EB10963002C0FD3 /* Build configuration list for PBXNativeTarget "WatchRunner Watch App" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
7310A7E02EB10963002C0FD3 /* Debug */,
|
||||||
|
7310A7E12EB10963002C0FD3 /* Release */,
|
||||||
|
7310A7E22EB10963002C0FD3 /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
73ACDFCB2E3D0E6100B63535 /* Build configuration list for PBXNativeTarget "SolianBroadcastExtension" */ = {
|
73ACDFCB2E3D0E6100B63535 /* Build configuration list for PBXNativeTarget "SolianBroadcastExtension" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import Flutter
|
import Flutter
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import WatchConnectivity
|
||||||
|
|
||||||
@main
|
@main
|
||||||
@objc class AppDelegate: FlutterAppDelegate {
|
@objc class AppDelegate: FlutterAppDelegate {
|
||||||
let notifyDelegate = NotifyDelegate()
|
let notifyDelegate = NotifyDelegate()
|
||||||
|
private var watchConnectivityService: WatchConnectivityService?
|
||||||
|
|
||||||
override func application(
|
override func application(
|
||||||
_ application: UIApplication,
|
_ application: UIApplication,
|
||||||
@@ -28,6 +30,55 @@ import UIKit
|
|||||||
|
|
||||||
GeneratedPluginRegistrant.register(with: self)
|
GeneratedPluginRegistrant.register(with: self)
|
||||||
|
|
||||||
|
if WCSession.isSupported() {
|
||||||
|
watchConnectivityService = WatchConnectivityService()
|
||||||
|
}
|
||||||
|
|
||||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class WatchConnectivityService: NSObject, WCSessionDelegate {
|
||||||
|
private let session: WCSession
|
||||||
|
|
||||||
|
override init() {
|
||||||
|
self.session = .default
|
||||||
|
super.init()
|
||||||
|
print("[iOS] Activating WCSession")
|
||||||
|
self.session.delegate = self
|
||||||
|
self.session.activate()
|
||||||
|
}
|
||||||
|
|
||||||
|
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
|
||||||
|
if let error = error {
|
||||||
|
print("[iOS] WCSession activation failed with error: \(error.localizedDescription)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
print("[iOS] WCSession activated with state: \(activationState.rawValue)")
|
||||||
|
}
|
||||||
|
|
||||||
|
func sessionDidBecomeInactive(_ session: WCSession) {}
|
||||||
|
|
||||||
|
func sessionDidDeactivate(_ session: WCSession) {
|
||||||
|
session.activate()
|
||||||
|
}
|
||||||
|
|
||||||
|
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
|
||||||
|
print("[iOS] Received message: \(message)")
|
||||||
|
if let request = message["request"] as? String, request == "data" {
|
||||||
|
let token = UserDefaults.standard.getFlutterToken()
|
||||||
|
let serverUrl = UserDefaults.standard.getServerUrl()
|
||||||
|
|
||||||
|
print("[iOS] Retrieved token: \(token ?? "nil")")
|
||||||
|
print("[iOS] Retrieved serverUrl: \(serverUrl)")
|
||||||
|
|
||||||
|
var data: [String: Any] = ["serverUrl": serverUrl]
|
||||||
|
if let token = token {
|
||||||
|
data["token"] = token
|
||||||
|
}
|
||||||
|
|
||||||
|
print("[iOS] Replying with data: \(data)")
|
||||||
|
replyHandler(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
func getAttachmentUrl(for identifier: String) -> String {
|
func getAttachmentUrl(for identifier: String) -> String {
|
||||||
let serverBaseUrl = "https://api.solian.app"
|
let serverBaseUrl = UserDefaults.standard.getServerUrl()
|
||||||
|
|
||||||
return identifier.starts(with: "http") ? identifier : "\(serverBaseUrl)/drive/files/\(identifier)"
|
return identifier.starts(with: "http") ? identifier : "\(serverBaseUrl)/drive/files/\(identifier)"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,6 @@ extension UserDefaults {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getServerUrl(forKey key: String = "app_server_url") -> String {
|
func getServerUrl(forKey key: String = "app_server_url") -> String {
|
||||||
return self.getFlutterValue(forKey: key) ?? "https://nt.solian.app"
|
return self.getFlutterValue(forKey: key) ?? "https://api.solian.app"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
6
ios/WatchRunner Watch App/Assets.xcassets/Contents.json
Normal file
6
ios/WatchRunner Watch App/Assets.xcassets/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
414
ios/WatchRunner Watch App/ContentView.swift
Normal file
414
ios/WatchRunner Watch App/ContentView.swift
Normal file
@@ -0,0 +1,414 @@
|
|||||||
|
//
|
||||||
|
// ContentView.swift
|
||||||
|
// WatchRunner Watch App
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2025/10/28.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import Combine
|
||||||
|
import WatchConnectivity
|
||||||
|
|
||||||
|
// MARK: - App State
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
class AppState: ObservableObject {
|
||||||
|
@Published var token: String? = nil
|
||||||
|
@Published var serverUrl: String? = nil
|
||||||
|
@Published var isReady = false
|
||||||
|
|
||||||
|
private var wcService = WatchConnectivityService()
|
||||||
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
init() {
|
||||||
|
wcService.$token.combineLatest(wcService.$serverUrl)
|
||||||
|
.receive(on: DispatchQueue.main)
|
||||||
|
.sink { [weak self] token, serverUrl in
|
||||||
|
self?.token = token
|
||||||
|
self?.serverUrl = serverUrl
|
||||||
|
if token != nil && serverUrl != nil {
|
||||||
|
self?.isReady = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestData() {
|
||||||
|
wcService.requestDataFromPhone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Watch Connectivity
|
||||||
|
|
||||||
|
class WatchConnectivityService: NSObject, WCSessionDelegate, ObservableObject {
|
||||||
|
@Published var token: String?
|
||||||
|
@Published var serverUrl: String?
|
||||||
|
|
||||||
|
private let session: WCSession
|
||||||
|
|
||||||
|
override init() {
|
||||||
|
self.session = .default
|
||||||
|
super.init()
|
||||||
|
print("[watchOS] Activating WCSession")
|
||||||
|
self.session.delegate = self
|
||||||
|
self.session.activate()
|
||||||
|
}
|
||||||
|
|
||||||
|
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
|
||||||
|
if let error = error {
|
||||||
|
print("[watchOS] WCSession activation failed with error: \(error.localizedDescription)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
print("[watchOS] WCSession activated with state: \(activationState.rawValue)")
|
||||||
|
if activationState == .activated {
|
||||||
|
requestDataFromPhone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
|
||||||
|
print("[watchOS] Received message: \(message)")
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
if let token = message["token"] as? String {
|
||||||
|
self.token = token
|
||||||
|
}
|
||||||
|
if let serverUrl = message["serverUrl"] as? String {
|
||||||
|
self.serverUrl = serverUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestDataFromPhone() {
|
||||||
|
guard session.isReachable else {
|
||||||
|
print("[watchOS] Phone is not reachable")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
print("[watchOS] Requesting data from phone")
|
||||||
|
session.sendMessage(["request": "data"]) { [weak self] response in
|
||||||
|
print("[watchOS] Received reply: \(response)")
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
if let token = response["token"] as? String {
|
||||||
|
self?.token = token
|
||||||
|
}
|
||||||
|
if let serverUrl = response["serverUrl"] as? String {
|
||||||
|
self?.serverUrl = serverUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} errorHandler: { error in
|
||||||
|
print("[watchOS] sendMessage failed with error: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Models
|
||||||
|
|
||||||
|
struct AppToken: Codable {
|
||||||
|
let token: String
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SnActivity: Codable, Identifiable {
|
||||||
|
let id: String
|
||||||
|
let type: String
|
||||||
|
let data: ActivityData?
|
||||||
|
let createdAt: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ActivityData: Codable {
|
||||||
|
case post(SnPost)
|
||||||
|
case discovery(DiscoveryData)
|
||||||
|
case unknown
|
||||||
|
|
||||||
|
init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.singleValueContainer()
|
||||||
|
if let post = try? container.decode(SnPost.self) {
|
||||||
|
self = .post(post)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let discoveryData = try? container.decode(DiscoveryData.self) {
|
||||||
|
self = .discovery(discoveryData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self = .unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
func encode(to encoder: Encoder) throws {
|
||||||
|
// Not needed for decoding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SnPost: Codable, Identifiable {
|
||||||
|
let id: String
|
||||||
|
let content: String?
|
||||||
|
let title: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DiscoveryData: Codable {
|
||||||
|
let items: [DiscoveryItem]
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DiscoveryItem: Codable, Identifiable {
|
||||||
|
var id = UUID()
|
||||||
|
let type: String
|
||||||
|
let data: DiscoveryItemData
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case type, data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum DiscoveryItemData: Codable {
|
||||||
|
case realm(SnRealm)
|
||||||
|
case publisher(SnPublisher)
|
||||||
|
case article(SnWebArticle)
|
||||||
|
case unknown
|
||||||
|
|
||||||
|
init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.singleValueContainer()
|
||||||
|
if let realm = try? container.decode(SnRealm.self) {
|
||||||
|
self = .realm(realm)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let publisher = try? container.decode(SnPublisher.self) {
|
||||||
|
self = .publisher(publisher)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let article = try? container.decode(SnWebArticle.self) {
|
||||||
|
self = .article(article)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self = .unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
func encode(to encoder: Encoder) throws {
|
||||||
|
// Not needed for decoding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SnRealm: Codable, Identifiable {
|
||||||
|
let id: String
|
||||||
|
let name: String
|
||||||
|
let description: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SnPublisher: Codable, Identifiable {
|
||||||
|
let id: String
|
||||||
|
let name: String
|
||||||
|
let description: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SnWebArticle: Codable, Identifiable {
|
||||||
|
let id: String
|
||||||
|
let title: String
|
||||||
|
let url: String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - Network Service
|
||||||
|
|
||||||
|
class NetworkService {
|
||||||
|
private let session = URLSession.shared
|
||||||
|
|
||||||
|
func fetchActivities(filter: String, cursor: String? = nil, token: String, serverUrl: String) async throws -> [SnActivity] {
|
||||||
|
guard let baseURL = URL(string: serverUrl) else {
|
||||||
|
throw URLError(.badURL)
|
||||||
|
}
|
||||||
|
var components = URLComponents(url: baseURL.appendingPathComponent("/sphere/activities"), resolvingAgainstBaseURL: false)!
|
||||||
|
var queryItems = [URLQueryItem(name: "take", value: "20")]
|
||||||
|
if filter.lowercased() != "explore" {
|
||||||
|
queryItems.append(URLQueryItem(name: "filter", value: filter.lowercased()))
|
||||||
|
}
|
||||||
|
if let cursor = cursor {
|
||||||
|
queryItems.append(URLQueryItem(name: "cursor", value: cursor))
|
||||||
|
}
|
||||||
|
components.queryItems = queryItems
|
||||||
|
|
||||||
|
var request = URLRequest(url: components.url!)
|
||||||
|
request.httpMethod = "GET"
|
||||||
|
request.setValue("application/json", forHTTPHeaderField: "Accept")
|
||||||
|
|
||||||
|
request.setValue("AtField \(token)", forHTTPHeaderField: "Authorization")
|
||||||
|
request.setValue("SolianWatch/1.0", forHTTPHeaderField: "User-Agent")
|
||||||
|
|
||||||
|
let (data, _) = try await session.data(for: request)
|
||||||
|
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
decoder.dateDecodingStrategy = .iso8601
|
||||||
|
decoder.keyDecodingStrategy = .convertFromSnakeCase
|
||||||
|
|
||||||
|
return try decoder.decode([SnActivity].self, from: data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - View Models
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
class ActivityViewModel: ObservableObject {
|
||||||
|
@Published var activities: [SnActivity] = []
|
||||||
|
@Published var isLoading = false
|
||||||
|
@Published var errorMessage: String?
|
||||||
|
|
||||||
|
private let networkService = NetworkService()
|
||||||
|
let filter: String
|
||||||
|
|
||||||
|
init(filter: String) {
|
||||||
|
self.filter = filter
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchActivities(appState: AppState) async {
|
||||||
|
guard !isLoading, appState.isReady, let token = appState.token, let serverUrl = appState.serverUrl else { return }
|
||||||
|
isLoading = true
|
||||||
|
errorMessage = nil
|
||||||
|
|
||||||
|
do {
|
||||||
|
let fetchedActivities = try await networkService.fetchActivities(filter: filter, token: token, serverUrl: serverUrl)
|
||||||
|
self.activities = fetchedActivities
|
||||||
|
} catch {
|
||||||
|
self.errorMessage = error.localizedDescription
|
||||||
|
print("[watchOS] fetchActivities failed with error: \(error)")
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Views
|
||||||
|
|
||||||
|
struct ActivityListView: View {
|
||||||
|
@StateObject private var viewModel: ActivityViewModel
|
||||||
|
@EnvironmentObject var appState: AppState
|
||||||
|
|
||||||
|
init(filter: String) {
|
||||||
|
_viewModel = StateObject(wrappedValue: ActivityViewModel(filter: filter))
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Group {
|
||||||
|
if viewModel.isLoading {
|
||||||
|
ProgressView()
|
||||||
|
} else if let errorMessage = viewModel.errorMessage {
|
||||||
|
VStack {
|
||||||
|
Text("Error fetching data")
|
||||||
|
.font(.headline)
|
||||||
|
Text(errorMessage)
|
||||||
|
.font(.caption)
|
||||||
|
.lineLimit(nil)
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
} else if viewModel.activities.isEmpty {
|
||||||
|
Text("No activities found.")
|
||||||
|
} else {
|
||||||
|
List(viewModel.activities) { activity in
|
||||||
|
switch activity.type {
|
||||||
|
case "posts.new", "posts.new.replies":
|
||||||
|
if case .post(let post) = activity.data {
|
||||||
|
PostRowView(post: post)
|
||||||
|
}
|
||||||
|
case "discovery":
|
||||||
|
if case .discovery(let discoveryData) = activity.data {
|
||||||
|
DiscoveryView(discoveryData: discoveryData)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Text("Unknown activity type: \(activity.type)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.task {
|
||||||
|
await viewModel.fetchActivities(appState: appState)
|
||||||
|
}
|
||||||
|
.navigationTitle(viewModel.filter)
|
||||||
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PostRowView: View {
|
||||||
|
let post: SnPost
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
|
Text(post.title ?? "Post")
|
||||||
|
.font(.headline)
|
||||||
|
if let content = post.content {
|
||||||
|
Text(content)
|
||||||
|
.font(.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DiscoveryView: View {
|
||||||
|
let discoveryData: DiscoveryData
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text("Discovery")
|
||||||
|
.font(.headline)
|
||||||
|
.padding(.bottom, 2)
|
||||||
|
ForEach(discoveryData.items) { item in
|
||||||
|
switch item.data {
|
||||||
|
case .realm(let realm):
|
||||||
|
Text("Realm: \(realm.name)")
|
||||||
|
case .publisher(let publisher):
|
||||||
|
Text("Publisher: \(publisher.name)")
|
||||||
|
case .article(let article):
|
||||||
|
Text("Article: \(article.title)")
|
||||||
|
case .unknown:
|
||||||
|
Text("Unknown discovery item")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The main view with the TabView for filtering.
|
||||||
|
struct ExploreView: View {
|
||||||
|
@StateObject private var appState = AppState()
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Group {
|
||||||
|
if appState.isReady {
|
||||||
|
TabView {
|
||||||
|
NavigationStack {
|
||||||
|
ActivityListView(filter: "Explore")
|
||||||
|
}
|
||||||
|
.tabItem {
|
||||||
|
Label("Explore", systemImage: "safari")
|
||||||
|
}
|
||||||
|
|
||||||
|
NavigationStack {
|
||||||
|
ActivityListView(filter: "Subscriptions")
|
||||||
|
}
|
||||||
|
.tabItem {
|
||||||
|
Label("Subscriptions", systemImage: "star")
|
||||||
|
}
|
||||||
|
|
||||||
|
NavigationStack {
|
||||||
|
ActivityListView(filter: "Friends")
|
||||||
|
}
|
||||||
|
.tabItem {
|
||||||
|
Label("Friends", systemImage: "person.2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.environmentObject(appState)
|
||||||
|
} else {
|
||||||
|
ProgressView { Text("Connecting to phone...") }
|
||||||
|
.onAppear {
|
||||||
|
appState.requestData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The root view of the app.
|
||||||
|
struct ContentView: View {
|
||||||
|
var body: some View {
|
||||||
|
ExploreView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
ContentView()
|
||||||
|
}
|
||||||
17
ios/WatchRunner Watch App/WatchRunnerApp.swift
Normal file
17
ios/WatchRunner Watch App/WatchRunnerApp.swift
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// WatchRunnerApp.swift
|
||||||
|
// WatchRunner Watch App
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2025/10/28.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
@main
|
||||||
|
struct WatchRunner_Watch_AppApp: App {
|
||||||
|
var body: some Scene {
|
||||||
|
WindowGroup {
|
||||||
|
ContentView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -350,7 +350,11 @@ class ExploreScreen extends HookConsumerWidget {
|
|||||||
toolbarHeight: 48 + 4,
|
toolbarHeight: 48 + 4,
|
||||||
flexibleSpace: Container(
|
flexibleSpace: Container(
|
||||||
height: 48,
|
height: 48,
|
||||||
margin: const EdgeInsets.only(left: 8, right: 8, top: 4),
|
margin: EdgeInsets.only(
|
||||||
|
left: 8,
|
||||||
|
right: 8,
|
||||||
|
top: 4 + MediaQuery.of(context).padding.top,
|
||||||
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 3.3.0+137
|
version: 3.3.0+138
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.7.2
|
sdk: ^3.7.2
|
||||||
|
|||||||
Reference in New Issue
Block a user