├── README.md ├── .swiftlint-ci.yml ├── Sources ├── InfomaniakCoreSwiftUI │ ├── Assets.xcassets │ │ ├── Contents.json │ │ └── Files │ │ │ ├── Contents.json │ │ │ ├── Colors │ │ │ ├── Contents.json │ │ │ ├── file-audio-color.colorset │ │ │ │ └── Contents.json │ │ │ ├── file-code-color.colorset │ │ │ │ └── Contents.json │ │ │ ├── file-doc-color.colorset │ │ │ │ └── Contents.json │ │ │ ├── file-font-color.colorset │ │ │ │ └── Contents.json │ │ │ ├── file-grid-color.colorset │ │ │ │ └── Contents.json │ │ │ ├── file-ics-color.colorset │ │ │ │ └── Contents.json │ │ │ ├── file-img-color.colorset │ │ │ │ └── Contents.json │ │ │ ├── file-pdf-color.colorset │ │ │ │ └── Contents.json │ │ │ ├── file-point-color.colorset │ │ │ │ └── Contents.json │ │ │ ├── file-vcard-color.colorset │ │ │ │ └── Contents.json │ │ │ ├── file-video-color.colorset │ │ │ │ └── Contents.json │ │ │ ├── file-archive-color.colorset │ │ │ │ └── Contents.json │ │ │ └── file-unknown-color.colorset │ │ │ │ └── Contents.json │ │ │ └── Images │ │ │ ├── Contents.json │ │ │ ├── file-audio.imageset │ │ │ ├── Contents.json │ │ │ └── file-audio.svg │ │ │ ├── file-code.imageset │ │ │ ├── Contents.json │ │ │ └── file-code.svg │ │ │ ├── file-doc.imageset │ │ │ ├── Contents.json │ │ │ └── file-doc.svg │ │ │ ├── file-font.imageset │ │ │ ├── Contents.json │ │ │ └── file-font.svg │ │ │ ├── file-grid.imageset │ │ │ ├── Contents.json │ │ │ └── file-grid.svg │ │ │ ├── file-ics.imageset │ │ │ ├── Contents.json │ │ │ └── file-ics.svg │ │ │ ├── file-img.imageset │ │ │ ├── Contents.json │ │ │ └── file-image.svg │ │ │ ├── file-pdf.imageset │ │ │ ├── Contents.json │ │ │ └── file-pdf.svg │ │ │ ├── file-point.imageset │ │ │ ├── Contents.json │ │ │ └── file-point.svg │ │ │ ├── file-vcard.imageset │ │ │ ├── Contents.json │ │ │ └── file-vcard.svg │ │ │ ├── file-video.imageset │ │ │ ├── Contents.json │ │ │ └── file-video.svg │ │ │ ├── file-archive.imageset │ │ │ ├── Contents.json │ │ │ └── file-archive.svg │ │ │ └── file-unknown.imageset │ │ │ ├── Contents.json │ │ │ └── file-unknown.svg │ ├── Resources │ │ ├── en.lproj │ │ │ └── Localizable.strings │ │ ├── de.lproj │ │ │ └── Localizable.strings │ │ ├── es.lproj │ │ │ └── Localizable.strings │ │ ├── fr.lproj │ │ │ └── Localizable.strings │ │ └── it.lproj │ │ │ └── Localizable.strings │ ├── Components │ │ ├── Buttons │ │ │ ├── Helpers │ │ │ │ └── IKButtonConstants.swift │ │ │ ├── Models │ │ │ │ ├── IKButtonHeight.swift │ │ │ │ └── IKButtonTheme.swift │ │ │ ├── IKSquareButtonStyle.swift │ │ │ └── ModalButtonsView.swift │ │ ├── SafariWebView.swift │ │ ├── AvatarView │ │ │ ├── AvatarImage.swift │ │ │ └── InitialsView.swift │ │ ├── FloatingPanelCloseButton.swift │ │ ├── ThemedLottieView.swift │ │ ├── CameraPickerView.swift │ │ ├── AlertView │ │ │ └── AskForReviewView.swift │ │ ├── Discovery │ │ │ └── DiscoveryPresenter.swift │ │ └── WebView.swift │ ├── Helpers │ │ ├── ReachabilityObserver.swift │ │ └── FileType │ │ │ ├── FileTypeProvider.swift │ │ │ └── FileType.swift │ ├── Extensions │ │ ├── IKIconSize+Image.swift │ │ └── IKPadding+View.swift │ ├── Style │ │ └── IKLabelStyle.swift │ ├── MandatoryEnvironmentContainer.swift │ ├── Modifiers │ │ ├── CompactWindowDetectorModifier.swift │ │ ├── SceneLifecycleModifier.swift │ │ └── FloatingPanelHelper.swift │ └── Alignment │ │ └── IconAndMultilineTextAlignment.swift ├── InfomaniakPrivacyManagement │ ├── Resources │ │ ├── Assets.xcassets │ │ │ ├── Contents.json │ │ │ ├── chevron-right.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── chevron-right.svg │ │ │ ├── matomo-short.imageset │ │ │ │ └── Contents.json │ │ │ ├── sentry-short.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── sentry.svg │ │ │ │ └── sentry-dark.svg │ │ │ ├── matomo-long.imageset │ │ │ │ └── Contents.json │ │ │ ├── sentry-long.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── sentry-text.svg │ │ │ │ └── sentry-text-dark.svg │ │ │ ├── backgroundColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── textPrimaryColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── textSecondaryColor.colorset │ │ │ │ └── Contents.json │ │ │ └── textTertiaryColor.colorset │ │ │ │ └── Contents.json │ │ └── Localizable │ │ │ ├── en.lproj │ │ │ └── Localizable.strings │ │ │ ├── it.lproj │ │ │ └── Localizable.strings │ │ │ ├── fr.lproj │ │ │ └── Localizable.strings │ │ │ ├── es.lproj │ │ │ └── Localizable.strings │ │ │ └── de.lproj │ │ │ └── Localizable.strings │ ├── Extensions │ │ └── MatomoUtils+Extension.swift │ ├── PrivacyManagementCell.swift │ ├── Tracker.swift │ └── TrackerDetailsView.swift ├── InfomaniakCoreCommonUI │ ├── Assets.xcassets │ │ ├── InfomaniakColors │ │ │ ├── Contents.json │ │ │ ├── cobaltColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── coralColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── grassColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── jeanColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── mauveColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── princeColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── yellowColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── fougereColor.colorset │ │ │ │ └── Contents.json │ │ │ └── tropicalColor.colorset │ │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── infomaniakColor.colorset │ │ │ └── Contents.json │ │ ├── backgroundCardView.colorset │ │ │ └── Contents.json │ │ ├── primaryTextColor.colorset │ │ │ └── Contents.json │ │ ├── backgroundCardViewSelected.colorset │ │ │ └── Contents.json │ │ └── titleColor.colorset │ │ │ └── Contents.json │ ├── Extensions │ │ ├── OSLog+Extension.swift │ │ └── UIApplication+Extension.swift │ ├── SnackBar │ │ ├── IKRootViewController.swift │ │ ├── IKWrapperView.swift │ │ ├── IKSnackBarAvoider.swift │ │ ├── IKSnackBarPresentable.swift │ │ └── IKWindow.swift │ ├── UIView+Extension.swift │ ├── Utils │ │ └── OrientationManager.swift │ ├── Assets │ │ └── Assets+InfomaniakCore.swift │ ├── AvatarColors.swift │ └── Security │ │ └── AppLockHelper.swift ├── InfomaniakCoreUIResources │ ├── swiftgen.yml │ └── Localizable │ │ ├── en.lproj │ │ └── Localizable.strings │ │ ├── es.lproj │ │ └── Localizable.strings │ │ ├── it.lproj │ │ └── Localizable.strings │ │ ├── de.lproj │ │ └── Localizable.strings │ │ └── fr.lproj │ │ └── Localizable.strings ├── DesignSystem │ ├── DesignTokens │ │ ├── IKIconSize.swift │ │ ├── IKRadius.swift │ │ └── IKPadding.swift │ └── Extensions │ │ ├── Color+Extension.swift │ │ └── Font+Extension.swift └── InfomaniakCoreUIKit │ ├── UITableView │ └── UITableView+Extension.swift │ ├── Extension │ ├── UIColor+Extension.swift │ ├── Model │ │ ├── OrganisationAccount+Color.swift │ │ └── InfomaniakUser+Avatar.swift │ ├── UIViewController+Extension.swift │ └── UIView+Extension.swift │ ├── UIButton │ └── UIButton+Extension.swift │ ├── UILabel │ └── IKLabel.swift │ ├── UICollectionView │ └── InsetCollectionViewCell.swift │ └── TitleSizeAdjustingNavigationController.swift ├── .mise.toml ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── contents.xcworkspacedata ├── .github ├── workflows │ ├── auto-author-assign.yml │ ├── swiftformat.yml │ ├── swiftlint.yml │ ├── dependent-issues.yml │ ├── ci.yml │ └── semantic-commit.yml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── .sonarcloud.properties ├── file-header-template.txt ├── Tests └── InfomaniakCoreUITests │ └── InfomaniakCoreUITests.swift ├── .gitignore ├── .swiftlint.yml ├── .swiftformat └── Package.swift /README.md: -------------------------------------------------------------------------------- 1 | # ios-core-ui 2 | UI component collection 3 | -------------------------------------------------------------------------------- /.swiftlint-ci.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - todo 3 | strict: true 4 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.mise.toml: -------------------------------------------------------------------------------- 1 | [tools] 2 | swiftformat = '0.54.5' 3 | swiftlint = '0.57.0' 4 | swiftgen = "latest" 5 | pipx = "latest" 6 | "pipx:infomaniak/importloco" = "1.1.0" -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Colors/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Assets.xcassets/InfomaniakColors/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "properties" : { 7 | "provides-namespace" : true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "properties" : { 7 | "generate-swift-asset-symbol-extensions" : "enabled" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Resources/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | InfomaniakCoreUI 4 | 5 | Created by Ambroise Decouttere on 15/10/2024. 6 | 7 | */ 8 | 9 | /* Close button */ 10 | "Close" = "Close"; 11 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Resources/de.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | InfomaniakCoreUI 4 | 5 | Created by Ambroise Decouttere on 15/10/2024. 6 | 7 | */ 8 | 9 | /* Close button */ 10 | "Close" = "Schliessen"; 11 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Resources/es.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | InfomaniakCoreUI 4 | 5 | Created by Ambroise Decouttere on 15/10/2024. 6 | 7 | */ 8 | 9 | /* Close button */ 10 | "Close" = "Cerrar"; 11 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Resources/fr.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | InfomaniakCoreUI 4 | 5 | Created by Ambroise Decouttere on 15/10/2024. 6 | 7 | */ 8 | 9 | /* Close button */ 10 | "Close" = "Fermer"; 11 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Resources/it.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | InfomaniakCoreUI 4 | 5 | Created by Ambroise Decouttere on 15/10/2024. 6 | 7 | */ 8 | 9 | /* Close button */ 10 | "Close" = "Chiudere"; 11 | -------------------------------------------------------------------------------- /.github/workflows/auto-author-assign.yml: -------------------------------------------------------------------------------- 1 | name: Auto Author Assign 2 | 3 | on: 4 | pull_request_target: 5 | types: [ opened, reopened ] 6 | 7 | permissions: 8 | pull-requests: write 9 | 10 | jobs: 11 | assign-author: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: toshimaru/auto-author-assign@v1.6.2 15 | -------------------------------------------------------------------------------- /.sonarcloud.properties: -------------------------------------------------------------------------------- 1 | ## Path to sources 2 | sonar.sources=Sources 3 | # sonar.exclusions= 4 | # sonar.inclusions= 5 | 6 | ## Path to tests 7 | sonar.tests=Tests 8 | # sonar.test.exclusions= 9 | # sonar.test.inclusions= 10 | 11 | ## Source encoding 12 | # sonar.sourceEncoding= 13 | 14 | # Exclusions for copy-paste detection 15 | # sonar.cpd.exclusions= 16 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-audio.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "file-audio.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-code.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "file-code.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-doc.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "file-doc.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-font.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "file-font.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-grid.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "file-grid.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-ics.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "file-ics.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-img.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "file-image.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-pdf.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "file-pdf.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-point.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "file-point.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-vcard.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "file-vcard.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-video.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "file-video.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-archive.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "file-archive.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-unknown.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "file-unknown.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Assets.xcassets/chevron-right.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "chevron-right.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-unknown.imageset/file-unknown.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Assets.xcassets/infomaniakColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "1.000", 9 | "green" : "0.596", 10 | "red" : "0.000" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Assets.xcassets/matomo-short.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "matomo.svg", 5 | "idiom" : "universal" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "dark" 12 | } 13 | ], 14 | "filename" : "matomo-dark.svg", 15 | "idiom" : "universal" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | }, 22 | "properties" : { 23 | "preserves-vector-representation" : true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Assets.xcassets/sentry-short.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "sentry.svg", 5 | "idiom" : "universal" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "dark" 12 | } 13 | ], 14 | "filename" : "sentry-dark.svg", 15 | "idiom" : "universal" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | }, 22 | "properties" : { 23 | "preserves-vector-representation" : true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Assets.xcassets/matomo-long.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "matomo-text.svg", 5 | "idiom" : "universal" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "dark" 12 | } 13 | ], 14 | "filename" : "matomo-text-dark.svg", 15 | "idiom" : "universal" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | }, 22 | "properties" : { 23 | "preserves-vector-representation" : true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Assets.xcassets/sentry-long.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "sentry-text.svg", 5 | "idiom" : "universal" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "dark" 12 | } 13 | ], 14 | "filename" : "sentry-text-dark.svg", 15 | "idiom" : "universal" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | }, 22 | "properties" : { 23 | "preserves-vector-representation" : true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-ics.imageset/file-ics.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/workflows/swiftformat.yml: -------------------------------------------------------------------------------- 1 | name: SwiftFormat 2 | 3 | on: 4 | pull_request: 5 | branches: [ main ] 6 | 7 | jobs: 8 | build: 9 | name: SwiftFormat 10 | runs-on: [ self-hosted, iOS ] 11 | 12 | steps: 13 | - name: Cancel Previous Runs 14 | uses: styfle/cancel-workflow-action@0.12.1 15 | with: 16 | access_token: ${{ github.token }} 17 | - uses: jdx/mise-action@v2 18 | with: 19 | cache: false 20 | - name: Checkout 21 | uses: actions/checkout@v4 22 | with: 23 | fetch-depth: 0 24 | - name: SwiftFormat 25 | run: swiftformat --lint . --reporter github-actions-log 26 | -------------------------------------------------------------------------------- /.github/workflows/swiftlint.yml: -------------------------------------------------------------------------------- 1 | name: SwiftLint 2 | 3 | on: 4 | pull_request: 5 | branches: [ main ] 6 | 7 | jobs: 8 | build: 9 | name: SwiftLint 10 | runs-on: [ self-hosted, iOS ] 11 | 12 | steps: 13 | - name: Cancel Previous Runs 14 | uses: styfle/cancel-workflow-action@0.12.1 15 | with: 16 | access_token: ${{ github.token }} 17 | - uses: jdx/mise-action@v2 18 | with: 19 | cache: false 20 | - name: Checkout 21 | uses: actions/checkout@v4 22 | with: 23 | fetch-depth: 0 24 | - name: SwiftLint 25 | run: swiftlint --config .swiftlint.yml --config .swiftlint-ci.yml --reporter github-actions-logging . 26 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-font.imageset/file-font.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/workflows/dependent-issues.yml: -------------------------------------------------------------------------------- 1 | name: Dependent Issues 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | - edited 8 | - closed 9 | - reopened 10 | pull_request_target: 11 | types: 12 | - opened 13 | - edited 14 | - closed 15 | - reopened 16 | # Makes sure we always add status check for PRs. Useful only if 17 | # this action is required to pass before merging. Otherwise, it 18 | # can be removed. 19 | - synchronize 20 | 21 | jobs: 22 | check: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: z0al/dependent-issues@v1 26 | env: 27 | # (Required) The token to use to make API calls to GitHub. 28 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 29 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-vcard.imageset/file-vcard.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI workflow 2 | 3 | on: 4 | pull_request: 5 | branches: [ main ] 6 | 7 | jobs: 8 | build_and_test_iOS: 9 | name: Build and Test project on iOS 10 | runs-on: [ self-hosted, iOS ] 11 | 12 | steps: 13 | - name: Cancel Previous Runs 14 | uses: styfle/cancel-workflow-action@0.12.1 15 | with: 16 | access_token: ${{ github.token }} 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | - name: Build 20 | run: xcodebuild -scheme InfomaniakCoreUI-Package build -sdk iphonesimulator -destination "generic/platform=iOS" 21 | - name: Test 22 | run: xcodebuild -scheme InfomaniakCoreUI-Package test -sdk iphonesimulator -destination "platform=iOS Simulator,name=iPhone 17,OS=latest" 23 | -------------------------------------------------------------------------------- /file-header-template.txt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Infomaniak Core UI - iOS 4 | Copyright (C) 2023 Infomaniak Network SA 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-video.imageset/file-video.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/workflows/semantic-commit.yml: -------------------------------------------------------------------------------- 1 | name: 'PR and Commit Message Check' 2 | on: 3 | pull_request_target: 4 | types: 5 | - opened 6 | - edited 7 | - reopened 8 | - synchronize 9 | 10 | jobs: 11 | check-commit-message: 12 | name: Check Commit Message 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Check Commit Message 16 | uses: gsactions/commit-message-checker@v2 17 | with: 18 | pattern: '^(Merge .+|((feat|fix|chore|docs|style|refactor|perf|ci|test)(\(.+\))?: [A-Z0-9].+[^.\s])$)' 19 | error: 'Commit messages and PR title should match conventional commit convention and start with an uppercase.' 20 | excludeDescription: 'true' 21 | excludeTitle: 'false' 22 | checkAllCommitMessages: 'true' 23 | accessToken: ${{ secrets.GITHUB_TOKEN }} 24 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-grid.imageset/file-grid.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Assets.xcassets/chevron-right.imageset/chevron-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-doc.imageset/file-doc.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | 12 | 13 | **Is your feature request related to a problem? Please describe.** 14 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 15 | 16 | **Describe the solution you'd like** 17 | A clear and concise description of what you want to happen. 18 | 19 | **Describe alternatives you've considered** 20 | A clear and concise description of any alternative solutions or features you've considered. 21 | 22 | **Additional context** 23 | Add any other context or screenshots about the feature request here. 24 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Assets.xcassets/backgroundCardView.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "1.000", 9 | "green" : "1.000", 10 | "red" : "1.000" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x2F", 27 | "green" : "0x2E", 28 | "red" : "0x2D" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Assets.xcassets/primaryTextColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.400", 9 | "green" : "0.400", 10 | "red" : "0.400" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0.620", 27 | "green" : "0.620", 28 | "red" : "0.620" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Assets.xcassets/InfomaniakColors/cobaltColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xB2", 9 | "green" : "0x6A", 10 | "red" : "0x00" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xF5", 27 | "green" : "0xB2", 28 | "red" : "0x0A" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Assets.xcassets/InfomaniakColors/coralColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x0B", 9 | "green" : "0x54", 10 | "red" : "0xFF" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x59", 27 | "green" : "0x94", 28 | "red" : "0xFD" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Assets.xcassets/InfomaniakColors/grassColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x50", 9 | "green" : "0xAF", 10 | "red" : "0x4B" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x93", 27 | "green" : "0xD0", 28 | "red" : "0x90" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Assets.xcassets/InfomaniakColors/jeanColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xF3", 9 | "green" : "0x96", 10 | "red" : "0x21" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xF8", 27 | "green" : "0xC4", 28 | "red" : "0x81" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Assets.xcassets/InfomaniakColors/mauveColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xC8", 9 | "green" : "0x68", 10 | "red" : "0xBA" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xD6", 27 | "green" : "0x8F", 28 | "red" : "0xCC" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Assets.xcassets/InfomaniakColors/princeColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xB7", 9 | "green" : "0x3A", 10 | "red" : "0x67" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xDD", 27 | "green" : "0x6D", 28 | "red" : "0x95" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Assets.xcassets/InfomaniakColors/yellowColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x0A", 9 | "green" : "0xC1", 10 | "red" : "0xFF" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x9E", 27 | "green" : "0xDF", 28 | "red" : "0xFF" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Colors/file-audio-color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xD4", 9 | "green" : "0xBC", 10 | "red" : "0x00" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "234", 27 | "green" : "222", 28 | "red" : "134" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Colors/file-code-color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xB7", 9 | "green" : "0x3A", 10 | "red" : "0x67" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xDD", 27 | "green" : "0x6D", 28 | "red" : "0x95" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Colors/file-doc-color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xF3", 9 | "green" : "0x96", 10 | "red" : "0x21" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xF8", 27 | "green" : "0xC4", 28 | "red" : "0x81" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Colors/file-font-color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xB0", 9 | "green" : "0x26", 10 | "red" : "0x9C" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xDE", 27 | "green" : "0x68", 28 | "red" : "0xCD" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Colors/file-grid-color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x50", 9 | "green" : "0xAF", 10 | "red" : "0x4B" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x93", 27 | "green" : "0xD0", 28 | "red" : "0x90" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Colors/file-ics-color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xEB", 9 | "green" : "0xD0", 10 | "red" : "0x36" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xF6", 27 | "green" : "0xE9", 28 | "red" : "0xA2" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Colors/file-img-color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xD4", 9 | "green" : "0xBC", 10 | "red" : "0x00" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xEA", 27 | "green" : "0xDE", 28 | "red" : "0x86" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Colors/file-pdf-color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x0B", 9 | "green" : "0x54", 10 | "red" : "0xFF" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x59", 27 | "green" : "0x94", 28 | "red" : "0xFD" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Colors/file-point-color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x02", 9 | "green" : "0x98", 10 | "red" : "0xFF" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x66", 27 | "green" : "0xC1", 28 | "red" : "0xFF" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Colors/file-vcard-color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xE1", 9 | "green" : "0x66", 10 | "red" : "0x9D" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xEE", 27 | "green" : "0xAA", 28 | "red" : "0xC8" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Colors/file-video-color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xD4", 9 | "green" : "0xBC", 10 | "red" : "0x00" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xEA", 27 | "green" : "0xDE", 28 | "red" : "0x86" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Assets.xcassets/InfomaniakColors/fougereColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x88", 9 | "green" : "0x96", 10 | "red" : "0x00" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xB3", 27 | "green" : "0xC7", 28 | "red" : "0x00" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Assets.xcassets/InfomaniakColors/tropicalColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xD4", 9 | "green" : "0xBC", 10 | "red" : "0x00" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xEA", 27 | "green" : "0xDE", 28 | "red" : "0x86" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Assets.xcassets/backgroundCardViewSelected.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.816", 9 | "green" : "0.792", 10 | "red" : "0.792" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0.816", 27 | "green" : "0.796", 28 | "red" : "0.796" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Colors/file-archive-color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x8B", 9 | "green" : "0x7D", 10 | "red" : "0x60" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xC0", 27 | "green" : "0xB7", 28 | "red" : "0xA5" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Colors/file-unknown-color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xB6", 9 | "green" : "0xA2", 10 | "red" : "0x85" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xCF", 27 | "green" : "0xC2", 28 | "red" : "0xAF" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Assets.xcassets/backgroundColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xFF", 9 | "green" : "0xFF", 10 | "red" : "0xFF" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x10", 27 | "green" : "0x10", 28 | "red" : "0x10" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Assets.xcassets/textPrimaryColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x33", 9 | "green" : "0x33", 10 | "red" : "0x33" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xF1", 27 | "green" : "0xF1", 28 | "red" : "0xF1" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Assets.xcassets/textSecondaryColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x66", 9 | "green" : "0x66", 10 | "red" : "0x66" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x9F", 27 | "green" : "0x9F", 28 | "red" : "0x9F" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Assets.xcassets/textTertiaryColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x9F", 9 | "green" : "0x9F", 10 | "red" : "0x9F" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x66", 27 | "green" : "0x66", 28 | "red" : "0x66" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Components/Buttons/Helpers/IKButtonConstants.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2024 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import Foundation 20 | 21 | public enum IKButtonConstants { 22 | public static let maxWidth: CGFloat = 500 23 | } 24 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Assets.xcassets/titleColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.200", 9 | "green" : "0.200", 10 | "red" : "0.200" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "1.000", 27 | "green" : "1.000", 28 | "red" : "1.000" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | }, 38 | "properties" : { 39 | "localizable" : true 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-audio.imageset/file-audio.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Extensions/OSLog+Extension.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import OSLog 20 | 21 | public extension Logger { 22 | private static var subsystem = "InfomaniakCoreUI" 23 | 24 | static let view = Logger(subsystem: subsystem, category: "view") 25 | } 26 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-img.imageset/file-image.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Extensions/MatomoUtils+Extension.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import Foundation 20 | import InfomaniakCoreCommonUI 21 | 22 | public protocol MatomoOptOutable { 23 | func optOut(_ optOut: Bool) 24 | } 25 | 26 | extension MatomoUtils: MatomoOptOutable {} 27 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/SnackBar/IKRootViewController.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #if canImport(UIKit) 20 | 21 | import UIKit 22 | 23 | final class IKRootViewController: UIViewController { 24 | override func loadView() { 25 | view = IKWrapperView() 26 | } 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | 12 | 13 | **Description** 14 | A clear and concise description of what the bug is. 15 | 16 | **Steps to reproduce** 17 | Steps to reproduce the behavior: 18 | 1. Go to '...' 19 | 2. Click on '....' 20 | 3. Scroll down to '....' 21 | 4. See error 22 | 23 | **Expected behavior** 24 | A clear and concise description of what you expected to happen. 25 | 26 | **Screenshots** 27 | If applicable, add screenshots to help explain your problem. 28 | 29 | **Smartphone (please complete the following information):** 30 | - Device: [e.g. iPhone 12] 31 | - iOS version: [e.g. iOS 14.0] 32 | - App version: [e.g. 4.0.1] 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-point.imageset/file-point.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreUIResources/swiftgen.yml: -------------------------------------------------------------------------------- 1 | # Infomaniak Core UI - iOS 2 | # Copyright (C) 2025 Infomaniak Network SA 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | output_dir: Generated/ 18 | 19 | strings: 20 | inputs: Localizable/en.lproj 21 | outputs: 22 | - templateName: structured-swift5 23 | output: Strings+Generated.swift 24 | params: 25 | enumName: CoreUILocalizable 26 | publicAccess: true 27 | -------------------------------------------------------------------------------- /Sources/DesignSystem/DesignTokens/IKIconSize.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import Foundation 20 | 21 | /// An enumeration to list the size of icons used for Infomaniak apps. 22 | @frozen public enum IKIconSize: CGFloat { 23 | /// 12pt icon 24 | case small = 12 25 | /// 16pt icon 26 | case medium = 16 27 | /// 24pt icon 28 | case large = 24 29 | } 30 | -------------------------------------------------------------------------------- /Sources/DesignSystem/DesignTokens/IKRadius.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import Foundation 20 | 21 | /// An enumeration to list the cornier radii used for Infomaniak apps. 22 | @frozen public enum IKRadius { 23 | /// 4pt radius 24 | public static let small: CGFloat = 4 25 | /// 8pt radius 26 | public static let medium: CGFloat = 8 27 | /// 16pt radius 28 | public static let large: CGFloat = 16 29 | } 30 | -------------------------------------------------------------------------------- /Tests/InfomaniakCoreUITests/InfomaniakCoreUITests.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import InfomaniakCore 20 | import InfomaniakCoreCommonUI 21 | import InfomaniakCoreUIKit 22 | import XCTest 23 | 24 | final class InfomaniakCoreUITests: XCTestCase { 25 | func testCanInit_IKLabel() throws { 26 | // GIVEN 27 | let label = IKLabel() 28 | 29 | // THEN 30 | XCTAssertNotNil(label) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/SnackBar/IKWrapperView.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Mail - iOS App 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #if canImport(UIKit) 20 | 21 | import UIKit 22 | 23 | final class IKWrapperView: UIView { 24 | override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { 25 | let view = super.hitTest(point, with: event) 26 | if view != self { 27 | return view 28 | } 29 | return nil 30 | } 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-archive.imageset/file-archive.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/SnackBar/IKSnackBarAvoider.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Mail - iOS App 3 | Copyright (C) 2022 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #if canImport(UIKit) 20 | 21 | import UIKit 22 | 23 | public final class IKSnackBarAvoider { 24 | public var snackBarInset: CGFloat = 0 25 | 26 | public init() { /* Needed to init */ } 27 | 28 | public func addAvoider(inset: CGFloat) { 29 | if inset != snackBarInset { 30 | snackBarInset = inset 31 | } 32 | } 33 | 34 | public func removeAvoider() { 35 | snackBarInset = 0 36 | } 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/UIView+Extension.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import UIKit 20 | 21 | public extension UIView { 22 | func addShadow(elevation: Double = 1) { 23 | layer.shadowColor = UIColor.black.cgColor 24 | layer.shadowOffset = CGSize(width: 0.0, height: 1.23118 * elevation - 0.03933) 25 | layer.shadowOpacity = 0.17 26 | layer.shadowRadius = CGFloat(0.666920 * elevation - 0.001648) 27 | layer.shouldRasterize = true 28 | layer.rasterizationScale = UIScreen.main.scale 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Helpers/ReachabilityObserver.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2024 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import InfomaniakCore 20 | import SwiftUI 21 | 22 | @MainActor 23 | public final class ReachabilityObserver: ObservableObject { 24 | @Published public var networkStatus = ReachabilityListener.instance.currentStatus 25 | 26 | public init() { 27 | ReachabilityListener.instance.observeNetworkChange(self) { [weak self] status in 28 | Task { @MainActor in 29 | self?.networkStatus = status 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Components/SafariWebView.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import SafariServices 20 | import SwiftUI 21 | 22 | public struct SafariWebView: UIViewControllerRepresentable { 23 | let url: URL 24 | 25 | public init(url: URL) { 26 | self.url = url 27 | } 28 | 29 | public func makeUIViewController(context: Context) -> SFSafariViewController { 30 | return SFSafariViewController(url: url) 31 | } 32 | 33 | public func updateUIViewController(_ uiViewController: SFSafariViewController, context: Context) {} 34 | } 35 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Components/Buttons/Models/IKButtonHeight.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import SwiftUI 20 | 21 | @available(iOS 15.0, *) 22 | public enum IKButtonHeight { 23 | public static let extraLarge: CGFloat = 64 24 | public static let large: CGFloat = 56 25 | public static let medium: CGFloat = 40 26 | 27 | static func convert(controlSize: ControlSize) -> CGFloat { 28 | if controlSize == .large { 29 | return IKButtonHeight.large 30 | } else { 31 | return IKButtonHeight.medium 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Extensions/IKIconSize+Image.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import DesignSystem 20 | import SwiftUI 21 | 22 | public extension Image { 23 | /// Resizes and scales the image to the specified ``IKIconSize`` size. 24 | /// - Parameter size: The specified size. 25 | /// - Returns: A square view containing the image scaled to fit in a frame of the specified size. 26 | func iconSize(_ size: IKIconSize) -> some View { 27 | resizable() 28 | .scaledToFit() 29 | .frame(width: size.rawValue, height: size.rawValue) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreUIKit/UITableView/UITableView+Extension.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import UIKit 20 | 21 | public extension UITableView { 22 | func register(cellView: AnyClass) { 23 | let name = String(describing: cellView.self) 24 | register(UINib(nibName: name, bundle: nil), forCellReuseIdentifier: name) 25 | } 26 | 27 | func dequeueReusableCell(type: CellClass.Type, for indexPath: IndexPath) -> CellClass { 28 | return dequeueReusableCell(withIdentifier: String(describing: type.self), for: indexPath) as! CellClass 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/DesignSystem/Extensions/Color+Extension.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import SwiftUI 20 | 21 | #if os(macOS) 22 | public typealias PlatformColor = NSColor 23 | #elseif os(iOS) || os(tvOS) || os(watchOS) || os(visionOS) 24 | public typealias PlatformColor = UIColor 25 | #endif 26 | 27 | public extension PlatformColor { 28 | convenience init(light: PlatformColor, dark: PlatformColor) { 29 | self.init { $0.userInterfaceStyle == .dark ? dark : light } 30 | } 31 | } 32 | 33 | public extension Color { 34 | init(light: PlatformColor, dark: PlatformColor) { 35 | self.init(uiColor: UIColor(light: light, dark: dark)) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Extensions/UIApplication+Extension.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import UIKit 20 | 21 | public extension UIApplication { 22 | var mainSceneKeyWindow: UIWindow? { 23 | // We want to have at least one foreground scene but we prefer active scenes rather than inactive ones 24 | let foregroundScenes = Array(connectedScenes).filter { $0.activationState == .foregroundActive } 25 | + Array(connectedScenes).filter { $0.activationState == .foregroundInactive } 26 | return foregroundScenes 27 | .compactMap { $0 as? UIWindowScene } 28 | .flatMap(\.windows) 29 | .first(where: \.isKeyWindow) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-code.imageset/file-code.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Extensions/IKPadding+View.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import DesignSystem 20 | import SwiftUI 21 | 22 | public extension View { 23 | /// Adds the padding amount specified by ``IKPadding`` to specific edges 24 | /// of this view. 25 | /// 26 | /// - Parameters: 27 | /// - edges: The set of edges to pad for this view. The default 28 | /// is `Edge.Set = .all`. 29 | /// - value: The amount of padding described by the ``IKPadding`` 30 | /// struct. 31 | /// 32 | /// - Returns: A view that's padded by the specified amount on the specified edges. 33 | @inlinable func padding(_ edges: Edge.Set = .all, value: IKPadding.Option) -> some View { 34 | padding(edges, value.rawValue) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Style/IKLabelStyle.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2024 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import DesignSystem 20 | import SwiftUI 21 | 22 | @available(iOS 15.0, *) 23 | public struct IKLabelStyle: LabelStyle { 24 | var spacing = IKPadding.mini 25 | 26 | public func makeBody(configuration: Configuration) -> some View { 27 | HStack(spacing: spacing) { 28 | configuration.icon 29 | configuration.title 30 | } 31 | } 32 | } 33 | 34 | @available(iOS 15.0, *) 35 | public extension LabelStyle where Self == IKLabelStyle { 36 | static var ikLabel: IKLabelStyle { 37 | return IKLabelStyle() 38 | } 39 | 40 | static func ikLabel(_ spacing: CGFloat) -> IKLabelStyle { 41 | return IKLabelStyle(spacing: spacing) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Components/AvatarView/AvatarImage.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import SwiftUI 20 | 21 | public struct AvatarImage: View { 22 | let image: Image 23 | let size: CGFloat 24 | 25 | public init(image: Image, size: CGFloat) { 26 | self.image = image 27 | self.size = size 28 | } 29 | 30 | public var body: some View { 31 | ZStack { 32 | Circle() 33 | .fill(.white) 34 | 35 | image 36 | .resizable() 37 | .scaledToFit() 38 | .clipShape(Circle()) 39 | } 40 | .frame(width: size, height: size) 41 | .drawingGroup() 42 | } 43 | } 44 | 45 | #Preview { 46 | AvatarImage(image: Image(systemName: "person"), size: 40) 47 | } 48 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/MandatoryEnvironmentContainer.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2024 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import Foundation 20 | 21 | public struct MandatoryEnvironmentContainer: Equatable where T: Equatable { 22 | public var value: T { 23 | #if DEBUG 24 | guard let _value else { 25 | fatalError("Container not initialized in the view tree") 26 | } 27 | return _value 28 | #else 29 | return _value! 30 | #endif 31 | } 32 | 33 | private let _value: T? 34 | 35 | public init(value: T) { 36 | _value = value 37 | } 38 | 39 | private init(value: T?) { 40 | _value = value 41 | } 42 | 43 | public static func emptyDefaultValue() -> MandatoryEnvironmentContainer { 44 | MandatoryEnvironmentContainer(value: nil) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreUIKit/Extension/UIColor+Extension.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import UIKit 20 | 21 | public extension UIColor { 22 | convenience init?(hex: String) { 23 | var cString: String = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased() 24 | 25 | if cString.hasPrefix("#") { 26 | cString.remove(at: cString.startIndex) 27 | } 28 | 29 | if (cString.count) != 6 { 30 | return nil 31 | } 32 | 33 | var rgbValue: UInt64 = 0 34 | Scanner(string: cString).scanHexInt64(&rgbValue) 35 | self.init(red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0, 36 | green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0, 37 | blue: CGFloat(rgbValue & 0x0000FF) / 255.0, 38 | alpha: 1) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreUIKit/Extension/Model/OrganisationAccount+Color.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import InfomaniakCore 20 | import UIKit 21 | 22 | public extension OrganisationAccount { 23 | var backgroundColor: UIColor { 24 | let nameAscii: [Int32] = name.replacingOccurrences(of: "/[^a-zA-Z ]+/", 25 | with: "", 26 | options: [.regularExpression]) 27 | .compactMap { $0.asciiValue } 28 | .compactMap { Int32($0) } 29 | 30 | let hashCode: Int32 = nameAscii.reduce(0) { a, b in 31 | ((a &<< Int32(5)) &- a) &+ Int32(b) 32 | } 33 | let colorIndex = (abs(Int(hashCode)) &+ id) % 8 34 | return UIColor(named: "organisationColor\(colorIndex)")! 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreUIKit/Extension/UIViewController+Extension.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import UIKit 20 | 21 | public extension UIViewController { 22 | func hideKeyboardWhenTappedAround() { 23 | let tap = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard)) 24 | tap.cancelsTouchesInView = false 25 | view.addGestureRecognizer(tap) 26 | } 27 | 28 | @objc func dismissKeyboard() { 29 | view.endEditing(true) 30 | } 31 | 32 | func okAlert(title: String, message: String?, completion: (() -> Void)? = nil) { 33 | let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) 34 | alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in completion?() }) 35 | present(alert, animated: true) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Utils/OrientationManager.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Mail - iOS App 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import Foundation 20 | import UIKit 21 | 22 | public protocol OrientationManageable { 23 | var orientationLock: UIInterfaceOrientationMask { get } 24 | 25 | func setOrientationLock(_ orientation: UIInterfaceOrientationMask) 26 | 27 | var interfaceOrientation: UIInterfaceOrientation? { get } 28 | } 29 | 30 | @available(iOSApplicationExtension, unavailable) 31 | public final class OrientationManager: OrientationManageable { 32 | public init() {} 33 | 34 | public var orientationLock = UIInterfaceOrientationMask.all 35 | 36 | public func setOrientationLock(_ orientation: UIInterfaceOrientationMask) { 37 | orientationLock = orientation 38 | } 39 | 40 | public var interfaceOrientation: UIInterfaceOrientation? { 41 | UIApplication.shared.mainSceneKeyWindow?.windowScene?.interfaceOrientation 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/PrivacyManagementCell.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import DesignSystem 20 | import SwiftUI 21 | 22 | @available(iOS 15.0, *) 23 | struct PrivacyManagementCell: View { 24 | let title: LocalizedStringKey 25 | var image: Image 26 | 27 | var body: some View { 28 | HStack(spacing: IKPadding.medium) { 29 | image 30 | 31 | Text(title, bundle: .module) 32 | .foregroundColor(Color("textPrimaryColor", bundle: .module)) 33 | .frame(maxWidth: .infinity, alignment: .leading) 34 | 35 | Image("chevron-right", bundle: .module) 36 | .foregroundColor(Color("textSecondaryColor", bundle: .module)) 37 | } 38 | .padding(IKPadding.medium) 39 | } 40 | } 41 | 42 | @available(iOS 15.0, *) 43 | #Preview { 44 | PrivacyManagementCell(title: "Matomo", image: Image("matomo-short", bundle: .module)) 45 | } 46 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/SnackBar/IKSnackBarPresentable.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Mail - iOS App 3 | Copyright (C) 2022 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #if canImport(UIKit) 20 | 21 | import SnackBar 22 | import UIKit 23 | 24 | public protocol IKSnackBarPresentable { 25 | /// Show a `SnackBar` is current context 26 | func show(message: String) 27 | 28 | /// Show a `SnackBar`, with an action, is current context 29 | func show(message: String, action: IKSnackBar.Action?) 30 | 31 | /// Show a `SnackBar`, with maximum flexibility 32 | /// - Parameters: 33 | /// - message: the message to be displayed 34 | /// - duration: The duration the message should be displayed 35 | /// - action: The optional action that should be displayed 36 | /// - contextView: pass a context view in which the `SnackBar` should be displayed. Useful in complex situation. 37 | func show( 38 | message: String, 39 | duration: SnackBar.Duration, 40 | action: IKSnackBar.Action?, 41 | contextView: UIView? 42 | ) 43 | } 44 | #endif 45 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreUIResources/Localizable/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | * Loco ios export: Xcode Strings (legacy) 3 | * Project: CoreUI 4 | * Locale: en, English 5 | * Tagged: ios, !emoji-reaction, !inapp2fa, !interapplogin, !ios-stringsdict, !kSuite, !kSuiteUtils, !my kSuite, !privacy 6 | * Exported by: Philippe Weidmann 7 | * Exported at: Thu, 25 Sep 2025 12:51:07 +0200 8 | */ 9 | 10 | /* loco:675fea0d40923b5c440f0f52 */ 11 | "anErrorHasOccurred" = "An error has occurred"; 12 | 13 | /* loco:6729ea9f4cb9f889f604d934 */ 14 | "buttonCancel" = "Cancel"; 15 | 16 | /* loco:679237f6daa3807fa008b175 */ 17 | "buttonClose" = "Close"; 18 | 19 | /* loco:67ac7d178defcfcd7806e182 */ 20 | "buttonLater" = "Later"; 21 | 22 | /* loco:675059634bdf0aedde06df72 */ 23 | "buttonNext" = "Next"; 24 | 25 | /* loco:67beed573c592678eb085582 */ 26 | "buttonNo" = "No"; 27 | 28 | /* loco:6729ead76f93fd246802f932 */ 29 | "buttonRetry" = "Retry"; 30 | 31 | /* loco:682dc3dd2d87d3cbda04b3a2 */ 32 | "buttonSave" = "Save"; 33 | 34 | /* loco:685d08b2fc3b99693f00c872 */ 35 | "buttonUploadFromCamera" = "Camera"; 36 | 37 | /* loco:685d0914ecd5fc13620f1fc2 */ 38 | "buttonUploadFromFiles" = "Browse files"; 39 | 40 | /* loco:685d08dc653f4deb94019b62 */ 41 | "buttonUploadFromGallery" = "Photo and video gallery"; 42 | 43 | /* loco:67beed7f8291a886220faf53 */ 44 | "buttonYes" = "Yes"; 45 | 46 | /* loco:676538295907d1ab51014ae2 */ 47 | "errorDownload" = "Download error"; 48 | 49 | /* loco:67653882015fa8304b01cbb9 */ 50 | "errorDownloadInsufficientSpace" = "Cannot download: Insufficient space"; 51 | 52 | /* loco:67dbc1f28c22b8594f030f32 */ 53 | "joinTheBetaButton" = "Join the beta program"; 54 | 55 | /* loco:67beee584d2044470e0df152 */ 56 | "reviewAlertTitle" = "Do you like %@?"; 57 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Modifiers/CompactWindowDetectorModifier.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2024 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import SwiftUI 20 | 21 | public extension EnvironmentValues { 22 | @Entry 23 | var isCompactWindow = true 24 | } 25 | 26 | public extension View { 27 | func detectCompactWindow() -> some View { 28 | modifier(CompactWindowDetectorModifier()) 29 | } 30 | } 31 | 32 | public struct CompactWindowDetectorModifier: ViewModifier { 33 | @Environment(\.horizontalSizeClass) private var horizontalSizeClass 34 | @Environment(\.verticalSizeClass) private var verticalSizeClass 35 | 36 | @State private var isCompactWindow = true 37 | 38 | public func body(content: Content) -> some View { 39 | content 40 | .environment(\.isCompactWindow, isCompactWindow) 41 | .task(id: horizontalSizeClass == .compact || verticalSizeClass == .compact) { 42 | isCompactWindow = horizontalSizeClass == .compact || verticalSizeClass == .compact 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Assets.xcassets/Files/Images/file-pdf.imageset/file-pdf.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Components/AvatarView/InitialsView.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import SwiftUI 20 | 21 | public struct InitialsView: View { 22 | let initials: String 23 | let backgroundColor: Color 24 | let foregroundColor: Color 25 | let size: CGFloat 26 | 27 | public init(initials: String, backgroundColor: Color, foregroundColor: Color, size: CGFloat) { 28 | self.initials = initials 29 | self.backgroundColor = backgroundColor 30 | self.foregroundColor = foregroundColor 31 | self.size = size 32 | } 33 | 34 | public var body: some View { 35 | ZStack { 36 | Circle() 37 | .fill(backgroundColor) 38 | Text(initials) 39 | .font(.system(size: size * 0.5, weight: .semibold)) 40 | .foregroundStyle(foregroundColor) 41 | } 42 | .frame(width: size, height: size) 43 | } 44 | } 45 | 46 | #Preview { 47 | InitialsView(initials: "TE", backgroundColor: .red, foregroundColor: .white, size: 40) 48 | } 49 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreUIResources/Localizable/es.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | * Loco ios export: Xcode Strings (legacy) 3 | * Project: CoreUI 4 | * Locale: es, Spanish 5 | * Tagged: ios, !emoji-reaction, !inapp2fa, !interapplogin, !ios-stringsdict, !kSuite, !kSuiteUtils, !my kSuite, !privacy 6 | * Exported by: Philippe Weidmann 7 | * Exported at: Thu, 25 Sep 2025 12:51:07 +0200 8 | */ 9 | 10 | /* loco:675fea0d40923b5c440f0f52 */ 11 | "anErrorHasOccurred" = "Se ha producido un error"; 12 | 13 | /* loco:6729ea9f4cb9f889f604d934 */ 14 | "buttonCancel" = "Cancelar"; 15 | 16 | /* loco:679237f6daa3807fa008b175 */ 17 | "buttonClose" = "Cerrar"; 18 | 19 | /* loco:67ac7d178defcfcd7806e182 */ 20 | "buttonLater" = "Más tarde"; 21 | 22 | /* loco:675059634bdf0aedde06df72 */ 23 | "buttonNext" = "Siguiente"; 24 | 25 | /* loco:67beed573c592678eb085582 */ 26 | "buttonNo" = "No"; 27 | 28 | /* loco:6729ead76f93fd246802f932 */ 29 | "buttonRetry" = "Reintentar"; 30 | 31 | /* loco:682dc3dd2d87d3cbda04b3a2 */ 32 | "buttonSave" = "Guardar"; 33 | 34 | /* loco:685d08b2fc3b99693f00c872 */ 35 | "buttonUploadFromCamera" = "Cámara"; 36 | 37 | /* loco:685d0914ecd5fc13620f1fc2 */ 38 | "buttonUploadFromFiles" = "Examinar archivos"; 39 | 40 | /* loco:685d08dc653f4deb94019b62 */ 41 | "buttonUploadFromGallery" = "Galería de fotos y vídeos"; 42 | 43 | /* loco:67beed7f8291a886220faf53 */ 44 | "buttonYes" = "Sí"; 45 | 46 | /* loco:676538295907d1ab51014ae2 */ 47 | "errorDownload" = "Error al descargar"; 48 | 49 | /* loco:67653882015fa8304b01cbb9 */ 50 | "errorDownloadInsufficientSpace" = "No se puede descargar: espacio insuficiente"; 51 | 52 | /* loco:67dbc1f28c22b8594f030f32 */ 53 | "joinTheBetaButton" = "Unirse al programa beta"; 54 | 55 | /* loco:67beee584d2044470e0df152 */ 56 | "reviewAlertTitle" = "¿Te gusta %@?"; 57 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreUIKit/Extension/UIView+Extension.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import UIKit 20 | 21 | public extension UIView { 22 | @IBInspectable var cornerRadius: CGFloat { 23 | get { 24 | return layer.cornerRadius 25 | } 26 | set { 27 | layer.cornerRadius = newValue 28 | } 29 | } 30 | 31 | @IBInspectable var borderWidth: CGFloat { 32 | get { 33 | return layer.borderWidth 34 | } 35 | set { 36 | layer.borderWidth = newValue 37 | } 38 | } 39 | 40 | @IBInspectable var borderColor: UIColor? { 41 | get { 42 | return UIColor(cgColor: layer.borderColor!) 43 | } 44 | set { 45 | layer.borderColor = newValue?.cgColor 46 | } 47 | } 48 | 49 | func roundCorners(corners: CACornerMask, radius: CGFloat) { 50 | clipsToBounds = false 51 | layer.cornerRadius = radius 52 | #if !os(tvOS) 53 | layer.maskedCorners = corners 54 | #endif 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreUIResources/Localizable/it.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | * Loco ios export: Xcode Strings (legacy) 3 | * Project: CoreUI 4 | * Locale: it, Italian 5 | * Tagged: ios, !emoji-reaction, !inapp2fa, !interapplogin, !ios-stringsdict, !kSuite, !kSuiteUtils, !my kSuite, !privacy 6 | * Exported by: Philippe Weidmann 7 | * Exported at: Thu, 25 Sep 2025 12:51:07 +0200 8 | */ 9 | 10 | /* loco:675fea0d40923b5c440f0f52 */ 11 | "anErrorHasOccurred" = "Si è verificato un errore"; 12 | 13 | /* loco:6729ea9f4cb9f889f604d934 */ 14 | "buttonCancel" = "Annulla"; 15 | 16 | /* loco:679237f6daa3807fa008b175 */ 17 | "buttonClose" = "Chiudere"; 18 | 19 | /* loco:67ac7d178defcfcd7806e182 */ 20 | "buttonLater" = "Più tardi"; 21 | 22 | /* loco:675059634bdf0aedde06df72 */ 23 | "buttonNext" = "Avanti"; 24 | 25 | /* loco:67beed573c592678eb085582 */ 26 | "buttonNo" = "No"; 27 | 28 | /* loco:6729ead76f93fd246802f932 */ 29 | "buttonRetry" = "Riprova"; 30 | 31 | /* loco:682dc3dd2d87d3cbda04b3a2 */ 32 | "buttonSave" = "Salva"; 33 | 34 | /* loco:685d08b2fc3b99693f00c872 */ 35 | "buttonUploadFromCamera" = "Macchina fotografica"; 36 | 37 | /* loco:685d0914ecd5fc13620f1fc2 */ 38 | "buttonUploadFromFiles" = "Sfoglia i file"; 39 | 40 | /* loco:685d08dc653f4deb94019b62 */ 41 | "buttonUploadFromGallery" = "Galleria di foto e video"; 42 | 43 | /* loco:67beed7f8291a886220faf53 */ 44 | "buttonYes" = "Sì"; 45 | 46 | /* loco:676538295907d1ab51014ae2 */ 47 | "errorDownload" = "Errore durante il download"; 48 | 49 | /* loco:67653882015fa8304b01cbb9 */ 50 | "errorDownloadInsufficientSpace" = "Impossibile scaricare: spazio insufficiente"; 51 | 52 | /* loco:67dbc1f28c22b8594f030f32 */ 53 | "joinTheBetaButton" = "Partecipa al programma beta"; 54 | 55 | /* loco:67beee584d2044470e0df152 */ 56 | "reviewAlertTitle" = "Ti piace %@?"; 57 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreUIResources/Localizable/de.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | * Loco ios export: Xcode Strings (legacy) 3 | * Project: CoreUI 4 | * Locale: de, German 5 | * Tagged: ios, !emoji-reaction, !inapp2fa, !interapplogin, !ios-stringsdict, !kSuite, !kSuiteUtils, !my kSuite, !privacy 6 | * Exported by: Philippe Weidmann 7 | * Exported at: Thu, 25 Sep 2025 12:51:07 +0200 8 | */ 9 | 10 | /* loco:675fea0d40923b5c440f0f52 */ 11 | "anErrorHasOccurred" = "Ein Fehler ist aufgetreten"; 12 | 13 | /* loco:6729ea9f4cb9f889f604d934 */ 14 | "buttonCancel" = "Abbrechen"; 15 | 16 | /* loco:679237f6daa3807fa008b175 */ 17 | "buttonClose" = "Schliessen"; 18 | 19 | /* loco:67ac7d178defcfcd7806e182 */ 20 | "buttonLater" = "Später"; 21 | 22 | /* loco:675059634bdf0aedde06df72 */ 23 | "buttonNext" = "Weiter"; 24 | 25 | /* loco:67beed573c592678eb085582 */ 26 | "buttonNo" = "Nein"; 27 | 28 | /* loco:6729ead76f93fd246802f932 */ 29 | "buttonRetry" = "Wiederholen"; 30 | 31 | /* loco:682dc3dd2d87d3cbda04b3a2 */ 32 | "buttonSave" = "Speichern"; 33 | 34 | /* loco:685d08b2fc3b99693f00c872 */ 35 | "buttonUploadFromCamera" = "Kamera"; 36 | 37 | /* loco:685d0914ecd5fc13620f1fc2 */ 38 | "buttonUploadFromFiles" = "Dateien durchsuchen"; 39 | 40 | /* loco:685d08dc653f4deb94019b62 */ 41 | "buttonUploadFromGallery" = "Foto- und Videogalerie"; 42 | 43 | /* loco:67beed7f8291a886220faf53 */ 44 | "buttonYes" = "Ja"; 45 | 46 | /* loco:676538295907d1ab51014ae2 */ 47 | "errorDownload" = "Fehler beim Download"; 48 | 49 | /* loco:67653882015fa8304b01cbb9 */ 50 | "errorDownloadInsufficientSpace" = "Download nicht möglich: Unzureichender Speicherplatz"; 51 | 52 | /* loco:67dbc1f28c22b8594f030f32 */ 53 | "joinTheBetaButton" = "Dem Beta-Programm beitreten"; 54 | 55 | /* loco:67beee584d2044470e0df152 */ 56 | "reviewAlertTitle" = "Mögen Sie %@?"; 57 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreUIResources/Localizable/fr.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | * Loco ios export: Xcode Strings (legacy) 3 | * Project: CoreUI 4 | * Locale: fr, French 5 | * Tagged: ios, !emoji-reaction, !inapp2fa, !interapplogin, !ios-stringsdict, !kSuite, !kSuiteUtils, !my kSuite, !privacy 6 | * Exported by: Philippe Weidmann 7 | * Exported at: Thu, 25 Sep 2025 12:51:07 +0200 8 | */ 9 | 10 | /* loco:675fea0d40923b5c440f0f52 */ 11 | "anErrorHasOccurred" = "Une erreur est survenue"; 12 | 13 | /* loco:6729ea9f4cb9f889f604d934 */ 14 | "buttonCancel" = "Annuler"; 15 | 16 | /* loco:679237f6daa3807fa008b175 */ 17 | "buttonClose" = "Fermer"; 18 | 19 | /* loco:67ac7d178defcfcd7806e182 */ 20 | "buttonLater" = "Plus tard"; 21 | 22 | /* loco:675059634bdf0aedde06df72 */ 23 | "buttonNext" = "Suivant"; 24 | 25 | /* loco:67beed573c592678eb085582 */ 26 | "buttonNo" = "Non"; 27 | 28 | /* loco:6729ead76f93fd246802f932 */ 29 | "buttonRetry" = "Réessayer"; 30 | 31 | /* loco:682dc3dd2d87d3cbda04b3a2 */ 32 | "buttonSave" = "Enregistrer"; 33 | 34 | /* loco:685d08b2fc3b99693f00c872 */ 35 | "buttonUploadFromCamera" = "Appareil photo"; 36 | 37 | /* loco:685d0914ecd5fc13620f1fc2 */ 38 | "buttonUploadFromFiles" = "Parcourir les fichiers"; 39 | 40 | /* loco:685d08dc653f4deb94019b62 */ 41 | "buttonUploadFromGallery" = "Galerie photos et vidéos"; 42 | 43 | /* loco:67beed7f8291a886220faf53 */ 44 | "buttonYes" = "Oui"; 45 | 46 | /* loco:676538295907d1ab51014ae2 */ 47 | "errorDownload" = "Erreur lors du téléchargement"; 48 | 49 | /* loco:67653882015fa8304b01cbb9 */ 50 | "errorDownloadInsufficientSpace" = "Téléchargement impossible : Espace insuffisant"; 51 | 52 | /* loco:67dbc1f28c22b8594f030f32 */ 53 | "joinTheBetaButton" = "Rejoindre le programme bêta"; 54 | 55 | /* loco:67beee584d2044470e0df152 */ 56 | "reviewAlertTitle" = "Vous aimez %@ ?"; 57 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Alignment/IconAndMultilineTextAlignment.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import SwiftUI 20 | 21 | public extension VerticalAlignment { 22 | /// Alignment ID used for the icon and the text 23 | /// The icon must be vertically centered with the first line of the text 24 | enum IconAndMultilineTextAlignment: AlignmentID { 25 | public static func defaultValue(in context: ViewDimensions) -> CGFloat { 26 | return context[.top] 27 | } 28 | } 29 | 30 | static let iconAndMultilineTextAlignment = VerticalAlignment(IconAndMultilineTextAlignment.self) 31 | } 32 | 33 | public extension View { 34 | func verticalAlignmentGuideForIcon() -> some View { 35 | alignmentGuide(.iconAndMultilineTextAlignment) { d in 36 | d[VerticalAlignment.center] 37 | } 38 | } 39 | 40 | func verticalAlignmentGuideForMultilineText() -> some View { 41 | alignmentGuide(.iconAndMultilineTextAlignment) { d in 42 | (d.height - (d[.lastTextBaseline] - d[.firstTextBaseline])) / 2 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/SnackBar/IKWindow.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Mail - iOS App 3 | Copyright (C) 2022 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #if canImport(UIKit) 20 | 21 | import UIKit 22 | 23 | final class IKWindow: UIWindow { 24 | init(with rootVC: UIViewController) { 25 | if let scene = UIApplication.shared.connectedScenes 26 | .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene { 27 | super.init(windowScene: scene) 28 | } else { 29 | super.init(frame: UIScreen.main.bounds) 30 | } 31 | backgroundColor = .clear 32 | rootViewController = rootVC 33 | accessibilityViewIsModal = true 34 | } 35 | 36 | @available(*, unavailable) 37 | required init?(coder: NSCoder) { 38 | fatalError("init(coder:) has not been implemented") 39 | } 40 | 41 | override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { 42 | if let rootViewController = IKWindowProvider.shared.rootViewController { 43 | return rootViewController.view.hitTest(point, with: event) 44 | } 45 | return nil 46 | } 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreUIKit/UIButton/UIButton+Extension.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import UIKit 20 | 21 | public extension UIButton { 22 | func setLoading(_ loading: Bool, style: UIActivityIndicatorView.Style = .medium) { 23 | isEnabled = !loading 24 | if loading { 25 | setTitle("", for: .disabled) 26 | let loadingSpinner = UIActivityIndicatorView(style: style) 27 | loadingSpinner.startAnimating() 28 | loadingSpinner.translatesAutoresizingMaskIntoConstraints = false 29 | loadingSpinner.hidesWhenStopped = true 30 | addSubview(loadingSpinner) 31 | loadingSpinner.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true 32 | loadingSpinner.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true 33 | } else { 34 | setTitle(title(for: .normal), for: .disabled) 35 | for view in subviews { 36 | if view.isKind(of: UIActivityIndicatorView.self) { 37 | view.removeFromSuperview() 38 | } 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Sources/DesignSystem/DesignTokens/IKPadding.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import Foundation 20 | 21 | /// An enumeration to list the paddings used for Infomaniak apps. 22 | @frozen public enum IKPadding { 23 | @frozen public enum Option: CGFloat { 24 | /// 4pt padding 25 | case micro = 4 26 | /// 8pt padding 27 | case mini = 8 28 | /// 12pt padding 29 | case small = 12 30 | /// 16pt padding 31 | case medium = 16 32 | /// 24pt padding 33 | case large = 24 34 | /// 48pt padding 35 | case huge = 32 36 | /// 48pt padding 37 | case giant = 48 38 | } 39 | 40 | /// 4pt padding 41 | public static let micro: CGFloat = 4 42 | /// 8pt padding 43 | public static let mini: CGFloat = 8 44 | /// 12pt padding 45 | public static let small: CGFloat = 12 46 | /// 16pt padding 47 | public static let medium: CGFloat = 16 48 | /// 24pt padding 49 | public static let large: CGFloat = 24 50 | /// 32pt padding 51 | public static let huge: CGFloat = 32 52 | /// 48pt padding 53 | public static let giant: CGFloat = 48 54 | } 55 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Localizable/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | * Loco ios export: Xcode Strings (legacy) 3 | * Project: CoreUI 4 | * Locale: en, English 5 | * Tagged: ios 6 | * Exported by: Baptiste Griva 7 | * Exported at: Tue, 30 Sep 2025 09:48:07 +0200 8 | */ 9 | 10 | /* loco:679b18c9e56503c64e0f47b2 */ 11 | "applicationSourceCode" = "See source code"; 12 | 13 | /* loco:679b16a81b0e3541200e1672 */ 14 | "authorizeTracking" = "Authorize tracking"; 15 | 16 | /* loco:679b17a8f70dbaf41b0c3c92 */ 17 | "trackingManagementDescription" = "At Infomaniak, your data is never a bargaining chip. We only use in-house tools, hosted and controlled by ourselves, to guarantee the quality and evolution of our applications.\n\nThis technical data is confidential, stored on our own servers in Switzerland, accessible only to our development teams, and never shared with third parties. Application source code can be verified, guaranteeing total transparency."; 18 | 19 | /* loco:679b1726759efd28eb0aae82 */ 20 | "trackingManagementTitle" = "Data management"; 21 | 22 | /* loco:679b1934489a90910a02ef02 */ 23 | "trackingMatomoDescription" = "Matomo is an analysis tool hosted and managed exclusively by Infomaniak to understand how the application is used.\n\nBy studying this data, our team is able to continually improve the application’s interface."; 24 | 25 | /* loco:679b19a71cbd373edb0fcc92 */ 26 | "trackingMatomoTitle" = "Matomo"; 27 | 28 | /* loco:679b19effce81c25230ef922 */ 29 | "trackingSentryDescription" = "Sentry is a tool hosted and managed exclusively by Infomaniak to monitor the stability of the application in real time and automatically report any technical errors to our developers.\n\nThis data enables our team to quickly correct and optimise the application, resulting in a better user experience for you."; 30 | 31 | /* loco:679b1a63d5844c9d0d041fb2 */ 32 | "trackingSentryTitle" = "Sentry"; 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/swiftpackagemanager,macos,xcode 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=swiftpackagemanager,macos,xcode 3 | 4 | ### macOS ### 5 | # General 6 | .DS_Store 7 | .AppleDouble 8 | .LSOverride 9 | 10 | # Icon must end with two \r 11 | Icon 12 | 13 | # Thumbnails 14 | ._* 15 | 16 | # Files that might appear in the root of a volume 17 | .DocumentRevisions-V100 18 | .fseventsd 19 | .Spotlight-V100 20 | .TemporaryItems 21 | .Trashes 22 | .VolumeIcon.icns 23 | .com.apple.timemachine.donotpresent 24 | 25 | # Directories potentially created on remote AFP share 26 | .AppleDB 27 | .AppleDesktop 28 | Network Trash Folder 29 | Temporary Items 30 | .apdisk 31 | 32 | ### SwiftPackageManager ### 33 | Packages 34 | .build/ 35 | xcuserdata 36 | DerivedData/ 37 | *.xcodeproj 38 | 39 | 40 | ### Xcode ### 41 | # Xcode 42 | # 43 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 44 | 45 | ## User settings 46 | xcuserdata/ 47 | 48 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 49 | *.xcscmblueprint 50 | *.xccheckout 51 | 52 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 53 | build/ 54 | *.moved-aside 55 | *.pbxuser 56 | !default.pbxuser 57 | *.mode1v3 58 | !default.mode1v3 59 | *.mode2v3 60 | !default.mode2v3 61 | *.perspectivev3 62 | !default.perspectivev3 63 | 64 | ## Gcc Patch 65 | /*.gcno 66 | 67 | ### Xcode Patch ### 68 | *.xcodeproj/* 69 | !*.xcodeproj/project.pbxproj 70 | !*.xcodeproj/xcshareddata/ 71 | !*.xcworkspace/contents.xcworkspacedata 72 | **/xcshareddata/WorkspaceSettings.xcsettings 73 | 74 | # End of https://www.toptal.com/developers/gitignore/api/swiftpackagemanager,macos,xcode% 75 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreUIKit/UILabel/IKLabel.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #if os(macOS) 20 | import AppKit 21 | #elseif os(iOS) 22 | import UIKit 23 | #elseif os(tvOS) || os(watchOS) 24 | import UIKit 25 | #endif 26 | 27 | import InfomaniakCoreCommonUI 28 | 29 | @IBDesignable public class IKLabel: UILabel { 30 | /// Set label style. 31 | @IBInspectable public var styleName: String = TextStyle.body1.rawValue { 32 | didSet { setUpLabel() } 33 | } 34 | 35 | /// Set label style. 36 | public var style: TextStyle { 37 | get { 38 | return TextStyle(rawValue: styleName) ?? .body1 39 | } 40 | set { 41 | styleName = newValue.rawValue 42 | } 43 | } 44 | 45 | override public init(frame: CGRect) { 46 | super.init(frame: frame) 47 | setUpLabel() 48 | } 49 | 50 | required init?(coder: NSCoder) { 51 | super.init(coder: coder) 52 | setUpLabel() 53 | } 54 | 55 | override public func prepareForInterfaceBuilder() { 56 | super.prepareForInterfaceBuilder() 57 | setUpLabel() 58 | } 59 | 60 | func setUpLabel() { 61 | font = style.font 62 | textColor = style.color 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - line_length 3 | - identifier_name 4 | - type_body_length 5 | - function_body_length 6 | - file_length 7 | - type_name 8 | - force_cast 9 | - cyclomatic_complexity 10 | - inclusive_language 11 | - for_where 12 | - optional_data_string_conversion 13 | opt_in_rules: 14 | - closure_end_indentation 15 | - closure_spacing 16 | - collection_alignment 17 | - contains_over_filter_count 18 | - contains_over_first_not_nil 19 | - contains_over_range_nil_comparison 20 | - empty_collection_literal 21 | - empty_count 22 | - empty_string 23 | - first_where 24 | - identical_operands 25 | - last_where 26 | - operator_usage_whitespace 27 | - overridden_super_call 28 | - prefer_zero_over_explicit_init 29 | - prohibited_super_call 30 | - redundant_type_annotation 31 | - toggle_bool 32 | - trailing_closure 33 | - unneeded_parentheses_in_closure_argument 34 | analyzer_rules: 35 | - unused_import 36 | excluded: 37 | - Derived/Sources/* 38 | - DerivedData/ 39 | - Derived/ 40 | - Tuist/.build/ 41 | - Tests/* 42 | - Sources/InfomaniakCoreUIResources/Generated/* 43 | custom_rules: 44 | private_state: 45 | included: 46 | - ".*\\.swift" 47 | regex: "(?. 17 | */ 18 | 19 | import SwiftUI 20 | 21 | public extension Font { 22 | /// Create a custom font with the UIFont preferred font family. 23 | /// - Parameters: 24 | /// - size: Default size of the font for the "large" `Dynamic Type Size`. 25 | /// - weight: Weight of the font. 26 | /// - textStyle: The text style on which the font will be based to scale. 27 | /// 28 | /// - Returns: A font with the specified attributes. 29 | /// 30 | /// SwiftUI will use the default system font with the specified weight and size use `Dynamic Type Size`. 31 | static func dynamicTypeSizeFont(size: CGFloat, weight: Weight, relativeTo textStyle: TextStyle) -> Font { 32 | #if canImport(UIKit) 33 | let fontFamily = UIFont.preferredFont(forTextStyle: .body).familyName 34 | return custom(fontFamily, size: size, relativeTo: textStyle).weight(weight) 35 | #elseif canImport(AppKit) 36 | let fontFamily = NSFont.preferredFont(forTextStyle: .body).familyName 37 | return custom(fontFamily, size: size, relativeTo: textStyle).weight(weight) 38 | #else 39 | fatalError("Unsupported UI platform") 40 | #endif 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Components/FloatingPanelCloseButton.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2024 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import DesignSystem 20 | import SwiftUI 21 | 22 | @available(iOS 15.0, *) 23 | public struct FloatingPanelCloseButton: View { 24 | let size: IKIconSize? 25 | let dismissHandler: () -> Void 26 | 27 | public init(size: IKIconSize? = nil, dismissHandler: @escaping () -> Void) { 28 | self.size = size 29 | self.dismissHandler = dismissHandler 30 | } 31 | 32 | public init(size: IKIconSize? = nil, dismissAction: DismissAction) { 33 | self.size = size 34 | dismissHandler = dismissAction.callAsFunction 35 | } 36 | 37 | public var body: some View { 38 | Button(action: dismissHandler) { 39 | Label { 40 | Text("Close", bundle: .module) 41 | } icon: { 42 | Image(systemName: "xmark") 43 | .resizable() 44 | .scaledToFit() 45 | .frame(width: size?.rawValue, height: size?.rawValue) 46 | } 47 | } 48 | .labelStyle(.iconOnly) 49 | .keyboardShortcut(.cancelAction) 50 | } 51 | } 52 | 53 | @available(iOS 15.0, *) 54 | #Preview { 55 | FloatingPanelCloseButton { /* Preview */ } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Tracker.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import SwiftUI 20 | 21 | public enum Tracker: String, CaseIterable, Identifiable { 22 | case matomo 23 | case sentry 24 | 25 | public var id: String { rawValue } 26 | 27 | public var title: LocalizedStringKey { 28 | switch self { 29 | case .matomo: 30 | return "trackingMatomoTitle" 31 | case .sentry: 32 | return "trackingSentryTitle" 33 | } 34 | } 35 | 36 | public var description: String { 37 | switch self { 38 | case .matomo: 39 | return "trackingMatomoDescription" 40 | case .sentry: 41 | return "trackingSentryDescription" 42 | } 43 | } 44 | 45 | public var logoShort: Image { 46 | switch self { 47 | case .matomo: 48 | return Image("matomo-short", bundle: .module) 49 | case .sentry: 50 | return Image("sentry-short", bundle: .module) 51 | } 52 | } 53 | 54 | public var logoLong: Image { 55 | switch self { 56 | case .matomo: 57 | return Image("matomo-long", bundle: .module) 58 | case .sentry: 59 | return Image("sentry-long", bundle: .module) 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Localizable/it.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | * Loco ios export: Xcode Strings (legacy) 3 | * Project: CoreUI 4 | * Locale: it, Italian 5 | * Tagged: ios 6 | * Exported by: Baptiste Griva 7 | * Exported at: Tue, 30 Sep 2025 09:48:07 +0200 8 | */ 9 | 10 | /* loco:679b18c9e56503c64e0f47b2 */ 11 | "applicationSourceCode" = "Vedi il codice sorgente"; 12 | 13 | /* loco:679b16a81b0e3541200e1672 */ 14 | "authorizeTracking" = "Autorizzare il tracciamento"; 15 | 16 | /* loco:679b17a8f70dbaf41b0c3c92 */ 17 | "trackingManagementDescription" = "In Infomaniak, i vostri dati non sono mai merce di scambio. Utilizziamo solo strumenti interni, ospitati e controllati da noi stessi, per garantire la qualità e lo sviluppo delle nostre applicazioni.\n\nQuesti dati tecnici sono riservati, archiviati sui nostri server in Svizzera, accessibili solo ai nostri team di sviluppo e non vengono mai condivisi con terzi. Il codice sorgente delle nostre applicazioni può essere verificato, garantendo una trasparenza totale."; 18 | 19 | /* loco:679b1726759efd28eb0aae82 */ 20 | "trackingManagementTitle" = "Gestione dei dati"; 21 | 22 | /* loco:679b1934489a90910a02ef02 */ 23 | "trackingMatomoDescription" = "Matomo è uno strumento di analisi ospitato e gestito esclusivamente da Infomaniak per capire come viene utilizzata l’applicazione.\n\nStudiando questi dati, il nostro team è in grado di migliorare continuamente l’interfaccia dell’applicazione."; 24 | 25 | /* loco:679b19a71cbd373edb0fcc92 */ 26 | "trackingMatomoTitle" = "Matomo"; 27 | 28 | /* loco:679b19effce81c25230ef922 */ 29 | "trackingSentryDescription" = "Sentry è uno strumento ospitato e gestito esclusivamente da Infomaniak per monitorare la stabilità dell’applicazione in tempo reale e segnalare automaticamente eventuali errori tecnici ai nostri sviluppatori.\n\nQuesti dati consentono al nostro team di correggere e ottimizzare rapidamente l’applicazione, migliorando l’esperienza dell’utente."; 30 | 31 | /* loco:679b1a63d5844c9d0d041fb2 */ 32 | "trackingSentryTitle" = "Sentry"; 33 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Components/ThemedLottieView.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import Lottie 20 | import SwiftUI 21 | 22 | public struct ThemedLottieView: View { 23 | @Environment(\.colorScheme) private var colorScheme 24 | 25 | let lightAnimationName: String 26 | let darkAnimationName: String? 27 | 28 | let bundle: Bundle 29 | 30 | let loopMode: Lottie.LottieLoopMode 31 | 32 | private var animationName: String { 33 | if colorScheme == .dark, 34 | let darkAnimationName { 35 | return darkAnimationName 36 | } else { 37 | return lightAnimationName 38 | } 39 | } 40 | 41 | public init( 42 | lightAnimationName: String, 43 | darkAnimationName: String? = nil, 44 | bundle: Bundle, 45 | loopMode: Lottie.LottieLoopMode = .autoReverse 46 | ) { 47 | self.lightAnimationName = lightAnimationName 48 | self.darkAnimationName = darkAnimationName 49 | self.bundle = bundle 50 | self.loopMode = loopMode 51 | } 52 | 53 | public var body: some View { 54 | LottieView { 55 | try await LottieAnimationSource.dotLottieFile(.named(animationName, bundle: bundle)) 56 | } 57 | .playing(loopMode: loopMode) 58 | .id(colorScheme) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Helpers/FileType/FileTypeProvider.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2024 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import SwiftUI 20 | import UniformTypeIdentifiers 21 | 22 | @available(iOS 14.0, *) 23 | public struct FileTypeProvider: Sendable { 24 | private static let checkableFileTypes: [FileType] = [ 25 | .archive, .audio, .video, .image, .pdf, .ics, .font, .grid, .point, .doc, .code 26 | ] 27 | 28 | public let uti: UTType? 29 | public let fileType: FileType 30 | 31 | public var image: Image { 32 | fileType.image 33 | } 34 | 35 | public var color: Color { 36 | fileType.color 37 | } 38 | 39 | public init(identifier: String) { 40 | self.init(uti: UTType(identifier)) 41 | } 42 | 43 | public init(mimeType: String) { 44 | self.init(uti: UTType(mimeType: mimeType)) 45 | } 46 | 47 | public init(uti: UTType?) { 48 | self.uti = uti 49 | fileType = FileTypeProvider.guessFileType(from: uti) 50 | } 51 | 52 | private static func guessFileType(from type: UTType?) -> FileType { 53 | guard let type else { return .unknown } 54 | 55 | for fileType in checkableFileTypes { 56 | if fileType.conforms(to: type) { 57 | return fileType 58 | } 59 | } 60 | 61 | return .unknown 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Localizable/fr.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | * Loco ios export: Xcode Strings (legacy) 3 | * Project: CoreUI 4 | * Locale: fr, French 5 | * Tagged: ios 6 | * Exported by: Baptiste Griva 7 | * Exported at: Tue, 30 Sep 2025 09:48:07 +0200 8 | */ 9 | 10 | /* loco:679b18c9e56503c64e0f47b2 */ 11 | "applicationSourceCode" = "Voir le code source"; 12 | 13 | /* loco:679b16a81b0e3541200e1672 */ 14 | "authorizeTracking" = "Autoriser le suivi"; 15 | 16 | /* loco:679b17a8f70dbaf41b0c3c92 */ 17 | "trackingManagementDescription" = "Chez Infomaniak, vos données ne sont jamais une monnaie d’échange. Nous utilisons uniquement des outils internes, hébergés et maîtrisés par nos soins, pour garantir la qualité et l’évolution de nos applications.\n\nCes données techniques sont confidentielles, stockées sur nos propres serveurs en Suisse, accessibles uniquement à nos équipes de développement, et ne sont jamais partagées avec des tiers. Le code source des applications peut être vérifié, garantissant une transparence totale."; 18 | 19 | /* loco:679b1726759efd28eb0aae82 */ 20 | "trackingManagementTitle" = "Gestion des données"; 21 | 22 | /* loco:679b1934489a90910a02ef02 */ 23 | "trackingMatomoDescription" = "Matomo est un outil d’analyse hébergé et géré exclusivement par Infomaniak pour comprendre comment l’application est utilisée.\n\nL’étude de ces données permet à notre équipe d’améliorer en continue l’interface de l’application."; 24 | 25 | /* loco:679b19a71cbd373edb0fcc92 */ 26 | "trackingMatomoTitle" = "Matomo"; 27 | 28 | /* loco:679b19effce81c25230ef922 */ 29 | "trackingSentryDescription" = "Sentry est un outil hébergé et géré exclusivement par Infomaniak pour surveiller en temps réel la stabilité de l’application et signaler automatiquement d’éventuelles erreurs techniques à nos développeurs.\n\nCes données permettent à notre équipe de rapidement corriger et optimiser l’application, ce qui se traduit par une meilleure expérience d’utilisation pour vous."; 30 | 31 | /* loco:679b1a63d5844c9d0d041fb2 */ 32 | "trackingSentryTitle" = "Sentry"; 33 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Localizable/es.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | * Loco ios export: Xcode Strings (legacy) 3 | * Project: CoreUI 4 | * Locale: es, Spanish 5 | * Tagged: ios 6 | * Exported by: Baptiste Griva 7 | * Exported at: Tue, 30 Sep 2025 09:48:07 +0200 8 | */ 9 | 10 | /* loco:679b18c9e56503c64e0f47b2 */ 11 | "applicationSourceCode" = "Ver código fuente"; 12 | 13 | /* loco:679b16a81b0e3541200e1672 */ 14 | "authorizeTracking" = "Autorizar el seguimiento"; 15 | 16 | /* loco:679b17a8f70dbaf41b0c3c92 */ 17 | "trackingManagementDescription" = "En Infomaniak, sus datos nunca son moneda de cambio. Solo utilizamos herramientas internas, alojadas y controladas por nosotros mismos, para garantizar la calidad y el desarrollo de nuestras aplicaciones.\n\nEstos datos técnicos son confidenciales, se almacenan en nuestros propios servidores en Suiza, sólo son accesibles a nuestros equipos de desarrollo y nunca se comparten con terceros. El código fuente de nuestras aplicaciones puede verificarse, lo que garantiza una total transparencia."; 18 | 19 | /* loco:679b1726759efd28eb0aae82 */ 20 | "trackingManagementTitle" = "Gestión de datos"; 21 | 22 | /* loco:679b1934489a90910a02ef02 */ 23 | "trackingMatomoDescription" = "Matomo es una herramienta de análisis alojada y gestionada exclusivamente por Infomaniak para comprender cómo se utiliza la aplicación.\n\nEl estudio de estos datos permite a nuestro equipo mejorar continuamente la interfaz de la aplicación."; 24 | 25 | /* loco:679b19a71cbd373edb0fcc92 */ 26 | "trackingMatomoTitle" = "Matomo"; 27 | 28 | /* loco:679b19effce81c25230ef922 */ 29 | "trackingSentryDescription" = "Sentry es una herramienta alojada y gestionada en exclusiva por Infomaniak para supervisar la estabilidad de la aplicación en tiempo real e informar automáticamente de cualquier error técnico a nuestros desarrolladores.\n\nEstos datos permiten a nuestro equipo corregir y optimizar rápidamente la aplicación, lo que se traduce en una mejor experiencia de usuario para usted."; 30 | 31 | /* loco:679b1a63d5844c9d0d041fb2 */ 32 | "trackingSentryTitle" = "Sentry"; 33 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Localizable/de.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | * Loco ios export: Xcode Strings (legacy) 3 | * Project: CoreUI 4 | * Locale: de, German 5 | * Tagged: ios 6 | * Exported by: Baptiste Griva 7 | * Exported at: Tue, 30 Sep 2025 09:48:07 +0200 8 | */ 9 | 10 | /* loco:679b18c9e56503c64e0f47b2 */ 11 | "applicationSourceCode" = "Siehe Quellcode"; 12 | 13 | /* loco:679b16a81b0e3541200e1672 */ 14 | "authorizeTracking" = "Verfolgung genehmigen"; 15 | 16 | /* loco:679b17a8f70dbaf41b0c3c92 */ 17 | "trackingManagementDescription" = "Bei Infomaniak sind Ihre Daten niemals eine Währung. Wir verwenden ausschließlich interne Tools, die von uns gehostet und kontrolliert werden, um die Qualität und die Weiterentwicklung unserer Anwendungen zu gewährleisten.\n\nDiese technischen Daten sind vertraulich, werden auf unseren eigenen Servern in der Schweiz gespeichert, sind nur für unsere Entwicklungsteams zugänglich und werden niemals an Dritte weitergegeben. Der Quellcode der Anwendungen kann überprüft werden, wodurch eine vollständige Transparenz gewährleistet wird."; 18 | 19 | /* loco:679b1726759efd28eb0aae82 */ 20 | "trackingManagementTitle" = "Verwaltung der Daten"; 21 | 22 | /* loco:679b1934489a90910a02ef02 */ 23 | "trackingMatomoDescription" = "Matomo ist ein Analysetool, das ausschliesslich von Infomaniak gehostet und verwaltet wird, um zu verstehen, wie die Anwendung genutzt wird.\n\nDurch die Untersuchung dieser Daten kann unser Team die Schnittstelle der Anwendung kontinuierlich verbessern."; 24 | 25 | /* loco:679b19a71cbd373edb0fcc92 */ 26 | "trackingMatomoTitle" = "Matomo"; 27 | 28 | /* loco:679b19effce81c25230ef922 */ 29 | "trackingSentryDescription" = "Sentry ist ein Tool, das ausschliesslich von Infomaniak gehostet und verwaltet wird, um die Stabilität der Anwendung in Echtzeit zu überwachen und unseren Entwicklern automatisch alle technischen Fehler zu melden.\n\nAnhand dieser Daten kann unser Team die Anwendung schnell korrigieren und optimieren, was zu einem besseren Nutzererlebnis für Sie führt."; 30 | 31 | /* loco:679b1a63d5844c9d0d041fb2 */ 32 | "trackingSentryTitle" = "Sentry"; 33 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Assets.xcassets/sentry-short.imageset/sentry.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Assets/Assets+InfomaniakCore.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | // swiftlint:disable all 20 | // swift-format-ignore-file 21 | // swiftformat:disable all 22 | 23 | #if os(macOS) 24 | import AppKit 25 | #elseif os(iOS) 26 | import UIKit 27 | #elseif os(tvOS) || os(watchOS) 28 | import UIKit 29 | #endif 30 | // swiftlint:disable superfluous_disable_command file_length implicit_return 31 | 32 | // MARK: - Asset Catalogs 33 | 34 | // swiftlint:disable identifier_name line_length nesting type_body_length type_name 35 | public enum InfomaniakCoreAsset { 36 | public static let backgroundCardView = InfomaniakCoreColor(name: "backgroundCardView") 37 | public static let backgroundCardViewSelected = InfomaniakCoreColor(name: "backgroundCardViewSelected") 38 | public static let titleColor = InfomaniakCoreColor(name: "titleColor") 39 | public static let primaryTextColor = InfomaniakCoreColor(name: "primaryTextColor") 40 | public static let infomaniakColor = InfomaniakCoreColor(name: "infomaniakColor") 41 | } 42 | 43 | // swiftlint:enable identifier_name line_length nesting type_body_length type_name 44 | // swiftlint:enable all 45 | // swiftformat:enable all 46 | 47 | // MARK: - Implementation Details 48 | 49 | public struct InfomaniakCoreColor { 50 | public fileprivate(set) var name: String 51 | 52 | public var color: UIColor { 53 | return UIColor(named: name, in: Bundle.module, compatibleWith: nil)! 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Components/Buttons/IKSquareButtonStyle.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import SwiftUI 20 | 21 | @available(iOS 15.0, *) 22 | public struct IKSquareButtonStyle: ButtonStyle { 23 | @Environment(\.ikButtonLoading) private var isLoading: Bool 24 | 25 | public func makeBody(configuration: Configuration) -> some View { 26 | configuration.label 27 | .labelStyle(.ikLabel) 28 | .modifier(IKButtonOpacityAnimationModifier(isPressed: configuration.isPressed)) 29 | .modifier(IKButtonLoadingModifier(isFilled: true)) 30 | .frame(width: IKButtonHeight.extraLarge, height: IKButtonHeight.extraLarge) 31 | .modifier(IKButtonFilledModifier(buttonRole: configuration.role, isProminent: true)) 32 | .allowsHitTesting(!isLoading) 33 | } 34 | } 35 | 36 | @available(iOS 15.0, *) 37 | public extension ButtonStyle where Self == IKSquareButtonStyle { 38 | static var ikSquare: IKSquareButtonStyle { 39 | return IKSquareButtonStyle() 40 | } 41 | } 42 | 43 | @available(iOS 15.0, *) 44 | #Preview { 45 | NavigationView { 46 | List { 47 | Section("Standard Button") { 48 | Button {} label: { 49 | Image(systemName: "visionpro") 50 | .iconSize(.medium) 51 | } 52 | } 53 | } 54 | .buttonStyle(.ikSquare) 55 | .navigationTitle("IKSquareButtonStyle") 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Assets.xcassets/sentry-short.imageset/sentry-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/AvatarColors.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #if canImport(UIKit) 20 | import UIKit 21 | 22 | public extension UIColor { 23 | static let avatarColors = [ 24 | UIColor.InfomaniakColors.yellow, 25 | UIColor.InfomaniakColors.coral, 26 | UIColor.InfomaniakColors.grass, 27 | UIColor.InfomaniakColors.fougere, 28 | UIColor.InfomaniakColors.cobalt, 29 | UIColor.InfomaniakColors.jean, 30 | UIColor.InfomaniakColors.tropical, 31 | UIColor.InfomaniakColors.mauve, 32 | UIColor.InfomaniakColors.prince 33 | ] 34 | 35 | class func backgroundColor(from hash: Int, with colors: [UIColor] = UIColor.avatarColors) -> UIColor { 36 | let colorIndex = abs(hash % colors.count) 37 | return colors[colorIndex] 38 | } 39 | } 40 | #endif 41 | 42 | import SwiftUI 43 | 44 | public extension Color { 45 | static let avatarColors = [ 46 | Color.InfomaniakColors.yellow, 47 | Color.InfomaniakColors.coral, 48 | Color.InfomaniakColors.grass, 49 | Color.InfomaniakColors.fougere, 50 | Color.InfomaniakColors.cobalt, 51 | Color.InfomaniakColors.jean, 52 | Color.InfomaniakColors.tropical, 53 | Color.InfomaniakColors.mauve, 54 | Color.InfomaniakColors.prince 55 | ] 56 | 57 | static func backgroundColor(from hash: Int, with colors: [Color] = Color.avatarColors) -> Color { 58 | let colorIndex = abs(hash % colors.count) 59 | return colors[colorIndex] 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Components/CameraPickerView.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import PhotosUI 20 | import SwiftUI 21 | 22 | public struct CameraPickerView: UIViewControllerRepresentable { 23 | @Environment(\.dismiss) private var dismiss 24 | @Binding private var selectedImage: UIImage? 25 | 26 | public init(selectedImage: Binding) { 27 | _selectedImage = selectedImage 28 | } 29 | 30 | public func makeUIViewController(context: Context) -> UIImagePickerController { 31 | let imagePicker = UIImagePickerController() 32 | imagePicker.sourceType = .camera 33 | imagePicker.delegate = context.coordinator 34 | return imagePicker 35 | } 36 | 37 | public func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {} 38 | 39 | public func makeCoordinator() -> Coordinator { 40 | return Coordinator(parent: self) 41 | } 42 | 43 | public class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate { 44 | private var parent: CameraPickerView 45 | 46 | public init(parent: CameraPickerView) { 47 | self.parent = parent 48 | } 49 | 50 | public func imagePickerController( 51 | _ picker: UIImagePickerController, 52 | didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any] 53 | ) { 54 | if let image = info[.originalImage] as? UIImage { 55 | parent.selectedImage = image 56 | } 57 | parent.dismiss() 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /.swiftformat: -------------------------------------------------------------------------------- 1 | --acronyms ID,URL,UUID 2 | --allman false 3 | --assetliterals visual-width 4 | --asynccapturing 5 | --beforemarks 6 | --binarygrouping 4,8 7 | --categorymark "MARK: %c" 8 | --classthreshold 0 9 | --closingparen balanced 10 | --closurevoid remove 11 | --commas always 12 | --conflictmarkers reject 13 | --decimalgrouping 3,6 14 | --elseposition same-line 15 | --emptybraces no-space 16 | --enumnamespaces always 17 | --enumthreshold 0 18 | --exponentcase lowercase 19 | --exponentgrouping disabled 20 | --extensionacl on-extension 21 | --extensionlength 0 22 | --extensionmark "MARK: - %t + %c" 23 | --fractiongrouping disabled 24 | --fragment false 25 | --funcattributes preserve 26 | --generictypes 27 | --groupedextension "MARK: %c" 28 | --guardelse auto 29 | --header ignore 30 | --hexgrouping 4,8 31 | --hexliteralcase uppercase 32 | --ifdef no-indent 33 | --importgrouping alpha 34 | --indent 4 35 | --indentcase false 36 | --indentstrings false 37 | --lifecycle 38 | --lineaftermarks true 39 | --linebreaks lf 40 | --markcategories true 41 | --markextensions always 42 | --marktypes always 43 | --maxwidth 130 44 | --modifierorder 45 | --nevertrailing 46 | --nospaceoperators 47 | --nowrapoperators 48 | --octalgrouping 4,8 49 | --operatorfunc spaced 50 | --organizetypes actor,class,enum,struct 51 | --patternlet inline 52 | --ranges spaced 53 | --redundanttype inferred 54 | --self remove 55 | --selfrequired 56 | --semicolons inline 57 | --shortoptionals always 58 | --smarttabs enabled 59 | --someany true 60 | --stripunusedargs unnamed-only 61 | --structthreshold 0 62 | --tabwidth unspecified 63 | --throwcapturing 64 | --trailingclosures 65 | --trimwhitespace always 66 | --typeattributes preserve 67 | --typeblanklines remove 68 | --typemark "MARK: - %t" 69 | --varattributes preserve 70 | --voidtype void 71 | --wraparguments preserve 72 | --wrapcollections preserve 73 | --wrapconditions preserve 74 | --wrapeffects preserve 75 | --wrapenumcases always 76 | --wrapparameters default 77 | --wrapreturntype preserve 78 | --wrapternary default 79 | --wraptypealiases preserve 80 | --xcodeindentation disabled 81 | --yodaswap always 82 | --disable andOperator,opaqueGenericParameters,preferKeyPath,redundantReturn,strongOutlets,trailingCommas,unusedArguments,wrapMultilineStatementBraces,conditionalAssignment 83 | --enable blankLineAfterImports,blankLinesBetweenImports 84 | --exclude DerivedData,Derived,Tuist,Project.swift,Build,.build,Sources/InfomaniakCoreUIResources/Generated/ 85 | 86 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreUIKit/Extension/Model/InfomaniakUser+Avatar.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import InfomaniakCore 20 | import Nuke 21 | import UIKit 22 | 23 | public extension InfomaniakUser { 24 | /// Can fetch an avatar from any abstract `InfomaniakUser` 25 | func getAvatar(size: CGSize = CGSize(width: 40, height: 40), completion: @MainActor @escaping (UIImage) -> Void) { 26 | let id = self.id 27 | let displayName = self.displayName 28 | let avatar = self.avatar 29 | 30 | Task { 31 | let avatarImage = await getAvatar(id: id, displayName: displayName, avatar: avatar, size: size) 32 | await completion(avatarImage) 33 | } 34 | } 35 | 36 | private func defaultAvatar(id: Int, displayName: String, size: CGSize) -> UIImage { 37 | let backgroundColor = UIColor.backgroundColor(from: id) 38 | return UIImage.getInitialsPlaceholder(with: displayName, size: size, backgroundColor: backgroundColor) 39 | } 40 | 41 | private func getAvatar(id: Int, displayName: String, avatar: String?, size: CGSize) async -> UIImage { 42 | guard let avatarString = avatar, 43 | let url = URL(string: avatarString) else { 44 | return defaultAvatar(id: id, displayName: displayName, size: size) 45 | } 46 | 47 | guard let avatarImage = try? await ImagePipeline.shared.image(for: url) else { 48 | return defaultAvatar(id: id, displayName: displayName, size: size) 49 | } 50 | 51 | return avatarImage 52 | } 53 | 54 | func getAvatar(size: CGSize = CGSize(width: 40, height: 40)) async -> UIImage { 55 | return await getAvatar(id: id, displayName: displayName, avatar: avatar, size: size) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreCommonUI/Security/AppLockHelper.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import LocalAuthentication 20 | import UIKit 21 | 22 | public final class AppLockHelper { 23 | public static let lockAfterOneMinute: TimeInterval = 60 24 | 25 | private var deviceHasBeenLocked = false 26 | private let intervalToLockApp: TimeInterval 27 | private var timeSinceAppEnteredBackground = TimeInterval.zero 28 | 29 | public var isAppLocked: Bool { 30 | let timeHasExpired = timeSinceAppEnteredBackground + intervalToLockApp < Date().timeIntervalSince1970 31 | return isAvailable() && (timeHasExpired || deviceHasBeenLocked) 32 | } 33 | 34 | public init(intervalToLockApp: TimeInterval = AppLockHelper.lockAfterOneMinute) { 35 | self.intervalToLockApp = intervalToLockApp 36 | NotificationCenter.default.addObserver(self, 37 | selector: #selector(deviceDidLock), 38 | name: UIApplication.willResignActiveNotification, 39 | object: nil) 40 | } 41 | 42 | public func isAvailable(_ context: LAContext? = nil) -> Bool { 43 | let currentContext = context ?? LAContext() 44 | return currentContext.canEvaluatePolicy(.deviceOwnerAuthentication, error: nil) 45 | } 46 | 47 | public func setTime() { 48 | timeSinceAppEnteredBackground = Date().timeIntervalSince1970 49 | deviceHasBeenLocked = false 50 | } 51 | 52 | public func evaluatePolicy(reason: String) async throws -> Bool { 53 | let context = LAContext() 54 | guard isAvailable(context) else { 55 | return false 56 | } 57 | 58 | return try await context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason) 59 | } 60 | 61 | @objc private func deviceDidLock() { 62 | deviceHasBeenLocked = true 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Modifiers/SceneLifecycleModifier.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2024 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import InfomaniakCore 20 | import InfomaniakDI 21 | import SwiftUI 22 | 23 | public extension View { 24 | func sceneLifecycle(willEnterForeground: (() -> Void)? = nil, didEnterBackground: (() -> Void)? = nil) -> some View { 25 | return modifier(SceneLifecycleModifier(willEnterForeground: willEnterForeground, didEnterBackground: didEnterBackground)) 26 | } 27 | } 28 | 29 | struct SceneLifecycleModifier: ViewModifier { 30 | @LazyInjectService private var platformDetector: PlatformDetectable 31 | 32 | var willEnterForeground: (() -> Void)? 33 | var didEnterBackground: (() -> Void)? 34 | 35 | func body(content: Content) -> some View { 36 | content 37 | .onAppear { 38 | /* 39 | On iOS/iPadOS, the `UIScene.willEnterForegroundNotification` notification is not posted when 40 | the app is opened for the first time. 41 | */ 42 | if !platformDetector.isMac { 43 | willEnterForeground?() 44 | } 45 | } 46 | .onReceive(NotificationCenter.default.publisher(for: UIScene.willEnterForegroundNotification)) { _ in 47 | /* 48 | On iOS/iPadOS: 49 | `scenePhase` changes each time a pop-up is presented. 50 | We have to listen to `UIScene.willEnterForegroundNotification` to increase the `appLaunchCounter` 51 | only when the app enters foreground. 52 | 53 | On macOS: 54 | `scenePhase` stays always active even when the app is on the background. 55 | */ 56 | willEnterForeground?() 57 | } 58 | .onReceive(NotificationCenter.default.publisher(for: UIScene.didEnterBackgroundNotification)) { _ in 59 | didEnterBackground?() 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Components/Buttons/Models/IKButtonTheme.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import SwiftUI 20 | 21 | @available(iOS 15.0, *) 22 | @frozen public struct IKButtonTheme { 23 | public let primary: any ShapeStyle 24 | public let secondary: any ShapeStyle 25 | public let tertiary: any ShapeStyle 26 | 27 | public let disabledPrimary: any ShapeStyle 28 | public let disabledSecondary: any ShapeStyle 29 | 30 | public let error: any ShapeStyle 31 | 32 | public let smallFont: Font 33 | public let mediumFont: Font 34 | 35 | public init( 36 | primary: any ShapeStyle, 37 | secondary: any ShapeStyle, 38 | tertiary: any ShapeStyle, 39 | disabledPrimary: any ShapeStyle, 40 | disabledSecondary: any ShapeStyle, 41 | error: any ShapeStyle, 42 | smallFont: Font, 43 | mediumFont: Font 44 | ) { 45 | self.primary = primary 46 | self.secondary = secondary 47 | self.tertiary = tertiary 48 | self.disabledPrimary = disabledPrimary 49 | self.disabledSecondary = disabledSecondary 50 | self.error = error 51 | self.smallFont = smallFont 52 | self.mediumFont = mediumFont 53 | } 54 | } 55 | 56 | // MARK: - Helpers 57 | 58 | @available(iOS 15.0, *) 59 | extension IKButtonTheme { 60 | func scaledFont(_ controlSize: ControlSize) -> Font { 61 | if controlSize == .small { 62 | return smallFont 63 | } else { 64 | return mediumFont 65 | } 66 | } 67 | } 68 | 69 | // MARK: - Default Theme 70 | 71 | @available(iOS 15.0, *) 72 | extension IKButtonTheme { 73 | static let defaultTheme = IKButtonTheme( 74 | primary: TintShapeStyle.tint, 75 | secondary: Color.white, 76 | tertiary: Color.gray.opacity(0.4), 77 | disabledPrimary: Color.gray, 78 | disabledSecondary: Color.white, 79 | error: Color.red, 80 | smallFont: .callout, 81 | mediumFont: .body 82 | ) 83 | } 84 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Assets.xcassets/sentry-long.imageset/sentry-text.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreUIKit/UICollectionView/InsetCollectionViewCell.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import UIKit 20 | 21 | open class InsetCollectionViewCell: UICollectionViewCell { 22 | @IBOutlet open weak var topConstraint: NSLayoutConstraint? 23 | @IBOutlet open weak var bottomConstraint: NSLayoutConstraint? 24 | @IBOutlet open weak var contentInsetView: UIView! 25 | @IBOutlet open weak var separator: UIView? 26 | 27 | override open func awakeFromNib() { 28 | super.awakeFromNib() 29 | selectedBackgroundView = UIView() 30 | } 31 | 32 | open func initWithPositionAndShadow(isFirst: Bool = false, isLast: Bool = false, elevation: Double = 0, radius: CGFloat = 6) { 33 | if isLast && isFirst { 34 | separator?.isHidden = true 35 | topConstraint?.constant = 8 36 | bottomConstraint?.constant = 8 37 | contentInsetView.roundCorners( 38 | corners: [.layerMaxXMaxYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMinXMinYCorner], 39 | radius: radius 40 | ) 41 | } else if isFirst { 42 | separator?.isHidden = false 43 | topConstraint?.constant = 8 44 | bottomConstraint?.constant = 0 45 | contentInsetView.roundCorners(corners: [.layerMaxXMinYCorner, .layerMinXMinYCorner], radius: radius) 46 | } else if isLast { 47 | separator?.isHidden = true 48 | topConstraint?.constant = 0 49 | bottomConstraint?.constant = 8 50 | contentInsetView.roundCorners(corners: [.layerMaxXMaxYCorner, .layerMinXMaxYCorner], radius: radius) 51 | } else { 52 | separator?.isHidden = false 53 | topConstraint?.constant = 0 54 | bottomConstraint?.constant = 0 55 | contentInsetView.roundCorners( 56 | corners: [.layerMaxXMaxYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMinXMinYCorner], 57 | radius: 0 58 | ) 59 | } 60 | contentInsetView.addShadow(elevation: elevation) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Components/AlertView/AskForReviewView.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import DesignSystem 20 | import InfomaniakCore 21 | import InfomaniakCoreCommonUI 22 | import InfomaniakCoreUIResources 23 | import InfomaniakDI 24 | import SwiftUI 25 | 26 | public struct AskForReviewView: View { 27 | private let appName: String 28 | private let feedbackURL: String 29 | private let onLike: () async throws -> Void 30 | private let onDislike: (URL) -> Void 31 | private let reviewManager: ReviewManageable 32 | 33 | public init( 34 | appName: String, 35 | feedbackURL: String, 36 | reviewManager: ReviewManageable, 37 | onLike: @escaping () async throws -> Void, 38 | onDislike: @escaping (URL) -> Void 39 | ) { 40 | self.appName = appName 41 | self.feedbackURL = feedbackURL 42 | self.reviewManager = reviewManager 43 | self.onLike = onLike 44 | self.onDislike = onDislike 45 | } 46 | 47 | public var body: some View { 48 | VStack(alignment: .leading, spacing: 0) { 49 | Text(CoreUILocalizable.reviewAlertTitle(appName)) 50 | .padding(.bottom, IKPadding.large) 51 | 52 | ModalButtonsView( 53 | primaryButtonTitle: CoreUILocalizable.buttonYes, 54 | secondaryButtonTitle: CoreUILocalizable.buttonNo, 55 | primaryButtonAction: { 56 | try await onLike() 57 | reviewManager.requestReview() 58 | }, 59 | secondaryButtonAction: { 60 | if let userReportURL = URL(string: feedbackURL) { 61 | onDislike(userReportURL) 62 | } 63 | } 64 | ) 65 | } 66 | } 67 | } 68 | 69 | #Preview { 70 | AskForReviewView( 71 | appName: "InfomaniakCoreUI ", 72 | feedbackURL: "https://infomaniak.com", 73 | reviewManager: ReviewManager( 74 | userDefaults: UserDefaults.standard, 75 | openingBeforeFirstReview: 1, 76 | openingBeforeNextReviews: 2 77 | ), 78 | onLike: {}, 79 | onDislike: { _ in 80 | } 81 | ) 82 | } 83 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreUIKit/TitleSizeAdjustingNavigationController.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #if os(macOS) 20 | import AppKit 21 | #elseif os(iOS) 22 | import UIKit 23 | #elseif os(tvOS) || os(watchOS) 24 | import UIKit 25 | #endif 26 | 27 | /// A `UINavigationController` that adjusts the font size of its large title labels to fit its content 28 | open class TitleSizeAdjustingNavigationController: UINavigationController { 29 | var minimumScaleFactor: CGFloat = 0.5 30 | 31 | #if !os(tvOS) 32 | override public func viewDidLayoutSubviews() { 33 | guard navigationBar.prefersLargeTitles else { return } 34 | 35 | updateLargeTitleLabels() 36 | } 37 | #endif 38 | 39 | private func updateLargeTitleLabels() { 40 | for largeTitleLabel in largeTitleLabels() { 41 | largeTitleLabel.adjustsFontSizeToFitWidth = true 42 | largeTitleLabel.minimumScaleFactor = minimumScaleFactor 43 | } 44 | } 45 | 46 | private func largeTitleLabels() -> [UILabel] { 47 | let subviews = recursiveSubviews(of: navigationBar) 48 | let labels = subviews.compactMap { $0 as? UILabel } 49 | let titles = viewControllers.compactMap { $0.navigationItem.title } + viewControllers.compactMap { $0.title } 50 | let titleLabels = labels.filter { 51 | if let text = $0.text, titles.contains(text) { 52 | return true 53 | } 54 | return false 55 | } 56 | // 'large' title labels are identified by comparing font size 57 | let titleLabelFontSizes = titleLabels.map { $0.font.pointSize } 58 | let largeTitleLabelFontSize = titleLabelFontSizes.max() 59 | let largeTitleLabels = titleLabels.filter { $0.font.pointSize == largeTitleLabelFontSize } 60 | return largeTitleLabels 61 | } 62 | 63 | private func recursiveSubviews(of view: UIView) -> [UIView] { 64 | var result = [UIView]() 65 | for subview in view.subviews { 66 | result.append(subview) 67 | result.append(contentsOf: recursiveSubviews(of: subview)) 68 | } 69 | return result 70 | } 71 | 72 | override open var childForStatusBarStyle: UIViewController? { 73 | return topViewController 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Components/Discovery/DiscoveryPresenter.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import DesignSystem 20 | import SwiftUI 21 | 22 | public extension View { 23 | func discoveryPresenter( 24 | isPresented: Binding, 25 | topPadding: CGFloat = IKPadding.large, 26 | bottomPadding: CGFloat = IKPadding.medium, 27 | alertBackgroundColor: Color, 28 | sheetBackgroundColor: Color, 29 | @ViewBuilder modalContent: @escaping () -> ModalContent 30 | ) -> some View { 31 | modifier(DiscoveryPresenter( 32 | isPresented: isPresented, 33 | topPadding: topPadding, 34 | bottomPadding: bottomPadding, 35 | alertBackgroundColor: alertBackgroundColor, 36 | sheetBackgroundColor: sheetBackgroundColor, 37 | modalContent: modalContent 38 | )) 39 | } 40 | } 41 | 42 | struct DiscoveryPresenter: ViewModifier { 43 | @Environment(\.isCompactWindow) private var isCompactWindow 44 | 45 | @Binding var isPresented: Bool 46 | 47 | let topPadding: CGFloat 48 | let bottomPadding: CGFloat 49 | let alertBackgroundColor: Color 50 | let sheetBackgroundColor: Color 51 | @ViewBuilder let modalContent: ModalContent 52 | 53 | func body(content: Content) -> some View { 54 | content 55 | .sheet(isPresented: Binding(get: { isCompactWindow && isPresented }, set: { isPresented = $0 })) { 56 | if #available(iOS 16.0, *) { 57 | modalContent.modifier(SelfSizingPanelViewModifier(topPadding: topPadding, bottomPadding: bottomPadding)) 58 | .background(sheetBackgroundColor) 59 | } else { 60 | modalContent.modifier(SelfSizingPanelBackportViewModifier( 61 | topPadding: topPadding, 62 | bottomPadding: bottomPadding 63 | )) 64 | .background(sheetBackgroundColor) 65 | } 66 | } 67 | .customAlert( 68 | isPresented: Binding(get: { !isCompactWindow && isPresented }, set: { isPresented = $0 }), 69 | backgroundColor: alertBackgroundColor 70 | ) { 71 | modalContent 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/TrackerDetailsView.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2025 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import DesignSystem 20 | import InfomaniakCore 21 | import InfomaniakCoreSwiftUI 22 | import InfomaniakDI 23 | import SwiftUI 24 | 25 | @available(iOS 15.0, *) 26 | struct TrackerDetailsView: View { 27 | @Environment(\.dismiss) private var dismiss 28 | 29 | @AppStorage private var dataValue: Bool 30 | 31 | private let backgroundColor: Color 32 | private let tracker: Tracker 33 | 34 | init(tracker: Tracker, appStorageKey: String, backgroundColor: Color) { 35 | self.tracker = tracker 36 | _dataValue = AppStorage(wrappedValue: true, appStorageKey) 37 | self.backgroundColor = backgroundColor 38 | } 39 | 40 | var body: some View { 41 | NavigationView { 42 | ScrollView { 43 | VStack(alignment: .leading, spacing: 0) { 44 | tracker.logoLong 45 | .padding(.vertical, value: .medium) 46 | .frame(maxWidth: .infinity) 47 | 48 | Text(LocalizedStringKey(tracker.description), bundle: .module) 49 | .font(.body) 50 | .multilineTextAlignment(.leading) 51 | .padding(IKPadding.medium) 52 | 53 | Toggle(isOn: $dataValue) { 54 | Text("authorizeTracking", bundle: .module) 55 | .font(.body) 56 | } 57 | .tint(.accentColor) 58 | .padding(value: .medium) 59 | } 60 | } 61 | .background(backgroundColor) 62 | .navigationBarTitle(Text(tracker.title, bundle: .module), displayMode: .inline) 63 | .toolbar { 64 | ToolbarItem(placement: .navigationBarLeading) { 65 | Button { 66 | dismiss() 67 | } label: { 68 | Image(systemName: "xmark") 69 | .resizable() 70 | .scaledToFit() 71 | } 72 | } 73 | } 74 | } 75 | } 76 | } 77 | 78 | @available(iOS 15.0, *) 79 | #Preview { 80 | TrackerDetailsView( 81 | tracker: Tracker.matomo, 82 | appStorageKey: "matomoKey", 83 | backgroundColor: .white 84 | ) 85 | } 86 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Helpers/FileType/FileType.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2024 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import SwiftUI 20 | import UniformTypeIdentifiers 21 | 22 | @available(iOS 14.0, *) 23 | public extension UTType { 24 | static let pages = UTType("com.apple.iwork.pages.sffpages")! 25 | static let wordDoc = UTType("com.microsoft.word.doc")! 26 | static let wordDocm = UTType(mimeType: "application/vnd.ms-word")! 27 | static let wordDocx = UTType("org.openxmlformats.wordprocessingml.document")! 28 | static let onlyOffice = UTType("org.oasis-open.opendocument.text")! 29 | 30 | static let ics = UTType(mimeType: "application/ics")! 31 | } 32 | 33 | @available(iOS 14.0, *) 34 | public extension FileType { 35 | static let archive = FileType(asset: "file-archive", types: [.archive]) 36 | static let audio = FileType(asset: "file-audio", types: [.audio]) 37 | static let code = FileType(asset: "file-code", types: [.sourceCode, .html, .json, .xml]) 38 | static let doc = FileType(asset: "file-doc", types: [.text, .pages, .onlyOffice, .wordDoc, .wordDocm, .wordDocx]) 39 | static let font = FileType(asset: "file-font", types: [.font]) 40 | static let grid = FileType(asset: "file-grid", types: [.spreadsheet]) 41 | static let ics = FileType(asset: "file-ics", types: [.calendarEvent, .ics]) 42 | static let image = FileType(asset: "file-img", types: [.image]) 43 | static let pdf = FileType(asset: "file-pdf", types: [.pdf]) 44 | static let point = FileType(asset: "file-point", types: [.presentation]) 45 | static let vCard = FileType(asset: "file-vcard", types: [.vCard]) 46 | static let video = FileType(asset: "file-video", types: [.video, .movie]) 47 | 48 | static let unknown = FileType(asset: "file-unknown", types: []) 49 | } 50 | 51 | @available(iOS 14.0, *) 52 | public struct FileType: Sendable { 53 | public let image: Image 54 | public let color: Color 55 | public let types: [UTType] 56 | 57 | public init(image: Image, color: Color, types: [UTType]) { 58 | self.image = image 59 | self.color = color 60 | self.types = types 61 | } 62 | 63 | private init(asset: String, types: [UTType]) { 64 | self.init(image: Image(asset, bundle: .module), color: Color("\(asset)-color", bundle: .module), types: types) 65 | } 66 | 67 | public func conforms(to type: UTType) -> Bool { 68 | return types.contains { conformingType in 69 | type.conforms(to: conformingType) 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Components/WebView.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import SwiftUI 20 | import UIKit 21 | import WebKit 22 | 23 | public struct WebView: UIViewRepresentable { 24 | public typealias UIViewType = WKWebView 25 | 26 | let initialURL: URL 27 | var onPageLoaded: ((URL) -> Void)? 28 | var shouldNavigateToPage: ((WKWebView, WKNavigationAction, @escaping (WKNavigationActionPolicy) -> Void) -> Void)? 29 | 30 | public init( 31 | initialURL: URL, 32 | onPageLoaded: ((URL) -> Void)? = nil, 33 | shouldNavigateToPage: ((WKWebView, WKNavigationAction, @escaping (WKNavigationActionPolicy) -> Void) -> Void)? = nil 34 | ) { 35 | self.initialURL = initialURL 36 | self.onPageLoaded = onPageLoaded 37 | self.shouldNavigateToPage = shouldNavigateToPage 38 | } 39 | 40 | public class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate { 41 | var parent: WebView 42 | 43 | init(_ parent: WebView) { 44 | self.parent = parent 45 | } 46 | 47 | public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation) { 48 | guard let pageURL = webView.url else { return } 49 | parent.onPageLoaded?(pageURL) 50 | } 51 | 52 | public func webView( 53 | _ webView: WKWebView, 54 | decidePolicyFor navigationAction: WKNavigationAction, 55 | decisionHandler: @escaping (WKNavigationActionPolicy) -> Void 56 | ) { 57 | guard let shouldNavigateToPage = parent.shouldNavigateToPage else { 58 | decisionHandler(.allow) 59 | return 60 | } 61 | shouldNavigateToPage(webView, navigationAction, decisionHandler) 62 | } 63 | } 64 | 65 | public func makeCoordinator() -> Coordinator { 66 | Coordinator(self) 67 | } 68 | 69 | public func makeUIView(context: Context) -> WKWebView { 70 | let webView = WKWebView() 71 | webView.navigationDelegate = context.coordinator 72 | webView.uiDelegate = context.coordinator 73 | webView.scrollView.bounces = false 74 | webView.scrollView.bouncesZoom = false 75 | webView.scrollView.showsVerticalScrollIndicator = false 76 | webView.scrollView.showsHorizontalScrollIndicator = true 77 | webView.scrollView.alwaysBounceVertical = false 78 | webView.scrollView.alwaysBounceHorizontal = false 79 | 80 | webView.load(URLRequest(url: initialURL)) 81 | return webView 82 | } 83 | 84 | public func updateUIView(_ uiView: WKWebView, context: Context) { 85 | // needed for UIViewRepresentable 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Components/Buttons/ModalButtonsView.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2023 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import DesignSystem 20 | import InfomaniakCoreCommonUI 21 | import InfomaniakCoreUIResources 22 | import OSLog 23 | import SwiftUI 24 | 25 | public struct ModalButtonsView: View { 26 | @Environment(\.dismiss) private var dismiss 27 | 28 | @State private var isButtonLoading = false 29 | 30 | private let primaryButtonTitle: String 31 | private var secondaryButtonTitle: String? 32 | private var primaryButtonEnabled = true 33 | private let primaryButtonAction: () async throws -> Void 34 | private var secondaryButtonAction: (() -> Void)? 35 | private var primaryButtonRole: ButtonRole? 36 | 37 | public init( 38 | primaryButtonTitle: String, 39 | secondaryButtonTitle: String? = CoreUILocalizable.buttonCancel, 40 | primaryButtonEnabled: Bool = true, 41 | primaryButtonAction: @escaping () async throws -> Void, 42 | secondaryButtonAction: (() -> Void)? = nil, 43 | primaryButtonRole: ButtonRole? = nil 44 | ) { 45 | self.primaryButtonTitle = primaryButtonTitle 46 | self.primaryButtonEnabled = primaryButtonEnabled 47 | self.secondaryButtonTitle = secondaryButtonTitle 48 | self.primaryButtonAction = primaryButtonAction 49 | self.secondaryButtonAction = secondaryButtonAction 50 | self.primaryButtonRole = primaryButtonRole 51 | } 52 | 53 | public var body: some View { 54 | HStack(spacing: IKPadding.micro) { 55 | if let secondaryButtonTitle { 56 | Button { 57 | secondaryButtonAction?() 58 | dismiss() 59 | } label: { 60 | Text(secondaryButtonTitle) 61 | } 62 | .buttonStyle(.ikBorderless) 63 | .keyboardShortcut(.cancelAction) 64 | } 65 | 66 | Button(primaryButtonTitle, role: primaryButtonRole) { 67 | Task { 68 | isButtonLoading = true 69 | do { 70 | try await primaryButtonAction() 71 | dismiss() 72 | } catch { 73 | Logger.view.warning("\(error)") 74 | } 75 | isButtonLoading = false 76 | } 77 | } 78 | .buttonStyle(.ikBorderedProminent) 79 | .disabled(!primaryButtonEnabled) 80 | .ikButtonLoading(isButtonLoading) 81 | .keyboardShortcut(.defaultAction) 82 | } 83 | .frame(maxWidth: .infinity, alignment: .trailing) 84 | } 85 | } 86 | 87 | #Preview { 88 | ModalButtonsView(primaryButtonTitle: "Save", secondaryButtonTitle: nil) { /* Preview */ } 89 | } 90 | -------------------------------------------------------------------------------- /Sources/InfomaniakPrivacyManagement/Resources/Assets.xcassets/sentry-long.imageset/sentry-text-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.7 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "InfomaniakCoreUI", 8 | defaultLocalization: "en", 9 | platforms: [ 10 | .iOS(.v15) 11 | ], 12 | products: [ 13 | .library( 14 | name: "InfomaniakCoreCommonUI", 15 | targets: ["InfomaniakCoreCommonUI"] 16 | ), 17 | .library( 18 | name: "InfomaniakCoreUIKit", 19 | targets: ["InfomaniakCoreUIKit"] 20 | ), 21 | .library( 22 | name: "InfomaniakCoreSwiftUI", 23 | targets: ["InfomaniakCoreSwiftUI"] 24 | ), 25 | .library( 26 | name: "InfomaniakPrivacyManagement", 27 | targets: ["InfomaniakPrivacyManagement"] 28 | ), 29 | .library( 30 | name: "InfomaniakCoreUIResources", 31 | targets: ["InfomaniakCoreUIResources"] 32 | ), 33 | .library( 34 | name: "DesignSystem", 35 | targets: ["DesignSystem"] 36 | ) 37 | ], 38 | dependencies: [ 39 | .package(url: "https://github.com/Infomaniak/ios-core", .upToNextMajor(from: "18.0.0")), 40 | .package(url: "https://github.com/Infomaniak/SnackBar.swift", .upToNextMajor(from: "1.2.0")), 41 | .package(url: "https://github.com/kean/Nuke", .upToNextMajor(from: "12.8.0")), 42 | .package(url: "https://github.com/matomo-org/matomo-sdk-ios", .upToNextMajor(from: "7.5.2")), 43 | .package(url: "https://github.com/shaps80/SwiftUIBackports", .upToNextMajor(from: "1.15.1")), 44 | .package(url: "https://github.com/siteline/SwiftUI-Introspect", .upToNextMajor(from: "26.0.0")), 45 | .package(url: "https://github.com/airbnb/lottie-spm", .upToNextMajor(from: "4.5.2")) 46 | ], 47 | targets: [ 48 | .target( 49 | name: "InfomaniakCoreCommonUI", 50 | dependencies: [ 51 | "Nuke", 52 | .product(name: "MatomoTracker", package: "matomo-sdk-ios"), 53 | .product(name: "InfomaniakCore", package: "ios-core"), 54 | .product(name: "SnackBar", package: "SnackBar.swift") 55 | ] 56 | ), 57 | .target( 58 | name: "InfomaniakCoreUIKit", 59 | dependencies: ["InfomaniakCoreCommonUI"] 60 | ), 61 | .target( 62 | name: "InfomaniakCoreSwiftUI", 63 | dependencies: [ 64 | "SwiftUIBackports", 65 | "DesignSystem", 66 | "InfomaniakCoreUIResources", 67 | "InfomaniakCoreCommonUI", 68 | .product(name: "Lottie", package: "lottie-spm"), 69 | .product(name: "InfomaniakCore", package: "ios-core"), 70 | .product(name: "SwiftUIIntrospect-Dynamic", package: "SwiftUI-Introspect") 71 | ] 72 | ), 73 | .target( 74 | name: "InfomaniakPrivacyManagement", 75 | dependencies: [ 76 | "DesignSystem", 77 | "InfomaniakCoreSwiftUI" 78 | ] 79 | ), 80 | .target( 81 | name: "InfomaniakCoreUIResources" 82 | ), 83 | .target( 84 | name: "DesignSystem" 85 | ), 86 | .testTarget( 87 | name: "InfomaniakCoreUITests", 88 | dependencies: ["InfomaniakCoreCommonUI", "InfomaniakCoreUIKit", "InfomaniakCoreSwiftUI"] 89 | ) 90 | ] 91 | ) 92 | -------------------------------------------------------------------------------- /Sources/InfomaniakCoreSwiftUI/Modifiers/FloatingPanelHelper.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Infomaniak Core UI - iOS 3 | Copyright (C) 2024 Infomaniak Network SA 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | import DesignSystem 20 | import InfomaniakCore 21 | import InfomaniakDI 22 | import SwiftUI 23 | import SwiftUIBackports 24 | import SwiftUIIntrospect 25 | 26 | @available(iOS 15, *) 27 | public extension View { 28 | func floatingPanel( 29 | isPresented: Binding, 30 | title: String? = nil, 31 | closeButtonHidden: Bool = false, 32 | backgroundColor: Color, 33 | topPadding: CGFloat = IKPadding.large, 34 | bottomPadding: CGFloat = IKPadding.medium, 35 | @ViewBuilder content: @escaping () -> Content 36 | ) -> some View { 37 | sheet(isPresented: isPresented) { 38 | if #available(iOS 16.0, *) { 39 | content().modifier(SelfSizingPanelViewModifier( 40 | title: title, 41 | closeButtonHidden: closeButtonHidden, 42 | topPadding: topPadding, 43 | bottomPadding: bottomPadding 44 | )) 45 | .background(backgroundColor) 46 | } else { 47 | content().modifier(SelfSizingPanelBackportViewModifier( 48 | title: title, 49 | closeButtonHidden: closeButtonHidden, 50 | topPadding: topPadding, 51 | bottomPadding: bottomPadding 52 | )) 53 | .background(backgroundColor) 54 | } 55 | } 56 | } 57 | 58 | func floatingPanel( 59 | item: Binding, 60 | backgroundColor: Color, 61 | title: String? = nil, 62 | closeButtonHidden: Bool = false, 63 | topPadding: CGFloat = IKPadding.large, 64 | bottomPadding: CGFloat = IKPadding.medium, 65 | @ViewBuilder content: @escaping (Item) -> Content 66 | ) -> some View { 67 | sheet(item: item) { item in 68 | if #available(iOS 16.0, *) { 69 | content(item) 70 | .modifier(SelfSizingPanelViewModifier( 71 | title: title, 72 | closeButtonHidden: closeButtonHidden, 73 | topPadding: topPadding, 74 | bottomPadding: bottomPadding 75 | )) 76 | .background(backgroundColor) 77 | } else { 78 | content(item) 79 | .modifier(SelfSizingPanelBackportViewModifier( 80 | title: title, 81 | closeButtonHidden: closeButtonHidden, 82 | topPadding: topPadding, 83 | bottomPadding: bottomPadding 84 | )) 85 | .background(backgroundColor) 86 | } 87 | } 88 | } 89 | } 90 | --------------------------------------------------------------------------------