Compare commits
237 Commits
983ae2a1fc
...
3.4.0+149
| Author | SHA1 | Date | |
|---|---|---|---|
|
5fc8859f3b
|
|||
|
e30e7adbe2
|
|||
|
68be4db160
|
|||
|
aa91e376ca
|
|||
|
caffb85588
|
|||
|
521b192205
|
|||
|
77ac0428ea
|
|||
|
88c8227c66
|
|||
|
b20d8350a8
|
|||
|
98b27bed0e
|
|||
|
3a7d8b1a0d
|
|||
|
b4801d6af6
|
|||
|
aab5b957af
|
|||
|
43d706a184
|
|||
|
98df275f88
|
|||
|
5663df6ef1
|
|||
|
e996a0c95f
|
|||
|
a090e93f57
|
|||
|
c69034c071
|
|||
|
369ea6cf5b
|
|||
|
2e371b5296
|
|||
|
2e9d61bcfa
|
|||
|
9c2b5b0dfa
|
|||
|
3b40f515b3
|
|||
|
5ee61dbef2
|
|||
|
b151ef6686
|
|||
|
ff934d0f08
|
|||
|
abe5ded896
|
|||
|
f1d72a5215
|
|||
|
864cbe73b7
|
|||
|
108a6da074
|
|||
|
f9a09599c9
|
|||
|
9067dadd3e
|
|||
|
09f8df1e78
|
|||
|
2c5f246c55
|
|||
|
a66c6ea654
|
|||
|
3ad4bb4518
|
|||
|
53f0dcb825
|
|||
|
557f5a2389
|
|||
|
78f14f890f
|
|||
|
77b2effb34
|
|||
|
f02b4abf65
|
|||
|
3f37c4f761
|
|||
|
5deb910fa4
|
|||
|
f50a19f573
|
|||
|
98c8a356e8
|
|||
|
d0c16ea08f
|
|||
|
f2c1b2a531
|
|||
|
3061f0c5a9
|
|||
|
98f7f33c65
|
|||
|
d9af5d32fd
|
|||
|
f2031697ec
|
|||
|
9b85b7573c
|
|||
|
4fb739b33b
|
|||
|
c03ba3bc3a
|
|||
|
fc65440420
|
|||
|
7b85533184
|
|||
|
77d9eb60c6
|
|||
|
4d8953cd22
|
|||
|
fafa460fe8
|
|||
|
faf3a677d4
|
|||
|
0f644a0234
|
|||
|
18d16fdd57
|
|||
|
18e890d63c
|
|||
|
9c5e50c16a
|
|||
|
96a2c8182e
|
|||
|
56b27c3e82
|
|||
|
ad4bf94195
|
|||
|
b77a832d8a
|
|||
|
5e61805db7
|
|||
|
35b96b0bd2
|
|||
|
c8ad791ff3
|
|||
|
1e908502dc
|
|||
|
715ce1a368
|
|||
|
548c9963ee
|
|||
|
db5199438a
|
|||
|
4409a6fb1e
|
|||
|
26a24b0e41
|
|||
|
9b948d259b
|
|||
|
1f713b5b2b
|
|||
|
f92cfafda4
|
|||
|
fa208b44d7
|
|||
|
94adecafbb
|
|||
|
0303ef4a93
|
|||
|
c2b18ce10b
|
|||
|
0767bb53ce
|
|||
|
b233f9a410
|
|||
|
256024fb46
|
|||
|
4a80aaf24d
|
|||
|
aafd160c44
|
|||
|
4a800725e3
|
|||
|
24791b3293
|
|||
|
3ac263d483
|
|||
|
2445d8adf8
|
|||
|
d4f95bbbf4
|
|||
|
943e4b7b5c
|
|||
|
7edc02a1d3
|
|||
|
3f9881e943
|
|||
|
50c25e919c
|
|||
|
99fb08dd55
|
|||
|
e43bc6b8a8
|
|||
|
c247cdf81c
|
|||
|
3ffa730505
|
|||
|
1cc34d3073
|
|||
|
96a919cc4e
|
|||
|
e7e3bfcadf
|
|||
|
a8617a5040
|
|||
|
d94f8d004f
|
|||
|
d93b066979
|
|||
|
320664a547
|
|||
|
98f4698d5b
|
|||
|
82397dd087
|
|||
|
4ec10ceb47
|
|||
|
4b03b45a0d
|
|||
|
7a72d32649
|
|||
|
5152dd13ea
|
|||
|
fd377aa7af
|
|||
|
67044148f1
|
|||
|
92bc43e4df
|
|||
|
a1a7b34c86
|
|||
|
40c0e052cf
|
|||
|
9a75228e38
|
|||
|
a9fd75cc45
|
|||
|
a713b30d93
|
|||
|
e516f0a862
|
|||
|
429b966c4b
|
|||
|
f14da0d3a2
|
|||
|
d201182bd2
|
|||
|
6f6422c15e
|
|||
|
9f6ae639ee
|
|||
|
35f4d7d885
|
|||
|
a9c8f49797
|
|||
|
5e9341a19c
|
|||
|
645a6dca93
|
|||
|
ea8e7ead2d
|
|||
|
5f2f083d72
|
|||
|
5cf40e27de
|
|||
|
1ab7295918
|
|||
|
07f191171c
|
|||
|
4a5dac248e
|
|||
|
3b983a6444
|
|||
|
4607b77355
|
|||
|
7957e4894a
|
|||
|
f94f80c375
|
|||
|
74fa2215a6
|
|||
|
0d11435feb
|
|||
|
e22598b0a6
|
|||
|
84cfe643f5
|
|||
|
05ac04e9a2
|
|||
|
66f283d6e8
|
|||
|
c779c7523c
|
|||
|
ac7cb29afe
|
|||
|
935aa77223
|
|||
|
24e5b3b824
|
|||
|
0391893b32
|
|||
|
b8d24876c8
|
|||
|
0493661f9a
|
|||
|
b40afde00f
|
|||
|
78a4022531
|
|||
|
8a291c80b7
|
|||
|
1395d65b76
|
|||
|
eb4942e0ed
|
|||
|
f254cfa81e
|
|||
|
4927795260
|
|||
|
e4019dadc8
|
|||
|
5e7d77e1a1
|
|||
|
bfcbed035c
|
|||
|
5ebefae961
|
|||
|
d4758674bb
|
|||
|
f5f1ddc0ea
|
|||
|
2720b59485
|
|||
|
29b1ac7fce
|
|||
|
83ca5551ad
|
|||
| 611cb024a9 | |||
|
74fb56891d
|
|||
|
ac4fa5eb85
|
|||
|
8857718709
|
|||
|
dd17b2b9c1
|
|||
|
848439f664
|
|||
|
f83117424d
|
|||
|
8c19c32c76
|
|||
|
d62b2bed80
|
|||
|
5a23eb1768
|
|||
|
5f6e4763d3
|
|||
|
580c36fb89
|
|||
|
6c25af3b30
|
|||
|
a1da72d447
|
|||
|
ab4120cc22
|
|||
|
52eff0fa25
|
|||
|
beeb28abf2
|
|||
|
c0ab3837ac
|
|||
|
59d38c0d8d
|
|||
|
bd2247ce86
|
|||
|
da2d3f7f17
|
|||
|
7497b77384
|
|||
|
f542d9fa97
|
|||
|
e70439870e
|
|||
|
d764b042fe
|
|||
|
a76b97d1d2
|
|||
|
cfbe6e580b
|
|||
|
f08b9e057f
|
|||
|
0509f37c96
|
|||
|
a7dc9ac6fa
|
|||
|
caf2f5f1f6
|
|||
|
12b79af3a2
|
|||
|
88f149584e
|
|||
|
877001b802
|
|||
| fec28f6223 | |||
| 85005ff9c3 | |||
| e3c92a3c55 | |||
| 9e9fbc5d6a | |||
| 8d1d836b52 | |||
| bc60ce5d42 | |||
| c093123e3a | |||
| 3de73538c7 | |||
| ba8d5cee09 | |||
|
5ee2e70442
|
|||
|
53a3a32907
|
|||
|
9a628779d9
|
|||
|
b60bd63d0c
|
|||
|
01cc71fd47
|
|||
|
a2b0cd0b6a
|
|||
|
7f971bcee3
|
|||
|
7de98a1731
|
|||
|
b52eb95b14
|
|||
|
b3ef7d6ad0
|
|||
|
d28c11940d
|
|||
|
504322c2dd
|
|||
|
a07ec3ca36
|
|||
| d96691e920 | |||
|
6273b2d917
|
|||
|
ab90d244b5
|
|||
|
dc6af6d9e5
|
|||
|
0ca801d963
|
|||
|
3edcdd72af
|
|||
|
402bb3fe04
|
|||
|
8ba55eb1be
|
@@ -62,3 +62,9 @@ If you want to build the release version, use the flutter build command. Learn m
|
|||||||
```bash
|
```bash
|
||||||
flutter build <platform>
|
flutter build <platform>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Known Issues
|
||||||
|
|
||||||
|
Due to the issues with the flutter build tools, [see](https://github.com/flutter/flutter/issues/160622).
|
||||||
|
|
||||||
|
Since there is a watchOS app for iOS, you're unable to use the flutter cli to run iOS app. Use xcode instead.
|
||||||
@@ -43,6 +43,16 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
|
<!-- App protocol -->
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<!-- Accepts URIs that begin with YOUR_SCHEME://YOUR_HOST -->
|
||||||
|
<data android:scheme="solian" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
<!-- Deeplinking -->
|
<!-- Deeplinking -->
|
||||||
<intent-filter android:autoVerify="true">
|
<intent-filter android:autoVerify="true">
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|||||||
@@ -136,6 +136,7 @@
|
|||||||
"reactionNegative": "Negative",
|
"reactionNegative": "Negative",
|
||||||
"reactionNeutral": "Neutral",
|
"reactionNeutral": "Neutral",
|
||||||
"customReaction": "Custom Reaction",
|
"customReaction": "Custom Reaction",
|
||||||
|
"customReactionHint": "Custom Reaction allow you to use user uploaded stickers as the symbol of the reaction for the post. Exclusive for Stellar Program members.",
|
||||||
"customReactions": "Custom Reactions",
|
"customReactions": "Custom Reactions",
|
||||||
"stickerPlaceholder": "Sticker Placeholder",
|
"stickerPlaceholder": "Sticker Placeholder",
|
||||||
"reactionAttitude": "Reaction Attitude",
|
"reactionAttitude": "Reaction Attitude",
|
||||||
@@ -162,6 +163,8 @@
|
|||||||
"accountConnectionProviderGithub": "GitHub",
|
"accountConnectionProviderGithub": "GitHub",
|
||||||
"accountConnectionProviderDiscord": "Discord",
|
"accountConnectionProviderDiscord": "Discord",
|
||||||
"accountConnectionProviderAfdian": "Afdian",
|
"accountConnectionProviderAfdian": "Afdian",
|
||||||
|
"accountConnectionProviderSpotify": "Spotify",
|
||||||
|
"accountConnectionProviderSteam": "Steam",
|
||||||
"checkIn": "Check In",
|
"checkIn": "Check In",
|
||||||
"checkInNone": "Not checked-in yet",
|
"checkInNone": "Not checked-in yet",
|
||||||
"checkInNoneHint": "Get your fortune tips and daily rewards by checking in.",
|
"checkInNoneHint": "Get your fortune tips and daily rewards by checking in.",
|
||||||
@@ -177,6 +180,7 @@
|
|||||||
"noFortuneData": "No fortune data available for this month.",
|
"noFortuneData": "No fortune data available for this month.",
|
||||||
"creatorHub": "Creator Hub",
|
"creatorHub": "Creator Hub",
|
||||||
"creatorHubDescription": "Manage posts, analytics, and more.",
|
"creatorHubDescription": "Manage posts, analytics, and more.",
|
||||||
|
"publicationSites": "Publication Sites",
|
||||||
"developerPortal": "Developer Portal",
|
"developerPortal": "Developer Portal",
|
||||||
"developerPortalDescription": "Build with Solar Network™.",
|
"developerPortalDescription": "Build with Solar Network™.",
|
||||||
"statusCreateHint": "What's on your mind? Add a status.",
|
"statusCreateHint": "What's on your mind? Add a status.",
|
||||||
@@ -229,6 +233,9 @@
|
|||||||
"pickFile": "Pick a file",
|
"pickFile": "Pick a file",
|
||||||
"uploading": "Uploading",
|
"uploading": "Uploading",
|
||||||
"uploadingProgress": "Uploading {} of {}",
|
"uploadingProgress": "Uploading {} of {}",
|
||||||
|
"upload": "Upload",
|
||||||
|
"uploadSuccess": "Upload successful!",
|
||||||
|
"wouldYouLikeToViewFile": "Would you like to view the file?",
|
||||||
"uploadAll": "Upload All",
|
"uploadAll": "Upload All",
|
||||||
"stickerCopyPlaceholder": "Copy Placeholder",
|
"stickerCopyPlaceholder": "Copy Placeholder",
|
||||||
"realmSelection": "Select a Realm",
|
"realmSelection": "Select a Realm",
|
||||||
@@ -469,6 +476,7 @@
|
|||||||
"pronouns": "Pronouns",
|
"pronouns": "Pronouns",
|
||||||
"location": "Location",
|
"location": "Location",
|
||||||
"timeZone": "Time Zone",
|
"timeZone": "Time Zone",
|
||||||
|
"timezoneNotFound": "Time zone not found",
|
||||||
"birthday": "Birthday",
|
"birthday": "Birthday",
|
||||||
"selectADate": "Select a date",
|
"selectADate": "Select a date",
|
||||||
"checkInResultT0": "Worst",
|
"checkInResultT0": "Worst",
|
||||||
@@ -1084,6 +1092,7 @@
|
|||||||
"levelingStage10": "Immortal",
|
"levelingStage10": "Immortal",
|
||||||
"levelingStage11": "Divine",
|
"levelingStage11": "Divine",
|
||||||
"levelingStage12": "Transcendent",
|
"levelingStage12": "Transcendent",
|
||||||
|
"uploadTasks": "Upload Tasks",
|
||||||
"uploadAttachment": "Upload Attachment",
|
"uploadAttachment": "Upload Attachment",
|
||||||
"attachmentPreview": "Attachment Preview",
|
"attachmentPreview": "Attachment Preview",
|
||||||
"selectPool": "Select Pool",
|
"selectPool": "Select Pool",
|
||||||
@@ -1104,7 +1113,6 @@
|
|||||||
"deleteRecycledFiles": "Delete Recycled Files",
|
"deleteRecycledFiles": "Delete Recycled Files",
|
||||||
"recycledFilesDeleted": "Recycled files deleted successfully",
|
"recycledFilesDeleted": "Recycled files deleted successfully",
|
||||||
"failedToDeleteRecycledFiles": "Failed to delete recycled files",
|
"failedToDeleteRecycledFiles": "Failed to delete recycled files",
|
||||||
"upload": "Upload",
|
|
||||||
"updateAvailable": "Update available",
|
"updateAvailable": "Update available",
|
||||||
"noChangelogProvided": "No changelog provided.",
|
"noChangelogProvided": "No changelog provided.",
|
||||||
"useSecondarySourceForDownload": "Use secondary source for download",
|
"useSecondarySourceForDownload": "Use secondary source for download",
|
||||||
@@ -1298,9 +1306,173 @@
|
|||||||
"thoughtInputHint": "Ask sn-chan anything...",
|
"thoughtInputHint": "Ask sn-chan anything...",
|
||||||
"thoughtNewConversation": "Start New Conversation",
|
"thoughtNewConversation": "Start New Conversation",
|
||||||
"thoughtParseError": "Failed to parse AI response",
|
"thoughtParseError": "Failed to parse AI response",
|
||||||
"thoughtFunctionCall": "Function Call",
|
"thoughtFunctionCall": "Use {}",
|
||||||
|
"thoughtFunctionCallBegin": "Calling tool {}",
|
||||||
|
"thoughtFunctionCallFinish": "{} responded",
|
||||||
"aiThought": "AI Thought",
|
"aiThought": "AI Thought",
|
||||||
"aiThoughtTitle": "Let sn-chan think",
|
"aiThoughtTitle": "Let sn-chan think",
|
||||||
"postReferenceUnavailable": "Referenced post is unavailable",
|
"postReferenceUnavailable": "Referenced post is unavailable",
|
||||||
"fabLocation": "FAB Location"
|
"fabLocation": "FAB Location",
|
||||||
|
"activities": "Activities",
|
||||||
|
"presenceTypeGaming": "Playing",
|
||||||
|
"presenceTypeMusic": "Listening to Music",
|
||||||
|
"presenceTypeWorkout": "Working out",
|
||||||
|
"articleCompose": "Compose Article",
|
||||||
|
"backToHub": "Back to Hub",
|
||||||
|
"advancedFilters": "Advanced Filters",
|
||||||
|
"searchPosts": "Search Posts",
|
||||||
|
"sortBy": "Sort by",
|
||||||
|
"fromDate": "From Date",
|
||||||
|
"toDate": "To Date",
|
||||||
|
"popularity": "Popularity",
|
||||||
|
"descendingOrder": "Descending Order",
|
||||||
|
"selectDate": "Select Date",
|
||||||
|
"pinnedPosts": "Pinned Posts",
|
||||||
|
"thoughtUnpaidHint": "Thinking unavaiable due to unpaid orders",
|
||||||
|
"more": "More",
|
||||||
|
"collapse": "Collapse",
|
||||||
|
"pollConfirmDiscard": "Are you sure you want to leave? All the poll data you're editing will not be saved.",
|
||||||
|
"discard": "Discard",
|
||||||
|
"fund": "Fund",
|
||||||
|
"fundsRecent": "Recent Funds",
|
||||||
|
"fundCreateNew": "Create New",
|
||||||
|
"fundCreateNewHint": "Create a new fund for your message. Select recipients and amount.",
|
||||||
|
"amountOfSplits": "Amount of Splits",
|
||||||
|
"enterNumberOfSplits": "Enter Splits Amount",
|
||||||
|
"orCreateWith": "Or\ncreate with",
|
||||||
|
"unindexedFiles": "Unindexed files",
|
||||||
|
"folder": "Folder",
|
||||||
|
"clearCompleted": "Clear Completed",
|
||||||
|
"contentCantEmpty": "Content cannot be empty",
|
||||||
|
"features": "Features",
|
||||||
|
"unnamed": "Unnamed",
|
||||||
|
"fundEnvelopeLoadFailed": "Failed to load fund envelope",
|
||||||
|
"fundEnvelope": "Fund Envelope",
|
||||||
|
"fundEnvelopeRemaining": "Remaining: {} {}",
|
||||||
|
"fundEnvelopeSplit": "Split: {}",
|
||||||
|
"fundEnvelopeSplitEvenly": "Evenly",
|
||||||
|
"fundEnvelopeSplitRandomly": "Randomly",
|
||||||
|
"fundEnvelopeClaimSuccess": "Fund claimed successfully!",
|
||||||
|
"fundEnvelopeStatusCreated": "Created",
|
||||||
|
"fundEnvelopeStatusPartial": "Partially Claimed",
|
||||||
|
"fundEnvelopeStatusCompleted": "Fully Claimed",
|
||||||
|
"fundEnvelopeStatusExpired": "Expired",
|
||||||
|
"fundEnvelopeStatusUnknown": "Unknown",
|
||||||
|
"fundEnvelopeRecipients": "Recipients ({}/{} claimed)",
|
||||||
|
"fundEnvelopeExpiredDaysAgo": {
|
||||||
|
"one": "Expired {} day ago",
|
||||||
|
"other": "Expired {} days ago"
|
||||||
|
},
|
||||||
|
"fundEnvelopeExpiresSoon": "Expires soon",
|
||||||
|
"fundEnvelopeExpiresInHours": {
|
||||||
|
"one": "Expires in {} hour",
|
||||||
|
"other": "Expires in {} hours"
|
||||||
|
},
|
||||||
|
"fundEnvelopeExpiresInDays": {
|
||||||
|
"one": "Expires in {} day",
|
||||||
|
"other": "Expires in {} days"
|
||||||
|
},
|
||||||
|
"fundEnvelopeRemainingWithSplits": "{} {} / {} splits",
|
||||||
|
"fundEnvelopeUnknownUser": "Unknown User",
|
||||||
|
"deleteSite": "Delete Site",
|
||||||
|
"deleteSiteConfirm": "Are you sure you want to delete this site?",
|
||||||
|
"siteDeletedSuccess": "Site deleted successfully",
|
||||||
|
"siteSlug": "Slug",
|
||||||
|
"siteSlugHint": "my-site",
|
||||||
|
"siteSlugRequired": "Please enter a slug",
|
||||||
|
"siteSlugInvalid": "Slug can only contain lowercase letters, numbers, and dashes",
|
||||||
|
"siteName": "Site Name",
|
||||||
|
"siteNameHint": "My Publication Site",
|
||||||
|
"siteNameRequired": "Please enter a site name",
|
||||||
|
"siteMode": "Mode",
|
||||||
|
"siteModeFullyManaged": "Fully Managed",
|
||||||
|
"siteModeSelfManaged": "Self-Managed",
|
||||||
|
"editPublicationSite": "Edit Publication Site",
|
||||||
|
"deletePublicationSite": "Delete Publication Site",
|
||||||
|
"publicationSiteSavedSuccess": "Publication site saved successfully",
|
||||||
|
"publicationSiteDeleteConfirm": "Are you sure you want to delete this publication site? This action cannot be undone.",
|
||||||
|
"publicationSiteDeletedSuccess": "Publication site deleted successfully",
|
||||||
|
"newPublicationSite": "New Publication Site",
|
||||||
|
"siteDetails": "Site Details",
|
||||||
|
"siteInformation": "Site Information",
|
||||||
|
"siteDomain": "Domain",
|
||||||
|
"siteCreated": "Created",
|
||||||
|
"siteUpdated": "Updated",
|
||||||
|
"failedToLoadSite": "Failed to load site",
|
||||||
|
"sitePages": "Pages",
|
||||||
|
"noPagesYet": "No pages yet",
|
||||||
|
"createFirstPage": "Create your first page to get started",
|
||||||
|
"failedToLoadPages": "Failed to load pages",
|
||||||
|
"fileManagement": "File Management",
|
||||||
|
"siteFiles": "Files",
|
||||||
|
"siteFolder": "Folder",
|
||||||
|
"siteRoot": "Root",
|
||||||
|
"noFilesUploadedYet": "No files uploaded yet",
|
||||||
|
"uploadFirstFile": "Upload your first file to get started",
|
||||||
|
"failedToLoadFiles": "Failed to load files",
|
||||||
|
"noFilesFoundInFolder": "No files found in the selected folder",
|
||||||
|
"fileActions": "File Actions",
|
||||||
|
"purgeFiles": "Purge Files",
|
||||||
|
"purgeFilesDescription": "Remove all uploaded files from the site",
|
||||||
|
"deploySite": "Deploy Site",
|
||||||
|
"deploySiteDescription": "Upload and deploy a new version from ZIP archive",
|
||||||
|
"confirmPurge": "Confirm Purge",
|
||||||
|
"purgeFilesConfirm": "This will permanently delete all files uploaded to this site. This action cannot be undone. Are you sure you want to continue?",
|
||||||
|
"purgeAllFiles": "Purge All Files",
|
||||||
|
"allFilesPurgedSuccess": "All files purged successfully",
|
||||||
|
"failedToPurgeFiles": "Failed to purge files: {}",
|
||||||
|
"siteDeployedSuccess": "Site deployed successfully",
|
||||||
|
"failedToDeploySite": "Failed to deploy site: {}",
|
||||||
|
"createPage": "Create Page",
|
||||||
|
"editPage": "Edit Page",
|
||||||
|
"pageType": "Page Type",
|
||||||
|
"htmlPage": "HTML Page",
|
||||||
|
"redirectPage": "Redirect Page",
|
||||||
|
"pageTypeRequired": "Please select a page type",
|
||||||
|
"pagePath": "Page Path",
|
||||||
|
"pagePathHint": "/about, /contact, etc.",
|
||||||
|
"pagePathRequired": "Please enter a page path",
|
||||||
|
"pagePathInvalid": "Page path can only contain letters, numbers, hyphens, underscores, and slashes",
|
||||||
|
"pagePathMustStartWithSlash": "Page path must start with /",
|
||||||
|
"pagePathNoConsecutiveSlashes": "Page path cannot have consecutive slashes",
|
||||||
|
"pageTitle": "Page Title",
|
||||||
|
"pageTitleHint": "About Us, Contact, etc.",
|
||||||
|
"pageTitleRequired": "Please enter a page title",
|
||||||
|
"pageContentHtml": "Page Content (HTML)",
|
||||||
|
"pageContentHint": "<h1>Hello World</h1><p>This is my page content...</p>",
|
||||||
|
"pageContentRequired": "Please enter HTML content for the page",
|
||||||
|
"redirectTarget": "Redirect Target",
|
||||||
|
"redirectTargetHint": "/new-page, https://example.com, etc.",
|
||||||
|
"redirectTargetRequired": "Please enter a redirect target",
|
||||||
|
"redirectTargetInvalid": "Target must be a relative path (/) or absolute URL (http/https)",
|
||||||
|
"deletePage": "Delete Page",
|
||||||
|
"deletePageConfirm": "Are you sure you want to delete this page?",
|
||||||
|
"savePage": "Save Page",
|
||||||
|
"pageCreatedSuccess": "Page created successfully",
|
||||||
|
"pageUpdatedSuccess": "Page updated successfully",
|
||||||
|
"pageDeletedSuccess": "Page deleted successfully",
|
||||||
|
"uploadFiles": "Upload Files",
|
||||||
|
"uploadPath": "Upload Path",
|
||||||
|
"uploadPathHint": "/ (root) or /assets/images/",
|
||||||
|
"uploadPathRequired": "Please enter an upload path",
|
||||||
|
"uploadPathMustStartWithSlash": "Path must start with /",
|
||||||
|
"uploadPathNoSpaces": "Path cannot contain spaces",
|
||||||
|
"uploadPathNoConsecutiveSlashes": "Path cannot have consecutive slashes",
|
||||||
|
"percentCompleted": "{}% completed",
|
||||||
|
"filesToUpload": "{} files to upload",
|
||||||
|
"fileSizeKb": "Size: {} KB",
|
||||||
|
"uploadingEllipsis": "Uploading...",
|
||||||
|
"uploadFilesCount": {
|
||||||
|
"one": "Upload {} File",
|
||||||
|
"other": "Upload {} Files"
|
||||||
|
},
|
||||||
|
"allUploadsCompleted": "All uploads completed",
|
||||||
|
"someUploadsFailed": "Some uploads failed",
|
||||||
|
"uploadingInProgress": "Uploading in progress",
|
||||||
|
"readyToUpload": "Ready to upload",
|
||||||
|
"allFilesUploadedSuccess": "All files uploaded successfully",
|
||||||
|
"lotteryLastNumberSpecial": "The last selected number will be your special number.",
|
||||||
|
"lotteryMultiplierRequired": "Please enter a multiplier",
|
||||||
|
"lotteryMultiplierRange": "Multiplier must be between 1 and 10",
|
||||||
|
"dropToShare": "Drop to share"
|
||||||
}
|
}
|
||||||
@@ -158,11 +158,11 @@
|
|||||||
"checkIn": "签到",
|
"checkIn": "签到",
|
||||||
"checkInNone": "尚未签到",
|
"checkInNone": "尚未签到",
|
||||||
"checkInNoneHint": "通过签到获取您的财富提示和每日奖励。",
|
"checkInNoneHint": "通过签到获取您的财富提示和每日奖励。",
|
||||||
"checkInResultLevel0": "最差运气",
|
"checkInResultLevel0": "大凶",
|
||||||
"checkInResultLevel1": "坏运气",
|
"checkInResultLevel1": "凶",
|
||||||
"checkInResultLevel2": "一个普通的日常",
|
"checkInResultLevel2": "中平",
|
||||||
"checkInResultLevel3": "好运",
|
"checkInResultLevel3": "吉",
|
||||||
"checkInResultLevel4": "最佳运气",
|
"checkInResultLevel4": "大吉",
|
||||||
"checkInActivityTitle": "{} 在 {} 签到并获得了 {}",
|
"checkInActivityTitle": "{} 在 {} 签到并获得了 {}",
|
||||||
"eventCalander": "活动日历",
|
"eventCalander": "活动日历",
|
||||||
"eventCalanderEmpty": "该日无活动。",
|
"eventCalanderEmpty": "该日无活动。",
|
||||||
@@ -251,10 +251,10 @@
|
|||||||
"translatorBadgeName": "翻译者",
|
"translatorBadgeName": "翻译者",
|
||||||
"translatorBadgeDescription": "协助将 Solar Network 翻译成不同语言",
|
"translatorBadgeDescription": "协助将 Solar Network 翻译成不同语言",
|
||||||
"wallet": "钱包",
|
"wallet": "钱包",
|
||||||
"walletCurrencyPoints": "新太阳点",
|
"walletCurrencyPoints": "源能点",
|
||||||
"walletCurrencyShortPoints": "NSP",
|
"walletCurrencyShortPoints": "NSP",
|
||||||
"walletCurrencyGolds": "太阳币",
|
"walletCurrencyGolds": "星辰碎片",
|
||||||
"walletCurrencyShortGolds": "TSD",
|
"walletCurrencyShortGolds": "SHD",
|
||||||
"retry": "重试",
|
"retry": "重试",
|
||||||
"creatorHubUnselectedHint": "选择/创建一个发布者以开始使用。",
|
"creatorHubUnselectedHint": "选择/创建一个发布者以开始使用。",
|
||||||
"relationships": "关系",
|
"relationships": "关系",
|
||||||
@@ -344,7 +344,7 @@
|
|||||||
"accountSettingsHelpContent": "此页面允许您管理您的帐户安全性、隐私和其他设置。如果您需要帮助,请联系管理员。",
|
"accountSettingsHelpContent": "此页面允许您管理您的帐户安全性、隐私和其他设置。如果您需要帮助,请联系管理员。",
|
||||||
"unauthorized": "未授权",
|
"unauthorized": "未授权",
|
||||||
"unauthorizedHint": "您未登录或会话已过期,请重新登录。",
|
"unauthorizedHint": "您未登录或会话已过期,请重新登录。",
|
||||||
"publisherBelongsTo": "属于",
|
"publisherBelongsTo": "属于 {}",
|
||||||
"postContent": "内容",
|
"postContent": "内容",
|
||||||
"postSettings": "设置",
|
"postSettings": "设置",
|
||||||
"postPublisherUnselected": "未指定发布者",
|
"postPublisherUnselected": "未指定发布者",
|
||||||
@@ -585,10 +585,10 @@
|
|||||||
"unknownChat": "未知聊天",
|
"unknownChat": "未知聊天",
|
||||||
"addAdditionalMessage": "添加附加消息……",
|
"addAdditionalMessage": "添加附加消息……",
|
||||||
"uploadingFiles": "上传文件中……",
|
"uploadingFiles": "上传文件中……",
|
||||||
"sharedSuccessfully": "分享成功!",
|
"sharedSuccessfully": "分享成功",
|
||||||
"shareSuccess": "分享成功!",
|
"shareSuccess": "分享成功",
|
||||||
"shareToSpecificChatSuccess": "成功分享至 {}!",
|
"shareToSpecificChatSuccess": "成功分享至 {}",
|
||||||
"wouldYouLikeToGoToChat": "是否前往该聊天?",
|
"wouldYouLikeToGoToChat": "是否前往该聊天页面?",
|
||||||
"no": "否",
|
"no": "否",
|
||||||
"yes": "是",
|
"yes": "是",
|
||||||
"navigateToChat": "前往聊天",
|
"navigateToChat": "前往聊天",
|
||||||
@@ -1090,5 +1090,6 @@
|
|||||||
"thoughtNewConversation": "开始新对话",
|
"thoughtNewConversation": "开始新对话",
|
||||||
"thoughtParseError": "解析 AI 响应失败",
|
"thoughtParseError": "解析 AI 响应失败",
|
||||||
"aiThought": "寻思",
|
"aiThought": "寻思",
|
||||||
"aiThoughtTitle": "让 SN 酱寻思寻思"
|
"aiThoughtTitle": "让 SN 酱寻思寻思",
|
||||||
|
"thoughtUnpaidHint": "寻思因为有未支付的订单而被禁用"
|
||||||
}
|
}
|
||||||
BIN
assets/icons/icon-tray.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
assets/images/oidc/spotify.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
1
assets/images/oidc/steam.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg width="2471" height="2500" viewBox="0 0 256 259" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid"><path d="M127.779 0C60.42 0 5.24 52.412 0 119.014l68.724 28.674a35.812 35.812 0 0 1 20.426-6.366c.682 0 1.356.019 2.02.056l30.566-44.71v-.626c0-26.903 21.69-48.796 48.353-48.796 26.662 0 48.352 21.893 48.352 48.796 0 26.902-21.69 48.804-48.352 48.804-.37 0-.73-.009-1.098-.018l-43.593 31.377c.028.582.046 1.163.046 1.735 0 20.204-16.283 36.636-36.294 36.636-17.566 0-32.263-12.658-35.584-29.412L4.41 164.654c15.223 54.313 64.673 94.132 123.369 94.132 70.818 0 128.221-57.938 128.221-129.393C256 57.93 198.597 0 127.779 0zM80.352 196.332l-15.749-6.568c2.787 5.867 7.621 10.775 14.033 13.47 13.857 5.83 29.836-.803 35.612-14.799a27.555 27.555 0 0 0 .046-21.035c-2.768-6.79-7.999-12.086-14.706-14.909-6.67-2.795-13.811-2.694-20.085-.304l16.275 6.79c10.222 4.3 15.056 16.145 10.794 26.46-4.253 10.314-15.998 15.195-26.22 10.895zm121.957-100.29c0-17.925-14.457-32.52-32.217-32.52-17.769 0-32.226 14.595-32.226 32.52 0 17.926 14.457 32.512 32.226 32.512 17.76 0 32.217-14.586 32.217-32.512zm-56.37-.055c0-13.488 10.84-24.42 24.2-24.42 13.368 0 24.208 10.932 24.208 24.42 0 13.488-10.84 24.421-24.209 24.421-13.359 0-24.2-10.933-24.2-24.42z" fill="#1A1918"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -1,3 +1,6 @@
|
|||||||
description: This file stores settings for Dart & Flutter DevTools.
|
description: This file stores settings for Dart & Flutter DevTools.
|
||||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||||
extensions:
|
extensions:
|
||||||
|
- drift: true
|
||||||
|
- provider: true
|
||||||
|
- shared_preferences: true
|
||||||
1
drift_schemas/app_database/drift_schema_v7.json
Normal file
10
ios/Podfile
@@ -1,3 +1,5 @@
|
|||||||
|
platform :ios, '15.0'
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
|
||||||
@@ -25,12 +27,12 @@ require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelpe
|
|||||||
flutter_ios_podfile_setup
|
flutter_ios_podfile_setup
|
||||||
|
|
||||||
target 'Runner' do
|
target 'Runner' do
|
||||||
platform :ios, '15.0'
|
|
||||||
|
|
||||||
use_frameworks!
|
use_frameworks!
|
||||||
use_modular_headers!
|
use_modular_headers!
|
||||||
|
|
||||||
pod 'Alamofire'
|
pod 'Alamofire'
|
||||||
|
pod 'Kingfisher', '~> 8.0'
|
||||||
|
pod 'KingfisherWebP'
|
||||||
|
|
||||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||||
|
|
||||||
@@ -40,8 +42,6 @@ target 'Runner' do
|
|||||||
|
|
||||||
target 'SolianNotificationService' do
|
target 'SolianNotificationService' do
|
||||||
inherit! :search_paths
|
inherit! :search_paths
|
||||||
pod 'Kingfisher', '~> 8.0'
|
|
||||||
pod 'Alamofire'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
target 'SolianShareExtension' do
|
target 'SolianShareExtension' do
|
||||||
@@ -49,7 +49,7 @@ target 'Runner' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
target 'WatchRunner Watch App' do
|
target 'Solian Watch App' do
|
||||||
platform :watchos, '11.0'
|
platform :watchos, '11.0'
|
||||||
|
|
||||||
use_frameworks!
|
use_frameworks!
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
PODS:
|
PODS:
|
||||||
- Alamofire (5.10.2)
|
- Alamofire (5.10.2)
|
||||||
- app_links (6.4.1):
|
|
||||||
- Flutter
|
|
||||||
- connectivity_plus (0.0.1):
|
- connectivity_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- croppy (0.0.1):
|
- croppy (0.0.1):
|
||||||
@@ -52,18 +50,18 @@ PODS:
|
|||||||
- Firebase/Messaging (12.4.0):
|
- Firebase/Messaging (12.4.0):
|
||||||
- Firebase/CoreOnly
|
- Firebase/CoreOnly
|
||||||
- FirebaseMessaging (~> 12.4.0)
|
- FirebaseMessaging (~> 12.4.0)
|
||||||
- firebase_analytics (12.0.3):
|
- firebase_analytics (12.0.4):
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- FirebaseAnalytics (= 12.4.0)
|
- FirebaseAnalytics (= 12.4.0)
|
||||||
- Flutter
|
- Flutter
|
||||||
- firebase_core (4.2.0):
|
- firebase_core (4.2.1):
|
||||||
- Firebase/CoreOnly (= 12.4.0)
|
- Firebase/CoreOnly (= 12.4.0)
|
||||||
- Flutter
|
- Flutter
|
||||||
- firebase_crashlytics (5.0.3):
|
- firebase_crashlytics (5.0.5):
|
||||||
- Firebase/Crashlytics (= 12.4.0)
|
- Firebase/Crashlytics (= 12.4.0)
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- Flutter
|
- Flutter
|
||||||
- firebase_messaging (16.0.3):
|
- firebase_messaging (16.0.4):
|
||||||
- Firebase/Messaging (= 12.4.0)
|
- Firebase/Messaging (= 12.4.0)
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- Flutter
|
- Flutter
|
||||||
@@ -142,15 +140,13 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- flutter_native_splash (2.4.3):
|
- flutter_native_splash (2.4.3):
|
||||||
- Flutter
|
- Flutter
|
||||||
- flutter_platform_alert (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
- flutter_secure_storage (6.0.0):
|
- flutter_secure_storage (6.0.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- flutter_timezone (0.0.1):
|
- flutter_timezone (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- flutter_udid (0.0.1):
|
- flutter_udid (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- SAMKeychain
|
- KeychainAccess
|
||||||
- flutter_webrtc (1.2.0):
|
- flutter_webrtc (1.2.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- WebRTC-SDK (= 137.7151.04)
|
- WebRTC-SDK (= 137.7151.04)
|
||||||
@@ -218,7 +214,8 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- irondash_engine_context (0.0.1):
|
- irondash_engine_context (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- Kingfisher (8.6.0)
|
- KeychainAccess (4.2.2)
|
||||||
|
- Kingfisher (8.6.2)
|
||||||
- KingfisherWebP (1.7.2):
|
- KingfisherWebP (1.7.2):
|
||||||
- Kingfisher (~> 8.0)
|
- Kingfisher (~> 8.0)
|
||||||
- libwebp (>= 1.1.0)
|
- libwebp (>= 1.1.0)
|
||||||
@@ -252,24 +249,24 @@ PODS:
|
|||||||
- nanopb/encode (3.30910.0)
|
- nanopb/encode (3.30910.0)
|
||||||
- native_exif (0.0.1):
|
- native_exif (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- objective_c (0.0.1):
|
||||||
|
- Flutter
|
||||||
- OrderedSet (6.0.3)
|
- OrderedSet (6.0.3)
|
||||||
- package_info_plus (0.4.5):
|
- package_info_plus (0.4.5):
|
||||||
- Flutter
|
- Flutter
|
||||||
- pasteboard (0.0.1):
|
- pasteboard (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- path_provider_foundation (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
- FlutterMacOS
|
|
||||||
- pointer_interceptor_ios (0.0.1):
|
- pointer_interceptor_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- PromisesObjC (2.4.0)
|
- PromisesObjC (2.4.0)
|
||||||
- PromisesSwift (2.4.0):
|
- PromisesSwift (2.4.0):
|
||||||
- PromisesObjC (= 2.4.0)
|
- PromisesObjC (= 2.4.0)
|
||||||
|
- protocol_handler_ios (0.0.1):
|
||||||
|
- Flutter
|
||||||
- receive_sharing_intent (1.8.1):
|
- receive_sharing_intent (1.8.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- record_ios (1.1.0):
|
- record_ios (1.1.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- SAMKeychain (1.5.3)
|
|
||||||
- SDWebImage (5.21.3):
|
- SDWebImage (5.21.3):
|
||||||
- SDWebImage/Core (= 5.21.3)
|
- SDWebImage/Core (= 5.21.3)
|
||||||
- SDWebImage/Core (5.21.3)
|
- SDWebImage/Core (5.21.3)
|
||||||
@@ -315,15 +312,12 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- url_launcher_ios (0.0.1):
|
- url_launcher_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- volume_controller (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
- wakelock_plus (0.0.1):
|
- wakelock_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- WebRTC-SDK (137.7151.04)
|
- WebRTC-SDK (137.7151.04)
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- Alamofire
|
- Alamofire
|
||||||
- app_links (from `.symlinks/plugins/app_links/ios`)
|
|
||||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||||
- croppy (from `.symlinks/plugins/croppy/ios`)
|
- croppy (from `.symlinks/plugins/croppy/ios`)
|
||||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||||
@@ -339,7 +333,6 @@ DEPENDENCIES:
|
|||||||
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
|
||||||
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||||
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
||||||
- flutter_platform_alert (from `.symlinks/plugins/flutter_platform_alert/ios`)
|
|
||||||
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
||||||
- flutter_timezone (from `.symlinks/plugins/flutter_timezone/ios`)
|
- flutter_timezone (from `.symlinks/plugins/flutter_timezone/ios`)
|
||||||
- flutter_udid (from `.symlinks/plugins/flutter_udid/ios`)
|
- flutter_udid (from `.symlinks/plugins/flutter_udid/ios`)
|
||||||
@@ -354,10 +347,11 @@ DEPENDENCIES:
|
|||||||
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
|
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
|
||||||
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
|
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
|
||||||
- native_exif (from `.symlinks/plugins/native_exif/ios`)
|
- native_exif (from `.symlinks/plugins/native_exif/ios`)
|
||||||
|
- objective_c (from `.symlinks/plugins/objective_c/ios`)
|
||||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||||
- pasteboard (from `.symlinks/plugins/pasteboard/ios`)
|
- pasteboard (from `.symlinks/plugins/pasteboard/ios`)
|
||||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
|
||||||
- pointer_interceptor_ios (from `.symlinks/plugins/pointer_interceptor_ios/ios`)
|
- pointer_interceptor_ios (from `.symlinks/plugins/pointer_interceptor_ios/ios`)
|
||||||
|
- protocol_handler_ios (from `.symlinks/plugins/protocol_handler_ios/ios`)
|
||||||
- receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
|
- receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
|
||||||
- record_ios (from `.symlinks/plugins/record_ios/ios`)
|
- record_ios (from `.symlinks/plugins/record_ios/ios`)
|
||||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||||
@@ -368,7 +362,6 @@ DEPENDENCIES:
|
|||||||
- super_native_extensions (from `.symlinks/plugins/super_native_extensions/ios`)
|
- super_native_extensions (from `.symlinks/plugins/super_native_extensions/ios`)
|
||||||
- syncfusion_flutter_pdfviewer (from `.symlinks/plugins/syncfusion_flutter_pdfviewer/ios`)
|
- syncfusion_flutter_pdfviewer (from `.symlinks/plugins/syncfusion_flutter_pdfviewer/ios`)
|
||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
- volume_controller (from `.symlinks/plugins/volume_controller/ios`)
|
|
||||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
@@ -390,6 +383,7 @@ SPEC REPOS:
|
|||||||
- GoogleAppMeasurement
|
- GoogleAppMeasurement
|
||||||
- GoogleDataTransport
|
- GoogleDataTransport
|
||||||
- GoogleUtilities
|
- GoogleUtilities
|
||||||
|
- KeychainAccess
|
||||||
- Kingfisher
|
- Kingfisher
|
||||||
- KingfisherWebP
|
- KingfisherWebP
|
||||||
- libwebp
|
- libwebp
|
||||||
@@ -397,15 +391,12 @@ SPEC REPOS:
|
|||||||
- OrderedSet
|
- OrderedSet
|
||||||
- PromisesObjC
|
- PromisesObjC
|
||||||
- PromisesSwift
|
- PromisesSwift
|
||||||
- SAMKeychain
|
|
||||||
- SDWebImage
|
- SDWebImage
|
||||||
- sqlite3
|
- sqlite3
|
||||||
- SwiftyGif
|
- SwiftyGif
|
||||||
- WebRTC-SDK
|
- WebRTC-SDK
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
app_links:
|
|
||||||
:path: ".symlinks/plugins/app_links/ios"
|
|
||||||
connectivity_plus:
|
connectivity_plus:
|
||||||
:path: ".symlinks/plugins/connectivity_plus/ios"
|
:path: ".symlinks/plugins/connectivity_plus/ios"
|
||||||
croppy:
|
croppy:
|
||||||
@@ -436,8 +427,6 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/flutter_local_notifications/ios"
|
:path: ".symlinks/plugins/flutter_local_notifications/ios"
|
||||||
flutter_native_splash:
|
flutter_native_splash:
|
||||||
:path: ".symlinks/plugins/flutter_native_splash/ios"
|
:path: ".symlinks/plugins/flutter_native_splash/ios"
|
||||||
flutter_platform_alert:
|
|
||||||
:path: ".symlinks/plugins/flutter_platform_alert/ios"
|
|
||||||
flutter_secure_storage:
|
flutter_secure_storage:
|
||||||
:path: ".symlinks/plugins/flutter_secure_storage/ios"
|
:path: ".symlinks/plugins/flutter_secure_storage/ios"
|
||||||
flutter_timezone:
|
flutter_timezone:
|
||||||
@@ -462,14 +451,16 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/media_kit_video/ios"
|
:path: ".symlinks/plugins/media_kit_video/ios"
|
||||||
native_exif:
|
native_exif:
|
||||||
:path: ".symlinks/plugins/native_exif/ios"
|
:path: ".symlinks/plugins/native_exif/ios"
|
||||||
|
objective_c:
|
||||||
|
:path: ".symlinks/plugins/objective_c/ios"
|
||||||
package_info_plus:
|
package_info_plus:
|
||||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||||
pasteboard:
|
pasteboard:
|
||||||
:path: ".symlinks/plugins/pasteboard/ios"
|
:path: ".symlinks/plugins/pasteboard/ios"
|
||||||
path_provider_foundation:
|
|
||||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
|
||||||
pointer_interceptor_ios:
|
pointer_interceptor_ios:
|
||||||
:path: ".symlinks/plugins/pointer_interceptor_ios/ios"
|
:path: ".symlinks/plugins/pointer_interceptor_ios/ios"
|
||||||
|
protocol_handler_ios:
|
||||||
|
:path: ".symlinks/plugins/protocol_handler_ios/ios"
|
||||||
receive_sharing_intent:
|
receive_sharing_intent:
|
||||||
:path: ".symlinks/plugins/receive_sharing_intent/ios"
|
:path: ".symlinks/plugins/receive_sharing_intent/ios"
|
||||||
record_ios:
|
record_ios:
|
||||||
@@ -490,14 +481,11 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/syncfusion_flutter_pdfviewer/ios"
|
:path: ".symlinks/plugins/syncfusion_flutter_pdfviewer/ios"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||||
volume_controller:
|
|
||||||
:path: ".symlinks/plugins/volume_controller/ios"
|
|
||||||
wakelock_plus:
|
wakelock_plus:
|
||||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
|
Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
|
||||||
app_links: 3dbc685f76b1693c66a6d9dd1e9ab6f73d97dc0a
|
|
||||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||||
croppy: 979e8ddc254f4642bffe7d52dc7193354b27ba30
|
croppy: 979e8ddc254f4642bffe7d52dc7193354b27ba30
|
||||||
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
|
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
|
||||||
@@ -506,10 +494,10 @@ SPEC CHECKSUMS:
|
|||||||
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
|
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
|
||||||
file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6
|
file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6
|
||||||
Firebase: f07b15ae5a6ec0f93713e30b923d9970d144af3e
|
Firebase: f07b15ae5a6ec0f93713e30b923d9970d144af3e
|
||||||
firebase_analytics: 1d024068b1d4707d5ba7a42a12976ddf3316d835
|
firebase_analytics: 67fbdd9f3c04e55048024f3da21cfc36f05e56cf
|
||||||
firebase_core: 744984dbbed8b3036abf34f0b98d80f130a7e464
|
firebase_core: f1aafb21c14f497e5498f7ffc4dc63cbb52b2594
|
||||||
firebase_crashlytics: f3a9a4338ab99b67042f64e9e22e1bf349cb44ed
|
firebase_crashlytics: c039028126cb45e32f4c217aa392408b0963d081
|
||||||
firebase_messaging: 82c70650c426a0a14873e1acdb9ec2b443c4e8b4
|
firebase_messaging: c17a29984eafce4b2997fe078bb0a9e0b06f5dde
|
||||||
FirebaseAnalytics: 0fc2b20091f0ddd21bf73397cf8f0eb5346dc24f
|
FirebaseAnalytics: 0fc2b20091f0ddd21bf73397cf8f0eb5346dc24f
|
||||||
FirebaseCore: bb595f3114953664e3c1dc032f008a244147cfd3
|
FirebaseCore: bb595f3114953664e3c1dc032f008a244147cfd3
|
||||||
FirebaseCoreExtension: 7e1f7118ee970e001a8013719fb90950ee5e0018
|
FirebaseCoreExtension: 7e1f7118ee970e001a8013719fb90950ee5e0018
|
||||||
@@ -525,10 +513,9 @@ SPEC CHECKSUMS:
|
|||||||
flutter_keyboard_visibility: 4625131e43015dbbe759d9b20daaf77e0e3f6619
|
flutter_keyboard_visibility: 4625131e43015dbbe759d9b20daaf77e0e3f6619
|
||||||
flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb
|
flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb
|
||||||
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
|
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
|
||||||
flutter_platform_alert: bf3b5fcd4ac14bd637e20527e9c471633071afd3
|
|
||||||
flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13
|
flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13
|
||||||
flutter_timezone: 7c838e17ffd4645d261e87037e5bebf6d38fe544
|
flutter_timezone: 7c838e17ffd4645d261e87037e5bebf6d38fe544
|
||||||
flutter_udid: f7c3884e6ec2951efe4f9de082257fc77c4d15e9
|
flutter_udid: 92a5d31fe0526b7b6002a2318df702e12e7eb300
|
||||||
flutter_webrtc: c3e21fc0dcd9d8eb246ae4d5256fcbeb2f5ecd22
|
flutter_webrtc: c3e21fc0dcd9d8eb246ae4d5256fcbeb2f5ecd22
|
||||||
gal: baecd024ebfd13c441269ca7404792a7152fde89
|
gal: baecd024ebfd13c441269ca7404792a7152fde89
|
||||||
GoogleAdsOnDeviceConversion: e03a386840803ea7eef3fd22a061930142c039c1
|
GoogleAdsOnDeviceConversion: e03a386840803ea7eef3fd22a061930142c039c1
|
||||||
@@ -537,7 +524,8 @@ SPEC CHECKSUMS:
|
|||||||
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||||
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
|
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
|
||||||
irondash_engine_context: 8e58ca8e0212ee9d1c7dc6a42121849986c88486
|
irondash_engine_context: 8e58ca8e0212ee9d1c7dc6a42121849986c88486
|
||||||
Kingfisher: 64278f126a815d0e2d391cdf71311b85882c4de0
|
KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51
|
||||||
|
Kingfisher: 23d18f54677d973b713e54ce6a8f5eef6e7056ba
|
||||||
KingfisherWebP: 38b9721821947f547afb78f933f75f4f9e0ae402
|
KingfisherWebP: 38b9721821947f547afb78f933f75f4f9e0ae402
|
||||||
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
|
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
|
||||||
livekit_client: 86c8af579274e4b7a215185a8080db2d4e176f40
|
livekit_client: 86c8af579274e4b7a215185a8080db2d4e176f40
|
||||||
@@ -546,16 +534,16 @@ SPEC CHECKSUMS:
|
|||||||
media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
|
media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
|
||||||
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
||||||
native_exif: 0eb73d3d5b3ca892719228df8d2d1b13d1ae396c
|
native_exif: 0eb73d3d5b3ca892719228df8d2d1b13d1ae396c
|
||||||
|
objective_c: 89e720c30d716b036faf9c9684022048eee1eee2
|
||||||
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
||||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
||||||
pasteboard: 49088aeb6119d51f976a421db60d8e1ab079b63c
|
pasteboard: 49088aeb6119d51f976a421db60d8e1ab079b63c
|
||||||
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
|
|
||||||
pointer_interceptor_ios: da06a662d5bfd329602b45b2ab41bc0fb5fdb0f0
|
pointer_interceptor_ios: da06a662d5bfd329602b45b2ab41bc0fb5fdb0f0
|
||||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||||
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
|
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
|
||||||
|
protocol_handler_ios: 59f23ee71f3ec602d67902ca7f669a80957888d5
|
||||||
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
|
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
|
||||||
record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374
|
record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374
|
||||||
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
|
|
||||||
SDWebImage: 16309af6d214ba3f77a7c6f6fdda888cb313a50a
|
SDWebImage: 16309af6d214ba3f77a7c6f6fdda888cb313a50a
|
||||||
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
||||||
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
||||||
@@ -567,10 +555,9 @@ SPEC CHECKSUMS:
|
|||||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||||
syncfusion_flutter_pdfviewer: 90dc48305d2e33d4aa20681d1e98ddeda891bc14
|
syncfusion_flutter_pdfviewer: 90dc48305d2e33d4aa20681d1e98ddeda891bc14
|
||||||
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
|
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
|
||||||
volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12
|
|
||||||
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
|
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
|
||||||
WebRTC-SDK: 40d4f5ba05cadff14e4db5614aec402a633f007e
|
WebRTC-SDK: 40d4f5ba05cadff14e4db5614aec402a633f007e
|
||||||
|
|
||||||
PODFILE CHECKSUM: 3096dc559be56aca856e757e1dc65ca039801e2e
|
PODFILE CHECKSUM: 585198f58dca90ac6492607c83a8d17045ab3852
|
||||||
|
|
||||||
COCOAPODS: 1.16.2
|
COCOAPODS: 1.16.2
|
||||||
|
|||||||
@@ -3,14 +3,15 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 77;
|
objectVersion = 54;
|
||||||
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, ); }; };
|
5D8143680678FCD1D1827271 /* Pods_Solian_Watch_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9C046CF867AE03DC170F861 /* Pods_Solian_Watch_App.framework */; };
|
||||||
|
7310A7DF2EB10963002C0FD3 /* Solian Watch App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 7310A7D42EB10962002C0FD3 /* Solian 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, ); }; };
|
||||||
@@ -21,7 +22,6 @@
|
|||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
A1D34487886D362AC8B99B2E /* Pods_WatchRunner_Watch_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 802C1CFCA7F1E069AAEFB454 /* Pods_WatchRunner_Watch_App.framework */; };
|
|
||||||
B87C0E607033790E71B54D73 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6D834CA86410B09796B312B /* Pods_Runner.framework */; };
|
B87C0E607033790E71B54D73 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6D834CA86410B09796B312B /* Pods_Runner.framework */; };
|
||||||
D174D53FF3E8EA943491A5CC /* Pods_SolianShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B40764A2C4CC0E7DC70A0D3 /* Pods_SolianShareExtension.framework */; };
|
D174D53FF3E8EA943491A5CC /* Pods_SolianShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B40764A2C4CC0E7DC70A0D3 /* Pods_SolianShareExtension.framework */; };
|
||||||
D1772CE196985AE8E8C9F2E5 /* Pods_SolianNotificationService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39FE4CC6223F0D3C0E1FFD04 /* Pods_SolianNotificationService.framework */; };
|
D1772CE196985AE8E8C9F2E5 /* Pods_SolianNotificationService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39FE4CC6223F0D3C0E1FFD04 /* Pods_SolianNotificationService.framework */; };
|
||||||
@@ -62,11 +62,11 @@
|
|||||||
/* Begin PBXCopyFilesBuildPhase section */
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
7310A7DE2EB10963002C0FD3 /* Embed Watch Content */ = {
|
7310A7DE2EB10963002C0FD3 /* Embed Watch Content */ = {
|
||||||
isa = PBXCopyFilesBuildPhase;
|
isa = PBXCopyFilesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 12;
|
||||||
dstPath = "$(CONTENTS_FOLDER_PATH)/Watch";
|
dstPath = "$(CONTENTS_FOLDER_PATH)/Watch";
|
||||||
dstSubfolderSpec = 16;
|
dstSubfolderSpec = 16;
|
||||||
files = (
|
files = (
|
||||||
7310A7DF2EB10963002C0FD3 /* WatchRunner Watch App.app in Embed Watch Content */,
|
7310A7DF2EB10963002C0FD3 /* Solian Watch App.app in Embed Watch Content */,
|
||||||
);
|
);
|
||||||
name = "Embed Watch Content";
|
name = "Embed Watch Content";
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -97,6 +97,7 @@
|
|||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
0ECC3D56D018DD87FC342699 /* Pods-Solian Watch App.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Solian Watch App.profile.xcconfig"; path = "Target Support Files/Pods-Solian Watch App/Pods-Solian Watch App.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
103EA2362B9E9F127016A1F1 /* Pods-WatchRunner Watch App.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WatchRunner Watch App.profile.xcconfig"; path = "Target Support Files/Pods-WatchRunner Watch App/Pods-WatchRunner Watch App.profile.xcconfig"; sourceTree = "<group>"; };
|
103EA2362B9E9F127016A1F1 /* Pods-WatchRunner Watch App.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WatchRunner Watch App.profile.xcconfig"; path = "Target Support Files/Pods-WatchRunner Watch App/Pods-WatchRunner Watch App.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
14118AC858B441AB16B7309E /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
14118AC858B441AB16B7309E /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||||
@@ -105,16 +106,18 @@
|
|||||||
17FAB080A9C53193ABD9C15B /* Pods-SolianShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolianShareExtension.debug.xcconfig"; path = "Target Support Files/Pods-SolianShareExtension/Pods-SolianShareExtension.debug.xcconfig"; sourceTree = "<group>"; };
|
17FAB080A9C53193ABD9C15B /* Pods-SolianShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolianShareExtension.debug.xcconfig"; path = "Target Support Files/Pods-SolianShareExtension/Pods-SolianShareExtension.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
192FDACE67D7CB6AED15C634 /* Pods-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.debug.xcconfig"; sourceTree = "<group>"; };
|
192FDACE67D7CB6AED15C634 /* Pods-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
1C14F71D23E4371602065522 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
1C14F71D23E4371602065522 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
2440CEDEAAD6D51FDA95FA62 /* Pods-Solian Watch App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Solian Watch App.release.xcconfig"; path = "Target Support Files/Pods-Solian Watch App/Pods-Solian Watch App.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
252A83CE6862573BB856ED8E /* Pods-NotificationService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.release.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.release.xcconfig"; sourceTree = "<group>"; };
|
252A83CE6862573BB856ED8E /* Pods-NotificationService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.release.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
27C66EFB5A705F1A822C3EB0 /* Pods-SolianShareExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolianShareExtension.release.xcconfig"; path = "Target Support Files/Pods-SolianShareExtension/Pods-SolianShareExtension.release.xcconfig"; sourceTree = "<group>"; };
|
27C66EFB5A705F1A822C3EB0 /* Pods-SolianShareExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolianShareExtension.release.xcconfig"; path = "Target Support Files/Pods-SolianShareExtension/Pods-SolianShareExtension.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
29812C17FFBE7DBBC7203981 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
29812C17FFBE7DBBC7203981 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
2D2457F8B2E6EF9C0F935035 /* Pods-NotificationService.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.profile.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.profile.xcconfig"; sourceTree = "<group>"; };
|
2D2457F8B2E6EF9C0F935035 /* Pods-NotificationService.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.profile.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
31EA49B10397BD4145AD765E /* Pods-Solian Watch App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Solian Watch App.debug.xcconfig"; path = "Target Support Files/Pods-Solian Watch App/Pods-Solian Watch App.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
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; };
|
7310A7D42EB10962002C0FD3 /* Solian Watch App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Solian 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; };
|
||||||
@@ -126,7 +129,6 @@
|
|||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||||
7B40764A2C4CC0E7DC70A0D3 /* Pods_SolianShareExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolianShareExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
7B40764A2C4CC0E7DC70A0D3 /* Pods_SolianShareExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolianShareExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
802C1CFCA7F1E069AAEFB454 /* Pods_WatchRunner_Watch_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_WatchRunner_Watch_App.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
86D60BA96DA647E1B11AA7F0 /* Pods-WatchRunner Watch App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WatchRunner Watch App.debug.xcconfig"; path = "Target Support Files/Pods-WatchRunner Watch App/Pods-WatchRunner Watch App.debug.xcconfig"; sourceTree = "<group>"; };
|
86D60BA96DA647E1B11AA7F0 /* Pods-WatchRunner Watch App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WatchRunner Watch App.debug.xcconfig"; path = "Target Support Files/Pods-WatchRunner Watch App/Pods-WatchRunner Watch App.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
8B40620B1EEBB09456406A3C /* Pods-SolianNotificationService.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolianNotificationService.profile.xcconfig"; path = "Target Support Files/Pods-SolianNotificationService/Pods-SolianNotificationService.profile.xcconfig"; sourceTree = "<group>"; };
|
8B40620B1EEBB09456406A3C /* Pods-SolianNotificationService.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolianNotificationService.profile.xcconfig"; path = "Target Support Files/Pods-SolianNotificationService/Pods-SolianNotificationService.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||||
@@ -142,6 +144,7 @@
|
|||||||
A85FF612AE7623A9934E57CE /* Pods-SolianShareExtension.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolianShareExtension.profile.xcconfig"; path = "Target Support Files/Pods-SolianShareExtension/Pods-SolianShareExtension.profile.xcconfig"; sourceTree = "<group>"; };
|
A85FF612AE7623A9934E57CE /* Pods-SolianShareExtension.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolianShareExtension.profile.xcconfig"; path = "Target Support Files/Pods-SolianShareExtension/Pods-SolianShareExtension.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
AA0CA8A3E15DEE023BB27438 /* Pods_NotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
AA0CA8A3E15DEE023BB27438 /* Pods_NotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
B93771F2A63E4148DC6142F7 /* Pods-SolianNotificationService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolianNotificationService.release.xcconfig"; path = "Target Support Files/Pods-SolianNotificationService/Pods-SolianNotificationService.release.xcconfig"; sourceTree = "<group>"; };
|
B93771F2A63E4148DC6142F7 /* Pods-SolianNotificationService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolianNotificationService.release.xcconfig"; path = "Target Support Files/Pods-SolianNotificationService/Pods-SolianNotificationService.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
C9C046CF867AE03DC170F861 /* Pods_Solian_Watch_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Solian_Watch_App.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
E6B10A9A85BECA2E576C91FF /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
E6B10A9A85BECA2E576C91FF /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
F6D834CA86410B09796B312B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
F6D834CA86410B09796B312B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
F830F535CB92E3F2E1653A11 /* Pods-SolianNotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolianNotificationService.debug.xcconfig"; path = "Target Support Files/Pods-SolianNotificationService/Pods-SolianNotificationService.debug.xcconfig"; sourceTree = "<group>"; };
|
F830F535CB92E3F2E1653A11 /* Pods-SolianNotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolianNotificationService.debug.xcconfig"; path = "Target Support Files/Pods-SolianNotificationService/Pods-SolianNotificationService.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
@@ -180,9 +183,11 @@
|
|||||||
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||||
|
|
||||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||||
7310A7D52EB10962002C0FD3 /* WatchRunner Watch App */ = {
|
7310A7D52EB10962002C0FD3 /* Solian Watch App */ = {
|
||||||
isa = PBXFileSystemSynchronizedRootGroup;
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
path = "WatchRunner Watch App";
|
exceptions = (
|
||||||
|
);
|
||||||
|
path = "Solian Watch App";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
73268D272DEB012A0076E970 /* Services */ = {
|
73268D272DEB012A0076E970 /* Services */ = {
|
||||||
@@ -232,7 +237,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
A1D34487886D362AC8B99B2E /* Pods_WatchRunner_Watch_App.framework in Frameworks */,
|
5D8143680678FCD1D1827271 /* Pods_Solian_Watch_App.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -289,7 +294,7 @@
|
|||||||
7B40764A2C4CC0E7DC70A0D3 /* Pods_SolianShareExtension.framework */,
|
7B40764A2C4CC0E7DC70A0D3 /* Pods_SolianShareExtension.framework */,
|
||||||
73ACDFAC2E3D0E6100B63535 /* ReplayKit.framework */,
|
73ACDFAC2E3D0E6100B63535 /* ReplayKit.framework */,
|
||||||
73ACDFB82E3D0E6100B63535 /* UIKit.framework */,
|
73ACDFB82E3D0E6100B63535 /* UIKit.framework */,
|
||||||
802C1CFCA7F1E069AAEFB454 /* Pods_WatchRunner_Watch_App.framework */,
|
C9C046CF867AE03DC170F861 /* Pods_Solian_Watch_App.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -315,6 +320,9 @@
|
|||||||
86D60BA96DA647E1B11AA7F0 /* Pods-WatchRunner Watch App.debug.xcconfig */,
|
86D60BA96DA647E1B11AA7F0 /* Pods-WatchRunner Watch App.debug.xcconfig */,
|
||||||
A2EB1DAFDE9B8E6D88BBF7A3 /* Pods-WatchRunner Watch App.release.xcconfig */,
|
A2EB1DAFDE9B8E6D88BBF7A3 /* Pods-WatchRunner Watch App.release.xcconfig */,
|
||||||
103EA2362B9E9F127016A1F1 /* Pods-WatchRunner Watch App.profile.xcconfig */,
|
103EA2362B9E9F127016A1F1 /* Pods-WatchRunner Watch App.profile.xcconfig */,
|
||||||
|
31EA49B10397BD4145AD765E /* Pods-Solian Watch App.debug.xcconfig */,
|
||||||
|
2440CEDEAAD6D51FDA95FA62 /* Pods-Solian Watch App.release.xcconfig */,
|
||||||
|
0ECC3D56D018DD87FC342699 /* Pods-Solian Watch App.profile.xcconfig */,
|
||||||
);
|
);
|
||||||
path = Pods;
|
path = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -338,7 +346,7 @@
|
|||||||
73CDD67B2DEC00480059D95D /* SolianNotificationService */,
|
73CDD67B2DEC00480059D95D /* SolianNotificationService */,
|
||||||
73C305CF2E0BE878009035B9 /* SolianShareExtension */,
|
73C305CF2E0BE878009035B9 /* SolianShareExtension */,
|
||||||
73ACDFAE2E3D0E6100B63535 /* SolianBroadcastExtension */,
|
73ACDFAE2E3D0E6100B63535 /* SolianBroadcastExtension */,
|
||||||
7310A7D52EB10962002C0FD3 /* WatchRunner Watch App */,
|
7310A7D52EB10962002C0FD3 /* Solian Watch App */,
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||||
91E124CE95BCB4DCD890160D /* Pods */,
|
91E124CE95BCB4DCD890160D /* Pods */,
|
||||||
@@ -355,7 +363,7 @@
|
|||||||
73CDD67A2DEC00480059D95D /* SolianNotificationService.appex */,
|
73CDD67A2DEC00480059D95D /* SolianNotificationService.appex */,
|
||||||
73C305CE2E0BE878009035B9 /* SolianShareExtension.appex */,
|
73C305CE2E0BE878009035B9 /* SolianShareExtension.appex */,
|
||||||
73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */,
|
73ACDFAB2E3D0E6100B63535 /* SolianBroadcastExtension.appex */,
|
||||||
7310A7D42EB10962002C0FD3 /* WatchRunner Watch App.app */,
|
7310A7D42EB10962002C0FD3 /* Solian Watch App.app */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -400,26 +408,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 */ = {
|
7310A7D32EB10962002C0FD3 /* Solian Watch App */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 7310A7E32EB10963002C0FD3 /* Build configuration list for PBXNativeTarget "WatchRunner Watch App" */;
|
buildConfigurationList = 7310A7E32EB10963002C0FD3 /* Build configuration list for PBXNativeTarget "Solian Watch App" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
DDEDA1BA6278B94F0F7B9B61 /* [CP] Check Pods Manifest.lock */,
|
DDEDA1BA6278B94F0F7B9B61 /* [CP] Check Pods Manifest.lock */,
|
||||||
7310A7D02EB10962002C0FD3 /* Sources */,
|
7310A7D02EB10962002C0FD3 /* Sources */,
|
||||||
7310A7D12EB10962002C0FD3 /* Frameworks */,
|
7310A7D12EB10962002C0FD3 /* Frameworks */,
|
||||||
7310A7D22EB10962002C0FD3 /* Resources */,
|
7310A7D22EB10962002C0FD3 /* Resources */,
|
||||||
C74B07D6587D29C67A198025 /* [CP] Embed Pods Frameworks */,
|
E29ECA5954168075BDB000DC /* [CP] Embed Pods Frameworks */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
);
|
);
|
||||||
fileSystemSynchronizedGroups = (
|
fileSystemSynchronizedGroups = (
|
||||||
7310A7D52EB10962002C0FD3 /* WatchRunner Watch App */,
|
7310A7D52EB10962002C0FD3 /* Solian Watch App */,
|
||||||
);
|
);
|
||||||
name = "WatchRunner Watch App";
|
name = "Solian Watch App";
|
||||||
productName = "WatchRunner Watch App";
|
productName = "WatchRunner Watch App";
|
||||||
productReference = 7310A7D42EB10962002C0FD3 /* WatchRunner Watch App.app */;
|
productReference = 7310A7D42EB10962002C0FD3 /* Solian Watch App.app */;
|
||||||
productType = "com.apple.product-type.application";
|
productType = "com.apple.product-type.application";
|
||||||
};
|
};
|
||||||
73ACDFAA2E3D0E6100B63535 /* SolianBroadcastExtension */ = {
|
73ACDFAA2E3D0E6100B63535 /* SolianBroadcastExtension */ = {
|
||||||
@@ -567,7 +575,7 @@
|
|||||||
73CDD6792DEC00480059D95D /* SolianNotificationService */,
|
73CDD6792DEC00480059D95D /* SolianNotificationService */,
|
||||||
73C305CD2E0BE878009035B9 /* SolianShareExtension */,
|
73C305CD2E0BE878009035B9 /* SolianShareExtension */,
|
||||||
73ACDFAA2E3D0E6100B63535 /* SolianBroadcastExtension */,
|
73ACDFAA2E3D0E6100B63535 /* SolianBroadcastExtension */,
|
||||||
7310A7D32EB10962002C0FD3 /* WatchRunner Watch App */,
|
7310A7D32EB10962002C0FD3 /* Solian Watch App */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
@@ -669,14 +677,10 @@
|
|||||||
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";
|
||||||
@@ -734,14 +738,10 @@
|
|||||||
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";
|
||||||
@@ -762,27 +762,6 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||||
};
|
};
|
||||||
C74B07D6587D29C67A198025 /* [CP] Embed Pods Frameworks */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputFileListPaths = (
|
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-WatchRunner Watch App/Pods-WatchRunner Watch App-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "[CP] Embed Pods Frameworks";
|
|
||||||
outputFileListPaths = (
|
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-WatchRunner Watch App/Pods-WatchRunner Watch App-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
|
||||||
);
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-WatchRunner Watch App/Pods-WatchRunner Watch App-frameworks.sh\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
DDEDA1BA6278B94F0F7B9B61 /* [CP] Check Pods Manifest.lock */ = {
|
DDEDA1BA6278B94F0F7B9B61 /* [CP] Check Pods Manifest.lock */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -798,13 +777,30 @@
|
|||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
);
|
);
|
||||||
outputPaths = (
|
outputPaths = (
|
||||||
"$(DERIVED_FILE_DIR)/Pods-WatchRunner Watch App-checkManifestLockResult.txt",
|
"$(DERIVED_FILE_DIR)/Pods-Solian Watch App-checkManifestLockResult.txt",
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
showEnvVarsInLog = 0;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
|
E29ECA5954168075BDB000DC /* [CP] Embed Pods Frameworks */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Solian Watch App/Pods-Solian Watch App-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
|
);
|
||||||
|
name = "[CP] Embed Pods Frameworks";
|
||||||
|
outputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Solian Watch App/Pods-Solian Watch App-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Solian Watch App/Pods-Solian Watch App-frameworks.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
E86CDE9D6464F4F52B910856 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */ = {
|
E86CDE9D6464F4F52B910856 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -1002,6 +998,7 @@
|
|||||||
CUSTOM_GROUP_ID = group.solsynth.solian;
|
CUSTOM_GROUP_ID = group.solsynth.solian;
|
||||||
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
|
EXCLUDED_SOURCE_FILE_NAMES = "";
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
@@ -1012,10 +1009,12 @@
|
|||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian;
|
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||||
SWIFT_ENABLE_EXPLICIT_MODULES = "$(SWIFT_USE_INTEGRATED_DRIVER)";
|
SWIFT_ENABLE_EXPLICIT_MODULES = "$(SWIFT_USE_INTEGRATED_DRIVER)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
WATCHOS_DEPLOYMENT_TARGET = 11.6;
|
||||||
};
|
};
|
||||||
name = Profile;
|
name = Profile;
|
||||||
};
|
};
|
||||||
@@ -1023,6 +1022,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 14DFD79BE7C26E51B117583C /* Pods-RunnerTests.debug.xcconfig */;
|
baseConfigurationReference = 14DFD79BE7C26E51B117583C /* Pods-RunnerTests.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
@@ -1031,6 +1031,8 @@
|
|||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||||
|
SUPPORTS_MACCATALYST = YES;
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -1042,6 +1044,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 14118AC858B441AB16B7309E /* Pods-RunnerTests.release.xcconfig */;
|
baseConfigurationReference = 14118AC858B441AB16B7309E /* Pods-RunnerTests.release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
@@ -1050,6 +1053,8 @@
|
|||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||||
|
SUPPORTS_MACCATALYST = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||||
};
|
};
|
||||||
@@ -1059,6 +1064,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = E6B10A9A85BECA2E576C91FF /* Pods-RunnerTests.profile.xcconfig */;
|
baseConfigurationReference = E6B10A9A85BECA2E576C91FF /* Pods-RunnerTests.profile.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
@@ -1067,6 +1073,8 @@
|
|||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.RunnerTests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||||
|
SUPPORTS_MACCATALYST = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||||
};
|
};
|
||||||
@@ -1074,7 +1082,7 @@
|
|||||||
};
|
};
|
||||||
7310A7E02EB10963002C0FD3 /* Debug */ = {
|
7310A7E02EB10963002C0FD3 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 86D60BA96DA647E1B11AA7F0 /* Pods-WatchRunner Watch App.debug.xcconfig */;
|
baseConfigurationReference = 31EA49B10397BD4145AD765E /* Pods-Solian Watch App.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
@@ -1092,9 +1100,12 @@
|
|||||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = WatchRunner;
|
INFOPLIST_FILE = "WatchRunner-Watch-App-Info.plist";
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
||||||
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = dev.solsynth.solian;
|
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = dev.solsynth.solian;
|
||||||
|
INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp = NO;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 18.6;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -1116,13 +1127,13 @@
|
|||||||
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = 4;
|
TARGETED_DEVICE_FAMILY = 4;
|
||||||
WATCHOS_DEPLOYMENT_TARGET = 26.0;
|
WATCHOS_DEPLOYMENT_TARGET = 11.6;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
7310A7E12EB10963002C0FD3 /* Release */ = {
|
7310A7E12EB10963002C0FD3 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = A2EB1DAFDE9B8E6D88BBF7A3 /* Pods-WatchRunner Watch App.release.xcconfig */;
|
baseConfigurationReference = 2440CEDEAAD6D51FDA95FA62 /* Pods-Solian Watch App.release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
@@ -1140,9 +1151,12 @@
|
|||||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = WatchRunner;
|
INFOPLIST_FILE = "WatchRunner-Watch-App-Info.plist";
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
||||||
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = dev.solsynth.solian;
|
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = dev.solsynth.solian;
|
||||||
|
INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp = NO;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 18.6;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -1155,19 +1169,20 @@
|
|||||||
SDKROOT = watchos;
|
SDKROOT = watchos;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SUPPORTED_PLATFORMS = "watchsimulator watchos";
|
||||||
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
|
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = 4;
|
TARGETED_DEVICE_FAMILY = 4;
|
||||||
WATCHOS_DEPLOYMENT_TARGET = 26.0;
|
WATCHOS_DEPLOYMENT_TARGET = 11.6;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
7310A7E22EB10963002C0FD3 /* Profile */ = {
|
7310A7E22EB10963002C0FD3 /* Profile */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 103EA2362B9E9F127016A1F1 /* Pods-WatchRunner Watch App.profile.xcconfig */;
|
baseConfigurationReference = 0ECC3D56D018DD87FC342699 /* Pods-Solian Watch App.profile.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
@@ -1185,9 +1200,12 @@
|
|||||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = WatchRunner;
|
INFOPLIST_FILE = "WatchRunner-Watch-App-Info.plist";
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
||||||
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = dev.solsynth.solian;
|
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = dev.solsynth.solian;
|
||||||
|
INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp = NO;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 18.6;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -1200,13 +1218,14 @@
|
|||||||
SDKROOT = watchos;
|
SDKROOT = watchos;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SUPPORTED_PLATFORMS = "watchsimulator watchos";
|
||||||
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
|
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = 4;
|
TARGETED_DEVICE_FAMILY = 4;
|
||||||
WATCHOS_DEPLOYMENT_TARGET = 26.0;
|
WATCHOS_DEPLOYMENT_TARGET = 11.6;
|
||||||
};
|
};
|
||||||
name = Profile;
|
name = Profile;
|
||||||
};
|
};
|
||||||
@@ -1243,6 +1262,7 @@
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.SolianBroadcastExtension;
|
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.SolianBroadcastExtension;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
@@ -1283,6 +1303,7 @@
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.SolianBroadcastExtension;
|
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.SolianBroadcastExtension;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
@@ -1321,6 +1342,7 @@
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.SolianBroadcastExtension;
|
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.SolianBroadcastExtension;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
@@ -1362,6 +1384,7 @@
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.SolianShareExtension;
|
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.SolianShareExtension;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_ENABLE_EXPLICIT_MODULES = NO;
|
SWIFT_ENABLE_EXPLICIT_MODULES = NO;
|
||||||
@@ -1405,6 +1428,7 @@
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.SolianShareExtension;
|
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.SolianShareExtension;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_ENABLE_EXPLICIT_MODULES = NO;
|
SWIFT_ENABLE_EXPLICIT_MODULES = NO;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -1446,6 +1470,7 @@
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.SolianShareExtension;
|
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian.SolianShareExtension;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_ENABLE_EXPLICIT_MODULES = NO;
|
SWIFT_ENABLE_EXPLICIT_MODULES = NO;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -1695,6 +1720,7 @@
|
|||||||
CUSTOM_GROUP_ID = group.solsynth.solian;
|
CUSTOM_GROUP_ID = group.solsynth.solian;
|
||||||
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
|
EXCLUDED_SOURCE_FILE_NAMES = "";
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
@@ -1710,6 +1736,7 @@
|
|||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
WATCHOS_DEPLOYMENT_TARGET = 11.6;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
@@ -1724,6 +1751,7 @@
|
|||||||
CUSTOM_GROUP_ID = group.solsynth.solian;
|
CUSTOM_GROUP_ID = group.solsynth.solian;
|
||||||
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
DEVELOPMENT_TEAM = W7HPZ53V6B;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
|
EXCLUDED_SOURCE_FILE_NAMES = "";
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
@@ -1732,12 +1760,15 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
|
ONLY_ACTIVE_ARCH = NO;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian;
|
PRODUCT_BUNDLE_IDENTIFIER = dev.solsynth.solian;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
|
||||||
SWIFT_ENABLE_EXPLICIT_MODULES = "$(SWIFT_USE_INTEGRATED_DRIVER)";
|
SWIFT_ENABLE_EXPLICIT_MODULES = "$(SWIFT_USE_INTEGRATED_DRIVER)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
WATCHOS_DEPLOYMENT_TARGET = 11.6;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
@@ -1754,7 +1785,7 @@
|
|||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
7310A7E32EB10963002C0FD3 /* Build configuration list for PBXNativeTarget "WatchRunner Watch App" */ = {
|
7310A7E32EB10963002C0FD3 /* Build configuration list for PBXNativeTarget "Solian Watch App" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
7310A7E02EB10963002C0FD3 /* Debug */,
|
7310A7E02EB10963002C0FD3 /* Debug */,
|
||||||
|
|||||||
@@ -20,6 +20,20 @@
|
|||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildActionEntry>
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "7310A7D32EB10962002C0FD3"
|
||||||
|
BuildableName = "Solian Watch App.app"
|
||||||
|
BlueprintName = "Solian Watch App"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
</BuildActionEntries>
|
</BuildActionEntries>
|
||||||
</BuildAction>
|
</BuildAction>
|
||||||
<TestAction
|
<TestAction
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import WatchConnectivity
|
|||||||
@main
|
@main
|
||||||
@objc class AppDelegate: FlutterAppDelegate {
|
@objc class AppDelegate: FlutterAppDelegate {
|
||||||
let notifyDelegate = NotifyDelegate()
|
let notifyDelegate = NotifyDelegate()
|
||||||
private var watchConnectivityService: WatchConnectivityService?
|
private static var sharedWatchConnectivityService: WatchConnectivityService?
|
||||||
|
|
||||||
override func application(
|
override func application(
|
||||||
_ application: UIApplication,
|
_ application: UIApplication,
|
||||||
@@ -25,36 +25,43 @@ import WatchConnectivity
|
|||||||
intentIdentifiers: [],
|
intentIdentifiers: [],
|
||||||
options: []
|
options: []
|
||||||
)
|
)
|
||||||
|
|
||||||
UNUserNotificationCenter.current().setNotificationCategories([replyableMessageCategory])
|
UNUserNotificationCenter.current().setNotificationCategories([replyableMessageCategory])
|
||||||
|
|
||||||
GeneratedPluginRegistrant.register(with: self)
|
GeneratedPluginRegistrant.register(with: self)
|
||||||
|
|
||||||
|
// Always initialize and retain a strong reference
|
||||||
if WCSession.isSupported() {
|
if WCSession.isSupported() {
|
||||||
watchConnectivityService = WatchConnectivityService()
|
AppDelegate.sharedWatchConnectivityService = WatchConnectivityService.shared
|
||||||
|
} else {
|
||||||
|
print("[iOS] WCSession not supported on this device.")
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class WatchConnectivityService: NSObject, WCSessionDelegate {
|
final class WatchConnectivityService: NSObject, WCSessionDelegate {
|
||||||
private let session: WCSession
|
static let shared = WatchConnectivityService()
|
||||||
|
private let session: WCSession = .default
|
||||||
|
|
||||||
override init() {
|
private override init() {
|
||||||
self.session = .default
|
|
||||||
super.init()
|
super.init()
|
||||||
print("[iOS] Activating WCSession")
|
print("[iOS] Activating WCSession...")
|
||||||
self.session.delegate = self
|
session.delegate = self
|
||||||
self.session.activate()
|
session.activate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - WCSessionDelegate
|
||||||
|
|
||||||
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
|
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
|
||||||
if let error = error {
|
if let error = error {
|
||||||
print("[iOS] WCSession activation failed with error: \(error.localizedDescription)")
|
print("[iOS] WCSession activation failed: \(error.localizedDescription)")
|
||||||
return
|
} else {
|
||||||
}
|
|
||||||
print("[iOS] WCSession activated with state: \(activationState.rawValue)")
|
print("[iOS] WCSession activated with state: \(activationState.rawValue)")
|
||||||
|
if activationState == .activated {
|
||||||
|
sendDataToWatch()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sessionDidBecomeInactive(_ session: WCSession) {}
|
func sessionDidBecomeInactive(_ session: WCSession) {}
|
||||||
@@ -69,10 +76,7 @@ class WatchConnectivityService: NSObject, WCSessionDelegate {
|
|||||||
let token = UserDefaults.standard.getFlutterToken()
|
let token = UserDefaults.standard.getFlutterToken()
|
||||||
let serverUrl = UserDefaults.standard.getServerUrl()
|
let serverUrl = UserDefaults.standard.getServerUrl()
|
||||||
|
|
||||||
print("[iOS] Retrieved token: \(token ?? "nil")")
|
var data: [String: Any] = ["serverUrl": serverUrl ?? ""]
|
||||||
print("[iOS] Retrieved serverUrl: \(serverUrl)")
|
|
||||||
|
|
||||||
var data: [String: Any] = ["serverUrl": serverUrl]
|
|
||||||
if let token = token {
|
if let token = token {
|
||||||
data["token"] = token
|
data["token"] = token
|
||||||
}
|
}
|
||||||
@@ -81,4 +85,25 @@ class WatchConnectivityService: NSObject, WCSessionDelegate {
|
|||||||
replyHandler(data)
|
replyHandler(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sendDataToWatch() {
|
||||||
|
guard session.activationState == .activated else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let token = UserDefaults.standard.getFlutterToken()
|
||||||
|
let serverUrl = UserDefaults.standard.getServerUrl()
|
||||||
|
|
||||||
|
var data: [String: Any] = ["serverUrl": serverUrl ?? ""]
|
||||||
|
if let token = token {
|
||||||
|
data["token"] = token
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
try session.updateApplicationContext(data)
|
||||||
|
print("[iOS] Sent application context: \(data)")
|
||||||
|
} catch {
|
||||||
|
print("[iOS] Failed to send application context: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="UTF-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">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>AppGroupId</key>
|
<key>AppGroupId</key>
|
||||||
<string>$(CUSTOM_GROUP_ID)</string>
|
<string>$(CUSTOM_GROUP_ID)</string>
|
||||||
<key>BUNDLE_ID</key>
|
<key>BUNDLE_ID</key>
|
||||||
<string>dev.solsynth.solian</string>
|
<string>dev.solsynth.solian</string>
|
||||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
<true/>
|
<true />
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
@@ -38,7 +38,9 @@
|
|||||||
</dict>
|
</dict>
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleTypeRole</key>
|
<key>CFBundleTypeRole</key>
|
||||||
<string>Viewer</string>
|
<string>Editor</string>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string></string>
|
||||||
<key>CFBundleURLSchemes</key>
|
<key>CFBundleURLSchemes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>solian</string>
|
<string>solian</string>
|
||||||
@@ -50,15 +52,16 @@
|
|||||||
<key>CLIENT_ID</key>
|
<key>CLIENT_ID</key>
|
||||||
<string>961776991058-stt7et4qvn3cpscl4r61gl1hnlatqkig.apps.googleusercontent.com</string>
|
<string>961776991058-stt7et4qvn3cpscl4r61gl1hnlatqkig.apps.googleusercontent.com</string>
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
<false/>
|
<false />
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true />
|
||||||
<key>NSCalendarsUsageDescription</key>
|
<key>NSCalendarsUsageDescription</key>
|
||||||
<string>Grant access to Calander help us to shows Solar Calander with your own events.</string>
|
<string>Grant access to Calander help us to shows Solar Calander with your own events.</string>
|
||||||
<key>NSCameraUsageDescription</key>
|
<key>NSCameraUsageDescription</key>
|
||||||
<string>Grant access to Camera will allow Solian take photo or video for your post.</string>
|
<string>Grant access to Camera will allow Solian take photo or video for your post.</string>
|
||||||
<key>NSFaceIDUsageDescription</key>
|
<key>NSFaceIDUsageDescription</key>
|
||||||
<string>Allow the Solar Network verify your ownership of the logged in account and continue your action quickly.</string>
|
<string>Allow the Solar Network verify your ownership of the logged in account and continue
|
||||||
|
your action quickly.</string>
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
<string>Grant access to Microphone will allow Solian record audio for your post.</string>
|
<string>Grant access to Microphone will allow Solian record audio for your post.</string>
|
||||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||||
@@ -75,7 +78,7 @@
|
|||||||
<key>REVERSED_CLIENT_ID</key>
|
<key>REVERSED_CLIENT_ID</key>
|
||||||
<string>com.googleusercontent.apps.961776991058-stt7et4qvn3cpscl4r61gl1hnlatqkig</string>
|
<string>com.googleusercontent.apps.961776991058-stt7et4qvn3cpscl4r61gl1hnlatqkig</string>
|
||||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
<true/>
|
<true />
|
||||||
<key>UIBackgroundModes</key>
|
<key>UIBackgroundModes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>fetch</string>
|
<string>fetch</string>
|
||||||
@@ -88,13 +91,15 @@
|
|||||||
<key>UIMainStoryboardFile</key>
|
<key>UIMainStoryboardFile</key>
|
||||||
<string>Main</string>
|
<string>Main</string>
|
||||||
<key>UIStatusBarHidden</key>
|
<key>UIStatusBarHidden</key>
|
||||||
<false/>
|
<false />
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
<array>
|
<array>
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
</array>
|
</array>
|
||||||
|
<key>WKCompanionAppBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
<array>
|
<array>
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
@@ -102,5 +107,5 @@
|
|||||||
<string>UIInterfaceOrientationPortrait</string>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
@@ -0,0 +1,318 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "icon-ios-20x20@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "20x20"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-ios-20x20@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"scale" : "3x",
|
||||||
|
"size" : "20x20"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-ios-29x29@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "29x29"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-ios-29x29@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"scale" : "3x",
|
||||||
|
"size" : "29x29"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-ios-38x38@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "38x38"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-ios-38x38@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"scale" : "3x",
|
||||||
|
"size" : "38x38"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-ios-40x40@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "40x40"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-ios-40x40@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"scale" : "3x",
|
||||||
|
"size" : "40x40"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-ios-60x60@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "60x60"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-ios-60x60@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"scale" : "3x",
|
||||||
|
"size" : "60x60"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-ios-64x64@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "64x64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-ios-64x64@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"scale" : "3x",
|
||||||
|
"size" : "64x64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-ios-68x68@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "68x68"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-ios-76x76@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "76x76"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-ios-83.5x83.5@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "83.5x83.5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-ios-1024x1024.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-mac-16x16.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-mac-16x16@2x.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-mac-32x32.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-mac-32x32@2x.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-mac-128x128.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "128x128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-mac-128x128@2x.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "128x128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-mac-256x256.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-mac-256x256@2x.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-mac-512x512.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "512x512"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-mac-512x512@2x.png",
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "512x512"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-22x22@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "22x22"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-24x24@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "24x24"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-27.5x27.5@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "27.5x27.5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-29x29@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "29x29"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-30x30@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "30x30"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-32x32@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-33x33@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "33x33"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-40x40@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "40x40"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-43.5x43.5@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "43.5x43.5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-44x44@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "44x44"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-46x46@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "46x46"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-50x50@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "50x50"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-51x51@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "51x51"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-54x54@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "54x54"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-86x86@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "86x86"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-98x98@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "98x98"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-108x108@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "108x108"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-117x117@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "117x117"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-129x129@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "129x129"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "icon-watchos-1024x1024.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 473 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 10 KiB |
21
ios/Solian Watch App/Assets.xcassets/Logo.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "icon.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
ios/Solian Watch App/Assets.xcassets/Logo.imageset/icon.png
vendored
Normal file
|
After Width: | Height: | Size: 70 KiB |
@@ -22,29 +22,37 @@ struct ContentView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationSplitView {
|
NavigationSplitView {
|
||||||
List(selection: $selection) {
|
List(selection: $selection) {
|
||||||
Label("Explore", systemImage: "globe").tag(Panel.explore)
|
AppInfoHeaderView()
|
||||||
Label("Chat", systemImage: "message").tag(Panel.chat)
|
.listRowBackground(Color.clear)
|
||||||
Label("Notifications", systemImage: "bell").tag(Panel.notifications)
|
.environmentObject(appState)
|
||||||
Label("Account", systemImage: "person.circle").tag(Panel.account)
|
|
||||||
|
Label("Explore", systemImage: "globe.fill").tag(Panel.explore)
|
||||||
|
Label("Chat", systemImage: "message.fill").tag(Panel.chat)
|
||||||
|
Label("Notifications", systemImage: "bell.fill").tag(Panel.notifications)
|
||||||
|
Label("Account", systemImage: "person.circle.fill").tag(Panel.account)
|
||||||
}
|
}
|
||||||
.listStyle(.automatic)
|
.listStyle(.automatic)
|
||||||
} detail: {
|
} detail: {
|
||||||
switch selection {
|
switch selection {
|
||||||
case .explore:
|
case .explore:
|
||||||
ExploreView()
|
ExploreView().environmentObject(appState)
|
||||||
.environmentObject(appState)
|
|
||||||
case .chat:
|
case .chat:
|
||||||
ChatView()
|
ChatView().environmentObject(appState)
|
||||||
.environmentObject(appState)
|
|
||||||
case .notifications:
|
case .notifications:
|
||||||
NotificationView()
|
NotificationView().environmentObject(appState)
|
||||||
.environmentObject(appState)
|
|
||||||
case .account:
|
case .account:
|
||||||
AccountView()
|
AccountView().environmentObject(appState)
|
||||||
.environmentObject(appState)
|
|
||||||
case .none:
|
case .none:
|
||||||
Text("Select a panel")
|
Text("Select a panel")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Placeholder Implementations for Preview ---
|
||||||
|
|
||||||
|
struct ContentView_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
ContentView()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -58,9 +58,8 @@ class ImageLoader: ObservableObject {
|
|||||||
switch result {
|
switch result {
|
||||||
case .success(let value):
|
case .success(let value):
|
||||||
self.image = Image(uiImage: value.image)
|
self.image = Image(uiImage: value.image)
|
||||||
print("[watchOS] Image loaded successfully from \(value.cacheType == .none ? "network" : "cache (\(value.cacheType))").")
|
|
||||||
self.isLoading = false
|
self.isLoading = false
|
||||||
case .failure(let error):
|
case .failure(_):
|
||||||
// If WebP processor fails (likely due to format), try with default processor
|
// If WebP processor fails (likely due to format), try with default processor
|
||||||
let defaultProcessor = DefaultImageProcessor.default
|
let defaultProcessor = DefaultImageProcessor.default
|
||||||
self.currentTask = KingfisherManager.shared.retrieveImage(
|
self.currentTask = KingfisherManager.shared.retrieveImage(
|
||||||
@@ -78,7 +77,6 @@ class ImageLoader: ObservableObject {
|
|||||||
switch fallbackResult {
|
switch fallbackResult {
|
||||||
case .success(let value):
|
case .success(let value):
|
||||||
self.image = Image(uiImage: value.image)
|
self.image = Image(uiImage: value.image)
|
||||||
print("[watchOS] Image loaded successfully from \(value.cacheType == .none ? "network" : "cache (\(value.cacheType))") using fallback processor.")
|
|
||||||
case .failure(let fallbackError):
|
case .failure(let fallbackError):
|
||||||
self.errorMessage = fallbackError.localizedDescription
|
self.errorMessage = fallbackError.localizedDescription
|
||||||
print("[watchOS] Image loading failed: \(fallbackError.localizedDescription)")
|
print("[watchOS] Image loading failed: \(fallbackError.localizedDescription)")
|
||||||
@@ -2,15 +2,58 @@
|
|||||||
// NetworkService.swift
|
// NetworkService.swift
|
||||||
// WatchRunner Watch App
|
// WatchRunner Watch App
|
||||||
//
|
//
|
||||||
// Created by LittleSheep on 2025/10/29.
|
// Created by LittleSheep on 2025/10/29. //
|
||||||
//
|
|
||||||
|
|
||||||
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
// MARK: - WebSocket Data Structures
|
||||||
|
|
||||||
|
enum WebSocketState: Equatable {
|
||||||
|
case connected
|
||||||
|
case connecting
|
||||||
|
case disconnected
|
||||||
|
case serverDown
|
||||||
|
case duplicateDevice
|
||||||
|
case error(String)
|
||||||
|
|
||||||
|
// Equatable conformance
|
||||||
|
static func == (lhs: WebSocketState, rhs: WebSocketState) -> Bool {
|
||||||
|
switch (lhs, rhs) {
|
||||||
|
case (.connected, .connected),
|
||||||
|
(.connecting, .connecting),
|
||||||
|
(.disconnected, .disconnected),
|
||||||
|
(.serverDown, .serverDown),
|
||||||
|
(.duplicateDevice, .duplicateDevice):
|
||||||
|
return true
|
||||||
|
case let (.error(a), .error(b)):
|
||||||
|
return a == b
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WebSocketPacket {
|
||||||
|
let type: String
|
||||||
|
let data: [String: Any]?
|
||||||
|
let endpoint: String?
|
||||||
|
let errorMessage: String?
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Network Service
|
// MARK: - Network Service
|
||||||
|
|
||||||
class NetworkService {
|
class NetworkService {
|
||||||
private let session = URLSession.shared
|
private let session: URLSession
|
||||||
|
|
||||||
|
init() {
|
||||||
|
let config = URLSessionConfiguration.ephemeral
|
||||||
|
config.waitsForConnectivity = true
|
||||||
|
session = URLSession(configuration: config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a serial queue for WebSocket operations
|
||||||
|
private let webSocketQueue = DispatchQueue(label: "com.solian.websocketQueue")
|
||||||
|
|
||||||
func fetchActivities(filter: String, cursor: String? = nil, token: String, serverUrl: String) async throws -> ActivityResponse {
|
func fetchActivities(filter: String, cursor: String? = nil, token: String, serverUrl: String) async throws -> ActivityResponse {
|
||||||
guard let baseURL = URL(string: serverUrl) else {
|
guard let baseURL = URL(string: serverUrl) else {
|
||||||
@@ -77,7 +120,7 @@ class NetworkService {
|
|||||||
throw URLError(.badURL)
|
throw URLError(.badURL)
|
||||||
}
|
}
|
||||||
var components = URLComponents(url: baseURL.appendingPathComponent("/ring/notifications"), resolvingAgainstBaseURL: false)!
|
var components = URLComponents(url: baseURL.appendingPathComponent("/ring/notifications"), resolvingAgainstBaseURL: false)!
|
||||||
var queryItems = [URLQueryItem(name: "offset", value: String(offset)), URLQueryItem(name: "take", value: String(take))]
|
let queryItems = [URLQueryItem(name: "offset", value: String(offset)), URLQueryItem(name: "take", value: String(take))]
|
||||||
components.queryItems = queryItems
|
components.queryItems = queryItems
|
||||||
|
|
||||||
var request = URLRequest(url: components.url!)
|
var request = URLRequest(url: components.url!)
|
||||||
@@ -148,7 +191,7 @@ class NetworkService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createOrUpdateStatus(attitude: Int, isInvisible: Bool, isNotDisturb: Bool, label: String?, token: String, serverUrl: String) async throws -> SnAccountStatus {
|
func createOrUpdateStatus(attitude: Int, isInvisible: Bool, isNotDisturb: Bool, label: String?, token: String, serverUrl: String) async throws -> SnAccountStatus {
|
||||||
// Check if there's already a customized status
|
// Check if there\'s already a customized status
|
||||||
let existingStatus = try? await fetchAccountStatus(token: token, serverUrl: serverUrl)
|
let existingStatus = try? await fetchAccountStatus(token: token, serverUrl: serverUrl)
|
||||||
let method = (existingStatus?.isCustomized == true) ? "PATCH" : "POST"
|
let method = (existingStatus?.isCustomized == true) ? "PATCH" : "POST"
|
||||||
|
|
||||||
@@ -167,7 +210,7 @@ class NetworkService {
|
|||||||
var body: [String: Any] = [
|
var body: [String: Any] = [
|
||||||
"attitude": attitude,
|
"attitude": attitude,
|
||||||
"is_invisible": isInvisible,
|
"is_invisible": isInvisible,
|
||||||
"is_not_disturb": isNotDisturb
|
"is_not_disturb": isNotDisturb,
|
||||||
]
|
]
|
||||||
|
|
||||||
if let label = label, !label.isEmpty {
|
if let label = label, !label.isEmpty {
|
||||||
@@ -338,7 +381,7 @@ class NetworkService {
|
|||||||
resolvingAgainstBaseURL: false
|
resolvingAgainstBaseURL: false
|
||||||
)!
|
)!
|
||||||
var queryItems = [
|
var queryItems = [
|
||||||
URLQueryItem(name: "take", value: String(take))
|
URLQueryItem(name: "take", value: String(take)),
|
||||||
]
|
]
|
||||||
if let before = before {
|
if let before = before {
|
||||||
queryItems.append(URLQueryItem(name: "before", value: ISO8601DateFormatter().string(from: before)))
|
queryItems.append(URLQueryItem(name: "before", value: ISO8601DateFormatter().string(from: before)))
|
||||||
@@ -376,24 +419,225 @@ class NetworkService {
|
|||||||
let messages = try decoder.decode([SnChatMessage].self, from: data)
|
let messages = try decoder.decode([SnChatMessage].self, from: data)
|
||||||
print("[watchOS] fetchChatMessages successfully decoded \(messages.count) messages")
|
print("[watchOS] fetchChatMessages successfully decoded \(messages.count) messages")
|
||||||
return messages
|
return messages
|
||||||
} catch DecodingError.dataCorrupted(let context) {
|
|
||||||
print(context)
|
|
||||||
return []
|
|
||||||
} catch DecodingError.keyNotFound(let key, let context) {
|
|
||||||
print("Key '\(key)' not found:", context.debugDescription)
|
|
||||||
print("codingPath:", context.codingPath)
|
|
||||||
return []
|
|
||||||
} catch DecodingError.valueNotFound(let value, let context) {
|
|
||||||
print("Value '\(value)' not found:", context.debugDescription)
|
|
||||||
print("codingPath:", context.codingPath)
|
|
||||||
return []
|
|
||||||
} catch DecodingError.typeMismatch(let type, let context) {
|
|
||||||
print("Type '\(type)' mismatch:", context.debugDescription)
|
|
||||||
print("codingPath:", context.codingPath)
|
|
||||||
return []
|
|
||||||
} catch {
|
} catch {
|
||||||
print("error: ", error)
|
print("error: ", error)
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - WebSocket
|
||||||
|
|
||||||
|
private var webSocketTask: URLSessionWebSocketTask?
|
||||||
|
private var heartbeatTimer: Timer?
|
||||||
|
private var reconnectTimer: Timer?
|
||||||
|
private var isDisconnectingManually = false
|
||||||
|
|
||||||
|
private var lastToken: String?
|
||||||
|
private var lastServerUrl: String?
|
||||||
|
|
||||||
|
private var heartbeatAt: Date?
|
||||||
|
var heartbeatDelay: TimeInterval?
|
||||||
|
|
||||||
|
private let connectLock = NSLock()
|
||||||
|
|
||||||
|
private let packetSubject = PassthroughSubject<WebSocketPacket, Error>()
|
||||||
|
private let stateSubject = CurrentValueSubject<WebSocketState, Never>(.disconnected) // Changed to CurrentValueSubject
|
||||||
|
|
||||||
|
private var currentConnectionState: WebSocketState = .disconnected { // New property
|
||||||
|
didSet {
|
||||||
|
// Only send updates if the state has actually changed
|
||||||
|
if oldValue != currentConnectionState {
|
||||||
|
stateSubject.send(currentConnectionState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var packetStream: AnyPublisher<WebSocketPacket, Error> {
|
||||||
|
packetSubject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
var stateStream: AnyPublisher<WebSocketState, Never> {
|
||||||
|
stateSubject.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
func connectWebSocket(token: String, serverUrl: String) {
|
||||||
|
webSocketQueue.async { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
self.connectLock.lock()
|
||||||
|
defer { self.connectLock.unlock() }
|
||||||
|
|
||||||
|
// Prevent redundant connection attempts
|
||||||
|
if self.currentConnectionState == .connecting || self.currentConnectionState == .connected {
|
||||||
|
print("[WebSocket] Already connecting or connected, ignoring new connect request.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.currentConnectionState = .connecting
|
||||||
|
|
||||||
|
// Ensure any existing task is cancelled before starting a new one
|
||||||
|
self.webSocketTask?.cancel(with: .goingAway, reason: nil)
|
||||||
|
self.webSocketTask = nil
|
||||||
|
|
||||||
|
self.isDisconnectingManually = false // Reset this flag for a new connection attempt
|
||||||
|
|
||||||
|
self.lastToken = token
|
||||||
|
self.lastServerUrl = serverUrl
|
||||||
|
|
||||||
|
guard var urlComponents = URLComponents(string: serverUrl) else {
|
||||||
|
self.currentConnectionState = .error("Invalid server URL")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
urlComponents.scheme = urlComponents.scheme?.replacingOccurrences(of: "http", with: "ws")
|
||||||
|
urlComponents.path = "/ws"
|
||||||
|
urlComponents.queryItems = [URLQueryItem(name: "deviceAlt", value: "watch")]
|
||||||
|
|
||||||
|
guard let url = urlComponents.url else {
|
||||||
|
self.currentConnectionState = .error("Invalid WebSocket URL")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = URLRequest(url: url)
|
||||||
|
request.setValue("AtField \(token)", forHTTPHeaderField: "Authorization")
|
||||||
|
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||||
|
|
||||||
|
print("[WebSocket] Trying connecting to \(url)")
|
||||||
|
|
||||||
|
self.webSocketTask = self.session.webSocketTask(with: request)
|
||||||
|
self.webSocketTask?.resume()
|
||||||
|
|
||||||
|
self.listenForWebSocketMessages()
|
||||||
|
self.scheduleHeartbeat()
|
||||||
|
self.currentConnectionState = .connected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func listenForWebSocketMessages() {
|
||||||
|
// Ensure webSocketTask is still valid before attempting to receive
|
||||||
|
guard let task = webSocketTask else {
|
||||||
|
print("[WebSocket] listenForWebSocketMessages: webSocketTask is nil, stopping listen.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
task.receive { [weak self] result in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
switch result {
|
||||||
|
case .failure(let error):
|
||||||
|
print("[WebSocket] Error in receiving message: \(error)")
|
||||||
|
// Only attempt to reconnect if not manually disconnecting
|
||||||
|
if !self.isDisconnectingManually {
|
||||||
|
self.currentConnectionState = .error(error.localizedDescription)
|
||||||
|
self.scheduleReconnect()
|
||||||
|
} else {
|
||||||
|
// If manually disconnecting, just ensure state is disconnected
|
||||||
|
self.currentConnectionState = .disconnected
|
||||||
|
}
|
||||||
|
case .success(let message):
|
||||||
|
switch message {
|
||||||
|
case .string(let text):
|
||||||
|
self.handleWebSocketMessage(text: text)
|
||||||
|
case .data(let data):
|
||||||
|
if let text = String(data: data, encoding: .utf8) {
|
||||||
|
self.handleWebSocketMessage(text: text)
|
||||||
|
}
|
||||||
|
@unknown default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Continue listening for next message only if task is still valid
|
||||||
|
if self.webSocketTask === task { // Check if it's the same task
|
||||||
|
self.listenForWebSocketMessages()
|
||||||
|
} else {
|
||||||
|
print("[WebSocket] listenForWebSocketMessages: Task changed, stopping listen for old task.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleWebSocketMessage(text: String) {
|
||||||
|
guard let data = text.data(using: .utf8) else {
|
||||||
|
print("[WebSocket] Could not convert message to data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
||||||
|
let type = json["type"] as? String
|
||||||
|
{
|
||||||
|
let packet = WebSocketPacket(
|
||||||
|
type: type,
|
||||||
|
data: json["data"] as? [String: Any],
|
||||||
|
endpoint: json["endpoint"] as? String,
|
||||||
|
errorMessage: json["errorMessage"] as? String
|
||||||
|
)
|
||||||
|
|
||||||
|
print("[WebSocket] Received packet: \(packet.type) \(packet.errorMessage ?? "")")
|
||||||
|
|
||||||
|
if packet.type == "error.dupe" {
|
||||||
|
self.currentConnectionState = .duplicateDevice
|
||||||
|
self.disconnectWebSocket()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if packet.type == "pong" {
|
||||||
|
if let beatAt = self.heartbeatAt {
|
||||||
|
let now = Date()
|
||||||
|
self.heartbeatDelay = now.timeIntervalSince(beatAt)
|
||||||
|
print("[WebSocket] Server respond last heartbeat for \((self.heartbeatDelay ?? 0) * 1000) ms")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.packetSubject.send(packet)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print("[WebSocket] Could not parse message json: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func scheduleReconnect() {
|
||||||
|
reconnectTimer?.invalidate()
|
||||||
|
reconnectTimer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { [weak self] _ in
|
||||||
|
guard let self = self, let token = self.lastToken, let serverUrl = self.lastServerUrl else { return }
|
||||||
|
print("[WebSocket] Attempting to reconnect...")
|
||||||
|
|
||||||
|
// No need to call disconnectWebSocket here, connectWebSocket will handle cancelling old task
|
||||||
|
self.isDisconnectingManually = false // Reset for the new connection attempt
|
||||||
|
|
||||||
|
self.connectWebSocket(token: token, serverUrl: serverUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func scheduleHeartbeat() {
|
||||||
|
heartbeatTimer?.invalidate()
|
||||||
|
heartbeatTimer = Timer.scheduledTimer(withTimeInterval: 60.0, repeats: true) { [weak self] _ in
|
||||||
|
self?.beatTheHeart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func beatTheHeart() {
|
||||||
|
heartbeatAt = Date()
|
||||||
|
print("[WebSocket] We\'re beating the heart! \(String(describing: self.heartbeatAt))")
|
||||||
|
sendWebSocketMessage(message: "{\"type\":\"ping\"}")
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendWebSocketMessage(message: String) {
|
||||||
|
webSocketTask?.send(.string(message)) { error in
|
||||||
|
if let error = error {
|
||||||
|
print("[WebSocket] Error sending message: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func disconnectWebSocket() {
|
||||||
|
isDisconnectingManually = true
|
||||||
|
reconnectTimer?.invalidate()
|
||||||
|
heartbeatTimer?.invalidate()
|
||||||
|
|
||||||
|
// Cancel the task and then nil it out
|
||||||
|
webSocketTask?.cancel(with: .goingAway, reason: nil)
|
||||||
|
webSocketTask = nil // Set to nil immediately after cancelling
|
||||||
|
|
||||||
|
self.currentConnectionState = .disconnected
|
||||||
|
}
|
||||||
}
|
}
|
||||||
58
ios/Solian Watch App/State/AppState.swift
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
//
|
||||||
|
// AppState.swift
|
||||||
|
// WatchRunner Watch App
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2025/10/29.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
// MARK: - App State
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
class AppState: ObservableObject {
|
||||||
|
@Published var token: String? = nil
|
||||||
|
@Published var serverUrl: String? = nil
|
||||||
|
@Published var isReady = false
|
||||||
|
@Published var errorMessage: String? = nil
|
||||||
|
|
||||||
|
let networkService = NetworkService()
|
||||||
|
private var wcService = WatchConnectivityService()
|
||||||
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
private var hasAttemptedConnection = false
|
||||||
|
|
||||||
|
init() {
|
||||||
|
wcService.$token.combineLatest(wcService.$serverUrl, wcService.$isFetched, wcService.$errorMessage)
|
||||||
|
.receive(on: DispatchQueue.main)
|
||||||
|
.sink { [weak self] (token: String?, serverUrl: String?, isFetched: Bool?, errorMessage: String?) in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
self.token = token
|
||||||
|
self.serverUrl = serverUrl
|
||||||
|
self.errorMessage = errorMessage
|
||||||
|
|
||||||
|
if let token = token, let serverUrl = serverUrl, !token.isEmpty, !serverUrl.isEmpty {
|
||||||
|
self.isReady = true
|
||||||
|
// Only connect once when we have valid credentials and tried fetch from phone
|
||||||
|
if !self.hasAttemptedConnection && isFetched == true {
|
||||||
|
self.hasAttemptedConnection = true
|
||||||
|
print("[AppState] Connecting WebSocket to server: \(serverUrl)")
|
||||||
|
self.networkService.connectWebSocket(token: token, serverUrl: serverUrl)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.isReady = false
|
||||||
|
if self.hasAttemptedConnection {
|
||||||
|
self.hasAttemptedConnection = false
|
||||||
|
// Disconnect WebSocket if token or serverUrl become invalid
|
||||||
|
self.networkService.disconnectWebSocket()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestData() {
|
||||||
|
wcService.requestDataFromPhone()
|
||||||
|
}
|
||||||
|
}
|
||||||
113
ios/Solian Watch App/State/WatchConnectivityService.swift
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
import WatchConnectivity
|
||||||
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class WatchConnectivityService: NSObject, WCSessionDelegate, ObservableObject {
|
||||||
|
@Published var token: String?
|
||||||
|
@Published var serverUrl: String?
|
||||||
|
@Published var isFetched: Bool?
|
||||||
|
@Published var errorMessage: String?
|
||||||
|
|
||||||
|
private let session: WCSession
|
||||||
|
private let userDefaults = UserDefaults.standard
|
||||||
|
private let tokenKey = "token"
|
||||||
|
private let serverUrlKey = "serverUrl"
|
||||||
|
|
||||||
|
override init() {
|
||||||
|
self.session = .default
|
||||||
|
super.init()
|
||||||
|
print("[watchOS] Activating WCSession")
|
||||||
|
self.session.delegate = self
|
||||||
|
self.session.activate()
|
||||||
|
|
||||||
|
// Load cached data
|
||||||
|
self.token = userDefaults.string(forKey: tokenKey)
|
||||||
|
self.serverUrl = userDefaults.string(forKey: serverUrlKey)
|
||||||
|
self.isFetched = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
|
||||||
|
if let error = error {
|
||||||
|
print("[watchOS] WCSession activation failed with error: \(error.localizedDescription)")
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.errorMessage = "WCSession activation failed: \(error.localizedDescription)"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
print("[watchOS] WCSession activated with state: \(activationState.rawValue)")
|
||||||
|
if activationState == .activated {
|
||||||
|
requestDataFromPhone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
|
||||||
|
print("[watchOS] Received application context: \(applicationContext)")
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
if let token = applicationContext["token"] as? String {
|
||||||
|
self.token = token
|
||||||
|
self.userDefaults.set(token, forKey: self.tokenKey)
|
||||||
|
}
|
||||||
|
if let serverUrl = applicationContext["serverUrl"] as? String {
|
||||||
|
self.serverUrl = serverUrl
|
||||||
|
self.userDefaults.set(serverUrl, forKey: self.serverUrlKey)
|
||||||
|
}
|
||||||
|
self.isFetched = true
|
||||||
|
self.errorMessage = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
self.userDefaults.set(token, forKey: self.tokenKey)
|
||||||
|
}
|
||||||
|
if let serverUrl = message["serverUrl"] as? String {
|
||||||
|
self.serverUrl = serverUrl
|
||||||
|
self.userDefaults.set(serverUrl, forKey: self.serverUrlKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestDataFromPhone() {
|
||||||
|
// Check if we already have valid data to avoid unnecessary requests
|
||||||
|
if let token = self.token, let serverUrl = self.serverUrl, !token.isEmpty, !serverUrl.isEmpty {
|
||||||
|
print("[watchOS] Skipped fetch - already have valid data")
|
||||||
|
self.isFetched = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard session.activationState == .activated else {
|
||||||
|
print("[watchOS] Session not activated yet, state: \(session.activationState.rawValue)")
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.errorMessage = "Session not ready yet"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
print("[watchOS] Requesting data from phone")
|
||||||
|
session.sendMessage(["request": "data"]) { [weak self] response in
|
||||||
|
guard let self = self else { return }
|
||||||
|
print("[watchOS] Received reply: \(response)")
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.isFetched = true
|
||||||
|
if let token = response["token"] as? String {
|
||||||
|
self.token = token
|
||||||
|
self.userDefaults.set(token, forKey: self.tokenKey)
|
||||||
|
}
|
||||||
|
if let serverUrl = response["serverUrl"] as? String {
|
||||||
|
self.serverUrl = serverUrl
|
||||||
|
self.userDefaults.set(serverUrl, forKey: self.serverUrlKey)
|
||||||
|
}
|
||||||
|
self.errorMessage = nil // Clear any previous errors
|
||||||
|
}
|
||||||
|
} errorHandler: { error in
|
||||||
|
print("[watchOS] sendMessage failed with error: \(error.localizedDescription)")
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.errorMessage = "Failed to get data from phone: \(error.localizedDescription)"
|
||||||
|
// Don't set isFetched = true on error - allow retry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
62
ios/Solian Watch App/Views/AppInfoHeaderView.swift
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
//
|
||||||
|
// AppInfoHeader.swift
|
||||||
|
// Runner
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2025/10/30.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct AppInfoHeaderView : View {
|
||||||
|
@EnvironmentObject var appState: AppState // Access AppState
|
||||||
|
@State private var webSocketConnectionState: WebSocketState = .disconnected // New state for WebSocket status
|
||||||
|
@State private var cancellables = Set<AnyCancellable>() // For managing subscriptions
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
HStack(spacing: 12) {
|
||||||
|
Image("Logo")
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 40, height: 40)
|
||||||
|
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text("Solian").font(.headline)
|
||||||
|
Text("for Apple Watch").font(.system(size: 11))
|
||||||
|
|
||||||
|
// Display WebSocket connection status
|
||||||
|
Text(webSocketStatusMessage)
|
||||||
|
.font(.system(size: 10))
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onAppear {
|
||||||
|
setupWebSocketListeners()
|
||||||
|
}
|
||||||
|
.onDisappear {
|
||||||
|
cancellables.forEach { $0.cancel() }
|
||||||
|
cancellables.removeAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var webSocketStatusMessage: String {
|
||||||
|
switch webSocketConnectionState {
|
||||||
|
case .connected: return "Connected"
|
||||||
|
case .connecting: return "Connecting..."
|
||||||
|
case .disconnected: return "Disconnected"
|
||||||
|
case .serverDown: return "Server Down"
|
||||||
|
case .duplicateDevice: return "Duplicate Device"
|
||||||
|
case .error(let msg): return "Error: \(msg)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setupWebSocketListeners() {
|
||||||
|
appState.networkService.stateStream
|
||||||
|
.receive(on: DispatchQueue.main)
|
||||||
|
.sink { state in
|
||||||
|
webSocketConnectionState = state
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -196,7 +196,7 @@ struct ChatRoomListItem: View {
|
|||||||
.resizable()
|
.resizable()
|
||||||
.frame(width: 32, height: 32)
|
.frame(width: 32, height: 32)
|
||||||
.clipShape(Circle())
|
.clipShape(Circle())
|
||||||
} else if let errorMessage = avatarLoader.errorMessage {
|
} else if avatarLoader.errorMessage != nil {
|
||||||
// Error state - show fallback
|
// Error state - show fallback
|
||||||
Circle()
|
Circle()
|
||||||
.fill(Color.gray.opacity(0.3))
|
.fill(Color.gray.opacity(0.3))
|
||||||
@@ -250,15 +250,37 @@ struct ChatRoomListItem: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
struct ChatRoomView: View {
|
struct ChatRoomView: View {
|
||||||
let room: SnChatRoom
|
let room: SnChatRoom
|
||||||
@EnvironmentObject var appState: AppState
|
@EnvironmentObject var appState: AppState
|
||||||
@State private var messages: [SnChatMessage] = []
|
@State private var messages: [SnChatMessage] = []
|
||||||
@State private var isLoading = false
|
@State private var isLoading = false
|
||||||
@State private var error: Error?
|
@State private var error: Error?
|
||||||
|
@State private var wsState: WebSocketState = .disconnected // New state for WebSocket status
|
||||||
|
@State private var hasLoadedMessages = false // Track if messages have been loaded
|
||||||
|
@State private var messageText = "" // Text input for sending messages
|
||||||
|
@State private var isSending = false // Track sending state
|
||||||
|
@State private var isInputHidden = false // Track if input should be hidden during scrolling
|
||||||
|
@State private var scrollTimer: Timer? // Timer to show input after scrolling stops
|
||||||
|
|
||||||
|
@State private var cancellables = Set<AnyCancellable>() // For managing subscriptions
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
|
// Display WebSocket connection status
|
||||||
|
if (wsState != .connected)
|
||||||
|
{
|
||||||
|
Text(webSocketStatusMessage)
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.padding(.vertical, 2)
|
||||||
|
.animation(.easeInOut, value: wsState) // Animate status changes
|
||||||
|
.transition(.opacity)
|
||||||
|
}
|
||||||
|
|
||||||
if isLoading {
|
if isLoading {
|
||||||
ProgressView()
|
ProgressView()
|
||||||
} else if error != nil {
|
} else if error != nil {
|
||||||
@@ -291,6 +313,7 @@ struct ChatRoomView: View {
|
|||||||
}
|
}
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, 8)
|
||||||
|
.padding(.bottom, 8)
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
// Scroll to bottom when messages load
|
// Scroll to bottom when messages load
|
||||||
@@ -298,7 +321,7 @@ struct ChatRoomView: View {
|
|||||||
scrollView.scrollTo(lastMessage.id, anchor: .bottom)
|
scrollView.scrollTo(lastMessage.id, anchor: .bottom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: messages.count) { _ in
|
.onChange(of: messages.count) { _, _ in
|
||||||
// Scroll to bottom when new messages arrive
|
// Scroll to bottom when new messages arrive
|
||||||
if let lastMessage = messages.last {
|
if let lastMessage = messages.last {
|
||||||
withAnimation {
|
withAnimation {
|
||||||
@@ -306,21 +329,94 @@ struct ChatRoomView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.onScrollPhaseChange { _, phase in
|
||||||
|
switch phase {
|
||||||
|
case .interacting:
|
||||||
|
if !isInputHidden {
|
||||||
|
withAnimation(.easeOut(duration: 0.2)) {
|
||||||
|
isInputHidden = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case .idle:
|
||||||
|
withAnimation(.easeIn(duration: 0.3)) {
|
||||||
|
isInputHidden = false
|
||||||
|
}
|
||||||
|
default: break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message input area
|
||||||
|
if !isInputHidden {
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
TextField("Send message...", text: $messageText)
|
||||||
|
.font(.system(size: 14))
|
||||||
|
.disabled(isSending)
|
||||||
|
.frame(height: 40)
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Task {
|
||||||
|
await sendMessage()
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
if isSending {
|
||||||
|
ProgressView()
|
||||||
|
.frame(width: 20, height: 20)
|
||||||
|
} else {
|
||||||
|
Image(systemName: "arrow.up.circle.fill")
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 20, height: 20)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.labelStyle(.iconOnly)
|
||||||
|
.buttonStyle(.automatic)
|
||||||
|
.disabled(messageText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || isSending)
|
||||||
|
.frame(width: 40, height: 40)
|
||||||
|
}
|
||||||
|
.padding(.horizontal)
|
||||||
|
.padding(.top, 8)
|
||||||
|
.transition(.move(edge: .bottom).combined(with: .opacity))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.navigationTitle(room.name ?? "Chat")
|
.navigationTitle(room.name ?? "Chat")
|
||||||
.task {
|
.task {
|
||||||
await loadMessages()
|
await loadMessages()
|
||||||
}
|
}
|
||||||
|
.onAppear {
|
||||||
|
setupWebSocketListeners()
|
||||||
|
}
|
||||||
|
.onDisappear {
|
||||||
|
cancellables.forEach { $0.cancel() }
|
||||||
|
cancellables.removeAll()
|
||||||
|
scrollTimer?.invalidate()
|
||||||
|
scrollTimer = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var webSocketStatusMessage: String {
|
||||||
|
switch wsState {
|
||||||
|
case .connected: return "Connected"
|
||||||
|
case .connecting: return "Connecting..."
|
||||||
|
case .disconnected: return "Disconnected"
|
||||||
|
case .serverDown: return "Server Down"
|
||||||
|
case .duplicateDevice: return "Duplicate Device"
|
||||||
|
case .error(let msg): return "Error: \(msg)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func loadMessages() async {
|
private func loadMessages() async {
|
||||||
|
// Prevent reloading if already loaded
|
||||||
|
guard !hasLoadedMessages else { return }
|
||||||
|
|
||||||
guard let token = appState.token, let serverUrl = appState.serverUrl else {
|
guard let token = appState.token, let serverUrl = appState.serverUrl else {
|
||||||
isLoading = false
|
isLoading = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isLoading = true
|
||||||
|
error = nil
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let messages = try await appState.networkService.fetchChatMessages(
|
let messages = try await appState.networkService.fetchChatMessages(
|
||||||
chatRoomId: room.id,
|
chatRoomId: room.id,
|
||||||
@@ -329,6 +425,7 @@ struct ChatRoomView: View {
|
|||||||
)
|
)
|
||||||
// Sort with newest messages first (for flipped list, newest will appear at bottom)
|
// Sort with newest messages first (for flipped list, newest will appear at bottom)
|
||||||
self.messages = messages.sorted { $0.createdAt < $1.createdAt }
|
self.messages = messages.sorted { $0.createdAt < $1.createdAt }
|
||||||
|
hasLoadedMessages = true
|
||||||
} catch {
|
} catch {
|
||||||
print("[watchOS] Error loading messages: \(error.localizedDescription)")
|
print("[watchOS] Error loading messages: \(error.localizedDescription)")
|
||||||
self.error = error
|
self.error = error
|
||||||
@@ -336,6 +433,129 @@ struct ChatRoomView: View {
|
|||||||
|
|
||||||
isLoading = false
|
isLoading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func sendMessage() async {
|
||||||
|
let content = messageText.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
|
guard !content.isEmpty,
|
||||||
|
let token = appState.token,
|
||||||
|
let serverUrl = appState.serverUrl else { return }
|
||||||
|
|
||||||
|
isSending = true
|
||||||
|
|
||||||
|
do {
|
||||||
|
// Generate a nonce for the message
|
||||||
|
let nonce = UUID().uuidString
|
||||||
|
|
||||||
|
// Prepare the request data
|
||||||
|
let messageData: [String: Any] = [
|
||||||
|
"content": content,
|
||||||
|
"attachments_id": [], // Empty for now, can be extended for attachments
|
||||||
|
"meta": [:],
|
||||||
|
"nonce": nonce
|
||||||
|
]
|
||||||
|
|
||||||
|
// Create the URL
|
||||||
|
guard let url = URL(string: "\(serverUrl)/sphere/chat/\(room.id)/messages") else {
|
||||||
|
throw URLError(.badURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the request
|
||||||
|
var request = URLRequest(url: url)
|
||||||
|
request.httpMethod = "POST"
|
||||||
|
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
||||||
|
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||||
|
request.httpBody = try JSONSerialization.data(withJSONObject: messageData, options: [])
|
||||||
|
|
||||||
|
// Send the request
|
||||||
|
let (data, response) = try await URLSession.shared.data(for: request)
|
||||||
|
|
||||||
|
guard let httpResponse = response as? HTTPURLResponse,
|
||||||
|
(200...299).contains(httpResponse.statusCode) else {
|
||||||
|
throw URLError(.badServerResponse)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the response to get the sent message
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
decoder.dateDecodingStrategy = .iso8601
|
||||||
|
decoder.keyDecodingStrategy = .convertFromSnakeCase
|
||||||
|
let sentMessage = try decoder.decode(SnChatMessage.self, from: data)
|
||||||
|
|
||||||
|
// Add the message to the local list
|
||||||
|
messages.append(sentMessage)
|
||||||
|
|
||||||
|
// Clear the input
|
||||||
|
messageText = ""
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
print("[watchOS] Error sending message: \(error.localizedDescription)")
|
||||||
|
// Could show an error alert here
|
||||||
|
}
|
||||||
|
|
||||||
|
isSending = false
|
||||||
|
}
|
||||||
|
|
||||||
|
private func sendReadReceipt() {
|
||||||
|
let data: [String: Any] = ["chat_room_id": room.id]
|
||||||
|
let packet: [String: Any] = ["type": "messages.read", "data": data, "endpoint": "sphere"]
|
||||||
|
if let jsonData = try? JSONSerialization.data(withJSONObject: packet, options: []),
|
||||||
|
let jsonString = String(data: jsonData, encoding: .utf8) {
|
||||||
|
appState.networkService.sendWebSocketMessage(message: jsonString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setupWebSocketListeners() {
|
||||||
|
// Listen for WebSocket packets (new messages)
|
||||||
|
appState.networkService.packetStream
|
||||||
|
.receive(on: DispatchQueue.main) // Ensure UI updates on main thread
|
||||||
|
.sink(receiveCompletion: { completion in
|
||||||
|
if case .failure(let err) = completion {
|
||||||
|
print("[ChatRoomView] WebSocket packet stream error: \(err.localizedDescription)")
|
||||||
|
}
|
||||||
|
}, receiveValue: { packet in
|
||||||
|
if ["messages.new", "messages.update", "messages.delete"].contains(packet.type),
|
||||||
|
let messageData = packet.data {
|
||||||
|
do {
|
||||||
|
let jsonData = try JSONSerialization.data(withJSONObject: messageData, options: [])
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
decoder.dateDecodingStrategy = .iso8601
|
||||||
|
decoder.keyDecodingStrategy = .convertFromSnakeCase
|
||||||
|
let message = try decoder.decode(SnChatMessage.self, from: jsonData)
|
||||||
|
|
||||||
|
if message.chatRoomId == room.id {
|
||||||
|
switch packet.type {
|
||||||
|
case "messages.new":
|
||||||
|
if message.type.hasPrefix("call") {
|
||||||
|
// TODO: Handle ongoing call
|
||||||
|
}
|
||||||
|
if !messages.contains(where: { $0.id == message.id }) {
|
||||||
|
messages.append(message)
|
||||||
|
}
|
||||||
|
sendReadReceipt()
|
||||||
|
case "messages.update":
|
||||||
|
if let index = messages.firstIndex(where: { $0.id == message.id }) {
|
||||||
|
messages[index] = message
|
||||||
|
}
|
||||||
|
case "messages.delete":
|
||||||
|
messages.removeAll(where: { $0.id == message.id })
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print("[ChatRoomView] Error decoding message from websocket: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
// Listen for WebSocket connection state changes
|
||||||
|
appState.networkService.stateStream
|
||||||
|
.receive(on: DispatchQueue.main) // Ensure UI updates on main thread
|
||||||
|
.sink { state in
|
||||||
|
wsState = state
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ChatMessageItem: View {
|
struct ChatMessageItem: View {
|
||||||
@@ -389,12 +609,26 @@ struct ChatMessageItem: View {
|
|||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let content = message.content {
|
if let content = message.content, !content.isEmpty {
|
||||||
Text(content)
|
Text(content)
|
||||||
.font(.system(size: 14))
|
.font(.system(size: 14))
|
||||||
.lineLimit(nil)
|
.lineLimit(nil)
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !message.attachments.isEmpty {
|
||||||
|
AttachmentView(attachment: message.attachments[0])
|
||||||
|
if message.attachments.count > 1 {
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
Image(systemName: "paperclip.circle.fill")
|
||||||
|
.frame(width: 12, height: 12)
|
||||||
|
.foregroundStyle(.gray)
|
||||||
|
Text("\(message.attachments.count - 1)+ attachments")
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundStyle(.gray)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.vertical, 4)
|
.padding(.vertical, 4)
|
||||||
@@ -9,7 +9,7 @@ import SwiftUI
|
|||||||
|
|
||||||
// The main view with the TabView for filtering.
|
// The main view with the TabView for filtering.
|
||||||
struct ExploreView: View {
|
struct ExploreView: View {
|
||||||
@StateObject private var appState = AppState()
|
@EnvironmentObject private var appState: AppState
|
||||||
@State private var isComposing = false
|
@State private var isComposing = false
|
||||||
@State private var selectedTab: String = "Explore"
|
@State private var selectedTab: String = "Explore"
|
||||||
|
|
||||||
@@ -46,17 +46,22 @@ struct ExploreView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.environmentObject(appState)
|
|
||||||
} else {
|
} else {
|
||||||
ProgressView { Text("Connecting to phone...") }
|
VStack {
|
||||||
.onAppear {
|
ProgressView { Text("Syncing...") }
|
||||||
|
Button("Retry") {
|
||||||
appState.requestData()
|
appState.requestData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.sheet(isPresented: $isComposing) {
|
.sheet(isPresented: $isComposing) {
|
||||||
ComposePostView()
|
ComposePostView()
|
||||||
.environmentObject(appState)
|
|
||||||
}
|
}
|
||||||
|
.alert("Error", isPresented: .constant(appState.errorMessage != nil), actions: {
|
||||||
|
Button("OK") { appState.errorMessage = nil }
|
||||||
|
}, message: {
|
||||||
|
Text(appState.errorMessage ?? "")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,14 +81,14 @@ struct StatusCreationView: View {
|
|||||||
Button("Cancel") {
|
Button("Cancel") {
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
.buttonStyle(.glass)
|
.buttonStyle(.automatic)
|
||||||
|
|
||||||
Button(isSubmitting ? "Saving..." : "Save") {
|
Button(isSubmitting ? "Saving..." : "Save") {
|
||||||
Task {
|
Task {
|
||||||
await submitStatus()
|
await submitStatus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.buttonStyle(.glassProminent)
|
.buttonStyle(.automatic)
|
||||||
.disabled(isSubmitting)
|
.disabled(isSubmitting)
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
@@ -9,6 +9,7 @@ import UserNotifications
|
|||||||
import Intents
|
import Intents
|
||||||
import Kingfisher
|
import Kingfisher
|
||||||
import UniformTypeIdentifiers
|
import UniformTypeIdentifiers
|
||||||
|
import KingfisherWebP
|
||||||
|
|
||||||
enum ParseNotificationPayloadError: Error {
|
enum ParseNotificationPayloadError: Error {
|
||||||
case missingMetadata(String)
|
case missingMetadata(String)
|
||||||
@@ -24,6 +25,11 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
_ request: UNNotificationRequest,
|
_ request: UNNotificationRequest,
|
||||||
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
|
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
|
||||||
) {
|
) {
|
||||||
|
KingfisherManager.shared.defaultOptions += [
|
||||||
|
.processor(WebPProcessor.default),
|
||||||
|
.cacheSerializer(WebPSerializer.default)
|
||||||
|
]
|
||||||
|
|
||||||
self.contentHandler = contentHandler
|
self.contentHandler = contentHandler
|
||||||
guard let bestAttemptContent = request.content.mutableCopy() as? UNMutableNotificationContent else {
|
guard let bestAttemptContent = request.content.mutableCopy() as? UNMutableNotificationContent else {
|
||||||
contentHandler(request.content)
|
contentHandler(request.content)
|
||||||
@@ -59,14 +65,44 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let pfpIdentifier = meta["pfp"] as? String
|
let pfpIdentifier = meta["pfp"] as? String
|
||||||
|
|
||||||
let metaCopy = meta as? [String: Any] ?? [:]
|
let metaCopy = meta as? [String: Any] ?? [:]
|
||||||
let pfpUrl = pfpIdentifier != nil ? getAttachmentUrl(for: pfpIdentifier!) : nil
|
let pfpUrl = pfpIdentifier != nil ? getAttachmentUrl(for: pfpIdentifier!) : nil
|
||||||
|
|
||||||
|
let handle = INPersonHandle(value: "\(metaCopy["user_id"] ?? "")", type: .unknown)
|
||||||
|
|
||||||
|
let completeNotificationProcessing: (Data?) -> Void = { imageData in
|
||||||
|
let sender = INPerson(
|
||||||
|
personHandle: handle,
|
||||||
|
nameComponents: PersonNameComponents(nickname: "\(metaCopy["sender_name"] ?? "")"),
|
||||||
|
displayName: content.title,
|
||||||
|
image: imageData == nil ? nil : INImage(imageData: imageData!),
|
||||||
|
contactIdentifier: nil,
|
||||||
|
customIdentifier: nil
|
||||||
|
)
|
||||||
|
|
||||||
|
let intent = self.createMessageIntent(with: sender, meta: metaCopy, body: content.body)
|
||||||
|
self.donateInteraction(for: intent)
|
||||||
|
|
||||||
|
if let updatedContent = try? request.content.updating(from: intent) {
|
||||||
|
if let mutableContent = updatedContent.mutableCopy() as? UNMutableNotificationContent {
|
||||||
|
mutableContent.categoryIdentifier = "CHAT_MESSAGE"
|
||||||
|
self.contentHandler?(mutableContent)
|
||||||
|
} else {
|
||||||
|
self.contentHandler?(updatedContent)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
content.categoryIdentifier = "CHAT_MESSAGE"
|
||||||
|
self.contentHandler?(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let pfpUrl = pfpUrl, let url = URL(string: pfpUrl) {
|
||||||
let targetSize = 512
|
let targetSize = 512
|
||||||
let scaleProcessor = ResizingImageProcessor(referenceSize: CGSize(width: targetSize, height: targetSize), mode: .aspectFit)
|
let scaleProcessor = ResizingImageProcessor(referenceSize: CGSize(width: targetSize, height: targetSize), mode: .aspectFit)
|
||||||
|
|
||||||
KingfisherManager.shared.retrieveImage(with: URL(string: pfpUrl!)!, options: [.processor(scaleProcessor)], completionHandler: { result in
|
KingfisherManager.shared.retrieveImage(with: url, options: [
|
||||||
|
.processor(scaleProcessor)
|
||||||
|
], completionHandler: { result in
|
||||||
var image: Data?
|
var image: Data?
|
||||||
switch result {
|
switch result {
|
||||||
case .success(let value):
|
case .success(let value):
|
||||||
@@ -74,20 +110,11 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
print("Unable to get pfp url: \(error)")
|
print("Unable to get pfp url: \(error)")
|
||||||
}
|
}
|
||||||
|
completeNotificationProcessing(image)
|
||||||
let handle = INPersonHandle(value: "\(metaCopy["user_id"] ?? "")", type: .unknown)
|
|
||||||
let sender = INPerson(
|
|
||||||
personHandle: handle,
|
|
||||||
nameComponents: PersonNameComponents(nickname: "\(metaCopy["sender_name"] ?? "")"),
|
|
||||||
displayName: content.title,
|
|
||||||
image: image == nil ? nil : INImage(imageData: image!),
|
|
||||||
contactIdentifier: nil,
|
|
||||||
customIdentifier: nil
|
|
||||||
)
|
|
||||||
|
|
||||||
content.categoryIdentifier = "CHAT_MESSAGE"
|
|
||||||
self.contentHandler?(content)
|
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
completeNotificationProcessing(nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleDefaultNotification(content: UNMutableNotificationContent) throws {
|
private func handleDefaultNotification(content: UNMutableNotificationContent) throws {
|
||||||
@@ -113,21 +140,29 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
|
|
||||||
guard !attachmentUrls.isEmpty else {
|
guard !attachmentUrls.isEmpty else {
|
||||||
print("Invalid URLs for attachments: \(attachmentUrls)")
|
print("Invalid URLs for attachments: \(attachmentUrls)")
|
||||||
|
self.contentHandler?(content)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let targetSize = 512
|
let targetSize = 512
|
||||||
let scaleProcessor = ResizingImageProcessor(referenceSize: CGSize(width: targetSize, height: targetSize), mode: .aspectFit)
|
let scaleProcessor = ResizingImageProcessor(referenceSize: CGSize(width: targetSize, height: targetSize), mode: .aspectFit)
|
||||||
|
|
||||||
|
let dispatchGroup = DispatchGroup()
|
||||||
|
var attachments: [UNNotificationAttachment] = []
|
||||||
|
let lock = NSLock() // To synchronize access to the attachments array
|
||||||
|
|
||||||
for attachmentUrl in attachmentUrls {
|
for attachmentUrl in attachmentUrls {
|
||||||
guard let remoteUrl = URL(string: attachmentUrl) else {
|
guard let remoteUrl = URL(string: attachmentUrl) else {
|
||||||
print("Invalid URL for attachment: \(attachmentUrl)")
|
print("Invalid URL for attachment: \(attachmentUrl)")
|
||||||
continue // Skip this URL and move to the next one
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dispatchGroup.enter()
|
||||||
|
|
||||||
KingfisherManager.shared.retrieveImage(with: remoteUrl, options: scaleDown ? [
|
KingfisherManager.shared.retrieveImage(with: remoteUrl, options: scaleDown ? [
|
||||||
.processor(scaleProcessor)
|
.processor(scaleProcessor)
|
||||||
] : nil) { [weak self] result in
|
] : nil) { [weak self] result in
|
||||||
|
defer { dispatchGroup.leave() }
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
switch result {
|
switch result {
|
||||||
@@ -139,48 +174,33 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
do {
|
do {
|
||||||
// Write the image data to a temporary file for UNNotificationAttachment
|
// Write the image data to a temporary file for UNNotificationAttachment
|
||||||
try retrievalResult.image.pngData()?.write(to: cachedFileUrl)
|
try retrievalResult.image.pngData()?.write(to: cachedFileUrl)
|
||||||
self.attachLocalMedia(to: content, fileType: type?.identifier, from: cachedFileUrl, withIdentifier: attachmentUrl)
|
|
||||||
|
if let attachment = try? UNNotificationAttachment(identifier: attachmentUrl, url: cachedFileUrl, options: [
|
||||||
|
UNNotificationAttachmentOptionsTypeHintKey: type?.identifier as Any,
|
||||||
|
UNNotificationAttachmentOptionsThumbnailHiddenKey: 0,
|
||||||
|
]) {
|
||||||
|
lock.lock()
|
||||||
|
attachments.append(attachment)
|
||||||
|
lock.unlock()
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
print("Failed to write media to temporary file: \(error.localizedDescription)")
|
print("Failed to write media to temporary file: \(error.localizedDescription)")
|
||||||
self.contentHandler?(content)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
print("Failed to retrieve image: \(error.localizedDescription)")
|
print("Failed to retrieve image: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchGroup.notify(queue: .main) { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
content.attachments = attachments
|
||||||
self.contentHandler?(content)
|
self.contentHandler?(content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func attachLocalMedia(to content: UNMutableNotificationContent, fileType type: String?, from localUrl: URL, withIdentifier identifier: String) {
|
|
||||||
do {
|
|
||||||
let attachment = try UNNotificationAttachment(identifier: identifier, url: localUrl, options: [
|
|
||||||
UNNotificationAttachmentOptionsTypeHintKey: type as Any,
|
|
||||||
UNNotificationAttachmentOptionsThumbnailHiddenKey: 0,
|
|
||||||
])
|
|
||||||
content.attachments = [attachment]
|
|
||||||
} catch let error as NSError {
|
|
||||||
// Log detailed error information
|
|
||||||
print("Failed to create attachment from file at \(localUrl.path)")
|
|
||||||
print("Error: \(error.localizedDescription)")
|
|
||||||
|
|
||||||
// Check specific error codes if needed
|
|
||||||
if error.domain == NSCocoaErrorDomain {
|
|
||||||
switch error.code {
|
|
||||||
case NSFileReadNoSuchFileError:
|
|
||||||
print("File does not exist at \(localUrl.path)")
|
|
||||||
case NSFileReadNoPermissionError:
|
|
||||||
print("No permission to read file at \(localUrl.path)")
|
|
||||||
default:
|
|
||||||
print("Unhandled file error: \(error.code)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call content handler regardless of success or failure
|
|
||||||
self.contentHandler?(content)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func createMessageIntent(with sender: INPerson, meta: [AnyHashable: Any], body: String) -> INSendMessageIntent {
|
private func createMessageIntent(with sender: INPerson, meta: [AnyHashable: Any], body: String) -> INSendMessageIntent {
|
||||||
INSendMessageIntent(
|
INSendMessageIntent(
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"filename" : "Icon-App-1024x1024@1x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"platform" : "watchos",
|
|
||||||
"size" : "1024x1024"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 48 KiB |
@@ -1,15 +0,0 @@
|
|||||||
//
|
|
||||||
// CustomPreviews.swift
|
|
||||||
// WatchRunner Watch App
|
|
||||||
//
|
|
||||||
// Created by LittleSheep on 2025/10/29.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
#Preview {
|
|
||||||
NavigationStack {
|
|
||||||
ActivityListView(filter: "Preview", mockActivities: SnActivity.mock)
|
|
||||||
.environmentObject(AppState())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
//
|
|
||||||
// MockData.swift
|
|
||||||
// WatchRunner Watch App
|
|
||||||
//
|
|
||||||
// Created by LittleSheep on 2025/10/29.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
extension SnActivity {
|
|
||||||
static var mock: [SnActivity] {
|
|
||||||
let mockPublisher = SnPublisher(id: "pub1", name: "Mock Publisher", nick: "mock_nick", description: "A publisher for testing", picture: SnCloudFile(id: "mock_avatar_id", mimeType: "image/png"))
|
|
||||||
let mockTag1 = SnPostTag(id: "tag1", slug: "swiftui", name: "SwiftUI")
|
|
||||||
let mockTag2 = SnPostTag(id: "tag2", slug: "watchos", name: "watchOS")
|
|
||||||
let mockAttachment1 = SnCloudFile(id: "mock_image_id_1", mimeType: "image/jpeg")
|
|
||||||
let mockAttachment2 = SnCloudFile(id: "mock_image_id_2", mimeType: "image/png")
|
|
||||||
|
|
||||||
let post1 = SnPost(id: "1", title: "Hello from a Mock Post!", content: "This is a mock post content. It can be a bit longer to see how it wraps.", publisher: mockPublisher, attachments: [mockAttachment1, mockAttachment2], tags: [mockTag1, mockTag2])
|
|
||||||
let activity1 = SnActivity(id: "1", type: "posts.new", data: .post(post1), createdAt: Date())
|
|
||||||
|
|
||||||
let realm1 = SnRealm(id: "r1", name: "SwiftUI Previews", description: "A place for designing in previews.")
|
|
||||||
let publisher1 = SnPublisher(id: "p1", name: "The Mock Times", nick: "mock_times", description: "All the news that's fit to mock.", picture: nil)
|
|
||||||
let article1 = SnWebArticle(id: "a1", title: "The Art of Mocking Data", url: "https://example.com")
|
|
||||||
|
|
||||||
let discoveryItem1 = DiscoveryItem(type: "realm", data: .realm(realm1))
|
|
||||||
let discoveryItem2 = DiscoveryItem(type: "publisher", data: .publisher(publisher1))
|
|
||||||
let discoveryItem3 = DiscoveryItem(type: "article", data: .article(article1))
|
|
||||||
let discoveryData = DiscoveryData(items: [discoveryItem1, discoveryItem2, discoveryItem3])
|
|
||||||
let activity2 = SnActivity(id: "2", type: "discovery", data: .discovery(discoveryData), createdAt: Date())
|
|
||||||
|
|
||||||
return [activity1, activity2]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
//
|
|
||||||
// AppState.swift
|
|
||||||
// WatchRunner Watch App
|
|
||||||
//
|
|
||||||
// Created by LittleSheep on 2025/10/29.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import Combine
|
|
||||||
|
|
||||||
// MARK: - App State
|
|
||||||
|
|
||||||
@MainActor
|
|
||||||
class AppState: ObservableObject {
|
|
||||||
@Published var token: String? = nil
|
|
||||||
@Published var serverUrl: String? = nil
|
|
||||||
@Published var isReady = false
|
|
||||||
|
|
||||||
let networkService = NetworkService()
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
//
|
|
||||||
// WatchConnectivityService.swift
|
|
||||||
// WatchRunner Watch App
|
|
||||||
//
|
|
||||||
// Created by LittleSheep on 2025/10/29.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import WatchConnectivity
|
|
||||||
import Combine
|
|
||||||
|
|
||||||
// MARK: - Watch Connectivity
|
|
||||||
|
|
||||||
class WatchConnectivityService: NSObject, WCSessionDelegate, ObservableObject {
|
|
||||||
@Published var token: String?
|
|
||||||
@Published var serverUrl: String?
|
|
||||||
|
|
||||||
private let session: WCSession
|
|
||||||
private let userDefaults = UserDefaults.standard
|
|
||||||
private let tokenKey = "token"
|
|
||||||
private let serverUrlKey = "serverUrl"
|
|
||||||
|
|
||||||
override init() {
|
|
||||||
self.session = .default
|
|
||||||
super.init()
|
|
||||||
print("[watchOS] Activating WCSession")
|
|
||||||
self.session.delegate = self
|
|
||||||
self.session.activate()
|
|
||||||
|
|
||||||
// Load cached data
|
|
||||||
self.token = userDefaults.string(forKey: tokenKey)
|
|
||||||
self.serverUrl = userDefaults.string(forKey: serverUrlKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
self.userDefaults.set(token, forKey: self.tokenKey)
|
|
||||||
}
|
|
||||||
if let serverUrl = message["serverUrl"] as? String {
|
|
||||||
self.serverUrl = serverUrl
|
|
||||||
self.userDefaults.set(serverUrl, forKey: self.serverUrlKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
guard let self = self else { return }
|
|
||||||
print("[watchOS] Received reply: \(response)")
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
if let token = response["token"] as? String {
|
|
||||||
self.token = token
|
|
||||||
self.userDefaults.set(token, forKey: self.tokenKey)
|
|
||||||
}
|
|
||||||
if let serverUrl = response["serverUrl"] as? String {
|
|
||||||
self.serverUrl = serverUrl
|
|
||||||
self.userDefaults.set(serverUrl, forKey: self.serverUrlKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} errorHandler: { error in
|
|
||||||
print("[watchOS] sendMessage failed with error: \(error.localizedDescription)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
10
ios/WatchRunner-Watch-App-Info.plist
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?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>UIBackgroundModes</key>
|
||||||
|
<array>
|
||||||
|
<string>remote-notification</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -2,17 +2,19 @@ import 'dart:convert';
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:island/database/message.dart';
|
import 'package:island/database/message.dart';
|
||||||
import 'package:island/database/draft.dart';
|
import 'package:island/database/draft.dart';
|
||||||
|
import 'package:island/models/account.dart';
|
||||||
|
import 'package:island/models/chat.dart';
|
||||||
import 'package:island/models/post.dart';
|
import 'package:island/models/post.dart';
|
||||||
|
|
||||||
part 'drift_db.g.dart';
|
part 'drift_db.g.dart';
|
||||||
|
|
||||||
// Define the database
|
// Define the database
|
||||||
@DriftDatabase(tables: [ChatMessages, PostDrafts])
|
@DriftDatabase(tables: [ChatRooms, ChatMembers, ChatMessages, PostDrafts])
|
||||||
class AppDatabase extends _$AppDatabase {
|
class AppDatabase extends _$AppDatabase {
|
||||||
AppDatabase(super.e);
|
AppDatabase(super.e);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get schemaVersion => 7;
|
int get schemaVersion => 8;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MigrationStrategy get migration => MigrationStrategy(
|
MigrationStrategy get migration => MigrationStrategy(
|
||||||
@@ -55,6 +57,11 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (from < 8) {
|
||||||
|
// Add new tables for separate sender and room data
|
||||||
|
await m.createTable(chatRooms);
|
||||||
|
await m.createTable(chatMembers);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -153,6 +160,7 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
String roomId,
|
String roomId,
|
||||||
String query, {
|
String query, {
|
||||||
bool? withAttachments,
|
bool? withAttachments,
|
||||||
|
Future<SnAccount?> Function(String accountId)? fetchAccount,
|
||||||
}) async {
|
}) async {
|
||||||
var selectStatement = select(chatMessages)
|
var selectStatement = select(chatMessages)
|
||||||
..where((m) => m.roomId.equals(roomId));
|
..where((m) => m.roomId.equals(roomId));
|
||||||
@@ -178,7 +186,11 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
await (selectStatement
|
await (selectStatement
|
||||||
..orderBy([(m) => OrderingTerm.desc(m.createdAt)]))
|
..orderBy([(m) => OrderingTerm.desc(m.createdAt)]))
|
||||||
.get();
|
.get();
|
||||||
return messages.map((msg) => companionToMessage(msg)).toList();
|
final messageFutures =
|
||||||
|
messages
|
||||||
|
.map((msg) => companionToMessage(msg, fetchAccount: fetchAccount))
|
||||||
|
.toList();
|
||||||
|
return await Future.wait(messageFutures);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert between Drift and model objects
|
// Convert between Drift and model objects
|
||||||
@@ -206,12 +218,88 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalChatMessage companionToMessage(ChatMessage dbMessage) {
|
Future<LocalChatMessage> companionToMessage(
|
||||||
|
ChatMessage dbMessage, {
|
||||||
|
Future<SnAccount?> Function(String accountId)? fetchAccount,
|
||||||
|
}) async {
|
||||||
final data = jsonDecode(dbMessage.data);
|
final data = jsonDecode(dbMessage.data);
|
||||||
|
SnChatMember? sender;
|
||||||
|
try {
|
||||||
|
final senderRow =
|
||||||
|
await (select(chatMembers)
|
||||||
|
..where((m) => m.id.equals(dbMessage.senderId))).getSingle();
|
||||||
|
SnAccount senderAccount;
|
||||||
|
senderAccount = SnAccount.fromJson(senderRow.account);
|
||||||
|
|
||||||
|
sender = SnChatMember(
|
||||||
|
id: senderRow.id,
|
||||||
|
chatRoomId: senderRow.chatRoomId,
|
||||||
|
accountId: senderRow.accountId,
|
||||||
|
account: senderAccount,
|
||||||
|
nick: senderRow.nick,
|
||||||
|
role: senderRow.role,
|
||||||
|
notify: senderRow.notify,
|
||||||
|
joinedAt: senderRow.joinedAt,
|
||||||
|
breakUntil: senderRow.breakUntil,
|
||||||
|
timeoutUntil: senderRow.timeoutUntil,
|
||||||
|
isBot: senderRow.isBot,
|
||||||
|
status: null,
|
||||||
|
lastTyped: senderRow.lastTyped,
|
||||||
|
createdAt: senderRow.createdAt,
|
||||||
|
updatedAt: senderRow.updatedAt,
|
||||||
|
deletedAt: senderRow.deletedAt,
|
||||||
|
chatRoom: null,
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
// Fallback to dummy sender with senderId as display name
|
||||||
|
sender = SnChatMember(
|
||||||
|
id: 'unknown',
|
||||||
|
chatRoomId: dbMessage.roomId,
|
||||||
|
accountId: dbMessage.senderId,
|
||||||
|
account: SnAccount(
|
||||||
|
id: 'unknown',
|
||||||
|
name: 'unknown',
|
||||||
|
nick: dbMessage.senderId, // Show the ID instead of Unknown
|
||||||
|
profile: SnAccountProfile(
|
||||||
|
picture: null,
|
||||||
|
id: 'unknown',
|
||||||
|
experience: 0,
|
||||||
|
level: 1,
|
||||||
|
levelingProgress: 0.0,
|
||||||
|
background: null,
|
||||||
|
verification: null,
|
||||||
|
createdAt: DateTime.now(),
|
||||||
|
updatedAt: DateTime.now(),
|
||||||
|
deletedAt: null,
|
||||||
|
),
|
||||||
|
language: '',
|
||||||
|
isSuperuser: false,
|
||||||
|
automatedId: null,
|
||||||
|
perkSubscription: null,
|
||||||
|
deletedAt: null,
|
||||||
|
createdAt: DateTime.now(),
|
||||||
|
updatedAt: DateTime.now(),
|
||||||
|
),
|
||||||
|
nick: dbMessage.senderId, // Show the senderId as fallback
|
||||||
|
role: 0,
|
||||||
|
notify: 0,
|
||||||
|
joinedAt: null,
|
||||||
|
breakUntil: null,
|
||||||
|
timeoutUntil: null,
|
||||||
|
isBot: false,
|
||||||
|
status: null,
|
||||||
|
lastTyped: null,
|
||||||
|
createdAt: DateTime.now(),
|
||||||
|
updatedAt: DateTime.now(),
|
||||||
|
deletedAt: null,
|
||||||
|
chatRoom: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
return LocalChatMessage(
|
return LocalChatMessage(
|
||||||
id: dbMessage.id,
|
id: dbMessage.id,
|
||||||
roomId: dbMessage.roomId,
|
roomId: dbMessage.roomId,
|
||||||
senderId: dbMessage.senderId,
|
senderId: dbMessage.senderId,
|
||||||
|
sender: sender,
|
||||||
data: data,
|
data: data,
|
||||||
createdAt: dbMessage.createdAt,
|
createdAt: dbMessage.createdAt,
|
||||||
status: dbMessage.status,
|
status: dbMessage.status,
|
||||||
@@ -231,6 +319,85 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChatRoomsCompanion companionFromRoom(SnChatRoom room) {
|
||||||
|
return ChatRoomsCompanion(
|
||||||
|
id: Value(room.id),
|
||||||
|
name: Value(room.name),
|
||||||
|
description: Value(room.description),
|
||||||
|
type: Value(room.type),
|
||||||
|
isPublic: Value(room.isPublic),
|
||||||
|
isCommunity: Value(room.isCommunity),
|
||||||
|
picture: Value(room.picture?.toJson()),
|
||||||
|
background: Value(room.background?.toJson()),
|
||||||
|
realmId: Value(room.realmId),
|
||||||
|
createdAt: Value(room.createdAt),
|
||||||
|
updatedAt: Value(room.updatedAt),
|
||||||
|
deletedAt: Value(room.deletedAt),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatMembersCompanion companionFromMember(SnChatMember member) {
|
||||||
|
return ChatMembersCompanion(
|
||||||
|
id: Value(member.id),
|
||||||
|
chatRoomId: Value(member.chatRoomId),
|
||||||
|
accountId: Value(member.accountId),
|
||||||
|
account: Value(member.account.toJson()),
|
||||||
|
nick: Value(member.nick),
|
||||||
|
role: Value(member.role),
|
||||||
|
notify: Value(member.notify),
|
||||||
|
joinedAt: Value(member.joinedAt),
|
||||||
|
breakUntil: Value(member.breakUntil),
|
||||||
|
timeoutUntil: Value(member.timeoutUntil),
|
||||||
|
isBot: Value(member.isBot),
|
||||||
|
status: Value(
|
||||||
|
member.status == null ? null : jsonEncode(member.status!.toJson()),
|
||||||
|
),
|
||||||
|
lastTyped: Value(member.lastTyped),
|
||||||
|
createdAt: Value(member.createdAt),
|
||||||
|
updatedAt: Value(member.updatedAt),
|
||||||
|
deletedAt: Value(member.deletedAt),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> saveChatRooms(List<SnChatRoom> rooms) async {
|
||||||
|
await transaction(() async {
|
||||||
|
// 1. Identify rooms to remove
|
||||||
|
final remoteRoomIds = rooms.map((r) => r.id).toSet();
|
||||||
|
final currentRooms = await select(chatRooms).get();
|
||||||
|
final currentRoomIds = currentRooms.map((r) => r.id).toSet();
|
||||||
|
final idsToRemove = currentRoomIds.difference(remoteRoomIds);
|
||||||
|
|
||||||
|
if (idsToRemove.isNotEmpty) {
|
||||||
|
final idsList = idsToRemove.toList();
|
||||||
|
// Remove messages
|
||||||
|
await (delete(chatMessages)..where((t) => t.roomId.isIn(idsList))).go();
|
||||||
|
// Remove members
|
||||||
|
await (delete(chatMembers)
|
||||||
|
..where((t) => t.chatRoomId.isIn(idsList))).go();
|
||||||
|
// Remove rooms
|
||||||
|
await (delete(chatRooms)..where((t) => t.id.isIn(idsList))).go();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Upsert remote rooms
|
||||||
|
await batch((batch) {
|
||||||
|
for (final room in rooms) {
|
||||||
|
batch.insert(
|
||||||
|
chatRooms,
|
||||||
|
companionFromRoom(room),
|
||||||
|
mode: InsertMode.insertOrReplace,
|
||||||
|
);
|
||||||
|
for (final member in room.members ?? []) {
|
||||||
|
batch.insert(
|
||||||
|
chatMembers,
|
||||||
|
companionFromMember(member),
|
||||||
|
mode: InsertMode.insertOrReplace,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Methods for post drafts
|
// Methods for post drafts
|
||||||
Future<List<SnPost>> getAllPostDrafts() async {
|
Future<List<SnPost>> getAllPostDrafts() async {
|
||||||
final drafts = await select(postDrafts).get();
|
final drafts = await select(postDrafts).get();
|
||||||
@@ -276,4 +443,19 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
return await (select(postDrafts)
|
return await (select(postDrafts)
|
||||||
..where((tbl) => tbl.id.equals(id))).getSingleOrNull();
|
..where((tbl) => tbl.id.equals(id))).getSingleOrNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> saveMember(SnChatMember member) async {
|
||||||
|
await into(
|
||||||
|
chatMembers,
|
||||||
|
).insert(companionFromMember(member), mode: InsertMode.insertOrReplace);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> saveMessageWithSender(LocalChatMessage message) async {
|
||||||
|
// First save the sender if it exists
|
||||||
|
if (message.sender != null) {
|
||||||
|
await saveMember(message.sender!);
|
||||||
|
}
|
||||||
|
// Then save the message
|
||||||
|
return await saveMessage(messageToCompanion(message));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||