├── .github
└── workflows
│ └── swift.yml
├── .gitignore
├── .swift-format
├── .swiftlint.yml
├── Addame.xcodeproj
└── project.pbxproj
├── Addame.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ ├── IDEWorkspaceChecks.plist
│ ├── swiftpm
│ └── Package.resolved
│ └── xcschemes
│ ├── AddameCI.xcscheme
│ ├── AddameDev.xcscheme
│ └── AddamePro.xcscheme
├── Addame
├── Addame.entitlements
├── Addame.swift
├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ ├── Icon-App-83.5x83.5@2x.png
│ │ └── ItunesArtwork@2x.png
│ └── Contents.json
├── Configs
│ ├── DevelopmentCI.xcconfig
│ ├── Environment.swift
│ └── ProductionCI.xcconfig
├── Info.plist
└── Preview Content
│ └── Preview Assets.xcassets
│ └── Contents.json
├── AddameSPM
├── .gitignore
├── .swiftpm
│ └── xcode
│ │ ├── package.xcworkspace
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata
│ │ └── xcschemes
│ │ ├── AppFeature.xcscheme
│ │ ├── AppFeatureTests.xcscheme
│ │ ├── AttachmentClient.xcscheme
│ │ ├── AuthenticationView.xcscheme
│ │ ├── ChatView.xcscheme
│ │ ├── ContactClient.xcscheme
│ │ ├── ContactClientLive.xcscheme
│ │ ├── ContactsViewTests.xcscheme
│ │ ├── Event.xcscheme
│ │ ├── EventClient.xcscheme
│ │ ├── EventClientLive.xcscheme
│ │ ├── EventFormView.xcscheme
│ │ ├── EventFormViewTests.xcscheme
│ │ ├── EventView.xcscheme
│ │ ├── EventViewTests.xcscheme
│ │ ├── KeychainService.xcscheme
│ │ ├── PathMonitorClient.xcscheme
│ │ ├── ProfileView.xcscheme
│ │ ├── SettingsView.xcscheme
│ │ ├── SharedModels.xcscheme
│ │ ├── SwiftUIExtension.xcscheme
│ │ ├── SwiftUIHelpers.xcscheme
│ │ └── TabsView.xcscheme
├── Package.resolved
├── Package.swift
├── README.md
├── Sources
│ ├── APIClient
│ │ ├── APIClient.swift
│ │ ├── URLRequest+Extension.swift
│ │ └── UserClient.swift
│ ├── AppConfiguration
│ │ └── AppConfiguration.swift
│ ├── AppFeature
│ │ ├── AppDelegate.swift
│ │ └── AppView.swift
│ ├── AsyncImageLoder
│ │ ├── AssetExtractor.swift
│ │ ├── AsyncImage.swift
│ │ ├── AsyncImageLoder.swift
│ │ ├── EnvironmentValues.swift
│ │ ├── ImageDraw.swift
│ │ ├── ImagePicker.swift
│ │ └── TemporaryImageCache.swift
│ ├── AttachmentS3Client
│ │ ├── AttachmentS3Client.swift
│ │ ├── AwsS3Manager.swift
│ │ └── Mocks.swift
│ ├── AuthenticationView
│ │ ├── AuthenticationCore.swift
│ │ ├── AuthenticationView.swift
│ │ ├── AuthenticationViewExtension.swift
│ │ ├── PhoneNumberKit+Extension.swift
│ │ ├── PhoneNumberTextFieldView.swift
│ │ └── Resources
│ │ │ └── PhoneNumberMetadata.json
│ ├── ChatClient
│ │ ├── ChatClient.swift
│ │ └── Mocks.swift
│ ├── ChatClientLive
│ │ └── Live.swift
│ ├── ChatView
│ │ ├── ChatAction.swift
│ │ ├── ChatBottomView.swift
│ │ ├── ChatEnvironment.swift
│ │ ├── ChatListView.swift
│ │ ├── ChatReducer.swift
│ │ ├── ChatRowView.swift
│ │ ├── ChatState.swift
│ │ └── ChatView.swift
│ ├── CombineHelpers
│ │ ├── Combine.swift
│ │ └── ReplaySubject.swift
│ ├── ComposableArchitectureHelpers
│ │ └── WebSocketId.swift
│ ├── ContactClient
│ │ ├── ContactClient.swift
│ │ └── Mocks.swift
│ ├── ContactClientLive
│ │ ├── FlatMapLatest.swift
│ │ └── Live.swift
│ ├── ContactsView
│ │ ├── ContactListAction.swift
│ │ ├── ContactListView.swift
│ │ ├── ContactRow.swift
│ │ ├── ContactRowAction.swift
│ │ ├── ContactRowReducer.swift
│ │ ├── ContactRowState.swift
│ │ ├── ContactsAction.swift
│ │ ├── ContactsEnvironment.swift
│ │ ├── ContactsReducer.swift
│ │ ├── ContactsState.swift
│ │ └── ContactsView.swift
│ ├── ConversationClient
│ │ ├── ConversationClient.swift
│ │ └── Mocks.swift
│ ├── ConversationClientLive
│ │ └── Live.swift
│ ├── ConversationsView
│ │ ├── ConversationEnvironment.swift
│ │ ├── ConversationsAction.swift
│ │ ├── ConversationsReducer.swift
│ │ ├── ConversationsState.swift
│ │ └── ConversationsView.swift
│ ├── CoreDataClient
│ │ └── CoreDataClient.swift
│ ├── CoreDataStore
│ │ ├── CoreDataStore.swift
│ │ ├── Entities
│ │ │ └── Contacts
│ │ │ │ ├── ContactEntity+CoreDataClass.swift
│ │ │ │ ├── ContactEntity+CoreDataProperties.swift
│ │ │ │ └── ContactEntityExtension.swift
│ │ ├── Helper
│ │ │ ├── CoreDataPublisher.swift
│ │ │ ├── ManagedModel.swift
│ │ │ └── NSManagedObjectContext+Extensions.swift
│ │ └── Models
│ │ │ └── AddaModel.xcdatamodeld
│ │ │ └── AddaModel.xcdatamodel
│ │ │ └── contents
│ ├── DeviceClient
│ │ └── DeviceClicnt.swift
│ ├── EventClient
│ │ ├── EventClient.swift
│ │ └── Mocks.swift
│ ├── EventClientLive
│ │ └── Live.swift
│ ├── EventFormView
│ │ ├── EventFormAction.swift
│ │ ├── EventFormEnvironment.swift
│ │ ├── EventFormReducer.swift
│ │ ├── EventFormState.swift
│ │ └── EventFormView.swift
│ ├── EventView
│ │ ├── EventRowView.swift
│ │ ├── EventView.swift
│ │ ├── EventsAction.swift
│ │ ├── EventsEnvironment.swift
│ │ ├── EventsReducer.swift
│ │ ├── EventsState.swift
│ │ └── EventsStateMocks.swift
│ ├── HangoutDetailsFeature
│ │ ├── EventDetailsAction.swift
│ │ ├── EventDetailsOverlayReducer.swift
│ │ ├── EventDetailsOverlayView.swift
│ │ ├── EventDetailsReducer.swift
│ │ ├── EventDetailsState.swift
│ │ ├── EventDetailsView.swift
│ │ └── Resources
│ │ │ ├── Media.xcassets
│ │ │ ├── Contents.json
│ │ │ └── hangout_dt.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── hangout_dt.jpg
│ │ │ ├── hangout_bc.png
│ │ │ └── hangout_dt.jpg
│ ├── ImagePicker
│ │ └── ImagePicker.swift
│ ├── LocationReducer
│ │ └── LocationReducer.swift
│ ├── LocationSearchClient
│ │ ├── Client.swift
│ │ ├── Live.swift
│ │ ├── Mock.swift
│ │ └── Models.swift
│ ├── Logger
│ │ └── Extension+Logger.swift
│ ├── MapView
│ │ ├── DynamicHeightForTextFieldInSwiftUI.swift
│ │ ├── LocationEnvironment.swift
│ │ ├── LocationSearch.swift
│ │ ├── LocationSearchAction.swift
│ │ ├── LocationSearchManager.swift
│ │ ├── LocationSearchState.swift
│ │ ├── MapView.swift
│ │ └── SearchMapView.swift
│ ├── MyEventsView
│ │ ├── EventRowView.swift
│ │ ├── MyEventsAction.swift
│ │ ├── MyEventsListView.swift
│ │ └── MyEventsReducer.swift
│ ├── ProfileView
│ │ ├── File.swift
│ │ ├── ProfileAction.swift
│ │ ├── ProfileReducer.swift
│ │ ├── ProfileState.swift
│ │ └── ProfileView.swift
│ ├── RegisterFormFeature
│ │ ├── IDFAPermissionView.swift
│ │ ├── LocationPermissionView.swift
│ │ ├── NotificationPermissionView.swift
│ │ ├── RegisterFormReducer.swift
│ │ └── RegisterFormView.swift
│ ├── SettingsFeature
│ │ ├── DistanceFilterView.swift
│ │ ├── NotificationsSettingsView.swift
│ │ ├── Settings.swift
│ │ ├── SettingsNavigationLink.swift
│ │ ├── SettingsRow.swift
│ │ ├── SettingsView.swift
│ │ ├── TermsAndPrivacyWebView.swift
│ │ ├── TermsWebView.swift
│ │ └── UserSettings.swift
│ ├── TabsView
│ │ ├── TabState.swift
│ │ ├── TabsAction.swift
│ │ ├── TabsEnvironment.swift
│ │ ├── TabsReducer.swift
│ │ └── TabsView.swift
│ ├── UserClient
│ │ ├── Mocks.swift
│ │ └── UserClient.swift
│ ├── UserClientLive
│ │ └── Live.swift
│ ├── WebSocketClient
│ │ └── WebSocketClient.swift
│ └── WebSocketReducer
│ │ └── WebSocketReducer.swift
└── Tests
│ ├── AppFeatureTests
│ └── AppFeatureTests.swift
│ ├── AuthenticationViewTests
│ └── AuthenticationViewTests.swift
│ ├── ContactsViewTests
│ └── ContactsViewTests.swift
│ ├── EventFormViewTests
│ └── EventFormViewTests.swift
│ ├── EventViewTests
│ └── EventsViewTests.swift
│ └── MapViewTests
│ └── MapViewTests.swift
├── Gemfile
├── Gemfile.lock
├── README.md
└── fastlane
├── Appfile.swift
├── Fastfile.swift
├── metadata
├── copyright.txt
├── en-US
│ ├── apple_tv_privacy_policy.txt
│ ├── description.txt
│ ├── keywords.txt
│ ├── marketing_url.txt
│ ├── name.txt
│ ├── privacy_url.txt
│ ├── promotional_text.txt
│ ├── release_notes.txt
│ ├── subtitle.txt
│ └── support_url.txt
├── primary_category.txt
├── primary_first_sub_category.txt
├── primary_second_sub_category.txt
├── review_information
│ ├── demo_password.txt
│ ├── demo_user.txt
│ ├── email_address.txt
│ ├── first_name.txt
│ ├── last_name.txt
│ ├── notes.txt
│ └── phone_number.txt
├── secondary_category.txt
├── secondary_first_sub_category.txt
└── secondary_second_sub_category.txt
├── screenshots
├── Framefile.json
├── README.txt
├── background.jpg
├── en-US
│ └── title.strings
├── fonts
│ └── Chalkduster.ttf
└── screenshots.html
└── swift
├── Actions.swift
├── Appfile.swift
├── ArgumentProcessor.swift
├── ControlCommand.swift
├── Deliverfile.swift
├── DeliverfileProtocol.swift
├── Fastfile.swift
├── Fastlane.swift
├── FastlaneSwiftRunner
├── FastlaneSwiftRunner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── FastlaneRunner.xcscheme
└── README.txt
├── Gymfile.swift
├── GymfileProtocol.swift
├── LaneFileProtocol.swift
├── MainProcess.swift
├── Matchfile.swift
├── MatchfileProtocol.swift
├── OptionalConfigValue.swift
├── Plugins.swift
├── Precheckfile.swift
├── PrecheckfileProtocol.swift
├── RubyCommand.swift
├── RubyCommandable.swift
├── Runner.swift
├── RunnerArgument.swift
├── Scanfile.swift
├── ScanfileProtocol.swift
├── Screengrabfile.swift
├── ScreengrabfileProtocol.swift
├── Snapshotfile.swift
├── SnapshotfileProtocol.swift
├── SocketClient.swift
├── SocketClientDelegateProtocol.swift
├── SocketResponse.swift
├── formatting
├── Brewfile
├── Brewfile.lock.json
└── Rakefile
├── main.swift
└── upgrade_manifest.json
/.github/workflows/swift.yml:
--------------------------------------------------------------------------------
1 | name: Swift
2 |
3 | on:
4 | pull_request:
5 | branches: [ main, develop ]
6 |
7 | jobs:
8 |
9 | swiftLint:
10 | runs-on: macos-latest
11 | steps:
12 | - uses: actions/checkout@v2
13 | - name: Install Bundle
14 | run: bundle install
15 | - name: Run swiftlint
16 | run: bundle exec fastlane swiftLintLane
17 |
18 | build:
19 | needs: swiftLint
20 | env:
21 | DEVELOPER_DIR: /Applications/Xcode_13.0.app/Contents/Developer
22 | runs-on: macos-11.0
23 | steps:
24 | - uses: actions/checkout@v2
25 | - name: Install Bundle
26 | run: bundle install
27 | - name: Build
28 | run: bundle exec fastlane buildLane
29 | - name: Upload build
30 | uses: actions/upload-artifact@v2
31 | with:
32 | name: build
33 | path: '"derivedData/Build/Products/Debug CI-iphonesimulator/Addame.app"'
34 |
35 | unitTests:
36 | needs: build
37 | env:
38 | DEVELOPER_DIR: /Applications/Xcode_13.0.app/Contents/Developer
39 | runs-on: macos-11.0
40 | steps:
41 | - uses: actions/checkout@v2
42 | - name: Install Bundle
43 | run: bundle install
44 | - name: Run unit tests
45 | run: bundle exec fastlane unitTestLane
46 | - name: Run tests
47 | uses: actions/download-artifact@v2
48 | with:
49 | name: unitTests
50 | path: '"derivedData/Build/Products/Debug CI-iphonesimulator/EventFormViewTests.xctest"'
51 |
52 |
--------------------------------------------------------------------------------
/.swift-format:
--------------------------------------------------------------------------------
1 | {
2 | "blankLineBetweenMembers" : {
3 | "ignoreSingleLineProperties" : true
4 | },
5 | "indentation" : {
6 | "spaces" : 2
7 | },
8 | "indentConditionalCompilationBlocks" : true,
9 | "lineBreakBeforeControlFlowKeywords" : false,
10 | "lineBreakBeforeEachArgument" : false,
11 | "lineLength" : 200,
12 | "maximumBlankLines" : 1,
13 | "respectsExistingLineBreaks" : true,
14 | "rules" : {
15 | "AllPublicDeclarationsHaveDocumentation" : false,
16 | "AlwaysUseLowerCamelCase" : true,
17 | "AmbiguousTrailingClosureOverload" : true,
18 | "BeginDocumentationCommentWithOneLineSummary" : true,
19 | "BlankLineBetweenMembers" : true,
20 | "CaseIndentLevelEqualsSwitch" : true,
21 | "DoNotUseSemicolons" : true,
22 | "DontRepeatTypeInStaticProperties" : true,
23 | "FullyIndirectEnum" : true,
24 | "GroupNumericLiterals" : true,
25 | "IdentifiersMustBeASCII" : true,
26 | "MultiLineTrailingCommas" : true,
27 | "NeverForceUnwrap" : true,
28 | "NeverUseForceTry" : true,
29 | "NeverUseImplicitlyUnwrappedOptionals" : false,
30 | "NoAccessLevelOnExtensionDeclaration" : true,
31 | "NoBlockComments" : true,
32 | "NoCasesWithOnlyFallthrough" : true,
33 | "NoEmptyTrailingClosureParentheses" : true,
34 | "NoLabelsInCasePatterns" : true,
35 | "NoLeadingUnderscores" : true,
36 | "NoParensAroundConditions" : true,
37 | "NoVoidReturnOnFunctionSignature" : true,
38 | "OneCasePerLine" : true,
39 | "OneVariableDeclarationPerLine" : true,
40 | "OnlyOneTrailingClosureArgument" : true,
41 | "OrderedImports" : true,
42 | "ReturnVoidInsteadOfEmptyTuple" : true,
43 | "UseEnumForNamespacing" : true,
44 | "UseLetInEveryBoundCaseVariable" : false,
45 | "UseShorthandTypeNames" : true,
46 | "UseSingleLinePropertyGetter" : true,
47 | "UseSynthesizedInitializer" : true,
48 | "UseTripleSlashForDocumentationComments" : true,
49 | "ValidateDocumentationComments" : true
50 | },
51 | "tabWidth" : 8,
52 | "version" : 1
53 | }
54 |
--------------------------------------------------------------------------------
/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | disabled_rules:
2 | - empty_enum_arguments
3 | - vertical_parameter_alignment_on_call
4 | - weak_delegate
5 | - vertical_parameter_alignment
6 | - closure_parameter_position
7 | - todo
8 | - multiple_closures_with_trailing_closure
9 | opt_in_rules:
10 | - empty_count
11 | - explicit_init
12 | - closure_spacing
13 | - overridden_super_call
14 | - redundant_nil_coalescing
15 | - private_outlet
16 | - nimble_operator
17 | - operator_usage_whitespace
18 | - closure_end_indentation
19 | - first_where
20 | - prohibited_super_call
21 | - fatal_error_message
22 | - unneeded_parentheses_in_closure_argument
23 | - pattern_matching_keywords
24 | - array_init
25 | - literal_expression_end_indentation
26 | - joined_default_parameter
27 | - contains_over_first_not_nil
28 | - override_in_extension
29 | - private_action
30 | - quick_discouraged_call
31 | - quick_discouraged_focused_test
32 | - quick_discouraged_pending_test
33 | - single_test_class
34 | - sorted_first_last
35 |
36 | analyzer_rules: # Rules run by `swiftlint analyze` (experimental)
37 | - explicit_self
38 |
39 | warning_threshold: 1
40 |
41 | line_length: 120
42 |
43 | type_body_length:
44 | - 300 # warning
45 | - 300 # error
46 |
47 | file_length:
48 | warning: 400 # warning
49 | error: 400 # error
50 |
51 | identifier_name:
52 | min_length:
53 | error: 2
54 | max_length:
55 | error: 50
56 | excluded:
57 | - id
58 | - _id
59 |
60 | indentation: 2
61 |
62 | excluded:
63 | - derivedData
64 | - test_output
65 | - fastlane
66 |
67 | reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit, html, emoji)
68 |
--------------------------------------------------------------------------------
/Addame.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Addame.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Addame/Addame.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | aps-environment
6 | development
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Addame/Addame.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TComposableAAddaMeApp.swift
3 | // TComposableAAddaMe
4 | //
5 | // Created by Saroar Khandoker on 05.04.2021.
6 | //
7 |
8 | import AppFeature
9 | import ComposableArchitecture
10 | import SwiftUI
11 | import UIKit
12 |
13 | final class AppDelegate: NSObject, UIApplicationDelegate {
14 | let store = Store(
15 | initialState: AppReducer.State()
16 | ) {
17 | AppReducer()
18 | ._printChanges()
19 | }
20 |
21 |
22 | func application(
23 | _ application: UIApplication,
24 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
25 | ) -> Bool {
26 | self.store.send(.appDelegate(.didFinishLaunching))
27 | return true
28 | }
29 |
30 | func application(
31 | _ application: UIApplication,
32 | didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
33 | ) {
34 | self.store.send(.appDelegate(.didRegisterForRemoteNotifications(.success(deviceToken))))
35 | }
36 |
37 | func application(
38 | _ application: UIApplication,
39 | didFailToRegisterForRemoteNotificationsWithError error: Error
40 | ) {
41 | self.store.send(.appDelegate(.didRegisterForRemoteNotifications(.failure(error))))
42 | }
43 | }
44 |
45 | @main
46 | struct AddameApp: App {
47 |
48 | @UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
49 | @Environment(\.scenePhase) private var scenePhase
50 |
51 | var body: some Scene {
52 | WindowGroup {
53 | AppView(store: self.appDelegate.store)
54 | }
55 | .onChange(of: self.scenePhase) {
56 | self.appDelegate.store.send(.didChangeScenePhase($0))
57 | }
58 | }
59 | }
60 |
61 |
--------------------------------------------------------------------------------
/Addame/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AddaMeSPB/AddaMeIOS/a407cf9eb7f9969cd5ca042d48c28736fc648b0c/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AddaMeSPB/AddaMeIOS/a407cf9eb7f9969cd5ca042d48c28736fc648b0c/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AddaMeSPB/AddaMeIOS/a407cf9eb7f9969cd5ca042d48c28736fc648b0c/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AddaMeSPB/AddaMeIOS/a407cf9eb7f9969cd5ca042d48c28736fc648b0c/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AddaMeSPB/AddaMeIOS/a407cf9eb7f9969cd5ca042d48c28736fc648b0c/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AddaMeSPB/AddaMeIOS/a407cf9eb7f9969cd5ca042d48c28736fc648b0c/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AddaMeSPB/AddaMeIOS/a407cf9eb7f9969cd5ca042d48c28736fc648b0c/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AddaMeSPB/AddaMeIOS/a407cf9eb7f9969cd5ca042d48c28736fc648b0c/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AddaMeSPB/AddaMeIOS/a407cf9eb7f9969cd5ca042d48c28736fc648b0c/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AddaMeSPB/AddaMeIOS/a407cf9eb7f9969cd5ca042d48c28736fc648b0c/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AddaMeSPB/AddaMeIOS/a407cf9eb7f9969cd5ca042d48c28736fc648b0c/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AddaMeSPB/AddaMeIOS/a407cf9eb7f9969cd5ca042d48c28736fc648b0c/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AddaMeSPB/AddaMeIOS/a407cf9eb7f9969cd5ca042d48c28736fc648b0c/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AddaMeSPB/AddaMeIOS/a407cf9eb7f9969cd5ca042d48c28736fc648b0c/Addame/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/Addame/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AddaMeSPB/AddaMeIOS/a407cf9eb7f9969cd5ca042d48c28736fc648b0c/Addame/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png
--------------------------------------------------------------------------------
/Addame/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Addame/Configs/DevelopmentCI.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Development.xcconfig
3 | // AddaMeIOS
4 | //
5 | // Created by Saroar Khandoker on 02.11.2020.
6 | //
7 |
8 | // Configuration settings file format documentation can be found at:
9 | // https://help.apple.com/xcode/#/dev745c5c974
10 |
11 | // Server URL
12 | ROOT_URL = http:/$()/localhost:8080/v1
13 | WEB_SOCKET_URL = ws:/$()/localhost:6060/v1/chat
14 |
15 | // Image Uploading to DigitalOcen
16 | ACCESS_KEY_ID = value
17 | SECRET_ACCESS_KEY = value
18 |
19 |
--------------------------------------------------------------------------------
/Addame/Configs/Environment.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Environment.swift
3 | // AddaMeIOS
4 | //
5 | // Created by Saroar Khandoker on 02.11.2020.
6 | //
7 |
8 | import Foundation
9 |
10 | public enum EnvironmentKeys {
11 | // MARK: - Keys
12 |
13 | private enum Keys {
14 | // swiftlint:disable nesting
15 | enum Plist {
16 | static let rootURL = "ROOT_URL"
17 | static let webSocketURL = "WEB_SOCKET_URL"
18 | static let accessKeyId = "ACCESS_KEY_ID"
19 | static let secretAccessKey = "SECRET_ACCESS_KEY"
20 | }
21 | }
22 |
23 | // MARK: - Plist
24 |
25 | private static let infoDictionary: [String: Any] = {
26 | guard let dict = Bundle.main.infoDictionary else {
27 | fatalError("Plist file not found")
28 | }
29 |
30 | return dict
31 | }()
32 |
33 | // MARK: - Plist values
34 |
35 | static let rootURL: URL = {
36 | guard let rootURLstring = EnvironmentKeys.infoDictionary["ROOT_URL"] as? String else {
37 | fatalError("Root URL not set in plist for this environment")
38 | }
39 |
40 | guard let url = URL(string: rootURLstring) else {
41 | fatalError("Root URL is invalid")
42 | }
43 |
44 | return url
45 | }()
46 |
47 | static let webSocketURL: URL = {
48 | guard let webSocketString = EnvironmentKeys.infoDictionary[Keys.Plist.webSocketURL] as? String
49 | else {
50 | fatalError("WEB SOCKET URL Key not set in plist for this environment")
51 | }
52 |
53 | guard let url = URL(string: webSocketString) else {
54 | fatalError("WEB SOCKET URL is invalid")
55 | }
56 |
57 | return url
58 | }()
59 |
60 | static let accessKeyId: String = {
61 | guard let accessKeyId = EnvironmentKeys.infoDictionary["ACCESS_KEY_ID"] as? String else {
62 | fatalError("ACCESS_KEY_ID not set in plist for this environment")
63 | }
64 |
65 | return accessKeyId
66 | }()
67 |
68 | static let secretAccessKey: String = {
69 | guard let secretAccessKey = EnvironmentKeys.infoDictionary["SECRET_ACCESS_KEY"] as? String
70 | else {
71 | fatalError("SECRET_ACCESS_KEY not set in plist for this environment")
72 | }
73 |
74 | return secretAccessKey
75 | }()
76 | }
77 |
--------------------------------------------------------------------------------
/Addame/Configs/ProductionCI.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Production.xcconfig
3 | // AddaMeIOS
4 | //
5 | // Created by Saroar Khandoker on 11.11.2020.
6 | //
7 |
8 | // Configuration settings file format documentation can be found at:
9 | // https://help.apple.com/xcode/#/dev745c5c974
10 |
11 | ROOT_URL = https:/$()/domain/v1
12 | WEB_SOCKET_URL = ws:/$()/domain:6060/v1/chat
13 |
14 | // Image Uploading to DigitalOcen
15 | ACCESS_KEY_ID = value
16 | SECRET_ACCESS_KEY = value
17 |
--------------------------------------------------------------------------------
/Addame/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/AddameSPM/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 | xcuserdata/
6 | DerivedData/
7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/AppFeature.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
54 |
60 |
61 |
67 |
68 |
69 |
70 |
72 |
73 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/AppFeatureTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
14 |
15 |
17 |
23 |
24 |
25 |
26 |
27 |
37 |
38 |
44 |
45 |
47 |
48 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/AttachmentClient.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/AuthenticationView.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/ChatView.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/ContactClient.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/ContactClientLive.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/ContactsViewTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
14 |
15 |
17 |
23 |
24 |
25 |
26 |
27 |
37 |
38 |
42 |
43 |
44 |
45 |
51 |
52 |
54 |
55 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/Event.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventClient.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventClientLive.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventFormView.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventFormViewTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
14 |
15 |
17 |
23 |
24 |
25 |
26 |
27 |
37 |
38 |
44 |
45 |
47 |
48 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventView.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/EventViewTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
14 |
15 |
17 |
23 |
24 |
25 |
26 |
27 |
37 |
38 |
44 |
45 |
47 |
48 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/KeychainService.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/PathMonitorClient.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/ProfileView.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/SettingsView.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/SharedModels.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/SwiftUIExtension.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/SwiftUIHelpers.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/.swiftpm/xcode/xcshareddata/xcschemes/TabsView.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/AddameSPM/README.md:
--------------------------------------------------------------------------------
1 | # Addame
2 |
3 | A description of this package.
4 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/APIClient/APIClient.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Combine
3 | import URLRouting
4 | import InfoPlist
5 | import FoundationExtension
6 | import Dependencies
7 | import AppConfiguration
8 | import KeychainClient
9 | import Build
10 | import AddaSharedModels
11 |
12 | public typealias APIClient = URLRoutingClient
13 |
14 | public enum APIClientKey: TestDependencyKey {
15 | public static let testValue = APIClient.failing
16 | }
17 |
18 | extension APIClientKey: DependencyKey {
19 | public static let baseURL = DependencyValues._current.appConfiguration.apiURL
20 | public static let liveValue: APIClient = APIClient.live(
21 | router: siteRouter.baseURL(APIClientKey.baseURL)
22 | )
23 | }
24 |
25 | extension DependencyValues {
26 | public var apiClient: APIClient {
27 | get { self[APIClientKey.self] }
28 | set { self[APIClientKey.self] = newValue }
29 | }
30 | }
31 |
32 | public enum APIError: Error {
33 | case serviceError(statusCode: Int, APIErrorPayload)
34 | case unknown
35 |
36 | init(error: Error) {
37 | if let apiError = error as? APIError {
38 | self = apiError
39 | } else {
40 | self = .unknown
41 | }
42 | }
43 | }
44 |
45 | extension APIError: Equatable {
46 |
47 | }
48 |
49 | public struct APIErrorPayload: Codable, Equatable {
50 | let reason: String?
51 | }
52 |
53 | extension APIClient {
54 |
55 | @available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *)
56 | public func request(
57 | for route: Route,
58 | as type: Value.Type = Value.self,
59 | decoder: JSONDecoder = .init()
60 | ) async throws -> Value {
61 | guard var request = try? siteRouter.baseURL(APIClientKey.baseURL).request(for: route)
62 | else { throw URLError(.badURL) }
63 | request.setHeaders()
64 |
65 | let (data, response) = try await URLSession.shared.data(for: request)
66 |
67 | // #if DEBUG
68 | // #endif
69 |
70 | if let statusCode = (response as? HTTPURLResponse)?.statusCode {
71 | switch statusCode {
72 | case 200 ..< 300:
73 | return try decoder.decode(Value.self, from: data)
74 |
75 | case 400 ..< 500:
76 | let payload = try decoder.decode(APIErrorPayload.self, from: data)
77 | throw APIError.serviceError(statusCode: statusCode, payload)
78 |
79 | default:
80 | throw APIError.unknown
81 | }
82 | } else {
83 | throw APIError.unknown
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/APIClient/URLRequest+Extension.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Dependencies
3 | import UIKit
4 | import AddaSharedModels
5 |
6 | extension URLRequest {
7 |
8 | public mutating func getToken() -> String? {
9 | let identifier = DependencyValues._current.build.identifier()
10 | let token = try? DependencyValues._current
11 | .keychainClient
12 | .readCodable(.token, identifier, RefreshTokenResponse.self)
13 | return token?.accessToken
14 | }
15 |
16 | mutating func setHeaders() {
17 | let token = getToken() ?? ""
18 | guard let infoDictionary = Bundle.main.infoDictionary else { return }
19 |
20 | let bundleName = infoDictionary[kCFBundleNameKey as String] ?? "NotifyWord"
21 | let marketingVersion = infoDictionary["CFBundleShortVersionString"].map { "/\($0)" } ?? ""
22 | let bundleVersion = infoDictionary[kCFBundleVersionKey as String].map { " bundle/\($0)" } ?? ""
23 | let gitSha = (infoDictionary["GitSHA"] as? String).map { $0.isEmpty ? "" : "git/\($0)" } ?? ""
24 | let identifierForVendor = UIDevice.current.identifierForVendor?.uuidString ?? ""
25 | self.setValue(
26 | "\(bundleName)\(marketingVersion)\(bundleVersion)\(gitSha)",
27 | forHTTPHeaderField: "User-Agent"
28 | )
29 | self.setValue("\(identifierForVendor)", forHTTPHeaderField: "IdentifierForVendor")
30 | self.addValue("Bearer " + token, forHTTPHeaderField: "Authorization")
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/APIClient/UserClient.swift:
--------------------------------------------------------------------------------
1 | import AddaSharedModels
2 | import Dependencies
3 |
4 | public struct UserClient {
5 | public typealias UserMeHandler = @Sendable (String) async throws -> UserOutput
6 | public typealias UserUpdateHandler = @Sendable (UserOutput) async throws -> UserOutput
7 | public typealias UserDeleteHandler = @Sendable (String) async throws -> Bool
8 |
9 | public let userMeHandler: UserMeHandler
10 | public let update: UserUpdateHandler
11 | public let delete: UserDeleteHandler
12 |
13 | public init(
14 | userMeHandler: @escaping UserMeHandler,
15 | update: @escaping UserUpdateHandler,
16 | delete: @escaping UserDeleteHandler
17 | ) {
18 | self.userMeHandler = userMeHandler
19 | self.update = update
20 | self.delete = delete
21 | }
22 | }
23 |
24 | extension UserClient {
25 |
26 | public static var live: UserClient =
27 | .init(
28 | userMeHandler: { id in
29 | @Dependency(\.apiClient) var apiClient
30 | return try await apiClient.request(
31 | for: .authEngine(.users(.user(id: id, route: .find))),
32 | as: UserOutput.self,
33 | decoder: .iso8601
34 | )
35 | },
36 | update: { userInput in
37 | @Dependency(\.apiClient) var apiClient
38 | return try await apiClient.request(
39 | for: .authEngine(.users(.update(input: userInput))),
40 | as: UserOutput.self,
41 | decoder: .iso8601
42 | )
43 | },
44 |
45 | delete: { id in
46 | @Dependency(\.apiClient) var apiClient
47 | return try await apiClient.data(
48 | for: .authEngine(.users(.user(id: id, route: .delete)))
49 | ).response.isResponseOK()
50 | }
51 | )
52 | }
53 |
54 | import Foundation
55 | extension URLResponse {
56 | func isResponseOK() -> Bool {
57 | if let httpResponse = self as? HTTPURLResponse {
58 | return (200...299).contains(httpResponse.statusCode)
59 | }
60 | return false
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/AsyncImageLoder/AssetExtractor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AssetExtractor.swift
3 | //
4 | //
5 | // Created by Saroar Khandoker on 26.01.2021.
6 | //
7 |
8 | import Foundation
9 |
10 | #if os(macOS)
11 |
12 | #else
13 | import UIKit
14 | #endif
15 |
16 | public enum AssetExtractor {
17 | public static func createLocalUrl(forImageNamed name: String) -> URL? {
18 | let fileManager = FileManager.default
19 | let cacheDirectory = fileManager.urls(
20 | for: .cachesDirectory, in: .userDomainMask
21 | )[0]
22 |
23 | let url = cacheDirectory.appendingPathComponent("\(name).png")
24 |
25 | guard fileManager.fileExists(atPath: url.path) else {
26 | guard
27 | let image = UIImage(named: name),
28 | let data = image.pngData()
29 | else {
30 | print(#line, self, "cant find image by name: \(name)")
31 | return nil
32 | }
33 |
34 | fileManager.createFile(atPath: url.path, contents: data, attributes: nil)
35 | return url
36 | }
37 |
38 | return url
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/AsyncImageLoder/AsyncImage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AsyncImage.swift
3 | // AddaMeIOS
4 | //
5 | // Created by Saroar Khandoker on 31.08.2020.
6 | //
7 |
8 | import SwiftUI
9 |
10 | public struct AsyncImage: View {
11 | @StateObject private var loader: ImageLoader
12 | private var placeholder: Placeholder
13 | private var image: (UIImage) -> Image
14 |
15 | public init(
16 | url: URL,
17 | @ViewBuilder placeholder: () -> Placeholder,
18 | @ViewBuilder image: @escaping (UIImage) -> Image = Image.init(uiImage:)
19 | ) {
20 | self.placeholder = placeholder()
21 | self.image = image
22 | _loader = StateObject(
23 | wrappedValue: ImageLoader(
24 | url: url,
25 | cache: Environment(\.imageCache).wrappedValue
26 | )
27 | )
28 | }
29 |
30 | public var body: some View {
31 | content
32 | .onAppear(perform: loader.load)
33 | }
34 |
35 | private var content: some View {
36 | Group {
37 | if let loaderImage = loader.image {
38 | image(loaderImage)
39 | } else {
40 | placeholder
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/AsyncImageLoder/AsyncImageLoder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageLoader.swift
3 | // AddaMeIOS
4 | //
5 | // Created by Saroar Khandoker on 30.08.2020.
6 | //
7 |
8 | import Combine
9 | import Foundation
10 | import SwiftUI
11 |
12 | public class ImageLoader: ObservableObject {
13 | @Published var image: UIImage?
14 | private let url: URL
15 | private var cancellable: AnyCancellable?
16 | private var cache: ImageCache?
17 | private(set) var isLodaing = false
18 | private static let imageProcessingQueue = DispatchQueue(label: "image-processing")
19 |
20 | init(url: URL, cache: ImageCache? = nil) {
21 | self.url = url
22 | self.cache = cache
23 | }
24 |
25 | deinit {
26 | cancel()
27 | }
28 |
29 | func load() {
30 | guard !isLodaing else { return }
31 |
32 | if let image = cache?[url] {
33 | self.image = image
34 | return
35 | }
36 |
37 | cancellable = URLSession.shared.dataTaskPublisher(for: url)
38 | .map { UIImage(data: $0.data) }
39 | .replaceError(with: nil)
40 | .handleEvents(
41 | receiveSubscription: { _ in self.onStart() },
42 | receiveOutput: { self.cache($0) },
43 | receiveCompletion: { _ in self.onFinished() },
44 | receiveCancel: { self.onFinished() }
45 | )
46 | .subscribe(on: Self.imageProcessingQueue)
47 | .receive(on: DispatchQueue.main)
48 | .delay(for: 6, scheduler: DispatchQueue.main)
49 | .sink(receiveValue: { [weak self] result in
50 | self?.image = result
51 | })
52 | }
53 |
54 | func cancel() {
55 | cancellable?.cancel()
56 | }
57 |
58 | private func onStart() {
59 | isLodaing = true
60 | }
61 |
62 | private func onFinished() {
63 | isLodaing = false
64 | }
65 |
66 | private func cache(_ image: UIImage?) {
67 | image.map { cache?[url] = $0 }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/AsyncImageLoder/EnvironmentValues.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EnvironmentValues+ImageCache.swift
3 | // AddaMeIOS
4 | //
5 | // Created by Saroar Khandoker on 31.08.2020.
6 | //
7 |
8 | import SwiftUI
9 |
10 | public struct ImageCacheKey: EnvironmentKey {
11 | public static let defaultValue: ImageCache = TemporaryImageCache()
12 | }
13 |
14 | extension EnvironmentValues {
15 | public var imageCache: ImageCache {
16 | get { self[ImageCacheKey.self] }
17 | set { self[ImageCacheKey.self] = newValue }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/AsyncImageLoder/ImageDraw.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageDraw.swift
3 | //
4 | //
5 | // Created by Saroar Khandoker on 28.01.2021.
6 | //
7 |
8 | import Foundation
9 | import UIKit
10 |
11 | public class ImageDraw {
12 | private let renderer = UIGraphicsImageRenderer(size: CGSize(width: 400, height: 400))
13 | private var colors = [
14 | UIColor.red, UIColor.brown, UIColor.yellow, UIColor.green, UIColor.black, UIColor.blue
15 | ]
16 |
17 | public init() {}
18 |
19 | public func buildRandomImage() -> UIImage {
20 | colors.shuffle()
21 |
22 | let image = renderer.image { context in
23 | UIColor.darkGray.setStroke()
24 | context.stroke(renderer.format.bounds)
25 |
26 | let count = 400 / colors.count
27 |
28 | colors.enumerated().forEach { idx, color in
29 | color.setFill()
30 | context.fill(CGRect(x: idx * count, y: 0, width: idx * count, height: 400))
31 | }
32 | }
33 |
34 | return image
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/AsyncImageLoder/ImagePicker.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImagePicker.swift
3 | //
4 | //
5 | // Created by Saroar Khandoker on 26.01.2021.
6 | //
7 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/AttachmentS3Client/AwsS3Manager.swift:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/AttachmentS3Client/Mocks.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | // swiftlint:disable line_length superfluous_disable_command
4 | extension AttachmentS3Client {
5 | public static let empty = Self(
6 | uploadImageToS3: { _, _, _ in "" }
7 | )
8 |
9 | public static let happyPath = Self(
10 | uploadImageToS3: { _, _, _ in "https://adda.nyc3.digitaloceanspaces.com/uploads/images/5fabb05d2470c17919b3c0e2/5fabb05d2470c17919b3c0e2_1605792619988.jpeg"
11 | }
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/AuthenticationView/PhoneNumberKit+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PhoneNumberKit+Extension.swift
3 | //
4 | //
5 | // Created by Saroar Khandoker on 06.10.2021.
6 | //
7 |
8 | import Foundation
9 | import PhoneNumberKit
10 |
11 | // extension PhoneNumberKit {
12 | //
13 | // public override convenience init() {
14 | // self.init(metadataCallback: PhoneNumberKit.bundleMetadataCallback)
15 | // }
16 | //
17 | // public static func bundleMetadataCallback() throws -> Data? {
18 | // guard let jsonPath = Bundle.main.path(forResource: "PhoneNumberMetadata", ofType: "json") else {
19 | // throw PhoneNumberError.metadataNotFound
20 | // }
21 | // let data = try Data(contentsOf: URL(fileURLWithPath: jsonPath))
22 | // return data
23 | // }
24 | //
25 | // }
26 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/AuthenticationView/PhoneNumberTextFieldView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PhoneNumberTextFieldView.swift
3 | //
4 | //
5 | // Created by Saroar Khandoker on 15.09.2021.
6 | //
7 |
8 | import PhoneNumberKit
9 | import SwiftUI
10 |
11 | public struct PhoneNumberTextFieldView: UIViewRepresentable, Equatable {
12 | public static func == (lhs: PhoneNumberTextFieldView, rhs: PhoneNumberTextFieldView) -> Bool {
13 | return lhs.isValid == rhs.isValid && lhs.phoneNumber == rhs.phoneNumber
14 | }
15 |
16 | public func makeCoordinator() -> Coordinator {
17 | Coordinator(self)
18 | }
19 |
20 | @Binding var phoneNumber: String
21 | @Binding var isValid: Bool
22 |
23 | let phoneTextField = PhoneNumberTextField()
24 |
25 | public func makeUIView(context: Context) -> PhoneNumberTextField {
26 | phoneTextField.withExamplePlaceholder = true
27 | phoneTextField.withFlag = true
28 | phoneTextField.withPrefix = true
29 | phoneTextField.withExamplePlaceholder = true
30 | // phoneTextField.placeholder = "Enter phone number"
31 | phoneTextField.becomeFirstResponder()
32 | phoneTextField.addTarget(
33 | context.coordinator, action: #selector(Coordinator.onTextUpdate), for: .editingChanged)
34 | return phoneTextField
35 | }
36 |
37 | public func getCurrentText() {
38 | guard let phoneText = phoneTextField.text else {
39 | return
40 | }
41 | phoneNumber = phoneText
42 | }
43 |
44 | public func updateUIView(_: PhoneNumberTextField, context _: Context) {}
45 |
46 | public class Coordinator: NSObject, UITextFieldDelegate {
47 | var control: PhoneNumberTextFieldView
48 |
49 | init(_ control: PhoneNumberTextFieldView) {
50 | self.control = control
51 | }
52 |
53 | @objc func onTextUpdate(textField _: UITextField) {
54 | control.isValid = control.phoneTextField.isValidNumber
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/ChatClient/ChatClient.swift:
--------------------------------------------------------------------------------
1 | // import Combine
2 | // import Foundation
3 | // import FoundationExtension
4 | // import AddaSharedModels
5 | // import URLRouting
6 | // import InfoPlist
7 | //
8 | // public struct ChatClient {
9 | // // swiftlint:disable superfluous_disable_command
10 | // public static let apiClient: URLRoutingClient = .live(
11 | //
12 | // router: siteRouter.baseRequestData(
13 | // .init(
14 | // scheme: EnvironmentKeys.rootURL.scheme,
15 | // host: EnvironmentKeys.rootURL.host,
16 | // port: EnvironmentKeys.setPort(),
17 | // headers: ["Authorization": [ "Bearer "]]
18 | // )
19 | // )
20 | // )
21 | //
22 | // public typealias MessageListHandler = @Sendable (QueryItem, String) async throws -> MessagePage
23 | //
24 | // public let messages: MessageListHandler
25 | //
26 | // public init(
27 | // messages: @escaping MessageListHandler
28 | // ) {
29 | // self.messages = messages
30 | // }
31 | // }
32 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/ChatClient/Mocks.swift:
--------------------------------------------------------------------------------
1 | ////
2 | //// Mocks.swift
3 | ////
4 | ////
5 | //// Created by Saroar Khandoker on 05.03.2021.
6 | ////
7 | //
8 | // import Combine
9 | // import Foundation
10 | // import FoundationExtension
11 | //
12 | // import AddaSharedModels
13 | // import BSON
14 | //
15 | // extension ChatClient {
16 | // public static let happyPath = Self(
17 | // messages: { _, _ in MessagePage.draff }
18 | // )
19 | // }
20 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/ChatClientLive/Live.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Live.swift
3 | //
4 | //
5 | // Created by Saroar Khandoker on 05.03.2021.
6 | //
7 |
8 | //
9 | // import Combine
10 | // import Foundation
11 | // import InfoPlist
12 | // import AddaSharedModels
13 | // import URLRouting
14 | //
15 | // extension ChatClient {
16 | // public static var live: ChatClient = .init(
17 | // messages: { query, conversationId in
18 | // return try await ChatClient.apiClient.decodedResponse(
19 | // for: .chatEngine(
20 | // .conversations(
21 | // .conversation(id: conversationId, route: .messages(.list(query: query)))
22 | // )
23 | // ),
24 | // as: MessagePage.self,
25 | // decoder: .iso8601
26 | // ).value
27 | // }
28 | // )
29 | //
30 | // }
31 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/ChatView/ChatAction.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChatAction.swift
3 | //
4 | //
5 | // Created by Saroar Khandoker on 06.04.2021.
6 | //
7 |
8 | import Foundation
9 |
10 | import AddaSharedModels
11 |
12 |
13 |
14 | extension Chat.Action {
15 | // swiftlint:disable cyclomatic_complexity
16 | public static func view(_ localAction: ChatView.ViewAction) -> Self {
17 | switch localAction {
18 | case .onAppear:
19 | return .onAppear
20 | case .alertDismissed:
21 | return .alertDismissed
22 | case let .fetchMoreMessageIfNeeded(currentItem: currentItem):
23 | return .fetchMoreMessageIfNeeded(currentItem: currentItem)
24 | case let .fetchMoreMessage(currentItem: item):
25 | return .fetchMoreMessage(currentItem: item)
26 | case let .message(index, action):
27 | return .message(index: index, action: action)
28 | case .messagesResponse(let response):
29 | return .messagesResponse(response)
30 | case .webSocketReducer(let wsra):
31 | return .webSocketReducer(wsra)
32 | case .chatButtom(let cb):
33 | return .chatButtom(cb)
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/ChatView/ChatEnvironment.swift:
--------------------------------------------------------------------------------
1 | ////
2 | //// ChatEnvironment.swift
3 | ////
4 | ////
5 | //// Created by Saroar Khandoker on 19.04.2021.
6 | ////
7 | //import Combine
8 | //import ComposableArchitecture
9 | //
10 | //import KeychainClient
11 | //import AddaSharedModels
12 |
13 | //import Foundation
14 | //
15 | //public struct ChatEnvironment {
16 | // public let websocketClient: WebSocketClient
17 | // public var mainQueue: AnySchedulerOf
18 | // public var backgroundQueue: AnySchedulerOf
19 | //
20 | // public init(
21 | // websocketClient: WebSocketClient,
22 | // mainQueue: AnySchedulerOf,
23 | // backgroundQueue: AnySchedulerOf
24 | // ) {
25 | // self.websocketClient = websocketClient
26 | // self.mainQueue = mainQueue
27 | // self.backgroundQueue = backgroundQueue
28 | // }
29 | //
30 | // public var currentUser: UserOutput {
31 | // return UserOutput.withFirstName
32 | // }
33 | //}
34 | //
35 | //extension ChatEnvironment {
36 | // public static let live: ChatEnvironment = .init(
37 | // websocketClient: .live,
38 | // mainQueue: .main,
39 | // backgroundQueue: .main
40 | // )
41 | //}
42 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/ChatView/ChatListView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChatListView.swift
3 | //
4 | //
5 | // Created by Saroar Khandoker on 17.06.2021.
6 | //
7 |
8 | import ComposableArchitecture
9 | import AddaSharedModels
10 | import SwiftUI
11 |
12 | struct ChatListView: View {
13 | let store: StoreOf
14 |
15 | var body: some View {
16 | WithViewStore(self.store, observe: { $0 }) { viewStore in
17 | ForEachStore(
18 | self.store.scope(
19 | state: \.messages,
20 | action: Chat.Action.message(index:action:)
21 | )
22 | ) { chatStore in
23 | WithViewStore(chatStore, observe: { $0 }) { messageViewStore in
24 | ChatRowView(store: chatStore)
25 | .onAppear {
26 | viewStore.send(.fetchMoreMessageIfNeeded(currentItem: messageViewStore.state))
27 | }
28 | .scaleEffect(x: 1, y: -1, anchor: .center)
29 | // .listRowSeparatorHiddenIfAvaibale()
30 | }
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/ChatView/ChatState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChatState.swift
3 | //
4 | //
5 | // Created by Saroar Khandoker on 06.04.2021.
6 | //
7 |
8 | import ComposableArchitecture
9 | import AddaSharedModels
10 | import WebSocketReducer
11 |
12 | extension Chat.State {
13 | public static let placeholderMessages = Self(
14 | isLoadingPage: true,
15 | conversation: .lookingForAcompanyDraff,
16 | messages: .init(uniqueElements: MessagePage.draff.items),
17 | currentUser: .withFirstName,
18 | websocketState: .init(user: .withFirstName)
19 | )
20 |
21 | // (
22 | // currentUser
23 | // isLoadingPage: true,
24 | // messages: .init(uniqueElements: MessagePage.draff.items)
25 | // )
26 | }
27 |
--------------------------------------------------------------------------------
/AddameSPM/Sources/CombineHelpers/Combine.swift:
--------------------------------------------------------------------------------
1 | import Combine
2 |
3 | extension Publisher where Output == Never {
4 | public func setOutputType(to _: NewOutput.Type) -> AnyPublisher {
5 | func absurd(_: Never) -> A {}
6 | return map(absurd).eraseToAnyPublisher()
7 | }
8 | }
9 |
10 | extension Publisher {
11 | public func ignoreOutput(
12 | setOutputType _: NewOutput.Type
13 | ) -> AnyPublisher {
14 | return
15 | ignoreOutput()
16 | .setOutputType(to: NewOutput.self)
17 | }
18 |
19 | public func ignoreFailure(
20 | setFailureType _: NewFailure.Type
21 | ) -> AnyPublisher