diff --git a/packages/stream_chat/example/ios/Flutter/Debug.xcconfig b/packages/stream_chat/example/ios/Flutter/Debug.xcconfig index e8efba11..592ceee8 100644 --- a/packages/stream_chat/example/ios/Flutter/Debug.xcconfig +++ b/packages/stream_chat/example/ios/Flutter/Debug.xcconfig @@ -1,2 +1 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/packages/stream_chat/example/ios/Flutter/Release.xcconfig b/packages/stream_chat/example/ios/Flutter/Release.xcconfig index 399e9340..592ceee8 100644 --- a/packages/stream_chat/example/ios/Flutter/Release.xcconfig +++ b/packages/stream_chat/example/ios/Flutter/Release.xcconfig @@ -1,2 +1 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/packages/stream_chat/example/ios/Runner.xcodeproj/project.pbxproj b/packages/stream_chat/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..1aec2aa0 --- /dev/null +++ b/packages/stream_chat/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,495 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/packages/stream_chat/example/lib/main.dart b/packages/stream_chat/example/lib/main.dart index 1261d3fe..2d0a529f 100644 --- a/packages/stream_chat/example/lib/main.dart +++ b/packages/stream_chat/example/lib/main.dart @@ -4,7 +4,10 @@ import 'package:stream_chat/stream_chat.dart'; Future main() async { /// Create a new instance of [StreamChatClient] passing the apikey obtained from your /// project dashboard. - final client = StreamChatClient('b67pax5b2wdq'); + final client = StreamChatClient( + 'b67pax5b2wdq', + logLevel: Level.INFO, + ); /// Set the current user. In a production scenario, this should be done using /// a backend to generate a user token using our server SDK. diff --git a/packages/stream_chat/lib/src/client.dart b/packages/stream_chat/lib/src/client.dart index 8b8d7c11..a1302539 100644 --- a/packages/stream_chat/lib/src/client.dart +++ b/packages/stream_chat/lib/src/client.dart @@ -10,6 +10,7 @@ import 'package:stream_chat/src/api/retry_policy.dart'; import 'package:stream_chat/src/event_type.dart'; import 'package:stream_chat/src/models/attachment_file.dart'; import 'package:stream_chat/src/models/own_user.dart'; +import 'package:stream_chat/src/platform_detector/platform_detector.dart'; import 'package:stream_chat/version.dart'; import 'package:uuid/uuid.dart'; @@ -888,9 +889,8 @@ class StreamChatClient { String get _authType => _anonymous ? 'anonymous' : 'jwt'; - // TODO: get the right version of the lib from the build toolchain String get _userAgent => - 'stream-chat-dart-client-${PACKAGE_VERSION.split('+')[0]}'; + 'stream-chat-dart-client-${CurrentPlatform.name}-${PACKAGE_VERSION.split('+')[0]}'; Map get _commonQueryParams => { 'user_id': state.user?.id, diff --git a/packages/stream_chat/lib/src/models/attachment.dart b/packages/stream_chat/lib/src/models/attachment.dart index cc55aa71..e2e81cd9 100644 --- a/packages/stream_chat/lib/src/models/attachment.dart +++ b/packages/stream_chat/lib/src/models/attachment.dart @@ -58,7 +58,7 @@ class Attachment { final AttachmentFile file; /// The current upload state of the attachment - final UploadState uploadState; + UploadState uploadState; /// Map of custom channel extraData @JsonKey(includeIfNull: false) @@ -123,10 +123,15 @@ class Attachment { this.actions, this.extraData, this.file, - this.uploadState, + UploadState uploadState, }) : id = id ?? Uuid().v4(), title = title ?? file?.name, - localUri = file?.path != null ? Uri.parse(file.path) : null; + localUri = file?.path != null ? Uri.parse(file.path) : null { + this.uploadState = uploadState ?? + ((assetUrl != null || imageUrl != null) + ? UploadState.success() + : UploadState.preparing()); + } /// Create a new instance from a json factory Attachment.fromJson(Map json) { diff --git a/packages/stream_chat/lib/src/platform_detector/platform_detector.dart b/packages/stream_chat/lib/src/platform_detector/platform_detector.dart new file mode 100644 index 00000000..8f601501 --- /dev/null +++ b/packages/stream_chat/lib/src/platform_detector/platform_detector.dart @@ -0,0 +1,47 @@ +import 'platform_detector_stub.dart' + if (dart.library.html) 'platform_detector_web.dart' + if (dart.library.io) 'platform_detector_io.dart'; + +enum PlatformType { + Android, + Ios, + Web, + MacOS, + Windows, + Linux, + Fuchsia, +} + +class CurrentPlatform { + CurrentPlatform._(); + static bool get isAndroid => type == PlatformType.Android; + static bool get isIos => type == PlatformType.Ios; + static bool get isWeb => type == PlatformType.Web; + static bool get isMacOS => type == PlatformType.MacOS; + static bool get isWindows => type == PlatformType.Windows; + static bool get isLinux => type == PlatformType.Linux; + static bool get isFuchsia => type == PlatformType.Fuchsia; + + static String get name { + switch (type) { + case PlatformType.Android: + return 'android'; + case PlatformType.Ios: + return 'ios'; + case PlatformType.Web: + return 'web'; + case PlatformType.MacOS: + return 'macos'; + case PlatformType.Windows: + return 'windows'; + case PlatformType.Linux: + return 'linux'; + case PlatformType.Fuchsia: + return 'fuchsia'; + default: + return ''; + } + } + + static PlatformType get type => currentPlatform; +} diff --git a/packages/stream_chat/lib/src/platform_detector/platform_detector_io.dart b/packages/stream_chat/lib/src/platform_detector/platform_detector_io.dart new file mode 100644 index 00000000..6cca45b6 --- /dev/null +++ b/packages/stream_chat/lib/src/platform_detector/platform_detector_io.dart @@ -0,0 +1,11 @@ +import 'dart:io'; +import 'platform_detector.dart'; + +PlatformType get currentPlatform { + if (Platform.isWindows) return PlatformType.Windows; + if (Platform.isFuchsia) return PlatformType.Fuchsia; + if (Platform.isMacOS) return PlatformType.MacOS; + if (Platform.isLinux) return PlatformType.Linux; + if (Platform.isIOS) return PlatformType.Ios; + return PlatformType.Android; +} diff --git a/packages/stream_chat/lib/src/platform_detector/platform_detector_stub.dart b/packages/stream_chat/lib/src/platform_detector/platform_detector_stub.dart new file mode 100644 index 00000000..4469fc46 --- /dev/null +++ b/packages/stream_chat/lib/src/platform_detector/platform_detector_stub.dart @@ -0,0 +1,5 @@ +import 'platform_detector.dart'; + +PlatformType get currentPlatform { + throw UnimplementedError(); +} diff --git a/packages/stream_chat/lib/src/platform_detector/platform_detector_web.dart b/packages/stream_chat/lib/src/platform_detector/platform_detector_web.dart new file mode 100644 index 00000000..b1613afb --- /dev/null +++ b/packages/stream_chat/lib/src/platform_detector/platform_detector_web.dart @@ -0,0 +1,3 @@ +import 'platform_detector.dart'; + +PlatformType get currentPlatform => PlatformType.Web; diff --git a/packages/stream_chat_flutter/lib/src/attachment/attachment_upload_state_builder.dart b/packages/stream_chat_flutter/lib/src/attachment/attachment_upload_state_builder.dart index fb65fd12..2425b966 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/attachment_upload_state_builder.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/attachment_upload_state_builder.dart @@ -27,7 +27,9 @@ class AttachmentUploadStateBuilder extends StatelessWidget { @override Widget build(BuildContext context) { - if (attachment.uploadState == null) return Offstage(); + if (message.status == null || message.status == MessageSendingStatus.sent) { + return Offstage(); + } final messageId = message.id; final attachmentId = attachment.id; diff --git a/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart index ee6b10c8..f7fbc277 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/file_attachment.dart @@ -227,6 +227,20 @@ class FileAttachment extends AttachmentWidget { }, ); + if (message != null && + (message.status == null || + message.status == MessageSendingStatus.sent)) { + trailingWidget = IconButton( + icon: StreamSvgIcon.cloudDownload(color: theme.colorTheme.black), + padding: const EdgeInsets.all(8), + visualDensity: VisualDensity.compact, + splashRadius: 16, + onPressed: () { + launchURL(context, attachment.assetUrl); + }, + ); + } + return Material( type: MaterialType.transparency, child: trailingWidget, @@ -241,6 +255,9 @@ class FileAttachment extends AttachmentWidget { ); return attachment.uploadState?.when( preparing: () { + if (message == null) { + return Text('${fileSize(size, 2)}', style: textStyle); + } return UploadProgressIndicator( uploaded: 0, total: double.maxFinite.toInt(), diff --git a/packages/stream_chat_flutter/lib/src/image_actions_modal.dart b/packages/stream_chat_flutter/lib/src/image_actions_modal.dart index 3c4a7c73..1304b90d 100644 --- a/packages/stream_chat_flutter/lib/src/image_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/image_actions_modal.dart @@ -103,11 +103,22 @@ class ImageActionsModal extends StatelessWidget { color: StreamChatTheme.of(context).colorTheme.accentRed, ), () { - Navigator.pop(context); - Navigator.pop(context); - StreamChannel.of(context) - .channel - .deleteMessage(message); + final channel = StreamChannel.of(context).channel; + if (message.attachments.length > 1 || + message.text.isNotEmpty) { + final remainingAttachments = [...message.attachments] + ..removeAt(currentIndex); + channel.updateMessage(message.copyWith( + attachments: remainingAttachments, + )); + Navigator.pop(context); + Navigator.pop(context); + } else { + channel.deleteMessage(message).then((value) { + Navigator.pop(context); + Navigator.pop(context); + }); + } }, color: StreamChatTheme.of(context).colorTheme.accentRed, ), diff --git a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart index af05d74c..d914afba 100644 --- a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart @@ -596,7 +596,8 @@ class _MessageActionsModalState extends State { elevation: 2, clipBehavior: Clip.hardEdge, isScrollControlled: true, - backgroundColor: StreamChatTheme.of(context).channelTheme.inputBackground, + backgroundColor: + StreamChatTheme.of(context).messageInputTheme.inputBackground, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(16), diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 26feba69..ec6b9574 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -235,7 +235,7 @@ class MessageInputState extends State { @override Widget build(BuildContext context) { Widget child = Container( - color: StreamChatTheme.of(context).channelTheme.inputBackground, + color: StreamChatTheme.of(context).messageInputTheme.inputBackground, child: SafeArea( child: GestureDetector( onPanUpdate: (details) { @@ -392,7 +392,8 @@ class MessageInputState extends State { : CrossFadeState.showSecond, firstChild: _buildSendButton(context), secondChild: _buildIdleSendButton(context), - duration: Duration(milliseconds: 300), + duration: + StreamChatTheme.of(context).messageInputTheme.sendAnimationDuration, alignment: Alignment.center, ), ); @@ -417,19 +418,21 @@ class MessageInputState extends State { ), splashRadius: 24, ), - secondChild: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - if (!widget.disableAttachments) _buildAttachmentButton(), - if (widget.editMessage == null && - StreamChannel.of(context) - .channel - ?.config - ?.commands - ?.isNotEmpty == - true) - _buildCommandButton(), - ].insertBetween(const SizedBox(width: 8)), + secondChild: FittedBox( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + if (!widget.disableAttachments) _buildAttachmentButton(), + if (widget.editMessage == null && + StreamChannel.of(context) + .channel + ?.config + ?.commands + ?.isNotEmpty == + true) + _buildCommandButton(), + ].insertBetween(const SizedBox(width: 8)), + ), ), duration: Duration(milliseconds: 300), alignment: Alignment.center, @@ -1683,8 +1686,10 @@ class MessageInputState extends State { return IconButton( icon: StreamSvgIcon.lightning( color: _commandsOverlay != null - ? StreamChatTheme.of(context).channelTheme.actionButtonColor - : StreamChatTheme.of(context).channelTheme.actionButtonIdleColor, + ? StreamChatTheme.of(context).messageInputTheme.actionButtonColor + : StreamChatTheme.of(context) + .messageInputTheme + .actionButtonIdleColor, ), padding: const EdgeInsets.all(0), constraints: BoxConstraints.tightFor( @@ -1721,8 +1726,10 @@ class MessageInputState extends State { return IconButton( icon: StreamSvgIcon.attach( color: _openFilePickerSection - ? StreamChatTheme.of(context).channelTheme.actionButtonColor - : StreamChatTheme.of(context).channelTheme.actionButtonIdleColor, + ? StreamChatTheme.of(context).messageInputTheme.actionButtonColor + : StreamChatTheme.of(context) + .messageInputTheme + .actionButtonIdleColor, ), padding: const EdgeInsets.all(0), constraints: BoxConstraints.tightFor( @@ -1961,7 +1968,7 @@ class MessageInputState extends State { Widget _buildIdleSendButton(BuildContext context) { return StreamSvgIcon( assetName: _getIdleSendIcon(), - color: StreamChatTheme.of(context).channelTheme.sendButtonIdleColor, + color: StreamChatTheme.of(context).messageInputTheme.sendButtonIdleColor, ); } @@ -1976,7 +1983,7 @@ class MessageInputState extends State { ), icon: StreamSvgIcon( assetName: _getSendIcon(), - color: StreamChatTheme.of(context).channelTheme.sendButtonColor, + color: StreamChatTheme.of(context).messageInputTheme.sendButtonColor, ), ); } @@ -2008,6 +2015,7 @@ class MessageInputState extends State { if (_commandEnabled) { text = '/${_chosenCommand.name} ' + text; + FocusScope.of(context).unfocus(); } final attachments = [..._attachments.values]; diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 1c5c8061..505c4e0f 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -130,6 +130,7 @@ class MessageListView extends StatefulWidget { this.emptyBuilder, this.messageListBuilder, this.errorWidgetBuilder, + this.customAttachmentBuilders, }) : super(key: key); /// Function used to build a custom message widget @@ -203,6 +204,10 @@ class MessageListView extends StatefulWidget { /// of a connection failure. final ErrorBuilder errorWidgetBuilder; + /// Attachment builders for the default message widget + /// Please change this in the [MessageWidget] if you are using a custom implementation + final Map customAttachmentBuilders; + @override _MessageListViewState createState() => _MessageListViewState(); } @@ -798,6 +803,7 @@ class _MessageListViewState extends State { break; } }, + customAttachmentBuilders: widget.customAttachmentBuilders, ); } @@ -958,6 +964,7 @@ class _MessageListViewState extends State { break; } }, + customAttachmentBuilders: widget.customAttachmentBuilders, ); if (!message.isDeleted && diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index c2f3ee7e..338e2603 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -60,6 +60,9 @@ class StreamChatThemeData { /// Theme of other users messages final MessageTheme otherMessageTheme; + /// Theme of other users messages + final MessageInputTheme messageInputTheme; + /// The widget that will be built when the channel image is unavailable final Widget Function(BuildContext, Channel) defaultChannelImage; @@ -80,6 +83,7 @@ class StreamChatThemeData { this.channelTheme, this.otherMessageTheme, this.ownMessageTheme, + this.messageInputTheme, this.defaultChannelImage, this.defaultUserImage, this.primaryIconTheme, @@ -108,6 +112,7 @@ class StreamChatThemeData { ChannelTheme channelTheme, MessageTheme ownMessageTheme, MessageTheme otherMessageTheme, + MessageInputTheme messageInputTheme, Widget Function(BuildContext, Channel) defaultChannelImage, Widget Function(BuildContext, User) defaultUserImage, IconThemeData primaryIconTheme, @@ -123,6 +128,7 @@ class StreamChatThemeData { channelTheme: channelTheme ?? this.channelTheme, ownMessageTheme: ownMessageTheme ?? this.ownMessageTheme, otherMessageTheme: otherMessageTheme ?? this.otherMessageTheme, + messageInputTheme: messageInputTheme ?? this.messageInputTheme, reactionIcons: reactionIcons ?? this.reactionIcons, ); @@ -143,6 +149,8 @@ class StreamChatThemeData { other.ownMessageTheme, otherMessageTheme: otherMessageTheme?.merge(other.otherMessageTheme) ?? other.otherMessageTheme, + messageInputTheme: messageInputTheme?.merge(other.messageInputTheme) ?? + other.messageInputTheme, reactionIcons: other.reactionIcons, ); } @@ -182,10 +190,6 @@ class StreamChatThemeData { ), indicatorIconSize: 16.0), channelTheme: ChannelTheme( - actionButtonColor: colorTheme.accentBlue, - actionButtonIdleColor: colorTheme.grey, - sendButtonColor: colorTheme.accentBlue, - sendButtonIdleColor: colorTheme.greyGainsboro, channelHeaderTheme: ChannelHeaderTheme( avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), @@ -195,16 +199,12 @@ class StreamChatThemeData { ), ), color: colorTheme.white, - title: TextStyle( - fontSize: 14, - color: colorTheme.black, - ), + title: textTheme.headlineBold, lastMessageAt: TextStyle( fontSize: 11, color: colorTheme.black.withOpacity(.5), ), ), - inputBackground: colorTheme.white.withAlpha(12), ), ownMessageTheme: MessageTheme( messageAuthor: textTheme.footnote.copyWith(color: colorTheme.grey), @@ -248,6 +248,14 @@ class StreamChatThemeData { ), ), ), + messageInputTheme: MessageInputTheme( + sendAnimationDuration: Duration(milliseconds: 300), + actionButtonColor: colorTheme.accentBlue, + actionButtonIdleColor: colorTheme.grey, + sendButtonColor: colorTheme.accentBlue, + sendButtonIdleColor: colorTheme.greyGainsboro, + inputBackground: colorTheme.white, + ), reactionIcons: [ ReactionIcon( type: 'love', @@ -628,47 +636,16 @@ class ChannelTheme { /// Theme of the [ChannelHeader] widget final ChannelHeaderTheme channelHeaderTheme; - /// Background color of [MessageInput] send button - final Color sendButtonColor; - - /// Background color of [MessageInput] action buttons - final Color actionButtonColor; - - /// Background color of [MessageInput] send button - final Color sendButtonIdleColor; - - /// Background color of [MessageInput] action buttons - final Color actionButtonIdleColor; - - /// Background color of [MessageInput] - final Color inputBackground; - ChannelTheme({ this.channelHeaderTheme, - this.actionButtonColor, - this.sendButtonColor, - this.actionButtonIdleColor, - this.sendButtonIdleColor, - this.inputBackground, }); /// Creates a copy of [ChannelTheme] with specified attributes overridden. ChannelTheme copyWith({ ChannelHeaderTheme channelHeaderTheme, - Color inputBackground, - Color actionButtonColor, - Color sendButtonColor, - Color actionButtonIdleColor, - Color sendButtonIdleColor, }) => ChannelTheme( channelHeaderTheme: channelHeaderTheme ?? this.channelHeaderTheme, - inputBackground: inputBackground ?? this.inputBackground, - actionButtonColor: actionButtonColor ?? this.actionButtonColor, - sendButtonColor: sendButtonColor ?? this.sendButtonColor, - actionButtonIdleColor: - actionButtonIdleColor ?? this.actionButtonIdleColor, - sendButtonIdleColor: sendButtonIdleColor ?? this.sendButtonIdleColor, ); ChannelTheme merge(ChannelTheme other) { @@ -676,11 +653,6 @@ class ChannelTheme { return copyWith( channelHeaderTheme: channelHeaderTheme?.merge(other.channelHeaderTheme) ?? other.channelHeaderTheme, - inputBackground: other.inputBackground, - actionButtonColor: other.actionButtonColor, - actionButtonIdleColor: other.actionButtonIdleColor, - sendButtonColor: other.sendButtonColor, - sendButtonIdleColor: other.sendButtonIdleColor, ); } } @@ -873,6 +845,65 @@ class ChannelHeaderTheme { } } +class MessageInputTheme { + final Duration sendAnimationDuration; + + /// Background color of [MessageInput] send button + final Color sendButtonColor; + + /// Background color of [MessageInput] action buttons + final Color actionButtonColor; + + /// Background color of [MessageInput] send button + final Color sendButtonIdleColor; + + /// Background color of [MessageInput] action buttons + final Color actionButtonIdleColor; + + /// Background color of [MessageInput] + final Color inputBackground; + + const MessageInputTheme({ + this.sendAnimationDuration, + this.actionButtonColor, + this.sendButtonColor, + this.actionButtonIdleColor, + this.sendButtonIdleColor, + this.inputBackground, + }); + + MessageInputTheme copyWith({ + Duration sendAnimationDuration, + Color inputBackground, + Color actionButtonColor, + Color sendButtonColor, + Color actionButtonIdleColor, + Color sendButtonIdleColor, + }) => + MessageInputTheme( + sendAnimationDuration: + sendAnimationDuration ?? this.sendAnimationDuration, + inputBackground: inputBackground ?? this.inputBackground, + actionButtonColor: actionButtonColor ?? this.actionButtonColor, + sendButtonColor: sendButtonColor ?? this.sendButtonColor, + actionButtonIdleColor: + actionButtonIdleColor ?? this.actionButtonIdleColor, + sendButtonIdleColor: sendButtonIdleColor ?? this.sendButtonIdleColor, + ); + + MessageInputTheme merge(MessageInputTheme other) { + if (other == null) return this; + return copyWith( + sendAnimationDuration: other.sendAnimationDuration, + inputBackground: other.inputBackground, + actionButtonColor: other.actionButtonColor, + actionButtonIdleColor: other.actionButtonIdleColor, + sendButtonColor: other.sendButtonColor, + sendButtonIdleColor: other.sendButtonIdleColor, + ); + } +} + class Effect { final double sigmaX; final double sigmaY;