1
0
mirror of https://github.com/bitwarden/mobile synced 2025-12-05 23:53:33 +00:00

Compare commits

...

411 Commits

Author SHA1 Message Date
Andreas Coroiu
da051b8fc1 Add example of delegated UI class 2024-02-19 16:44:15 +01:00
Andreas Coroiu
c801b2fc3a Fix incompatible GUID conversions 2024-02-19 15:35:17 +01:00
Federico Maccaroni
41161864db PM-5154 [Passkeys iOS] Fix Credential ID handling on bytes and string formats. Fix Discoverable to be lowercase on set so it doesn't break parsing on clients. Added UserDisplayName on Fido2 entities. Extracted the Guid Standard/Raw format helpers to a extensions class. 2024-02-16 19:30:33 -03:00
Andreas Coroiu
a1c9ebf01f fix wrong signature format 2024-02-16 10:57:44 +01:00
Federico Maccaroni
7381d5278a PM-5154 Fixed select passkey flow and started implementing create passkey on iOS 2024-02-15 21:16:54 -03:00
Federico Maccaroni
8b5a7b257d Merge branch 'PM-5731-create-c-web-authn-authenticator-to-support-maui-apps' into temp-passkeys-ios-fede 2024-02-15 21:09:09 -03:00
mpbw2
62e0626648 Merge branch 'feature/maui-migration-passkeys' into PM-5731-create-c-web-authn-authenticator-to-support-maui-apps 2024-02-15 14:42:53 -05:00
Federico Maccaroni
d339514d9a Merge branch 'main' into feature/maui-migration-passkeys
# Conflicts:
#	.github/workflows/build.yml
#	nuget.config
#	src/App/App.csproj
#	src/App/Platforms/Android/AndroidManifest.xml
#	src/App/Platforms/iOS/AppDelegate.cs
#	src/Core/Core.csproj
#	src/Core/Pages/Settings/AutofillSettingsPageViewModel.android.cs
#	src/Core/Utilities/ThemeManager.cs
#	src/iOS.Autofill/CredentialProviderViewController.cs
#	src/iOS.Autofill/iOS.Autofill.csproj
2024-02-14 14:19:51 -03:00
Federico Maccaroni
75ec96f282 PM-3349 Added exception on gitignore so the nupkg for the AndroidX Credentials is added 2024-02-14 13:58:35 -03:00
mpbw2
96a9978ef8 fix resources path for crowdin (#3008) 2024-02-14 10:26:36 -05:00
Dinis Vieira
1ae388cb03 [PM-5900] Fix for Device Login push notifications cause the app to show HomePage (#2989)
* PM-5900 Fix for Device Login push notifications cause the app to show the HomePage

* PM-5900 Added edge case scenario if intent / packageName / packageManager is null
2024-02-13 22:07:09 +00:00
Vince Grassia
c6aaf5002f Add xmllint install step (#3006) 2024-02-12 12:37:52 -07:00
Bitwarden DevOps
75be6504e1 Bumped version to 2024.2.2 (#3005) 2024-02-12 19:20:44 +00:00
renovate[bot]
cae1825e3f [deps]: Update gh minor (#2992)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-12 14:09:14 -05:00
Vince Grassia
c23100d281 Update CODEOWNERS file for Version Bump automation (#3004) 2024-02-12 14:03:12 -05:00
Vince Grassia
c9c0d0b4d6 Fix while loop (#3003) 2024-02-12 18:20:29 +00:00
mpbw2
fec0743e4d Fix for Android builds (#3001)
* enable unit test flag

* revert UT flag and modify flags in ThemeManager
2024-02-12 12:45:52 -05:00
Vince Grassia
118dcf164c Fix all paths (#2999) 2024-02-12 07:51:51 -08:00
Vince Grassia
bd03b6b5aa Version Bump workflow - Fix location of AndroidManifest.xml file (#2998) 2024-02-12 07:35:19 -08:00
Federico Maccaroni
333917c00d Fix Android build UT Failing because of precompiler directives. (#2991) 2024-02-12 09:34:43 -05:00
Vince Grassia
450101d9e4 Update auto version bump workflow (#2987) 2024-02-12 07:56:08 -05:00
Andreas Coroiu
3c848a3dcc [PM-5731] feat: implement credential assertion in client 2024-02-12 13:45:41 +01:00
Federico Maccaroni
18beb4e5f4 Added iOS passkeys integration, warning this branch has lots of logs to ease "debugging" extensions. 2024-02-09 18:15:25 -03:00
Federico Maccaroni
4e50f1697d PM-6209 Removed MAUI label from environment and about pages (#2990) 2024-02-09 12:08:45 -03:00
Dinis Vieira
3c96ae2220 [PM-5913] Fix for MAUI not reporting the correct Theme when resuming an iOS App (#2988)
* PM-5913 Fix for incorrect iOS Theme when resuming iOS app. Also added minor DeviceInfo change and InvokeOnMainThread is on ThemeManager even though it can be moved elsewhere.

* PM-5913 removed redundant iOS check and changed #elif to #else
2024-02-09 14:28:43 +00:00
Vince Grassia
fdbd16a6fd Add build version to step summary (#2986) 2024-02-09 11:31:25 +01:00
Federico Maccaroni
39a34bd8c4 [PM-3349] [PM-3350] MAUI Migration Initial (#2806)
* PM-3349 PM-3350 MAUI Migration Initial

* PM-3349 PM-3350 MAUI Migration fix nullable exception bindings and AsyncCommand canExecute null exception

* PM-3349 PM-3350 MAUI Migration fix nullable bindings and fallbacks

* PM-3349: Android
Added CustomTabbedPageHandler for Android to handle the tab "reselection" for PopToRoot.
Commented support for Windows in App.csproj
Disabled Interpreter on Android to avoid very slow app in Debug (during Login for example)
Added some null checks that were causing crashes (on GeneratorPageVM and PickerVM)
Minor TabsPage cleanup

* TabBarEffect removed and it's behavior is now taken care of by CustomTabbedPageHandler

* PM-3349 PM-3350 Add null checks on CipherDetailsPageVM to avoid crash opening Secure Notes.

* PM-3349 PM-3350 MAUI Migration Start iOS extensions

* Changes to solution to hopefully fix Config Mappings

* PM-3349 Removed Deploy from iOS.Autofill to allow running Android
Changed MainApplication SpecialFolder.Personal to SpecialFolder.LocalApplicationData

* PM-3350 MAUI Migration Fix iOS Autofill extension

* PM-3349 Changed UseMauiApp init so that Android Handlers still get added

* PM-3349 Implemented HybridWebViewHandler for Android which enables 2nd factor auth flows
Ensured CustomTabbedPageHandler had it's DisconnectHandler called
Some minor code upgrades of older obsolete Xamarin Forms code.

* PM-3349 Implemented HybridWebViewHandler for iOS

* hardcoded AccountViewCell Avatar image to 40x40 to avoid current iOS/Android bugs where they fill much larger space.

* PM-3349 PM-3350
Added (migrated) CustomNavigationHandler (which should partially fix the AvatarIcon in the NavBar in iOS)
Added (migrated) CustomContentPageHandler (which should mostly place the AvatarIcon in the navBar in the correct place for iOS)
Added Task.Delay (workaround) to allow the Avatar to load in iOS on the LoginPage
Added workaround for iOS bug with the toolbar size (more info in comment in AvatarImageSource.cs)
Went through the AccountViewCell MAUI-Migration comments. (and deleted/added more comments as needed)
Migrated some Device calls to DeviceInfo and MainThread
Added (migrated) CustomTabbedHandler (for managing the iOS TabBar)

* PM-3349 Replaced the FabShadowEffect with the new MAUI Shadow to fix the buggy shadows on the Android Fab Button.

* PM-3349 ToolbarHandler created for setting text on Android go back buttons.

* PM-3350 Migrated the CustomViewCellRenderer for iOS

* PM-3350 Removed ButtonHandlerMappings and some other code related with fonts as MAUI is taking care of Accessibility and no custom code should be needed
Migrated SelectableLabelRenderer to Handler
Cleaned LabelHandlerMappings and added logic to migrate the CustomLabelRenderer

* Enabled argon2Id for iOS

* PM-3349
Added Argon libraries for Android
minor change to gitignore so that the Argon x86 lib is not ignored on the Android platform

* PM-3350 Migrated some Device to DeviceInfo and added temporary workaround with some comments to be able to see the Generated Password on iOS

* PM-3350 Added some missing images in iOS

* PM-3349 PRM-3350 Replaced XZing with Camera.MAUI for QRCodes

* Checked some [MAUI-Migration] and deleted when it's working as intended.
SearchBarHandlerMapping: IME options working as intended
SliderHandlerMappings: The MAUI "replacement" for Color.Default seems to be White so the old use case doesn't seem to be needed anymore.

* PM-3350 Checked some [MAUI-Migration] and changed as needed.
TimePickerHandlerMappings: Remove old code for forcing the Wheel. After testing without it wheel picker is still used so this code shouldn't be needed anymore.
AppDelegate.ContinueUserActivity: Uncommented and changed the iOS ContinueUserActivity. It needs to call Platform.ContinueUserActivity according with Xamarin Essentials migration docs.

* PM-3349 Fixed white tint color not appearing on images added as MAU IImage SVG
PM-3349 PM-3350 Fix for Avatar text not adjusting to white/black color correctly

* PM-3350 Removed MAUI Splash Screen. Fixed iOS Privacy Screen logo (hardcoded image to avoid it getting cropped)

* PM-3350 Quick workaround to allow 2nd factor auth to not get stuck in iOS in modals.
Updated some older "Device" code to the newer MAUI code.

* PM-3350 Removed duplicate reference to LaunchScreen.storyboard

* PM-3349 PM-3350 Minor change to HomePage to set fixed Image height otherwise it takes more space than it did in the old Xamarin Forms app.
Added HIdeSoftInputOnTapped on several pages (the ones with Entry controls) to allow hiding the keyboard when tapping "outside" of it. (just like we did in Xamarin Forms app)

* PM-3350 Added Scrollview on HomePage so that the "Create account" button can be accessed in smaller devices like iPhone SE.

* PM-3349 Added Handler that enables the ExtendedDatePicker to get IsFocused events in Android. This is a workaround for fixing the current bug where it's not possible to select the "current day" in the expiration date of a Send.
Fix for TimePicker not displaying default Time Value
Updated some "Device" code to the new MAUI "DeviceInfo"

* PM-3349 PM-3350 Migrated IconLabelButton Frames to Borders to fix issue with TapGestureRecognizer in Android
Also fixed some minor "styles" for normal Button and IconLabelButton (both Android and iOS)

* PM-3349 Fix for TabGestureRecognizer not working inside the StackLayout area of IconLabelButton

* PM-3349 Fix for Android buttons having all letters in Caps

* PM-3349 PM-3350 Started using OnNavigatedTo/From instead of On(Dis)Appearing for LoginPage and LoginSSOPage to avoid the "Modal loading" issues in iOS
Also had to add IsInitialized logic to these pages because OnNavigatedTo can be called twice in some scenario.
Some minor migrations of Device to DeviceInfo was also done

* PM-3350 Fixed iOS extensions (iOS.Extension and iOS.ShareExtension)  to load and commented argon2id from debug configuration until we have the .a compiled again with the new platform/arch

* PM-3350 Added configurations for Release mode (no FDroid yet)

* PM-3349 PM-3350 Migrated remaining AutomationProperties to SemanticProperties.
All 'IsInAccessibleTree="True"' were deleted.
'IsInAccessibleTree="False"' were kept and stayed in code.

* PM-3349 PM-3350 Changed binding set for CipherViewCell so it updates accordingly

* PM-3349 PM-3350 Changed AccountViewCell and its binding to be directly against the ViewModel

* PM-3349 Fix for HTML Label on Android. Color hex doesn't need to be cropped anymore.

* PM-3350 Fix for colored html text on iOS

* PM-3349 PM-3350 Added the partial MAUI Community Toolkit implementation for TouchEffect. This is a temporary solution until they finalize this and add it to their nuget package.
This allows implementing the LongPressCommand in AccountSwitchingOverlay and also have the "Ripple effect" animation when touching an item in Android

* PM-3349 PM-3350 Changed SendViewCell and its binding to be directly against the ViewModel

* PM-3350 Fixed iOS Share extension lazy views loading and an issue with the avatar loading. Also discovered issue with TapGestureRecognizer not working on MAUI Embedding

* PM-3350 Fixed iOS Extensions navigation to several pages and improved avoiding duplicate calls to OnNavigatedTo

* PM-3350 Updated PCL Crypto to latest alpha version to fix "Dll not found NCrypt" issue

* PM-3350 Removed workaround for iOS issue with Avatar icon as it's now fixed in latest .Net8 release.

* PM-3349 PM-3350 Removed AsyncCommand "wrapper" and added AsyncRelayCommand directly in all ViewModels that were using the other one.

* PM-3350 Added watchOS app to main project and fixed some csproj conditions for runtime identifiers on iOS.

* PM-3350 Fixed/Updated all MAUI-Migration TODOs

* PM-3350 Fixed account toolbar item and TitleView on SendAddOnlyPage, also removed comments on AvatarImageSource given the workaround is not needed anymore to draw the image successfully.

* PM-3350 Updated AppCenter package to latest version 5.0.3 and updated some things into MAUI style

* PM-3350 Added workaround for iOS Avatar icon again.

* PM-3349 Added workaround for Android to avoid issues with setting MainPage when app is in background. They are now kept on a Queue to be executed after the app has resumed.
Updated some things on App.xaml.cs to the new MAUI style

* PM-3349 PM-3350 Fixed issue where creating an account with weak/exposed password would get stuck after the Captcha (if a captcha is shown)
Changed App.xaml.cs NavigateImpl to be private

* PM-3349 Started to configure build.yml for MAUI Android

* PM-3349 build.yml update paths for MAUI Android

* PM-3349 build.yml commented verify format and just set qa as variant on MAUI Android for faster checks on CI

* PM-3349 PM-3350 build.cake updated paths

* PM-3349 build.yml updated env helpers variables and set specific csproj to build on Android so not to build iOS extensions

* PM-3349 build.yml add Android "prod" variant

* PM-3350 build.yml updated iOS build and ignore Android build to try the CI faster

* PM-3350 build.yml changed nuget restore for dotnet restore on iOS build to fix issue on restoring due to msbuild

* PM-3350 build.yml Upgraded iOS build to run on macos-13 image which has XCode 15, and set the XCode 15 version as currently the default one is 14.x

* PM-3350 build.yml try to fix ILLINK warnings and changed image to be macos-13-arm64 to see if the build is faster

* PM-3350 build.yml changed image back to be macos-13 to see if the build is faster

* PM-3350 Added Document.Build.props to disable trimming on publish

* PM-3350 build.yml disable trimming on publish so it's faster

* PM-3350 added linkskip for iOS csprojs

* PM-3350 iOS projs disable linking and set Newstandkit as weak framework

* Update build.yml disabling iOS job to avoid long running process of publish until we can fix that

* PM-3349 PM-3350 Workaround to fix issues with text getting cropped/truncated when a Label has both Multiline and LinebreakMode set

* PM-3349 build.yml enabled android build workflow

* PM-3349 build.yml configured FDROID job for MAUI

* PM-3350 iOS extensions TapGestureRecognizer try Window workaround

* PM-3350 iOS applied workaround on the iOS Autofill and Share extension to maui embed the navigation page with its content page in the Window

* PM-3349 PM-3350 Added workaround for More Options to work on Search and Groupings Page
Updated some code to MAUI Style also

* PM-3349 PM-3350 Added the ability for users to press "Continue" button as a fallback when using the Yubikey if the "SubmitCommand" doesn't trigger automatically.

* PM-3349 PM-3350 Fix for text getting cut/truncated in both account switcher and ciphers/search lists
Issue is due to MAUI but can be avoided by using slightly different layout

* PM-3350 iOS updated CFBundlerShortVersionString to latest one 2023.10.1

* PM-3350 fix build.yml Bitwarden.ipa AppStore exported file

* PM-3350 build.yml added step to validate app for submitting into App Store and have better logs of it

* PM-3350 build.yml Added several fixes like not using MtouchUseLLVM on the iOS builds to fix they taking forever to build and some changes on the automation CI to do a debug build for the moment

* PM-3350 Improved MTouch linking and extra args on iOS related csprojs

* PM-3349 PM-3350 Added MAUI label on self-host settings and on about settings to differentiate from XF app

* PM-3349 PM-3350 build.yml uncommented jobs so we have a more complete workflow

* PM-3349 PM-3350 Minor change: removed unneeded HorizontalTextAlignment from Label.

* PM-3349 Replaced CrossCurrentActivity plugin with MAUI internal CurrentActivity

* PM-3350 Fix iOS extensions navigation and Window/RootViewController handling for TapGestureRecognizer to work

* PM-3350 Cleared left ClipLogger from the iOS extensions debug logging.

* PM-3349 PM-3350 Refactored cipher bindings to have a simpler approach reusing a new CipherItemViewModel to avoid unwanted issues in the app

* PM-3349 Added base structure for avoiding Android Autofill crash. This workaround works but it's not complete as it can't handle the entire workflow when showing CipherSelectionPAge (like checking if it should show LockPage)

* PM-3350 Bumped iOS version

* PM-3350 Changed linker to use default mode given that "Full" is presenting some problems as the linker is stripping things it shouldn't and we're trying to solve it. So for now we will use the mode "Link SDK assemblies only" so QA can test.

* PM-3349 Fix for app crashing on Android when Dark mode is enabled
Removed unused button style for android

* Proof of concept for having multiple window in Android for autofill support and navigating with the help of an Extended splash page.

* PM-3350 Fix crash on Release by adding Interpreter on iOS and also adding System.Security.Cryptography to be ignored by the linker

* PM-3350 Apply Cryptography TrimmerRootAssembly only to iOS

* PM-3350 Updated Plugin.Fingerprint so biometrics work

* Update .github/workflows/build.yml setup-xcode commit hash

Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com>

* PM-3349 PM-3350 Enabled argon2id and fixed one issue with the Uris when getting the icon image

* PM-3349 Upgraded Android targetSdkVersion to 34

* minor change (public to private fields)

* minor improvemments on autofill-redirect

* PM-3349 Commented the Deploy step for Android job given that we're using the hotfix-rc branch for testing iOS on TestFlight

* PM-3349 Uncommented the Deploy step for Android job

* PM-3349 Ensure "_isResumed=true" is set on App.xaml.cs:Bootstrap

* Reusing App.xaml.cs Navigation for the Android RedirectPage
Some other cleanup and changes

* Improved autofill workaround to better handle switching between windows.

* PM-3349 minor fix to add space in HomePage between the region picker labels.

* Added some comments and improvemments.

* PM-3349 Added Window events unsubscription of events. Also changed code to avoid potentially having multiple autofillwindow

* PM-3349 Minor ui fix (space between buttons in delete account page)

* initial commit of android credential provider service (wip)

* Revert "initial commit of android credential provider service (wip)"

This reverts commit 6011b63958.

* PM-3350 Fix for Delete Account buttons on iOS

* PM-3349 PM-3350 Changed search icon used in app to avoid issue with icon size on iOS

* PM-3349 Added custom window so that we can always get the current Active Window. This is used to support the Android Autofil and multi-window scenarios.

* PM-3349 Fix for icon and text spacing in some list items

* PM-3349 Minor aligment improvemment for region selection in HomePage

* PM-3349 Changed the "track color" for the Android switch so that the color is different from the "thumb"

* PM-3350 Updated version to 2024.1.0 on iOS

* PM-3349 Fix Picker selection style by doing a custom PickerHandler for Android which uses SetSingleChoiceItems(...) to provide with the appropriate UI

* PM-3350 Updated MauiVersion to 8.0.4-nightly.* to have the TapGestureRecognizer fix applied. This is done on the Directory.Build.props so we don't have to change it on every csproj. Also removed the workaround of TapGestureHack and fix the Show environment picker to work on the extensions as well.

* PM-3350 Added nuget.config so we add the nuget package source for MAUI Nightly builds

* Bump main iOS version

* PM-3350 Removed "iOS" old folder project that has been moved into the MAUI Single app project.

* PM-3350 Improved code safety adding a lot of try...catch and logging throughout the app. Also made the invoking on main thread safer on several places of the app. Additionally, on the GroupingsPageViewModel changed the code removing the old Xamarin hack and just using Replace directly instead of Clearing first to see if that fixes the crash we're having sometimes on the app.

* PM-3350 PM-3349 Updated Unit Test projects to NET 8.0 and fixed it to work with Core project reference. Also fixed a test that was breaking due to CIpherKey creation being wrong. Added "UT" as a constant to add when building/running Core.Test project so we have something on the context that tells us that is for a UT. With this I had to remove FFImageLoading on UT context because it doesn't support NET 8.0

* PM-3350 PM-3349 Updated Readme with MAUI and main branch

* PM-3350 PM-3349 Enable running Core tests

* PM-3350 Fix build.yml format

* PM-3349 Fix navigation when coming from autofill with Accessibility Services enabled. The user was getting into Home page instead of where they were, with this workaround the app navigates as if the account has been switched, leaving the user as closely as possible to where they were, basically on the first screen for the current state of the user.

* PM-3350 PM-3349 Added property to Directory.Build.props to enable Unit Testing globally so Test runners work

* Improve TOTP scan performance on Android

* Move Android camera/scan changes to xaml

* PM-3350 Testing UseInterpreter false on CI build

* PM-3350 Enabled back UseInterpreter on iOS Release given that it crashes on startup without it.

* PM-3349 PM-3350 Improved code safety with try...catch, better invoke on main thread and better null handling.

* PM-3349 PM-3350 Updated XCode version on build.yml to 15.1

* PM-3350 Removed TapGesture Window MAUI hack from iOS.Extension and iOS.ShareExtension

* PM-3350 Fixed CancellationTokenSource proper disposal

* PM-3350 Fix Avatar toolbar icon on extensions to load properly and to take advantage of using directly SkiaSharp to do the native conversion to UIImage. Also improved the toolbar item so that size is set appropriately.

* PM-3349 PM-3350 Fix external link icon

* PM-3350 Added new style to prevent spell check and text prediction

* Fix merge from main

* PM-3350 Commented event collection upload on the timer and when sending the app to background to see if that prevents the app from crashing on release mode.

* PM-3350 Added check for state migration version before trying to migrate LiteDB values into Prefs when there's no need to and that may be inducing crashes on backgrounded iOS apps.

* PM-3350 Try to disable Interpreter to have better crash knowledge. This time testing if avoiding loading the argon2id lib we're able to not use the interpreter.

* PM-5928 Fix circle animation to be shown on verification codes list on each item

* PM-3350 Go back to use Interpreter and added some Directory.Build.props to easily change Codesign properties and also include/exclude iOS extensions / WatchOS from the build.

* PM-3350 Enabled iOS extensions and WatchOS app to be included based on the Directory.Build.props

* PM-3350 Go back to include argon2id and interpreter

* Removing error/loading placeholders of icons on the cells to see if that is causing the background crash on iOS; so we can test this in TestFlight

* [PM-5910] Workaround for for sliding elements in Duo 2FA flow (#2967)

* workaround for sliding elements in duo 2fa flow

* restrict workaround to Android

* restrict workaround to Android

* Revert "restrict workaround to Android"

This reverts commit c2753d5dc4.

* Revert "restrict workaround to Android"

This reverts commit 69688cfb98.

* PM-5902 fix for account switcher not dismissing when tapping outside (#2974)

* PM-3350 Fix iossimulator-x64 argon2id load so we can test on simulators and also made easier to maintain loading the argon2id library on the iOS projects by setting a general Directory.Build.props that is shared.

* PM-5903 Changed App.xaml.cs SetOption to only update the needed properties instead of replacing the existing Options object which would cause the AccountSwitcher button bug (#2973)

* [PM-5896] Fix MAUI iOS Background crash due to lock files on suspension (#2969)

* PM-5896 Fix background crash on iOS due to lock files when app gets suspended. Changed loading and error placeholders of the CachedImage to not be used and use default icon of IconLabel instead changing visibility.

* PM-5896 Changed methods to be protected so that they don't get removed by the linker.

* PM-5896 Added stub class and references to it so to have stronger references to Icon_Success and Icon_Error so the linker doesn't remove them.

* PM-3349 Removed commented code from build.yml regarding FDroid that is not needed anymore.

* PM-6077 Separated Android and iOS HybridWebViewHandler so that it can be used on iOS.Core (#2983)

* [PM-5907] Fix for incorrect TOTP white text color on label when using light theme on iOS (#2982)

* PM-5907 workaround for incorrect textcolor when programmatically changing text on Entry

* Update src/Core/Pages/Vault/CipherAddEditPage.xaml.cs

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

---------

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

* [PM-5906] Fix for incorrect Send MaxAccess white text color on label when using light theme on iOS (#2981)

* PM-5906 workaround for incorrect textcolor when programmatically changing text on Entry

* Update src/Core/Pages/Send/SendAddEditPage.xaml.cs

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

---------

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

* PM-3349 PM-3350 Fixed Unit tests because of referencing FFImageLoading when it's not possible

---------

Co-authored-by: Dinis Vieira <dinisvieira@outlook.com>
Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com>
Co-authored-by: mpbw2 <59324545+mpbw2@users.noreply.github.com>
2024-02-08 16:05:26 -03:00
Federico Maccaroni
e9d1792dd7 Merge branch 'feature/maui-migration-passkeys' into PM-5731-create-c-web-authn-authenticator-to-support-maui-apps 2024-02-08 12:33:33 -03:00
Federico Maccaroni
8f8a5795d3 Merge branch 'feature/maui-migration' into feature/maui-migration-passkeys 2024-02-08 12:33:16 -03:00
Federico Maccaroni
4631a9e62c PM-3349 PM-3350 Fixed Unit tests because of referencing FFImageLoading when it's not possible 2024-02-08 12:31:52 -03:00
Federico Maccaroni
51ee6a84b5 Merged main into maui-migration 2024-02-08 12:17:34 -03:00
Andreas Coroiu
b8c5ef501a [PM-5731] feat: implement fido2 client createCredential 2024-02-08 14:41:08 +01:00
Andreas Coroiu
2075f8168c [PM-5731] chore: document uri helpers 2024-02-08 14:41:07 +01:00
Andreas Coroiu
0f5df0f6b0 [PM-5731] feat: add incomplete rpId verification 2024-02-08 14:41:07 +01:00
Andreas Coroiu
ad8faec200 [PM-5731] feat: add sameOriginWithAncestor and user id length checks 2024-02-08 14:41:07 +01:00
Andreas Coroiu
3223ceb9a8 [PM-5731] fix: failing test 2024-02-08 14:41:06 +01:00
Bitwarden DevOps
f30158adf5 Bumped version to 2024.2.1 (#2985) 2024-02-07 21:25:16 +00:00
Dinis Vieira
8d5006c0bd [PM-5906] Fix for incorrect Send MaxAccess white text color on label when using light theme on iOS (#2981)
* PM-5906 workaround for incorrect textcolor when programmatically changing text on Entry

* Update src/Core/Pages/Send/SendAddEditPage.xaml.cs

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

---------

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
2024-02-07 19:09:18 +00:00
Dinis Vieira
37208571fe [PM-5907] Fix for incorrect TOTP white text color on label when using light theme on iOS (#2982)
* PM-5907 workaround for incorrect textcolor when programmatically changing text on Entry

* Update src/Core/Pages/Vault/CipherAddEditPage.xaml.cs

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

---------

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
2024-02-07 19:08:51 +00:00
Federico Maccaroni
7469dad35a PM-5731 Fix build updating discoverable flag 2024-02-07 15:31:21 -03:00
Dinis Vieira
759627b3c7 PM-6077 Separated Android and iOS HybridWebViewHandler so that it can be used on iOS.Core (#2983) 2024-02-07 17:50:07 +00:00
Federico Maccaroni
eae84ded42 Merge branch 'feature/maui-migration-passkeys' into PM-5731-create-c-web-authn-authenticator-to-support-maui-apps 2024-02-07 14:00:00 -03:00
Federico Maccaroni
563210a74e Merge branch 'PM-5731-create-c-web-authn-authenticator-to-support-maui-apps' of https://github.com/bitwarden/mobile into PM-5731-create-c-web-authn-authenticator-to-support-maui-apps 2024-02-07 13:59:53 -03:00
Federico Maccaroni
08fac4752f PM-3349 PM-3350 Fix crash on iOS AppGroup container URL because of sln config on AndroidX Credentials. Changed the project reference of Credentials to be a local NuGet. 2024-02-07 13:59:31 -03:00
Andreas Coroiu
70db27b750 [PM-5731] feat: scaffold fido2 client 2024-02-06 14:20:52 +01:00
Andreas Coroiu
00cff182b4 [PM-5731] chore: add user presence todo comment 2024-02-06 08:38:38 +01:00
Federico Maccaroni
dc5e90436b Merge branch 'feature/maui-migration-passkeys' into PM-5731-create-c-web-authn-authenticator-to-support-maui-apps 2024-02-05 14:32:00 -03:00
Federico Maccaroni
9307e7e0d8 Merge branch 'feature/maui-migration' into feature/maui-migration-passkeys 2024-02-05 14:31:44 -03:00
Federico Maccaroni
b1a0801f9b PM-3349 Removed commented code from build.yml regarding FDroid that is not needed anymore. 2024-02-05 13:14:37 -03:00
Federico Maccaroni
04cc53b934 Merge branch 'main' into feature/maui-migration 2024-02-05 11:50:41 -03:00
Federico Maccaroni
c138658a31 [PM-5896] Fix MAUI iOS Background crash due to lock files on suspension (#2969)
* PM-5896 Fix background crash on iOS due to lock files when app gets suspended. Changed loading and error placeholders of the CachedImage to not be used and use default icon of IconLabel instead changing visibility.

* PM-5896 Changed methods to be protected so that they don't get removed by the linker.

* PM-5896 Added stub class and references to it so to have stronger references to Icon_Success and Icon_Error so the linker doesn't remove them.
2024-02-05 11:46:08 -03:00
renovate[bot]
c6a086fe62 [deps]: Update gh minor (#2977)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-05 09:08:52 -05:00
renovate[bot]
b217451ea9 [deps]: Update crazy-max/ghaction-import-gpg action to v6 (#2978)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-05 09:08:33 -05:00
renovate[bot]
8cb7d5e1a3 [deps]: Update dawidd6/action-download-artifact action to v3 (#2979)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-05 09:03:08 -05:00
Vince Grassia
82b837ef33 Update Version Bump workflow logic (#2975) 2024-02-05 08:49:22 -05:00
Dinis Vieira
f1854f2c04 PM-5903 Changed App.xaml.cs SetOption to only update the needed properties instead of replacing the existing Options object which would cause the AccountSwitcher button bug (#2973) 2024-02-03 15:59:22 +00:00
Federico Maccaroni
e4056d9ee6 Merge branch 'feature/maui-migration' into feature/maui-migration-passkeys 2024-02-02 15:51:50 -03:00
Federico Maccaroni
eb95a54db2 PM-3350 Fix iossimulator-x64 argon2id load so we can test on simulators and also made easier to maintain loading the argon2id library on the iOS projects by setting a general Directory.Build.props that is shared. 2024-02-02 15:48:04 -03:00
Dinis Vieira
7ddea4c70b PM-5902 fix for account switcher not dismissing when tapping outside (#2974) 2024-02-01 21:44:13 +00:00
Federico Maccaroni
3804e86995 Merge branch 'feature/maui-migration' into feature/maui-migration-passkeys 2024-02-01 12:35:50 -03:00
Andreas Coroiu
b787a6c840 [PM-5731] chore: clean up and refactor attestation tests 2024-02-01 13:57:38 +01:00
Andreas Coroiu
a6c4bc9273 [PM-5731] chore: clean up and refactor assertion tests 2024-02-01 09:23:30 +01:00
Federico Maccaroni
b23bed182f Merge branch 'main' into feature/maui-migration 2024-01-31 12:14:02 -03:00
Federico Maccaroni
f8e421871b Merge branch 'feature/maui-migration' of https://github.com/bitwarden/mobile into feature/maui-migration 2024-01-31 12:13:31 -03:00
Andreas Coroiu
4988dbea72 [PM-5731] feat: ensure unlocked vault 2024-01-30 14:40:48 +01:00
Andreas Coroiu
ca250c53ad [PM-5731] feat: add support for specifying user presence requirement 2024-01-30 14:19:41 +01:00
André Bispo
ebb2a288a1 [PM-5856] Add visibility to label. (#2955) 2024-01-30 12:30:23 +00:00
Andreas Coroiu
6bb724ff06 [PM-5731] feat: add support for silent discoverability 2024-01-30 13:10:09 +01:00
Andreas Coroiu
f3c64a89eb [PM-5731] chore: add Async to method names 2024-01-30 10:15:58 +01:00
Andreas Coroiu
aa71ebc634 [PM-5731] chore: use primary constructor 2024-01-30 10:14:08 +01:00
Andreas Coroiu
d0bb7f0a54 [PM-5731] feat: remove logging 2024-01-30 10:01:11 +01:00
Todd Martin
de7ae27a77 [PM-5638] Update minimum version for vault item encryption to 2024.2.0 (#2966) 2024-01-29 17:54:30 -05:00
mpbw2
d0103496b9 [PM-5910] Workaround for for sliding elements in Duo 2FA flow (#2967)
* workaround for sliding elements in duo 2fa flow

* restrict workaround to Android

* restrict workaround to Android

* Revert "restrict workaround to Android"

This reverts commit c2753d5dc4.

* Revert "restrict workaround to Android"

This reverts commit 69688cfb98.
2024-01-29 17:26:14 -05:00
Federico Maccaroni
cd8952221e Merge branch 'main' into feature/maui-migration 2024-01-29 17:17:07 -03:00
Federico Maccaroni
155c7539bd Removing error/loading placeholders of icons on the cells to see if that is causing the background crash on iOS; so we can test this in TestFlight 2024-01-29 17:16:01 -03:00
Vince Grassia
d3dd2e9342 Add files for Version Bump automation (#2965) 2024-01-29 14:15:06 -05:00
Federico Maccaroni
5f43681fb1 PM-3350 Go back to include argon2id and interpreter 2024-01-29 14:30:42 -03:00
Federico Maccaroni
d2965e6e10 PM-3350 Enabled iOS extensions and WatchOS app to be included based on the Directory.Build.props 2024-01-29 14:01:18 -03:00
Federico Maccaroni
ec1ade7761 Merge branch 'main' into feature/maui-migration
# Conflicts:
#	src/App/Platforms/Android/AndroidManifest.xml
2024-01-29 13:58:30 -03:00
Federico Maccaroni
f35bef0d7b PM-3350 Go back to use Interpreter and added some Directory.Build.props to easily change Codesign properties and also include/exclude iOS extensions / WatchOS from the build. 2024-01-29 13:56:31 -03:00
Bitwarden DevOps
a5878d3341 Bumped version to 2024.2.0 (#2964) 2024-01-29 13:30:13 -03:00
renovate[bot]
1dc55f78e7 [deps]: Update gh minor (#2960)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-29 10:38:18 -05:00
renovate[bot]
37b62b317f [deps]: Update actions/stale action to v9 (#2961)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-29 10:36:54 -05:00
renovate[bot]
528e412458 [deps]: Update actions/upload-artifact action to v4 (#2962)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-29 10:34:12 -05:00
Andreas Coroiu
5d5d113369 [PM-5731] feat: implement signing 2024-01-29 14:43:14 +01:00
Andreas Coroiu
7ca9e61e93 [PM-5731] feat: return public key in DER format 2024-01-29 13:50:30 +01:00
github-actions[bot]
0f22f2750e Autosync the updated translations (#2963)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2024-01-29 11:18:32 +00:00
Andreas Coroiu
da7326b0cc [PM-5731] feat: implement key generation 2024-01-29 11:27:24 +01:00
Todd Martin
7bbb711175 [PM-5638] Bump minimum server version for vault item encryption (#2959)
Co-authored-by: Carlos Gonçalves <cgoncalves@bitwarden.com>
2024-01-26 17:03:39 -05:00
Federico Maccaroni
138d37cf5e PM-5928 Fix circle animation to be shown on verification codes list on each item 2024-01-26 12:27:57 -03:00
Andreas Coroiu
c87728027e [PM-5731] feat: partial attestation implementation 2024-01-26 14:57:44 +01:00
Federico Maccaroni
fc2fed079f PM-3350 Try to disable Interpreter to have better crash knowledge. This time testing if avoiding loading the argon2id lib we're able to not use the interpreter. 2024-01-26 10:34:28 -03:00
Federico Maccaroni
9c441a98f4 Merge branch 'main' into feature/maui-migration 2024-01-26 10:17:21 -03:00
github-actions[bot]
fd80a9ce7c Autosync the updated translations (#2957)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2024-01-26 10:52:01 +00:00
Andreas Coroiu
e1908d8eef [PM-5731] chore: clean up unusued params 2024-01-26 10:45:23 +01:00
Andreas Coroiu
8be604feac [PM-5731] feat: add unknown error handling 2024-01-26 10:44:39 +01:00
Andreas Coroiu
c90ed74faa [PM-5731] feat: add user verification checks 2024-01-26 10:30:31 +01:00
Federico Maccaroni
1491872b62 PM-3350 Added check for state migration version before trying to migrate LiteDB values into Prefs when there's no need to and that may be inducing crashes on backgrounded iOS apps. 2024-01-25 17:56:28 -03:00
Federico Maccaroni
c74636ffa5 PM-3350 Commented event collection upload on the timer and when sending the app to background to see if that prevents the app from crashing on release mode. 2024-01-25 13:22:42 -03:00
Federico Maccaroni
05677f93c5 Fix merge from main 2024-01-25 13:20:13 -03:00
Federico Maccaroni
0aef241df6 Merge branch 'main' into feature/maui-migration
# Conflicts:
#	src/Core/Pages/Settings/AboutSettingsPageViewModel.cs
2024-01-25 13:16:42 -03:00
Andreas Coroiu
32c43afae2 [PM-5731] feat: implement credential creation 2024-01-25 16:29:26 +01:00
Andreas Coroiu
44b2443554 [PM-5731] feat: add new credential confirmaiton 2024-01-25 10:49:23 +01:00
mpbw2
3f10a6be24 Add privacy policy link to about screen (#2954) 2024-01-24 15:07:39 -05:00
renovate[bot]
f3537b1a74 [deps]: Update gh minor (#2544)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-24 10:07:10 -05:00
Vince Grassia
849a0c24b0 Update Renovate config (#2953) 2024-01-24 10:05:30 -05:00
Federico Maccaroni
e0b58461b5 Merge branch 'main' into feature/maui-migration 2024-01-24 11:22:28 -03:00
Federico Maccaroni
cd33c7f608 PM-3350 Added new style to prevent spell check and text prediction 2024-01-24 11:22:02 -03:00
Andreas Coroiu
f0dde7eb82 [PM-5731] feat: implement credential exclusion 2024-01-24 14:18:27 +01:00
Carlos Gonçalves
f6a58e469f [PM-4739] Implement checksum uri validation (#2893)
* PM-4739 Implement checksum uri validation

* PM-4739 Add missing field

* PM-4739 Fix PR comments

* PM-4739 Remove unnecessary comment

* PM-4739 Add try catch and log exception

* PM-4739 Added missing files from last commit

* PM-4739 Change arg name

* [PM-5461] Fix item saving with blank URI (#2948)

* PM-5461 Fix item saving with blank URI

* PM-5461 Fix PR comment
2024-01-24 13:15:24 +00:00
Andreas Coroiu
19639b61c3 [PM-5731] feat: start implementing attestation 2024-01-24 11:04:37 +01:00
Federico Maccaroni
9d29af36e5 Merge branch 'feature/maui-migration' into feature/maui-migration-passkeys 2024-01-23 18:00:53 -03:00
Federico Maccaroni
4472d7f9a8 PM-3349 PM-3350 Fix external link icon 2024-01-23 17:59:32 -03:00
Federico Maccaroni
999579915c Merge branch 'main' into feature/maui-migration 2024-01-23 17:34:55 -03:00
Federico Maccaroni
63904fd303 PM-3350 Fix Avatar toolbar icon on extensions to load properly and to take advantage of using directly SkiaSharp to do the native conversion to UIImage. Also improved the toolbar item so that size is set appropriately. 2024-01-23 17:34:27 -03:00
renovate[bot]
983937c9eb [deps]: Update actions/setup-node action to v4 (#2868)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-23 15:02:04 -05:00
Andreas Coroiu
ce550fee74 [PM-5731] feat: scaffold make credential 2024-01-23 14:29:20 +01:00
Andreas Coroiu
f0841eb8b2 [PM-5731] chore: minor clean up 2024-01-23 10:37:04 +01:00
Andreas Coroiu
b23d58c0b1 [PM-5732] feat: finish authenticator assertion implementation
note: CryptoFunctionService still needs Sign implemenation
2024-01-23 10:28:00 +01:00
Federico Maccaroni
2cb6872e4e Merge branch 'feature/maui-migration' into feature/maui-migration-passkeys 2024-01-22 16:57:59 -03:00
Federico Maccaroni
f539bf051d Merge branch 'main' into feature/maui-migration 2024-01-22 16:57:45 -03:00
Federico Maccaroni
14f845d623 Merge branch 'feature/maui-migration' into feature/maui-migration-passkeys
# Conflicts:
#	src/App/Platforms/iOS/AppDelegate.cs
2024-01-22 16:57:07 -03:00
renovate[bot]
b2f93d3d4b [deps]: Update actions/setup-dotnet action to v4 (#2947)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-22 10:31:17 -05:00
Federico Maccaroni
133a80acef PM-3350 Fixed CancellationTokenSource proper disposal 2024-01-22 12:30:29 -03:00
Andreas Coroiu
e8f6c37c06 [PM-5731] feat: implement assertion without signature 2024-01-22 16:08:15 +01:00
Federico Maccaroni
b43790de9a Merge branch 'main' into feature/maui-migration 2024-01-22 10:00:30 -03:00
Andreas Coroiu
d0e0f0ecdb [PM-5731] feat: add support for counter 2024-01-22 13:36:53 +01:00
Matt Bishop
64c694e593 Fix code ownership (#2946) 2024-01-19 17:31:32 -05:00
renovate[bot]
56b9e3f615 Pin dependency gh-pages to 3.2.3 (#2542)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-19 17:05:36 -05:00
Matt Bishop
7558f60a44 Fix Renovate config (#2945) 2024-01-19 17:04:54 -05:00
Federico Maccaroni
0bdd63df06 Merge branch 'main' into feature/maui-migration 2024-01-19 15:14:50 -03:00
Federico Maccaroni
c6544b49e9 PM-3350 Removed TapGesture Window MAUI hack from iOS.Extension and iOS.ShareExtension 2024-01-19 15:14:22 -03:00
Federico Maccaroni
8e1a8b5f0e PM-3349 PM-3350 Updated XCode version on build.yml to 15.1 2024-01-19 15:02:53 -03:00
Federico Maccaroni
4717f5e230 PM-3349 PM-3350 Improved code safety with try...catch, better invoke on main thread and better null handling. 2024-01-19 15:01:31 -03:00
Andreas Coroiu
ad80defa40 [PM-5731] fix: tests a bit, needed some additional "arrange" steps 2024-01-19 16:42:24 +01:00
Andreas Coroiu
0dc281edc1 [PM-5731] feat: check for UV when reprompt is active 2024-01-19 15:47:06 +01:00
Andreas Coroiu
378551e2d5 [PM-5731] feat: add user does not consent test 2024-01-19 15:18:46 +01:00
Andreas Coroiu
dbe4110027 [PM-5731] feat: add tests for successful UV requests 2024-01-19 11:36:34 +01:00
Andreas Coroiu
a08466d220 [PM-5731] feat: find discoverable credentials 2024-01-19 11:23:56 +01:00
github-actions[bot]
e66ac9dd44 Autosync the updated translations (#2944)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2024-01-19 09:45:12 +00:00
Andreas Coroiu
66a01e30d3 [PM-5731] feat: ask for credentials when found 2024-01-19 10:45:03 +01:00
Federico Maccaroni
01ee1ff845 PM-3350 Enabled back UseInterpreter on iOS Release given that it crashes on startup without it. 2024-01-18 18:54:34 -03:00
Federico Maccaroni
75b4655f38 PM-3350 Testing UseInterpreter false on CI build 2024-01-18 16:32:00 -03:00
mpbw2
9b2f596d15 Move Android camera/scan changes to xaml 2024-01-18 11:31:16 -05:00
Andreas Coroiu
cc89b6a5d5 [PM-5731] feat: add rp mismatch test 2024-01-18 10:15:21 +01:00
Andreas Coroiu
32c2f2aac4 [PM-5731] feat: add first test 2024-01-18 09:23:06 +01:00
Andreas Coroiu
f9b4e30b0b [PM-5731] feat: implement get assertion params object 2024-01-18 09:23:05 +01:00
mpbw2
55fb71744d Improve TOTP scan performance on Android 2024-01-17 13:03:11 -05:00
Federico Maccaroni
ee252be634 Merge branch 'feature/maui-migration' into feature/maui-migration-passkeys 2024-01-17 13:22:47 -03:00
Federico Maccaroni
66f0471f2e Merge branch 'main' into feature/maui-migration 2024-01-17 13:22:26 -03:00
Federico Maccaroni
6b9eeba88d PM-3350 PM-3349 Added property to Directory.Build.props to enable Unit Testing globally so Test runners work 2024-01-17 13:22:00 -03:00
Federico Maccaroni
0a1fbfafb5 PM-3349 Fix navigation when coming from autofill with Accessibility Services enabled. The user was getting into Home page instead of where they were, with this workaround the app navigates as if the account has been switched, leaving the user as closely as possible to where they were, basically on the first screen for the current state of the user. 2024-01-17 09:34:31 -03:00
Daniel James Smith
d6c139cb8a Import-link routes to import page after login (#2939)
Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>
2024-01-16 12:02:06 -03:00
Federico Maccaroni
0a5d772886 PM-3350 Fix build.yml format 2024-01-16 11:32:27 -03:00
Daniel James Smith
6b7c6eac71 Import-link routes to import page after login (#2937)
Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>
2024-01-16 11:49:40 +00:00
Federico Maccaroni
70c8a264d2 PM-3350 PM-3349 Enable running Core tests 2024-01-15 17:35:37 -03:00
Federico Maccaroni
b5fbb2cade Merge branch 'feature/maui-migration' into feature/maui-migration-passkeys
# Conflicts:
#	bitwarden-mobile.sln
2024-01-15 17:24:33 -03:00
Federico Maccaroni
9027755b71 PM-3350 PM-3349 Updated Readme with MAUI and main branch 2024-01-15 17:20:46 -03:00
Federico Maccaroni
6d625f285b PM-3350 PM-3349 Updated Unit Test projects to NET 8.0 and fixed it to work with Core project reference. Also fixed a test that was breaking due to CIpherKey creation being wrong. Added "UT" as a constant to add when building/running Core.Test project so we have something on the context that tells us that is for a UT. With this I had to remove FFImageLoading on UT context because it doesn't support NET 8.0 2024-01-15 17:18:51 -03:00
Federico Maccaroni
822ad7564e Merge branch 'feature/maui-migration' into feature/maui-migration-passkeys
# Conflicts:
#	src/iOS.Autofill/iOS.Autofill.csproj
2024-01-12 13:59:59 -03:00
Federico Maccaroni
1949a450fd PM-3350 Improved code safety adding a lot of try...catch and logging throughout the app. Also made the invoking on main thread safer on several places of the app. Additionally, on the GroupingsPageViewModel changed the code removing the old Xamarin hack and just using Replace directly instead of Clearing first to see if that fixes the crash we're having sometimes on the app. 2024-01-12 13:54:34 -03:00
Federico Maccaroni
27fa79e0bd Merge branch 'main' into feature/maui-migration 2024-01-12 09:16:10 -03:00
github-actions[bot]
9e1d6c7b03 Autosync the updated translations (#2936)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2024-01-12 06:46:31 +01:00
Federico Maccaroni
1e29eacc61 PM-3350 Removed "iOS" old folder project that has been moved into the MAUI Single app project. 2024-01-11 17:51:34 -03:00
Federico Maccaroni
b81d26d589 Bump main iOS version 2024-01-11 14:18:34 -03:00
Federico Maccaroni
cd107b6161 Merge branch 'main' into feature/maui-migration
# Conflicts:
#	src/App/Platforms/Android/AndroidManifest.xml
#	src/iOS.Core/Renderers/CollectionView/ExtendedGroupableItemsViewController.cs
2024-01-11 14:17:34 -03:00
Federico Maccaroni
7ac3646fb0 PM-3350 Added nuget.config so we add the nuget package source for MAUI Nightly builds 2024-01-11 10:31:36 -03:00
Federico Maccaroni
d1e4e8645a PM-3350 Updated MauiVersion to 8.0.4-nightly.* to have the TapGestureRecognizer fix applied. This is done on the Directory.Build.props so we don't have to change it on every csproj. Also removed the workaround of TapGestureHack and fix the Show environment picker to work on the extensions as well. 2024-01-10 19:53:53 -03:00
Bitwarden DevOps
e107b893ea Bumped version to 2024.1.1 (#2934) 2024-01-10 17:30:04 +00:00
André Bispo
5de02c863f [PM-5633] Ignore ArgumentOutOfRangeException to collect more data about the crash (#2933) 2024-01-10 17:02:54 +00:00
André Bispo
0e95d4d4ca [PM-5542] Update sso endpoint (#2930) 2024-01-09 21:32:42 +00:00
Federico Maccaroni
36a648e53e Merge branch 'feature/maui-migration' into feature/maui-migration-passkeys
# Conflicts:
#	src/Core/Core.csproj
2024-01-09 18:10:56 -03:00
Federico Maccaroni
6c04ac67b1 PM-3349 Fix Picker selection style by doing a custom PickerHandler for Android which uses SetSingleChoiceItems(...) to provide with the appropriate UI 2024-01-09 15:08:45 -03:00
github-actions[bot]
a42b88b666 Autosync the updated translations (#2929)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2024-01-05 11:37:30 +01:00
Federico Maccaroni
dfb7a0621f PM-5154 Added Fido2AuthenticationService to provide us a wrapper for the actual implementation 2024-01-03 19:02:49 -03:00
mpbw2
1eb9e5f8ea add cred manager project to build config 2024-01-03 16:36:56 -05:00
mpbw2
b149e7549c initial commit of android credential provider service (wip) 2024-01-03 16:30:44 -05:00
Federico Maccaroni
e3877cc589 PM-5154 Continue Passkeys Autofill in iOS 2024-01-03 18:22:03 -03:00
Federico Maccaroni
275ae76761 PM-5154 Start implementing Passkeys Autofill in iOS 2024-01-03 18:21:02 -03:00
Federico Maccaroni
a1e4f0aaa2 PM-3350 Updated version to 2024.1.0 on iOS 2024-01-02 13:21:32 -03:00
Federico Maccaroni
adaef0d15b Merge branch 'main' into feature/maui-migration
# Conflicts:
#	src/App/Platforms/Android/AndroidManifest.xml
2024-01-02 13:20:15 -03:00
Bitwarden DevOps
af6866cee1 Bumped version to 2024.1.0 (#2928) 2024-01-02 14:40:03 +00:00
André Bispo
0cec49f121 [PM-4584] Add device identifier to request headers. (#2909) 2024-01-02 13:10:37 +00:00
github-actions[bot]
d091922017 Autosync the updated translations (#2927)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2024-01-02 11:49:43 +01:00
github-actions[bot]
f14be2a3a2 Autosync the updated translations (#2919)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-12-29 00:59:08 +00:00
github-actions[bot]
8ee744b746 Autosync the updated translations (#2918)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-12-28 13:07:30 +00:00
Dinis Vieira
fa4a2247e3 PM-3349 Changed the "track color" for the Android switch so that the color is different from the "thumb" 2023-12-23 23:09:11 +00:00
Dinis Vieira
5d2fc4530f PM-3349 Minor aligment improvemment for region selection in HomePage 2023-12-23 15:25:41 +00:00
Dinis Vieira
9b64af3423 PM-3349 Fix for icon and text spacing in some list items 2023-12-23 14:30:24 +00:00
Dinis Vieira
b6ff6e34f6 PM-3349 Added custom window so that we can always get the current Active Window. This is used to support the Android Autofil and multi-window scenarios. 2023-12-23 12:30:21 +00:00
Dinis Vieira
6d4c706026 Merge branch 'feature/maui-migration-android-autofill' into feature/maui-migration-android-autofill-redirect-page 2023-12-22 22:16:17 +00:00
Dinis Vieira
14fd026ea0 Merge branch 'feature/maui-migration' into feature/maui-migration-android-autofill 2023-12-22 22:15:58 +00:00
Dinis Vieira
a4392a8730 PM-3349 PM-3350 Changed search icon used in app to avoid issue with icon size on iOS 2023-12-22 22:15:01 +00:00
Dinis Vieira
1b885ea438 PM-3350 Fix for Delete Account buttons on iOS 2023-12-22 17:07:43 +00:00
github-actions[bot]
15a03ba573 Autosync the updated translations (#2913)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-12-22 10:20:55 +00:00
mpbw2
fa022a1a4f Revert "initial commit of android credential provider service (wip)"
This reverts commit 6011b63958.
2023-12-20 18:23:08 -05:00
mpbw2
6011b63958 initial commit of android credential provider service (wip) 2023-12-20 18:04:21 -05:00
Dinis Vieira
7d79b98bf2 PM-3349 Minor ui fix (space between buttons in delete account page) 2023-12-20 19:04:26 +00:00
Dinis Vieira
d4e75e9de8 PM-3349 Added Window events unsubscription of events. Also changed code to avoid potentially having multiple autofillwindow 2023-12-18 22:56:21 +00:00
Vince Grassia
82711a0235 Merge _cut_rc.yml into version-bump.yml (#2908) 2023-12-18 10:59:41 -07:00
Dinis Vieira
c3370b58ec Added some comments and improvemments. 2023-12-18 00:24:38 +00:00
Dinis Vieira
3de13325c9 Merge branch 'feature/maui-migration-android-autofill' into feature/maui-migration-android-autofill-redirect-page 2023-12-17 22:26:46 +00:00
Dinis Vieira
c253c110c1 Merge branch 'feature/maui-migration' into feature/maui-migration-android-autofill 2023-12-17 22:26:33 +00:00
Dinis Vieira
bf35d1f2dc PM-3349 minor fix to add space in HomePage between the region picker labels. 2023-12-17 22:26:15 +00:00
Dinis Vieira
05b6aa90b6 Improved autofill workaround to better handle switching between windows. 2023-12-17 22:05:37 +00:00
Dinis Vieira
e39898bba6 Reusing App.xaml.cs Navigation for the Android RedirectPage
Some other cleanup and changes
2023-12-16 15:18:07 +00:00
Dinis Vieira
da0866cc85 Merge branch 'feature/maui-migration-android-autofill' into feature/maui-migration-android-autofill-redirect-page 2023-12-15 23:51:08 +00:00
Dinis Vieira
b3140381ab Merge branch 'feature/maui-migration' into feature/maui-migration-android-autofill
# Conflicts:
#	src/Core/App.xaml.cs
2023-12-15 23:50:48 +00:00
Dinis Vieira
c01a8f8d93 PM-3349 Ensure "_isResumed=true" is set on App.xaml.cs:Bootstrap 2023-12-15 23:48:11 +00:00
Federico Maccaroni
8484b4af30 PM-3349 Uncommented the Deploy step for Android job 2023-12-15 16:38:40 -03:00
Federico Maccaroni
6b9faed45f PM-3349 Commented the Deploy step for Android job given that we're using the hotfix-rc branch for testing iOS on TestFlight 2023-12-15 12:08:01 -03:00
Federico Maccaroni
770a1c5dfe Merge branch 'main' into feature/maui-migration 2023-12-15 11:53:57 -03:00
github-actions[bot]
e6635564aa Autosync the updated translations (#2906)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-12-15 15:20:45 +01:00
Dinis Vieira
3c87d4db1c minor improvemments on autofill-redirect 2023-12-15 13:48:34 +00:00
Vince Grassia
6c078fe343 Update version bump workflow (#2905) 2023-12-15 13:30:15 +01:00
Dinis Vieira
8b3c6ab35f minor change (public to private fields) 2023-12-14 22:43:50 +00:00
Dinis Vieira
90912977c4 Merge branch 'feature/maui-migration-android-autofill' into feature/maui-migration-android-autofill-redirect-page 2023-12-14 22:02:39 +00:00
Dinis Vieira
740b368b8c Merge branch 'feature/maui-migration' into feature/maui-migration-android-autofill 2023-12-14 22:00:06 +00:00
Federico Maccaroni
3a40a4cda8 PM-3349 Upgraded Android targetSdkVersion to 34 2023-12-14 17:52:11 -03:00
Federico Maccaroni
9bcd2e51f7 Merge branch 'feature/maui-migration' of https://github.com/bitwarden/mobile into feature/maui-migration 2023-12-14 17:32:48 -03:00
Federico Maccaroni
741214a1cc PM-3349 PM-3350 Enabled argon2id and fixed one issue with the Uris when getting the icon image 2023-12-14 17:32:43 -03:00
Federico Maccaroni
aad87dfdce Update .github/workflows/build.yml setup-xcode commit hash
Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com>
2023-12-14 17:28:10 -03:00
Federico Maccaroni
8fc1e9a3b9 PM-3350 Updated Plugin.Fingerprint so biometrics work 2023-12-14 16:32:04 -03:00
Federico Maccaroni
2a8e15146e PM-3350 Apply Cryptography TrimmerRootAssembly only to iOS 2023-12-14 14:28:20 -03:00
Federico Maccaroni
8559d5908e Merge branch 'feature/maui-migration' of https://github.com/bitwarden/mobile into feature/maui-migration 2023-12-14 13:16:41 -03:00
Federico Maccaroni
f60c4d94fe PM-3350 Fix crash on Release by adding Interpreter on iOS and also adding System.Security.Cryptography to be ignored by the linker 2023-12-14 13:16:32 -03:00
Dinis Vieira
05858bea48 Proof of concept for having multiple window in Android for autofill support and navigating with the help of an Extended splash page. 2023-12-13 23:42:58 +00:00
Dinis Vieira
5cbef47fd4 Merge branch 'feature/maui-migration' into feature/maui-migration-android-autofill 2023-12-13 22:05:52 +00:00
Dinis Vieira
4bf695d18c PM-3349 Fix for app crashing on Android when Dark mode is enabled
Removed unused button style for android
2023-12-13 19:20:43 +00:00
Dinis Vieira
c24e0dfa28 Merge branch 'feature/maui-migration' into feature/maui-migration-android-autofill 2023-12-13 17:30:27 +00:00
Federico Maccaroni
9ccd0834ff Merge branch 'main' into feature/maui-migration 2023-12-13 10:24:29 -03:00
Joseph Flinn
743e71ff92 Fix branch (#2903) 2023-12-13 05:56:34 -05:00
Federico Maccaroni
a806f17d3b PM-3350 Changed linker to use default mode given that "Full" is presenting some problems as the linker is stripping things it shouldn't and we're trying to solve it. So for now we will use the mode "Link SDK assemblies only" so QA can test. 2023-12-12 21:10:51 -03:00
Federico Maccaroni
436a162df2 Merge branch 'main' into feature/maui-migration 2023-12-12 20:19:42 -03:00
github-actions[bot]
7b579b7aa5 Autosync the updated translations (#2902)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-12-12 20:09:30 +00:00
Joseph Flinn
fe10fd7766 Point workflows to main (#2896) 2023-12-12 11:12:27 -08:00
Vince Grassia
3c0de8aacc Add token to checkout step (#2901) 2023-12-12 09:38:12 -08:00
Vince Grassia
18d9a77f25 Fix version bump workflow on call (#2900) 2023-12-12 08:55:24 -08:00
Vince Grassia
9eca82a62b Update version bump workflow (#2898) 2023-12-12 10:22:22 -05:00
Dinis Vieira
f2c298607e Merge branch 'feature/maui-migration' into feature/maui-migration-android-autofill 2023-12-11 22:19:49 +00:00
mpbw2
b90e030b8f [PM-4837] Hide TOTP seed copy button when Can view, except password permission set (#2869)
* Hide TOTP seed copy button when Can view, except password permission set

* additional check

* removal of null check
2023-12-11 16:40:09 -05:00
Federico Maccaroni
b5dbb9ae5e PM-3350 Bumped iOS version 2023-12-11 13:21:31 -03:00
Federico Maccaroni
7a5f7c0274 Merge branch 'master' into feature/maui-migration 2023-12-11 11:42:46 -03:00
Dinis Vieira
17acb57732 PM-3349 Added base structure for avoiding Android Autofill crash. This workaround works but it's not complete as it can't handle the entire workflow when showing CipherSelectionPAge (like checking if it should show LockPage) 2023-12-10 15:05:08 +00:00
github-actions[bot]
9a28419a4e Autosync the updated translations (#2894)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-12-08 10:56:26 +00:00
Federico Maccaroni
5803635f44 PM-3349 PM-3350 Refactored cipher bindings to have a simpler approach reusing a new CipherItemViewModel to avoid unwanted issues in the app 2023-12-07 23:59:06 -03:00
Federico Maccaroni
19c393842f PM-3350 Cleared left ClipLogger from the iOS extensions debug logging. 2023-12-07 18:14:02 -03:00
Federico Maccaroni
15a306490d Merge branch 'feature/maui-migration' into feature/maui-migration-ios-ext-tap-workaround 2023-12-07 17:41:53 -03:00
Federico Maccaroni
a4a3d31c19 PM-3350 Fix iOS extensions navigation and Window/RootViewController handling for TapGestureRecognizer to work 2023-12-07 17:40:20 -03:00
github-actions[bot]
f4c468e6a1 Bumped version to 2023.12.1 (#2892)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-12-06 13:35:08 -05:00
Dinis Vieira
922dc683af PM-3349 Replaced CrossCurrentActivity plugin with MAUI internal CurrentActivity 2023-12-06 17:27:17 +00:00
github-actions[bot]
2c346eb710 Bumped version to 2023.12.0 (#2891)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-12-06 10:47:08 -05:00
Daniel James Smith
9c0908f7b7 Remove tools ownership for store/google/Publisher (#2890) 2023-12-06 08:15:24 -05:00
Bahasnyldz
827fbbc9ce Add Cromite browser (#2640) 2023-12-04 18:37:34 -03:00
Dinis Vieira
bae1b3e891 PM-3349 PM-3350 Minor change: removed unneeded HorizontalTextAlignment from Label. 2023-12-04 16:54:55 +00:00
Federico Maccaroni
a5888827c9 Merge branch 'feature/maui-migration' into feature/maui-migration-ios-ext-tap-workaround 2023-12-04 12:18:01 -03:00
Federico Maccaroni
0348940a12 Merge branch 'master' into feature/maui-migration 2023-12-04 12:17:48 -03:00
Federico Maccaroni
5b249bed67 PM-5064 Fix lock interaction between biometrics and vault timeout never (#2885) 2023-12-04 12:13:13 -03:00
Federico Maccaroni
4c2998337d Merge branch 'feature/maui-migration' into feature/maui-migration-ios-ext-tap-workaround 2023-12-04 11:44:03 -03:00
Federico Maccaroni
7ea86380f4 PM-3349 PM-3350 build.yml uncommented jobs so we have a more complete workflow 2023-12-04 11:41:55 -03:00
Federico Maccaroni
406f4425c8 PM-3349 PM-3350 Added MAUI label on self-host settings and on about settings to differentiate from XF app 2023-12-04 11:35:35 -03:00
Federico Maccaroni
95ca911444 PM-3350 Improved MTouch linking and extra args on iOS related csprojs 2023-12-04 11:30:54 -03:00
Federico Maccaroni
fa62510e09 PM-3350 build.yml Added several fixes like not using MtouchUseLLVM on the iOS builds to fix they taking forever to build and some changes on the automation CI to do a debug build for the moment 2023-12-04 10:41:41 -03:00
Federico Maccaroni
65dc73495d PM-3350 build.yml added step to validate app for submitting into App Store and have better logs of it 2023-12-04 10:11:29 -03:00
Federico Maccaroni
02a2e41118 PM-3350 fix build.yml Bitwarden.ipa AppStore exported file 2023-12-04 10:10:18 -03:00
Federico Maccaroni
bd6f8295e7 PM-3350 iOS updated CFBundlerShortVersionString to latest one 2023.10.1 2023-12-04 10:01:56 -03:00
Federico Maccaroni
0a0cb7093b Merge branch 'master' into feature/maui-migration
# Conflicts:
#	.github/workflows/build.yml
2023-12-04 09:59:52 -03:00
Dinis Vieira
465e5eff76 PM-3349 PM-3350 Fix for text getting cut/truncated in both account switcher and ciphers/search lists
Issue is due to MAUI but can be avoided by using slightly different layout
2023-12-03 22:17:16 +00:00
Dinis Vieira
5b756aaf7a PM-3349 PM-3350 Added the ability for users to press "Continue" button as a fallback when using the Yubikey if the "SubmitCommand" doesn't trigger automatically. 2023-12-01 16:49:14 +00:00
Federico Maccaroni
afbcb212f6 [PM-4896] Fix null reference exception on the region when setting env urls (#2876)
* PM-4896 Fix null reference exception on the region

* PM-4896 Updated dotnet version to set up in build workflow

* PM-4896 Add NET 3.1.x and NET 7.0.x to Android build

* PM-4896 Reversed to NET 3.1.x  Android build

* PM-4896 Removed changes on build.yml for net version name
2023-12-01 12:30:27 -03:00
Dinis Vieira
d168a7b750 PM-3349 PM-3350 Added workaround for More Options to work on Search and Groupings Page
Updated some code to MAUI Style also
2023-12-01 15:02:12 +00:00
github-actions[bot]
a71c28536d Autosync the updated translations (#2884)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-12-01 12:06:17 +01:00
Federico Maccaroni
7f4bbafe3c PM-3350 iOS applied workaround on the iOS Autofill and Share extension to maui embed the navigation page with its content page in the Window 2023-11-30 18:23:54 -03:00
Federico Maccaroni
a5804df6a3 PM-3350 iOS extensions TapGestureRecognizer try Window workaround 2023-11-29 18:42:39 -03:00
Vince Grassia
ba5fa8a518 Fix Build workflow - Install OpenJDK 11 (#2883) 2023-11-27 17:18:28 -05:00
Federico Maccaroni
bfa2a51608 PM-3349 build.yml configured FDROID job for MAUI 2023-11-27 17:53:01 -03:00
Federico Maccaroni
32be08daae PM-3349 build.yml enabled android build workflow 2023-11-27 09:24:36 -03:00
github-actions[bot]
65ea5574de Autosync the updated translations (#2880)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-11-27 11:36:59 +00:00
Dinis Vieira
0a628cc8a8 PM-3349 PM-3350 Workaround to fix issues with text getting cropped/truncated when a Label has both Multiline and LinebreakMode set 2023-11-26 14:46:30 +00:00
Federico Maccaroni
80c424ed03 Update build.yml disabling iOS job to avoid long running process of publish until we can fix that 2023-11-25 10:17:48 -03:00
Federico Maccaroni
99fb5463cf PM-3350 iOS projs disable linking and set Newstandkit as weak framework 2023-11-24 17:47:12 -03:00
Federico Maccaroni
c5d941e1df PM-3350 added linkskip for iOS csprojs 2023-11-24 15:13:45 -03:00
Federico Maccaroni
3edfef6169 PM-3350 build.yml disable trimming on publish so it's faster 2023-11-24 13:59:09 -03:00
Federico Maccaroni
1c8742511a PM-3350 Added Document.Build.props to disable trimming on publish 2023-11-24 12:50:17 -03:00
Federico Maccaroni
8e424d6c05 PM-3350 build.yml changed image back to be macos-13 to see if the build is faster 2023-11-24 11:17:45 -03:00
Federico Maccaroni
390c303b90 PM-3350 build.yml try to fix ILLINK warnings and changed image to be macos-13-arm64 to see if the build is faster 2023-11-24 10:50:36 -03:00
Federico Maccaroni
443f7282b8 PM-3350 build.yml Upgraded iOS build to run on macos-13 image which has XCode 15, and set the XCode 15 version as currently the default one is 14.x 2023-11-23 18:05:58 -03:00
Federico Maccaroni
50109ee70b PM-3350 build.yml changed nuget restore for dotnet restore on iOS build to fix issue on restoring due to msbuild 2023-11-23 17:38:23 -03:00
Federico Maccaroni
9ffdfd51cc PM-3350 build.yml updated iOS build and ignore Android build to try the CI faster 2023-11-23 17:20:17 -03:00
Federico Maccaroni
04e409f3c6 PM-3349 build.yml add Android "prod" variant 2023-11-23 16:32:10 -03:00
Federico Maccaroni
6c143bad57 PM-3349 build.yml updated env helpers variables and set specific csproj to build on Android so not to build iOS extensions 2023-11-23 15:39:16 -03:00
Federico Maccaroni
286e18059a PM-3349 PM-3350 build.cake updated paths 2023-11-23 14:08:14 -03:00
Federico Maccaroni
553bf9ed0a PM-3349 build.yml commented verify format and just set qa as variant on MAUI Android for faster checks on CI 2023-11-23 13:08:18 -03:00
Federico Maccaroni
ddb27b52d3 PM-3349 build.yml update paths for MAUI Android 2023-11-23 12:49:29 -03:00
Federico Maccaroni
6c504aa710 PM-3349 Started to configure build.yml for MAUI Android 2023-11-23 12:18:31 -03:00
Dinis Vieira
62254aef8d PM-3349 PM-3350 Fixed issue where creating an account with weak/exposed password would get stuck after the Captcha (if a captcha is shown)
Changed App.xaml.cs NavigateImpl to be private
2023-11-21 22:39:44 +00:00
Dinis Vieira
06a0195a6d PM-3349 Added workaround for Android to avoid issues with setting MainPage when app is in background. They are now kept on a Queue to be executed after the app has resumed.
Updated some things on App.xaml.cs to the new MAUI style
2023-11-21 21:26:14 +00:00
Dinis Vieira
df2b0b21d5 PM-3350 Added workaround for iOS Avatar icon again. 2023-11-20 22:07:40 +00:00
Federico Maccaroni
e6b1bab860 PM-3350 Updated AppCenter package to latest version 5.0.3 and updated some things into MAUI style 2023-11-20 17:29:16 -03:00
Federico Maccaroni
ce41eb0578 PM-3350 Fixed account toolbar item and TitleView on SendAddOnlyPage, also removed comments on AvatarImageSource given the workaround is not needed anymore to draw the image successfully. 2023-11-20 16:09:23 -03:00
Federico Maccaroni
1a0b52d644 PM-3350 Fixed/Updated all MAUI-Migration TODOs 2023-11-20 13:10:03 -03:00
Federico Maccaroni
16ada4993c Merge branch 'feature/maui-migration' of https://github.com/bitwarden/mobile into feature/maui-migration
# Conflicts:
#	src/Core/Pages/Settings/OtherSettingsPageViewModel.cs
2023-11-20 10:49:42 -03:00
Federico Maccaroni
3795f3aa17 PM-3350 Added watchOS app to main project and fixed some csproj conditions for runtime identifiers on iOS. 2023-11-20 10:44:56 -03:00
Dinis Vieira
eceb506c77 Merge branch 'master' into feature/maui-migration
Fixed conflicts

# Conflicts:
#	src/App/Resources/AppResources.cs.Designer.cs
#	src/App/Resources/AppResources.da.Designer.cs
#	src/App/Resources/AppResources.de.Designer.cs
#	src/App/Resources/AppResources.es.Designer.cs
#	src/App/Resources/AppResources.fi.Designer.cs
#	src/App/Resources/AppResources.fr.Designer.cs
#	src/App/Resources/AppResources.hi.Designer.cs
#	src/App/Resources/AppResources.hr.Designer.cs
#	src/App/Resources/AppResources.hu.Designer.cs
#	src/App/Resources/AppResources.id.Designer.cs
#	src/App/Resources/AppResources.it.Designer.cs
#	src/App/Resources/AppResources.ja.Designer.cs
#	src/App/Resources/AppResources.nl.Designer.cs
#	src/App/Resources/AppResources.pl.Designer.cs
#	src/App/Resources/AppResources.pt-BR.Designer.cs
#	src/App/Resources/AppResources.pt-PT.Designer.cs
#	src/App/Resources/AppResources.ro.Designer.cs
#	src/App/Resources/AppResources.ru.Designer.cs
#	src/App/Resources/AppResources.sk.Designer.cs
#	src/App/Resources/AppResources.sv.Designer.cs
#	src/App/Resources/AppResources.th.Designer.cs
#	src/App/Resources/AppResources.tr.Designer.cs
#	src/App/Resources/AppResources.uk.Designer.cs
#	src/App/Resources/AppResources.vi.Designer.cs
#	src/App/Resources/AppResources.zh-Hans.Designer.cs
#	src/App/Resources/AppResources.zh-Hant.Designer.cs
#	src/Core/Controls/Settings/BaseSettingControlView.cs
#	src/Core/Pages/Accounts/EnvironmentPageViewModel.cs
#	src/Core/Pages/Accounts/HomePage.xaml.cs
#	src/Core/Pages/Accounts/HomePageViewModel.cs
#	src/Core/Pages/Accounts/SetPasswordPageViewModel.cs
#	src/Core/Pages/Settings/SecuritySettingsPageViewModel.cs
#	src/Core/Pages/TabsPage.cs
#	src/Core/Services/StateMigrationService.cs
#	src/Core/Utilities/BoolToColorConverter.cs
2023-11-19 15:06:02 +00:00
github-actions[bot]
f013f69669 Autosync the updated translations (#2872)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-11-19 09:33:27 +01:00
cubemike99
f98dfa6581 [PM-4800] Send item domain name to fastmail (#2867)
* Send item domain name to fastmail

- Added a metadata field (forDomain:) to the Fastmail Forwarder API
  request that's set to the domain name of the item being added to the
  vault, or to "" if the username generator is being used in standalone
  mode. This allows the user's Fastmail account to display the domain
  name for the username that was generated.

* Minor changes for readability

* dotnet format

---------

Co-authored-by:  Audrey  <ajensen@bitwarden.com>
2023-11-17 17:17:25 -05:00
Federico Maccaroni
0723999652 [PM-4857] Hide "Allow screen capture" on iOS (#2873)
* PM-4857 Hide "Allow screen capture" on iOS

* PM-4857 Try to fix FDroid build by forcing .NET 7

* PM-4857 Try to fix FDroid build by forcing .NET 7, adding rollForward and disable allowPrerelease to the global json

* PM-4857 Changed global.json to use 7.0.400 so FDroid pass in CI
2023-11-17 19:14:25 -03:00
Dinis Vieira
2c7870d660 PM-3349 PM-3350 Removed AsyncCommand "wrapper" and added AsyncRelayCommand directly in all ViewModels that were using the other one. 2023-11-16 22:31:01 +00:00
Dinis Vieira
f02b3415a3 PM-3350 Removed workaround for iOS issue with Avatar icon as it's now fixed in latest .Net8 release. 2023-11-14 23:24:10 +00:00
Federico Maccaroni
beda4e9ff8 PM-3350 Updated PCL Crypto to latest alpha version to fix "Dll not found NCrypt" issue 2023-11-14 18:43:23 -03:00
Federico Maccaroni
df4d89cd52 PM-3350 Fixed iOS Extensions navigation to several pages and improved avoiding duplicate calls to OnNavigatedTo 2023-11-14 13:43:59 -03:00
Federico Maccaroni
5f12bb9747 PM-3350 Fixed iOS Share extension lazy views loading and an issue with the avatar loading. Also discovered issue with TapGestureRecognizer not working on MAUI Embedding 2023-11-13 21:30:56 -03:00
Federico Maccaroni
5712639492 Merge branch 'feature/maui-migration' of https://github.com/bitwarden/mobile into feature/maui-migration 2023-11-13 14:44:24 -03:00
Federico Maccaroni
e0a3c301fb PM-3349 PM-3350 Changed SendViewCell and its binding to be directly against the ViewModel 2023-11-13 14:44:19 -03:00
Dinis Vieira
27306fe353 PM-3349 PM-3350 Added the partial MAUI Community Toolkit implementation for TouchEffect. This is a temporary solution until they finalize this and add it to their nuget package.
This allows implementing the LongPressCommand in AccountSwitchingOverlay and also have the "Ripple effect" animation when touching an item in Android
2023-11-13 09:59:54 +00:00
Dinis Vieira
a31f15559f PM-3350 Fix for colored html text on iOS 2023-11-11 15:05:51 +00:00
Dinis Vieira
0e75f3f5c8 PM-3349 Fix for HTML Label on Android. Color hex doesn't need to be cropped anymore. 2023-11-10 23:30:54 +00:00
Federico Maccaroni
363da063fa PM-3349 PM-3350 Changed AccountViewCell and its binding to be directly against the ViewModel 2023-11-10 17:30:08 -03:00
Federico Maccaroni
974a571455 PM-3349 PM-3350 Changed binding set for CipherViewCell so it updates accordingly 2023-11-10 14:41:41 -03:00
github-actions[bot]
96343eccf7 Autosync the updated translations (#2863)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-11-10 07:22:22 +00:00
Dinis Vieira
e0c721098c PM-3349 PM-3350 Migrated remaining AutomationProperties to SemanticProperties.
All 'IsInAccessibleTree="True"' were deleted.
'IsInAccessibleTree="False"' were kept and stayed in code.
2023-11-09 23:01:04 +00:00
Federico Maccaroni
a86f6e3034 PM-3350 Added configurations for Release mode (no FDroid yet) 2023-11-09 17:15:02 -03:00
Federico Maccaroni
fe17288b99 Merge branch 'feature/maui-migration' of https://github.com/bitwarden/mobile into feature/maui-migration 2023-11-09 16:16:26 -03:00
Federico Maccaroni
7324da9d47 PM-3350 Fixed iOS extensions (iOS.Extension and iOS.ShareExtension) to load and commented argon2id from debug configuration until we have the .a compiled again with the new platform/arch 2023-11-09 16:16:17 -03:00
André Bispo
793c5fef6f [PM-3273][PM-4679] New owner/admin permission on login (#2837)
* [PM-3273] Add property for password set. Add labels. Update sync service.

* [PM-3273] Set password needs set in state. Read value on sync and nav to page.

* [PM-3273] Add navigation to Set Password on vault landing if needed.

* [PM-3273] Update SetPasswordPage copy

* [PM-3273] Add ManageResetPassword to Org Permissions, handle it on sync.

* [PM-3273] Change user has master password state when set master password is complete.

* [PM-3273] Code clean up

* [PM-3273] Remove unnecessary property from account profile

* [PM-3273] Add check for remembered org identifier

* [PM-4679] Added logging calls for future checks.

---------

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
2023-11-09 17:21:00 +00:00
Vince Grassia
3a13ba4efa Update 'master' to 'main' (#2861) 2023-11-09 10:18:34 -05:00
Dinis Vieira
69aa6fc044 PM-3349 PM-3350 Started using OnNavigatedTo/From instead of On(Dis)Appearing for LoginPage and LoginSSOPage to avoid the "Modal loading" issues in iOS
Also had to add IsInitialized logic to these pages because OnNavigatedTo can be called twice in some scenario.
Some minor migrations of Device to DeviceInfo was also done
2023-11-09 15:09:37 +00:00
André Bispo
c5288d3921 [PM-891] Remove check for biometrics from IsLocked method. (#2853) 2023-11-07 16:46:31 +00:00
André Bispo
9506595fdd [PM-2671] Update mobile client to use regions (#2798)
* [PM-2671] Update mobile client to use regions

* [PM-2671] Refactor

* [PM-2671] Move migration of region to migration service.

* [PM-2671] Move comment

* [PM-2671] Change method name

* [PM-2671] Change method name on usages

---------

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
2023-11-07 12:15:32 +00:00
André Bispo
7a65bf7fd7 [PM-3340] Update timeout action for users without master password. (#2818)
* [PM-3340] Update timeout action for users without master password.

* [PM-3340] PR fixes and refactor

* [PM-3340] Raise command can execute.

* [PM-3340] Fix converter name

* [PM-3340] Fix variable naming

---------

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
2023-11-06 15:28:54 +00:00
github-actions[bot]
d0ce89fedb Autosync the updated translations (#2851)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-11-06 15:11:43 +00:00
Daniel James Smith
3c94ea4579 Assign CrowdinPRs to team-tools-dev (#2860)
Co-authored-by: Daniel James Smith <djsmith85@users.noreply.github.com>
2023-11-06 16:03:06 +01:00
Dinis Vieira
e840dc2e30 Merge branch 'master' into feature/maui-migration
Fixed conflicts and added null check on ForwardEmailDomainName

# Conflicts:
#	src/Core/Pages/Vault/CipherAddEditPage.xaml
#	src/Core/Pages/Vault/CipherDetailsPage.xaml
#	src/iOS.Core/Renderers/CollectionView/ExtendedGroupableItemsViewController.cs
2023-11-05 23:59:30 +00:00
Dinis Vieira
eb25ee5d1b PM-3349 Fix for Android buttons having all letters in Caps 2023-11-04 18:39:08 +00:00
Dinis Vieira
840f24dbe5 PM-3349 Fix for TabGestureRecognizer not working inside the StackLayout area of IconLabelButton 2023-11-04 18:08:44 +00:00
Dinis Vieira
c6309173ba PM-3349 PM-3350 Migrated IconLabelButton Frames to Borders to fix issue with TapGestureRecognizer in Android
Also fixed some minor "styles" for normal Button and IconLabelButton (both Android and iOS)
2023-11-04 17:48:59 +00:00
Dinis Vieira
946c465f0c PM-3349 Added Handler that enables the ExtendedDatePicker to get IsFocused events in Android. This is a workaround for fixing the current bug where it's not possible to select the "current day" in the expiration date of a Send.
Fix for TimePicker not displaying default Time Value
Updated some "Device" code to the new MAUI "DeviceInfo"
2023-11-02 02:32:12 +00:00
github-actions[bot]
658c1eaf64 Bumped version to 2023.10.1 (#2849)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-11-01 14:07:28 -04:00
github-actions[bot]
02b0265767 Bumped version to 2023.10.0 (#2847)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-10-31 11:07:07 -04:00
github-actions[bot]
bd2481b3e4 Autosync the updated translations (#2840)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-10-30 08:21:49 +00:00
Dinis Vieira
e90409d842 PM-3350 Added Scrollview on HomePage so that the "Create account" button can be accessed in smaller devices like iPhone SE. 2023-10-29 21:34:33 +00:00
Dinis Vieira
484b5a5160 PM-3349 PM-3350 Minor change to HomePage to set fixed Image height otherwise it takes more space than it did in the old Xamarin Forms app.
Added HIdeSoftInputOnTapped on several pages (the ones with Entry controls) to allow hiding the keyboard when tapping "outside" of it. (just like we did in Xamarin Forms app)
2023-10-28 19:02:54 +01:00
Jake Fink
12c72b2833 migrate old enc key (#2732) 2023-10-27 12:19:41 -04:00
Dinis Vieira
2688209752 PM-3350 Removed duplicate reference to LaunchScreen.storyboard 2023-10-27 17:19:20 +01:00
Dinis Vieira
53e0e55915 PM-3350 Quick workaround to allow 2nd factor auth to not get stuck in iOS in modals.
Updated some older "Device" code to the newer MAUI code.
2023-10-27 15:36:47 +01:00
Dinis Vieira
ca57948d9f PM-3350 Removed MAUI Splash Screen. Fixed iOS Privacy Screen logo (hardcoded image to avoid it getting cropped) 2023-10-27 11:41:21 +01:00
aj-rosado
2e5fb414b5 [PM-1835] Add ForwardEmail alias to Username Generator (#2803)
* Add ForwardEmail alias to Username Generator

* remove unnecessary initializer

* Corrected order of alias Generators

* PM-4307 - Trigger ForwardEmailDomainName PropertyChanged after initialization
2023-10-26 13:58:07 +01:00
Dinis Vieira
aaf082faba PM-3349 Fixed white tint color not appearing on images added as MAU IImage SVG
PM-3349 PM-3350 Fix for Avatar text not adjusting to white/black color correctly
2023-10-25 22:20:01 +01:00
Dinis Vieira
e7aeb08cae PM-3350 Checked some [MAUI-Migration] and changed as needed.
TimePickerHandlerMappings: Remove old code for forcing the Wheel. After testing without it wheel picker is still used so this code shouldn't be needed anymore.
AppDelegate.ContinueUserActivity: Uncommented and changed the iOS ContinueUserActivity. It needs to call Platform.ContinueUserActivity according with Xamarin Essentials migration docs.
2023-10-24 23:37:18 +01:00
Dinis Vieira
f177968958 Checked some [MAUI-Migration] and deleted when it's working as intended.
SearchBarHandlerMapping: IME options working as intended
SliderHandlerMappings: The MAUI "replacement" for Color.Default seems to be White so the old use case doesn't seem to be needed anymore.
2023-10-24 22:25:05 +01:00
Dinis Vieira
f1d59210f9 PM-3349 PRM-3350 Replaced XZing with Camera.MAUI for QRCodes 2023-10-23 15:17:14 +01:00
github-actions[bot]
4dda7a6634 Autosync the updated translations (#2836)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-10-23 09:51:53 +00:00
Dinis Vieira
62213c0aaf PM-3350 Added some missing images in iOS 2023-10-20 13:33:39 +01:00
github-actions[bot]
a1808f64b3 Autosync the updated translations (#2833)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-10-20 08:53:18 +00:00
Dinis Vieira
8be8abb8fe PM-3350 Migrated some Device to DeviceInfo and added temporary workaround with some comments to be able to see the Generated Password on iOS 2023-10-20 00:04:19 +01:00
Federico Maccaroni
142c3145f0 PM-4404 Added CreationDate to Fido2Credential objects and updated the UI bindings accordingly (#2832) 2023-10-19 17:46:26 -03:00
Dinis Vieira
174acbc558 PM-3349
Added Argon libraries for Android
minor change to gitignore so that the Argon x86 lib is not ignored on the Android platform
2023-10-18 15:41:20 +01:00
Dinis Vieira
4bcc7c0d71 Enabled argon2Id for iOS 2023-10-18 12:20:41 +01:00
Dinis Vieira
14b2960f30 PM-3350 Removed ButtonHandlerMappings and some other code related with fonts as MAUI is taking care of Accessibility and no custom code should be needed
Migrated SelectableLabelRenderer to Handler
Cleaned LabelHandlerMappings and added logic to migrate the CustomLabelRenderer
2023-10-18 01:21:19 +01:00
Dinis Vieira
455c3a257c PM-3350 Migrated the CustomViewCellRenderer for iOS 2023-10-17 22:23:04 +01:00
Federico Maccaroni
72de17bd1d PM-4314 Removed move passkey to organization duplicate check (#2828) 2023-10-17 12:36:54 -03:00
Dinis Vieira
8c623a2067 PM-3349 ToolbarHandler created for setting text on Android go back buttons. 2023-10-16 20:45:58 +01:00
Dinis Vieira
3cdf1c2f0e PM-3349 Replaced the FabShadowEffect with the new MAUI Shadow to fix the buggy shadows on the Android Fab Button. 2023-10-16 00:47:52 +01:00
Dinis Vieira
ce9503fa0c PM-3349 PM-3350
Added (migrated) CustomNavigationHandler (which should partially fix the AvatarIcon in the NavBar in iOS)
Added (migrated) CustomContentPageHandler (which should mostly place the AvatarIcon in the navBar in the correct place for iOS)
Added Task.Delay (workaround) to allow the Avatar to load in iOS on the LoginPage
Added workaround for iOS bug with the toolbar size (more info in comment in AvatarImageSource.cs)
Went through the AccountViewCell MAUI-Migration comments. (and deleted/added more comments as needed)
Migrated some Device calls to DeviceInfo and MainThread
Added (migrated) CustomTabbedHandler (for managing the iOS TabBar)
2023-10-15 22:06:26 +01:00
André Bispo
ed3467515e [PM-3531] Add missing automation ids. (#2814) 2023-10-14 00:39:57 +01:00
Dinis Vieira
2e4da1b87d hardcoded AccountViewCell Avatar image to 40x40 to avoid current iOS/Android bugs where they fill much larger space. 2023-10-13 18:49:30 +01:00
Jake Fink
21fc56457d fix isLocked logic and add comments (#2802) 2023-10-13 13:41:52 -04:00
ifernandezdiaz
bc2eb212a6 Adding missing ids (#2823)
* Adding missing ids

* Fixing repeated IDs
2023-10-13 12:12:47 -03:00
André Bispo
a1912526c2 [PM-3532] Code clean up. DeviceType delete. (#2762) 2023-10-13 14:51:19 +01:00
github-actions[bot]
9d0209751c Autosync the updated translations (#2822)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-10-13 08:19:14 +00:00
Federico Maccaroni
f2936c95fa [PM-4054] Rename Fido2Key to Fido2Credential (#2821)
* PM-4054 Renamed Fido2Key to Fido2Credential on the entire codebase

* PM-4054 Renamed file Fido2KeyApi to Fido2CredentialApi
2023-10-12 16:51:19 -03:00
mpbw2
bb2f1f0f5f [PM-3741] [PM-3750] Improvements to local storage handling (#2795)
* [PM-3741] [PM-3750] Improvements to local storage handling

* Update src/Android/MainActivity.cs

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>

---------

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
2023-10-12 08:58:11 -04:00
github-actions[bot]
5a0c2115a1 Bumped version to 2023.9.3 (#2820)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-10-11 15:42:03 -07:00
aj-rosado
a67f50b145 Added CultureInfo in char.ToLower at GetServiceRegistrationName method (#2810) 2023-10-10 16:22:39 +01:00
Dinis Vieira
d63a219272 PM-3349 Implemented HybridWebViewHandler for iOS 2023-10-07 23:44:24 +01:00
Dinis Vieira
c92cd90a97 PM-3349 Implemented HybridWebViewHandler for Android which enables 2nd factor auth flows
Ensured CustomTabbedPageHandler had it's DisconnectHandler called
Some minor code upgrades of older obsolete Xamarin Forms code.
2023-10-07 17:25:29 +01:00
Dinis Vieira
1dcd3a3daa PM-3349 Changed UseMauiApp init so that Android Handlers still get added 2023-10-07 16:56:08 +01:00
github-actions[bot]
757e5ea647 Autosync the updated translations (#2805)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-10-06 07:46:57 +00:00
Federico Maccaroni
efb8763d3c Merge branch 'feature/maui-migration' of https://github.com/bitwarden/mobile into feature/maui-migration 2023-10-04 12:45:08 -03:00
Federico Maccaroni
90649d1c8b PM-3350 MAUI Migration Fix iOS Autofill extension 2023-10-04 12:35:43 -03:00
André Bispo
b23f29511c [PM-868] Re-open app to item could crash the app (#2813)
* [PM-868] Check for previous page before loading vault. Remove exception throw.

* [PM-868] Continue to throw exceptions
2023-10-04 15:48:04 +01:00
Federico Maccaroni
71731bb9b7 PM-2658 Removed deprecated strings resources. (#2812) 2023-10-03 15:40:55 -03:00
aj-rosado
f2be840a7d Added GetOrDeriveMasterKey to UserVerificationService (#2808) 2023-10-03 12:54:22 +01:00
Dinis Vieira
828055791f PM-3349 Removed Deploy from iOS.Autofill to allow running Android
Changed MainApplication SpecialFolder.Personal to SpecialFolder.LocalApplicationData
2023-10-02 21:15:33 +01:00
André Bispo
685e0f407a [PM-2915] Fix config service null exception error bug (#2778) 2023-10-02 20:43:42 +01:00
Dinis Vieira
87eebda55f Changes to solution to hopefully fix Config Mappings 2023-10-02 16:40:31 +01:00
Dinis Vieira
7542d1ae1c fix conflicts 2023-10-02 16:08:09 +01:00
Federico Maccaroni
990de4ea4e PM-3349 PM-3350 MAUI Migration Start iOS extensions 2023-10-02 12:05:57 -03:00
Dinis Vieira
0dbc23f734 PM-3349 PM-3350 Add null checks on CipherDetailsPageVM to avoid crash opening Secure Notes. 2023-10-01 23:15:55 +01:00
Dinis Vieira
9f6c8601d3 TabBarEffect removed and it's behavior is now taken care of by CustomTabbedPageHandler 2023-10-01 22:32:37 +01:00
Dinis Vieira
8b7f9b9fb3 PM-3349: Android
Added CustomTabbedPageHandler for Android to handle the tab "reselection" for PopToRoot.
Commented support for Windows in App.csproj
Disabled Interpreter on Android to avoid very slow app in Debug (during Login for example)
Added some null checks that were causing crashes (on GeneratorPageVM and PickerVM)
Minor TabsPage cleanup
2023-10-01 15:35:04 +01:00
Federico Maccaroni
d17789d5ee PM-3349 PM-3350 MAUI Migration fix nullable bindings and fallbacks 2023-09-29 12:27:12 -03:00
Federico Maccaroni
b8f0747dd4 PM-3349 PM-3350 MAUI Migration fix nullable exception bindings and AsyncCommand canExecute null exception 2023-09-29 12:12:01 -03:00
Federico Maccaroni
8ef9443b1e PM-3349 PM-3350 MAUI Migration Initial 2023-09-29 11:02:19 -03:00
Federico Maccaroni
bbef0f8c93 PM-4138 Remove hyphen from clip-board => clipboard on resources. (#2804) 2023-09-28 12:55:18 -04:00
Federico Maccaroni
3cdf5ccd3b [PM-115] Cipher key encryption update (#2421)
* PM-115 Added new cipher key and encryption/decryption mechanisms on cipher

* PM-115 fix format

* PM-115 removed ForceKeyRotation from new cipher encryption model given that another approach will be taken

* [PM-1690] Added minimum server version restriction to cipher key encryption (#2463)

* PM-1690 added minimum server version restriction to cipher key encryption and also change the force key rotation flag

* PM-1690 Updated min server version for new cipher encryption key and fixed configService registration

* PM-1690 removed forcekeyrotation

* PM-115 Temporarily Changed cipher key new encryption config to help testing (this change should be reseted eventually)

* PM-2456 Fix attachment encryption on new cipher item encryption model (#2556)

* PM-2531 Fix new cipher encryption on adding attachments on ciphers with no item level key (#2559)

* PM-115 Changed temporarily cipher key encryption min server version to 2023.6.0 to test

* PM-115 Reseted cipher key encryption minimum server version to 2023.5.0 and disable new cipher key on local cipher creation

* Added Key value to the cipher export model (#2628)

* Update Constants.cs

Updated minimum encryption server version to 2023.9.0 so QA can test its behavior

* PM-115 Fix file format

* PM-115 Changed new encryption off and minimum new encryption server version to 2023.8.0 for testing purposes

* PM-115 Changed CIpher key encryption minimum server version to 2023.9.0

* PM-3737 Remove suffix on client version sent to server (#2779)

* PM-115 QA testing server min version and enable new cipher key encryption

* PM-115 Disable new cipher encryption creation and change minimum server encryption version to 2023.9.1

---------

Co-authored-by: aj-rosado <109146700+aj-rosado@users.noreply.github.com>
2023-09-28 10:00:20 -03:00
Federico Maccaroni
e97a37222a [PM-2658] Settings Reorganization feature (#2702)
* [PM-2658] Settings Reorganization Init (#2697)

* PM-2658 Started settings reorganization (settings main + vault + about)

* PM-2658 Added settings controls based on templates and implemented OtherSettingsPage

* PM-2658 Fix format

* [PM-3512] Settings Appearance (#2703)

* PM-3512 Implemented new Appearance Settings

* PM-3512 Fix format

* [PM-3510] Implement Account Security Settings view (#2714)

* PM-3510 Implemented Security settings view

* PM-3510 Fix format

* PM-3510 Added empty placeholder to pending login requests and also improved a11y on security settings view.

* PM-3511 Implemented autofill settings view (#2735)

* [PM-3695] Add Connect to Watch to Other settings (#2736)

* PM-3511 Implemented autofill settings view

* PM-3695 Add Connect to watch setting to other settings view

* [PM-3693] Clear old Settings approach (#2737)

* PM-3511 Implemented autofill settings view

* PM-3693 Remove old Settings approach

* PM-3845 Fix default dark theme description verbiage (#2759)

* PM-3839 Fix allow screen capture and submit crash logs to init their state when the page appears (#2760)

* PM-3834 Fix dialogs strings on settings (#2758)

* [PM-3834] Fix import items link (#2782)

* PM-3834 Fix import items link

* PM-3834 Fix import items link, removed old link.

* [PM-4092] Fix vault timeout policies on new Settings (#2796)

* PM-4092 Fix vault timeout policy on settings for disabling controls and reset timeout when surpassing maximum

* PM-4092 Removed testing hardcoding of policy data
2023-09-27 16:26:12 -03:00
André Bispo
218a30b510 [PM-3446] User without MP, item with MP does not show on Android keyboard for autofill (#2764)
* [PM-3446] Check if user has mp and allow autofill to use items with mp re-prompt
2023-09-26 17:25:47 +01:00
github-actions[bot]
828043ec97 Bumped version to 2023.9.2 (#2797)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-09-26 11:05:07 -04:00
André Bispo
b25c8b0842 [PM-3893] Make PreLogin and Register endpoint use identity endpoints (#2772) 2023-09-25 16:28:58 +01:00
Federico Maccaroni
a4a0d31fc6 [PM-3811] Passkeys unification (#2774)
* PM-3811 Unified passkeys view and moved both inside Login as an array of FIdo2Key

* PM-3811 Passkeys unification => updated cipher details view an helpers

* PM-3811 Updated passkeys creation date time format
2023-09-22 14:55:35 +00:00
ifernandezdiaz
6ef6cf5d84 Adding missing IDs (#2786) 2023-09-22 11:24:30 -03:00
github-actions[bot]
597f629920 Autosync the updated translations (#2785)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-09-22 08:04:57 +00:00
github-actions[bot]
b8cef16711 Bumped version to 2023.9.1 (#2784)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-09-20 18:36:32 -04:00
Jake Fink
c4f6ae9077 [PM-3726] prevent legacy user login (#2769)
* [PM-3726] prevent legacy user login

* [PM-3726] prevent unlock or auto key migration if legacy user

* [PM-3726] add legacy checks to lock page and refactor

* [PM-3726] rethrow exception from pin

* formatting

* [PM-3726] add changes to LockViewController, consolidate logout calls

* formatting

* [PM-3726] pr feedback

* generate resx

* formatting
2023-09-20 15:56:51 -04:00
github-actions[bot]
8b9658d2c5 Bumped version to 2023.9.0 (#2783)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-09-20 12:34:30 -04:00
André Bispo
43bf0fbdb3 [PM-3086] Account switcher endpoint use domain string for Bitwarden production environments (#2773) 2023-09-19 10:35:37 +01:00
André Bispo
11922c6f49 [PM-3522] Keep variable value after logout. (#2761) 2023-09-19 10:33:01 +01:00
André Bispo
a6f05338c2 [PM-3393] Excessive Invalid Biometric unlock attempts should automatically log out TDE users (#2747)
* [PM-3393] Log user out on biometric exceed attempts

* [PM-3393] Move duplicated code to AppHelpers

* [PM-3393] Update copy on new pop up

* [PM-3393] Moved VaultTimeoutService to LazyResolve.

* [PM-3382] Change IVaultTimeoutService for messaging

* [PM-3393] Use default values.
2023-09-19 10:32:23 +01:00
Federico Maccaroni
b932824b5a Make dept-development-mobile default code owner (#2780) 2023-09-18 18:23:16 -03:00
github-actions[bot]
efd1671f48 Autosync the updated translations (#2771)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2023-09-14 14:14:00 +00:00
1048 changed files with 32863 additions and 16358 deletions

31
.github/CODEOWNERS vendored
View File

@@ -1,10 +1,21 @@
# Please sort lines alphabetically, this will ensure we don't accidentally add duplicates.
# Please sort into logical groups with comment headers. Sort groups in order of specificity.
# For example, default owners should always be the first group.
# Sort lines alphabetically within these groups to avoid accidentally adding duplicates.
#
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
# The following owners will be the default owners for everything in the repo.
# Unless a later match takes precedence
# @bitwarden/tech-leads
# Default file owners
* @bitwarden/dept-development-mobile
# DevOps for Actions and other workflow changes
.github/workflows @bitwarden/dept-devops
# DevOps for Version Bumping
src/App/Platforms/Android/AndroidManifest.xml
src/iOS.Autofill/Info.plist
src/iOS.Extension/Info.plist
src/iOS.ShareExtension/Info.plist
src/App/Platforms/iOS/Info.plist
## Auth team files ##
@@ -18,12 +29,18 @@ src/watchOS @bitwarden/team-vault-dev
## Tools team files ##
src/Core/Services/EmailForwarders @bitwarden/team-tools-dev
## Crowdin Sync files ##
src/App/Resources @bitwarden/tech-leads
src/watchOS/bitwarden/bitwarden\ WatchKit\ Extension/Localization @bitwarden/tech-leads
src/App/Resources @bitwarden/team-tools-dev
src/watchOS/bitwarden/bitwarden\ WatchKit\ Extension/Localization @bitwarden/team-tools-dev
store/apple @bitwarden/team-tools-dev
store/google @bitwarden/team-tools-dev
## Locales ##
src/App/Resources/AppResources.Designer.cs
src/App/Resources/AppResources.resx
src/watchOS/bitwarden/bitwarden\ WatchKit\ Extension/Localization/en.lproj
store/apple/en
store/google/en
## Utils ##
store/google/Publisher

17
.github/renovate.json vendored
View File

@@ -2,22 +2,21 @@
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base",
"github>bitwarden/renovate-config:pin-actions",
":combinePatchMinorReleases",
":dependencyDashboard",
":maintainLockFilesWeekly",
":pinAllExceptPeerDependencies",
":prConcurrentLimit10",
":rebaseStalePrs",
"schedule:weekends",
":separateMajorReleases"
":separateMajorReleases",
"group:monorepos",
"schedule:weekends"
],
"enabledManagers": ["cargo", "github-actions", "npm", "nuget"],
"enabledManagers": ["github-actions", "npm", "nuget"],
"commitMessagePrefix": "[deps]:",
"commitMessageTopic": "{{depName}}",
"packageRules": [
{
"groupName": "cargo minor",
"matchManagers": ["cargo"],
"matchUpdateTypes": ["minor", "patch"]
},
{
"groupName": "gh minor",
"matchManagers": ["github-actions"],
@@ -32,6 +31,6 @@
"groupName": "nuget minor",
"matchManagers": ["nuget"],
"matchUpdateTypes": ["minor", "patch"]
},
}
]
}

View File

@@ -9,15 +9,19 @@ on:
paths-ignore:
- ".github/workflows/**"
workflow_dispatch:
inputs: {}
env:
main_app_folder_path: src/App
main_app_project_path: src/App/App.csproj
target-net-version: net8.0
jobs:
cloc:
name: CLOC
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- name: Checkout repo
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Set up CLOC
run: |
@@ -27,16 +31,15 @@ jobs:
- name: Print lines of code
run: cloc --vcs git --exclude-dir Resources,store,test,Properties --include-lang C#,XAML
setup:
name: Setup
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
outputs:
rc_branch_exists: ${{ steps.branch-check.outputs.rc_branch_exists }}
hotfix_branch_exists: ${{ steps.branch-check.outputs.hotfix_branch_exists }}
steps:
- name: Checkout repo
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
submodules: 'true'
@@ -54,8 +57,6 @@ jobs:
else
echo "hotfix_branch_exists=0" >> $GITHUB_OUTPUT
fi
shell: bash
android:
name: Android
@@ -65,42 +66,36 @@ jobs:
fail-fast: false
matrix:
variant: ["prod", "qa"]
env:
android_folder_path: src/App/Platforms/Android
steps:
- name: Setup NuGet
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
with:
nuget-version: 5.9.0
nuget-version: 6.4.0
- name: Set up .NET
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0
uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.0
with:
dotnet-version: '3.1.x'
dotnet-version: '8.0.x'
- name: Set up MSBuild
uses: microsoft/setup-msbuild@1ff57057b5cfdc39105cd07a01d78e9b0ea0c14c # v1.3.1
uses: microsoft/setup-msbuild@ede762b26a2de8d110bb5a3db4d7e0e080c0e917 # v1.3.3
# 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
- name: Work Around for broken Windows 2022 Runner Image
- name: Install Microsoft OpenJDK 11
run: |
Set-Location "C:\Program Files (x86)\Microsoft Visual Studio\Installer\"
$InstallPath = "C:\Program Files\Microsoft Visual Studio\2022\Enterprise"
$componentsToAdd = @(
"Component.Xamarin"
)
[string]$workloadArgs = $componentsToAdd | ForEach-Object {" --add " + $_}
$Arguments = ('/c', "vs_installer.exe", 'modify', '--installPath', "`"$InstallPath`"",$workloadArgs, '--quiet', '--norestart', '--nocache')
$process = Start-Process -FilePath cmd.exe -ArgumentList $Arguments -Wait -PassThru -WindowStyle Hidden
if ($process.ExitCode -eq 0)
{
Write-Host "components have been successfully added"
}
else
{
Write-Host "components were not installed"
exit 1
}
choco install microsoft-openjdk11 --no-progress
Write-Output "JAVA_HOME=$(Get-ChildItem -Path 'C:\Program Files\Microsoft\jdk*' | Select -First 1 -ExpandProperty FullName)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
Write-Output "Java Home: $env:JAVA_HOME"
- name: Print environment
run: |
nuget help | grep Version
@@ -110,9 +105,10 @@ jobs:
echo "GitHub event: $GITHUB_EVENT"
- name: Checkout repo
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
fetch-depth: 0
- name: Decrypt secrets
env:
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
@@ -120,20 +116,22 @@ jobs:
mkdir -p ~/secrets
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--output ./src/Android/app_play-keystore.jks ./.github/secrets/app_play-keystore.jks.gpg
--output ./${{ env.main_app_folder_path }}/app_play-keystore.jks ./.github/secrets/app_play-keystore.jks.gpg
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--output ./src/Android/app_upload-keystore.jks ./.github/secrets/app_upload-keystore.jks.gpg
--output ./${{ env.main_app_folder_path }}/app_upload-keystore.jks ./.github/secrets/app_upload-keystore.jks.gpg
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--output $HOME/secrets/play_creds.json ./.github/secrets/play_creds.json.gpg
shell: bash
- name: Decrypt secrets - Google Services
if: ${{ matrix.variant == 'prod' }}
env:
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
run: |
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--output ./src/Android/google-services.json ./.github/secrets/google-services.json.gpg
--output ./${{ env.android_folder_path }}/google-services.json ./.github/secrets/google-services.json.gpg
shell: bash
- name: Increment version
run: |
BUILD_NUMBER=$((3000 + $GITHUB_RUN_NUMBER))
@@ -141,9 +139,9 @@ jobs:
echo "########################################"
echo "##### Setting Version Code $BUILD_NUMBER"
echo "########################################"
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \
./src/Android/Properties/AndroidManifest.xml
./${{ env.android_folder_path }}/AndroidManifest.xml
shell: bash
- name: Restore packages
@@ -151,18 +149,15 @@ jobs:
- name: Restore tools
run: dotnet tool restore
shell: pwsh
- name: Verify Format
run: dotnet tool run dotnet-format --check
shell: pwsh
# - name: Verify Format
# run: dotnet tool run dotnet-format --check
- name: Run Core tests
run: dotnet test test/Core.Test/Core.Test.csproj --logger "trx;LogFileName=test-results.trx"
shell: pwsh
run: dotnet test test/Core.Test/Core.Test.csproj --logger "trx;LogFileName=test-results.trx" /p:CustomConstants=UT
- name: Report test results
uses: dorny/test-reporter@c9b3d0e2bd2a4e96aaf424dbaa31c46b42318226 # v1.6.0
uses: dorny/test-reporter@eaa763f6ffc21c7a37837f56cd5f9737f27fc6c8 # v1.8.0
if: always()
with:
name: Test Results
@@ -180,20 +175,20 @@ jobs:
- name: Build Android
run: |
$configuration = "Release";
$projToBuild = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}");
Write-Output "########################################"
Write-Output "##### Build $configuration Configuration"
Write-Output "########################################"
msbuild "$($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj")" "/p:Configuration=$configuration"
shell: pwsh
dotnet build $projToBuild -c $configuration -f ${{ env.target-net-version }}-android
- name: Sign Android Build
env:
PLAY_KEYSTORE_PASSWORD: ${{ secrets.PLAY_KEYSTORE_PASSWORD }}
UPLOAD_KEYSTORE_PASSWORD: ${{ secrets.UPLOAD_KEYSTORE_PASSWORD }}
run: |
$androidPath = $($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj");
$projToBuild = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}");
$packageName = "com.x8bit.bitwarden";
if ("${{ matrix.variant }}" -ne "prod")
@@ -204,16 +199,13 @@ jobs:
Write-Output "##### Sign Google Play Bundle Release Configuration"
Write-Output "########################################"
msbuild "$($androidPath)" "/t:SignAndroidPackage" "/p:Configuration=Release" "/p:AndroidKeyStore=true" `
"/p:AndroidSigningKeyAlias=upload" "/p:AndroidSigningKeyPass=$($env:UPLOAD_KEYSTORE_PASSWORD)" `
"/p:AndroidSigningKeyStore=$("app_upload-keystore.jks")" `
"/p:AndroidSigningStorePass=$($env:UPLOAD_KEYSTORE_PASSWORD)" "/p:AndroidPackageFormat=aab" "/v:quiet"
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android /p:AndroidPackageFormats=aab /p:AndroidKeyStore=true /p:AndroidSigningKeyStore=$("app_upload-keystore.jks") /p:AndroidSigningKeyAlias=upload /p:AndroidSigningKeyPass="$($env:UPLOAD_KEYSTORE_PASSWORD)" /p:AndroidSigningStorePass="$($env:UPLOAD_KEYSTORE_PASSWORD)" --no-restore
Write-Output "########################################"
Write-Output "##### Copy Google Play Bundle to project root"
Write-Output "########################################"
$signedAabPath = $($env:GITHUB_WORKSPACE + "/src/Android/bin/Release/$($packageName)-Signed.aab");
$signedAabPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_folder_path }}/bin/Release/${{ env.target-net-version }}-android/publish/$($packageName)-Signed.aab");
$signedAabDestPath = $($env:GITHUB_WORKSPACE + "/$($packageName).aab");
Copy-Item $signedAabPath $signedAabDestPath
@@ -221,23 +213,20 @@ jobs:
Write-Output "##### Sign APK Release Configuration"
Write-Output "########################################"
msbuild "$($androidPath)" "/t:SignAndroidPackage" "/p:Configuration=Release" "/p:AndroidKeyStore=true" `
"/p:AndroidSigningKeyAlias=bitwarden" "/p:AndroidSigningKeyPass=$($env:PLAY_KEYSTORE_PASSWORD)" `
"/p:AndroidSigningKeyStore=$("app_play-keystore.jks")" `
"/p:AndroidSigningStorePass=$($env:PLAY_KEYSTORE_PASSWORD)" "/v:quiet"
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android /p:AndroidKeyStore=true /p:AndroidSigningKeyStore=$("app_play-keystore.jks") /p:AndroidSigningKeyAlias=bitwarden /p:AndroidSigningKeyPass="$($env:PLAY_KEYSTORE_PASSWORD)" /p:AndroidSigningStorePass="$($env:PLAY_KEYSTORE_PASSWORD)" --no-restore
Write-Output "########################################"
Write-Output "##### Copy Release APK to project root"
Write-Output "########################################"
$signedApkPath = $($env:GITHUB_WORKSPACE + "/src/Android/bin/Release/$($packageName)-Signed.apk");
$signedApkPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_folder_path }}/bin/Release/${{ env.target-net-version }}-android/publish/$($packageName)-Signed.apk");
$signedApkDestPath = $($env:GITHUB_WORKSPACE + "/$($packageName).apk");
Copy-Item $signedApkPath $signedApkDestPath
shell: pwsh
- name: Upload Prod .aab artifact
if: ${{ matrix.variant == 'prod' }}
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: com.x8bit.bitwarden.aab
path: ./com.x8bit.bitwarden.aab
@@ -245,7 +234,7 @@ jobs:
- name: Upload Prod .apk artifact
if: ${{ matrix.variant == 'prod' }}
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: com.x8bit.bitwarden.apk
path: ./com.x8bit.bitwarden.apk
@@ -253,7 +242,7 @@ jobs:
- name: Upload Other .apk artifact
if: ${{ matrix.variant != 'prod' }}
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: com.x8bit.bitwarden.${{ matrix.variant }}.apk
path: ./com.x8bit.bitwarden.${{ matrix.variant }}.apk
@@ -273,7 +262,7 @@ jobs:
- name: Upload .apk sha file for prod
if: ${{ matrix.variant == 'prod' }}
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: bw-android-apk-sha256.txt
path: ./bw-android-apk-sha256.txt
@@ -281,20 +270,20 @@ jobs:
- name: Upload .apk sha file for other
if: ${{ matrix.variant != 'prod' }}
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: bw-android-${{ matrix.variant }}-apk-sha256.txt
path: ./bw-android-${{ matrix.variant }}-apk-sha256.txt
if-no-files-found: error
- name: Deploy to Play Store
if: ${{ matrix.variant == 'prod' && (( github.ref == 'refs/heads/master'
if: ${{ matrix.variant == 'prod' && (( github.ref == 'refs/heads/main'
&& needs.setup.outputs.rc_branch_exists == 0
&& needs.setup.outputs.hotfix_branch_exists == 0)
|| (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0)
|| github.ref == 'refs/heads/hotfix-rc' ) }}
run: |
PUBLISHER_PATH="$GITHUB_WORKSPACE/store/google/Publisher/bin/Release/netcoreapp3.1/Publisher.dll"
PUBLISHER_PATH="$GITHUB_WORKSPACE/store/google/Publisher/bin/Release/net7.0/Publisher.dll"
CREDS_PATH="$HOME/secrets/play_creds.json"
AAB_PATH="$GITHUB_WORKSPACE/com.x8bit.bitwarden.aab"
TRACK="internal"
@@ -306,37 +295,36 @@ jobs:
f-droid:
name: F-Droid Build
runs-on: windows-2022
env:
android_folder_path: src/App/Platforms/Android
android_manifest_path: src/App/Platforms/Android/AndroidManifest.xml
steps:
- name: Setup NuGet
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
with:
nuget-version: 5.9.0
nuget-version: 6.4.0
- name: Set up .NET
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0
with:
dotnet-version: '8.0.x'
- name: Set up MSBuild
uses: microsoft/setup-msbuild@1ff57057b5cfdc39105cd07a01d78e9b0ea0c14c # v1.3.1
uses: microsoft/setup-msbuild@ede762b26a2de8d110bb5a3db4d7e0e080c0e917 # v1.3.3
# 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
- name: Work Around for broken Windows 2022 Runner Image
- name: Install Microsoft OpenJDK 11
run: |
Set-Location "C:\Program Files (x86)\Microsoft Visual Studio\Installer\"
$InstallPath = "C:\Program Files\Microsoft Visual Studio\2022\Enterprise"
$componentsToAdd = @(
"Component.Xamarin"
)
[string]$workloadArgs = $componentsToAdd | ForEach-Object {" --add " + $_}
$Arguments = ('/c', "vs_installer.exe", 'modify', '--installPath', "`"$InstallPath`"",$workloadArgs, '--quiet', '--norestart', '--nocache')
$process = Start-Process -FilePath cmd.exe -ArgumentList $Arguments -Wait -PassThru -WindowStyle Hidden
if ($process.ExitCode -eq 0)
{
Write-Host "components have been successfully added"
}
else
{
Write-Host "components were not installed"
exit 1
}
choco install microsoft-openjdk11 --no-progress
Write-Output "JAVA_HOME=$(Get-ChildItem -Path 'C:\Program Files\Microsoft\jdk*' | Select -First 1 -ExpandProperty FullName)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
Write-Output "Java Home: $env:JAVA_HOME"
- name: Print environment
run: |
@@ -347,7 +335,7 @@ jobs:
echo "GitHub event: $GITHUB_EVENT"
- name: Checkout repo
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Decrypt secrets
env:
@@ -356,7 +344,7 @@ jobs:
mkdir -p ~/secrets
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--output ./src/Android/app_fdroid-keystore.jks ./.github/secrets/app_fdroid-keystore.jks.gpg
--output ./${{ env.main_app_folder_path }}/app_fdroid-keystore.jks ./.github/secrets/app_fdroid-keystore.jks.gpg
shell: bash
- name: Increment version
@@ -368,30 +356,21 @@ jobs:
echo "########################################"
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \
./src/Android/Properties/AndroidManifest.xml
./${{ env.android_manifest_path }}
shell: bash
- name: Clean for F-Droid
run: |
$androidPath = $($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj");
$appPath = $($env:GITHUB_WORKSPACE + "/src/App/App.csproj");
$appPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}");
$corePath = $($env:GITHUB_WORKSPACE + "/src/Core/Core.csproj");
$androidManifest = $($env:GITHUB_WORKSPACE + "/src/Android/Properties/AndroidManifest.xml");
Write-Output "########################################"
Write-Output "##### Clean Android and App"
Write-Output "########################################"
msbuild "$($androidPath)" "/t:Clean" "/p:Configuration=FDroid"
msbuild "$($appPath)" "/t:Clean" "/p:Configuration=FDroid"
$androidManifest = $($env:GITHUB_WORKSPACE + "/${{ env.android_manifest_path }}");
Write-Output "########################################"
Write-Output "##### Backup project files"
Write-Output "########################################"
Copy-Item $androidManifest $($androidManifest + ".original");
Copy-Item $androidPath $($androidPath + ".original");
Copy-Item $appPath $($appPath + ".original");
Write-Output "########################################"
@@ -406,83 +385,44 @@ jobs:
$xml.Save($androidManifest);
Write-Output "########################################"
Write-Output "##### Uninstall from Android.csproj"
Write-Output "########################################"
$xml=New-Object XML;
$xml.Load($androidPath);
$ns=New-Object System.Xml.XmlNamespaceManager($xml.NameTable);
$ns.AddNamespace("ns", $xml.DocumentElement.NamespaceURI);
$firebaseNode=$xml.SelectSingleNode(`
"/ns:Project/ns:ItemGroup/ns:PackageReference[@Include='Xamarin.Firebase.Messaging']", $ns);
$firebaseNode.ParentNode.RemoveChild($firebaseNode);
$daggerNode=$xml.SelectSingleNode(`
"/ns:Project/ns:ItemGroup/ns:PackageReference[@Include='Xamarin.Google.Dagger']", $ns);
$daggerNode.ParentNode.RemoveChild($daggerNode);
$safetyNetNode=$xml.SelectSingleNode(`
"/ns:Project/ns:ItemGroup/ns:PackageReference[@Include='Xamarin.GooglePlayServices.SafetyNet']", $ns);
$safetyNetNode.ParentNode.RemoveChild($safetyNetNode);
$xml.Save($androidPath);
Write-Output "########################################"
Write-Output "##### Uninstall from Core.csproj"
Write-Output "########################################"
$xml=New-Object XML;
$xml.Load($corePath);
$appCenterNode=$xml.SelectSingleNode("/Project/ItemGroup/PackageReference[@Include='Microsoft.AppCenter.Crashes']");
$appCenterNode.ParentNode.RemoveChild($appCenterNode);
$xml.Save($corePath);
shell: pwsh
- name: Restore packages
run: nuget restore
run: dotnet restore
- name: Build for F-Droid
run: |
$configuration = "FDroid";
$configuration = "Release";
$projToBuild = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}");
Write-Output "########################################"
Write-Output "##### Build $configuration Configuration"
Write-Output "##### Build $configuration FDROID
Write-Output "########################################"
msbuild "$($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj")" "/p:Configuration=$configuration"
shell: pwsh
dotnet build $projToBuild -c $configuration -f ${{ env.target-net-version }}-android /p:CustomConstants="FDROID"
- name: Sign for F-Droid
env:
FDROID_KEYSTORE_PASSWORD: ${{ secrets.FDROID_KEYSTORE_PASSWORD }}
run: |
$projToBuild = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}");
$packageName = "com.x8bit.bitwarden";
Write-Output "########################################"
Write-Output "##### Sign FDroid Configuration"
Write-Output "##### Sign FDroid"
Write-Output "########################################"
msbuild "$($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj")" `
"/t:SignAndroidPackage" "/p:Configuration=FDroid" "/p:AndroidKeyStore=true" `
"/p:AndroidSigningKeyAlias=bitwarden" "/p:AndroidSigningKeyPass=$($env:FDROID_KEYSTORE_PASSWORD)" `
"/p:AndroidSigningKeyStore=$("app_fdroid-keystore.jks")" `
"/p:AndroidSigningStorePass=$($env:FDROID_KEYSTORE_PASSWORD)" "/v:quiet"
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android /p:AndroidKeyStore=true /p:AndroidSigningKeyStore=$("app_fdroid-keystore.jks") /p:AndroidSigningKeyAlias=bitwarden /p:AndroidSigningKeyPass="$($env:FDROID_KEYSTORE_PASSWORD)" /p:AndroidSigningStorePass="$($env:FDROID_KEYSTORE_PASSWORD)" /p:CustomConstants="FDROID" --no-restore
Write-Output "########################################"
Write-Output "##### Copy FDroid apk to project root"
Write-Output "########################################"
$signedApkPath = $($env:GITHUB_WORKSPACE + "/src/Android/bin/FDroid/com.x8bit.bitwarden-Signed.apk");
$signedApkPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_folder_path }}/bin/Release/${{ env.target-net-version }}-android/publish/$($packageName)-Signed.apk");
$signedApkDestPath = $($env:GITHUB_WORKSPACE + "/com.x8bit.bitwarden-fdroid.apk");
Copy-Item $signedApkPath $signedApkDestPath
shell: pwsh
- name: Upload F-Droid .apk artifact
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: com.x8bit.bitwarden-fdroid.apk
path: ./com.x8bit.bitwarden-fdroid.apk
@@ -494,54 +434,64 @@ jobs:
-t sha256 | Out-File -Encoding ASCII ./bw-fdroid-apk-sha256.txt
- name: Upload F-Droid sha file
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: bw-fdroid-apk-sha256.txt
path: ./bw-fdroid-apk-sha256.txt
if-no-files-found: error
ios:
name: Apple iOS
runs-on: macos-12
runs-on: macos-13
needs: setup
env:
ios_folder_path: src/App/Platforms/iOS
app_output_name: App
app_ci_output_filename: App_x64_Debug
steps:
- name: Set XCode version
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
with:
xcode-version: 15.1
- name: Setup NuGet
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
with:
nuget-version: 5.9.0
nuget-version: 6.4.0
- name: Set up .NET
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0
with:
dotnet-version: '8.0.x'
# 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: Print environment
run: |
nuget help | grep Version
msbuild -version
dotnet --info
echo "GitHub ref: $GITHUB_REF"
echo "GitHub event: $GITHUB_EVENT"
- name: Checkout repo
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
submodules: 'true'
- name: Login to Azure - CI Subscription
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.6
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
- name: Retrieve secrets
id: retrieve-secrets
env:
KEYVAULT: bitwarden-ci
SECRETS: |
appcenter-ios-token
run: |
for i in ${SECRETS//,/ }
do
VALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $i --query value --output tsv)
echo "::add-mask::$VALUE"
echo "$i=$VALUE" >> $GITHUB_OUTPUT
done
uses: bitwarden/gh-actions/get-keyvault-secrets@main
with:
keyvault: "bitwarden-ci"
secrets: "appcenter-ios-token"
- name: Decrypt secrets
env:
@@ -570,7 +520,6 @@ jobs:
./.github/secrets/dist_watch_app_extension.mobileprovision.gpg
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--output ./src/watchOS/bitwarden/GoogleService-Info.plist ./.github/secrets/GoogleService-Info.plist.gpg
shell: bash
- name: Increment version
run: |
@@ -580,14 +529,14 @@ jobs:
echo "##### Setting CFBundleVersion $BUILD_NUMBER"
echo "########################################"
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS/Info.plist
echo "### CFBundleVersion $BUILD_NUMBER" >> $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
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Extension/Info.plist
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Autofill/Info.plist
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.ShareExtension/Info.plist
cd src/watchOS/bitwarden
agvtool new-version -all $BUILD_NUMBER
cd ../../..
shell: bash
- name: Update Entitlements
run: |
@@ -595,9 +544,8 @@ jobs:
echo "##### Updating Entitlements"
echo "########################################"
perl -0777 -pi.bak -e 's/<key>aps-environment<\/key>\s*<string>development<\/string>/<key>aps-environment<\/key>\n\t<string>production<\/string>/' ./src/iOS/Entitlements.plist
shell: bash
perl -0777 -pi.bak -e 's/<key>aps-environment<\/key>\s*<string>development<\/string>/<key>aps-environment<\/key>\n\t<string>production<\/string>/' ./${{ env.ios_folder_path }}/Entitlements.plist
- name: Set up Keychain
env:
KEYCHAIN_PASSWORD: ${{ secrets.IOS_KEYCHAIN_PASSWORD }}
@@ -613,7 +561,6 @@ jobs:
security import ~/secrets/iphone-distribution-cert.p12 -k build.keychain -P $DIST_CERT_PASSWORD \
-T /usr/bin/codesign -T /usr/bin/security
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain
shell: bash
- name: Set up provisioning profiles
run: |
@@ -644,7 +591,9 @@ jobs:
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"
shell: bash
- name: Restore packages
run: dotnet restore
- name: Bulid WatchApp
run: |
@@ -657,21 +606,14 @@ jobs:
echo "########################################"
echo "##### Done"
echo "########################################"
shell: bash
- name: Restore packages
run: nuget restore
- name: Archive Build for App Store
run: |
$configuration = "AppStore";
$platform = "iPhone";
Write-Output "########################################"
Write-Output "##### Archive for Release ios-arm64
Write-Output "########################################"
Write-Output "########################################"
Write-Output "##### Archive $configuration Configuration for $platform Platform"
Write-Output "########################################"
msbuild "$($env:GITHUB_WORKSPACE + "/src/iOS/iOS.csproj")" "/p:Platform=$platform" `
"/p:Configuration=$configuration" "/p:ArchiveOnBuild=true" "/t:`"Build`""
dotnet publish ${{ env.main_app_project_path }} -c Release -f ${{ env.target-net-version }}-ios /p:RuntimeIdentifier=ios-arm64 /p:ArchiveOnBuild=true /p:MtouchUseLlvm=false
Write-Output "########################################"
Write-Output "##### Done"
@@ -680,14 +622,11 @@ jobs:
- name: Archive Build for Mobile Automation
run: |
$configuration = "Release";
$platform = "iPhoneSimulator";
Write-Output "########################################"
Write-Output "##### Archive Debug for iossimulator-x64
Write-Output "########################################"
Write-Output "########################################"
Write-Output "##### Archive $configuration Configuration for $platform Platform"
Write-Output "########################################"
msbuild "$($env:GITHUB_WORKSPACE + "/src/iOS/iOS.csproj")" "/p:Platform=$platform" `
"/p:Configuration=$configuration" "/p:ArchiveOnBuild=true" "/t:`"Build`""
dotnet build ${{ env.main_app_project_path }} -c Debug -f ${{ env.target-net-version }}-ios /p:RuntimeIdentifier=iossimulator-x64 /p:ArchiveOnBuild=true /p:MtouchUseLlvm=false
Write-Output "########################################"
Write-Output "##### Done"
@@ -703,16 +642,14 @@ jobs:
xcodebuild -exportArchive -archivePath $ARCHIVE_PATH -exportPath $EXPORT_PATH \
-exportOptionsPlist $EXPORT_OPTIONS_PATH
shell: bash
- name: Export .app for Automation CI
run: |
ARCHIVE_PATH="./src/iOS/bin/iPhoneSimulator/Release/BitwardeniOS.app"
ARCHIVE_PATH="./${{ env.main_app_folder_path }}/bin/Debug/${{ env.target-net-version }}-ios/iossimulator-x64"
EXPORT_PATH="./bitwarden-export"
zip -r -q BitwardeniOS.app.zip $ARCHIVE_PATH
mv BitwardeniOS.app.zip $EXPORT_PATH
shell: bash
zip -r -q ${{ env.app_ci_output_filename }}.app.zip $ARCHIVE_PATH
mv ${{ env.app_ci_output_filename }}.app.zip $EXPORT_PATH
- name: Copy all dSYMs files to upload
run: |
@@ -725,10 +662,9 @@ jobs:
cp -r -v $ARCHIVE_DSYMS_PATH $EXPORT_PATH
mkdir $WATCH_DSYMS_EXPORT_PATH
cp -r -v $WATCH_ARCHIVE_DSYMS_PATH $WATCH_DSYMS_EXPORT_PATH
shell: bash
- name: Upload App Store .ipa & dSYMs artifacts
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: Bitwarden iOS
path: |
@@ -737,15 +673,15 @@ jobs:
if-no-files-found: error
- name: Upload .app file for Automation CI
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: BitwardeniOS.app.zip
path: ./bitwarden-export/BitwardeniOS.app.zip
name: ${{ env.app_ci_output_filename }}.app.zip
path: ./bitwarden-export/${{ env.app_ci_output_filename }}.app.zip
if-no-files-found: error
- name: Install AppCenter CLI
if: |
(github.ref == 'refs/heads/master'
(github.ref == 'refs/heads/main'
&& needs.setup.outputs.rc_branch_exists == 0
&& needs.setup.outputs.hotfix_branch_exists == 0)
|| (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0)
@@ -754,7 +690,7 @@ jobs:
- name: Upload dSYMs to App Center
if: |
(github.ref == 'refs/heads/master'
(github.ref == 'refs/heads/main'
&& needs.setup.outputs.rc_branch_exists == 0
&& needs.setup.outputs.hotfix_branch_exists == 0)
|| (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0)
@@ -762,25 +698,22 @@ jobs:
env:
APPCENTER_IOS_TOKEN: ${{ steps.retrieve-secrets.outputs.appcenter-ios-token }}
run: appcenter crashes upload-symbols -a bitwarden/bitwarden -s "./bitwarden-export/dSYMs" --token $APPCENTER_IOS_TOKEN
shell: bash
- name: Upload Watch dSYMs to Firebase Crashlytics
if: |
(github.ref == 'refs/heads/master'
(github.ref == 'refs/heads/main'
&& needs.setup.outputs.rc_branch_exists == 0
&& needs.setup.outputs.hotfix_branch_exists == 0)
|| (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0)
|| github.ref == 'refs/heads/hotfix-rc'
run: |
echo "########################################"
echo "##### Uploading Watch dSYMs to Firebase"
echo "########################################"
find "$HOME/Library/Developer/XCode/DerivedData" -name "upload-symbols" -exec chmod +x {} \; -exec {} -gsp "./src/watchOS/bitwarden/GoogleService-Info.plist" -p ios "./bitwarden-export/Watch_dSYMs" \;
shell: bash
- name: Deploy to App Store
- name: Validate app in App Store
if: |
(github.ref == 'refs/heads/master'
&& needs.setup.outputs.rc_branch_exists == 0
@@ -791,52 +724,59 @@ jobs:
APPLE_ID_USERNAME: ${{ secrets.APPLE_ID_USERNAME }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
run: |
xcrun altool --upload-app --type ios --file "./bitwarden-export/Bitwarden.ipa" \
xcrun altool --validate-app --type ios --file "./bitwarden-export/Bitwarden.ipa" \
--username "$APPLE_ID_USERNAME" --password "$APPLE_ID_PASSWORD"
shell: bash
- name: Deploy to App Store
if: |
(github.ref == 'refs/heads/main'
&& needs.setup.outputs.rc_branch_exists == 0
&& needs.setup.outputs.hotfix_branch_exists == 0)
|| (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0)
|| github.ref == 'refs/heads/hotfix-rc'
env:
APPLE_ID_USERNAME: ${{ secrets.APPLE_ID_USERNAME }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
run: |
xcrun altool --upload-app --type ios --file "./bitwarden-export/Bitwarden.ipa" \
--username "$APPLE_ID_USERNAME" --password "$APPLE_ID_PASSWORD"
crowdin-push:
name: Crowdin Push
if: github.ref == 'refs/heads/master'
if: github.ref == 'refs/heads/main'
needs:
- android
- f-droid
- ios
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
env:
_CROWDIN_PROJECT_ID: "269690"
steps:
- name: Checkout repo
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Login to Azure - CI Subscription
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.6
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
- name: Retrieve secrets
id: retrieve-secrets
env:
KEYVAULT: bitwarden-ci
SECRETS: |
crowdin-api-token
run: |
for i in ${SECRETS//,/ }
do
VALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $i --query value --output tsv)
echo "::add-mask::$VALUE"
echo "$i=$VALUE" >> $GITHUB_OUTPUT
done
uses: bitwarden/gh-actions/get-keyvault-secrets@main
with:
keyvault: "bitwarden-ci"
secrets: "crowdin-api-token"
- name: Upload Sources
uses: crowdin/github-action@965d501f160af7b1f88aed4c29154b0caf1e94b9 # v1.9.0
uses: crowdin/github-action@198daeb2d30636c4608d6a6bb96c009dbefc02a2 # v1.18.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
with:
config: crowdin.yml
crowdin_branch_name: master
crowdin_branch_name: main
upload_sources: true
upload_translations: false
@@ -844,7 +784,7 @@ jobs:
check-failures:
name: Check for failures
if: always()
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
needs:
- cloc
- android
@@ -854,7 +794,7 @@ jobs:
steps:
- name: Check if any job failed
if: |
(github.ref == 'refs/heads/master')
(github.ref == 'refs/heads/main')
|| (github.ref == 'refs/heads/rc')
|| (github.ref == 'refs/heads/hotfix-rc')
env:
@@ -877,25 +817,18 @@ jobs:
fi
- name: Login to Azure - CI Subscription
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.6
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
if: failure()
with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
- name: Retrieve secrets
id: retrieve-secrets
uses: bitwarden/gh-actions/get-keyvault-secrets@main
if: failure()
env:
KEYVAULT: bitwarden-ci
SECRETS: |
devops-alerts-slack-webhook-url
run: |
for i in ${SECRETS//,/ }
do
VALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $i --query value --output tsv)
echo "::add-mask::$VALUE"
echo "$i=$VALUE" >> $GITHUB_OUTPUT
done
with:
keyvault: "bitwarden-ci"
secrets: "devops-alerts-slack-webhook-url"
- name: Notify Slack on failure
uses: act10ns/slack@ed1309ab9862e57e9e583e51c7889486b9a00b0f # v2.0.0

View File

@@ -15,28 +15,28 @@ jobs:
_CROWDIN_PROJECT_ID: "269690"
steps:
- name: Checkout repo
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Login to Azure - CI Subscription
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.6
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
- name: Retrieve secrets
id: retrieve-secrets
uses: bitwarden/gh-actions/get-keyvault-secrets@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67
uses: bitwarden/gh-actions/get-keyvault-secrets@main
with:
keyvault: "bitwarden-ci"
secrets: "crowdin-api-token, github-gpg-private-key, github-gpg-private-key-passphrase"
- name: Download translations
uses: crowdin/github-action@965d501f160af7b1f88aed4c29154b0caf1e94b9 # v1.9.0
uses: crowdin/github-action@198daeb2d30636c4608d6a6bb96c009dbefc02a2 # v1.18.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
with:
config: crowdin.yml
crowdin_branch_name: master
crowdin_branch_name: main
upload_sources: false
upload_translations: false
download_translations: true

View File

@@ -38,11 +38,11 @@ jobs:
fi
- name: Checkout repo
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Check Release Version
id: version
uses: bitwarden/gh-actions/release-version-check@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67
uses: bitwarden/gh-actions/release-version-check@main
with:
release-type: ${{ github.event.inputs.release_type }}
project-type: xamarin
@@ -56,7 +56,7 @@ jobs:
- name: Create GitHub deployment
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
uses: chrnorm/deployment-action@d42cde7132fcec920de534fffc3be83794335c00 # v2.0.5
uses: chrnorm/deployment-action@55729fcebec3d284f60f5bcabbd8376437d696b1 # v2.0.7
id: deployment
with:
token: '${{ secrets.GITHUB_TOKEN }}'
@@ -68,7 +68,7 @@ jobs:
- name: Download all artifacts
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
uses: dawidd6/action-download-artifact@e7466d1a7587ed14867642c2ca74b5bcc1e19a2d # v3.0.0
with:
workflow: build.yml
workflow_conclusion: success
@@ -76,18 +76,18 @@ jobs:
- name: Dry Run - Download all artifacts
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
uses: dawidd6/action-download-artifact@e7466d1a7587ed14867642c2ca74b5bcc1e19a2d # v3.0.0
with:
workflow: build.yml
workflow_conclusion: success
branch: master
branch: main
- name: Prep Bitwarden iOS release asset
run: zip -r Bitwarden\ iOS.zip Bitwarden\ iOS
- name: Create release
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
uses: ncipollo/release-action@6c75be85e571768fa31b40abf38de58ba0397db5 # v1.13.0
uses: ncipollo/release-action@2c591bcc8ecdcd2db72b97d6147f871fcd833ba5 # v1.14.0
with:
artifacts: "./com.x8bit.bitwarden.aab/com.x8bit.bitwarden.aab,
./com.x8bit.bitwarden.apk/com.x8bit.bitwarden.apk,
@@ -126,11 +126,11 @@ jobs:
if: inputs.fdroid_publish
steps:
- name: Checkout repo
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
- name: Download F-Droid .apk artifact
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
uses: dawidd6/action-download-artifact@e7466d1a7587ed14867642c2ca74b5bcc1e19a2d # v3.0.0
with:
workflow: build.yml
workflow_conclusion: success
@@ -139,15 +139,15 @@ jobs:
- name: Dry Run - Download F-Droid .apk artifact
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
uses: dawidd6/action-download-artifact@e7466d1a7587ed14867642c2ca74b5bcc1e19a2d # v3.0.0
with:
workflow: build.yml
workflow_conclusion: success
branch: master
branch: main
name: com.x8bit.bitwarden-fdroid.apk
- name: Set up Node
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: '16.x'

View File

@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: 'Run stale action'
uses: actions/stale@f7176fd3007623b69d27091f9b9d4ab7995f0a06 # v5.2.1
uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0
with:
stale-issue-label: 'needs-reply'
stale-pr-label: 'needs-changes'
@@ -27,4 +27,4 @@ jobs:
If youre still working on this, please respond here after youve made the changes weve requested and our team will re-open it for further review.
Please make sure to resolve any conflicts with the master branch before requesting another review.
Please make sure to resolve any conflicts with the main branch before requesting another review.

View File

@@ -1,5 +1,5 @@
---
name: Version Auto Bump
name: Auto Bump Mobile Version
on:
push:
@@ -7,14 +7,12 @@ on:
- v**
jobs:
setup:
name: "Setup"
bump-version:
name: Bump Mobile Version
runs-on: ubuntu-22.04
outputs:
version_number: ${{ steps.version.outputs.new-version }}
steps:
- name: Checkout Branch
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Calculate bumped version
id: version
@@ -29,11 +27,23 @@ jobs:
NEW_PATCH=$((CURR_PATCH+1))
NEW_VER=$CURR_MAJOR.$NEW_PATCH
echo "New Version: $NEW_VER"
echo "new-version=$NEW_VER" >> $GITHUB_OUTPUT
echo "new_version=$NEW_VER" >> $GITHUB_OUTPUT
trigger_version_bump:
name: Bump version to ${{ needs.setup.outputs.version_number }}
needs: setup
uses: ./.github/workflows/version-bump.yml
with:
version_number: ${{ needs.setup.outputs.version_number }}
- name: Login to Azure - CI Subscription
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
- name: Retrieve bot secrets
id: retrieve-bot-secrets
uses: bitwarden/gh-actions/get-keyvault-secrets@main
with:
keyvault: bitwarden-ci
secrets: "github-pat-bitwarden-devops-bot-repo-scope"
- name: "Bump version to ${{ steps.version.outputs.new_version }}"
env:
GH_TOKEN: ${{ steps.retrieve-bot-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
run: |
echo '{"cut_rc_branch": "false", "version_number": "${{ steps.version.outputs.new_version }}"}' | \
gh workflow run version-bump.yml --json --repo bitwarden/mobile

View File

@@ -1,40 +1,54 @@
---
name: Version Bump
run-name: Version Bump - v${{ inputs.version_number }}
on:
workflow_dispatch:
inputs:
version_number:
description: "New Version"
description: "New version (example: '2024.1.0')"
required: true
workflow_call:
inputs:
version_number:
required: true
type: string
cut_rc_branch:
description: "Cut RC branch?"
default: true
type: boolean
jobs:
bump_version:
name: "Create version_bump_${{ github.event.inputs.version_number }} branch"
runs-on: ubuntu-20.04
name: "Bump Version to v${{ inputs.version_number }}"
runs-on: ubuntu-22.04
steps:
- name: Checkout Branch
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- name: Login to Azure - CI Subscription
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.7
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
- name: Retrieve secrets
id: retrieve-secrets
uses: bitwarden/gh-actions/get-keyvault-secrets@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67
uses: bitwarden/gh-actions/get-keyvault-secrets@main
with:
keyvault: "bitwarden-ci"
secrets: "github-gpg-private-key, github-gpg-private-key-passphrase"
secrets: "github-gpg-private-key,
github-gpg-private-key-passphrase,
github-pat-bitwarden-devops-bot-repo-scope"
- name: Checkout Branch
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
ref: main
- name: Check if RC branch exists
if: ${{ inputs.cut_rc_branch == true }}
run: |
remote_rc_branch_check=$(git ls-remote --heads origin rc | wc -l)
if [[ "${remote_rc_branch_check}" -gt 0 ]]; then
echo "Remote RC branch exists."
echo "Please delete current RC branch before running again."
exit 1
fi
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@d6f3f49f3345e29369fe57596a3ca8f94c4d2ca7 # v5.4.0
uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.0
with:
gpg_private_key: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key }}
passphrase: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key-passphrase }}
@@ -42,37 +56,68 @@ jobs:
git_commit_gpgsign: true
- name: Create Version Branch
run: git switch -c version_bump_${{ github.event.inputs.version_number }}
id: create-branch
run: |
NAME=version_bump_${{ github.ref_name }}_${{ inputs.version_number }}
git switch -c $NAME
echo "name=$NAME" >> $GITHUB_OUTPUT
- name: Install xmllint
run: sudo apt install -y libxml2-utils
- name: Verify input version
env:
NEW_VERSION: ${{ inputs.version_number }}
run: |
CURRENT_VERSION=$(xmllint --xpath '
string(/manifest/@*[local-name()="versionName"
and namespace-uri()="http://schemas.android.com/apk/res/android"])
' src/App/Platforms/Android/AndroidManifest.xml)
# Error if version has not changed.
if [[ "$NEW_VERSION" == "$CURRENT_VERSION" ]]; then
echo "Version has not changed."
exit 1
fi
# Check if version is newer.
printf '%s\n' "${CURRENT_VERSION}" "${NEW_VERSION}" | sort -C -V
if [ $? -eq 0 ]; then
echo "Version check successful."
else
echo "Version check failed."
exit 1
fi
- name: Bump Version - Android XML
uses: bitwarden/gh-actions/version-bump@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67
uses: bitwarden/gh-actions/version-bump@main
with:
version: ${{ github.event.inputs.version_number }}
file_path: "./src/Android/Properties/AndroidManifest.xml"
version: ${{ inputs.version_number }}
file_path: "src/App/Platforms/Android/AndroidManifest.xml"
- name: Bump Version - iOS.Autofill
uses: bitwarden/gh-actions/version-bump@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67
uses: bitwarden/gh-actions/version-bump@main
with:
version: ${{ github.event.inputs.version_number }}
file_path: "./src/iOS.Autofill/Info.plist"
version: ${{ inputs.version_number }}
file_path: "src/iOS.Autofill/Info.plist"
- name: Bump Version - iOS.Extension
uses: bitwarden/gh-actions/version-bump@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67
uses: bitwarden/gh-actions/version-bump@main
with:
version: ${{ github.event.inputs.version_number }}
file_path: "./src/iOS.Extension/Info.plist"
version: ${{ inputs.version_number }}
file_path: "src/iOS.Extension/Info.plist"
- name: Bump Version - iOS.ShareExtension
uses: bitwarden/gh-actions/version-bump@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67
uses: bitwarden/gh-actions/version-bump@main
with:
version: ${{ github.event.inputs.version_number }}
file_path: "./src/iOS.ShareExtension/Info.plist"
version: ${{ inputs.version_number }}
file_path: "src/iOS.ShareExtension/Info.plist"
- name: Bump Version - iOS
uses: bitwarden/gh-actions/version-bump@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67
uses: bitwarden/gh-actions/version-bump@main
with:
version: ${{ github.event.inputs.version_number }}
file_path: "./src/iOS/Info.plist"
version: ${{ inputs.version_number }}
file_path: "src/App/Platforms/iOS/Info.plist"
- name: Setup git
run: |
@@ -91,22 +136,24 @@ jobs:
- name: Commit files
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
run: git commit -m "Bumped version to ${{ github.event.inputs.version_number }}" -a
run: git commit -m "Bumped version to ${{ inputs.version_number }}" -a
- name: Push changes
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
run: git push -u origin version_bump_${{ github.event.inputs.version_number }}
env:
PR_BRANCH: ${{ steps.create-branch.outputs.name }}
run: git push -u origin $PR_BRANCH
- name: Create Version PR
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
id: create-pr
env:
PR_BRANCH: "version_bump_${{ github.event.inputs.version_number }}"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
BASE_BRANCH: master
TITLE: "Bump version to ${{ github.event.inputs.version_number }}"
GH_TOKEN: ${{ steps.retrieve-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
PR_BRANCH: ${{ steps.create-branch.outputs.name }}
TITLE: "Bump version to ${{ inputs.version_number }}"
run: |
gh pr create --title "$TITLE" \
--base "$BASE" \
PR_URL=$(gh pr create --title "$TITLE" \
--base "main" \
--head "$PR_BRANCH" \
--label "version update" \
--label "automated pr" \
@@ -119,4 +166,54 @@ jobs:
- [X] Other
## Objective
Automated version bump to ${{ github.event.inputs.version_number }}"
Automated version bump to ${{ inputs.version_number }}")
echo "pr_number=${PR_URL##*/}" >> $GITHUB_OUTPUT
- name: Approve PR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }}
run: gh pr review $PR_NUMBER --approve
- name: Merge PR
env:
GH_TOKEN: ${{ steps.retrieve-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }}
run: gh pr merge $PR_NUMBER --squash --auto --delete-branch
cut_rc:
name: Cut RC branch
needs: bump_version
if: ${{ inputs.cut_rc_branch == true }}
runs-on: ubuntu-22.04
steps:
- name: Checkout Branch
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
ref: main
- name: Install xmllint
run: sudo apt install -y libxml2-utils
- name: Verify version has been updated
env:
NEW_VERSION: ${{ inputs.version_number }}
run: |
# Wait for version to change.
while : ; do
echo "Waiting for version to be updated..."
git pull --force
CURRENT_VERSION=$(xmllint --xpath '
string(/manifest/@*[local-name()="versionName"
and namespace-uri()="http://schemas.android.com/apk/res/android"])
' src/App/Platforms/Android/AndroidManifest.xml)
# If the versions don't match we continue the loop, otherwise we break out of the loop.
[[ "$NEW_VERSION" != "$CURRENT_VERSION" ]] || break
sleep 10
done
- name: Cut RC branch
run: |
git switch --quiet --create rc
git push --quiet --set-upstream origin rc

View File

@@ -8,4 +8,4 @@ on:
jobs:
call-workflow:
uses: bitwarden/gh-actions/.github/workflows/workflow-linter.yml@4a7ddc1b38ca5cb4e3e43578f4df5cabe4f55a67
uses: bitwarden/gh-actions/.github/workflows/workflow-linter.yml@main

2
.gitignore vendored
View File

@@ -31,6 +31,7 @@ Components/
x64/
x86/
!src/lib/x86/
!src/App/Platforms/Android/lib/x86/
build/
bld/
[Bb]in/
@@ -147,6 +148,7 @@ publish/
# NuGet Packages
*.nupkg
!**/Xamarin.AndroidX.Credentials.1.0.0.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.

13
Directory.Build.props Normal file
View File

@@ -0,0 +1,13 @@
<Project>
<PropertyGroup>
<MauiVersion>8.0.7-nightly.*</MauiVersion>
<ReleaseCodesignProvision>Automatic:AppStore</ReleaseCodesignProvision>
<ReleaseCodesignKey>iPhone Distribution</ReleaseCodesignKey>
<IncludeBitwardeniOSExtensions>True</IncludeBitwardeniOSExtensions>
<IncludeBitwardenWatchOSApp>True</IncludeBitwardenWatchOSApp>
<Argon2IdLoadMtouchExtraArgs>-gcc_flags "-L$(ProjectDir)../../lib/ios -largon2 -force_load $(ProjectDir)../../lib/ios/libargon2.a"</Argon2IdLoadMtouchExtraArgs>
<!-- Uncomment this when Unit Testing-->
<!-- <CustomConstants>UT</CustomConstants> -->
</PropertyGroup>
</Project>

View File

@@ -1,4 +1,4 @@
[![Github Workflow build on master](https://github.com/bitwarden/mobile/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/bitwarden/mobile/actions/workflows/build.yml?query=branch:master)
[![Github Workflow build on main](https://github.com/bitwarden/mobile/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/bitwarden/mobile/actions/workflows/build.yml?query=branch:main)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/bitwarden-mobile/localized.svg)](https://crowdin.com/project/bitwarden-mobile)
[![Join the chat at https://gitter.im/bitwarden/Lobby](https://badges.gitter.im/bitwarden/Lobby.svg)](https://gitter.im/bitwarden/Lobby)
@@ -6,7 +6,7 @@
<a href="https://play.google.com/store/apps/details?id=com.x8bit.bitwarden" target="_blank"><img alt="Get it on Google Play" src="https://imgur.com/YQzmZi9.png" width="153" height="46"></a> <a href="https://mobileapp.bitwarden.com/fdroid/" target="_blank"><img alt="Get it on F-Droid" src="https://i.imgur.com/HDicnzz.png" width="154" height="46"></a> <a href="https://itunes.apple.com/us/app/bitwarden-free-password-manager/id1137397744?mt=8" target="_blank"><img src="https://imgur.com/GdGqPMY.png" width="135" height="40"></a>
The Bitwarden mobile application is written in C# with Xamarin Android, Xamarin iOS, and Xamarin Forms.
The Bitwarden mobile application is written in C# using .NET MAUI.
<img src="https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/mobile-android-myvault.png" alt="" width="325" height="650" /> <img src="https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/mobile-ios-myvault.png" alt="" width="300" height="650" />
@@ -20,6 +20,6 @@ Interested in contributing in a big way? Consider joining our team! We're hiring
# Contribute
Code contributions are welcome! Please commit any pull requests against the `master` branch. Learn more about how to contribute by reading the [Contributing Guidelines](https://contributing.bitwarden.com/contributing/). Check out the [Contributing Documentation](https://contributing.bitwarden.com/) for how to get started with your first contribution.
Code contributions are welcome! Please commit any pull requests against the `main` branch. Learn more about how to contribute by reading the [Contributing Guidelines](https://contributing.bitwarden.com/contributing/). Check out the [Contributing Documentation](https://contributing.bitwarden.com/) for how to get started with your first contribution.
Security audits and feedback are welcome. Please open an issue or email us privately if the report is sensitive in nature. You can read our security policy in the [`SECURITY.md`](SECURITY.md) file.

View File

@@ -1,471 +1,233 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29009.5
# Visual Studio Version 17
VisualStudioVersion = 17.8.34112.27
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Android", "src\Android\Android.csproj", "{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "src\App\App.csproj", "{971FDF07-E288-4239-B47A-E9E7E912193B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "App", "src\App\App.csproj", "{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "src\Core\Core.csproj", "{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "src\Core\Core.csproj", "{4B8A8C41-9820-4341-974C-41E65B7F4366}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Playground", "test\Playground\Playground.csproj", "{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D10CA4A9-F866-40E1-B658-F69051236C71}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{8904C536-C67D-420F-9971-51B26574C3AA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "store", "store", "{92470CBD-9047-4C3C-8EA3-D972D6622D84}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "google", "google", "{2E399654-26A2-46F6-B9CA-1B496A3F370A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{76690DFB-B7F4-4781-83E4-113FDC450AFE}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
.github\workflows\build.yml = .github\workflows\build.yml
CONTRIBUTING.md = CONTRIBUTING.md
crowdin.yml = crowdin.yml
README.md = README.md
SECURITY.md = SECURITY.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Publisher", "store\google\Publisher\Publisher.csproj", "{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Core", "src\iOS.Core\iOS.Core.csproj", "{E71F3053-056C-4381-9638-048ED73BDFF6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS", "src\iOS\iOS.csproj", "{599E0201-420A-4C3E-A7BA-5349F72E0B15}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "iOS.Core", "src\iOS.Core\iOS.Core.csproj", "{E71F3053-056C-4381-9638-048ED73BDFF6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Extension", "src\iOS.Extension\iOS.Extension.csproj", "{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "test\Common\Common.csproj", "{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Test", "test\Core.Test\Core.Test.csproj", "{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.ShareExtension", "src\iOS.ShareExtension\iOS.ShareExtension.csproj", "{F8C3F648-EA5A-4719-8005-85D1690B1655}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Autofill", "src\iOS.Autofill\iOS.Autofill.csproj", "{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Autofill", "src\iOS.Autofill\iOS.Autofill.csproj", "{83449CC4-1F76-4CFE-92B1-D2E13A62506F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{BB702EBD-3B79-4ECA-A2A6-1237B07F0AF0}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B972BBFA-917F-4A10-B07E-B89CFEC6BBDC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Test", "test\Core.Test\Core.Test.csproj", "{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "test\Common\Common.csproj", "{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
Ad-Hoc|iPhone = Ad-Hoc|iPhone
Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator
AppStore|Any CPU = AppStore|Any CPU
AppStore|iPhone = AppStore|iPhone
AppStore|iPhoneSimulator = AppStore|iPhoneSimulator
Debug|Any CPU = Debug|Any CPU
Debug|iPhone = Debug|iPhone
Debug|iPhoneSimulator = Debug|iPhoneSimulator
FDroid|Any CPU = FDroid|Any CPU
FDroid|iPhone = FDroid|iPhone
FDroid|iPhoneSimulator = FDroid|iPhoneSimulator
Release|Any CPU = Release|Any CPU
Release|iPhone = Release|iPhone
Debug|iPhoneSimulator = Debug|iPhoneSimulator
Release|iPhoneSimulator = Release|iPhoneSimulator
Debug|iPhone = Debug|iPhone
Release|iPhone = Release|iPhone
AppStore|iPhoneSimulator = AppStore|iPhoneSimulator
AppStore|iPhone = AppStore|iPhone
Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator
Ad-Hoc|iPhone = Ad-Hoc|iPhone
FDroid|Any CPU = FDroid|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|Any CPU.Deploy.0 = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhone.Deploy.0 = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|Any CPU.Build.0 = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|Any CPU.Deploy.0 = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhone.Build.0 = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhone.Deploy.0 = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhoneSimulator.Deploy.0 = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhone.Build.0 = Debug|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhone.Deploy.0 = Debug|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|Any CPU.Deploy.0 = FDroid|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhone.Build.0 = FDroid|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhone.Deploy.0 = FDroid|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhoneSimulator.Deploy.0 = FDroid|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|Any CPU.Build.0 = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|Any CPU.Deploy.0 = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhone.ActiveCfg = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhone.Build.0 = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhone.Deploy.0 = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|Any CPU.Deploy.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhone.Deploy.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|Any CPU.Build.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|Any CPU.Deploy.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhone.Build.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhone.Deploy.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhoneSimulator.Deploy.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhone.Build.0 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhone.Deploy.0 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|iPhone.Build.0 = FDroid|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|Any CPU.Build.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|Any CPU.Deploy.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhone.ActiveCfg = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhone.Build.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhone.Deploy.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|Any CPU.Build.0 = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhone.Build.0 = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|iPhone.Build.0 = Debug|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|iPhone.Build.0 = FDroid|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|Any CPU.Build.0 = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|iPhone.ActiveCfg = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|iPhone.Build.0 = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|iPhone.Build.0 = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|iPhone.Build.0 = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|iPhone.Build.0 = FDroid|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|Any CPU.Build.0 = Release|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|iPhone.ActiveCfg = Release|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|iPhone.Build.0 = Release|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|iPhone.Build.0 = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|iPhone.Build.0 = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|iPhone.Build.0 = FDroid|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|Any CPU.Build.0 = Release|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|iPhone.ActiveCfg = Release|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|iPhone.Build.0 = Release|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|Any CPU.Build.0 = Ad-Hoc|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|Any CPU.ActiveCfg = AppStore|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|Any CPU.Build.0 = AppStore|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.Build.0 = AppStore|iPhone
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|Any CPU.Build.0 = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|Any CPU.Deploy.0 = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|iPhone.Build.0 = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|iPhone.ActiveCfg = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|iPhone.Build.0 = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.AppStore|iPhone.Build.0 = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.FDroid|Any CPU.Build.0 = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|Any CPU.Build.0 = Release|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|iPhone.Build.0 = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|iPhone.ActiveCfg = Release|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|iPhone.Build.0 = Release|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.AppStore|iPhone.Build.0 = Release|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.FDroid|Any CPU.Build.0 = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhone.ActiveCfg = Debug|iPhone
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhone.Build.0 = Debug|iPhone
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|iPhone.Build.0 = FDroid|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|Any CPU.Build.0 = Release|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.ActiveCfg = Release|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.Build.0 = Release|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhone.Build.0 = AppStore|iPhone
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|Any CPU.ActiveCfg = Debug|iPhone
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.ActiveCfg = Debug|iPhone
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.Build.0 = Debug|iPhone
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.Deploy.0 = Debug|iPhone
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|Any CPU.ActiveCfg = FDroid|iPhone
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhone.ActiveCfg = FDroid|iPhone
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhone.Build.0 = FDroid|iPhone
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|iPhoneSimulator
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhoneSimulator.Build.0 = FDroid|iPhoneSimulator
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|Any CPU.ActiveCfg = Release|iPhone
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhone.ActiveCfg = Release|iPhone
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhone.Build.0 = Release|iPhone
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|Any CPU.Build.0 = Ad-Hoc|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|Any CPU.Build.0 = AppStore|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.Build.0 = AppStore|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|Any CPU.ActiveCfg = Debug|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.ActiveCfg = Debug|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.Build.0 = Debug|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.Deploy.0 = Debug|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.ActiveCfg = Release|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.Build.0 = Release|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhone.ActiveCfg = Release|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhone.Build.0 = Release|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|Any CPU.ActiveCfg = Release|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.ActiveCfg = Release|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.Build.0 = Release|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|Any CPU.Build.0 = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhone.Build.0 = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhone.Build.0 = Debug|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|Any CPU.ActiveCfg = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|Any CPU.Build.0 = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhone.ActiveCfg = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhone.Build.0 = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhoneSimulator.ActiveCfg = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhoneSimulator.Build.0 = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|Any CPU.Build.0 = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhone.ActiveCfg = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhone.Build.0 = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|Any CPU.Build.0 = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhone.Build.0 = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhone.Build.0 = Debug|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|Any CPU.ActiveCfg = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|Any CPU.Build.0 = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhone.ActiveCfg = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhone.Build.0 = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhoneSimulator.ActiveCfg = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhoneSimulator.Build.0 = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|Any CPU.Build.0 = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhone.ActiveCfg = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhone.Build.0 = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|Any CPU.ActiveCfg = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|Any CPU.Build.0 = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhone.ActiveCfg = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhone.Build.0 = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|Any CPU.ActiveCfg = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|Any CPU.Build.0 = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhone.ActiveCfg = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhone.Build.0 = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhone.ActiveCfg = Debug|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhone.Build.0 = Debug|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|Any CPU.ActiveCfg = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|Any CPU.Build.0 = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|iPhone.ActiveCfg = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|iPhone.Build.0 = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|Any CPU.ActiveCfg = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|Any CPU.Build.0 = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhone.ActiveCfg = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhone.Build.0 = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|Any CPU.Build.0 = Ad-Hoc|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|Any CPU.Build.0 = AppStore|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhone.Build.0 = AppStore|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|Any CPU.ActiveCfg = Debug|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.ActiveCfg = Debug|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.Build.0 = Debug|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.Deploy.0 = Debug|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|Any CPU.ActiveCfg = Release|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|Any CPU.Build.0 = Release|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhone.ActiveCfg = Release|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhone.Build.0 = Release|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|Any CPU.ActiveCfg = Release|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhone.ActiveCfg = Release|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhone.Build.0 = Release|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhone.Build.0 = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.ActiveCfg = Release|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.Build.0 = Release|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.Build.0 = Release|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|Any CPU.Build.0 = Debug|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|Any CPU.Build.0 = Debug|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|Any CPU.ActiveCfg = Release|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|Any CPU.Build.0 = Release|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.Build.0 = Debug|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.ActiveCfg = Release|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.Build.0 = Release|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.Build.0 = Release|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.Build.0 = Debug|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|Any CPU.Build.0 = Release|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhone.Build.0 = Debug|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhone.ActiveCfg = Release|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhone.Build.0 = Release|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhone.Build.0 = Release|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|Any CPU.Build.0 = Debug|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Release|Any CPU.Build.0 = Release|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Release|iPhone.ActiveCfg = Release|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Release|iPhone.Build.0 = Release|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.AppStore|iPhone.Build.0 = Release|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.FDroid|Any CPU.Build.0 = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|Any CPU.Build.0 = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|iPhone.Build.0 = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|iPhone.ActiveCfg = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|iPhone.Build.0 = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.AppStore|iPhone.Build.0 = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.FDroid|Any CPU.Build.0 = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|Any CPU.Build.0 = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|iPhone.Build.0 = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|iPhone.ActiveCfg = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|iPhone.Build.0 = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.AppStore|iPhone.Build.0 = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.FDroid|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F} = {D10CA4A9-F866-40E1-B658-F69051236C71}
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C} = {D10CA4A9-F866-40E1-B658-F69051236C71}
{4B8A8C41-9820-4341-974C-41E65B7F4366} = {D10CA4A9-F866-40E1-B658-F69051236C71}
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3} = {8904C536-C67D-420F-9971-51B26574C3AA}
{2E399654-26A2-46F6-B9CA-1B496A3F370A} = {92470CBD-9047-4C3C-8EA3-D972D6622D84}
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D} = {2E399654-26A2-46F6-B9CA-1B496A3F370A}
{E71F3053-056C-4381-9638-048ED73BDFF6} = {D10CA4A9-F866-40E1-B658-F69051236C71}
{599E0201-420A-4C3E-A7BA-5349F72E0B15} = {D10CA4A9-F866-40E1-B658-F69051236C71}
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545} = {D10CA4A9-F866-40E1-B658-F69051236C71}
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39} = {8904C536-C67D-420F-9971-51B26574C3AA}
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0} = {8904C536-C67D-420F-9971-51B26574C3AA}
{F8C3F648-EA5A-4719-8005-85D1690B1655} = {D10CA4A9-F866-40E1-B658-F69051236C71}
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A} = {D10CA4A9-F866-40E1-B658-F69051236C71}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7D436EA3-8B7E-45D2-8D14-0730BD2E0410}
SolutionGuid = {3B3A9B6C-D325-4BB3-97D3-8070630C5D3B}
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0
$0.DotNetNamingPolicy = $1
$1.DirectoryNamespaceAssociation = PrefixedHierarchical
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{971FDF07-E288-4239-B47A-E9E7E912193B} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC}
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC}
{83449CC4-1F76-4CFE-92B1-D2E13A62506F} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC}
{E71F3053-056C-4381-9638-048ED73BDFF6} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC}
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC}
{F8C3F648-EA5A-4719-8005-85D1690B1655} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC}
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6} = {BB702EBD-3B79-4ECA-A2A6-1237B07F0AF0}
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44} = {BB702EBD-3B79-4ECA-A2A6-1237B07F0AF0}
EndGlobalSection
EndGlobal

View File

@@ -67,7 +67,7 @@ Task("UpdateAndroidManifest")
.Does(()=>
{
var buildVariant = GetVariant();
var manifestPath = Path.Combine(_slnPath, "src", "Android", "Properties", "AndroidManifest.xml");
var manifestPath = Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "AndroidManifest.xml");
// Cake.AndroidAppManifest doesn't currently enable us to access nested items so, quick (not ideal) fix:
var manifestText = FileReadText(manifestPath);
@@ -119,26 +119,26 @@ Task("UpdateAndroidCodeFiles")
//We're not using _androidPackageName here because the codefile is currently slightly different string than the one in AndroidManifest.xml
var keyName = "com.8bit.bitwarden";
var fixedPackageName = buildVariant.AndroidPackageName.Replace("x8bit", "8bit");
var filePath = Path.Combine(_slnPath, "src", "Android", "Services", "BiometricService.cs");
var filePath = Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Services", "BiometricService.cs");
ReplaceInFile(filePath, keyName, fixedPackageName);
var packageFileList = new string[] {
Path.Combine(_slnPath, "src", "Android", "MainActivity.cs"),
Path.Combine(_slnPath, "src", "Android", "MainApplication.cs"),
Path.Combine(_slnPath, "src", "Android", "Constants.cs"),
Path.Combine(_slnPath, "src", "Android", "Accessibility", "AccessibilityService.cs"),
Path.Combine(_slnPath, "src", "Android", "Autofill", "AutofillHelpers.cs"),
Path.Combine(_slnPath, "src", "Android", "Autofill", "AutofillService.cs"),
Path.Combine(_slnPath, "src", "Android", "Receivers", "ClearClipboardAlarmReceiver.cs"),
Path.Combine(_slnPath, "src", "Android", "Receivers", "EventUploadReceiver.cs"),
Path.Combine(_slnPath, "src", "Android", "Receivers", "PackageReplacedReceiver.cs"),
Path.Combine(_slnPath, "src", "Android", "Receivers", "RestrictionsChangedReceiver.cs"),
Path.Combine(_slnPath, "src", "Android", "Services", "DeviceActionService.cs"),
Path.Combine(_slnPath, "src", "Android", "Services", "FileService.cs"),
Path.Combine(_slnPath, "src", "Android", "Tiles", "AutofillTileService.cs"),
Path.Combine(_slnPath, "src", "Android", "Tiles", "GeneratorTileService.cs"),
Path.Combine(_slnPath, "src", "Android", "Tiles", "MyVaultTileService.cs"),
Path.Combine(_slnPath, "src", "Android", "google-services.json"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "MainActivity.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "MainApplication.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Constants.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Accessibility", "AccessibilityService.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Autofill", "AutofillHelpers.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Autofill", "AutofillService.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Receivers", "ClearClipboardAlarmReceiver.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Receivers", "EventUploadReceiver.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Receivers", "PackageReplacedReceiver.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Receivers", "RestrictionsChangedReceiver.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Services", "DeviceActionService.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Services", "FileService.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Tiles", "AutofillTileService.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Tiles", "GeneratorTileService.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Tiles", "MyVaultTileService.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "google-services.json"),
Path.Combine(_slnPath, "store", "google", "Publisher", "Program.cs"),
};
@@ -148,7 +148,7 @@ Task("UpdateAndroidCodeFiles")
}
var labelFileList = new string[] {
Path.Combine(_slnPath, "src", "Android", "Autofill", "AutofillService.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Autofill", "AutofillService.cs"),
};
foreach(string path in labelFileList)
@@ -315,7 +315,7 @@ private void UpdateAppleIcons(string target, string appiconsetTarget)
Task("UpdateiOSIcons")
.Does(()=>{
UpdateAppleIcons("ios", Path.Combine(_slnPath, "src", "iOS", "Resources", "Assets.xcassets", "AppIcons.appiconset"));
UpdateAppleIcons("ios", Path.Combine(_slnPath, "src", "App", "Platforms", "iOS", "Resources", "Assets.xcassets", "AppIcons.appiconset"));
UpdateAppleIcons("watch", Path.Combine(_slnPath, "src", "watchOS", "bitwarden", "bitwarden WatchKit App", "Assets.xcassets", "AppIcon.appiconset"));
// TODO: Update complication icons when they start working
});
@@ -324,8 +324,8 @@ Task("UpdateiOSPlist")
.IsDependentOn("GetGitInfo")
.Does(()=> {
var buildVariant = GetVariant();
var infoPath = Path.Combine(_slnPath, "src", "iOS", "Info.plist");
var entitlementsPath = Path.Combine(_slnPath, "src", "iOS", "Entitlements.plist");
var infoPath = Path.Combine(_slnPath, "src", "App", "Platforms", "iOS", "Info.plist");
var entitlementsPath = Path.Combine(_slnPath, "src", "App", "Platforms", "iOS", "Entitlements.plist");
UpdateiOSInfoPlist(infoPath, buildVariant, _gitVersion, iOSProjectType.MainApp);
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant);
});

View File

@@ -2,9 +2,9 @@ project_id_env: _CROWDIN_PROJECT_ID
api_token_env: CROWDIN_API_TOKEN
preserve_hierarchy: true
files:
- source: /src/App/Resources/AppResources.resx
dest: /src/App/Resources/%original_file_name%
translation: /src/App/Resources/AppResources.%two_letters_code%.resx
- source: /src/Core/Resources/Localization/AppResources.resx
dest: /src/Core/Resources/Localization/%original_file_name%
translation: /src/Core/Resources/Localization/AppResources.%two_letters_code%.resx
update_option: update_as_unapproved
languages_mapping:
two_letters_code:

View File

@@ -0,0 +1,8 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>Xamarin.AndroidX.Credentials</name>
</assembly>
<members>
</members>
</doc>

7
nuget.config Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="MAUI Nightly builds" value="https://pkgs.dev.azure.com/xamarin/public/_packaging/maui-nightly/nuget/v3/index.json" />
<add key="Local AndroidX Credentials" value="lib/android/Xamarin.AndroidX.Credentials" />
</packageSources>
</configuration>

2
package-lock.json generated
View File

@@ -8,7 +8,7 @@
"name": "bitwarden-mobile",
"version": "0.0.0",
"devDependencies": {
"gh-pages": "^3.2.3"
"gh-pages": "3.2.3"
}
},
"node_modules/array-union": {

View File

@@ -6,6 +6,6 @@
"clean:l10n": "git push origin --delete l10n_master"
},
"devDependencies": {
"gh-pages": "^3.2.3"
"gh-pages": "3.2.3"
}
}

View File

@@ -1,319 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TemplateGuid>{c9e5eea5-ca05-42a1-839b-61506e0a37df}</TemplateGuid>
<OutputType>Library</OutputType>
<RootNamespace>Bit.Droid</RootNamespace>
<AssemblyName>BitwardenAndroid</AssemblyName>
<AndroidApplication>True</AndroidApplication>
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
<AndroidResgenClass>Resource</AndroidResgenClass>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
<TargetFrameworkVersion>v13.0</TargetFrameworkVersion>
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>portable</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>3</WarningLevel>
<AndroidSupportedAbis />
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugSymbols>false</DebugSymbols>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidManagedSymbols>true</AndroidManagedSymbols>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'FDroid|AnyCPU'">
<DebugSymbols>false</DebugSymbols>
<OutputPath>bin\FDroid\</OutputPath>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<DefineConstants>FDROID</DefineConstants>
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
<Reference Include="Mono.Android.Export" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" />
<Reference Include="System.Net.Http" Condition="'$(Configuration)'=='FDroid'" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Plugin.CurrentActivity">
<Version>2.1.0.4</Version>
</PackageReference>
<PackageReference Include="Portable.BouncyCastle">
<Version>1.9.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.6.1.3" />
<PackageReference Include="Xamarin.AndroidX.AutoFill" Version="1.1.0.18" />
<PackageReference Include="Xamarin.AndroidX.CardView" Version="1.0.0.21" />
<PackageReference Include="Xamarin.AndroidX.Core" Version="1.10.1.2" />
<PackageReference Include="Xamarin.AndroidX.MediaRouter" Version="1.4.0.2" />
<PackageReference Include="Xamarin.Essentials">
<Version>1.8.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.Firebase.Messaging">
<Version>123.1.2.2</Version>
</PackageReference>
<PackageReference Include="Xamarin.Google.Android.Material" Version="1.9.0.2" />
<PackageReference Include="Xamarin.Google.Dagger" Version="2.46.1.2" />
<PackageReference Include="Xamarin.GooglePlayServices.SafetyNet">
<Version>118.0.1.5</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Compile Include="Accessibility\AccessibilityActivity.cs" />
<Compile Include="Accessibility\AccessibilityHelpers.cs" />
<Compile Include="Accessibility\Credentials.cs" />
<Compile Include="Accessibility\AccessibilityService.cs" />
<Compile Include="Accessibility\Browser.cs" />
<Compile Include="Accessibility\NodeList.cs" />
<Compile Include="Accessibility\KnownUsernameField.cs" />
<Compile Include="Autofill\AutofillConstants.cs" />
<Compile Include="Autofill\AutofillHelpers.cs" />
<Compile Include="Autofill\AutofillService.cs" />
<Compile Include="Autofill\AutofillExternalSelectionActivity.cs" />
<Compile Include="Autofill\Field.cs" />
<Compile Include="Autofill\FieldCollection.cs" />
<Compile Include="Autofill\FilledItem.cs" />
<Compile Include="Autofill\Parser.cs" />
<Compile Include="Autofill\SavedItem.cs" />
<Compile Include="Effects\FabShadowEffect.cs" />
<Compile Include="Effects\FixedSizeEffect.cs" />
<Compile Include="Effects\TabBarEffect.cs" />
<Compile Include="Push\FirebaseMessagingService.cs" />
<Compile Include="Receivers\ClearClipboardAlarmReceiver.cs" />
<Compile Include="Receivers\RestrictionsChangedReceiver.cs" />
<Compile Include="Receivers\EventUploadReceiver.cs" />
<Compile Include="Receivers\PackageReplacedReceiver.cs" />
<Compile Include="Renderers\ExtendedGridRenderer.cs" />
<Compile Include="Renderers\ExtendedDatePickerRenderer.cs" />
<Compile Include="Renderers\CustomTabbedRenderer.cs" />
<Compile Include="Renderers\ExtendedStackLayoutRenderer.cs" />
<Compile Include="Renderers\ExtendedStepperRenderer.cs" />
<Compile Include="Renderers\CustomSwitchRenderer.cs" />
<Compile Include="Renderers\ExtendedTimePickerRenderer.cs" />
<Compile Include="Renderers\ExtendedSliderRenderer.cs" />
<Compile Include="Renderers\CustomEditorRenderer.cs" />
<Compile Include="Renderers\CustomPickerRenderer.cs" />
<Compile Include="Renderers\CustomEntryRenderer.cs" />
<Compile Include="Renderers\CustomSearchBarRenderer.cs" />
<Compile Include="Renderers\HybridWebViewRenderer.cs" />
<Compile Include="Services\AndroidPushNotificationService.cs" />
<Compile Include="Services\AndroidLogService.cs" />
<Compile Include="MainApplication.cs" />
<Compile Include="MainActivity.cs" />
<Compile Include="Resources\Resource.designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\BiometricService.cs" />
<Compile Include="Services\CryptoPrimitiveService.cs" />
<Compile Include="Services\DeviceActionService.cs" />
<Compile Include="Services\LocalizeService.cs" />
<Compile Include="Tiles\AutofillTileService.cs" />
<Compile Include="Tiles\GeneratorTileService.cs" />
<Compile Include="Tiles\MyVaultTileService.cs" />
<Compile Include="Utilities\AndroidHelpers.cs" />
<Compile Include="Utilities\ThemeHelpers.cs" />
<Compile Include="WebAuthCallbackActivity.cs" />
<Compile Include="Renderers\SelectableLabelRenderer.cs" />
<Compile Include="Services\ClipboardService.cs" />
<Compile Include="Utilities\IntentExtensions.cs" />
<Compile Include="Renderers\CustomPageRenderer.cs" />
<Compile Include="Effects\NoEmojiKeyboardEffect.cs" />
<Compile Include="Receivers\NotificationDismissReceiver.cs" />
<Compile Include="Services\FileService.cs" />
<Compile Include="Services\AutofillHandler.cs" />
<Compile Include="Constants.cs" />
<Compile Include="Effects\RemoveFontPaddingEffect.cs" />
<Compile Include="Services\WatchDeviceService.cs" />
<Compile Include="Renderers\CustomLabelRenderer.cs" />
</ItemGroup>
<ItemGroup>
<AndroidAsset Include="Assets\bwi-font.ttf" />
<AndroidAsset Include="Assets\RobotoMono_Regular.ttf" />
<AndroidAsset Include="Assets\MaterialIcons_Regular.ttf" />
<None Include="8bit.keystore.enc" />
<GoogleServicesJson Include="google-services.json" />
<GoogleServicesJson Include="google-services.json.enc" />
<None Include="fdroid-keystore.jks.enc" />
<AndroidNativeLibrary Include="lib\arm64-v8a\libargon2.so" />
<AndroidNativeLibrary Include="lib\armeabi-v7a\libargon2.so" />
<AndroidNativeLibrary Include="lib\x86\libargon2.so" />
<AndroidNativeLibrary Include="lib\x86_64\libargon2.so" />
<None Include="Properties\AndroidManifest.xml" />
<None Include="upload-keystore.jks.enc" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\logo_legacy.png" />
<AndroidResource Include="Resources\drawable-hdpi\logo_white_legacy.png" />
<AndroidResource Include="Resources\drawable-xhdpi\logo_legacy.png" />
<AndroidResource Include="Resources\drawable-xhdpi\logo_white_legacy.png" />
<AndroidResource Include="Resources\drawable-xxhdpi\logo_legacy.png" />
<AndroidResource Include="Resources\drawable-xxhdpi\logo_white_legacy.png" />
<AndroidResource Include="Resources\drawable\card.xml" />
<AndroidResource Include="Resources\drawable\cog_environment.xml" />
<AndroidResource Include="Resources\drawable\cog_settings.xml" />
<AndroidResource Include="Resources\drawable\icon.xml" />
<AndroidResource Include="Resources\drawable\ic_launcher_foreground.xml" />
<AndroidResource Include="Resources\drawable\ic_launcher_monochrome.xml" />
<AndroidResource Include="Resources\drawable\ic_warning.xml" />
<AndroidResource Include="Resources\drawable\id.xml" />
<AndroidResource Include="Resources\drawable\info.xml" />
<AndroidResource Include="Resources\drawable\list_item_bg.xml" />
<AndroidResource Include="Resources\drawable\lock.xml" />
<AndroidResource Include="Resources\drawable\login.xml" />
<AndroidResource Include="Resources\drawable\logo.xml" />
<AndroidResource Include="Resources\drawable\logo_white.xml" />
<AndroidResource Include="Resources\drawable\send.xml" />
<AndroidResource Include="Resources\drawable\pencil.xml" />
<AndroidResource Include="Resources\drawable\plus.xml" />
<AndroidResource Include="Resources\drawable\generate.xml" />
<AndroidResource Include="Resources\drawable\search.xml" />
<AndroidResource Include="Resources\drawable\shield.xml" />
<AndroidResource Include="Resources\drawable-v23\splash_screen.xml" />
<AndroidResource Include="Resources\drawable-v23\splash_screen_dark.xml" />
<AndroidResource Include="Resources\drawable\switch_thumb.xml" />
<AndroidResource Include="Resources\layout\progress_dialog_layout.xml" />
<AndroidResource Include="Resources\layout\Tabbar.axml" />
<AndroidResource Include="Resources\layout\Toolbar.axml" />
<AndroidResource Include="Resources\mipmap-anydpi-v26\ic_launcher.xml" />
<AndroidResource Include="Resources\mipmap-anydpi-v26\ic_launcher_round.xml" />
<AndroidResource Include="Resources\mipmap-hdpi\ic_launcher.png" />
<AndroidResource Include="Resources\mipmap-hdpi\ic_launcher_round.png" />
<AndroidResource Include="Resources\mipmap-mdpi\ic_launcher.png" />
<AndroidResource Include="Resources\mipmap-mdpi\ic_launcher_round.png" />
<AndroidResource Include="Resources\mipmap-xhdpi\ic_launcher.png" />
<AndroidResource Include="Resources\mipmap-xhdpi\ic_launcher_round.png" />
<AndroidResource Include="Resources\mipmap-xxhdpi\ic_launcher.png" />
<AndroidResource Include="Resources\mipmap-xxhdpi\ic_launcher_round.png" />
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher.png" />
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher_round.png" />
<AndroidResource Include="Resources\values-night\styles.xml" />
<AndroidResource Include="Resources\values\styles.xml" />
<AndroidResource Include="Resources\values\colors.xml" />
<AndroidResource Include="Resources\values\manifest.xml" />
<AndroidResource Include="Resources\values-v30\manifest.xml" />
<AndroidResource Include="Resources\drawable-v26\splash_screen_round.xml" />
<AndroidResource Include="Resources\drawable\logo_rounded.xml" />
<AndroidResource Include="Resources\drawable-night-v26\splash_screen_round.xml" />
<AndroidResource Include="Resources\drawable\ic_notification.xml">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\layout\validatable_input_dialog_layout.xml">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\drawable\empty_uris_placeholder.xml">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\drawable\empty_uris_placeholder_dark.xml">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\splash_screen.xml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\App\App.csproj">
<Project>{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}</Project>
<Name>App</Name>
</ProjectReference>
<ProjectReference Include="..\Core\Core.csproj">
<Project>{4b8a8c41-9820-4341-974c-41e65b7f4366}</Project>
<Name>Core</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\xml\accessibilityservice.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\xml\autofillservice.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\xml\filepaths.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\xml\network_security_config.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\values\strings.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\values\ic_launcher_background.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\autofill_listitem.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\yubikey.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\yubikey.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\yubikey.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\slider_thumb.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\splash_screen_dark.xml">
<Generator>MSBuild:UpdateGeneratedFiles</Generator>
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\values\dimens.xml">
<Generator>MSBuild:UpdateGeneratedFiles</Generator>
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\xml\app_restrictions.xml">
<Generator>MSBuild:UpdateGeneratedFiles</Generator>
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\values-v30\" />
<Folder Include="Resources\drawable-v26\" />
<Folder Include="Resources\drawable-night-v26\" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
</Project>

View File

@@ -1,7 +0,0 @@
namespace Bit.Droid
{
public static class Constants
{
public const string PACKAGE_NAME = "com.x8bit.bitwarden";
}
}

View File

@@ -1,30 +0,0 @@
using Android.Graphics.Drawables;
using Bit.Droid.Effects;
using Bit.Droid.Utilities;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportEffect(typeof(FabShadowEffect), "FabShadowEffect")]
namespace Bit.Droid.Effects
{
public class FabShadowEffect : PlatformEffect
{
protected override void OnAttached ()
{
if (Control is Android.Widget.Button button)
{
var gd = new GradientDrawable();
gd.SetColor(ThemeHelpers.FabColor);
gd.SetCornerRadius(100);
button.SetBackground(gd);
button.Elevation = 6;
button.TranslationZ = 20;
}
}
protected override void OnDetached ()
{
}
}
}

View File

@@ -1,23 +0,0 @@
using Android.Widget;
using Bit.Droid.Effects;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportEffect(typeof(FixedSizeEffect), "FixedSizeEffect")]
namespace Bit.Droid.Effects
{
public class FixedSizeEffect : PlatformEffect
{
protected override void OnAttached()
{
if (Element is Label label && Control is TextView textView)
{
textView.SetTextSize(Android.Util.ComplexUnitType.Pt, (float)label.FontSize);
}
}
protected override void OnDetached()
{
}
}
}

View File

@@ -1,23 +0,0 @@
using Android.Widget;
using Bit.Droid.Effects;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportEffect(typeof(RemoveFontPaddingEffect), nameof(RemoveFontPaddingEffect))]
namespace Bit.Droid.Effects
{
public class RemoveFontPaddingEffect : PlatformEffect
{
protected override void OnAttached()
{
if (Control is TextView textView)
{
textView.SetIncludeFontPadding(false);
}
}
protected override void OnDetached()
{
}
}
}

View File

@@ -1,30 +0,0 @@
using Android.Views;
using Bit.Droid.Effects;
using Google.Android.Material.BottomNavigation;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ResolutionGroupName("Bitwarden")]
[assembly: ExportEffect(typeof(TabBarEffect), "TabBarEffect")]
namespace Bit.Droid.Effects
{
public class TabBarEffect : PlatformEffect
{
protected override void OnAttached()
{
if (!(Container.GetChildAt(0) is ViewGroup layout))
{
return;
}
if (!(layout.GetChildAt(1) is BottomNavigationView bottomNavigationView))
{
return;
}
bottomNavigationView.LabelVisibilityMode = LabelVisibilityMode.LabelVisibilityLabeled;
}
protected override void OnDetached()
{
}
}
}

View File

@@ -1,28 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("BitwardenAndroid")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Bitwarden Inc.")]
[assembly: AssemblyProduct("Bitwarden")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -1,69 +0,0 @@
using System.ComponentModel;
using Android.Content;
using Android.Content.Res;
using Android.Views.InputMethods;
using Bit.Droid.Renderers;
using Bit.Droid.Utilities;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(Editor), typeof(CustomEditorRenderer))]
namespace Bit.Droid.Renderers
{
public class CustomEditorRenderer : EditorRenderer
{
public CustomEditorRenderer(Context context)
: base(context)
{ }
// Workaround for issue described here:
// https://github.com/xamarin/Xamarin.Forms/issues/8291#issuecomment-617456651
protected override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
EditText.Enabled = false;
EditText.Enabled = true;
}
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
UpdateBorderColor();
if (Control != null && e.NewElement != null)
{
Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight,
Control.PaddingBottom + 20);
Control.ImeOptions = Control.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning |
(ImeAction)ImeFlags.NoExtractUi;
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == Entry.TextColorProperty.PropertyName)
{
UpdateBorderColor();
}
}
private void UpdateBorderColor()
{
if (Control != null)
{
var states = new[]
{
new[] { Android.Resource.Attribute.StateFocused }, // focused
new[] { -Android.Resource.Attribute.StateFocused }, // unfocused
};
var colors = new int[]
{
ThemeHelpers.PrimaryColor,
ThemeHelpers.MutedColor
};
Control.BackgroundTintList = new ColorStateList(states, colors);
}
}
}
}

View File

@@ -1,107 +0,0 @@
using System.ComponentModel;
using Android.Content;
using Android.Content.Res;
using Android.Graphics;
using Android.Text;
using Android.Views.InputMethods;
using Android.Widget;
using Bit.Droid.Renderers;
using Bit.Droid.Utilities;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(Entry), typeof(CustomEntryRenderer))]
namespace Bit.Droid.Renderers
{
public class CustomEntryRenderer : EntryRenderer
{
public CustomEntryRenderer(Context context)
: base(context)
{ }
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
UpdateBorderColor();
if (Control != null && e.NewElement != null)
{
Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight,
Control.PaddingBottom + 20);
Control.ImeOptions = Control.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning |
(ImeAction)ImeFlags.NoExtractUi;
}
}
// Workaround for bug preventing long-press -> copy/paste on Android 11
// See https://issuetracker.google.com/issues/37095917
protected override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
Control.Enabled = false;
Control.Enabled = true;
}
// Workaround for failure to disable text prediction on non-password fields
// see https://github.com/xamarin/Xamarin.Forms/issues/10857
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
// Check if changed property is "IsPassword", otherwise ignore
if (e.PropertyName == Entry.IsPasswordProperty.PropertyName)
{
// Check if field type is text, otherwise ignore (numeric passwords, etc.)
EditText.InputType = Element.Keyboard.ToInputType();
bool isText = (EditText.InputType & InputTypes.ClassText) == InputTypes.ClassText,
isNumber = (EditText.InputType & InputTypes.ClassNumber) == InputTypes.ClassNumber;
if (isText || isNumber)
{
if (Element.IsPassword)
{
// Element is a password field, set inputType to TextVariationPassword which disables
// predictive text by default
EditText.InputType = EditText.InputType |
(isText ? InputTypes.TextVariationPassword : InputTypes.NumberVariationPassword);
}
else
{
// Element is not a password field, set inputType to TextVariationVisiblePassword to
// disable predictive text while still displaying the content.
EditText.InputType = EditText.InputType |
(isText ? InputTypes.TextVariationVisiblePassword : InputTypes.NumberVariationNormal);
}
// The workaround above forces a reset of the style properties, so we need to re-apply the font.
// see https://xamarin.github.io/bugzilla-archives/33/33666/bug.html
var typeface = Typeface.CreateFromAsset(Context.Assets, "RobotoMono_Regular.ttf");
if (Control is TextView label)
{
label.Typeface = typeface;
}
}
}
else if (e.PropertyName == Entry.TextColorProperty.PropertyName)
{
UpdateBorderColor();
}
}
private void UpdateBorderColor()
{
if (Control != null)
{
var states = new[]
{
new[] { Android.Resource.Attribute.StateFocused }, // focused
new[] { -Android.Resource.Attribute.StateFocused }, // unfocused
};
var colors = new int[]
{
ThemeHelpers.PrimaryColor,
ThemeHelpers.MutedColor
};
Control.BackgroundTintList = new ColorStateList(states, colors);
}
}
}
}

View File

@@ -1,43 +0,0 @@
using System.ComponentModel;
using Android.Content;
using Android.OS;
using Bit.App.Controls;
using Bit.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(CustomLabel), typeof(CustomLabelRenderer))]
namespace Bit.Droid.Renderers
{
public class CustomLabelRenderer : LabelRenderer
{
public CustomLabelRenderer(Context context)
: base(context)
{ }
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
if (Control != null && e.NewElement is CustomLabel label)
{
if (label.FontWeight.HasValue && Build.VERSION.SdkInt >= BuildVersionCodes.P)
{
Control.Typeface = Android.Graphics.Typeface.Create(null, label.FontWeight.Value, false);
}
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var label = sender as CustomLabel;
switch (e.PropertyName)
{
case nameof(CustomLabel.AutomationId):
Control.ContentDescription = label.AutomationId;
break;
}
base.OnElementPropertyChanged(sender, e);
}
}
}

View File

@@ -1,31 +0,0 @@
using System;
using Android.App;
using Android.Content;
using AndroidX.AppCompat.Widget;
using Bit.App.Resources;
using Bit.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(ContentPage), typeof(CustomPageRenderer))]
namespace Bit.Droid.Renderers
{
public class CustomPageRenderer : PageRenderer
{
public CustomPageRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
Activity context = (Activity)this.Context;
var toolbar = context.FindViewById<Toolbar>(Resource.Id.toolbar);
if(toolbar != null)
{
toolbar.NavigationContentDescription = AppResources.TapToGoBack;
}
}
}
}

View File

@@ -1,57 +0,0 @@
using System.ComponentModel;
using Android.Content;
using Android.Content.Res;
using Bit.Droid.Renderers;
using Bit.Droid.Utilities;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(Picker), typeof(CustomPickerRenderer))]
namespace Bit.Droid.Renderers
{
public class CustomPickerRenderer : PickerRenderer
{
public CustomPickerRenderer(Context context)
: base(context)
{ }
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
UpdateBorderColor();
if (Control != null && e.NewElement != null)
{
Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight,
Control.PaddingBottom + 20);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == Picker.TextColorProperty.PropertyName)
{
UpdateBorderColor();
}
}
private void UpdateBorderColor()
{
if (Control != null)
{
var states = new[]
{
new[] { Android.Resource.Attribute.StateFocused }, // focused
new[] { -Android.Resource.Attribute.StateFocused }, // unfocused
};
var colors = new int[]
{
ThemeHelpers.PrimaryColor,
ThemeHelpers.MutedColor
};
Control.BackgroundTintList = new ColorStateList(states, colors);
}
}
}
}

View File

@@ -1,33 +0,0 @@
using Android.Content;
using Android.Views.InputMethods;
using Bit.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(SearchBar), typeof(CustomSearchBarRenderer))]
namespace Bit.Droid.Renderers
{
public class CustomSearchBarRenderer : SearchBarRenderer
{
public CustomSearchBarRenderer(Context context)
: base(context)
{ }
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
if (Control != null && e.NewElement != null)
{
try
{
var magId = Resources.GetIdentifier("android:id/search_mag_icon", null, null);
var magImage = (Android.Widget.ImageView)Control.FindViewById(magId);
magImage.LayoutParameters = new Android.Widget.LinearLayout.LayoutParams(0, 0);
}
catch { }
Control.SetImeOptions(Control.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning |
(ImeAction)ImeFlags.NoExtractUi);
}
}
}
}

View File

@@ -1,67 +0,0 @@
using System.ComponentModel;
using Android.Content;
using Android.Content.Res;
using Android.Graphics.Drawables;
using Android.OS;
using AndroidX.Core.Content.Resources;
using Bit.Droid.Renderers;
using Bit.Droid.Utilities;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(Switch), typeof(CustomSwitchRenderer))]
namespace Bit.Droid.Renderers
{
public class CustomSwitchRenderer : SwitchRenderer
{
public CustomSwitchRenderer(Context context)
: base(context)
{}
protected override void OnElementChanged(ElementChangedEventArgs<Switch> e)
{
base.OnElementChanged(e);
UpdateColors();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == Switch.OnColorProperty.PropertyName)
{
UpdateColors();
}
}
private void UpdateColors()
{
if (Build.VERSION.SdkInt <= BuildVersionCodes.LollipopMr1)
{
// Android 5.x doesn't support ThumbTintList, and using SwitchCompat on every version after 5.x
// doesn't apply tinting the way we want. Let 5.x to do its own thing here.
return;
}
if (Control != null)
{
Control.SetHintTextColor(ThemeHelpers.MutedColor);
var t = ResourcesCompat.GetDrawable(Resources, Resource.Drawable.switch_thumb, null);
if (t is GradientDrawable thumb)
{
Control.ThumbDrawable = thumb;
}
var thumbStates = new[]
{
new[] { Android.Resource.Attribute.StateChecked }, // checked
new[] { -Android.Resource.Attribute.StateChecked }, // unchecked
};
var thumbColors = new int[]
{
ThemeHelpers.SwitchOnColor,
ThemeHelpers.SwitchThumbColor
};
Control.ThumbTintList = new ColorStateList(thumbStates, thumbColors);
}
}
}
}

View File

@@ -1,66 +0,0 @@
using Android.Content;
using Android.Views;
using Bit.App.Pages;
using Bit.Droid.Renderers;
using Google.Android.Material.BottomNavigation;
using Google.Android.Material.Navigation;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms.Platform.Android.AppCompat;
[assembly: ExportRenderer(typeof(TabbedPage), typeof(CustomTabbedRenderer))]
namespace Bit.Droid.Renderers
{
public class CustomTabbedRenderer : TabbedPageRenderer, NavigationBarView.IOnItemReselectedListener
{
private TabbedPage _page;
public CustomTabbedRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
_page = e.NewElement;
GetBottomNavigationView()?.SetOnItemReselectedListener(this);
}
else
{
_page = e.OldElement;
}
}
private BottomNavigationView GetBottomNavigationView()
{
for (var i = 0; i < ViewGroup.ChildCount; i++)
{
var childView = ViewGroup.GetChildAt(i);
if (childView is ViewGroup viewGroup)
{
for (var j = 0; j < viewGroup.ChildCount; j++)
{
var childRelativeLayoutView = viewGroup.GetChildAt(j);
if (childRelativeLayoutView is BottomNavigationView bottomNavigationView)
{
return bottomNavigationView;
}
}
}
}
return null;
}
public void OnNavigationItemReselected(IMenuItem item)
{
if (_page?.CurrentPage?.Navigation != null && _page.CurrentPage.Navigation.NavigationStack.Count > 0)
{
if (_page is TabsPage tabsPage)
{
tabsPage.OnPageReselected();
}
Device.BeginInvokeOnMainThread(async () => await _page.CurrentPage.Navigation.PopToRootAsync());
}
}
}
}

View File

@@ -1,50 +0,0 @@
using System.ComponentModel;
using Android.Content;
using Android.Views;
using Bit.App.Controls;
using Bit.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(ExtendedDatePicker), typeof(ExtendedDatePickerRenderer))]
namespace Bit.Droid.Renderers
{
public class ExtendedDatePickerRenderer : DatePickerRenderer
{
public ExtendedDatePickerRenderer(Context context)
: base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
{
base.OnElementChanged(e);
if (Control != null && Element is ExtendedDatePicker element)
{
// center text
Control.Gravity = GravityFlags.CenterHorizontal;
// use placeholder until NullableDate set
if (!element.NullableDate.HasValue)
{
Control.Text = element.PlaceHolder;
}
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == DatePicker.DateProperty.PropertyName ||
e.PropertyName == DatePicker.FormatProperty.PropertyName)
{
if (Control != null && Element is ExtendedDatePicker element)
{
if (Element.Format == element.PlaceHolder)
{
Control.Text = element.PlaceHolder;
return;
}
}
}
base.OnElementPropertyChanged(sender, e);
}
}
}

View File

@@ -1,23 +0,0 @@
using Android.Content;
using Bit.App.Controls;
using Bit.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(ExtendedGrid), typeof(ExtendedGridRenderer))]
namespace Bit.Droid.Renderers
{
public class ExtendedGridRenderer : ViewRenderer
{
public ExtendedGridRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<View> elementChangedEvent)
{
base.OnElementChanged(elementChangedEvent);
if (elementChangedEvent.NewElement != null)
{
SetBackgroundResource(Resource.Drawable.list_item_bg);
}
}
}
}

View File

@@ -1,56 +0,0 @@
using System.ComponentModel;
using Android.Content;
using Android.Graphics.Drawables;
using AndroidX.Core.Content.Resources;
using Bit.App.Controls;
using Bit.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(ExtendedSlider), typeof(ExtendedSliderRenderer))]
namespace Bit.Droid.Renderers
{
public class ExtendedSliderRenderer : SliderRenderer
{
public ExtendedSliderRenderer(Context context)
: base(context)
{}
protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
{
base.OnElementChanged(e);
UpdateColor();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == ExtendedSlider.ThumbBorderColorProperty.PropertyName)
{
UpdateColor();
}
}
private void UpdateColor()
{
if (Control != null && Element is ExtendedSlider view)
{
var t = ResourcesCompat.GetDrawable(Resources, Resource.Drawable.slider_thumb, null);
if (t is GradientDrawable thumb)
{
if (view.ThumbColor == Color.Default)
{
thumb.SetColor(Color.White.ToAndroid());
}
else
{
thumb.SetColor(view.ThumbColor.ToAndroid());
}
thumb.SetStroke(3, view.ThumbBorderColor.ToAndroid());
Control.SetThumb(thumb);
}
}
}
}
}

View File

@@ -1,23 +0,0 @@
using Android.Content;
using Bit.App.Controls;
using Bit.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(ExtendedStackLayout), typeof(ExtendedStackLayoutRenderer))]
namespace Bit.Droid.Renderers
{
public class ExtendedStackLayoutRenderer : ViewRenderer
{
public ExtendedStackLayoutRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<View> elementChangedEvent)
{
base.OnElementChanged(elementChangedEvent);
if (elementChangedEvent.NewElement != null)
{
SetBackgroundResource(Resource.Drawable.list_item_bg);
}
}
}
}

View File

@@ -1,72 +0,0 @@
using System.ComponentModel;
using Android.Content;
using Android.Graphics;
using Android.OS;
using Bit.App.Controls;
using Bit.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(ExtendedStepper), typeof(ExtendedStepperRenderer))]
namespace Bit.Droid.Renderers
{
public class ExtendedStepperRenderer : StepperRenderer
{
public ExtendedStepperRenderer(Context context)
: base(context)
{}
protected override void OnElementChanged(ElementChangedEventArgs<Stepper> e)
{
base.OnElementChanged(e);
UpdateBgColor();
UpdateFgColor();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == ExtendedStepper.StepperBackgroundColorProperty.PropertyName)
{
UpdateBgColor();
}
else if (e.PropertyName == ExtendedStepper.StepperForegroundColorProperty.PropertyName)
{
UpdateFgColor();
}
}
private void UpdateBgColor()
{
if (Control != null && Element is ExtendedStepper view)
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.Q)
{
Control.GetChildAt(0)?.Background?.SetColorFilter(
new BlendModeColorFilter(view.StepperBackgroundColor.ToAndroid(), BlendMode.Multiply));
Control.GetChildAt(1)?.Background?.SetColorFilter(
new BlendModeColorFilter(view.StepperBackgroundColor.ToAndroid(), BlendMode.Multiply));
}
else
{
Control.GetChildAt(0)?.Background?.SetColorFilter(
view.StepperBackgroundColor.ToAndroid(), PorterDuff.Mode.Multiply);
Control.GetChildAt(1)?.Background?.SetColorFilter(
view.StepperBackgroundColor.ToAndroid(), PorterDuff.Mode.Multiply);
}
}
}
private void UpdateFgColor()
{
if (Control != null && Element is ExtendedStepper view)
{
var btn0 = Control.GetChildAt(0) as Android.Widget.Button;
btn0?.SetTextColor(view.StepperForegroundColor.ToAndroid());
var btn1 = Control.GetChildAt(1) as Android.Widget.Button;
btn1?.SetTextColor(view.StepperForegroundColor.ToAndroid());
}
}
}
}

View File

@@ -1,50 +0,0 @@
using System.ComponentModel;
using Android.Content;
using Android.Views;
using Bit.App.Controls;
using Bit.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(ExtendedTimePicker), typeof(ExtendedTimePickerRenderer))]
namespace Bit.Droid.Renderers
{
public class ExtendedTimePickerRenderer : TimePickerRenderer
{
public ExtendedTimePickerRenderer(Context context)
: base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
{
base.OnElementChanged(e);
if (Control != null && Element is ExtendedTimePicker element)
{
// center text
Control.Gravity = GravityFlags.CenterHorizontal;
// use placeholder until NullableTime set
if (!element.NullableTime.HasValue)
{
Control.Text = element.PlaceHolder;
}
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == TimePicker.TimeProperty.PropertyName ||
e.PropertyName == TimePicker.FormatProperty.PropertyName)
{
if (Control != null && Element is ExtendedTimePicker element)
{
if (Element.Format == element.PlaceHolder)
{
Control.Text = element.PlaceHolder;
return;
}
}
}
base.OnElementPropertyChanged(sender, e);
}
}
}

View File

@@ -1,98 +0,0 @@
using System;
using Bit.App.Controls;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Android.Webkit;
using AWebkit = Android.Webkit;
using Java.Interop;
using Android.Content;
using Bit.Droid.Renderers;
using System.ComponentModel;
[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace Bit.Droid.Renderers
{
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, AWebkit.WebView>
{
private const string JSFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}";
private readonly Context _context;
public HybridWebViewRenderer(Context context)
: base(context)
{
_context = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
var webView = new AWebkit.WebView(_context);
webView.Settings.JavaScriptEnabled = true;
webView.SetWebViewClient(new JSWebViewClient(string.Format("javascript: {0}", JSFunction)));
SetNativeControl(webView);
}
if (e.OldElement != null)
{
Control.RemoveJavascriptInterface("jsBridge");
var hybridWebView = e.OldElement as HybridWebView;
hybridWebView.Cleanup();
}
if (e.NewElement != null)
{
Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
Control.LoadUrl(Element.Uri);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == HybridWebView.UriProperty.PropertyName)
{
Control.LoadUrl(Element.Uri);
}
}
public class JSBridge : Java.Lang.Object
{
private readonly WeakReference<HybridWebViewRenderer> _hybridWebViewRenderer;
public JSBridge(HybridWebViewRenderer hybridRenderer)
{
_hybridWebViewRenderer = new WeakReference<HybridWebViewRenderer>(hybridRenderer);
}
[JavascriptInterface]
[Export("invokeAction")]
public void InvokeAction(string data)
{
if (_hybridWebViewRenderer != null &&
_hybridWebViewRenderer.TryGetTarget(out HybridWebViewRenderer hybridRenderer))
{
hybridRenderer.Element.InvokeAction(data);
}
}
}
public class JSWebViewClient : WebViewClient
{
private readonly string _javascript;
public JSWebViewClient(string javascript)
{
_javascript = javascript;
}
public override void OnPageFinished(AWebkit.WebView view, string url)
{
base.OnPageFinished(view, url);
view.EvaluateJavascript(_javascript, null);
}
}
}
}

View File

@@ -1,25 +0,0 @@
using System;
using Android.Content;
using Bit.App.Controls;
using Bit.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(SelectableLabel), typeof(SelectableLabelRenderer))]
namespace Bit.Droid.Renderers
{
public class SelectableLabelRenderer : LabelRenderer
{
public SelectableLabelRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.SetTextIsSelectable(true);
}
}
}
}

View File

@@ -1,448 +1,261 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<RootNamespace>Bit.App</RootNamespace>
<AssemblyName>BitwardenApp</AssemblyName>
<Configurations>Debug;Release;FDroid</Configurations>
<PropertyGroup>
<TargetFrameworks>net8.0-android;net8.0-ios</TargetFrameworks>
<!-- Uncomment to also build for Windows platform.-->
<!--<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>-->
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
<OutputType>Exe</OutputType>
<RootNamespace>Bit.App</RootNamespace>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<!-- Display name -->
<ApplicationTitle>Bitwarden</ApplicationTitle>
<!-- App Identifier -->
<ApplicationId Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">com.8bit.bitwarden</ApplicationId>
<ApplicationId Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">com.x8bit.bitwarden</ApplicationId>
<ApplicationIdGuid>ccf4766c-a36c-4647-900c-0ea7d323ccc6</ApplicationIdGuid>
<!-- Versions -->
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">11.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<ForceSimulatorX64ArchitectureInIDE>true</ForceSimulatorX64ArchitectureInIDE>
</PropertyGroup>
<PropertyGroup>
<DefineConstants Condition=" '$(CustomConstants)' != '' ">$(DefineConstants);$(CustomConstants)</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>pdbonly</DebugType>
<DebugSymbols>true</DebugSymbols>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-android|AnyCPU'">
<AndroidEnableMultiDex>True</AndroidEnableMultiDex>
<UseInterpreter>False</UseInterpreter>
<DebugSymbols>True</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Plugin.Fingerprint" Version="2.1.5" />
<PackageReference Include="SkiaSharp.Views.Forms" Version="2.88.3" />
<PackageReference Include="Xamarin.CommunityToolkit" Version="2.0.6" />
<PackageReference Include="Xamarin.Essentials" Version="1.8.0" />
<PackageReference Include="Xamarin.FFImageLoading.Forms" Version="2.4.11.982" />
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2612" />
<PackageReference Include="ZXing.Net.Mobile" Version="2.4.1" />
<PackageReference Include="ZXing.Net.Mobile.Forms" Version="2.4.1" />
<PackageReference Include="MessagePack" Version="2.4.59" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Core\Core.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Pages\Accounts\EnvironmentPage.xaml.cs">
<DependentUpon>EnvironmentPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Accounts\HintPage.xaml.cs">
<DependentUpon>HintPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Accounts\LockPage.xaml.cs">
<DependentUpon>LockPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Accounts\TwoFactorPage.xaml.cs">
<DependentUpon>TwoFactorPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Accounts\RegisterPage.xaml.cs">
<DependentUpon>RegisterPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Accounts\LoginPage.xaml.cs">
<DependentUpon>LoginPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Generator\GeneratorPage.xaml.cs">
<DependentUpon>GeneratorPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Generator\GeneratorHistoryPage.xaml.cs">
<DependentUpon>GeneratorHistoryPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Settings\AutofillPage.xaml.cs">
<DependentUpon>AutofillPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Settings\ExtensionPage.xaml.cs">
<DependentUpon>ExtensionPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Settings\AutofillServicesPage.xaml.cs">
<DependentUpon>AutofillServicesPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Settings\FolderAddEditPage.xaml.cs">
<DependentUpon>FolderAddEditPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Settings\FoldersPage.xaml.cs">
<DependentUpon>FoldersPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Settings\ExportVaultPage.xaml.cs">
<DependentUpon>ExportVaultPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Settings\OptionsPage.xaml.cs">
<DependentUpon>OptionsPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Settings\SyncPage.xaml.cs">
<DependentUpon>SyncPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Vault\AttachmentsPage.xaml.cs">
<DependentUpon>AttachmentsPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Vault\AutofillCiphersPage.xaml.cs">
<DependentUpon>AutofillCiphersPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Vault\CollectionsPage.xaml.cs">
<DependentUpon>CollectionsPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Vault\ScanPage.xaml.cs">
<DependentUpon>ScanPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Vault\SharePage.xaml.cs">
<DependentUpon>SharePage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Vault\CiphersPage.xaml.cs">
<DependentUpon>CiphersPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Vault\PasswordHistoryPage.xaml.cs">
<DependentUpon>PasswordHistoryPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Vault\CipherDetailsPage.xaml.cs">
<DependentUpon>CipherDetailsPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Vault\CipherAddEditPage.xaml.cs">
<DependentUpon>CipherAddEditPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Settings\SettingsPage\SettingsPage.xaml.cs">
<DependentUpon>SettingsPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Vault\GroupingsPage\GroupingsPage.xaml.cs">
<DependentUpon>GroupingsPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Accounts\LoginSsoPage.xaml.cs">
<DependentUpon>LoginSsoPage.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Update="Pages\Accounts\SetPasswordPage.xaml.cs">
<DependentUpon>ResetMasterPasswordPage.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Update="Pages\Send\SendGroupingsPage\SendGroupingsPage.xaml.cs">
<DependentUpon>SendGroupingsPage.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Remove="Pages\Accounts\AccountsPopupPage.xaml.cs" />
<Compile Update="Pages\Accounts\LoginPasswordlessPage.xaml.cs">
<DependentUpon>LoginPasswordlessPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Accounts\LoginPasswordlessRequestPage.xaml.cs">
<DependentUpon>LoginPasswordlessRequestPage.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\" />
<Folder Include="Behaviors\" />
<Folder Include="Lists\" />
<Folder Include="Lists\ItemLayouts\" />
<Folder Include="Lists\DataTemplateSelectors\" />
<Folder Include="Lists\ItemLayouts\CustomFields\" />
<Folder Include="Lists\ItemViewModels\" />
<Folder Include="Lists\ItemViewModels\CustomFields\" />
<Folder Include="Controls\AccountSwitchingOverlay\" />
<Folder Include="Utilities\AccountManagement\" />
<Folder Include="Controls\DateTime\" />
<Folder Include="Controls\IconLabelButton\" />
<Folder Include="Controls\PasswordStrengthProgressBar\" />
<Folder Include="Utilities\Automation\" />
<Folder Include="Utilities\Prompts\" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="Pages\Accounts\AccountsPopupPage.xaml" />
</ItemGroup>
<ItemGroup>
<Compile Update="Styles\Black.xaml.cs">
<DependentUpon>Black.xaml</DependentUpon>
</Compile>
<Compile Update="Styles\Nord.xaml.cs">
<DependentUpon>Nord.xaml</DependentUpon>
</Compile>
<Compile Update="Styles\Variables.xaml.cs">
<DependentUpon>Variables.xaml</DependentUpon>
</Compile>
<Compile Update="Styles\Light.xaml.cs">
<DependentUpon>Light.xaml</DependentUpon>
</Compile>
<Compile Update="Styles\Dark.xaml.cs">
<DependentUpon>Dark.xaml</DependentUpon>
</Compile>
<Compile Update="Styles\iOS.xaml.cs">
<DependentUpon>iOS.xaml</DependentUpon>
</Compile>
<Compile Update="Styles\Android.xaml.cs">
<DependentUpon>Android.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Update="Resources\AppResources.cs.Designer.cs">
<DependentUpon>AppResources.cs.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.da.Designer.cs">
<DependentUpon>AppResources.da.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.de.Designer.cs">
<DependentUpon>AppResources.de.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>AppResources.resx</DependentUpon>
</Compile>
<Compile Update="Resources\AppResources.es.Designer.cs">
<DependentUpon>AppResources.es.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.fi.Designer.cs">
<DependentUpon>AppResources.fi.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.fr.Designer.cs">
<DependentUpon>AppResources.fr.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.hi.Designer.cs">
<DependentUpon>AppResources.hi.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.hr.Designer.cs">
<DependentUpon>AppResources.hr.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.hu.Designer.cs">
<DependentUpon>AppResources.hu.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.id.Designer.cs">
<DependentUpon>AppResources.id.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.it.Designer.cs">
<DependentUpon>AppResources.it.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.ja.Designer.cs">
<DependentUpon>AppResources.ja.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.nl.Designer.cs">
<DependentUpon>AppResources.nl.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.pl.Designer.cs">
<DependentUpon>AppResources.pl.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.pt-BR.Designer.cs">
<DependentUpon>AppResources.pt-BR.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.pt-PT.Designer.cs">
<DependentUpon>AppResources.pt-PT.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.ro.Designer.cs">
<DependentUpon>AppResources.ro.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.ru.Designer.cs">
<DependentUpon>AppResources.ru.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.sk.Designer.cs">
<DependentUpon>AppResources.sk.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.sv.Designer.cs">
<DependentUpon>AppResources.sv.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.th.Designer.cs">
<DependentUpon>AppResources.th.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.tr.Designer.cs">
<DependentUpon>AppResources.tr.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.uk.Designer.cs">
<DependentUpon>AppResources.uk.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.vi.Designer.cs">
<DependentUpon>AppResources.vi.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.zh-Hans.Designer.cs">
<DependentUpon>AppResources.zh-Hans.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
<Compile Update="Resources\AppResources.zh-Hant.Designer.cs">
<DependentUpon>AppResources.zh-Hant.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources\AppResources.cs.resx">
<LastGenOutput>AppResources.cs.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.da.resx">
<LastGenOutput>AppResources.da.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.de.resx">
<LastGenOutput>AppResources.de.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.es.resx">
<LastGenOutput>AppResources.es.Designer.cs</LastGenOutput>
<Generator>PublicResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.fi.resx">
<LastGenOutput>AppResources.fi.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.fr.resx">
<LastGenOutput>AppResources.fr.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.hi.resx">
<LastGenOutput>AppResources.hi.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.hr.resx">
<LastGenOutput>AppResources.hr.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.hu.resx">
<LastGenOutput>AppResources.hu.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.id.resx">
<LastGenOutput>AppResources.id.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.it.resx">
<LastGenOutput>AppResources.it.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.ja.resx">
<LastGenOutput>AppResources.ja.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.nl.resx">
<LastGenOutput>AppResources.nl.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.pl.resx">
<LastGenOutput>AppResources.pl.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.pt-BR.resx">
<LastGenOutput>AppResources.pt-BR.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.pt-PT.resx">
<LastGenOutput>AppResources.pt-PT.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.ro.resx">
<LastGenOutput>AppResources.ro.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.ru.resx">
<LastGenOutput>AppResources.ru.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.sk.resx">
<LastGenOutput>AppResources.sk.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.sv.resx">
<LastGenOutput>AppResources.sv.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.th.resx">
<LastGenOutput>AppResources.th.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.tr.resx">
<LastGenOutput>AppResources.tr.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.uk.resx">
<LastGenOutput>AppResources.uk.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.vi.resx">
<LastGenOutput>AppResources.vi.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.zh-Hans.resx">
<LastGenOutput>AppResources.zh-Hans.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\AppResources.zh-Hant.resx">
<LastGenOutput>AppResources.zh-Hant.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Remove="Behaviors\" />
<None Remove="Xamarin.CommunityToolkit" />
<None Remove="Lists\" />
<None Remove="Lists\DataTemplates\" />
<None Remove="Lists\DataTemplateSelectors\" />
<None Remove="Lists\DataTemplates\CustomFields\" />
<None Remove="Lists\ItemViewModels\" />
<None Remove="Lists\ItemViewModels\CustomFields\" />
<None Remove="Controls\AccountSwitchingOverlay\" />
<None Remove="Utilities\AccountManagement\" />
<None Remove="Controls\DateTime\" />
<None Remove="Controls\IconLabelButton\" />
<None Remove="MessagePack" />
<None Remove="MessagePack.MSBuild.Tasks" />
<None Remove="Controls\PasswordStrengthProgressBar\" />
<None Remove="Utilities\Automation\" />
<None Remove="Utilities\Prompts\" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-android|AnyCPU'">
<AndroidEnableMultiDex>True</AndroidEnableMultiDex>
<UseInterpreter>False</UseInterpreter>
<DebugSymbols>False</DebugSymbols>
<RunAOTCompilation>False</RunAOTCompilation>
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-ios|AnyCPU'">
<CreatePackage>false</CreatePackage>
<CodesignProvision>Automatic</CodesignProvision>
<CodesignKey>iPhone Developer</CodesignKey>
<CodesignEntitlements>Platforms\iOS\Entitlements.plist</CodesignEntitlements>
<UseInterpreter>true</UseInterpreter>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(RuntimeIdentifier)'=='Debug|net8.0-ios|iossimulator-x64'">
<MtouchExtraArgs>$(Argon2IdLoadMtouchExtraArgs)</MtouchExtraArgs>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(RuntimeIdentifier)'=='Debug|net8.0-ios|ios-arm64'">
<MtouchExtraArgs>$(Argon2IdLoadMtouchExtraArgs)</MtouchExtraArgs>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-ios|AnyCPU'">
<CreatePackage>false</CreatePackage>
<CodesignProvision>$(ReleaseCodesignProvision)</CodesignProvision>
<CodesignKey>$(ReleaseCodesignKey)</CodesignKey>
<CodesignEntitlements>Platforms\iOS\Entitlements.plist</CodesignEntitlements>
<UseInterpreter>true</UseInterpreter>
<MtouchExtraArgs>$(Argon2IdLoadMtouchExtraArgs)</MtouchExtraArgs>
</PropertyGroup>
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">
<!--This is needed for PCLCrypto to work correctly-->
<TrimmerRootAssembly Include="System.Security.Cryptography" />
</ItemGroup>
<ItemGroup>
<AndroidNativeLibrary Include="Platforms\Android\lib\arm64-v8a\libargon2.so" />
<AndroidNativeLibrary Include="Platforms\Android\lib\armeabi-v7a\libargon2.so" />
<AndroidNativeLibrary Include="Platforms\Android\lib\x86\libargon2.so" />
<AndroidNativeLibrary Include="Platforms\Android\lib\x86_64\libargon2.so" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Camera.MAUI" Version="1.4.4" />
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
<PackageReference Include="CsvHelper" Version="30.0.1" />
<PackageReference Include="LiteDB" Version="5.0.17" />
<PackageReference Include="MessagePack" Version="2.5.124" />
<PackageReference Include="MessagePack.MSBuild.Tasks" Version="2.5.124">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="zxcvbn-core" Version="7.0.92" />
<PackageReference Include="CommunityToolkit.Maui" Version="5.2.0" />
<PackageReference Include="Plugin.Fingerprint" Version="3.0.0-beta.1" />
<PackageReference Include="SkiaSharp.Views.Maui.Controls" Version="2.88.4-preview.84" />
<PackageReference Include="SkiaSharp.Views.Maui.Controls.Compatibility" Version="2.88.4-preview.84" />
<PackageReference Include="FFImageLoadingCompat.Maui" Version="0.1.1" />
<PackageReference Include="AsyncAwaitBestPractices.MVVM" Version="6.0.6" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
<PackageReference Include="PCLCrypto" Version="2.1.40-alpha" />
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Effects\" />
<Folder Include="Resources\" />
<Folder Include="Resources\AppIcon\" />
<Folder Include="Resources\Splash\" />
<Folder Include="Platforms\Android\Accessibility\" />
<Folder Include="Platforms\Android\Autofill\" />
<Folder Include="Platforms\Android\Push\" />
<Folder Include="Platforms\Android\Receivers\" />
<Folder Include="Platforms\Android\Services\" />
<Folder Include="Platforms\Android\Tiles\" />
<Folder Include="Platforms\Android\Utilities\" />
</ItemGroup>
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
<PackageReference Include="Xamarin.AndroidX.AutoFill" Version="1.1.0.18" />
<PackageReference Include="Xamarin.AndroidX.Activity.Ktx" Version="1.7.2.1" />
<PackageReference Include="Xamarin.AndroidX.Credentials" Version="1.0.0" />
</ItemGroup>
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android' AND !$(DefineConstants.Contains(FDROID))">
<PackageReference Include="Xamarin.GooglePlayServices.SafetyNet" Version="118.0.1.5" />
<PackageReference Include="Xamarin.Firebase.Messaging" Version="123.1.2.2" />
</ItemGroup>
<ItemGroup Condition="!$(DefineConstants.Contains(FDROID))">
<PackageReference Include="Microsoft.AppCenter.Crashes" Version="5.0.3" />
</ItemGroup>
<ItemGroup>
<BundleResource Include="Platforms\Android\Resources\mipmap-mdpi\ic_launcher.png" />
<BundleResource Include="Platforms\Android\Resources\mipmap-mdpi\ic_launcher_round.png" />
<BundleResource Include="Platforms\Android\Resources\mipmap-xxhdpi\ic_launcher.png" />
<BundleResource Include="Platforms\Android\Resources\mipmap-xxhdpi\ic_launcher_round.png" />
<BundleResource Include="Platforms\Android\Resources\mipmap-xxxhdpi\ic_launcher.png" />
<BundleResource Include="Platforms\Android\Resources\mipmap-xxxhdpi\ic_launcher_round.png" />
<BundleResource Include="Platforms\Android\Resources\mipmap-hdpi\ic_launcher.png" />
<BundleResource Include="Platforms\Android\Resources\mipmap-hdpi\ic_launcher_round.png" />
<BundleResource Include="Platforms\Android\Resources\mipmap-mdpi\ic_launcher.png" />
<BundleResource Include="Platforms\Android\Resources\mipmap-mdpi\ic_launcher_round.png" />
<BundleResource Include="Platforms\Android\Resources\mipmap-hdpi\ic_launcher.png" />
<BundleResource Include="Platforms\Android\Resources\mipmap-hdpi\ic_launcher_round.png" />
<BundleResource Include="Platforms\Android\Resources\mipmap-xxxhdpi\ic_launcher.png" />
<BundleResource Include="Platforms\Android\Resources\mipmap-xxxhdpi\ic_launcher_round.png" />
<BundleResource Include="Platforms\Android\Resources\mipmap-xxhdpi\ic_launcher.png" />
<BundleResource Include="Platforms\Android\Resources\mipmap-xxhdpi\ic_launcher_round.png" />
<BundleResource Include="Platforms\Android\Resources\drawable-xhdpi\logo_legacy.png" />
<BundleResource Include="Platforms\Android\Resources\drawable-xhdpi\yubikey.png" />
<BundleResource Include="Platforms\Android\Resources\drawable-xhdpi\logo_white_legacy.png" />
<BundleResource Include="Platforms\Android\Resources\drawable-xxhdpi\logo_legacy.png" />
<BundleResource Include="Platforms\Android\Resources\drawable-xxhdpi\yubikey.png" />
<BundleResource Include="Platforms\Android\Resources\drawable-xxhdpi\logo_white_legacy.png" />
<BundleResource Include="Platforms\Android\Resources\drawable-hdpi\logo_legacy.png" />
<BundleResource Include="Platforms\Android\Resources\drawable-hdpi\yubikey.png" />
<BundleResource Include="Platforms\Android\Resources\drawable-hdpi\logo_white_legacy.png" />
<BundleResource Include="Platforms\Android\Resources\mipmap-xhdpi\ic_launcher.png" />
<BundleResource Include="Platforms\Android\Resources\mipmap-xhdpi\ic_launcher_round.png" />
<BundleResource Include="Platforms\iOS\Resources\logo.png" />
<BundleResource Include="Platforms\iOS\Resources\logo_white%402x.png" />
<BundleResource Include="Platforms\iOS\Resources\more_vert%402x.png" />
<BundleResource Include="Platforms\iOS\Resources\logo_white%403x.png" />
<BundleResource Include="Platforms\iOS\Resources\logo%403x.png" />
<BundleResource Include="Platforms\iOS\Resources\more_vert%403x.png" />
<BundleResource Include="Platforms\iOS\Resources\more_vert.png" />
<BundleResource Include="Platforms\iOS\Resources\logo_white.png" />
<BundleResource Include="Platforms\iOS\Resources\logo%402x.png" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\iOS.Core\iOS.Core.csproj" Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'" />
<ProjectReference Include="..\Core\Core.csproj" />
</ItemGroup>
<ItemGroup>
<!-- App Icon -->
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />
</ItemGroup>
<ItemGroup>
<MauiImage Include="Resources\cog_settings.svg">
<BaseSize>24,24</BaseSize>
</MauiImage>
<MauiImage Include="Resources\ext_act.png" />
<MauiImage Include="Resources\ext_more.png" />
<MauiImage Include="Resources\ext_use.png" />
<MauiImage Include="Resources\generate.svg">
<BaseSize>24,24</BaseSize>
</MauiImage>
<MauiImage Include="Resources\info.svg">
<BaseSize>24,24</BaseSize>
</MauiImage>
<MauiImage Include="Resources\lock.svg">
<BaseSize>24,24</BaseSize>
</MauiImage>
<MauiImage Include="Resources\login.svg">
<BaseSize>24,24</BaseSize>
</MauiImage>
<MauiImage Include="Resources\logo_white.png" />
<MauiImage Include="Resources\logo.png" />
<MauiImage Include="Resources\more_vert.svg">
<BaseSize>24,24</BaseSize>
</MauiImage>
<MauiImage Include="Resources\more.svg">
<BaseSize>24,24</BaseSize>
</MauiImage>
<MauiImage Include="Resources\plus.svg" TintColor="#FFFFFFFF">
<BaseSize>24,24</BaseSize>
</MauiImage>
<MauiImage Include="Resources\send.svg">
<BaseSize>24,24</BaseSize>
</MauiImage>
<MauiImage Include="Resources\yubikey.png" />
</ItemGroup>
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios' AND '$(IncludeBitwardeniOSExtensions)' == 'True'">
<ProjectReference Include="..\iOS.Autofill\iOS.Autofill.csproj">
<IsAppExtension>true</IsAppExtension>
<IsWatchApp>false</IsWatchApp>
</ProjectReference>
<ProjectReference Include="..\iOS.Extension\iOS.Extension.csproj">
<IsAppExtension>true</IsAppExtension>
<IsWatchApp>false</IsWatchApp>
</ProjectReference>
<ProjectReference Include="..\iOS.ShareExtension\iOS.ShareExtension.csproj">
<IsAppExtension>true</IsAppExtension>
<IsWatchApp>false</IsWatchApp>
</ProjectReference>
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)'=='net8.0-ios' AND '$(IncludeBitwardenWatchOSApp)' == 'True'">
<WatchAppBuildPath Condition=" '$(Configuration)' == 'Debug' ">$(Home)/Library/Developer/Xcode/DerivedData/bitwarden-acgkbpwvmebfiofokotvoerzkqcl/Build/Products</WatchAppBuildPath>
<WatchAppBuildPath Condition=" '$(Configuration)' != 'Debug' ">$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\..'))/watchOS/bitwarden.xcarchive/Products/Applications/bitwarden.app/Watch</WatchAppBuildPath>
<WatchAppBundle>Bitwarden.app</WatchAppBundle>
<WatchAppConfiguration Condition="'$(RuntimeIdentifier)'!='ios-arm64'">watchsimulator</WatchAppConfiguration>
<WatchAppConfiguration Condition="'$(RuntimeIdentifier)'=='ios-arm64'">watchos</WatchAppConfiguration>
<WatchAppBundleFullPath Condition=" '$(Configuration)' == 'Debug' ">$(WatchAppBuildPath)/$(Configuration)-$(WatchAppConfiguration)/$(WatchAppBundle)</WatchAppBundleFullPath>
<WatchAppBundleFullPath Condition=" '$(Configuration)' != 'Debug' ">$(WatchAppBuildPath)/$(WatchAppBundle)</WatchAppBundleFullPath>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net8.0-ios' AND Exists('$(WatchAppBundleFullPath)') ">
<_ResolvedWatchAppReferences Include="$(WatchAppBundleFullPath)" />
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)'=='net8.0-ios' AND Exists('$(WatchAppBundleFullPath)') ">
<CreateAppBundleDependsOn>
_CopyWatchOS2AppsToBundle;
$(CreateAppBundleDependsOn);
</CreateAppBundleDependsOn>
</PropertyGroup>
<ItemGroup>
<GoogleServicesJson Include="Platforms\Android\google-services.json" />
<GoogleServicesJson Include="Platforms\Android\google-services.json.enc" />
</ItemGroup>
<ItemGroup>
<None Remove="Platforms\iOS\Resources\logo.png" />
<None Remove="Platforms\iOS\Resources\logo_white%402x.png" />
<None Remove="Platforms\iOS\Resources\more_vert%402x.png" />
<None Remove="Platforms\iOS\Resources\logo_white%403x.png" />
<None Remove="Platforms\iOS\Resources\logo%403x.png" />
<None Remove="Platforms\iOS\Resources\more_vert%403x.png" />
<None Remove="Platforms\iOS\Resources\more_vert.png" />
<None Remove="Platforms\iOS\Resources\logo_white.png" />
<None Remove="Platforms\iOS\Resources\logo%402x.png" />
</ItemGroup>
</Project>

View File

@@ -1,67 +0,0 @@
using System;
using Bit.App.Pages;
using Bit.App.Utilities;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public partial class AuthenticatorViewCell : ExtendedGrid
{
public static readonly BindableProperty CipherProperty = BindableProperty.Create(
nameof(Cipher), typeof(CipherView), typeof(AuthenticatorViewCell), default(CipherView), BindingMode.TwoWay);
public static readonly BindableProperty WebsiteIconsEnabledProperty = BindableProperty.Create(
nameof(WebsiteIconsEnabled), typeof(bool?), typeof(AuthenticatorViewCell));
public static readonly BindableProperty TotpSecProperty = BindableProperty.Create(
nameof(TotpSec), typeof(long), typeof(AuthenticatorViewCell));
public AuthenticatorViewCell()
{
InitializeComponent();
}
public Command CopyCommand { get; set; }
public CipherView Cipher
{
get => GetValue(CipherProperty) as CipherView;
set => SetValue(CipherProperty, value);
}
public bool? WebsiteIconsEnabled
{
get => (bool)GetValue(WebsiteIconsEnabledProperty);
set => SetValue(WebsiteIconsEnabledProperty, value);
}
public long TotpSec
{
get => (long)GetValue(TotpSecProperty);
set => SetValue(TotpSecProperty, value);
}
public bool ShowIconImage
{
get => WebsiteIconsEnabled ?? false
&& !string.IsNullOrWhiteSpace(Cipher.Login?.Uri)
&& IconImageSource != null;
}
private string _iconImageSource = string.Empty;
public string IconImageSource
{
get
{
if (_iconImageSource == string.Empty) // default value since icon source can return null
{
_iconImageSource = IconImageHelper.GetLoginIconImage(Cipher);
}
return _iconImageSource;
}
}
}
}

View File

@@ -1,180 +0,0 @@
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Bit.Core.Utilities;
using SkiaSharp;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class AvatarImageSource : StreamImageSource
{
private readonly string _text;
private readonly string _id;
private readonly string _color;
public override bool Equals(object obj)
{
if (obj is null)
{
return false;
}
if (obj is AvatarImageSource avatar)
{
return avatar._id == _id && avatar._text == _text && avatar._color == _color;
}
return base.Equals(obj);
}
public override int GetHashCode() => _id?.GetHashCode() ?? _text?.GetHashCode() ?? -1;
public AvatarImageSource(string userId = null, string name = null, string email = null, string color = null)
{
_id = userId;
_text = name;
if (string.IsNullOrWhiteSpace(_text))
{
_text = email;
}
_color = color;
}
public override Func<CancellationToken, Task<Stream>> Stream => GetStreamAsync;
private Task<Stream> GetStreamAsync(CancellationToken userToken = new CancellationToken())
{
OnLoadingStarted();
userToken.Register(CancellationTokenSource.Cancel);
var result = Draw();
OnLoadingCompleted(CancellationTokenSource.IsCancellationRequested);
return Task.FromResult(result);
}
private Stream Draw()
{
string chars;
string upperCaseText = null;
if (string.IsNullOrEmpty(_text))
{
chars = "..";
}
else if (_text?.Length > 1)
{
upperCaseText = _text.ToUpper();
chars = GetFirstLetters(upperCaseText, 2);
}
else
{
chars = upperCaseText = _text.ToUpper();
}
var bgColor = _color ?? CoreHelpers.StringToColor(_id ?? upperCaseText, "#33ffffff");
var textColor = CoreHelpers.TextColorFromBgColor(bgColor);
var size = 50;
using (var bitmap = new SKBitmap(size * 2,
size * 2,
SKImageInfo.PlatformColorType,
SKAlphaType.Premul))
{
using (var canvas = new SKCanvas(bitmap))
{
canvas.Clear(SKColors.Transparent);
using (var paint = new SKPaint
{
IsAntialias = true,
Style = SKPaintStyle.Fill,
StrokeJoin = SKStrokeJoin.Miter,
Color = SKColor.Parse(bgColor)
})
{
var midX = canvas.LocalClipBounds.Size.ToSizeI().Width / 2;
var midY = canvas.LocalClipBounds.Size.ToSizeI().Height / 2;
var radius = midX - midX / 5;
using (var circlePaint = new SKPaint
{
IsAntialias = true,
Style = SKPaintStyle.Fill,
StrokeJoin = SKStrokeJoin.Miter,
Color = SKColor.Parse(bgColor)
})
{
canvas.DrawCircle(midX, midY, radius, circlePaint);
var typeface = SKTypeface.FromFamilyName("Arial", SKFontStyle.Normal);
var textSize = midX / 1.3f;
using (var textPaint = new SKPaint
{
IsAntialias = true,
Style = SKPaintStyle.Fill,
Color = SKColor.Parse(textColor),
TextSize = textSize,
TextAlign = SKTextAlign.Center,
Typeface = typeface
})
{
var rect = new SKRect();
textPaint.MeasureText(chars, ref rect);
canvas.DrawText(chars, midX, midY + rect.Height / 2, textPaint);
using (var img = SKImage.FromBitmap(bitmap))
{
var data = img.Encode(SKEncodedImageFormat.Png, 100);
return data?.AsStream(true);
}
}
}
}
}
}
}
private string GetFirstLetters(string data, int charCount)
{
var sanitizedData = data.Trim();
var parts = sanitizedData.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length > 1 && charCount <= 2)
{
var text = string.Empty;
for (var i = 0; i < charCount; i++)
{
text += parts[i][0];
}
return text;
}
if (sanitizedData.Length > 2)
{
return sanitizedData.Substring(0, 2);
}
return sanitizedData;
}
private Color StringToColor(string str)
{
if (str == null)
{
return Color.FromHex("#33ffffff");
}
var hash = 0;
for (var i = 0; i < str.Length; i++)
{
hash = str[i] + ((hash << 5) - hash);
}
var color = "#FF";
for (var i = 0; i < 3; i++)
{
var value = (hash >> (i * 8)) & 0xff;
var base16 = "00" + Convert.ToString(value, 16);
color += base16.Substring(base16.Length - 2);
}
return Color.FromHex(color);
}
}
}

View File

@@ -1,82 +0,0 @@
using System;
using System.Windows.Input;
using Bit.App.Abstractions;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public partial class CipherViewCell : ExtendedGrid
{
private const int ICON_COLUMN_DEFAULT_WIDTH = 40;
private const int ICON_IMAGE_DEFAULT_WIDTH = 22;
public static readonly BindableProperty CipherProperty = BindableProperty.Create(
nameof(Cipher), typeof(CipherView), typeof(CipherViewCell), default(CipherView), BindingMode.OneWay);
public static readonly BindableProperty WebsiteIconsEnabledProperty = BindableProperty.Create(
nameof(WebsiteIconsEnabled), typeof(bool?), typeof(CipherViewCell));
public static readonly BindableProperty ButtonCommandProperty = BindableProperty.Create(
nameof(ButtonCommand), typeof(ICommand), typeof(CipherViewCell));
public CipherViewCell()
{
InitializeComponent();
var fontScale = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService").GetSystemFontSizeScale();
_iconColumn.Width = new GridLength(ICON_COLUMN_DEFAULT_WIDTH * fontScale, GridUnitType.Absolute);
_iconImage.WidthRequest = ICON_IMAGE_DEFAULT_WIDTH * fontScale;
_iconImage.HeightRequest = ICON_IMAGE_DEFAULT_WIDTH * fontScale;
}
public bool? WebsiteIconsEnabled
{
get => (bool)GetValue(WebsiteIconsEnabledProperty);
set => SetValue(WebsiteIconsEnabledProperty, value);
}
public CipherView Cipher
{
get => GetValue(CipherProperty) as CipherView;
set => SetValue(CipherProperty, value);
}
public ICommand ButtonCommand
{
get => GetValue(ButtonCommandProperty) as ICommand;
set => SetValue(ButtonCommandProperty, value);
}
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName == CipherProperty.PropertyName)
{
if (Cipher == null)
{
return;
}
BindingContext = new CipherViewCellViewModel(Cipher, WebsiteIconsEnabled ?? false);
}
else if (propertyName == WebsiteIconsEnabledProperty.PropertyName)
{
if (Cipher == null)
{
return;
}
((CipherViewCellViewModel)BindingContext).WebsiteIconsEnabled = WebsiteIconsEnabled ?? false;
}
}
private void MoreButton_Clicked(object sender, EventArgs e)
{
var cipher = ((sender as MiButton)?.BindingContext as CipherViewCellViewModel)?.Cipher;
if (cipher != null)
{
ButtonCommand?.Execute(cipher);
}
}
}
}

View File

@@ -1,51 +0,0 @@
using Bit.App.Utilities;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
namespace Bit.App.Controls
{
public class CipherViewCellViewModel : ExtendedViewModel
{
private CipherView _cipher;
private bool _websiteIconsEnabled;
private string _iconImageSource = string.Empty;
public CipherViewCellViewModel(CipherView cipherView, bool websiteIconsEnabled)
{
Cipher = cipherView;
WebsiteIconsEnabled = websiteIconsEnabled;
}
public CipherView Cipher
{
get => _cipher;
set => SetProperty(ref _cipher, value);
}
public bool WebsiteIconsEnabled
{
get => _websiteIconsEnabled;
set => SetProperty(ref _websiteIconsEnabled, value);
}
public bool ShowIconImage
{
get => WebsiteIconsEnabled
&& !string.IsNullOrWhiteSpace(Cipher.LaunchUri)
&& IconImageSource != null;
}
public string IconImageSource
{
get
{
if (_iconImageSource == string.Empty) // default value since icon source can return null
{
_iconImageSource = IconImageHelper.GetIconImage(Cipher);
}
return _iconImageSource;
}
}
}
}

View File

@@ -1,20 +0,0 @@
using System.Linq;
using Xamarin.CommunityToolkit.Converters;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class ExtendedCollectionView : CollectionView
{
public string ExtraDataForLogging { get; set; }
}
public class SelectionChangedEventArgsConverter : BaseNullableConverterOneWay<SelectionChangedEventArgs, object>
{
public override object? ConvertFrom(SelectionChangedEventArgs? value)
{
return value?.CurrentSelection.FirstOrDefault();
}
}
}

View File

@@ -1,8 +0,0 @@
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class ExtendedGrid : Grid
{
}
}

View File

@@ -1,19 +0,0 @@
using Bit.App.Utilities;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class ExtendedSearchBar : SearchBar
{
public ExtendedSearchBar()
{
if (Device.RuntimePlatform == Device.iOS)
{
if (ThemeManager.UsingLightTheme)
{
TextColor = Color.Black;
}
}
}
}
}

View File

@@ -1,8 +0,0 @@
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class ExtendedStackLayout : StackLayout
{
}
}

View File

@@ -1,42 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Frame xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Controls.IconLabelButton"
xmlns:controls="clr-namespace:Bit.App.Controls"
x:Name="_iconLabelButton"
HeightRequest="45"
Padding="1"
StyleClass="btn-icon-secondary"
BackgroundColor="{Binding IconLabelBorderColor, Source={x:Reference _iconLabelButton}}"
BorderColor="Transparent"
HasShadow="False">
<Frame.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ButtonCommand, Source={x:Reference _iconLabelButton}}" />
</Frame.GestureRecognizers>
<Frame
Margin="0"
Padding="0"
CornerRadius="{Binding CornerRadius, Source={x:Reference _iconLabelButton}}"
BackgroundColor="{Binding IconLabelBackgroundColor, Source={x:Reference _iconLabelButton}}"
BorderColor="Transparent"
IsClippedToBounds="True"
HasShadow="False">
<StackLayout
Orientation="Horizontal"
HorizontalOptions="Center">
<controls:IconLabel
VerticalOptions="Center"
HorizontalTextAlignment="Center"
FontSize="Large"
TextColor="{Binding IconLabelColor, Source={x:Reference _iconLabelButton}}"
Text="{Binding Icon, Source={x:Reference _iconLabelButton}}">
</controls:IconLabel>
<Label
VerticalOptions="Center"
HorizontalTextAlignment="Center"
TextColor="{Binding IconLabelColor, Source={x:Reference _iconLabelButton}}"
FontSize="Medium"
Text="{Binding Label, Source={x:Reference _iconLabelButton}}"/>
</StackLayout>
</Frame>
</Frame>

View File

@@ -1,20 +0,0 @@
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class MonoEntry : Entry
{
public MonoEntry()
{
switch (Device.RuntimePlatform)
{
case Device.iOS:
FontFamily = "Menlo-Regular";
break;
case Device.Android:
FontFamily = "RobotoMono_Regular.ttf#Roboto Mono";
break;
}
}
}
}

View File

@@ -1,20 +0,0 @@
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class MonoLabel : Label
{
public MonoLabel()
{
switch (Device.RuntimePlatform)
{
case Device.iOS:
FontFamily = "Menlo-Regular";
break;
case Device.Android:
FontFamily = "RobotoMono_Regular.ttf#Roboto Mono";
break;
}
}
}
}

View File

@@ -1,68 +0,0 @@
using System;
using Bit.App.Abstractions;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public partial class SendViewCell : ExtendedGrid
{
public static readonly BindableProperty SendProperty = BindableProperty.Create(
nameof(Send), typeof(SendView), typeof(SendViewCell), default(SendView), BindingMode.OneWay);
public static readonly BindableProperty ButtonCommandProperty = BindableProperty.Create(
nameof(ButtonCommand), typeof(Command<SendView>), typeof(SendViewCell));
public static readonly BindableProperty ShowOptionsProperty = BindableProperty.Create(
nameof(ShowOptions), typeof(bool), typeof(SendViewCell), true, BindingMode.OneWay);
public SendViewCell()
{
InitializeComponent();
var deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
_iconColumn.Width = new GridLength(40 * deviceActionService.GetSystemFontSizeScale(), GridUnitType.Absolute);
}
public SendView Send
{
get => GetValue(SendProperty) as SendView;
set => SetValue(SendProperty, value);
}
public Command<SendView> ButtonCommand
{
get => GetValue(ButtonCommandProperty) as Command<SendView>;
set => SetValue(ButtonCommandProperty, value);
}
public bool ShowOptions
{
get => (bool)GetValue(ShowOptionsProperty);
set => SetValue(ShowOptionsProperty, value);
}
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName == SendProperty.PropertyName)
{
if (Send == null)
{
return;
}
BindingContext = new SendViewCellViewModel(Send, ShowOptions);
}
}
private void MoreButton_Clicked(object sender, EventArgs e)
{
var send = ((sender as MiButton)?.BindingContext as SendViewCellViewModel)?.Send;
if (send != null)
{
ButtonCommand?.Execute(send);
}
}
}
}

View File

@@ -1,11 +0,0 @@
using Xamarin.Forms;
namespace Bit.App.Effects
{
public class FabShadowEffect : RoutingEffect
{
public FabShadowEffect()
: base("Bitwarden.FabShadowEffect")
{ }
}
}

View File

@@ -1,11 +0,0 @@
using Xamarin.Forms;
namespace Bit.App.Effects
{
public class FixedSizeEffect : RoutingEffect
{
public FixedSizeEffect()
: base("Bitwarden.FixedSizeEffect")
{ }
}
}

View File

@@ -1,12 +0,0 @@
using System;
using Xamarin.Forms;
namespace Bit.App.Effects
{
public class NoEmojiKeyboardEffect : RoutingEffect
{
public NoEmojiKeyboardEffect()
: base("Bitwarden.NoEmojiKeyboardEffect")
{ }
}
}

View File

@@ -1,13 +0,0 @@
using System;
using Xamarin.Forms;
namespace Bit.App.Effects
{
public class RemoveFontPaddingEffect : RoutingEffect
{
public RemoveFontPaddingEffect()
: base("Bitwarden.RemoveFontPaddingEffect")
{ }
}
}

View File

@@ -1,33 +0,0 @@
using Xamarin.Forms;
namespace Bit.App.Effects
{
public enum ScrollContentInsetAdjustmentBehavior
{
Automatic,
ScrollableAxes,
Never,
Always
}
public class ScrollViewContentInsetAdjustmentBehaviorEffect : RoutingEffect
{
public static readonly BindableProperty ContentInsetAdjustmentBehaviorProperty =
BindableProperty.CreateAttached("ContentInsetAdjustmentBehavior", typeof(ScrollContentInsetAdjustmentBehavior), typeof(ScrollViewContentInsetAdjustmentBehaviorEffect), ScrollContentInsetAdjustmentBehavior.Automatic);
public static ScrollContentInsetAdjustmentBehavior GetContentInsetAdjustmentBehavior(BindableObject view)
{
return (ScrollContentInsetAdjustmentBehavior)view.GetValue(ContentInsetAdjustmentBehaviorProperty);
}
public static void SetContentInsetAdjustmentBehavior(BindableObject view, ScrollContentInsetAdjustmentBehavior value)
{
view.SetValue(ContentInsetAdjustmentBehaviorProperty, value);
}
public ScrollViewContentInsetAdjustmentBehaviorEffect()
: base($"Bitwarden.{nameof(ScrollViewContentInsetAdjustmentBehaviorEffect)}")
{
}
}
}

View File

@@ -1,11 +0,0 @@
using Xamarin.Forms;
namespace Bit.App.Effects
{
public class TabBarEffect : RoutingEffect
{
public TabBarEffect()
: base("Bitwarden.TabBarEffect")
{ }
}
}

41
src/App/MauiProgram.cs Normal file
View File

@@ -0,0 +1,41 @@
namespace Bit.App
{
public class MauiProgram
{
public static MauiApp CreateMauiApp()
{
return Core.MauiProgram.ConfigureMauiAppBuilder(
effects =>
{
#if IOS
iOS.Core.Utilities.iOSCoreHelpers.ConfigureMAUIEffects(effects);
#endif
},
handlers =>
{
#if ANDROID
Bit.App.Handlers.EntryHandlerMappings.Setup();
Bit.App.Handlers.EditorHandlerMappings.Setup();
Bit.App.Handlers.LabelHandlerMappings.Setup();
Bit.App.Handlers.PickerHandlerMappings.Setup();
Bit.App.Handlers.SearchBarHandlerMappings.Setup();
Bit.App.Handlers.SwitchHandlerMappings.Setup();
Bit.App.Handlers.DatePickerHandlerMappings.Setup();
Bit.App.Handlers.SliderHandlerMappings.Setup();
Bit.App.Handlers.StepperHandlerMappings.Setup();
Bit.App.Handlers.TimePickerHandlerMappings.Setup();
Bit.App.Handlers.ButtonHandlerMappings.Setup();
Bit.App.Handlers.ToolbarHandlerMappings.Setup();
handlers.AddHandler(typeof(Bit.App.Controls.HybridWebView), typeof(Bit.App.Handlers.HybridWebViewHandler));
handlers.AddHandler(typeof(Bit.App.Pages.TabsPage), typeof(Bit.App.Handlers.CustomTabbedPageHandler));
handlers.AddHandler(typeof(Bit.App.Controls.ExtendedDatePicker), typeof(Bit.App.Handlers.ExtendedDatePickerHandler));
#else
iOS.Core.Utilities.iOSCoreHelpers.ConfigureMAUIHandlers(handlers);
#endif
},
initUseMauiApp: true
).Build();
}
}
}

View File

@@ -1,145 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<pages:BaseContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.HomePage"
xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:u="clr-namespace:Bit.App.Utilities"
x:DataType="pages:HomeViewModel"
x:Name="_page"
Title="{Binding PageTitle}">
<ContentPage.BindingContext>
<pages:HomeViewModel />
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<controls:ExtendedToolbarItem
x:Name="_accountAvatar"
x:Key="accountAvatar"
IconImageSource="{Binding AvatarImageSource}"
Command="{Binding Source={x:Reference _accountListOverlay}, Path=ToggleVisibililtyCommand}"
Order="Primary"
Priority="-1"
UseOriginalImage="True"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Account}"
AutomationId="AccountIconButton" />
<ToolbarItem x:Name="_closeButton" Text="{u:I18n Close}" Command="{Binding CloseCommand}" Order="Primary" Priority="-1"/>
</ContentPage.ToolbarItems>
<ContentPage.Resources>
<ResourceDictionary>
<u:InverseBoolConverter x:Key="inverseBool" />
<StackLayout x:Name="_mainLayout" x:Key="mainLayout" Spacing="30" Padding="20, 50, 20, 0">
<Image
x:Name="_logo"
Source="logo.png"
VerticalOptions="Center" />
<Label Text="{u:I18n LoginOrCreateNewAccount}"
StyleClass="text-lg"
HorizontalTextAlignment="Center"/>
<StackLayout
StyleClass="box-row">
<Label
Text="{u:I18n EmailAddress}"
StyleClass="box-label" />
<Entry
x:Name="_email"
Text="{Binding Email}"
Keyboard="Email"
StyleClass="box-value"
ReturnType="Go"
ReturnCommand="{Binding ContinueCommand}"
AutomationId="EmailAddressEntry"
>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{DynamicResource MutedColor}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
<StackLayout
Orientation="Horizontal"
Margin="0, 6, 0 ,0">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding ShowEnvironmentPickerCommand}" />
</StackLayout.GestureRecognizers>
<Label
Text="{Binding RegionText}"
FontSize="13"
TextColor="{DynamicResource MutedColor}"
VerticalOptions="Center"
VerticalTextAlignment="Center"/>
<controls:IconLabel
Text="{Binding SelectedEnvironmentName}"
FontSize="13"
TextColor="{DynamicResource PrimaryColor}"
VerticalOptions="Center"
VerticalTextAlignment="Center"
AutomationId="RegionSelectorDropdown"/>
</StackLayout>
<StackLayout
Orientation="Horizontal"
Margin="0, 20, 0 ,0">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding RememberEmailCommand}" />
</StackLayout.GestureRecognizers>
<Label
Text="{u:I18n RememberMe}"
StyleClass="text-sm"
HorizontalOptions="FillAndExpand"
VerticalOptions="Center"
VerticalTextAlignment="Center"
/>
<Switch
Scale="0.8"
IsToggled="{Binding RememberEmail}"
VerticalOptions="Center"
AutomationId="RememberMeSwitch"
/>
</StackLayout>
</StackLayout>
<Button Text="{u:I18n Continue}"
StyleClass="btn-primary"
IsEnabled="{Binding CanContinue}"
Command="{Binding ContinueCommand}"
AutomationId="ContinueButton"
/>
<Label FormattedText="{Binding CreateAccountText}"
Margin="0, 10"
StyleClass="box-footer-label"
AutomationId="CreateAccountLabel">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding CreateAccountCommand}" />
</Label.GestureRecognizers>
</Label>
</StackLayout>
</ResourceDictionary>
</ContentPage.Resources>
<AbsoluteLayout
x:Name="_absLayout"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<ContentView
x:Name="_mainContent"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0, 0, 1, 1">
</ContentView>
<controls:AccountSwitchingOverlayView
x:Name="_accountListOverlay"
AbsoluteLayout.LayoutBounds="0, 0, 1, 1"
AbsoluteLayout.LayoutFlags="All"
MainPage="{Binding Source={x:Reference _page}}"
BindingContext="{Binding AccountSwitchingOverlayViewModel}"/>
</AbsoluteLayout>
</pages:BaseContentPage>

View File

@@ -1,162 +0,0 @@
using System;
using System.Threading.Tasks;
using Bit.App.Abstractions;
using Bit.App.Controls;
using Bit.App.Utilities;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using Xamarin.Forms;
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
namespace Bit.App.Pages
{
public class BaseContentPage : ContentPage
{
private IStateService _stateService;
private IDeviceActionService _deviceActionService;
protected int ShowModalAnimationDelay = 400;
protected int ShowPageAnimationDelay = 100;
public BaseContentPage()
{
if (Device.RuntimePlatform == Device.iOS)
{
On<iOS>().SetUseSafeArea(true);
On<iOS>().SetModalPresentationStyle(UIModalPresentationStyle.FullScreen);
}
}
public DateTime? LastPageAction { get; set; }
public bool IsThemeDirty { get; set; }
protected async override void OnAppearing()
{
base.OnAppearing();
if (IsThemeDirty)
{
UpdateOnThemeChanged();
}
await SaveActivityAsync();
}
public bool DoOnce(Action action = null, int milliseconds = 1000)
{
if (LastPageAction.HasValue && (DateTime.UtcNow - LastPageAction.Value).TotalMilliseconds < milliseconds)
{
// Last action occurred recently.
return false;
}
LastPageAction = DateTime.UtcNow;
action?.Invoke();
return true;
}
public virtual Task UpdateOnThemeChanged()
{
IsThemeDirty = false;
return Task.CompletedTask;
}
protected void SetActivityIndicator(ContentView targetView = null)
{
var indicator = new ActivityIndicator
{
IsRunning = true,
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.Center,
Color = ThemeManager.GetResourceColor("PrimaryColor"),
};
if (targetView != null)
{
targetView.Content = indicator;
}
else
{
Content = indicator;
}
}
protected async Task LoadOnAppearedAsync(View sourceView, bool fromModal, Func<Task> workFunction,
ContentView targetView = null)
{
async Task DoWorkAsync()
{
await workFunction.Invoke();
if (sourceView != null)
{
if (targetView != null)
{
targetView.Content = sourceView;
}
else
{
Content = sourceView;
}
}
}
if (Device.RuntimePlatform == Device.iOS)
{
await DoWorkAsync();
return;
}
await Task.Run(async () =>
{
await Task.Delay(fromModal ? ShowModalAnimationDelay : ShowPageAnimationDelay);
Device.BeginInvokeOnMainThread(async () => await DoWorkAsync());
});
}
protected void RequestFocus(InputView input)
{
Task.Run(async () =>
{
await Task.Delay(ShowModalAnimationDelay);
Device.BeginInvokeOnMainThread(() => input.Focus());
});
}
protected async Task<bool> ShowAccountSwitcherAsync()
{
return await _stateService.GetActiveUserIdAsync() != null;
}
protected async Task<AvatarImageSource> GetAvatarImageSourceAsync(bool useCurrentActiveAccount = true)
{
if (useCurrentActiveAccount)
{
var user = await _stateService.GetActiveUserCustomDataAsync(a => (a?.Profile?.UserId, a?.Profile?.Name, a?.Profile?.Email, a?.Profile?.AvatarColor));
return new AvatarImageSource(user.UserId, user.Name, user.Email, user.AvatarColor);
}
return new AvatarImageSource();
}
private void SetServices()
{
if (_stateService == null)
{
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
}
if (_deviceActionService == null)
{
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
}
}
private async Task SaveActivityAsync()
{
SetServices();
if (await _stateService.GetActiveUserIdAsync() == null)
{
// Fresh install and/or all users logged out won't have an active user, skip saving last active time
return;
}
await _stateService.SetLastActiveTimeAsync(_deviceActionService.GetActiveTime());
}
}
}

View File

@@ -1,51 +0,0 @@
using System;
using Bit.App.Abstractions;
using Bit.App.Controls;
using Bit.App.Resources;
using Bit.Core.Abstractions;
using Bit.Core.Exceptions;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public abstract class BaseViewModel : ExtendedViewModel
{
private string _pageTitle = string.Empty;
private AvatarImageSource _avatar;
private LazyResolve<IDeviceActionService> _deviceActionService = new LazyResolve<IDeviceActionService>();
private LazyResolve<IPlatformUtilsService> _platformUtilsService = new LazyResolve<IPlatformUtilsService>();
private LazyResolve<ILogger> _logger = new LazyResolve<ILogger>();
public string PageTitle
{
get => _pageTitle;
set => SetProperty(ref _pageTitle, value);
}
public AvatarImageSource AvatarImageSource
{
get => _avatar ?? new AvatarImageSource();
set => SetProperty(ref _avatar, value);
}
public ContentPage Page { get; set; }
protected void HandleException(Exception ex, string message = null)
{
if (ex is ApiException apiException && apiException.Error != null)
{
message = apiException.Error.GetSingleMessage();
}
Xamarin.Essentials.MainThread.InvokeOnMainThreadAsync(async () =>
{
await _deviceActionService.Value.HideLoadingAsync();
await _platformUtilsService.Value.ShowDialogAsync(message ?? AppResources.GenericErrorMessage);
}).FireAndForget();
_logger.Value.Exception(ex);
}
}
}

View File

@@ -1,131 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<pages:BaseContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.AutofillServicesPage"
xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:u="clr-namespace:Bit.App.Utilities"
x:DataType="pages:AutofillServicesPageViewModel"
Title="{Binding PageTitle}">
<ContentPage.BindingContext>
<pages:AutofillServicesPageViewModel />
</ContentPage.BindingContext>
<ScrollView>
<StackLayout Padding="0" Spacing="20">
<StackLayout
StyleClass="box"
IsVisible="{Binding AutofillServiceVisible}">
<StackLayout StyleClass="box-row, box-row-switch">
<Label
Text="{u:I18n AutofillService}"
StyleClass="box-label-regular"
HorizontalOptions="StartAndExpand" />
<RelativeLayout HorizontalOptions="End">
<Switch
x:Name="AutofillServiceSwitch"
IsToggled="{Binding AutofillServiceToggled}"
StyleClass="box-value"
HorizontalOptions="End" />
<Button
Clicked="ToggleAutofillService"
StyleClass="box-overlay"
RelativeLayout.XConstraint="0"
RelativeLayout.YConstraint="0"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToView, ElementName=AutofillServiceSwitch, Property=Width}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToView, ElementName=AutofillServiceSwitch, Property=Height}" />
</RelativeLayout>
</StackLayout>
<Label
Text="{u:I18n AutofillServiceDescription}"
StyleClass="box-footer-label, box-footer-label-switch" />
</StackLayout>
<StackLayout
StyleClass="box"
IsVisible="{Binding InlineAutofillVisible}">
<StackLayout StyleClass="box-row, box-row-switch">
<Label
Text="{u:I18n InlineAutofill}"
StyleClass="box-label-regular"
IsEnabled="{Binding InlineAutofillEnabled}"
HorizontalOptions="StartAndExpand" />
<RelativeLayout HorizontalOptions="End">
<Switch
x:Name="InlineAutofillSwitch"
IsEnabled="{Binding InlineAutofillEnabled}"
IsToggled="{Binding InlineAutofillToggled}"
StyleClass="box-value"
HorizontalOptions="End" />
<Button
Clicked="ToggleInlineAutofill"
StyleClass="box-overlay"
RelativeLayout.XConstraint="0"
RelativeLayout.YConstraint="0"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToView, ElementName=InlineAutofillSwitch, Property=Width}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToView, ElementName=InlineAutofillSwitch, Property=Height}" />
</RelativeLayout>
</StackLayout>
<Label
Text="{u:I18n InlineAutofillDescription}"
StyleClass="box-footer-label, box-footer-label-switch"
IsEnabled="{Binding InlineAutofillEnabled}"/>
</StackLayout>
<StackLayout StyleClass="box">
<StackLayout StyleClass="box-row, box-row-switch">
<Label
Text="{u:I18n Accessibility}"
StyleClass="box-label-regular"
HorizontalOptions="StartAndExpand" />
<RelativeLayout HorizontalOptions="End">
<Switch
x:Name="AccessibilitySwitch"
IsToggled="{Binding AccessibilityToggled}"
StyleClass="box-value"
HorizontalOptions="End" />
<Button
Command="{Binding ToggleAccessibilityCommand}"
StyleClass="box-overlay"
RelativeLayout.XConstraint="0"
RelativeLayout.YConstraint="0"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToView, ElementName=AccessibilitySwitch, Property=Width}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToView, ElementName=AccessibilitySwitch, Property=Height}" />
</RelativeLayout>
</StackLayout>
<Label
Text="{Binding AccessibilityDescriptionLabel}"
StyleClass="box-footer-label, box-footer-label-switch" />
</StackLayout>
<StackLayout
StyleClass="box"
IsVisible="{Binding DrawOverVisible}">
<StackLayout StyleClass="box-row, box-row-switch">
<Label
Text="{u:I18n DrawOver}"
StyleClass="box-label-regular"
IsEnabled="{Binding DrawOverEnabled}"
HorizontalOptions="StartAndExpand" />
<RelativeLayout HorizontalOptions="End">
<Switch
x:Name="DrawOverSwitch"
IsEnabled="{Binding DrawOverEnabled}"
IsToggled="{Binding DrawOverToggled}"
StyleClass="box-value"
HorizontalOptions="End" />
<Button
Clicked="ToggleDrawOver"
StyleClass="box-overlay"
RelativeLayout.XConstraint="0"
RelativeLayout.YConstraint="0"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToView, ElementName=DrawOverSwitch, Property=Width}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToView, ElementName=DrawOverSwitch, Property=Height}" />
</RelativeLayout>
</StackLayout>
<Label
Text="{Binding DrawOverDescriptionLabel}"
StyleClass="box-footer-label, box-footer-label-switch"
IsEnabled="{Binding InlineAutofillEnabled}"/>
</StackLayout>
</StackLayout>
</ScrollView>
</pages:BaseContentPage>

View File

@@ -1,66 +0,0 @@
using System;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public partial class AutofillServicesPage : BaseContentPage
{
private readonly AutofillServicesPageViewModel _vm;
private readonly SettingsPage _settingsPage;
private DateTime? _timerStarted = null;
private TimeSpan _timerMaxLength = TimeSpan.FromMinutes(5);
public AutofillServicesPage(SettingsPage settingsPage)
{
InitializeComponent();
_vm = BindingContext as AutofillServicesPageViewModel;
_vm.Page = this;
_settingsPage = settingsPage;
}
protected async override void OnAppearing()
{
await _vm.InitAsync();
_vm.UpdateEnabled();
_timerStarted = DateTime.UtcNow;
Device.StartTimer(new TimeSpan(0, 0, 0, 0, 500), () =>
{
if (_timerStarted == null || (DateTime.UtcNow - _timerStarted) > _timerMaxLength)
{
return false;
}
_vm.UpdateEnabled();
return true;
});
base.OnAppearing();
}
protected override void OnDisappearing()
{
_timerStarted = null;
_settingsPage.BuildList();
base.OnDisappearing();
}
private void ToggleAutofillService(object sender, EventArgs e)
{
if (DoOnce())
{
_vm.ToggleAutofillService();
}
}
private void ToggleInlineAutofill(object sender, EventArgs e)
{
_vm.ToggleInlineAutofill();
}
private void ToggleDrawOver(object sender, EventArgs e)
{
if (DoOnce())
{
_vm.ToggleDrawOver();
}
}
}
}

View File

@@ -1,231 +0,0 @@
using System.Threading.Tasks;
using System.Windows.Input;
using Bit.App.Abstractions;
using Bit.App.Resources;
using Bit.App.Services;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using Xamarin.CommunityToolkit.ObjectModel;
namespace Bit.App.Pages
{
public class AutofillServicesPageViewModel : BaseViewModel
{
private readonly IDeviceActionService _deviceActionService;
private readonly IAutofillHandler _autofillHandler;
private readonly IStateService _stateService;
private readonly MobileI18nService _i18nService;
private readonly IPlatformUtilsService _platformUtilsService;
readonly LazyResolve<ILogger> _logger = new LazyResolve<ILogger>("logger");
private bool _autofillServiceToggled;
private bool _inlineAutofillToggled;
private bool _accessibilityToggled;
private bool _drawOverToggled;
private bool _inited;
public AutofillServicesPageViewModel()
{
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
_autofillHandler = ServiceContainer.Resolve<IAutofillHandler>();
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
_i18nService = ServiceContainer.Resolve<II18nService>("i18nService") as MobileI18nService;
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
PageTitle = AppResources.AutofillServices;
ToggleAccessibilityCommand = new AsyncCommand(ToggleAccessibilityAsync,
onException: ex => _logger.Value.Exception(ex),
allowsMultipleExecutions: false);
}
#region Autofill Service
public bool AutofillServiceVisible
{
get => _deviceActionService.SystemMajorVersion() >= 26;
}
public bool AutofillServiceToggled
{
get => _autofillServiceToggled;
set => SetProperty(ref _autofillServiceToggled, value,
additionalPropertyNames: new string[]
{
nameof(InlineAutofillEnabled)
});
}
#endregion
#region Inline Autofill
public bool InlineAutofillVisible
{
get => _deviceActionService.SystemMajorVersion() >= 30;
}
public bool InlineAutofillEnabled
{
get => AutofillServiceToggled;
}
public bool InlineAutofillToggled
{
get => _inlineAutofillToggled;
set
{
if (SetProperty(ref _inlineAutofillToggled, value))
{
var task = UpdateInlineAutofillToggledAsync();
}
}
}
#endregion
#region Accessibility
public ICommand ToggleAccessibilityCommand { get; }
public string AccessibilityDescriptionLabel
{
get
{
if (_deviceActionService.SystemMajorVersion() <= 22)
{
// Android 5
return _i18nService.T("AccessibilityDescription");
}
if (_deviceActionService.SystemMajorVersion() == 23)
{
// Android 6
return _i18nService.T("AccessibilityDescription2");
}
if (_deviceActionService.SystemMajorVersion() == 24 || _deviceActionService.SystemMajorVersion() == 25)
{
// Android 7
return _i18nService.T("AccessibilityDescription3");
}
// Android 8+
return _i18nService.T("AccessibilityDescription4");
}
}
public bool AccessibilityToggled
{
get => _accessibilityToggled;
set => SetProperty(ref _accessibilityToggled, value,
additionalPropertyNames: new string[]
{
nameof(DrawOverEnabled)
});
}
#endregion
#region Draw-Over
public bool DrawOverVisible
{
get => _deviceActionService.SystemMajorVersion() >= 23;
}
public string DrawOverDescriptionLabel
{
get
{
if (_deviceActionService.SystemMajorVersion() <= 23)
{
// Android 6
return _i18nService.T("DrawOverDescription");
}
if (_deviceActionService.SystemMajorVersion() == 24 || _deviceActionService.SystemMajorVersion() == 25)
{
// Android 7
return _i18nService.T("DrawOverDescription2");
}
// Android 8+
return _i18nService.T("DrawOverDescription3");
}
}
public bool DrawOverEnabled
{
get => AccessibilityToggled;
}
public bool DrawOverToggled
{
get => _drawOverToggled;
set => SetProperty(ref _drawOverToggled, value);
}
#endregion
public async Task InitAsync()
{
InlineAutofillToggled = await _stateService.GetInlineAutofillEnabledAsync() ?? true;
_inited = true;
}
public void ToggleAutofillService()
{
if (!AutofillServiceToggled)
{
_deviceActionService.OpenAutofillSettings();
}
else
{
_autofillHandler.DisableAutofillService();
}
}
public void ToggleInlineAutofill()
{
if (!InlineAutofillEnabled)
{
return;
}
InlineAutofillToggled = !InlineAutofillToggled;
}
public async Task ToggleAccessibilityAsync()
{
if (!_autofillHandler.AutofillAccessibilityServiceRunning())
{
var accept = await _platformUtilsService.ShowDialogAsync(AppResources.AccessibilityDisclosureText,
AppResources.AccessibilityServiceDisclosure, AppResources.Accept,
AppResources.Decline);
if (!accept)
{
return;
}
}
_deviceActionService.OpenAccessibilitySettings();
}
public void ToggleDrawOver()
{
if (!DrawOverEnabled)
{
return;
}
_deviceActionService.OpenAccessibilityOverlayPermissionSettings();
}
public void UpdateEnabled()
{
AutofillServiceToggled =
_autofillHandler.SupportsAutofillService() && _autofillHandler.AutofillServiceEnabled();
AccessibilityToggled = _autofillHandler.AutofillAccessibilityServiceRunning();
DrawOverToggled = _autofillHandler.AutofillAccessibilityOverlayPermitted();
}
private async Task UpdateInlineAutofillToggledAsync()
{
if (_inited)
{
await _stateService.SetInlineAutofillEnabledAsync(InlineAutofillToggled);
}
}
}
}

View File

@@ -1,169 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<pages:BaseContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.OptionsPage"
xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:u="clr-namespace:Bit.App.Utilities"
x:DataType="pages:OptionsPageViewModel"
Title="{Binding PageTitle}">
<ContentPage.BindingContext>
<pages:OptionsPageViewModel />
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
</ContentPage.ToolbarItems>
<ScrollView Padding="0, 0, 0, 20">
<StackLayout Padding="0" Spacing="20">
<StackLayout StyleClass="box">
<StackLayout StyleClass="box-row, box-row-input, box-row-input-options-platform">
<Label
Text="{u:I18n Theme}"
StyleClass="box-label" />
<Picker
x:Name="_themePicker"
ItemsSource="{Binding ThemeOptions, Mode=OneTime}"
SelectedIndex="{Binding ThemeSelectedIndex}"
StyleClass="box-value"
AutomationId="ThemeSelectorPicker" />
</StackLayout>
<Label
StyleClass="box-footer-label"
Text="{u:I18n ThemeDescription}" />
</StackLayout>
<StackLayout
StyleClass="box"
IsVisible="{Binding ShowAutoDarkThemeOptions}">
<StackLayout StyleClass="box-row, box-row-input, box-row-input-options-platform">
<Label
Text="{u:I18n DefaultDarkTheme}"
StyleClass="box-label" />
<Picker
x:Name="_autoDarkThemePicker"
ItemsSource="{Binding AutoDarkThemeOptions, Mode=OneTime}"
SelectedIndex="{Binding AutoDarkThemeSelectedIndex}"
StyleClass="box-value"
AutomationId="DefaultDarkThemePicker" />
</StackLayout>
<Label
StyleClass="box-footer-label"
Text="{u:I18n DefaultDarkThemeDescription}" />
</StackLayout>
<StackLayout StyleClass="box">
<StackLayout StyleClass="box-row, box-row-input, box-row-input-options-platform">
<Label
Text="{u:I18n DefaultUriMatchDetection}"
StyleClass="box-label" />
<Picker
x:Name="_uriMatchPicker"
ItemsSource="{Binding UriMatchOptions, Mode=OneTime}"
SelectedIndex="{Binding UriMatchSelectedIndex}"
StyleClass="box-value"
AutomationId="DefaultUriMatchDetectionPicker" />
</StackLayout>
<Label
Text="{u:I18n DefaultUriMatchDetectionDescription}"
StyleClass="box-footer-label" />
</StackLayout>
<StackLayout StyleClass="box">
<StackLayout StyleClass="box-row, box-row-input, box-row-input-options-platform">
<Label
Text="{u:I18n ClearClipboard}"
StyleClass="box-label" />
<Picker
x:Name="_clearClipboardPicker"
ItemsSource="{Binding ClearClipboardOptions, Mode=OneTime}"
SelectedIndex="{Binding ClearClipboardSelectedIndex}"
StyleClass="box-value"
AutomationId="ClearClipboardPicker" />
</StackLayout>
<Label
Text="{u:I18n ClearClipboardDescription}"
StyleClass="box-footer-label" />
</StackLayout>
<StackLayout StyleClass="box">
<StackLayout StyleClass="box-row, box-row-input, box-row-input-options-platform">
<Label
Text="{u:I18n Language}"
StyleClass="box-label" />
<Picker
x:Name="_languagePicker"
ItemsSource="{Binding LocalesOptions, Mode=OneTime}"
SelectedItem="{Binding SelectedLocale}"
ItemDisplayBinding="{Binding Value}"
StyleClass="box-value"
AutomationId="LanguagePicker" />
</StackLayout>
<Label
Text="{u:I18n LanguageChangeRequiresAppRestart}"
StyleClass="box-footer-label" />
</StackLayout>
<StackLayout StyleClass="box">
<StackLayout StyleClass="box-row, box-row-switch">
<Label
Text="{u:I18n CopyTotpAutomatically}"
StyleClass="box-label-regular"
HorizontalOptions="StartAndExpand" />
<Switch
IsToggled="{Binding AutoTotpCopy}"
StyleClass="box-value"
HorizontalOptions="End"
AutomationId="CopyTotpAutomaticallyToggle" />
</StackLayout>
<Label
Text="{u:I18n CopyTotpAutomaticallyDescription}"
StyleClass="box-footer-label, box-footer-label-switch" />
</StackLayout>
<StackLayout StyleClass="box">
<StackLayout StyleClass="box-row, box-row-switch">
<Label
Text="{u:I18n ShowWebsiteIcons}"
StyleClass="box-label-regular"
HorizontalOptions="StartAndExpand" />
<Switch
IsToggled="{Binding Favicon}"
StyleClass="box-value"
HorizontalOptions="End"
AutomationId="ShowWebsiteIconsToggle" />
</StackLayout>
<Label
Text="{u:I18n ShowWebsiteIconsDescription}"
StyleClass="box-footer-label, box-footer-label-switch" />
</StackLayout>
<StackLayout StyleClass="box" IsVisible="{Binding ShowAndroidAutofillSettings}">
<StackLayout StyleClass="box-row-header">
<Label Text="{u:I18n AutofillService, Header=True}"
StyleClass="box-header, box-header-platform" />
</StackLayout>
<StackLayout StyleClass="box-row, box-row-switch">
<Label
Text="{u:I18n AskToAddLogin}"
StyleClass="box-label-regular"
HorizontalOptions="StartAndExpand" />
<Switch
IsToggled="{Binding AutofillSavePrompt}"
StyleClass="box-value"
HorizontalOptions="End" />
</StackLayout>
<Label
Text="{u:I18n AskToAddLoginDescription}"
StyleClass="box-footer-label, box-footer-label-switch" />
</StackLayout>
<StackLayout StyleClass="box" IsVisible="{Binding ShowAndroidAutofillSettings}">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding GoToBlockAutofillUrisCommand}" />
</StackLayout.GestureRecognizers>
<Label
Text="{u:I18n BlockAutoFill}"
StyleClass="box-label-regular" />
<Label
Text="{u:I18n AutoFillWillNotBeOfferedForTheseURIs}"
StyleClass="box-footer-label" />
</StackLayout>
</StackLayout>
</ScrollView>
</pages:BaseContentPage>

View File

@@ -1,53 +0,0 @@
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using Xamarin.Forms;
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
namespace Bit.App.Pages
{
public partial class OptionsPage : BaseContentPage
{
private readonly IAutofillHandler _autofillHandler;
private readonly OptionsPageViewModel _vm;
public OptionsPage()
{
_autofillHandler = ServiceContainer.Resolve<IAutofillHandler>();
InitializeComponent();
_vm = BindingContext as OptionsPageViewModel;
_vm.Page = this;
_themePicker.ItemDisplayBinding = new Binding("Value");
_autoDarkThemePicker.ItemDisplayBinding = new Binding("Value");
_uriMatchPicker.ItemDisplayBinding = new Binding("Value");
_clearClipboardPicker.ItemDisplayBinding = new Binding("Value");
if (Device.RuntimePlatform == Device.Android)
{
ToolbarItems.RemoveAt(0);
_vm.ShowAndroidAutofillSettings = _autofillHandler.SupportsAutofillService();
}
else
{
_themePicker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
_autoDarkThemePicker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
_uriMatchPicker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
_clearClipboardPicker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
_languagePicker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
}
}
protected async override void OnAppearing()
{
base.OnAppearing();
await _vm.InitAsync();
}
private async void Close_Clicked(object sender, System.EventArgs e)
{
if (DoOnce())
{
await Navigation.PopModalAsync();
}
}
}
}

View File

@@ -1,300 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using Bit.App.Resources;
using Bit.App.Utilities;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Utilities;
using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public class OptionsPageViewModel : BaseViewModel
{
private readonly IStateService _stateService;
private readonly IMessagingService _messagingService;
private readonly II18nService _i18nService;
private readonly IPlatformUtilsService _platformUtilsService;
private bool _autofillSavePrompt;
private bool _favicon;
private bool _autoTotpCopy;
private int _clearClipboardSelectedIndex;
private int _themeSelectedIndex;
private int _autoDarkThemeSelectedIndex;
private int _uriMatchSelectedIndex;
private KeyValuePair<string, string> _selectedLocale;
private bool _inited;
private bool _updatingAutofill;
private bool _showAndroidAutofillSettings;
public OptionsPageViewModel()
{
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
_i18nService = ServiceContainer.Resolve<II18nService>();
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>();
PageTitle = AppResources.Options;
var iosIos = Device.RuntimePlatform == Device.iOS;
ClearClipboardOptions = new List<KeyValuePair<int?, string>>
{
new KeyValuePair<int?, string>(null, AppResources.Never),
new KeyValuePair<int?, string>(10, AppResources.TenSeconds),
new KeyValuePair<int?, string>(20, AppResources.TwentySeconds),
new KeyValuePair<int?, string>(30, AppResources.ThirtySeconds),
new KeyValuePair<int?, string>(60, AppResources.OneMinute)
};
if (!iosIos)
{
ClearClipboardOptions.Add(new KeyValuePair<int?, string>(120, AppResources.TwoMinutes));
ClearClipboardOptions.Add(new KeyValuePair<int?, string>(300, AppResources.FiveMinutes));
}
ThemeOptions = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>(null, AppResources.ThemeDefault),
new KeyValuePair<string, string>(ThemeManager.Light, AppResources.Light),
new KeyValuePair<string, string>(ThemeManager.Dark, AppResources.Dark),
new KeyValuePair<string, string>(ThemeManager.Black, AppResources.Black),
new KeyValuePair<string, string>(ThemeManager.Nord, AppResources.Nord),
new KeyValuePair<string, string>(ThemeManager.SolarizedDark, AppResources.SolarizedDark),
};
AutoDarkThemeOptions = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>(ThemeManager.Dark, AppResources.Dark),
new KeyValuePair<string, string>(ThemeManager.Black, AppResources.Black),
new KeyValuePair<string, string>(ThemeManager.Nord, AppResources.Nord),
new KeyValuePair<string, string>(ThemeManager.SolarizedDark, AppResources.SolarizedDark),
};
UriMatchOptions = new List<KeyValuePair<UriMatchType?, string>>
{
new KeyValuePair<UriMatchType?, string>(UriMatchType.Domain, AppResources.BaseDomain),
new KeyValuePair<UriMatchType?, string>(UriMatchType.Host, AppResources.Host),
new KeyValuePair<UriMatchType?, string>(UriMatchType.StartsWith, AppResources.StartsWith),
new KeyValuePair<UriMatchType?, string>(UriMatchType.RegularExpression, AppResources.RegEx),
new KeyValuePair<UriMatchType?, string>(UriMatchType.Exact, AppResources.Exact),
new KeyValuePair<UriMatchType?, string>(UriMatchType.Never, AppResources.Never),
};
LocalesOptions = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>(null, AppResources.DefaultSystem)
};
LocalesOptions.AddRange(_i18nService.LocaleNames.ToList());
GoToBlockAutofillUrisCommand = new AsyncCommand(() => Page.Navigation.PushAsync(new BlockAutofillUrisPage()),
onException: ex => HandleException(ex),
allowsMultipleExecutions: false);
}
public List<KeyValuePair<int?, string>> ClearClipboardOptions { get; set; }
public List<KeyValuePair<string, string>> ThemeOptions { get; set; }
public List<KeyValuePair<string, string>> AutoDarkThemeOptions { get; set; }
public List<KeyValuePair<UriMatchType?, string>> UriMatchOptions { get; set; }
public List<KeyValuePair<string, string>> LocalesOptions { get; }
public int ClearClipboardSelectedIndex
{
get => _clearClipboardSelectedIndex;
set
{
if (SetProperty(ref _clearClipboardSelectedIndex, value))
{
SaveClipboardChangedAsync().FireAndForget();
}
}
}
public int ThemeSelectedIndex
{
get => _themeSelectedIndex;
set
{
if (SetProperty(ref _themeSelectedIndex, value,
additionalPropertyNames: new[] { nameof(ShowAutoDarkThemeOptions) })
)
{
SaveThemeAsync().FireAndForget();
}
}
}
public bool ShowAutoDarkThemeOptions => ThemeOptions[ThemeSelectedIndex].Key == null;
public int AutoDarkThemeSelectedIndex
{
get => _autoDarkThemeSelectedIndex;
set
{
if (SetProperty(ref _autoDarkThemeSelectedIndex, value))
{
SaveThemeAsync().FireAndForget();
}
}
}
public int UriMatchSelectedIndex
{
get => _uriMatchSelectedIndex;
set
{
if (SetProperty(ref _uriMatchSelectedIndex, value))
{
SaveDefaultUriAsync().FireAndForget();
}
}
}
public KeyValuePair<string, string> SelectedLocale
{
get => _selectedLocale;
set
{
if (SetProperty(ref _selectedLocale, value))
{
UpdateCurrentLocaleAsync().FireAndForget();
}
}
}
public bool Favicon
{
get => _favicon;
set
{
if (SetProperty(ref _favicon, value))
{
UpdateFaviconAsync().FireAndForget();
}
}
}
public bool AutoTotpCopy
{
get => _autoTotpCopy;
set
{
if (SetProperty(ref _autoTotpCopy, value))
{
UpdateAutoTotpCopyAsync().FireAndForget();
}
}
}
public bool AutofillSavePrompt
{
get => _autofillSavePrompt;
set
{
if (SetProperty(ref _autofillSavePrompt, value))
{
UpdateAutofillSavePromptAsync().FireAndForget();
}
}
}
public bool ShowAndroidAutofillSettings
{
get => _showAndroidAutofillSettings;
set => SetProperty(ref _showAndroidAutofillSettings, value);
}
public ICommand GoToBlockAutofillUrisCommand { get; }
public async Task InitAsync()
{
AutofillSavePrompt = !(await _stateService.GetAutofillDisableSavePromptAsync()).GetValueOrDefault();
AutoTotpCopy = !(await _stateService.GetDisableAutoTotpCopyAsync() ?? false);
Favicon = !(await _stateService.GetDisableFaviconAsync()).GetValueOrDefault();
var theme = await _stateService.GetThemeAsync();
ThemeSelectedIndex = ThemeOptions.FindIndex(k => k.Key == theme);
var autoDarkTheme = await _stateService.GetAutoDarkThemeAsync() ?? "dark";
AutoDarkThemeSelectedIndex = AutoDarkThemeOptions.FindIndex(k => k.Key == autoDarkTheme);
var defaultUriMatch = await _stateService.GetDefaultUriMatchAsync();
UriMatchSelectedIndex = defaultUriMatch == null ? 0 :
UriMatchOptions.FindIndex(k => (int?)k.Key == defaultUriMatch);
var clearClipboard = await _stateService.GetClearClipboardAsync();
ClearClipboardSelectedIndex = ClearClipboardOptions.FindIndex(k => k.Key == clearClipboard);
var appLocale = _stateService.GetLocale();
SelectedLocale = appLocale == null ? LocalesOptions.First() : LocalesOptions.FirstOrDefault(kv => kv.Key == appLocale);
_inited = true;
}
private async Task UpdateAutoTotpCopyAsync()
{
if (_inited)
{
// TODO: [PS-961] Fix negative function names
await _stateService.SetDisableAutoTotpCopyAsync(!AutoTotpCopy);
}
}
private async Task UpdateFaviconAsync()
{
if (_inited)
{
// TODO: [PS-961] Fix negative function names
await _stateService.SetDisableFaviconAsync(!Favicon);
}
}
private async Task SaveClipboardChangedAsync()
{
if (_inited && ClearClipboardSelectedIndex > -1)
{
await _stateService.SetClearClipboardAsync(ClearClipboardOptions[ClearClipboardSelectedIndex].Key);
}
}
private async Task SaveThemeAsync()
{
if (_inited && ThemeSelectedIndex > -1)
{
await _stateService.SetThemeAsync(ThemeOptions[ThemeSelectedIndex].Key);
await _stateService.SetAutoDarkThemeAsync(AutoDarkThemeOptions[AutoDarkThemeSelectedIndex].Key);
ThemeManager.SetTheme(Application.Current.Resources);
_messagingService.Send("updatedTheme");
}
}
private async Task SaveDefaultUriAsync()
{
if (_inited && UriMatchSelectedIndex > -1)
{
await _stateService.SetDefaultUriMatchAsync((int?)UriMatchOptions[UriMatchSelectedIndex].Key);
}
}
private async Task UpdateAutofillSavePromptAsync()
{
if (_inited)
{
// TODO: [PS-961] Fix negative function names
await _stateService.SetAutofillDisableSavePromptAsync(!AutofillSavePrompt);
}
}
private async Task UpdateCurrentLocaleAsync()
{
if (!_inited)
{
return;
}
_stateService.SetLocale(SelectedLocale.Key);
await _platformUtilsService.ShowDialogAsync(string.Format(AppResources.LanguageChangeXDescription, SelectedLocale.Value), AppResources.Language, AppResources.Ok);
}
}
}

View File

@@ -1,6 +0,0 @@
namespace Bit.App.Pages
{
public interface ISettingsPageListItem
{
}
}

View File

@@ -1,123 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<pages:BaseContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.SettingsPage"
xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:u="clr-namespace:Bit.App.Utilities"
x:DataType="pages:SettingsPageViewModel"
Title="{Binding PageTitle}">
<ContentPage.BindingContext>
<pages:SettingsPageViewModel />
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<u:InverseBoolConverter x:Key="inverseBool" />
<u:StringHasValueConverter x:Key="stringHasValue" />
<DataTemplate
x:Key="regularTemplate"
x:DataType="pages:SettingsPageListItem">
<controls:ExtendedStackLayout Orientation="Horizontal"
StyleClass="list-row, list-row-platform">
<Frame
IsVisible="{Binding UseFrame}"
Padding="10"
HasShadow="False"
BackgroundColor="Transparent"
BorderColor="{DynamicResource PrimaryColor}">
<Label
Text="{Binding Name, Mode=OneWay}"
StyleClass="text-muted, text-sm, text-bold"
HorizontalTextAlignment="Center" />
</Frame>
<controls:CustomLabel IsVisible="{Binding UseFrame, Converter={StaticResource inverseBool}}"
Text="{Binding Name, Mode=OneWay}"
LineBreakMode="{Binding LineBreakMode}"
HorizontalOptions="StartAndExpand"
VerticalOptions="CenterAndExpand"
StyleClass="list-title"
AutomationId="{Binding AutomationIdSettingName}" />
<controls:CustomLabel Text="{Binding SubLabel, Mode=OneWay}"
IsVisible="{Binding ShowSubLabel}"
HorizontalOptions="End"
HorizontalTextAlignment="End"
VerticalOptions="CenterAndExpand"
TextColor="{Binding SubLabelColor}"
StyleClass="list-sub"
AutomationId="{Binding AutomationIdSettingStatus}" />
</controls:ExtendedStackLayout>
</DataTemplate>
<DataTemplate
x:Key="timePickerTemplate"
x:DataType="pages:SettingsPageListItem">
<controls:ExtendedStackLayout Orientation="Horizontal"
StyleClass="list-row, list-row-platform">
<Frame
IsVisible="{Binding UseFrame}"
Padding="10"
HasShadow="False"
BackgroundColor="Transparent"
BorderColor="{DynamicResource PrimaryColor}"
AutomationId="SettingActivePolicyTextLabel">
<Label
Text="{Binding Name, Mode=OneWay}"
StyleClass="text-muted, text-sm, text-bold"
HorizontalTextAlignment="Center" />
</Frame>
<Label IsVisible="{Binding UseFrame, Converter={StaticResource inverseBool}}"
Text="{Binding Name, Mode=OneWay}"
LineBreakMode="{Binding LineBreakMode}"
HorizontalOptions="StartAndExpand"
VerticalOptions="CenterAndExpand"
StyleClass="list-title"/>
<TimePicker Time="{Binding Time}" Format="HH:mm"
PropertyChanged="OnTimePickerPropertyChanged"
HorizontalOptions="End"
VerticalOptions="Center"
FontSize="Small"
TextColor="{Binding SubLabelColor}"
StyleClass="list-sub" Margin="-5"
AutomationId="SettingCustomVaultTimeoutPicker" />
<controls:ExtendedStackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="ActivateTimePicker"/>
</controls:ExtendedStackLayout.GestureRecognizers>
</controls:ExtendedStackLayout>
</DataTemplate>
<DataTemplate
x:Key="headerTemplate"
x:DataType="pages:SettingsPageHeaderListItem">
<StackLayout
Padding="0" Spacing="0" VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
<BoxView
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
<StackLayout StyleClass="list-row-header, list-row-header-platform">
<Label
Text="{Binding Title}"
StyleClass="list-header, list-header-platform" />
</StackLayout>
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
</StackLayout>
</DataTemplate>
<pages:SettingsPageListItemSelector
x:Key="listItemDataTemplateSelector"
HeaderTemplate="{StaticResource headerTemplate}"
RegularTemplate="{StaticResource regularTemplate}"
TimePickerTemplate="{StaticResource timePickerTemplate}" />
</ResourceDictionary>
</ContentPage.Resources>
<controls:ExtendedCollectionView
ItemsSource="{Binding GroupedItems}"
VerticalOptions="FillAndExpand"
ItemTemplate="{StaticResource listItemDataTemplateSelector}"
SelectionMode="Single"
SelectionChanged="RowSelected"
StyleClass="list, list-platform"
ExtraDataForLogging="Settings Page" />
</pages:BaseContentPage>

View File

@@ -1,73 +0,0 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using Bit.App.Controls;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public partial class SettingsPage : BaseContentPage
{
private readonly TabsPage _tabsPage;
private SettingsPageViewModel _vm;
public SettingsPage(TabsPage tabsPage)
{
_tabsPage = tabsPage;
InitializeComponent();
_vm = BindingContext as SettingsPageViewModel;
_vm.Page = this;
}
public async Task InitAsync()
{
await _vm.InitAsync();
}
public void BuildList()
{
_vm.BuildList();
}
protected override bool OnBackButtonPressed()
{
if (Device.RuntimePlatform == Device.Android && _tabsPage != null)
{
_tabsPage.ResetToVaultPage();
return true;
}
return base.OnBackButtonPressed();
}
void ActivateTimePicker(object sender, EventArgs args)
{
var stackLayout = (ExtendedStackLayout)sender;
SettingsPageListItem item = (SettingsPageListItem)stackLayout.BindingContext;
if (item.ShowTimeInput)
{
var timePicker = stackLayout.Children.Where(x => x is TimePicker).FirstOrDefault();
((TimePicker)timePicker)?.Focus();
}
}
async void OnTimePickerPropertyChanged(object sender, PropertyChangedEventArgs args)
{
var s = (TimePicker)sender;
var time = s.Time.TotalMinutes;
if (s.IsFocused && args.PropertyName == "Time")
{
await _vm.VaultTimeoutAsync(false, (int)time);
}
}
private void RowSelected(object sender, SelectionChangedEventArgs e)
{
((ExtendedCollectionView)sender).SelectedItem = null;
if (e.CurrentSelection?.FirstOrDefault() is SettingsPageListItem item)
{
_vm?.ExecuteSettingItemCommand.Execute(item);
}
}
}
}

View File

@@ -1,12 +0,0 @@
namespace Bit.App.Pages
{
public class SettingsPageHeaderListItem : ISettingsPageListItem
{
public SettingsPageHeaderListItem(string title)
{
Title = title;
}
public string Title { get; }
}
}

View File

@@ -1,29 +0,0 @@
using System.Collections.Generic;
namespace Bit.App.Pages
{
public class SettingsPageListGroup : List<SettingsPageListItem>
{
public SettingsPageListGroup(List<SettingsPageListItem> groupItems, string name, bool doUpper = true,
bool first = false)
{
AddRange(groupItems);
if (string.IsNullOrWhiteSpace(name))
{
Name = "-";
}
else if (doUpper)
{
Name = name.ToUpperInvariant();
}
else
{
Name = name;
}
First = first;
}
public bool First { get; set; }
public string Name { get; set; }
}
}

View File

@@ -1,52 +0,0 @@
using System;
using System.Globalization;
using System.Threading.Tasks;
using Bit.App.Resources;
using Bit.App.Utilities;
using Bit.App.Utilities.Automation;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public class SettingsPageListItem : ISettingsPageListItem
{
public string Icon { get; set; }
public string Name { get; set; }
public string SubLabel { get; set; }
public TimeSpan? Time { get; set; }
public bool UseFrame { get; set; }
public Func<Task> ExecuteAsync { get; set; }
public bool SubLabelTextEnabled => SubLabel == AppResources.On;
public string LineBreakMode => SubLabel == null ? "TailTruncation" : "";
public bool ShowSubLabel => SubLabel.Length != 0;
public bool ShowTimeInput => Time != null;
public Color SubLabelColor => SubLabelTextEnabled ?
ThemeManager.GetResourceColor("SuccessColor") :
ThemeManager.GetResourceColor("MutedColor");
public string AutomationIdSettingName
{
get
{
return AutomationIdsHelper.AddSuffixFor(
UseFrame ? "EnabledPolicy"
: AutomationIdsHelper.ToEnglishTitleCase(Name)
, SuffixType.Cell);
}
}
public string AutomationIdSettingStatus
{
get
{
if (UseFrame)
{
return null;
}
return AutomationIdsHelper.AddSuffixFor(AutomationIdsHelper.ToEnglishTitleCase(Name), SuffixType.SettingValue);
}
}
}
}

View File

@@ -1,24 +0,0 @@
using Xamarin.Forms;
namespace Bit.App.Pages
{
public class SettingsPageListItemSelector : DataTemplateSelector
{
public DataTemplate HeaderTemplate { get; set; }
public DataTemplate RegularTemplate { get; set; }
public DataTemplate TimePickerTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
if (item is SettingsPageHeaderListItem)
{
return HeaderTemplate;
}
if (item is SettingsPageListItem listItem)
{
return listItem.ShowTimeInput ? TimePickerTemplate : RegularTemplate;
}
return null;
}
}
}

View File

@@ -1,903 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Bit.App.Abstractions;
using Bit.App.Pages.Accounts;
using Bit.App.Resources;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Models.Domain;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public class SettingsPageViewModel : BaseViewModel
{
private readonly IPlatformUtilsService _platformUtilsService;
private readonly ICryptoService _cryptoService;
private readonly IStateService _stateService;
private readonly IDeviceActionService _deviceActionService;
private readonly IAutofillHandler _autofillHandler;
private readonly IEnvironmentService _environmentService;
private readonly IMessagingService _messagingService;
private readonly IVaultTimeoutService _vaultTimeoutService;
private readonly ISyncService _syncService;
private readonly IBiometricService _biometricService;
private readonly IPolicyService _policyService;
private readonly ILocalizeService _localizeService;
private readonly IUserVerificationService _userVerificationService;
private readonly IClipboardService _clipboardService;
private readonly ILogger _loggerService;
private readonly IPushNotificationService _pushNotificationService;
private readonly IAuthService _authService;
private readonly IWatchDeviceService _watchDeviceService;
private const int CustomVaultTimeoutValue = -100;
private bool _supportsBiometric;
private bool _pin;
private bool _biometric;
private bool _screenCaptureAllowed;
private string _lastSyncDate;
private string _vaultTimeoutDisplayValue;
private string _vaultTimeoutActionDisplayValue;
private bool _showChangeMasterPassword;
private bool _reportLoggingEnabled;
private bool _approvePasswordlessLoginRequests;
private bool _shouldConnectToWatch;
private bool _hasMasterPassword;
private readonly static List<KeyValuePair<string, int?>> VaultTimeoutOptions =
new List<KeyValuePair<string, int?>>
{
new KeyValuePair<string, int?>(AppResources.Immediately, 0),
new KeyValuePair<string, int?>(AppResources.OneMinute, 1),
new KeyValuePair<string, int?>(AppResources.FiveMinutes, 5),
new KeyValuePair<string, int?>(AppResources.FifteenMinutes, 15),
new KeyValuePair<string, int?>(AppResources.ThirtyMinutes, 30),
new KeyValuePair<string, int?>(AppResources.OneHour, 60),
new KeyValuePair<string, int?>(AppResources.FourHours, 240),
new KeyValuePair<string, int?>(AppResources.OnRestart, -1),
new KeyValuePair<string, int?>(AppResources.Never, null),
new KeyValuePair<string, int?>(AppResources.Custom, CustomVaultTimeoutValue),
};
private readonly static List<KeyValuePair<string, VaultTimeoutAction>> VaultTimeoutActionOptions =
new List<KeyValuePair<string, VaultTimeoutAction>>
{
new KeyValuePair<string, VaultTimeoutAction>(AppResources.Lock, VaultTimeoutAction.Lock),
new KeyValuePair<string, VaultTimeoutAction>(AppResources.LogOut, VaultTimeoutAction.Logout),
};
private Policy _vaultTimeoutPolicy;
private int? _vaultTimeout;
private List<KeyValuePair<string, int?>> _vaultTimeoutOptions = VaultTimeoutOptions;
private List<KeyValuePair<string, VaultTimeoutAction>> _vaultTimeoutActionOptions = VaultTimeoutActionOptions;
public SettingsPageViewModel()
{
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
_cryptoService = ServiceContainer.Resolve<ICryptoService>("cryptoService");
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
_autofillHandler = ServiceContainer.Resolve<IAutofillHandler>();
_environmentService = ServiceContainer.Resolve<IEnvironmentService>("environmentService");
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
_biometricService = ServiceContainer.Resolve<IBiometricService>("biometricService");
_policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
_localizeService = ServiceContainer.Resolve<ILocalizeService>("localizeService");
_userVerificationService = ServiceContainer.Resolve<IUserVerificationService>();
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
_loggerService = ServiceContainer.Resolve<ILogger>("logger");
_pushNotificationService = ServiceContainer.Resolve<IPushNotificationService>();
_authService = ServiceContainer.Resolve<IAuthService>();
_watchDeviceService = ServiceContainer.Resolve<IWatchDeviceService>();
GroupedItems = new ObservableRangeCollection<ISettingsPageListItem>();
PageTitle = AppResources.Settings;
ExecuteSettingItemCommand = new AsyncCommand<SettingsPageListItem>(item => item.ExecuteAsync(), onException: _loggerService.Exception, allowsMultipleExecutions: false);
}
private bool IsVaultTimeoutActionLockAllowed => _hasMasterPassword || _biometric || _pin;
public ObservableRangeCollection<ISettingsPageListItem> GroupedItems { get; set; }
public IAsyncCommand<SettingsPageListItem> ExecuteSettingItemCommand { get; }
public async Task InitAsync()
{
var decryptionOptions = await _stateService.GetAccountDecryptionOptions();
// set has true for backwards compatibility
_hasMasterPassword = decryptionOptions?.HasMasterPassword ?? true;
_supportsBiometric = await _platformUtilsService.SupportsBiometricAsync();
var lastSync = await _syncService.GetLastSyncAsync();
if (lastSync != null)
{
lastSync = lastSync.Value.ToLocalTime();
_lastSyncDate = string.Format("{0} {1}",
_localizeService.GetLocaleShortDate(lastSync.Value),
_localizeService.GetLocaleShortTime(lastSync.Value));
}
_vaultTimeoutPolicy = null;
_vaultTimeoutOptions = VaultTimeoutOptions;
_vaultTimeoutActionOptions = VaultTimeoutActionOptions;
_vaultTimeout = await _vaultTimeoutService.GetVaultTimeout();
_vaultTimeoutDisplayValue = _vaultTimeoutOptions.FirstOrDefault(o => o.Value == _vaultTimeout).Key;
_vaultTimeoutDisplayValue ??= _vaultTimeoutOptions.Where(o => o.Value == CustomVaultTimeoutValue).First().Key;
var pinSet = await _vaultTimeoutService.GetPinLockTypeAsync();
_pin = pinSet != PinLockType.Disabled;
_biometric = await _vaultTimeoutService.IsBiometricLockSetAsync();
var timeoutAction = await _vaultTimeoutService.GetVaultTimeoutAction() ?? VaultTimeoutAction.Lock;
if (!IsVaultTimeoutActionLockAllowed && timeoutAction == VaultTimeoutAction.Lock)
{
timeoutAction = VaultTimeoutAction.Logout;
await _vaultTimeoutService.SetVaultTimeoutOptionsAsync(_vaultTimeout, VaultTimeoutAction.Logout);
}
_vaultTimeoutActionDisplayValue = _vaultTimeoutActionOptions.FirstOrDefault(o => o.Value == timeoutAction).Key;
if (await _policyService.PolicyAppliesToUser(PolicyType.MaximumVaultTimeout))
{
// if we have a vault timeout policy, we need to filter the timeout options
_vaultTimeoutPolicy = (await _policyService.GetAll(PolicyType.MaximumVaultTimeout)).First();
var policyMinutes = _vaultTimeoutPolicy.GetInt(Policy.MINUTES_KEY);
_vaultTimeoutOptions = _vaultTimeoutOptions.Where(t =>
t.Value <= policyMinutes &&
(t.Value > 0 || t.Value == CustomVaultTimeoutValue) &&
t.Value != null).ToList();
}
_screenCaptureAllowed = await _stateService.GetScreenCaptureAllowedAsync();
if (_vaultTimeoutDisplayValue == null)
{
_vaultTimeoutDisplayValue = AppResources.Custom;
}
_showChangeMasterPassword = IncludeLinksWithSubscriptionInfo() && await _userVerificationService.HasMasterPasswordAsync();
_reportLoggingEnabled = await _loggerService.IsEnabled();
_approvePasswordlessLoginRequests = await _stateService.GetApprovePasswordlessLoginsAsync();
_shouldConnectToWatch = await _stateService.GetShouldConnectToWatchAsync();
BuildList();
}
public async Task AboutAsync()
{
var debugText = string.Format("{0}: {1} ({2})", AppResources.Version,
_platformUtilsService.GetApplicationVersion(), _deviceActionService.GetBuildNumber());
#if DEBUG
var pushNotificationsRegistered = ServiceContainer.Resolve<IPushNotificationService>("pushNotificationService").IsRegisteredForPush;
var pnServerRegDate = await _stateService.GetPushLastRegistrationDateAsync();
var pnServerError = await _stateService.GetPushInstallationRegistrationErrorAsync();
var pnServerRegDateMessage = default(DateTime) == pnServerRegDate ? "-" : $"{pnServerRegDate.GetValueOrDefault().ToShortDateString()}-{pnServerRegDate.GetValueOrDefault().ToShortTimeString()} UTC";
var errorMessage = string.IsNullOrEmpty(pnServerError) ? string.Empty : $"Push Notifications Server Registration error: {pnServerError}";
var text = string.Format("© Bitwarden Inc. 2015-{0}\n\n{1}\nPush Notifications registered:{2}\nPush Notifications Server Last Date :{3}\n{4}", DateTime.Now.Year, debugText, pushNotificationsRegistered, pnServerRegDateMessage, errorMessage);
#else
var text = string.Format("© Bitwarden Inc. 2015-{0}\n\n{1}", DateTime.Now.Year, debugText);
#endif
var copy = await _platformUtilsService.ShowDialogAsync(text, AppResources.Bitwarden, AppResources.Copy,
AppResources.Close);
if (copy)
{
await _clipboardService.CopyTextAsync(debugText);
}
}
public void Help()
{
_platformUtilsService.LaunchUri("https://bitwarden.com/help/");
}
public async Task FingerprintAsync()
{
List<string> fingerprint;
try
{
fingerprint = await _cryptoService.GetFingerprintAsync(await _stateService.GetActiveUserIdAsync());
}
catch (Exception e) when (e.Message == "No public key available.")
{
return;
}
var phrase = string.Join("-", fingerprint);
var text = string.Format("{0}:\n\n{1}", AppResources.YourAccountsFingerprint, phrase);
var learnMore = await _platformUtilsService.ShowDialogAsync(text, AppResources.FingerprintPhrase,
AppResources.LearnMore, AppResources.Close);
if (learnMore)
{
_platformUtilsService.LaunchUri("https://bitwarden.com/help/fingerprint-phrase/");
}
}
public void Rate()
{
_deviceActionService.RateApp();
}
public void Import()
{
_platformUtilsService.LaunchUri("https://bitwarden.com/help/import-data/");
}
public void WebVault()
{
_platformUtilsService.LaunchUri(_environmentService.GetWebVaultUrl());
}
public async Task ShareAsync()
{
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.LearnOrgConfirmation,
AppResources.LearnOrg, AppResources.Yes, AppResources.Cancel);
if (confirmed)
{
_platformUtilsService.LaunchUri("https://bitwarden.com/help/about-organizations/");
}
}
public async Task TwoStepAsync()
{
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.TwoStepLoginConfirmation,
AppResources.TwoStepLogin, AppResources.Yes, AppResources.Cancel);
if (confirmed)
{
_platformUtilsService.LaunchUri($"{_environmentService.GetWebVaultUrl()}/#/settings");
}
}
public async Task ChangePasswordAsync()
{
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.ChangePasswordConfirmation,
AppResources.ChangeMasterPassword, AppResources.Yes, AppResources.Cancel);
if (confirmed)
{
_platformUtilsService.LaunchUri($"{_environmentService.GetWebVaultUrl()}/#/settings");
}
}
public async Task LogOutAsync()
{
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.LogoutConfirmation,
AppResources.LogOut, AppResources.Yes, AppResources.Cancel);
if (confirmed)
{
_messagingService.Send("logout");
}
}
public async Task LockAsync()
{
await _vaultTimeoutService.LockAsync(true, true);
}
public async Task VaultTimeoutAsync(bool promptOptions = true, int? newTimeout = 0)
{
var oldTimeout = _vaultTimeout;
var options = _vaultTimeoutOptions.Select(
o => o.Key == _vaultTimeoutDisplayValue ? $"✓ {o.Key}" : o.Key).ToArray();
if (promptOptions)
{
var selection = await Page.DisplayActionSheet(AppResources.VaultTimeout,
AppResources.Cancel, null, options);
if (selection == null || selection == AppResources.Cancel)
{
return;
}
var cleanSelection = selection.Replace("✓ ", string.Empty);
var selectionOption = _vaultTimeoutOptions.FirstOrDefault(o => o.Key == cleanSelection);
// Check if the selected Timeout action is "Never" and if it's different from the previous selected value
if (selectionOption.Value == null && selectionOption.Value != oldTimeout)
{
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.NeverLockWarning,
AppResources.Warning, AppResources.Yes, AppResources.Cancel);
if (!confirmed)
{
return;
}
}
_vaultTimeoutDisplayValue = selectionOption.Key;
newTimeout = selectionOption.Value;
}
if (_vaultTimeoutPolicy != null)
{
var maximumTimeout = _vaultTimeoutPolicy.GetInt(Policy.MINUTES_KEY);
if (newTimeout > maximumTimeout)
{
await _platformUtilsService.ShowDialogAsync(AppResources.VaultTimeoutToLarge, AppResources.Warning);
var timeout = await _vaultTimeoutService.GetVaultTimeout();
_vaultTimeoutDisplayValue = _vaultTimeoutOptions.FirstOrDefault(o => o.Value == timeout).Key ??
AppResources.Custom;
return;
}
}
await _vaultTimeoutService.SetVaultTimeoutOptionsAsync(newTimeout,
GetVaultTimeoutActionFromKey(_vaultTimeoutActionDisplayValue));
if (newTimeout != CustomVaultTimeoutValue)
{
_vaultTimeout = newTimeout;
}
if (oldTimeout != newTimeout)
{
await _cryptoService.RefreshKeysAsync();
await Device.InvokeOnMainThreadAsync(BuildList);
}
}
public async Task LoggerReportingAsync()
{
var options = new[]
{
CreateSelectableOption(AppResources.Yes, _reportLoggingEnabled),
CreateSelectableOption(AppResources.No, !_reportLoggingEnabled),
};
var selection = await Page.DisplayActionSheet(AppResources.SubmitCrashLogsDescription, AppResources.Cancel, null, options);
if (selection == null || selection == AppResources.Cancel)
{
return;
}
await _loggerService.SetEnabled(CompareSelection(selection, AppResources.Yes));
_reportLoggingEnabled = await _loggerService.IsEnabled();
BuildList();
}
public async Task ApproveLoginRequestsAsync()
{
var options = new[]
{
CreateSelectableOption(AppResources.Yes, _approvePasswordlessLoginRequests),
CreateSelectableOption(AppResources.No, !_approvePasswordlessLoginRequests),
};
var selection = await Page.DisplayActionSheet(AppResources.UseThisDeviceToApproveLoginRequestsMadeFromOtherDevices, AppResources.Cancel, null, options);
if (selection == null || selection == AppResources.Cancel)
{
return;
}
_approvePasswordlessLoginRequests = CompareSelection(selection, AppResources.Yes);
await _stateService.SetApprovePasswordlessLoginsAsync(_approvePasswordlessLoginRequests);
BuildList();
if (!_approvePasswordlessLoginRequests || await _pushNotificationService.AreNotificationsSettingsEnabledAsync())
{
return;
}
var openAppSettingsResult = await _platformUtilsService.ShowDialogAsync(AppResources.ReceivePushNotificationsForNewLoginRequests, title: string.Empty, confirmText: AppResources.Settings, cancelText: AppResources.NoThanks);
if (openAppSettingsResult)
{
_deviceActionService.OpenAppSettings();
}
}
public async Task VaultTimeoutActionAsync()
{
if (_vaultTimeoutPolicy != null &&
!string.IsNullOrEmpty(_vaultTimeoutPolicy.GetString(Policy.ACTION_KEY)))
{
// do nothing if we have a policy set
return;
}
var options = IsVaultTimeoutActionLockAllowed
? _vaultTimeoutActionOptions.Select(o => CreateSelectableOption(o.Key, _vaultTimeoutActionDisplayValue == o.Key)).ToArray()
: _vaultTimeoutActionOptions.Where(o => o.Value == VaultTimeoutAction.Logout).Select(v => ToSelectedOption(v.Key)).ToArray();
var selection = await Page.DisplayActionSheet(AppResources.VaultTimeoutAction,
AppResources.Cancel, null, options);
if (selection == null || selection == AppResources.Cancel)
{
return;
}
var cleanSelection = selection.Replace("✓ ", string.Empty);
if (cleanSelection == AppResources.LogOut)
{
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.VaultTimeoutLogOutConfirmation,
AppResources.Warning, AppResources.Yes, AppResources.Cancel);
if (!confirmed)
{
// Reset to lock and continue process as if lock were selected
cleanSelection = AppResources.Lock;
}
}
var selectionOption = _vaultTimeoutActionOptions.FirstOrDefault(o => o.Key == cleanSelection);
var changed = _vaultTimeoutActionDisplayValue != selectionOption.Key;
_vaultTimeoutActionDisplayValue = selectionOption.Key;
await _vaultTimeoutService.SetVaultTimeoutOptionsAsync(_vaultTimeout,
selectionOption.Value);
if (changed)
{
_messagingService.Send("vaultTimeoutActionChanged");
}
BuildList();
}
public async Task UpdatePinAsync()
{
_pin = !_pin;
if (_pin)
{
var pin = await _deviceActionService.DisplayPromptAync(AppResources.EnterPIN,
AppResources.SetPINDescription, null, AppResources.Submit, AppResources.Cancel, true);
if (!string.IsNullOrWhiteSpace(pin))
{
var masterPassOnRestart = false;
if (await _userVerificationService.HasMasterPasswordAsync())
{
masterPassOnRestart = await _platformUtilsService.ShowDialogAsync(
AppResources.PINRequireMasterPasswordRestart, AppResources.UnlockWithPIN,
AppResources.Yes, AppResources.No);
}
var kdfConfig = await _stateService.GetActiveUserCustomDataAsync(a => new KdfConfig(a?.Profile));
var email = await _stateService.GetEmailAsync();
var pinKey = await _cryptoService.MakePinKeyAsync(pin, email, kdfConfig);
var userKey = await _cryptoService.GetUserKeyAsync();
var protectedPinKey = await _cryptoService.EncryptAsync(userKey.Key, pinKey);
var encPin = await _cryptoService.EncryptAsync(pin);
await _stateService.SetProtectedPinAsync(encPin.EncryptedString);
if (masterPassOnRestart)
{
await _stateService.SetPinKeyEncryptedUserKeyEphemeralAsync(protectedPinKey);
}
else
{
await _stateService.SetPinKeyEncryptedUserKeyAsync(protectedPinKey);
}
}
else
{
_pin = false;
}
}
if (!_pin)
{
await _vaultTimeoutService.ClearAsync();
await UpdateVaultTimeoutActionIfNeededAsync();
}
BuildList();
}
public async Task UpdateBiometricAsync()
{
var current = _biometric;
if (_biometric)
{
_biometric = false;
}
else if (await _platformUtilsService.SupportsBiometricAsync())
{
_biometric = await _platformUtilsService.AuthenticateBiometricAsync(null,
Device.RuntimePlatform == Device.Android ? "." : null);
}
if (_biometric == current)
{
return;
}
if (_biometric)
{
await _biometricService.SetupBiometricAsync();
await _stateService.SetBiometricUnlockAsync(true);
}
else
{
await _stateService.SetBiometricUnlockAsync(null);
await UpdateVaultTimeoutActionIfNeededAsync();
}
await _stateService.SetBiometricLockedAsync(false);
await _cryptoService.RefreshKeysAsync();
BuildList();
}
public void BuildList()
{
//TODO: Refactor this once navigation is abstracted so that it doesn't depend on Page, e.g. Page.Navigation.PushModalAsync...
var doUpper = Device.RuntimePlatform != Device.Android;
var autofillItems = new List<SettingsPageListItem>();
if (Device.RuntimePlatform == Device.Android)
{
autofillItems.Add(new SettingsPageListItem
{
Name = AppResources.AutofillServices,
SubLabel = _autofillHandler.AutofillServicesEnabled() ? AppResources.On : AppResources.Off,
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new AutofillServicesPage(Page as SettingsPage)))
});
}
else
{
if (_deviceActionService.SystemMajorVersion() >= 12)
{
autofillItems.Add(new SettingsPageListItem
{
Name = AppResources.PasswordAutofill,
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new AutofillPage()))
});
}
autofillItems.Add(new SettingsPageListItem
{
Name = AppResources.AppExtension,
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new ExtensionPage()))
});
}
var manageItems = new List<SettingsPageListItem>
{
new SettingsPageListItem
{
Name = AppResources.Folders,
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new FoldersPage()))
},
new SettingsPageListItem
{
Name = AppResources.Sync,
SubLabel = _lastSyncDate,
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new SyncPage()))
}
};
var securityItems = new List<SettingsPageListItem>
{
new SettingsPageListItem
{
Name = AppResources.VaultTimeout,
SubLabel = _vaultTimeoutDisplayValue,
ExecuteAsync = () => VaultTimeoutAsync() },
new SettingsPageListItem
{
Name = AppResources.VaultTimeoutAction,
SubLabel = _vaultTimeoutActionDisplayValue,
ExecuteAsync = () => VaultTimeoutActionAsync()
},
new SettingsPageListItem
{
Name = AppResources.UnlockWithPIN,
SubLabel = _pin ? AppResources.On : AppResources.Off,
ExecuteAsync = () => UpdatePinAsync()
},
new SettingsPageListItem
{
Name = AppResources.ApproveLoginRequests,
SubLabel = _approvePasswordlessLoginRequests ? AppResources.On : AppResources.Off,
ExecuteAsync = () => ApproveLoginRequestsAsync()
},
new SettingsPageListItem
{
Name = AppResources.LockNow,
ExecuteAsync = () => LockAsync()
},
new SettingsPageListItem
{
Name = AppResources.TwoStepLogin,
ExecuteAsync = () => TwoStepAsync()
}
};
if (_approvePasswordlessLoginRequests)
{
manageItems.Add(new SettingsPageListItem
{
Name = AppResources.PendingLogInRequests,
ExecuteAsync = () => PendingLoginRequestsAsync()
});
}
if (_supportsBiometric || _biometric)
{
var biometricName = AppResources.Biometrics;
if (Device.RuntimePlatform == Device.iOS)
{
biometricName = _deviceActionService.SupportsFaceBiometric() ? AppResources.FaceID :
AppResources.TouchID;
}
var item = new SettingsPageListItem
{
Name = string.Format(AppResources.UnlockWith, biometricName),
SubLabel = _biometric ? AppResources.On : AppResources.Off,
ExecuteAsync = () => UpdateBiometricAsync()
};
securityItems.Insert(2, item);
}
if (_vaultTimeoutDisplayValue == AppResources.Custom)
{
securityItems.Insert(1, new SettingsPageListItem
{
Name = AppResources.Custom,
Time = TimeSpan.FromMinutes(Math.Abs((double)_vaultTimeout.GetValueOrDefault())),
});
}
if (_vaultTimeoutPolicy != null)
{
var policyMinutes = _vaultTimeoutPolicy.GetInt(Policy.MINUTES_KEY);
var policyAction = _vaultTimeoutPolicy.GetString(Policy.ACTION_KEY);
if (policyMinutes.HasValue || !string.IsNullOrWhiteSpace(policyAction))
{
string policyAlert;
if (policyMinutes.HasValue && string.IsNullOrWhiteSpace(policyAction))
{
policyAlert = string.Format(AppResources.VaultTimeoutPolicyInEffect,
Math.Floor((float)policyMinutes / 60),
policyMinutes % 60);
}
else if (!policyMinutes.HasValue && !string.IsNullOrWhiteSpace(policyAction))
{
policyAlert = string.Format(AppResources.VaultTimeoutActionPolicyInEffect,
policyAction == Policy.ACTION_LOCK ? AppResources.Lock : AppResources.LogOut);
}
else
{
policyAlert = string.Format(AppResources.VaultTimeoutPolicyWithActionInEffect,
Math.Floor((float)policyMinutes / 60),
policyMinutes % 60,
policyAction == Policy.ACTION_LOCK ? AppResources.Lock : AppResources.LogOut);
}
securityItems.Insert(0, new SettingsPageListItem
{
Name = policyAlert,
UseFrame = true,
});
}
}
if (Device.RuntimePlatform == Device.Android)
{
securityItems.Add(new SettingsPageListItem
{
Name = AppResources.AllowScreenCapture,
SubLabel = _screenCaptureAllowed ? AppResources.On : AppResources.Off,
ExecuteAsync = () => SetScreenCaptureAllowedAsync()
});
}
var accountItems = new List<SettingsPageListItem>();
if (Device.RuntimePlatform == Device.iOS)
{
accountItems.Add(new SettingsPageListItem
{
Name = AppResources.ConnectToWatch,
SubLabel = _shouldConnectToWatch ? AppResources.On : AppResources.Off,
ExecuteAsync = () => ToggleWatchConnectionAsync()
});
}
accountItems.Add(new SettingsPageListItem
{
Name = AppResources.FingerprintPhrase,
ExecuteAsync = () => FingerprintAsync()
});
accountItems.Add(new SettingsPageListItem
{
Name = AppResources.LogOut,
ExecuteAsync = () => LogOutAsync()
});
if (_showChangeMasterPassword)
{
accountItems.Insert(0, new SettingsPageListItem
{
Name = AppResources.ChangeMasterPassword,
ExecuteAsync = () => ChangePasswordAsync()
});
}
var toolsItems = new List<SettingsPageListItem>
{
new SettingsPageListItem
{
Name = AppResources.ImportItems,
ExecuteAsync = () => Device.InvokeOnMainThreadAsync(() => Import())
},
new SettingsPageListItem
{
Name = AppResources.ExportVault,
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new ExportVaultPage()))
}
};
if (IncludeLinksWithSubscriptionInfo())
{
toolsItems.Add(new SettingsPageListItem
{
Name = AppResources.LearnOrg,
ExecuteAsync = () => ShareAsync()
});
toolsItems.Add(new SettingsPageListItem
{
Name = AppResources.WebVault,
ExecuteAsync = () => Device.InvokeOnMainThreadAsync(() => WebVault())
});
}
var otherItems = new List<SettingsPageListItem>
{
new SettingsPageListItem
{
Name = AppResources.Options,
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new OptionsPage()))
},
new SettingsPageListItem
{
Name = AppResources.About,
ExecuteAsync = () => AboutAsync()
},
new SettingsPageListItem
{
Name = AppResources.HelpAndFeedback,
ExecuteAsync = () => Device.InvokeOnMainThreadAsync(() => Help())
},
#if !FDROID
new SettingsPageListItem
{
Name = AppResources.SubmitCrashLogs,
SubLabel = _reportLoggingEnabled ? AppResources.On : AppResources.Off,
ExecuteAsync = () => LoggerReportingAsync()
},
#endif
new SettingsPageListItem
{
Name = AppResources.RateTheApp,
ExecuteAsync = () => Device.InvokeOnMainThreadAsync(() => Rate())
},
new SettingsPageListItem
{
Name = AppResources.DeleteAccount,
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new DeleteAccountPage()))
}
};
// TODO: improve this. Leaving this as is to reduce error possibility on the hotfix.
var settingsListGroupItems = new List<SettingsPageListGroup>()
{
new SettingsPageListGroup(autofillItems, AppResources.Autofill, doUpper, true),
new SettingsPageListGroup(manageItems, AppResources.Manage, doUpper),
new SettingsPageListGroup(securityItems, AppResources.Security, doUpper),
new SettingsPageListGroup(accountItems, AppResources.Account, doUpper),
new SettingsPageListGroup(toolsItems, AppResources.Tools, doUpper),
new SettingsPageListGroup(otherItems, AppResources.Other, doUpper)
};
// TODO: refactor this
if (Device.RuntimePlatform == Device.Android
||
GroupedItems.Any())
{
var items = new List<ISettingsPageListItem>();
foreach (var itemGroup in settingsListGroupItems)
{
items.Add(new SettingsPageHeaderListItem(itemGroup.Name));
items.AddRange(itemGroup);
}
GroupedItems.ReplaceRange(items);
}
else
{
// HACK: we need this on iOS, so that it doesn't crash when adding coming from an empty list
var first = true;
var items = new List<ISettingsPageListItem>();
foreach (var itemGroup in settingsListGroupItems)
{
if (!first)
{
items.Add(new SettingsPageHeaderListItem(itemGroup.Name));
}
else
{
first = false;
}
items.AddRange(itemGroup);
}
if (settingsListGroupItems.Any())
{
GroupedItems.ReplaceRange(new List<ISettingsPageListItem> { new SettingsPageHeaderListItem(settingsListGroupItems[0].Name) });
GroupedItems.AddRange(items);
}
else
{
GroupedItems.Clear();
}
}
}
private async Task PendingLoginRequestsAsync()
{
try
{
var requests = await _authService.GetActivePasswordlessLoginRequestsAsync();
if (requests == null || !requests.Any())
{
_platformUtilsService.ShowToast("info", null, AppResources.NoPendingRequests);
return;
}
Page.Navigation.PushModalAsync(new NavigationPage(new LoginPasswordlessRequestsListPage())).FireAndForget();
}
catch (Exception ex)
{
HandleException(ex);
}
}
private bool IncludeLinksWithSubscriptionInfo()
{
if (Device.RuntimePlatform == Device.iOS)
{
return false;
}
return true;
}
private VaultTimeoutAction GetVaultTimeoutActionFromKey(string key)
{
return _vaultTimeoutActionOptions.FirstOrDefault(o => o.Key == key).Value;
}
private int? GetVaultTimeoutFromKey(string key)
{
return _vaultTimeoutOptions.FirstOrDefault(o => o.Key == key).Value;
}
private string CreateSelectableOption(string option, bool selected) => selected ? ToSelectedOption(option) : option;
private bool CompareSelection(string selection, string compareTo) => selection == compareTo || selection == ToSelectedOption(compareTo);
private string ToSelectedOption(string option) => $"✓ {option}";
public async Task SetScreenCaptureAllowedAsync()
{
try
{
if (!_screenCaptureAllowed
&&
!await Page.DisplayAlert(AppResources.AllowScreenCapture, AppResources.AreYouSureYouWantToEnableScreenCapture, AppResources.Yes, AppResources.No))
{
return;
}
await _stateService.SetScreenCaptureAllowedAsync(!_screenCaptureAllowed);
_screenCaptureAllowed = !_screenCaptureAllowed;
await _deviceActionService.SetScreenCaptureAllowedAsync();
BuildList();
}
catch (Exception ex)
{
_loggerService.Exception(ex);
await Page.DisplayAlert(AppResources.AnErrorHasOccurred, AppResources.GenericErrorMessage, AppResources.Ok);
}
}
private async Task ToggleWatchConnectionAsync()
{
_shouldConnectToWatch = !_shouldConnectToWatch;
await _watchDeviceService.SetShouldConnectToWatchAsync(_shouldConnectToWatch);
BuildList();
}
private async Task UpdateVaultTimeoutActionIfNeededAsync()
{
if (IsVaultTimeoutActionLockAllowed)
{
return;
}
_vaultTimeoutActionDisplayValue = _vaultTimeoutActionOptions.First(o => o.Value == VaultTimeoutAction.Logout).Key;
await _vaultTimeoutService.SetVaultTimeoutOptionsAsync(_vaultTimeout, VaultTimeoutAction.Logout);
_deviceActionService.Toast(AppResources.VaultTimeoutActionChangedToLogOut);
}
}
}

View File

@@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<pages:BaseContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.SyncPage"
xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:u="clr-namespace:Bit.App.Utilities"
x:DataType="pages:SyncPageViewModel"
Title="{Binding PageTitle}">
<ContentPage.BindingContext>
<pages:SyncPageViewModel />
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
</ContentPage.ToolbarItems>
<ScrollView Padding="0, 0, 0, 20">
<StackLayout Padding="0" Spacing="20">
<StackLayout StyleClass="box">
<StackLayout StyleClass="box-row, box-row-switch">
<Label
Text="{u:I18n EnableSyncOnRefresh}"
StyleClass="box-label-regular"
HorizontalOptions="StartAndExpand" />
<Switch
IsToggled="{Binding EnableSyncOnRefresh}"
StyleClass="box-value"
HorizontalOptions="End" />
</StackLayout>
<Label
Text="{u:I18n EnableSyncOnRefreshDescription}"
StyleClass="box-footer-label, box-footer-label-switch" />
</StackLayout>
<StackLayout StyleClass="box">
<Button Text="{u:I18n SyncVaultNow}" Clicked="Sync_Clicked"></Button>
<Label StyleClass="text-muted, text-sm" HorizontalTextAlignment="Center" Margin="0,10">
<Label.FormattedText>
<FormattedString>
<Span Text="{u:I18n LastSync}" />
<Span Text=" " />
<Span Text="{Binding LastSync}" />
</FormattedString>
</Label.FormattedText>
</Label>
</StackLayout>
</StackLayout>
</ScrollView>
</pages:BaseContentPage>

View File

@@ -1,43 +0,0 @@
using System;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public partial class SyncPage : BaseContentPage
{
private readonly SyncPageViewModel _vm;
public SyncPage()
{
InitializeComponent();
_vm = BindingContext as SyncPageViewModel;
_vm.Page = this;
if (Device.RuntimePlatform == Device.Android)
{
ToolbarItems.RemoveAt(0);
}
}
protected async override void OnAppearing()
{
base.OnAppearing();
await _vm.InitAsync();
}
private async void Sync_Clicked(object sender, EventArgs e)
{
if (DoOnce())
{
await _vm.SyncAsync();
}
}
private async void Close_Clicked(object sender, System.EventArgs e)
{
if (DoOnce())
{
await Navigation.PopModalAsync();
}
}
}
}

View File

@@ -1,117 +0,0 @@
using System.Threading.Tasks;
using Bit.App.Abstractions;
using Bit.App.Resources;
using Bit.Core.Abstractions;
using Bit.Core.Exceptions;
using Bit.Core.Utilities;
namespace Bit.App.Pages
{
public class SyncPageViewModel : BaseViewModel
{
private readonly IDeviceActionService _deviceActionService;
private readonly IPlatformUtilsService _platformUtilsService;
private readonly IStateService _stateService;
private readonly ISyncService _syncService;
private readonly ILocalizeService _localizeService;
private string _lastSync = "--";
private bool _inited;
private bool _syncOnRefresh;
public SyncPageViewModel()
{
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
_localizeService = ServiceContainer.Resolve<ILocalizeService>("localizeService");
PageTitle = AppResources.Sync;
}
public bool EnableSyncOnRefresh
{
get => _syncOnRefresh;
set
{
if (SetProperty(ref _syncOnRefresh, value))
{
var task = UpdateSyncOnRefreshAsync();
}
}
}
public string LastSync
{
get => _lastSync;
set => SetProperty(ref _lastSync, value);
}
public async Task InitAsync()
{
await SetLastSyncAsync();
EnableSyncOnRefresh = await _stateService.GetSyncOnRefreshAsync();
_inited = true;
}
public async Task UpdateSyncOnRefreshAsync()
{
if (_inited)
{
await _stateService.SetSyncOnRefreshAsync(_syncOnRefresh);
}
}
public async Task SetLastSyncAsync()
{
var last = await _syncService.GetLastSyncAsync();
if (last != null)
{
var localDate = last.Value.ToLocalTime();
LastSync = string.Format("{0} {1}",
_localizeService.GetLocaleShortDate(localDate),
_localizeService.GetLocaleShortTime(localDate));
}
else
{
LastSync = AppResources.Never;
}
}
public async Task SyncAsync()
{
if (Xamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.None)
{
await _platformUtilsService.ShowDialogAsync(AppResources.InternetConnectionRequiredMessage,
AppResources.InternetConnectionRequiredTitle);
return;
}
try
{
await _deviceActionService.ShowLoadingAsync(AppResources.Syncing);
await _syncService.SyncPasswordlessLoginRequestsAsync();
var success = await _syncService.FullSyncAsync(true);
await _deviceActionService.HideLoadingAsync();
if (success)
{
await SetLastSyncAsync();
_platformUtilsService.ShowToast("success", null, AppResources.SyncingComplete);
}
else
{
await Page.DisplayAlert(null, AppResources.SyncingFailed, AppResources.Ok);
}
}
catch (ApiException e)
{
await _deviceActionService.HideLoadingAsync();
if (e?.Error != null)
{
await _platformUtilsService.ShowDialogAsync(e.Error.GetSingleMessage(),
AppResources.AnErrorHasOccurred);
}
}
}
}
}

View File

@@ -1,178 +0,0 @@
using System;
using System.Threading.Tasks;
using Bit.App.Effects;
using Bit.App.Models;
using Bit.App.Resources;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Models.Data;
using Bit.Core.Utilities;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public class TabsPage : TabbedPage
{
private readonly IBroadcasterService _broadcasterService;
private readonly IMessagingService _messagingService;
private readonly IKeyConnectorService _keyConnectorService;
private readonly IStateService _stateService;
private readonly LazyResolve<ILogger> _logger = new LazyResolve<ILogger>("logger");
private NavigationPage _groupingsPage;
private NavigationPage _sendGroupingsPage;
private NavigationPage _generatorPage;
public TabsPage(AppOptions appOptions = null, PreviousPageInfo previousPage = null)
{
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
_keyConnectorService = ServiceContainer.Resolve<IKeyConnectorService>("keyConnectorService");
_stateService = ServiceContainer.Resolve<IStateService>();
_groupingsPage = new NavigationPage(new GroupingsPage(true, previousPage: previousPage))
{
Title = AppResources.MyVault,
IconImageSource = "lock.png"
};
Children.Add(_groupingsPage);
_sendGroupingsPage = new NavigationPage(new SendGroupingsPage(true, null, null, appOptions))
{
Title = AppResources.Send,
IconImageSource = "send.png",
};
Children.Add(_sendGroupingsPage);
_generatorPage = new NavigationPage(new GeneratorPage(true, null, this))
{
Title = AppResources.Generator,
IconImageSource = "generate.png"
};
Children.Add(_generatorPage);
var settingsPage = new NavigationPage(new SettingsPage(this))
{
Title = AppResources.Settings,
IconImageSource = "cog_settings.png"
};
Children.Add(settingsPage);
if (Device.RuntimePlatform == Device.Android)
{
Effects.Add(new TabBarEffect());
Xamarin.Forms.PlatformConfiguration.AndroidSpecific.TabbedPage.SetToolbarPlacement(this,
Xamarin.Forms.PlatformConfiguration.AndroidSpecific.ToolbarPlacement.Bottom);
Xamarin.Forms.PlatformConfiguration.AndroidSpecific.TabbedPage.SetIsSwipePagingEnabled(this, false);
Xamarin.Forms.PlatformConfiguration.AndroidSpecific.TabbedPage.SetIsSmoothScrollEnabled(this, false);
}
if (appOptions?.GeneratorTile ?? false)
{
appOptions.GeneratorTile = false;
ResetToGeneratorPage();
}
else if (appOptions?.MyVaultTile ?? false)
{
appOptions.MyVaultTile = false;
}
else if (appOptions?.CreateSend != null)
{
ResetToSendPage();
}
}
protected override async void OnAppearing()
{
base.OnAppearing();
_broadcasterService.Subscribe(nameof(TabsPage), async (message) =>
{
if (message.Command == "syncCompleted")
{
Device.BeginInvokeOnMainThread(async () => await UpdateVaultButtonTitleAsync());
}
});
await UpdateVaultButtonTitleAsync();
if (await _keyConnectorService.UserNeedsMigrationAsync())
{
_messagingService.Send("convertAccountToKeyConnector");
}
var forcePasswordResetReason = await _stateService.GetForcePasswordResetReasonAsync();
if (forcePasswordResetReason.HasValue)
{
_messagingService.Send(Constants.ForceUpdatePassword);
}
}
protected override void OnDisappearing()
{
base.OnDisappearing();
_broadcasterService.Unsubscribe(nameof(TabsPage));
}
public void ResetToVaultPage()
{
CurrentPage = _groupingsPage;
}
public void ResetToGeneratorPage()
{
CurrentPage = _generatorPage;
}
public void ResetToSendPage()
{
CurrentPage = _sendGroupingsPage;
}
protected async override void OnCurrentPageChanged()
{
if (CurrentPage is NavigationPage navPage)
{
if (_groupingsPage?.RootPage is GroupingsPage groupingsPage)
{
await groupingsPage.HideAccountSwitchingOverlayAsync();
}
_messagingService.Send("updatedTheme");
if (navPage.RootPage is GroupingsPage)
{
// Load something?
}
else if (navPage.RootPage is GeneratorPage genPage)
{
await genPage.InitAsync();
}
else if (navPage.RootPage is SettingsPage settingsPage)
{
await settingsPage.InitAsync();
}
}
}
public void OnPageReselected()
{
if (_groupingsPage?.RootPage is GroupingsPage groupingsPage)
{
groupingsPage.HideAccountSwitchingOverlayAsync().FireAndForget();
}
}
private async Task UpdateVaultButtonTitleAsync()
{
try
{
var policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
var isShowingVaultFilter = await policyService.ShouldShowVaultFilterAsync();
_groupingsPage.Title = isShowingVaultFilter ? AppResources.Vaults : AppResources.MyVault;
}
catch (Exception ex)
{
_logger.Value.Exception(ex);
}
}
}
}

View File

@@ -1,121 +0,0 @@
using System;
using System.Threading.Tasks;
using Bit.App.Resources;
using Bit.App.Utilities;
using Bit.Core.Abstractions;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public class GroupingsPageTOTPListItem : ExtendedViewModel, IGroupingsPageListItem
{
private readonly LazyResolve<ILogger> _logger = new LazyResolve<ILogger>("logger");
private readonly ITotpService _totpService;
private readonly IPlatformUtilsService _platformUtilsService;
private readonly IClipboardService _clipboardService;
private CipherView _cipher;
private bool _websiteIconsEnabled;
private string _iconImageSource = string.Empty;
private double _progress;
private string _totpSec;
private string _totpCodeFormatted;
private TotpHelper _totpTickHelper;
public GroupingsPageTOTPListItem(CipherView cipherView, bool websiteIconsEnabled)
{
_totpService = ServiceContainer.Resolve<ITotpService>("totpService");
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
Cipher = cipherView;
WebsiteIconsEnabled = websiteIconsEnabled;
CopyCommand = new AsyncCommand(CopyToClipboardAsync,
onException: ex => _logger.Value.Exception(ex),
allowsMultipleExecutions: false);
_totpTickHelper = new TotpHelper(cipherView);
}
public AsyncCommand CopyCommand { get; set; }
public CipherView Cipher
{
get => _cipher;
set => SetProperty(ref _cipher, value);
}
public string TotpCodeFormatted
{
get => _totpCodeFormatted;
set => SetProperty(ref _totpCodeFormatted, value,
additionalPropertyNames: new string[]
{
nameof(TotpCodeFormattedStart),
nameof(TotpCodeFormattedEnd),
});
}
public string TotpSec
{
get => _totpSec;
set => SetProperty(ref _totpSec, value);
}
public double Progress
{
get => _progress;
set => SetProperty(ref _progress, value);
}
public bool WebsiteIconsEnabled
{
get => _websiteIconsEnabled;
set => SetProperty(ref _websiteIconsEnabled, value);
}
public bool ShowIconImage
{
get => WebsiteIconsEnabled
&& !string.IsNullOrWhiteSpace(Cipher.Login?.Uri)
&& IconImageSource != null;
}
public string IconImageSource
{
get
{
if (_iconImageSource == string.Empty) // default value since icon source can return null
{
_iconImageSource = IconImageHelper.GetLoginIconImage(Cipher);
}
return _iconImageSource;
}
}
public string TotpCodeFormattedStart => TotpCodeFormatted?.Split(' ')[0];
public string TotpCodeFormattedEnd => TotpCodeFormatted?.Split(' ')[1];
public async Task CopyToClipboardAsync()
{
await _clipboardService.CopyTextAsync(TotpCodeFormatted?.Replace(" ", string.Empty));
_platformUtilsService.ShowToast("info", null, string.Format(AppResources.ValueHasBeenCopied, AppResources.VerificationCodeTotp));
}
public async Task TotpTickAsync()
{
await _totpTickHelper.GenerateNewTotpValues();
MainThread.BeginInvokeOnMainThread(() =>
{
TotpSec = _totpTickHelper.TotpSec;
Progress = _totpTickHelper.Progress;
TotpCodeFormatted = _totpTickHelper.TotpCodeFormatted;
});
}
}
}

View File

@@ -6,7 +6,7 @@ using Android.Views;
using System;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using Bit.Droid.Utilities;
using Bit.App.Droid.Utilities;
namespace Bit.Droid.Accessibility
{

View File

@@ -10,8 +10,13 @@ using Android.Runtime;
using Android.Views;
using Android.Views.Accessibility;
using Android.Widget;
using Bit.App.Resources;
using Bit.Core.Resources.Localization;
using Bit.Core;
using Application = Android.App.Application;
using View = Android.Views.View;
using Resource = Bit.Core.Resource;
using Point = Android.Graphics.Point;
using Rect = Android.Graphics.Rect;
namespace Bit.Droid.Accessibility
{
@@ -107,6 +112,7 @@ namespace Bit.Droid.Accessibility
new Browser("org.bromite.chromium", "url_bar"),
new Browser("org.chromium.chrome", "url_bar"),
new Browser("org.codeaurora.swe.browser", "url_bar"),
new Browser("org.cromite.cromite", "url_bar"),
new Browser("org.gnu.icecat", "url_bar_title,mozac_browser_toolbar_url_view"), // 2nd = Anticipation
new Browser("org.mozilla.fenix", "mozac_browser_toolbar_url_view"),
new Browser("org.mozilla.fenix.nightly", "mozac_browser_toolbar_url_view"), // [DEPRECATED ENTRY]
@@ -704,7 +710,7 @@ namespace Bit.Droid.Accessibility
public static LinearLayout GetOverlayView(Context context)
{
var inflater = (LayoutInflater)context.GetSystemService(Context.LayoutInflaterService);
var view = (LinearLayout)inflater.Inflate(Resource.Layout.autofill_listitem, null);
var view = (LinearLayout)inflater.Inflate(Bit.Core.Resource.Layout.autofill_listitem, null);
var text1 = (TextView)view.FindViewById(Resource.Id.text1);
var text2 = (TextView)view.FindViewById(Resource.Id.text2);
var icon = (ImageView)view.FindViewById(Resource.Id.icon);

View File

@@ -9,9 +9,10 @@ using Android.Runtime;
using Android.Views;
using Android.Views.Accessibility;
using Android.Widget;
using Bit.App.Resources;
using Bit.Core.Resources.Localization;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using View = Android.Views.View;
namespace Bit.Droid.Accessibility
{

View File

@@ -1,6 +1,6 @@
<?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="2023.8.1" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" />
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionCode="1" android:versionName="2024.2.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" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Some files were not shown because too many files have changed in this diff Show More