1
0
mirror of https://github.com/bitwarden/mobile synced 2026-02-04 10:33:14 +00:00

Compare commits

..

2 Commits

Author SHA1 Message Date
Carlos Gonçalves
13c9f3f0d2 Merge branch 'main' into vault/pm-950 2024-05-28 22:09:54 +01:00
Carlos Gonçalves
0968c456e4 PM-950 Added views in case personal ownership policy is true 2024-05-28 22:06:23 +01:00
38 changed files with 403 additions and 148 deletions

View File

@@ -85,6 +85,11 @@ jobs:
- name: Set up MSBuild
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2.0.0
# This step might be obsolete at some point as .NET MAUI workloads
# are starting to come pre-installed on the GH Actions build agents.
- name: Install MAUI Workload
run: dotnet workload install maui --ignore-failed-sources
- name: Setup Windows builder
run: choco install checksum --no-progress
@@ -140,7 +145,7 @@ jobs:
- name: Increment version
run: |
BUILD_NUMBER=$((11000 + $GITHUB_RUN_NUMBER))
BUILD_NUMBER=$((3000 + $GITHUB_RUN_NUMBER))
echo "##### Setting Android Version Code to $BUILD_NUMBER" | tee -a $GITHUB_STEP_SUMMARY
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \
@@ -307,6 +312,11 @@ jobs:
- name: Set up MSBuild
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2.0.0
# This step might be obsolete at some point as .NET MAUI workloads
# are starting to come pre-installed on the GH Actions build agents.
- name: Install MAUI Workload
run: dotnet workload install maui --ignore-failed-sources
- name: Setup Windows builder
run: choco install checksum --no-progress
@@ -344,7 +354,7 @@ jobs:
- name: Increment version
run: |
BUILD_NUMBER=$((11000 + $GITHUB_RUN_NUMBER))
BUILD_NUMBER=$((3000 + $GITHUB_RUN_NUMBER))
echo "##### Setting F-Droid Version Code to $BUILD_NUMBER" | tee -a $GITHUB_STEP_SUMMARY
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \
@@ -509,7 +519,7 @@ jobs:
- name: Increment version
run: |
BUILD_NUMBER=$((8000 + $GITHUB_RUN_NUMBER))
BUILD_NUMBER=$((100 + $GITHUB_RUN_NUMBER))
echo "##### Setting iOS CFBundleVersion to $BUILD_NUMBER" | tee -a $GITHUB_STEP_SUMMARY
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./${{ env.ios_folder_path }}/Info.plist
@@ -723,7 +733,7 @@ jobs:
secrets: "crowdin-api-token"
- name: Upload Sources
uses: crowdin/github-action@61ac8b980551f674046220c3e104bddae2916ac5 # v2.0.0
uses: crowdin/github-action@30849777a3cba6ee9a09e24e195272b8287a0a5b # v1.20.4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}

View File

@@ -30,7 +30,7 @@ jobs:
secrets: "crowdin-api-token, github-gpg-private-key, github-gpg-private-key-passphrase"
- name: Download translations
uses: crowdin/github-action@61ac8b980551f674046220c3e104bddae2916ac5 # v2.0.0
uses: crowdin/github-action@30849777a3cba6ee9a09e24e195272b8287a0a5b # v1.20.4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}

View File

@@ -67,29 +67,22 @@ jobs:
- name: Download all artifacts
if: ${{ inputs.release_type != 'Dry Run' }}
uses: bitwarden/gh-actions/download-artifacts@main
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
with:
workflow: build.yml
workflow_conclusion: success
branch: ${{ steps.branch.outputs.branch-name }}
skip_unpack: true
- name: Dry Run - Download all artifacts
if: ${{ inputs.release_type == 'Dry Run' }}
uses: bitwarden/gh-actions/download-artifacts@main
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
with:
workflow: build.yml
workflow_conclusion: success
branch: main
skip_unpack: true
- name: Unzip release assets
run: |
unzip bw-android-apk-sha256.txt.zip -d bw-android-apk-sha256.txt
unzip bw-fdroid-apk-sha256.txt.zip -d bw-fdroid-apk-sha256.txt
unzip com.x8bit.bitwarden-fdroid.apk.zip -d com.x8bit.bitwarden-fdroid.apk
unzip com.x8bit.bitwarden.aab.zip -d com.x8bit.bitwarden.aab
unzip com.x8bit.bitwarden.apk.zip -d com.x8bit.bitwarden.apk
- name: Prep Bitwarden iOS release asset
run: zip -r Bitwarden\ iOS.zip Bitwarden\ iOS
- name: Create release
if: ${{ inputs.release_type != 'Dry Run' }}
@@ -136,7 +129,7 @@ jobs:
- name: Download F-Droid .apk artifact
if: ${{ inputs.release_type != 'Dry Run' }}
uses: bitwarden/gh-actions/download-artifacts@main
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
with:
workflow: build.yml
workflow_conclusion: success
@@ -145,7 +138,7 @@ jobs:
- name: Dry Run - Download F-Droid .apk artifact
if: ${{ inputs.release_type == 'Dry Run' }}
uses: bitwarden/gh-actions/download-artifacts@main
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
with:
workflow: build.yml
workflow_conclusion: success

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionCode="1" android:versionName="2024.7.0" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionCode="1" android:versionName="2024.5.2" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.NFC" />

View File

@@ -11,7 +11,7 @@
<key>CFBundleIdentifier</key>
<string>com.8bit.bitwarden</string>
<key>CFBundleShortVersionString</key>
<string>2024.7.0</string>
<string>2024.5.2</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CFBundleIconName</key>

View File

@@ -41,6 +41,7 @@ namespace Bit.Core.Abstractions
Task<CipherResponse> PutShareCipherAsync(string id, CipherShareRequest request);
Task PutDeleteCipherAsync(string id);
Task<CipherResponse> PutRestoreCipherAsync(string id);
Task<bool> HasUnassignedCiphersAsync();
Task RefreshIdentityTokenAsync();
Task<SsoPrevalidateResponse> PreValidateSsoAsync(string identifier);
Task<TResponse> SendAsync<TRequest, TResponse>(HttpMethod method, string path,

View File

@@ -36,5 +36,6 @@ namespace Bit.Core.Abstractions
Task RestoreWithServerAsync(string id);
Task<string> CreateNewLoginForPasskeyAsync(Fido2ConfirmNewCredentialParams newPasskeyParams);
Task CopyTotpCodeIfNeededAsync(CipherView cipher);
Task<bool> VerifyOrganizationHasUnassignedItemsAsync();
}
}

View File

@@ -187,6 +187,8 @@ namespace Bit.Core.Abstractions
Task<BwRegion?> GetPreAuthRegionAsync();
Task SetPreAuthRegionAsync(BwRegion value);
Task ReloadStateAsync();
Task<bool> GetShouldCheckOrganizationUnassignedItemsAsync(string userId = null);
Task SetShouldCheckOrganizationUnassignedItemsAsync(bool shouldCheck, string userId = null);
[Obsolete("Use GetPinKeyEncryptedUserKeyAsync instead, left for migration purposes")]
Task<string> GetPinProtectedAsync(string userId = null);
[Obsolete("Use SetPinKeyEncryptedUserKeyAsync instead, left for migration purposes")]

View File

@@ -45,6 +45,8 @@ namespace Bit.Core
public const string PasswordlessLoginRequestKey = "passwordlessLoginRequest";
public const string PreLoginEmailKey = "preLoginEmailKey";
public const string ConfigsKey = "configsKey";
public const string DisplayEuEnvironmentFlag = "display-eu-environment";
public const string UnassignedItemsBannerFlag = "unassigned-items-banner";
public const string RegionEnvironment = "regionEnvironment";
public const string DuoCallback = "bitwarden://duo-callback";
public const string NavigateToMessageCommand = "navigateTo";
@@ -137,6 +139,7 @@ namespace Bit.Core
public static string ShouldConnectToWatchKey(string userId) => $"shouldConnectToWatch_{userId}";
public static string ScreenCaptureAllowedKey(string userId) => $"screenCaptureAllowed_{userId}";
public static string PendingAdminAuthRequest(string userId) => $"pendingAdminAuthRequest_{userId}";
public static string ShouldCheckOrganizationUnassignedItemsKey(string userId) => $"shouldCheckOrganizationUnassignedItems_{userId}";
[Obsolete]
public static string KeyKey(string userId) => $"key_{userId}";
[Obsolete]

View File

@@ -27,6 +27,7 @@ namespace Bit.App.Models
public bool HideAccountSwitcher { get; set; }
public OtpData? OtpData { get; set; }
public bool HasUnlockedInThisTransaction { get; set; }
public bool HasJustLoggedInOrUnlocked { get; set; }
public void SetAllFrom(AppOptions o)
{

View File

@@ -25,6 +25,7 @@ namespace Bit.App.Pages
private bool _rememberEmail;
private string _email;
private string _selectedEnvironmentName;
private bool _displayEuEnvironment;
public HomeViewModel()
{
@@ -115,6 +116,7 @@ namespace Bit.App.Pages
{
Email = await _stateService.GetRememberedEmailAsync();
RememberEmail = !string.IsNullOrEmpty(Email);
_displayEuEnvironment = await _configService.GetFeatureFlagBoolAsync(Constants.DisplayEuEnvironmentFlag, forceRefresh: true);
}
public async Task ContinueToLoginStepAsync()
@@ -156,7 +158,11 @@ namespace Bit.App.Pages
public async Task ShowEnvironmentPickerAsync()
{
var options = new string[] { BwRegion.US.Domain(), BwRegion.EU.Domain(), AppResources.SelfHosted };
_displayEuEnvironment = await _configService.GetFeatureFlagBoolAsync(Constants.DisplayEuEnvironmentFlag);
var options = _displayEuEnvironment
? new string[] { BwRegion.US.Domain(), BwRegion.EU.Domain(), AppResources.SelfHosted }
: new string[] { BwRegion.US.Domain(), AppResources.SelfHosted };
await MainThread.InvokeOnMainThreadAsync(async () =>
{
var result = await _deviceActionService.Value.DisplayActionSheetAsync(AppResources.LoggingInOn, AppResources.Cancel, null, options);

View File

@@ -232,6 +232,11 @@ namespace Bit.App.Pages
return;
}
var previousPage = await AppHelpers.ClearPreviousPage();
if (_appOptions != null)
{
_appOptions.HasJustLoggedInOrUnlocked = true;
}
App.MainPage = new TabsPage(_appOptions, previousPage);
}
}

View File

@@ -35,6 +35,11 @@ namespace Bit.App.Pages
{
return;
}
if (_appOptions != null)
{
_appOptions.HasJustLoggedInOrUnlocked = true;
}
var previousPage = await AppHelpers.ClearPreviousPage();
App.MainPage = new TabsPage(_appOptions, previousPage);
}

View File

@@ -196,6 +196,11 @@ namespace Bit.App.Pages
{
return;
}
if (_appOptions != null)
{
_appOptions.HasJustLoggedInOrUnlocked = true;
}
var previousPage = await AppHelpers.ClearPreviousPage();
App.MainPage = new TabsPage(_appOptions, previousPage);
}

View File

@@ -56,6 +56,11 @@ namespace Bit.App.Pages
{
return;
}
if (_appOptions != null)
{
_appOptions.HasJustLoggedInOrUnlocked = true;
}
var previousPage = await AppHelpers.ClearPreviousPage();
App.MainPage = new TabsPage(_appOptions, previousPage);
}

View File

@@ -71,6 +71,11 @@ namespace Bit.App.Pages
{
return;
}
if (_appOptions != null)
{
_appOptions.HasJustLoggedInOrUnlocked = true;
}
var previousPage = await AppHelpers.ClearPreviousPage();
App.MainPage = new TabsPage(_appOptions, previousPage);
}

View File

@@ -207,6 +207,11 @@ namespace Bit.App.Pages
{
return;
}
if (_appOptions != null)
{
_appOptions.HasJustLoggedInOrUnlocked = true;
}
var previousPage = await AppHelpers.ClearPreviousPage();
App.MainPage = new TabsPage(_appOptions, previousPage);
}

View File

@@ -33,7 +33,7 @@ namespace Bit.App.Pages
_keyConnectorService = ServiceContainer.Resolve<IKeyConnectorService>("keyConnectorService");
_stateService = ServiceContainer.Resolve<IStateService>();
_groupingsPage = new NavigationPage(new GroupingsPage(true, previousPage: previousPage))
_groupingsPage = new NavigationPage(new GroupingsPage(true, previousPage: previousPage, appOptions: appOptions))
{
Title = AppResources.MyVault,
IconImageSource = "lock.png"

View File

@@ -28,7 +28,7 @@ namespace Bit.App.Pages
public GroupingsPage(bool mainPage, CipherType? type = null, string folderId = null,
string collectionId = null, string pageTitle = null, string vaultFilterSelection = null,
PreviousPageInfo previousPage = null, bool deleted = false, bool showTotp = false)
PreviousPageInfo previousPage = null, bool deleted = false, bool showTotp = false, AppOptions appOptions = null)
{
_pageName = string.Concat(nameof(GroupingsPage), "_", DateTime.UtcNow.Ticks);
InitializeComponent();
@@ -51,6 +51,7 @@ namespace Bit.App.Pages
_vm.CollectionId = collectionId;
_vm.Deleted = deleted;
_vm.ShowTotp = showTotp;
_vm.AppOptions = appOptions;
_previousPage = previousPage;
if (pageTitle != null)
{
@@ -161,6 +162,8 @@ namespace Bit.App.Pages
return;
}
await _vm.CheckOrganizationUnassignedItemsAsync();
// Push registration
var lastPushRegistration = await _stateService.GetPushLastRegistrationDateAsync();
lastPushRegistration = lastPushRegistration.GetValueOrDefault(DateTime.MinValue);

View File

@@ -46,6 +46,8 @@ namespace Bit.App.Pages
private readonly IPasswordRepromptService _passwordRepromptService;
private readonly IOrganizationService _organizationService;
private readonly IPolicyService _policyService;
private readonly IConfigService _configService;
private readonly IEnvironmentService _environmentService;
private readonly ILogger _logger;
public GroupingsPageViewModel()
@@ -62,6 +64,8 @@ namespace Bit.App.Pages
_passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService");
_organizationService = ServiceContainer.Resolve<IOrganizationService>("organizationService");
_policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
_configService = ServiceContainer.Resolve<IConfigService>();
_environmentService = ServiceContainer.Resolve<IEnvironmentService>();
_logger = ServiceContainer.Resolve<ILogger>("logger");
Loading = true;
@@ -105,6 +109,7 @@ namespace Bit.App.Pages
public List<Core.Models.View.CollectionView> Collections { get; set; }
public List<TreeNode<Core.Models.View.CollectionView>> NestedCollections { get; set; }
public AppOptions AppOptions { get; internal set; }
protected override ICipherService cipherService => _cipherService;
protected override IPolicyService policyService => _policyService;
protected override IOrganizationService organizationService => _organizationService;
@@ -700,5 +705,59 @@ namespace Bit.App.Pages
var folders = decFolders.Where(f => _allCiphers.Any(c => c.FolderId == f.Id)).ToList();
return folders.Any() ? folders : null;
}
internal async Task CheckOrganizationUnassignedItemsAsync()
{
try
{
if (AppOptions?.HasJustLoggedInOrUnlocked != true)
{
return;
}
AppOptions.HasJustLoggedInOrUnlocked = false;
if (!await _configService.GetFeatureFlagBoolAsync(Core.Constants.UnassignedItemsBannerFlag)
||
!await _stateService.GetShouldCheckOrganizationUnassignedItemsAsync())
{
return;
}
var waitSyncTask = Task.Run(async () =>
{
while (_syncService.SyncInProgress)
{
await Task.Delay(100);
}
});
await waitSyncTask.WaitAsync(TimeSpan.FromMinutes(5));
if (!await _cipherService.VerifyOrganizationHasUnassignedItemsAsync())
{
return;
}
var message = _environmentService.SelectedRegion == Core.Enums.Region.SelfHosted
? AppResources.OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong
: AppResources.OrganizationUnassignedItemsMessageUSEUDescriptionLong;
var response = await _deviceActionService.DisplayAlertAsync(AppResources.Notice,
message,
null,
AppResources.RemindMeLater,
AppResources.Ok);
if (response == AppResources.Ok)
{
await _stateService.SetShouldCheckOrganizationUnassignedItemsAsync(false);
}
}
catch (TimeoutException) { }
catch (Exception ex)
{
_logger.Exception(ex);
}
}
}
}

View File

@@ -1328,7 +1328,7 @@ namespace Bit.Core.Resources.Localization {
}
/// <summary>
/// Looks up a localized string similar to Bitwarden help center.
/// Looks up a localized string similar to Bitwarden Help Center.
/// </summary>
public static string BitwardenHelpCenter {
get {
@@ -4929,6 +4929,15 @@ namespace Bit.Core.Resources.Localization {
}
}
/// <summary>
/// Looks up a localized string similar to Notice.
/// </summary>
public static string Notice {
get {
return ResourceManager.GetString("Notice", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to This account has two-step login set up, however, none of the configured two-step providers are supported on this device. Please use a supported device and/or add additional providers that are better supported across devices (such as an authenticator app)..
/// </summary>
@@ -5164,6 +5173,24 @@ namespace Bit.Core.Resources.Localization {
}
}
/// <summary>
/// Looks up a localized string similar to On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible..
/// </summary>
public static string OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong {
get {
return ResourceManager.GetString("OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible..
/// </summary>
public static string OrganizationUnassignedItemsMessageUSEUDescriptionLong {
get {
return ResourceManager.GetString("OrganizationUnassignedItemsMessageUSEUDescriptionLong", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Organization identifier.
/// </summary>
@@ -5849,6 +5876,15 @@ namespace Bit.Core.Resources.Localization {
}
}
/// <summary>
/// Looks up a localized string similar to Remind me later.
/// </summary>
public static string RemindMeLater {
get {
return ResourceManager.GetString("RemindMeLater", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Remove.
/// </summary>

View File

@@ -422,7 +422,7 @@
<value>خدمة التعبئة التلقائية</value>
</data>
<data name="SetBitwardenAsPasskeyManagerDescription" xml:space="preserve">
<value>تعيين Bitwarden كموفر مفتاح المرور الخاص بك في إعدادات الجهاز.</value>
<value>Set Bitwarden as your passkey provider in device settings.</value>
</data>
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
<value>تجنب الأحرف الغامضة</value>

View File

@@ -2818,7 +2818,7 @@ Haluatko vaihtaa tähän tiliin?</value>
<value>Tekstinsisäistä automattitäyttöä käytetään, jos aktiivinen näppäimistö tukee sitä. Muussa tapauksessa käytetään ponnahdusvalintaa.</value>
</data>
<data name="AdditionalOptions" xml:space="preserve">
<value>Lisävalinnat</value>
<value>Lisäasetukset</value>
</data>
<data name="ContinueToWebApp" xml:space="preserve">
<value>Avataanko verkkosovellus?</value>

View File

@@ -1662,7 +1662,7 @@ Nolasīšana notiks automātiski.</value>
<value>Jāapstiprina identitāte, lai turpinātu.</value>
</data>
<data name="ExportVaultWarning" xml:space="preserve">
<value>Šī izguve satur glabātavas datus nešifrētā veidā. Izto datni nevajadzētu glabāt vai sūtīt nedrošos veidos (piemēram, e-pastā). Tā ir jāizdzēš uzreiz pēc izmantošanas.</value>
<value>Šī izguve satur glabātavas datus nešifrētā veidā. Izdoto datni nevajadzētu glabāt vai sūtīt nedrošos veidos (piemēram, e-pastā). Izdzēst to uzreiz pēc izmantošanas.</value>
</data>
<data name="EncExportKeyWarning" xml:space="preserve">
<value>Šī izguve šifrē datus ar konta šifrēšanas atslēgu. Ja tā jebkad tiks mainīta, izvadi vajadzētu veikt vēlreiz, jo vairs nebūs iespējams atšifrēt šo datni.</value>

View File

@@ -961,7 +961,7 @@ A leitura será efetuada automaticamente.</value>
<value>Ambiente personalizado</value>
</data>
<data name="CustomEnvironmentFooter" xml:space="preserve">
<value>Para utilizadores avançados. Pode especificar o URL de base de cada serviço de forma independente.</value>
<value>Para utilizadores avançados. Pode especificar o URL de base de cada serviço independentemente.</value>
</data>
<data name="EnvironmentSaved" xml:space="preserve">
<value>Os URLs de ambiente foram guardados.</value>

View File

@@ -2769,7 +2769,7 @@ Do you want to switch to this account?</value>
<value>Account security</value>
</data>
<data name="BitwardenHelpCenter" xml:space="preserve">
<value>Bitwarden help center</value>
<value>Bitwarden Help Center</value>
</data>
<data name="ContactBitwardenSupport" xml:space="preserve">
<value>Contact Bitwarden support</value>
@@ -2975,6 +2975,18 @@ Do you want to switch to this account?</value>
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
<value>Your passkey will be saved to your Bitwarden vault for {0}</value>
</data>
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
<value>Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
</data>
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
<value>On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
</data>
<data name="RemindMeLater" xml:space="preserve">
<value>Remind me later</value>
</data>
<data name="Notice" xml:space="preserve">
<value>Notice</value>
</data>
<data name="PasskeysNotSupportedForThisApp" xml:space="preserve">
<value>Passkeys not supported for this app</value>
</data>

View File

@@ -2897,19 +2897,19 @@ Vill du byta till detta konto?</value>
<value>Choose a login to save this passkey to</value>
</data>
<data name="SavePasskeyAsNewLogin" xml:space="preserve">
<value>Spara passkey som ny inloggning</value>
<value>Save passkey as new login</value>
</data>
<data name="SavePasskey" xml:space="preserve">
<value>Spara passkey</value>
<value>Save passkey</value>
</data>
<data name="PasskeysForX" xml:space="preserve">
<value>Passkeys för {0}</value>
<value>Passkeys for {0}</value>
</data>
<data name="PasswordsForX" xml:space="preserve">
<value>Lösenord för {0}</value>
<value>Passwords for {0}</value>
</data>
<data name="OverwritePasskey" xml:space="preserve">
<value>Skriv över passkey?</value>
<value>Overwrite passkey?</value>
</data>
<data name="ThisItemAlreadyContainsAPasskeyAreYouSureYouWantToOverwriteTheCurrentPasskey" xml:space="preserve">
<value>This item already contains a passkey. Are you sure you want to overwrite the current passkey?</value>
@@ -2924,16 +2924,16 @@ Vill du byta till detta konto?</value>
<value>Starta Duo</value>
</data>
<data name="VerificationRequiredByX" xml:space="preserve">
<value>Verifiering krävs av {0}</value>
<value>Verification required by {0}</value>
</data>
<data name="VerificationRequiredForThisActionSetUpAnUnlockMethodInBitwardenToContinue" xml:space="preserve">
<value>Verification required for this action. Set up an unlock method in Bitwarden to continue.</value>
</data>
<data name="ErrorCreatingPasskey" xml:space="preserve">
<value>Fel vid skapande av passkey</value>
<value>Error creating passkey</value>
</data>
<data name="ErrorReadingPasskey" xml:space="preserve">
<value>Fel vid läsning av passkey</value>
<value>Error reading passkey</value>
</data>
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
<value>There was a problem creating a passkey for {0}. Try again later.</value>
@@ -2944,7 +2944,7 @@ Vill du byta till detta konto?</value>
<comment>The parameter is the RpId</comment>
</data>
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
<value>Verifierar identitet...</value>
<value>Verifying identity...</value>
</data>
<data name="Passwords" xml:space="preserve">
<value>Lösenord</value>
@@ -2965,22 +2965,22 @@ Vill du byta till detta konto?</value>
<value>1. Gå till din enhets Inställningar &gt; Lösenord &gt; Lösenordsalternativ</value>
</data>
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
<value>2. Slå på AutoFyll</value>
<value>2. Turn on AutoFill</value>
</data>
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
<value>3. Välj att använda "Bitwarden" för lösenord och passkeys</value>
<value>3. Select "Bitwarden" to use for passwords and passkeys</value>
</data>
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
<value>Your passkey will be saved to your Bitwarden vault</value>
</data>
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
<value>Din passkey kommer att sparas i ditt Bitwarden-valv för {0}</value>
<value>Your passkey will be saved to your Bitwarden vault for {0}</value>
</data>
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
<value>Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
</data>
<data name="OrganizationUnassignedItemsMessageSelfHost041624DescriptionLong" xml:space="preserve">
<value>Den 16 maj 2024 kommer otilldelade organisationsobjekt inte längre att synas i alla valvs-vyn och endast nås via administratörskonsollen. Tilldela dessa objekt till en samling från administratörskonsollen för att göra dem synliga.</value>
<value>On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
</data>
<data name="RemindMeLater" xml:space="preserve">
<value>Påminn mig senare</value>

View File

@@ -2838,7 +2838,7 @@ Bu hesaba geçmek ister misiniz?</value>
<value>App Store'a gitmek ister misiniz?</value>
</data>
<data name="ContinueToDeviceSettings" xml:space="preserve">
<value>Cihaz ayarlarına gidilsin mi?</value>
<value>Continue to device Settings?</value>
</data>
<data name="TwoStepLoginDescriptionLong" xml:space="preserve">
<value>Bitwarden web uygulamasında iki aşamalı girişi ayarlayarak hesabınızın güvenliğini artırabilirsiniz.</value>
@@ -2933,11 +2933,11 @@ Bu hesaba geçmek ister misiniz?</value>
<value>Geçiş anahtarı okuma hatası</value>
</data>
<data name="ThereWasAProblemCreatingAPasskeyForXTryAgainLater" xml:space="preserve">
<value>{0} için geçiş anahtarı oluşturulamadı. Daha sonra tekrar deneyin.</value>
<value>There was a problem creating a passkey for {0}. Try again later.</value>
<comment>The parameter is the RpId</comment>
</data>
<data name="ThereWasAProblemReadingAPasskeyForXTryAgainLater" xml:space="preserve">
<value>{0} için geçiş anahtarı okunamadı. Daha sonra tekrar deneyin.</value>
<value>There was a problem reading your passkey for {0}. Try again later.</value>
<comment>The parameter is the RpId</comment>
</data>
<data name="VerifyingIdentityEllipsis" xml:space="preserve">
@@ -2962,16 +2962,16 @@ Bu hesaba geçmek ister misiniz?</value>
<value>1. Go to your device's Settings &gt; Passwords &gt; Password Options</value>
</data>
<data name="SecondDotTurnOnAutoFill" xml:space="preserve">
<value>Oto-Doldurma'yı Etkinleştir</value>
<value>2. Turn on AutoFill</value>
</data>
<data name="ThirdDotSelectBitwardenToUseForPasswordsAndPasskeys" xml:space="preserve">
<value>Parolalarınızı ve geçiş anahtarlarını kullanmak için "Bitwarden" seçin</value>
<value>3. Select "Bitwarden" to use for passwords and passkeys</value>
</data>
<data name="YourPasskeyWillBeSavedToYourBitwardenVault" xml:space="preserve">
<value>Geçiş anahtarınız Bitwarden kasasına kaydedilecektir</value>
<value>Your passkey will be saved to your Bitwarden vault</value>
</data>
<data name="YourPasskeyWillBeSavedToYourBitwardenVaultForX" xml:space="preserve">
<value>{0} için geçiş anahtarınız Bitwarden kasasına kaydedilecektir</value>
<value>Your passkey will be saved to your Bitwarden vault for {0}</value>
</data>
<data name="OrganizationUnassignedItemsMessageUSEUDescriptionLong" xml:space="preserve">
<value>Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible.</value>
@@ -2989,18 +2989,18 @@ Bu hesaba geçmek ister misiniz?</value>
<value>Bu uygulamada geçiş anahtarları desteklenmiyor</value>
</data>
<data name="PasskeyOperationFailedBecauseBrowserIsNotPrivileged" xml:space="preserve">
<value>Geçiş anahtarı eylemi başarısız oldu çünkü tarayıcı ayrıcalıklı değil</value>
<value>Passkey operation failed because browser is not privileged</value>
</data>
<data name="PasskeyOperationFailedBecauseBrowserSignatureDoesNotMatch" xml:space="preserve">
<value>Geçiş anahtarı eylemi başarısız oldu çünkü tarayıcı imzası uyumsuz</value>
<value>Passkey operation failed because browser signature does not match</value>
</data>
<data name="PasskeyOperationFailedBecauseOfMissingAssetLinks" xml:space="preserve">
<value>Geçiş anahtarı eylemi başarısız oldu çünkü varlık bağlantıları eksik</value>
<value>Passkey operation failed because of missing asset links</value>
</data>
<data name="PasskeyOperationFailedBecauseAppNotFoundInAssetLinks" xml:space="preserve">
<value>Geçiş anahtarı eylemi başarısız oldu çünkü uygulama varlık bağlantılarında bulunamadı</value>
<value>Passkey operation failed because app not found in asset links</value>
</data>
<data name="PasskeyOperationFailedBecauseAppCouldNotBeVerified" xml:space="preserve">
<value>Geçiş anahtarı eylemi başarısız oldu çünkü uygulama doğrulanamadı</value>
<value>Passkey operation failed because app could not be verified</value>
</data>
</root>

View File

@@ -2500,7 +2500,7 @@
<value>在 {1} 上以 {0} 身份登录</value>
</data>
<data name="NotYou" xml:space="preserve">
<value>不是您吗</value>
<value>不是</value>
</data>
<data name="LogInWithMasterPassword" xml:space="preserve">
<value>使用主密码登录</value>
@@ -2695,7 +2695,7 @@
<value>批准后,您将收到通知。 </value>
</data>
<data name="TroubleLoggingIn" xml:space="preserve">
<value>登录遇到问题</value>
<value>登录遇到问题?</value>
</data>
<data name="LoggingInAsX" xml:space="preserve">
<value>正登录为 {0}</value>

View File

@@ -334,6 +334,11 @@ namespace Bit.Core.Services
return SendAsync<object, CipherResponse>(HttpMethod.Put, string.Concat("/ciphers/", id, "/restore"), null, true, true);
}
public Task<bool> HasUnassignedCiphersAsync()
{
return SendAsync<object, bool>(HttpMethod.Get, "/ciphers/has-unassigned-ciphers", null, true, true);
}
#endregion
#region Attachments APIs

View File

@@ -1,4 +1,4 @@
#define ENABLE_NEW_CIPHER_KEY_ENCRYPTION_ON_CREATION
//#define ENABLE_NEW_CIPHER_KEY_ENCRYPTION_ON_CREATION
using System;
using System.Collections.Generic;
@@ -114,7 +114,7 @@ namespace Bit.Core.Services
public async Task<Cipher> EncryptAsync(CipherView model, SymmetricCryptoKey key = null,
Cipher originalCipher = null)
{
// Adjust password history and attachments
// Adjust password history
if (model.Id != null)
{
if (originalCipher == null)
@@ -169,9 +169,6 @@ namespace Bit.Core.Services
}
}
}
//adjust attachments
model.Attachments = existingCipher.Attachments;
}
if (!model.PasswordHistory?.Any() ?? false)
{
@@ -838,6 +835,24 @@ namespace Bit.Core.Services
await ClearCacheAsync();
}
public async Task<bool> VerifyOrganizationHasUnassignedItemsAsync()
{
var organizations = await _stateService.GetOrganizationsAsync();
if (organizations?.Any() != true)
{
return false;
}
try
{
return await _apiService.HasUnassignedCiphersAsync();
}
catch (ApiException ex) when (ex.Error?.StatusCode == System.Net.HttpStatusCode.BadRequest)
{
return false;
}
}
// Helpers
private async Task<Tuple<SymmetricCryptoKey, EncString, SymmetricCryptoKey>> MakeAttachmentKeyAsync(string organizationId, Cipher cipher = null, CipherView cipherView = null)

View File

@@ -1384,6 +1384,16 @@ namespace Bit.Core.Services
await _storageMediatorService.SaveAsync(Constants.RegionEnvironment, value);
}
public async Task<bool> GetShouldCheckOrganizationUnassignedItemsAsync(string userId = null)
{
return await _storageMediatorService.GetAsync<bool?>(await ComposeKeyAsync(Constants.ShouldCheckOrganizationUnassignedItemsKey, userId)) ?? true;
}
public async Task SetShouldCheckOrganizationUnassignedItemsAsync(bool shouldCheck, string userId = null)
{
await _storageMediatorService.SaveAsync<bool?>(await ComposeKeyAsync(Constants.ShouldCheckOrganizationUnassignedItemsKey, userId), shouldCheck);
}
// Helpers
[Obsolete("Use IStorageMediatorService instead")]

View File

@@ -152,17 +152,17 @@ namespace Bit.iOS.Autofill
}
}
public override async void ProvideCredentialWithoutUserInteraction(ASPasswordCredentialIdentity credentialIdentity)
{
try
{
await ProvideCredentialWithoutUserInteractionAsync(credentialIdentity);
}
catch (Exception ex)
{
OnProvidingCredentialException(ex);
}
}
//public override async void ProvideCredentialWithoutUserInteraction(ASPasswordCredentialIdentity credentialIdentity)
//{
// try
// {
// await ProvideCredentialWithoutUserInteractionAsync(credentialIdentity);
// }
// catch (Exception ex)
// {
// OnProvidingCredentialException(ex);
// }
//}
[Export("prepareInterfaceToProvideCredentialForRequest:")]
public override async void PrepareInterfaceToProvideCredential(IASCredentialRequest credentialRequest)
@@ -197,17 +197,17 @@ namespace Bit.iOS.Autofill
}
}
public override async void PrepareInterfaceToProvideCredential(ASPasswordCredentialIdentity credentialIdentity)
{
try
{
await PrepareInterfaceToProvideCredentialAsync(c => c.PasswordCredentialIdentity = credentialIdentity);
}
catch (Exception ex)
{
OnProvidingCredentialException(ex);
}
}
//public override async void PrepareInterfaceToProvideCredential(ASPasswordCredentialIdentity credentialIdentity)
//{
// try
// {
// await PrepareInterfaceToProvideCredentialAsync(c => c.PasswordCredentialIdentity = credentialIdentity);
// }
// catch (Exception ex)
// {
// OnProvidingCredentialException(ex);
// }
//}
public override async void PrepareInterfaceForExtensionConfiguration()
{

View File

@@ -11,7 +11,7 @@
<key>CFBundleIdentifier</key>
<string>com.8bit.bitwarden.autofill</string>
<key>CFBundleShortVersionString</key>
<string>2024.7.0</string>
<string>2024.5.2</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CFBundleLocalizations</key>

View File

@@ -15,6 +15,9 @@ using Foundation;
using Microsoft.Maui.Controls.Compatibility;
using UIKit;
using Microsoft.Maui.Platform;
using CollectionView = Bit.Core.Models.View.CollectionView;
using Bit.Core.Models.Domain;
using Bit.Core.Enums;
namespace Bit.iOS.Core.Controllers
{
@@ -23,7 +26,19 @@ namespace Bit.iOS.Core.Controllers
private ICipherService _cipherService;
private IFolderService _folderService;
private IStorageService _storageService;
private IOrganizationService _organizationService;
private ICollectionService _collectionService;
private IPolicyService _policyService;
private IEnumerable<FolderView> _folders;
private IEnumerable<CollectionView> _collections;
private IEnumerable<CollectionView> _writeableCollections;
private IEnumerable<Organization> _organizations;
private bool _personalOwnershipPolicyApplies;
//Here we have the different sizes dependent of the _personalOwnershipPolicyApplies
private readonly int[] _personalVault = { 3, 1, 2, 1 };
private readonly int[] _groupVault = { 1, 3, 1, 2, 1, 2 };
private ExtendedUITableViewCell[][] _tableViewCell;
protected LoginAddViewController(IntPtr handle)
: base(handle)
@@ -38,6 +53,10 @@ namespace Bit.iOS.Core.Controllers
public FormEntryTableViewCell NotesCell { get; set; } = new FormEntryTableViewCell(
useTextView: true, height: 180);
public PickerTableViewCell FolderCell { get; set; } = new PickerTableViewCell(AppResources.Folder);
public PickerTableViewCell OrganizationCell { get; set; } = new PickerTableViewCell(AppResources.Organization);
public PickerTableViewCell CollectionCell { get; set; } = new PickerTableViewCell(AppResources.Collections);
public FormEntryTableViewCell PersonalOwnershipPolicyCell { get; set; } = new FormEntryTableViewCell(empty: true);
public abstract UINavigationItem BaseNavItem { get; }
public abstract UIBarButtonItem BaseCancelButton { get; }
@@ -51,6 +70,9 @@ namespace Bit.iOS.Core.Controllers
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
_folderService = ServiceContainer.Resolve<IFolderService>("folderService");
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
_organizationService = ServiceContainer.Resolve<IOrganizationService>("organizationService");
_collectionService = ServiceContainer.Resolve<ICollectionService>("collectionService");
_policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
BaseNavItem.Title = AppResources.AddItem;
BaseCancelButton.Title = AppResources.Cancel;
@@ -113,6 +135,42 @@ namespace Bit.iOS.Core.Controllers
folderNames.Insert(0, AppResources.FolderNone);
FolderCell.Items = folderNames;
_personalOwnershipPolicyApplies = _policyService.PolicyAppliesToUser(PolicyType.PersonalOwnership).GetAwaiter().GetResult();
var index = 0;
if (_personalOwnershipPolicyApplies)
{
_organizations = _organizationService.GetAllAsync().GetAwaiter().GetResult().OrderBy(o => o.Name).ToList();
OrganizationCell.Items = _organizations.Select(o => o.Name).ToList();
OrganizationCell.ValueChanged += Type_ValueChanged;
_collections = _collectionService.GetAllDecryptedAsync().GetAwaiter().GetResult();
_writeableCollections = _collections.Where(c => !c.ReadOnly).OrderBy(c => c.Name).ToList();
var collectionsNames = _writeableCollections.Where(c => c.OrganizationId == _organizations.ElementAt(OrganizationCell.SelectedIndex).Id).Select(s => s.Name).ToList();
if (collectionsNames.Count == 0)
{
collectionsNames.Insert(0, AppResources.NoCollectionsToList);
}
CollectionCell.Items = collectionsNames;
_tableViewCell = new ExtendedUITableViewCell[_groupVault.Length][];
_tableViewCell[0] = new ExtendedUITableViewCell[] { PersonalOwnershipPolicyCell };
_tableViewCell[5] = new ExtendedUITableViewCell[] { OrganizationCell, CollectionCell };
index = 1;
}
else
{
_tableViewCell = new ExtendedUITableViewCell[_personalVault.Length][];
}
_tableViewCell[index] = new ExtendedUITableViewCell[] { NameCell, UsernameCell, PasswordCell };
_tableViewCell[++index] = new ExtendedUITableViewCell[] { UriCell };
_tableViewCell[++index] = new ExtendedUITableViewCell[] { FolderCell, FavoriteCell };
_tableViewCell[++index] = new ExtendedUITableViewCell[] { NotesCell };
TableView.RowHeight = UITableView.AutomaticDimension;
TableView.EstimatedRowHeight = 70;
TableView.Source = new TableSource(this);
@@ -121,6 +179,19 @@ namespace Bit.iOS.Core.Controllers
base.ViewDidLoad();
}
private void Type_ValueChanged(object sender, EventArgs e)
{
var organizationList = _organizations.OrderBy(o => o.Name).ToList();
var collectionsNames = _writeableCollections.Where(c => c.OrganizationId == _organizations.ElementAt(OrganizationCell.SelectedIndex).Id).Select(s => s.Name).ToList();
if (collectionsNames.Count == 0)
{
collectionsNames.Insert(0, AppResources.NoCollectionsToList);
}
CollectionCell.Items = collectionsNames;
_tableViewCell[5][1].ReloadInputViews();
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
@@ -167,7 +238,10 @@ namespace Bit.iOS.Core.Controllers
null : UsernameCell.TextField.Text,
Password = string.IsNullOrWhiteSpace(PasswordCell.TextField.Text) ?
null : PasswordCell.TextField.Text,
}
},
CollectionIds = CollectionCell.SelectedItem.ToString() == AppResources.NoCollectionsToList ?
null : new HashSet<string> { _collections.ElementAtOrDefault(CollectionCell.SelectedIndex)?.Id },
OrganizationId = OrganizationCell.SelectedItem != null ? _organizations.ElementAtOrDefault(CollectionCell.SelectedIndex)?.Id : null,
};
if (!string.IsNullOrWhiteSpace(UriCell?.TextField?.Text))
@@ -272,42 +346,7 @@ namespace Bit.iOS.Core.Controllers
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
if (indexPath.Section == 0)
{
if (indexPath.Row == 0)
{
return _controller.NameCell;
}
else if (indexPath.Row == 1)
{
return _controller.UsernameCell;
}
else if (indexPath.Row == 2)
{
return _controller.PasswordCell;
}
}
else if (indexPath.Section == 1)
{
return _controller.UriCell;
}
else if (indexPath.Section == 2)
{
if (indexPath.Row == 0)
{
return _controller.FolderCell;
}
else if (indexPath.Row == 1)
{
return _controller.FavoriteCell;
}
}
else if (indexPath.Section == 3)
{
return _controller.NotesCell;
}
return new ExtendedUITableViewCell();
return _controller._tableViewCell[indexPath.Section][indexPath.Row];
}
public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
@@ -317,43 +356,71 @@ namespace Bit.iOS.Core.Controllers
public override nint NumberOfSections(UITableView tableView)
{
return 4;
if (_controller._personalOwnershipPolicyApplies)
{
return _controller._groupVault.Length;
}
else
{
return _controller._personalVault.Length;
}
}
public override nint RowsInSection(UITableView tableview, nint section)
{
if (section == 0)
if (_controller._personalOwnershipPolicyApplies)
{
return 3;
}
else if (section == 1)
{
return 1;
}
else if (section == 2)
{
return 2;
return _controller._groupVault[section];
}
else
{
return 1;
return _controller._personalVault[section];
}
}
public override nfloat GetHeightForHeader(UITableView tableView, nint section)
{
return section == 0 || section == 3 ? UITableView.AutomaticDimension : 0.00001f;
if (_controller._personalOwnershipPolicyApplies)
{
return section == 0 || section == 1 || section == 4 || section == 5 ? UITableView.AutomaticDimension : 0.00001f;
}
else
{
return section == 0 || section == 3 ? UITableView.AutomaticDimension : 0.00001f;
}
}
public override string TitleForHeader(UITableView tableView, nint section)
{
if (section == 0)
if (_controller._personalOwnershipPolicyApplies)
{
return AppResources.ItemInformation;
if (section == 0)
{
return AppResources.PersonalOwnershipPolicyInEffect;
}
if (section == 1)
{
return AppResources.ItemInformation;
}
else if (section == 4)
{
return AppResources.Notes;
}
else if (section == 5)
{
return AppResources.WhoOwnsThisItem;
}
}
else if (section == 3)
else
{
return AppResources.Notes;
if (section == 0)
{
return AppResources.ItemInformation;
}
else if (section == 3)
{
return AppResources.Notes;
}
}
return string.Empty;

View File

@@ -22,7 +22,8 @@ namespace Bit.iOS.Core.Views
nfloat? height = null,
ButtonsConfig buttonsConfig = ButtonsConfig.None,
bool useLabelAsPlaceholder = false,
float leadingConstant = 15f)
float leadingConstant = 15f,
bool empty = false)
: base(UITableViewCellStyle.Default, nameof(FormEntryTableViewCell))
{
var descriptor = UIFontDescriptor.PreferredBody;
@@ -86,7 +87,7 @@ namespace Bit.iOS.Core.Views
ValueChanged?.Invoke(sender, e);
};
}
else
else if( !empty )
{
TextField = new UITextField
{
@@ -128,18 +129,18 @@ namespace Bit.iOS.Core.Views
NSLayoutConstraint.Create(TextField, NSLayoutAttribute.Top, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Top, 1f, 10f));
}
if (height.HasValue)
{
ContentView.AddConstraint(
NSLayoutConstraint.Create(TextField, NSLayoutAttribute.Height, NSLayoutRelation.Equal, null, NSLayoutAttribute.NoAttribute, 1f, height.Value));
}
TextField.AddTarget((object sender, EventArgs e) =>
{
ValueChanged?.Invoke(sender, e);
}, UIControlEvent.EditingChanged);
}
if (empty && height.HasValue)
{
ContentView.AddConstraint(
NSLayoutConstraint.Create(TextField, NSLayoutAttribute.Height, NSLayoutRelation.Equal, null, NSLayoutAttribute.NoAttribute, 1f, height.Value));
}
if (labelName != null && !useLabelAsPlaceholder)
{
ContentView.AddConstraints(new NSLayoutConstraint[] {

View File

@@ -11,7 +11,7 @@
<key>CFBundleIdentifier</key>
<string>com.8bit.bitwarden.find-login-action-extension</string>
<key>CFBundleShortVersionString</key>
<string>2024.7.0</string>
<string>2024.5.2</string>
<key>CFBundleLocalizations</key>
<array>
<string>en</string>

View File

@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>2024.7.0</string>
<string>2024.5.2</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>MinimumOSVersion</key>