[PM-10562] Added the complication to the watchOS app (#836)
10
.github/workflows/build.yml
vendored
@ -156,6 +156,7 @@ jobs:
|
|||||||
"dist_share_extension.mobileprovision"
|
"dist_share_extension.mobileprovision"
|
||||||
"dist_bitwarden_watch_app.mobileprovision"
|
"dist_bitwarden_watch_app.mobileprovision"
|
||||||
"dist_bitwarden_watch_app_extension.mobileprovision"
|
"dist_bitwarden_watch_app_extension.mobileprovision"
|
||||||
|
"dist_bitwarden_watch_widget_extension.mobileprovision"
|
||||||
)
|
)
|
||||||
|
|
||||||
for FILE in "${profiles[@]}"
|
for FILE in "${profiles[@]}"
|
||||||
@ -178,6 +179,7 @@ jobs:
|
|||||||
"dist_beta_share_extension.mobileprovision"
|
"dist_beta_share_extension.mobileprovision"
|
||||||
"dist_beta_bitwarden_watch_app.mobileprovision"
|
"dist_beta_bitwarden_watch_app.mobileprovision"
|
||||||
"dist_beta_bitwarden_watch_app_extension.mobileprovision"
|
"dist_beta_bitwarden_watch_app_extension.mobileprovision"
|
||||||
|
"dist_beta_bitwarden_watch_widget_extension.mobileprovision"
|
||||||
)
|
)
|
||||||
|
|
||||||
for FILE in "${profiles[@]}"
|
for FILE in "${profiles[@]}"
|
||||||
@ -274,6 +276,7 @@ jobs:
|
|||||||
SHARE_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_share_extension.mobileprovision
|
SHARE_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_share_extension.mobileprovision
|
||||||
WATCH_APP_PROFILE_PATH=$HOME/secrets/dist_bitwarden_watch_app.mobileprovision
|
WATCH_APP_PROFILE_PATH=$HOME/secrets/dist_bitwarden_watch_app.mobileprovision
|
||||||
WATCH_APP_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_bitwarden_watch_app_extension.mobileprovision
|
WATCH_APP_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_bitwarden_watch_app_extension.mobileprovision
|
||||||
|
WATCH_WIDGET_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_bitwarden_watch_widget_extension.mobileprovision
|
||||||
PROFILES_DIR_PATH=$HOME/Library/MobileDevice/Provisioning\ Profiles
|
PROFILES_DIR_PATH=$HOME/Library/MobileDevice/Provisioning\ Profiles
|
||||||
|
|
||||||
mkdir -p "$PROFILES_DIR_PATH"
|
mkdir -p "$PROFILES_DIR_PATH"
|
||||||
@ -296,6 +299,9 @@ jobs:
|
|||||||
WATCH_APP_EXTENSION_UUID=$(grep UUID -A1 -a $WATCH_APP_EXTENSION_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
|
WATCH_APP_EXTENSION_UUID=$(grep UUID -A1 -a $WATCH_APP_EXTENSION_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
|
||||||
cp $WATCH_APP_EXTENSION_PROFILE_PATH "$PROFILES_DIR_PATH/$WATCH_APP_EXTENSION_UUID.mobileprovision"
|
cp $WATCH_APP_EXTENSION_PROFILE_PATH "$PROFILES_DIR_PATH/$WATCH_APP_EXTENSION_UUID.mobileprovision"
|
||||||
|
|
||||||
|
WATCH_WIDGET_EXTENSION_UUID=$(grep UUID -A1 -a $WATCH_WIDGET_EXTENSION_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
|
||||||
|
cp $WATCH_WIDGET_EXTENSION_PROFILE_PATH "$PROFILES_DIR_PATH/$WATCH_WIDGET_EXTENSION_UUID.mobileprovision"
|
||||||
|
|
||||||
- name: Configure beta provisioning profiles
|
- name: Configure beta provisioning profiles
|
||||||
if: env.BUILD_VARIANT == 'Beta'
|
if: env.BUILD_VARIANT == 'Beta'
|
||||||
run: |
|
run: |
|
||||||
@ -305,6 +311,7 @@ jobs:
|
|||||||
SHARE_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_beta_share_extension.mobileprovision
|
SHARE_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_beta_share_extension.mobileprovision
|
||||||
WATCH_APP_PROFILE_PATH=$HOME/secrets/dist_beta_bitwarden_watch_app.mobileprovision
|
WATCH_APP_PROFILE_PATH=$HOME/secrets/dist_beta_bitwarden_watch_app.mobileprovision
|
||||||
WATCH_APP_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_beta_bitwarden_watch_app_extension.mobileprovision
|
WATCH_APP_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_beta_bitwarden_watch_app_extension.mobileprovision
|
||||||
|
WATCH_WIDGET_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_beta_bitwarden_watch_widget_extension.mobileprovision
|
||||||
PROFILES_DIR_PATH=$HOME/Library/MobileDevice/Provisioning\ Profiles
|
PROFILES_DIR_PATH=$HOME/Library/MobileDevice/Provisioning\ Profiles
|
||||||
|
|
||||||
mkdir -p "$PROFILES_DIR_PATH"
|
mkdir -p "$PROFILES_DIR_PATH"
|
||||||
@ -327,6 +334,9 @@ jobs:
|
|||||||
WATCH_APP_EXTENSION_UUID=$(grep UUID -A1 -a $WATCH_APP_EXTENSION_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
|
WATCH_APP_EXTENSION_UUID=$(grep UUID -A1 -a $WATCH_APP_EXTENSION_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
|
||||||
cp $WATCH_APP_EXTENSION_PROFILE_PATH "$PROFILES_DIR_PATH/$WATCH_APP_EXTENSION_UUID.mobileprovision"
|
cp $WATCH_APP_EXTENSION_PROFILE_PATH "$PROFILES_DIR_PATH/$WATCH_APP_EXTENSION_UUID.mobileprovision"
|
||||||
|
|
||||||
|
WATCH_WIDGET_EXTENSION_UUID=$(grep UUID -A1 -a $WATCH_WIDGET_EXTENSION_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
|
||||||
|
cp $WATCH_WIDGET_EXTENSION_PROFILE_PATH "$PROFILES_DIR_PATH/$WATCH_WIDGET_EXTENSION_UUID.mobileprovision"
|
||||||
|
|
||||||
- name: Update beta export compliance key
|
- name: Update beta export compliance key
|
||||||
if: env.BUILD_VARIANT == 'Beta'
|
if: env.BUILD_VARIANT == 'Beta'
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@ -626,11 +626,14 @@ class AutofillCredentialServiceTests: BitwardenTestCase { // swiftlint:disable:t
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// `syncIdentities(vaultLockStatus:)` doesn't remove identities if the store's state is disabled.
|
/// `syncIdentities(vaultLockStatus:)` doesn't remove identities if the store's state is disabled.
|
||||||
func test_syncIdentities_removeDisabled() {
|
func test_syncIdentities_removeDisabled() async throws {
|
||||||
|
try await waitAndResetRemoveAllCredentialIdentitiesCalled()
|
||||||
identityStore.state.mockIsEnabled = false
|
identityStore.state.mockIsEnabled = false
|
||||||
|
|
||||||
vaultTimeoutService.vaultLockStatusSubject.send(nil)
|
vaultTimeoutService.vaultLockStatusSubject.send(nil)
|
||||||
waitFor(identityStore.stateCalled)
|
try await waitForAsync {
|
||||||
|
self.identityStore.stateCalled
|
||||||
|
}
|
||||||
|
|
||||||
XCTAssertFalse(identityStore.removeAllCredentialIdentitiesCalled)
|
XCTAssertFalse(identityStore.removeAllCredentialIdentitiesCalled)
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 969 B |
|
Before Width: | Height: | Size: 1.1 KiB |
@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Circular38mm2x.png",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x",
|
|
||||||
"screen-width" : "<=145"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Circular44mm2x.png",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x",
|
|
||||||
"screen-width" : ">183"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"auto-scaling" : "auto"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
{
|
|
||||||
"assets" : [
|
|
||||||
{
|
|
||||||
"filename" : "Circular.imageset",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"role" : "circular"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Extra Large.imageset",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"role" : "extra-large"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Graphic Bezel.imageset",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"role" : "graphic-bezel"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Graphic Circular.imageset",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"role" : "graphic-circular"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Graphic Corner.imageset",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"role" : "graphic-corner"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Graphic Extra Large.imageset",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"role" : "graphic-extra-large"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Graphic Large Rectangular.imageset",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"role" : "graphic-large-rectangular"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Modular.imageset",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"role" : "modular"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "Utilitarian.imageset",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"role" : "utilitarian"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "ExtraLarge38mm2x.png",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x",
|
|
||||||
"screen-width" : "<=145"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "ExtraLarge44mm2x.png",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x",
|
|
||||||
"screen-width" : ">183"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"auto-scaling" : "auto"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "GraphicBezel44mm2x.png",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x",
|
|
||||||
"screen-width" : ">183"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"auto-scaling" : "auto"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 2.2 KiB |
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "GraphicCircular44mm2x.png",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x",
|
|
||||||
"screen-width" : ">183"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"auto-scaling" : "auto"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 2.2 KiB |
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "GraphicCorner44mm2x.png",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x",
|
|
||||||
"screen-width" : ">183"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"auto-scaling" : "auto"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB |
@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "GraphicExtraLarge38mm2x.png",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x",
|
|
||||||
"screen-width" : "<=145"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "GraphicExtraLarge44mm2x.png",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x",
|
|
||||||
"screen-width" : ">183"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"auto-scaling" : "auto"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 6.4 KiB |
@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x",
|
|
||||||
"screen-width" : ">183"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"auto-scaling" : "auto"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "GraphicModular38mm2x.png",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x",
|
|
||||||
"screen-width" : "<=145"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "GraphicModular44mm2x.png",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x",
|
|
||||||
"screen-width" : ">183"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"auto-scaling" : "auto"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "GraphicUtilitarian38mm2x.png",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x",
|
|
||||||
"screen-width" : "<=145"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "GraphicUtilitarian44mm2x.png",
|
|
||||||
"idiom" : "watch",
|
|
||||||
"scale" : "2x",
|
|
||||||
"screen-width" : ">183"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"auto-scaling" : "auto"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
12
BitwardenWatchApp/Assets.xcassets/ComplicationIcon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "bw-logo.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
BitwardenWatchApp/Assets.xcassets/ComplicationIcon.imageset/bw-logo.pdf
vendored
Normal file
@ -6,64 +6,94 @@ class ComplicationController: NSObject, CLKComplicationDataSource {
|
|||||||
func getComplicationDescriptors(handler: @escaping ([CLKComplicationDescriptor]) -> Void) {
|
func getComplicationDescriptors(handler: @escaping ([CLKComplicationDescriptor]) -> Void) {
|
||||||
let descriptors = [
|
let descriptors = [
|
||||||
CLKComplicationDescriptor(
|
CLKComplicationDescriptor(
|
||||||
identifier: "complication",
|
identifier: "bitwarden-watch-complication",
|
||||||
displayName: "Bitwarden",
|
displayName: "Bitwarden",
|
||||||
supportedFamilies: CLKComplicationFamily.allCases
|
supportedFamilies: [
|
||||||
|
CLKComplicationFamily.circularSmall,
|
||||||
|
CLKComplicationFamily.graphicCircular,
|
||||||
|
CLKComplicationFamily.graphicCorner,
|
||||||
|
CLKComplicationFamily.utilitarianSmall,
|
||||||
|
]
|
||||||
),
|
),
|
||||||
// Multiple complication support can be added here with more descriptors
|
|
||||||
]
|
]
|
||||||
|
|
||||||
// Call the handler with the currently supported complication descriptors
|
|
||||||
handler(descriptors)
|
handler(descriptors)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleSharedComplicationDescriptors(_: [CLKComplicationDescriptor]) {
|
|
||||||
// Do any necessary work to support these newly shared complication descriptors
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Timeline Configuration
|
// MARK: - Timeline Configuration
|
||||||
|
|
||||||
func getTimelineEndDate(for _: CLKComplication, withHandler handler: @escaping (Date?) -> Void) {
|
|
||||||
// Call the handler with the last entry date you can currently provide or nil if you can't support future
|
|
||||||
// timelines
|
|
||||||
handler(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPrivacyBehavior(
|
func getPrivacyBehavior(
|
||||||
for _: CLKComplication,
|
for _: CLKComplication,
|
||||||
withHandler handler: @escaping (CLKComplicationPrivacyBehavior) -> Void
|
withHandler handler: @escaping (CLKComplicationPrivacyBehavior) -> Void
|
||||||
) {
|
) {
|
||||||
// Call the handler with your desired behavior when the device is locked
|
|
||||||
handler(.showOnLockScreen)
|
handler(.showOnLockScreen)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Timeline Population
|
// MARK: - Timeline Population
|
||||||
|
|
||||||
func getCurrentTimelineEntry(
|
func getCurrentTimelineEntry(
|
||||||
for _: CLKComplication,
|
for complication: CLKComplication,
|
||||||
withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void
|
withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void
|
||||||
) {
|
) {
|
||||||
// Call the handler with the current timeline entry
|
guard let icon = UIImage(named: "ComplicationIcon") else {
|
||||||
handler(nil)
|
handler(nil)
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
let imageProvider = CLKFullColorImageProvider(fullColorImage: icon)
|
||||||
|
|
||||||
func getTimelineEntries(
|
switch complication.family {
|
||||||
for _: CLKComplication,
|
case .circularSmall:
|
||||||
after _: Date,
|
let template = CLKComplicationTemplateCircularSmallSimpleImage(
|
||||||
limit _: Int,
|
imageProvider: CLKImageProvider(onePieceImage: icon)
|
||||||
withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void
|
)
|
||||||
) {
|
handler(CLKComplicationTimelineEntry(date: .now, complicationTemplate: template))
|
||||||
// Call the handler with the timeline entries after the given date
|
case .graphicCircular:
|
||||||
handler(nil)
|
let template = CLKComplicationTemplateGraphicCircularImage(imageProvider: imageProvider)
|
||||||
|
handler(CLKComplicationTimelineEntry(date: .now, complicationTemplate: template))
|
||||||
|
case .graphicCorner:
|
||||||
|
let template = CLKComplicationTemplateGraphicCornerCircularImage(imageProvider: imageProvider)
|
||||||
|
handler(CLKComplicationTimelineEntry(date: .now, complicationTemplate: template))
|
||||||
|
case .utilitarianSmall:
|
||||||
|
let template = CLKComplicationTemplateUtilitarianSmallSquare(
|
||||||
|
imageProvider: CLKImageProvider(onePieceImage: icon)
|
||||||
|
)
|
||||||
|
handler(CLKComplicationTimelineEntry(date: .now, complicationTemplate: template))
|
||||||
|
default:
|
||||||
|
handler(nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Sample Templates
|
// MARK: - Sample Templates
|
||||||
|
|
||||||
func getLocalizableSampleTemplate(
|
func getLocalizableSampleTemplate(
|
||||||
for _: CLKComplication,
|
for complication: CLKComplication,
|
||||||
withHandler handler: @escaping (CLKComplicationTemplate?) -> Void
|
withHandler handler: @escaping (CLKComplicationTemplate?) -> Void
|
||||||
) {
|
) {
|
||||||
// This method will be called once per supported complication, and the results will be cached
|
guard let icon = UIImage(named: "ComplicationIcon") else {
|
||||||
handler(nil)
|
handler(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let imageProvider = CLKFullColorImageProvider(fullColorImage: icon)
|
||||||
|
|
||||||
|
switch complication.family {
|
||||||
|
case .circularSmall:
|
||||||
|
let template = CLKComplicationTemplateCircularSmallSimpleImage(
|
||||||
|
imageProvider: CLKImageProvider(onePieceImage: icon)
|
||||||
|
)
|
||||||
|
handler(template)
|
||||||
|
case .graphicCircular:
|
||||||
|
let template = CLKComplicationTemplateGraphicCircularImage(imageProvider: imageProvider)
|
||||||
|
handler(template)
|
||||||
|
case .graphicCorner:
|
||||||
|
let template = CLKComplicationTemplateGraphicCornerCircularImage(imageProvider: imageProvider)
|
||||||
|
handler(template)
|
||||||
|
case .utilitarianSmall:
|
||||||
|
let template = CLKComplicationTemplateUtilitarianSmallSquare(
|
||||||
|
imageProvider: CLKImageProvider(onePieceImage: icon)
|
||||||
|
)
|
||||||
|
handler(template)
|
||||||
|
default:
|
||||||
|
handler(nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,8 @@
|
|||||||
<string>$(MARKETING_VERSION)</string>
|
<string>$(MARKETING_VERSION)</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
|
<key>CLKComplicationPrincipalClass</key>
|
||||||
|
<string>$(PRODUCT_MODULE_NAME).ComplicationController</string>
|
||||||
<key>WKApplication</key>
|
<key>WKApplication</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>WKCompanionAppBundleIdentifier</key>
|
<key>WKCompanionAppBundleIdentifier</key>
|
||||||
|
|||||||
29
BitwardenWatchWidgetExtension/Application/Support/Info.plist
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?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>CFBundleDisplayName</key>
|
||||||
|
<string>Bitwarden Watch Widget</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>Bitwarden Watch Widget Extension</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>XPC!</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>$(MARKETING_VERSION)</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
|
<key>NSExtension</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionPointIdentifier</key>
|
||||||
|
<string>com.apple.widgetkit-extension</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
12
BitwardenWatchWidgetExtension/Assets.xcassets/AccentedComplicationIcon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "bw-logo.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
BitwardenWatchWidgetExtension/Assets.xcassets/AccentedComplicationIcon.imageset/bw-logo.pdf
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "Icon-1024.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "watchos",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 30 KiB |
12
BitwardenWatchWidgetExtension/Assets.xcassets/ComplicationIcon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "Icon-100.png",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
BitwardenWatchWidgetExtension/Assets.xcassets/ComplicationIcon.imageset/Icon-100.png
vendored
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
import SwiftUI
|
||||||
|
import WidgetKit
|
||||||
|
|
||||||
|
/// Provider that provides the entries for the widget.
|
||||||
|
struct Provider: TimelineProvider {
|
||||||
|
func placeholder(in context: Context) -> SimpleEntry {
|
||||||
|
SimpleEntry(date: Date())
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) {
|
||||||
|
let entry = SimpleEntry(date: Date())
|
||||||
|
completion(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
|
||||||
|
let entry = SimpleEntry(date: Date())
|
||||||
|
let timeline = Timeline(entries: [entry], policy: .never)
|
||||||
|
completion(timeline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Simple timeline entry to comply with the widget provider.
|
||||||
|
struct SimpleEntry: TimelineEntry {
|
||||||
|
let date: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Entry view to be used to render the widget.
|
||||||
|
struct BitwardenComplicationEntryView: View {
|
||||||
|
/// The widget family.
|
||||||
|
@Environment(\.widgetFamily) var family
|
||||||
|
/// The widget rendering mode.
|
||||||
|
@Environment(\.widgetRenderingMode) var renderingMode
|
||||||
|
|
||||||
|
/// The provider entry
|
||||||
|
var entry: Provider.Entry
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
if renderingMode == .fullColor {
|
||||||
|
Image("ComplicationIcon")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.clipShape(Circle())
|
||||||
|
.padding()
|
||||||
|
} else {
|
||||||
|
Image("AccentedComplicationIcon")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.padding(5)
|
||||||
|
.widgetAccentable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extension entry point of the widget.
|
||||||
|
@main
|
||||||
|
struct BitwardenWatchWidgetExtension: Widget {
|
||||||
|
let kind: String = "BitwardenWatchWidgetExtension"
|
||||||
|
|
||||||
|
var body: some WidgetConfiguration {
|
||||||
|
StaticConfiguration(kind: kind, provider: Provider()) { entry in
|
||||||
|
if #available(watchOS 10.0, *) {
|
||||||
|
BitwardenComplicationEntryView(entry: entry)
|
||||||
|
.containerBackground(.fill.tertiary, for: .widget)
|
||||||
|
} else {
|
||||||
|
BitwardenComplicationEntryView(entry: entry)
|
||||||
|
.padding()
|
||||||
|
.background()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.configurationDisplayName("Bitwarden")
|
||||||
|
.supportedFamilies([.accessoryCircular, .accessoryCorner, .accessoryInline])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(watchOS 10.0, *)
|
||||||
|
#Preview(as: .accessoryCorner) {
|
||||||
|
BitwardenWatchWidgetExtension()
|
||||||
|
} timeline: {
|
||||||
|
SimpleEntry(date: .now)
|
||||||
|
}
|
||||||
BIN
BitwardenWatchWidgetExtension/Icon-50.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
@ -1,7 +1,8 @@
|
|||||||
#include "./Common.xcconfig"
|
#include "./Common.xcconfig"
|
||||||
|
#include "./WatchCommon.xcconfig"
|
||||||
#include? "./Local.xcconfig"
|
#include? "./Local.xcconfig"
|
||||||
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon-Dev
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon-Dev
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = $(BASE_BUNDLE_ID).watchkitapp
|
PRODUCT_BUNDLE_IDENTIFIER = $(BASE_WATCH_BUNDLE_ID)
|
||||||
WK_COMPANION_APP_BUNDLE_IDENTIFIER = $(BASE_BUNDLE_ID)
|
WK_COMPANION_APP_BUNDLE_IDENTIFIER = $(BASE_BUNDLE_ID)
|
||||||
PROVISIONING_PROFILE_SPECIFIER = $(PROVISIONING_PROFILE_SPECIFIER_WATCH_APP)
|
PROVISIONING_PROFILE_SPECIFIER = $(PROVISIONING_PROFILE_SPECIFIER_WATCH_APP)
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
#include "./Common.xcconfig"
|
#include "./Common.xcconfig"
|
||||||
|
#include "./WatchCommon.xcconfig"
|
||||||
#include? "./Local.xcconfig"
|
#include? "./Local.xcconfig"
|
||||||
|
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = $(APPICON_NAME)
|
ASSETCATALOG_COMPILER_APPICON_NAME = $(APPICON_NAME)
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = $(BASE_BUNDLE_ID).watchkitapp
|
PRODUCT_BUNDLE_IDENTIFIER = $(BASE_WATCH_BUNDLE_ID)
|
||||||
WK_COMPANION_APP_BUNDLE_IDENTIFIER = $(BASE_BUNDLE_ID)
|
WK_COMPANION_APP_BUNDLE_IDENTIFIER = $(BASE_BUNDLE_ID)
|
||||||
PROVISIONING_PROFILE_SPECIFIER = $(PROVISIONING_PROFILE_SPECIFIER_WATCH_APP)
|
PROVISIONING_PROFILE_SPECIFIER = $(PROVISIONING_PROFILE_SPECIFIER_WATCH_APP)
|
||||||
|
|||||||
6
Configs/BitwardenWatchWidgetExtension.xcconfig
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include "./Common.xcconfig"
|
||||||
|
#include "./WatchCommon.xcconfig"
|
||||||
|
#include? "./Local.xcconfig"
|
||||||
|
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = $(BASE_WATCH_BUNDLE_ID).widget-extension
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = $(PROVISIONING_PROFILE_SPECIFIER_WATCH_WIDGET_EXTENSION)
|
||||||
@ -18,6 +18,7 @@ APPICON_NAME = AppIcon
|
|||||||
// PROVISIONING_PROFILE_SPECIFIER_AUTOFILL_EXTENSION = <Optional provisioning profile specifier for the autofill extension>
|
// PROVISIONING_PROFILE_SPECIFIER_AUTOFILL_EXTENSION = <Optional provisioning profile specifier for the autofill extension>
|
||||||
// PROVISIONING_PROFILE_SPECIFIER_SHARE_EXTENSION = <Optional provisioning profile specifier for the share extension>
|
// PROVISIONING_PROFILE_SPECIFIER_SHARE_EXTENSION = <Optional provisioning profile specifier for the share extension>
|
||||||
// PROVISIONING_PROFILE_SPECIFIER_WATCH_APP = <Optional provisioning profile specifier for the watch app>
|
// PROVISIONING_PROFILE_SPECIFIER_WATCH_APP = <Optional provisioning profile specifier for the watch app>
|
||||||
|
// PROVISIONING_PROFILE_SPECIFIER_WATCH_WIDGET_EXTENSION = <Optional provisioning profile specifier for the watch widget extension>
|
||||||
//
|
//
|
||||||
// This should allow Xcode to build the application based on these settings without
|
// This should allow Xcode to build the application based on these settings without
|
||||||
// code signing errors or having to modify the project itself.
|
// code signing errors or having to modify the project itself.
|
||||||
|
|||||||
4
Configs/WatchCommon.xcconfig
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#include "./Common.xcconfig"
|
||||||
|
#include? "./Local.xcconfig"
|
||||||
|
|
||||||
|
BASE_WATCH_BUNDLE_ID = $(BASE_BUNDLE_ID).watchkitapp
|
||||||
@ -49,6 +49,7 @@ PROVISIONING_PROFILE_SPECIFIER_ACTION_EXTENSION = ${profile_prefix} Extension
|
|||||||
PROVISIONING_PROFILE_SPECIFIER_AUTOFILL_EXTENSION = ${profile_prefix} Autofill
|
PROVISIONING_PROFILE_SPECIFIER_AUTOFILL_EXTENSION = ${profile_prefix} Autofill
|
||||||
PROVISIONING_PROFILE_SPECIFIER_SHARE_EXTENSION = ${profile_prefix} Share Extension
|
PROVISIONING_PROFILE_SPECIFIER_SHARE_EXTENSION = ${profile_prefix} Share Extension
|
||||||
PROVISIONING_PROFILE_SPECIFIER_WATCH_APP = ${profile_prefix} Bitwarden Watch App
|
PROVISIONING_PROFILE_SPECIFIER_WATCH_APP = ${profile_prefix} Bitwarden Watch App
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER_WATCH_WIDGET_EXTENSION = ${profile_prefix} Bitwarden Watch Widget Extension
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat << EOF > ${export_options_file}
|
cat << EOF > ${export_options_file}
|
||||||
@ -70,6 +71,8 @@ cat << EOF > ${export_options_file}
|
|||||||
<string>${profile_prefix} Share Extension</string>
|
<string>${profile_prefix} Share Extension</string>
|
||||||
<key>${ios_bundle_id}.watchkitapp</key>
|
<key>${ios_bundle_id}.watchkitapp</key>
|
||||||
<string>${profile_prefix} Bitwarden Watch App</string>
|
<string>${profile_prefix} Bitwarden Watch App</string>
|
||||||
|
<key>${ios_bundle_id}.watchkitapp.widget-extension</key>
|
||||||
|
<string>${profile_prefix} Bitwarden Watch Widget Extension</string>
|
||||||
</dict>
|
</dict>
|
||||||
<key>manageAppVersionAndBuildNumber</key>
|
<key>manageAppVersionAndBuildNumber</key>
|
||||||
<false/>
|
<false/>
|
||||||
|
|||||||
18
project.yml
@ -117,6 +117,10 @@ schemes:
|
|||||||
build:
|
build:
|
||||||
targets:
|
targets:
|
||||||
BitwardenWatchApp: all
|
BitwardenWatchApp: all
|
||||||
|
BitwardenWatchWidgetExtension:
|
||||||
|
build:
|
||||||
|
targets:
|
||||||
|
BitwardenWatchWidgetExtension: all
|
||||||
targets:
|
targets:
|
||||||
Bitwarden:
|
Bitwarden:
|
||||||
type: application
|
type: application
|
||||||
@ -396,6 +400,7 @@ targets:
|
|||||||
- path: BitwardenWatchApp/GoogleService-Info.plist
|
- path: BitwardenWatchApp/GoogleService-Info.plist
|
||||||
buildPhase: resources
|
buildPhase: resources
|
||||||
dependencies:
|
dependencies:
|
||||||
|
- target: BitwardenWatchWidgetExtension
|
||||||
- package: Firebase
|
- package: Firebase
|
||||||
product: FirebaseCrashlytics
|
product: FirebaseCrashlytics
|
||||||
postBuildScripts:
|
postBuildScripts:
|
||||||
@ -405,3 +410,16 @@ targets:
|
|||||||
inputFiles:
|
inputFiles:
|
||||||
- ${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}
|
- ${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}
|
||||||
- ${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}
|
- ${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}
|
||||||
|
|
||||||
|
BitwardenWatchWidgetExtension:
|
||||||
|
type: app-extension
|
||||||
|
platform: watchOS
|
||||||
|
deploymentTarget: 9.0
|
||||||
|
configFiles:
|
||||||
|
Debug: Configs/BitwardenWatchWidgetExtension.xcconfig
|
||||||
|
Release: Configs/BitwardenWatchWidgetExtension.xcconfig
|
||||||
|
settings:
|
||||||
|
base:
|
||||||
|
INFOPLIST_FILE: BitwardenWatchWidgetExtension/Application/Support/Info.plist
|
||||||
|
sources:
|
||||||
|
- path: BitwardenWatchWidgetExtension
|
||||||
|
|||||||