Giter Club home page Giter Club logo

swiftychat's Introduction

Swift 5.8

SwiftyChat

For Flutter version check this link

Content

About

Simple Chat Interface to quick start with built-in message cells.

Features

  • Attributed string support that came with SwiftUI
  • Landscape orientation support (autoscales message cells with the given cellWidth property, if exists)
  • User Avatar (with different position options, optional usage)
  • Dismiss keyboard (on tapping outside).
  • Multiline Input Bar added (investigate BasicInputView)
  • Scroll to bottom.
  • "Picture in Picture" background mode video playing (to enable, visit >> Xcode "Sign in and Capabilities")
  • Round specific corner of text messages.
  • Implement custom message cells. See CustomMessage.md for details.
  • Swipe to dismiss keyboard.

Quick Preview

Basic Example Preview
Text (Light) Text (Dark)
Advanced Example Preview
Contact, QuickReply, Text, Carousel Map, Image ContextMenu

Installation

SPM: https://github.com/EnesKaraosman/SwiftyChat.git

Message Kinds

public enum ChatMessageKind {
    
    /// A text message,
    /// supports emoji 👍🏻 (auto scales if text is all about emojis)
    case text(String)
    
    /// An image message, from local(UIImage) or remote(URL).
    case image(ImageLoadingKind)
    
    /// A location message, pins given location & presents on MapKit.
    case location(LocationItem)
    
    /// A contact message, generally for sharing purpose.
    case contact(ContactItem)
    
    /// Multiple options, disables itself after selection.
    case quickReply([QuickReplyItem])
    
    /// `CarouselItem`s that contains title, subtitle, image & button in a scrollable view
    case carousel([CarouselItem])
    
    /// A video message, opens the given URL.
    case video(VideoItem)
}

Usage

  • ChatView

Here below is minimum code required to get started (see up & running)
For detail, visit example project here

import SwiftyChat
import SwiftyChatMock

@State private var scrollToBottom = false
@State private var messages: [MockMessages.ChatMessageItem] = [] // for quick test assign MockMessages.generatedMessages()

// ChatMessageItem & ChatUserItem is a sample objects/structs 
// that conforms `ChatMessage` & `ChatUser` protocols.
ChatView<MockMessages.ChatMessageItem, MockMessages.ChatUserItem>(
    messages: $messages,
    scrollToBottom: $scrollToBottom
) {
    // InputView here, continue reading..
}
// ▼ Required
.environmentObject(
    // All parameters initialized by default, 
    // change as you want.
    ChatMessageCellStyle()
)
.onReceive(
    messages.debounce(for: .milliseconds(650), scheduler: RunLoop.main),
    perform: { _ in
        scrollToBottom = true
    }
)
// ...
  • InputView

You can investigate existing BasicInputView in project.
You can use it if it suits your need, or create a new one.
Recommended way is just clone this BasicInputView and modify (ex. add camera icon etc.)

// InputBarView variables
@State private var message = ""

var inputBarView: some View {
    BasicInputView(
        message: $message, // Typed text.
        placeholder: "Type something",
        onCommit: { messageKind in
            self.messages.append(
                .init(user: MockMessages.sender, messageKind: messageKind, isSender: true)
            )
        }
    )
    .background(Color.primary.colorInvert())
    // ▼ An extension that wraps view inside AnyView
    .embedInAnyView()
}

// Pass in ChatView
ChatView(messages: $messages) {
    inputBarView 
}
...
...

Style and Customization

public class ChatMessageCellStyle: ObservableObject {
    
    let incomingTextStyle: TextCellStyle
    let outgoingTextStyle: TextCellStyle
    
    let incomingCellEdgeInsets: EdgeInsets
    let outgoingCellEdgeInsets: EdgeInsets
    
    let contactCellStyle: ContactCellStyle
    
    let imageCellStyle: ImageCellStyle
    
    let quickReplyCellStyle: QuickReplyCellStyle
    
    let carouselCellStyle: CarouselCellStyle
    
    let locationCellStyle: LocationCellStyle
    
    let incomingAvatarStyle: AvatarStyle
    let outgoingAvatarStyle: AvatarStyle
    
}

You must initiate this class to build a proper style & inject it as environmentObject,
All styles has default initializer;

For detail documentation, visit Styles.md

You can also use your own custom message cell, see CustomMessage.md for details.


Please feel free to contribute.
  • Create PR for a feature/bug you'd like to add/fix.

Inspiration

swiftychat's People

Contributors

andrew-chen-wang avatar blakebc avatar bporter95 avatar eneskaraosman avatar gabrielpeart avatar lemonandlime avatar leonardmaetzner avatar nikitapokatovich avatar renovate[bot] avatar sheikhbayazid avatar wilderlopez avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swiftychat's Issues

Scroll To Bottom

Scroll to bottom doesn't scroll completely to the bottom. The last message is still hidden. Is it because the InputView is a part of ChatView? Is there any work around?

image

How to load historical chat records in pages

Hello, how can I avoid the scrolling of ScrollView when loading chat records in pages? When I send a message, I use messages.append(message), and when the user looks up the chat history, using messages.insert(contentsOf: preMessages, at: 0) causes the ScrollView to scroll down.
Thanks.

BasicInputView on tabbar

hi. When I use tabview, BasicInputView is under the tabbar. How can I show BasicInputView on tabbar?

Ekran Resmi 2020-12-17 00 37 34

Scroll down when receiving messages

Hello! First of all, your code is helping me alot on one of my projects tyvm!

I have implemeted a chat that send a message to server and a bot answers. But when I receive the answer the chat don't scroll down:

I'm doing it like this=>

        .onReceive(chatViewModel.$messages, perform: { messages in
            self.messages = messages
        })

Is there a way to refresh the view?

Tyvm!!

When using alignToMessageTop, if the avatar and cell are the same height, it will not align.

截屏2023-02-14 23 14 15

Suggest changing the code in AvatarModifier to...

public func body(content: Content) -> some View {
HStack(alignment: avatarAlignment, spacing: avatarSpacing) {
if !isSender { avatar.zIndex(2) }
content
if isSender { avatar.zIndex(2) }
}
}

private var avatarAlignment: VerticalAlignment {
switch currentAvatarPosition {
case .alignToMessageTop: return .top
case .alignToMessageCenter: return .center
case .alignToMessageBottom: return .bottom
}
}

Chat view doesn't scroll on keyboard open / input

There's a listener for keyboardWillShowNotification, but chat view doesn't scroll to bottom, because isKeyboardActive is true.

Screenshot 2022-04-13 at 12 56 04

Also, I couldn't find if there's functionality to scroll to bottom on message sent (nice to have, i.e. if you scrolled up while typing).

scrollToBottom

hi all
when I send a new message the scroll view does not scroll to the new message at the bottom
please advise
regards

How to show Avatar on some messages

Hello mate!

I'm trying to display the avatar on my messages but I can't found the method to do it. I've just added the avatar url on my message user but it's not working.

Do I have to do something special?

Tyvm!

UI shaking when popped with keyboard was shown

Enter BasicExampleView than tap TextView, wait til keyboard shows up, than tap navigation back, observe the UI closely, you will find the whole view including navigation bar was shaking slightly while popping.
I have found the cause was the code below, but didn't find a solution yet.
Binding<NSAttributedString>( get: { NSAttributedString( string: self.message, attributes: [ NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .body), NSAttributedString.Key.foregroundColor: UIColor.label, ] ) }, set: { self.message = $0.string } )

Kingfisher archive issues

Kingfisher issues when attempting build/archive for arm64 device

Cannot find type 'Binding' in scope
Cannot find type 'Image' in scope
Cannot find type 'View' in scope

Xcode 13.0, building for iOS 13.
Runs OK on the simulator.
Reproducible with SwiftyChatExample project.

Is this a config issue?

Thanks
Martin

How do you extend Message Kinds?

Hello. Since ChatMessageKind is a enum, and does not contain any .custom option either, how do you suppose to add new messages kinds?

quick reply

hi,
what if I want not to disable the selected choice after quick reply ?
regards

Mac OS X Version fix

Kindly update the package definition of SwiftUIExtension to support MacOS X.
platforms: [
.iOS(.v13),
.macOS(.v11)
],
should be like in SwiftyChat
platforms: [
.iOS(.v14),
.macOS(.v10_15)
],
Thanks

kingfisher not updated

The old version of the kingfisher is used, Xcode 13 is not archiving because of that.

Protocols for ChatMessage, ChatUser

Have you considered using protocols for ChatMessage and ChatUser instead of structs?

A lot of the time, we already have our own domain objects/structs to represent a message or user and it would be nice if we could just extend those objects to conform to a protocol rather than having to convert to a new object. Additionally, the ChatMessage and ChatUser structs both initialize their own UUID which can't be changed, however we have our own IDs from our backend to identify a user/message that we want to use.

Protocols is how MessageKit does it and since the README says you took inspiration from MessageKit, this might have been an intentional decision that you made to not go the protocol route but anyways, cool library and thought I would suggest something!

Custom Cell shape

Hi Enes,

First tnx for the great library.
How can I change cell shape?
I need the cell to look like in Viber where only one of the corners isn't rounded.
Since CommonViewStyle protocol has only cornerRadius as CGFloat, I don't see a way to change the shape of the cell.

Testing performance using Instruments

I suggest that you inspect the library using Instruments, there are several issues with the performance of the cpu. I have solved one in particular, I hope you understand the importance of this work. Here is the solution that I propose:

SwiftyChat > Styles > ChatMessageCellStyle.swift

import SwiftUI
import Combine

public class ChatMessageCellStyle: ObservableObject {

   
    public let objectWillChange = ObservableObjectPublisher()
   
    ...
    
    public init(...) {
        ...
        
        objectWillChange.send()
    }

}

The error before being solved, tracked with instruments

Captura de Pantalla 2020-12-16 a la(s) 10 00 20 a  m

attributed text

how can I write one message with different colors ? I have tried to form it as HTML but no luck
please advise
regards

scrollToBottom using onRecieve

when I added this part

.onReceive(
messages.debounce(for: .milliseconds(650), scheduler: RunLoop.main),
perform: { _ in
scrollToBottom = true
}
)

I got a lot of errors
Cannot call value of non-function type 'Binding'
Cannot infer contextual base in reference to member 'milliseconds'
Referencing subscript 'subscript(dynamicMember:)' requires wrapper 'Binding<[MockMessages.ChatMessageItem]>'
Insert '$'
Value of type '[MockMessages.ChatMessageItem]' has no dynamic member 'debounce' using key path from root type '[MockMessages.ChatMessageItem]'

please advise
regards

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

This repository currently has no open or pending branches.

Detected dependencies

github-actions
.github/workflows/close_stale_issues.yml
  • actions/stale v9
.github/workflows/swift.yml
  • actions/checkout v4
  • macos 14
swift
Package.swift
  • onevcat/Kingfisher from: "7.11.0"
  • EnesKaraosman/SwiftUIEKtensions from: "0.4.0"
  • dkk/WrappingHStack from: "2.2.11"

  • Check this box to trigger a request for Renovate to run again on this repository

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.