浏览代码

update fix bugs, add feature mention chatbot in Editor 1-1 and release for 5.0.65

alqindiirsyam 1 周之前
父节点
当前提交
26192553a8

+ 3 - 0
AppBuilder/AppBuilder/SecondTabViewController.swift

@@ -2256,6 +2256,9 @@ extension SecondTabViewController: UITableViewDelegate, UITableViewDataSource {
                             }
                             stringMessage.append(NSAttributedString(string: fullname + ": ", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12 + String.offset(), weight: .medium)]))
                         }
+                        if data.messageScope == MessageScope.WHISPER && data.isBot == 1 {
+                            stringMessage.append(NSAttributedString(string: "GPT SmartBot" + ": ", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12 + String.offset(), weight: .medium)]))
+                        }
                         if data.lock == "1" {
                             stringMessage.append(("🚫 _"+"This message was deleted".localized()+"_").richText())
                         } else {

+ 98 - 85
NexilisLite/NexilisLite/Resource/Palio.storyboard

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24127" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
     <device id="retina6_1" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24063"/>
         <capability name="Image references" minToolsVersion="12.0"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="System colors in document resources" minToolsVersion="11.0"/>
@@ -217,10 +217,10 @@
                             <tableViewSection id="4n8-6o-0im">
                                 <cells>
                                     <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" accessoryType="disclosureIndicator" indentationWidth="10" id="pc8-2U-MSs">
-                                        <rect key="frame" x="0.0" y="18" width="414" height="43.5"/>
+                                        <rect key="frame" x="0.0" y="18" width="414" height="51"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="pc8-2U-MSs" id="Xmq-xK-1yg">
-                                            <rect key="frame" x="0.0" y="0.0" width="383.5" height="43.5"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="383.5" height="51"/>
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Target Audience" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="y2e-Vl-JVL">
@@ -244,10 +244,10 @@
                                         </connections>
                                     </tableViewCell>
                                     <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" accessoryType="disclosureIndicator" indentationWidth="10" id="Zbt-qh-ktl">
-                                        <rect key="frame" x="0.0" y="61.5" width="414" height="43.5"/>
+                                        <rect key="frame" x="0.0" y="69" width="414" height="51"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Zbt-qh-ktl" id="nyg-ih-YLJ">
-                                            <rect key="frame" x="0.0" y="0.0" width="383.5" height="43.5"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="383.5" height="51"/>
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Promotion Type" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jjY-KN-zVt">
@@ -275,10 +275,10 @@
                             <tableViewSection id="Qif-KQ-tIx">
                                 <cells>
                                     <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="2aR-Gy-nAR">
-                                        <rect key="frame" x="0.0" y="141" width="414" height="43.5"/>
+                                        <rect key="frame" x="0.0" y="156" width="414" height="51"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="2aR-Gy-nAR" id="SBd-1d-vj4">
-                                            <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <textField opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Title" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="voK-ZY-QUL">
@@ -295,7 +295,7 @@
                             <tableViewSection id="9Ih-ev-XJh">
                                 <cells>
                                     <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" rowHeight="72" id="Bky-Xc-nqO">
-                                        <rect key="frame" x="0.0" y="220.5" width="414" height="72"/>
+                                        <rect key="frame" x="0.0" y="243" width="414" height="72"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Bky-Xc-nqO" id="2ub-Mm-d0R">
                                             <rect key="frame" x="0.0" y="0.0" width="414" height="72"/>
@@ -336,10 +336,10 @@
                             <tableViewSection id="GEy-Eq-KOr">
                                 <cells>
                                     <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="5qi-68-FZD">
-                                        <rect key="frame" x="0.0" y="328.5" width="414" height="43.5"/>
+                                        <rect key="frame" x="0.0" y="351" width="414" height="51"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="5qi-68-FZD" id="nr5-9p-FLy">
-                                            <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <textField opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Tagline" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="D86-KC-FS3">
@@ -383,10 +383,10 @@
                         <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                         <prototypes>
                             <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="reuseCell" id="6y6-2f-cif">
-                                <rect key="frame" x="0.0" y="55.5" width="414" height="43.5"/>
+                                <rect key="frame" x="0.0" y="55.5" width="414" height="51"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="6y6-2f-cif" id="Lss-GN-Uug">
-                                    <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                 </tableViewCellContentView>
                                 <connections>
@@ -417,10 +417,10 @@
                         <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                         <prototypes>
                             <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="reuseIdentifier" id="RT8-Qa-6dG">
-                                <rect key="frame" x="0.0" y="55.5" width="414" height="43.5"/>
+                                <rect key="frame" x="0.0" y="55.5" width="414" height="51"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="RT8-Qa-6dG" id="Axr-HY-bpT">
-                                    <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                 </tableViewCellContentView>
@@ -448,10 +448,10 @@
                         <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                         <prototypes>
                             <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="reuseIdentifier" id="OiN-Zh-59R">
-                                <rect key="frame" x="0.0" y="50" width="414" height="43.5"/>
+                                <rect key="frame" x="0.0" y="50" width="414" height="51"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="OiN-Zh-59R" id="7Yl-bg-HYf">
-                                    <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                 </tableViewCellContentView>
                             </tableViewCell>
@@ -646,10 +646,10 @@
                             <tableViewSection id="rtf-JY-NkZ">
                                 <cells>
                                     <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="SfX-q3-OtR">
-                                        <rect key="frame" x="0.0" y="18" width="414" height="43.5"/>
+                                        <rect key="frame" x="0.0" y="18" width="414" height="51"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="SfX-q3-OtR" id="IBH-OI-435">
-                                            <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <textField opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Name" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="l6U-Nt-tuz">
@@ -709,16 +709,16 @@
                                                     </constraints>
                                                 </imageView>
                                                 <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="40M-iH-oyA">
-                                                    <rect key="frame" x="286" y="154.5" width="68" height="24.5"/>
+                                                    <rect key="frame" x="286" y="154.5" width="68" height="20.5"/>
                                                     <subviews>
                                                         <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_internal" translatesAutoresizingMaskIntoConstraints="NO" id="yKV-8p-D06">
-                                                            <rect key="frame" x="5" y="-51.5" width="10" height="127.5"/>
+                                                            <rect key="frame" x="5" y="-51.5" width="10" height="123.5"/>
                                                             <constraints>
                                                                 <constraint firstAttribute="width" constant="10" id="Vh5-7K-sQv"/>
                                                             </constraints>
                                                         </imageView>
                                                         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Internal" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="evL-sf-Uad">
-                                                            <rect key="frame" x="20" y="5" width="43" height="14.5"/>
+                                                            <rect key="frame" x="20" y="5" width="43" height="10.5"/>
                                                             <fontDescription key="fontDescription" type="system" pointSize="12"/>
                                                             <nil key="textColor"/>
                                                             <nil key="highlightedColor"/>
@@ -762,7 +762,7 @@
                                                     <rect key="frame" x="266" y="51" width="88" height="83.5"/>
                                                 </imageView>
                                                 <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="zJO-fc-bwa">
-                                                    <rect key="frame" x="20" y="114" width="109" height="65"/>
+                                                    <rect key="frame" x="20" y="110" width="109" height="65"/>
                                                     <subviews>
                                                         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Status: " textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Y9j-ww-76p">
                                                             <rect key="frame" x="0.0" y="0.0" width="109" height="17"/>
@@ -864,7 +864,7 @@
                                                             <buttonConfiguration key="configuration" style="filled" title="Contact Center History"/>
                                                         </button>
                                                         <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="oaQ-vC-3bV">
-                                                            <rect key="frame" x="315" y="41.5" width="51" height="31"/>
+                                                            <rect key="frame" x="303" y="43" width="63" height="28"/>
                                                             <color key="onTintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                                         </switch>
                                                         <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ndh-T2-T4k">
@@ -877,7 +877,7 @@
                                                             <state key="normal" image="pencil" catalog="system"/>
                                                         </button>
                                                         <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="imY-6r-cWB">
-                                                            <rect key="frame" x="315" y="117.5" width="51" height="31"/>
+                                                            <rect key="frame" x="303" y="119" width="63" height="28"/>
                                                             <color key="onTintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                                         </switch>
                                                         <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Private Account Mode" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Nvg-uC-lAp">
@@ -1271,10 +1271,10 @@
                             <tableViewSection id="C9U-nb-4b7">
                                 <cells>
                                     <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="6oa-Ua-lTL">
-                                        <rect key="frame" x="0.0" y="18" width="414" height="43.5"/>
+                                        <rect key="frame" x="0.0" y="18" width="414" height="51"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="6oa-Ua-lTL" id="Z85-Eh-3Lu">
-                                            <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <textField opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Title Group" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="agZ-7H-Lfa">
@@ -1291,10 +1291,10 @@
                             <tableViewSection id="FF5-hQ-v1U">
                                 <cells>
                                     <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="6fV-Ax-hVZ">
-                                        <rect key="frame" x="0.0" y="97.5" width="414" height="43.5"/>
+                                        <rect key="frame" x="0.0" y="105" width="414" height="51"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="6fV-Ax-hVZ" id="ohg-8B-qhq">
-                                            <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <textField opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Sub Group" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="CE0-fn-PUw">
@@ -1333,17 +1333,17 @@
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <prototypes>
                             <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="profileCell" id="0wF-pE-j3u" customClass="ProfileCell" customModule="NexilisLite" customModuleProvider="target">
-                                <rect key="frame" x="20" y="55.5" width="374" height="43.5"/>
+                                <rect key="frame" x="20" y="55.5" width="374" height="51"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="0wF-pE-j3u" id="5QZ-kT-xNR">
-                                    <rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="374" height="51"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                     <subviews>
                                         <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="BDh-zV-5ME">
-                                            <rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="374" height="51"/>
                                         </imageView>
                                         <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="DVh-UE-GCr">
-                                            <rect key="frame" x="127" y="-38.5" width="120" height="120.5"/>
+                                            <rect key="frame" x="127" y="-34.5" width="120" height="120"/>
                                             <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                             <color key="tintColor" red="0.41176470590000003" green="0.27058823529999998" blue="0.64705882349999999" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
                                             <constraints>
@@ -1367,10 +1367,10 @@
                                 </connections>
                             </tableViewCell>
                             <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="reuseIdentifier" id="PHV-Mi-xcN">
-                                <rect key="frame" x="20" y="99" width="374" height="43.5"/>
+                                <rect key="frame" x="20" y="106.5" width="374" height="51"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="PHV-Mi-xcN" id="iGc-u7-rr2">
-                                    <rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="374" height="51"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                 </tableViewCellContentView>
                             </tableViewCell>
@@ -1736,10 +1736,10 @@
                         <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                         <prototypes>
                             <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="reuseCell" id="jeA-6G-jy2">
-                                <rect key="frame" x="0.0" y="55.5" width="414" height="43.5"/>
+                                <rect key="frame" x="0.0" y="55.5" width="414" height="51"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="jeA-6G-jy2" id="DdU-aI-BRO">
-                                    <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                 </tableViewCellContentView>
                                 <connections>
@@ -1826,7 +1826,7 @@
                 <navigationController storyboardIdentifier="streamingNav" automaticallyAdjustsScrollViewInsets="NO" id="dEs-fL-JC4" sceneMemberID="viewController">
                     <toolbarItems/>
                     <navigationBar key="navigationBar" contentMode="scaleToFill" id="VMx-jK-5xn">
-                        <rect key="frame" x="0.0" y="96" width="414" height="44"/>
+                        <rect key="frame" x="0.0" y="96" width="414" height="54"/>
                         <autoresizingMask key="autoresizingMask"/>
                     </navigationBar>
                     <nil name="viewControllers"/>
@@ -1844,7 +1844,7 @@
                 <navigationController storyboardIdentifier="settingNav" automaticallyAdjustsScrollViewInsets="NO" id="jUQ-Vs-n9A" sceneMemberID="viewController">
                     <toolbarItems/>
                     <navigationBar key="navigationBar" contentMode="scaleToFill" id="5pa-h0-hNP">
-                        <rect key="frame" x="0.0" y="96" width="414" height="44"/>
+                        <rect key="frame" x="0.0" y="96" width="414" height="54"/>
                         <autoresizingMask key="autoresizingMask"/>
                     </navigationBar>
                     <nil name="viewControllers"/>
@@ -1862,7 +1862,7 @@
                 <navigationController storyboardIdentifier="contactChatNav" automaticallyAdjustsScrollViewInsets="NO" id="fN9-fa-00b" sceneMemberID="viewController">
                     <toolbarItems/>
                     <navigationBar key="navigationBar" contentMode="scaleToFill" id="cuo-kr-hfM">
-                        <rect key="frame" x="0.0" y="96" width="414" height="44"/>
+                        <rect key="frame" x="0.0" y="96" width="414" height="54"/>
                         <autoresizingMask key="autoresizingMask"/>
                     </navigationBar>
                     <nil name="viewControllers"/>
@@ -1884,28 +1884,28 @@
                         <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                         <prototypes>
                             <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="reuseIdentifierChat" id="zd4-bn-4R1">
-                                <rect key="frame" x="0.0" y="50" width="414" height="43.5"/>
+                                <rect key="frame" x="0.0" y="50" width="414" height="51"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="zd4-bn-4R1" id="N2x-sI-FVQ">
-                                    <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                 </tableViewCellContentView>
                                 <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                             </tableViewCell>
                             <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="reuseIdentifierContact" id="C8N-ND-gaQ">
-                                <rect key="frame" x="0.0" y="93.5" width="414" height="43.5"/>
+                                <rect key="frame" x="0.0" y="101" width="414" height="51"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="C8N-ND-gaQ" id="RU8-Cm-q4o">
-                                    <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                 </tableViewCellContentView>
                                 <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                             </tableViewCell>
                             <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="reuseIdentifierGroup" id="fwt-K3-Cph">
-                                <rect key="frame" x="0.0" y="137" width="414" height="43.5"/>
+                                <rect key="frame" x="0.0" y="152" width="414" height="51"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="fwt-K3-Cph" id="wls-xz-0W0">
-                                    <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                 </tableViewCellContentView>
                                 <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -1932,10 +1932,10 @@
                         <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                         <prototypes>
                             <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="reuseIdentifier" id="XJk-Zo-ZWJ">
-                                <rect key="frame" x="0.0" y="50" width="414" height="43.5"/>
+                                <rect key="frame" x="0.0" y="50" width="414" height="51"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="XJk-Zo-ZWJ" id="Ssg-PF-ctd">
-                                    <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                 </tableViewCellContentView>
                             </tableViewCell>
@@ -1957,7 +1957,7 @@
                 <navigationController storyboardIdentifier="addFriendNav" automaticallyAdjustsScrollViewInsets="NO" id="7Wn-tA-a36" sceneMemberID="viewController">
                     <toolbarItems/>
                     <navigationBar key="navigationBar" contentMode="scaleToFill" id="BPo-Ji-MTR">
-                        <rect key="frame" x="0.0" y="96" width="414" height="44"/>
+                        <rect key="frame" x="0.0" y="96" width="414" height="54"/>
                         <autoresizingMask key="autoresizingMask"/>
                     </navigationBar>
                     <nil name="viewControllers"/>
@@ -1991,7 +1991,7 @@
                 <navigationController storyboardIdentifier="createGroupNav" automaticallyAdjustsScrollViewInsets="NO" id="gGk-tB-HXd" sceneMemberID="viewController">
                     <toolbarItems/>
                     <navigationBar key="navigationBar" contentMode="scaleToFill" id="AVS-vC-GWW">
-                        <rect key="frame" x="0.0" y="96" width="414" height="44"/>
+                        <rect key="frame" x="0.0" y="96" width="414" height="54"/>
                         <autoresizingMask key="autoresizingMask"/>
                     </navigationBar>
                     <nil name="viewControllers"/>
@@ -2217,7 +2217,7 @@
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Members" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Aft-wF-Mau">
-                                                    <rect key="frame" x="20" y="0.0" width="60.5" height="44"/>
+                                                    <rect key="frame" x="20" y="4" width="60.5" height="44"/>
                                                     <constraints>
                                                         <constraint firstAttribute="height" constant="44" id="vrk-t1-nD6"/>
                                                     </constraints>
@@ -2226,7 +2226,7 @@
                                                     <nil key="highlightedColor"/>
                                                 </label>
                                                 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="jXj-wl-ncj">
-                                                    <rect key="frame" x="364" y="11" width="30" height="30"/>
+                                                    <rect key="frame" x="364" y="15" width="30" height="30"/>
                                                     <constraints>
                                                         <constraint firstAttribute="width" constant="30" id="IdU-xJ-rSi"/>
                                                         <constraint firstAttribute="height" constant="30" id="tC6-FO-Uwr"/>
@@ -2239,18 +2239,18 @@
                                                     </connections>
                                                 </button>
                                                 <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="pAb-RO-Znf">
-                                                    <rect key="frame" x="0.0" y="49" width="414" height="151"/>
+                                                    <rect key="frame" x="0.0" y="53" width="414" height="147"/>
                                                     <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                                                     <prototypes>
                                                         <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="memberCell" id="KLi-it-fQR" customClass="BroadcastMembersTableViewCell" customModule="NexilisLite" customModuleProvider="target">
-                                                            <rect key="frame" x="0.0" y="50" width="414" height="43.5"/>
+                                                            <rect key="frame" x="0.0" y="50" width="414" height="51"/>
                                                             <autoresizingMask key="autoresizingMask"/>
                                                             <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="KLi-it-fQR" id="T6c-sB-rPD">
-                                                                <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                                                <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                                                 <autoresizingMask key="autoresizingMask"/>
                                                                 <subviews>
                                                                     <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6KW-dw-64C">
-                                                                        <rect key="frame" x="354" y="7" width="30" height="30"/>
+                                                                        <rect key="frame" x="354" y="10.5" width="30" height="30"/>
                                                                         <constraints>
                                                                             <constraint firstAttribute="height" constant="30" id="5wC-cz-htK"/>
                                                                             <constraint firstAttribute="width" constant="30" id="Zok-mQ-nL0"/>
@@ -2338,7 +2338,7 @@
                                                     </constraints>
                                                 </view>
                                                 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="BYe-aL-wmw">
-                                                    <rect key="frame" x="364" y="219" width="30" height="30"/>
+                                                    <rect key="frame" x="364" y="215" width="30" height="30"/>
                                                     <constraints>
                                                         <constraint firstAttribute="width" constant="30" id="nCy-cD-0QQ"/>
                                                         <constraint firstAttribute="height" constant="30" id="yh7-XK-PeI"/>
@@ -2349,7 +2349,7 @@
                                                     </connections>
                                                 </button>
                                                 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aOH-VA-ubc">
-                                                    <rect key="frame" x="224" y="219" width="30" height="30"/>
+                                                    <rect key="frame" x="224" y="215" width="30" height="30"/>
                                                     <constraints>
                                                         <constraint firstAttribute="height" constant="30" id="4pl-VT-FRr"/>
                                                         <constraint firstAttribute="width" constant="30" id="o9I-Rn-PuH"/>
@@ -2360,7 +2360,7 @@
                                                     </connections>
                                                 </button>
                                                 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5Xj-YZ-dwa">
-                                                    <rect key="frame" x="294" y="219" width="30" height="30"/>
+                                                    <rect key="frame" x="294" y="215" width="30" height="30"/>
                                                     <constraints>
                                                         <constraint firstAttribute="height" constant="30" id="DIf-GA-WHh"/>
                                                         <constraint firstAttribute="width" constant="30" id="s2O-Kz-fgq"/>
@@ -2371,7 +2371,7 @@
                                                     </connections>
                                                 </button>
                                                 <button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6bK-gT-tMC">
-                                                    <rect key="frame" x="364" y="11" width="30" height="30"/>
+                                                    <rect key="frame" x="364" y="15" width="30" height="30"/>
                                                     <constraints>
                                                         <constraint firstAttribute="width" constant="30" id="Ozv-gS-iVI"/>
                                                         <constraint firstAttribute="height" constant="30" id="ekc-aX-2Y9"/>
@@ -2483,7 +2483,7 @@
             <objects>
                 <navigationController storyboardIdentifier="broadcastNav" title="Broadcast Navigation Controller" modalPresentationStyle="fullScreen" id="NH6-7u-Fec" sceneMemberID="viewController">
                     <navigationBar key="navigationBar" contentMode="scaleToFill" id="56D-ii-ei5">
-                        <rect key="frame" x="0.0" y="96" width="414" height="44"/>
+                        <rect key="frame" x="0.0" y="96" width="414" height="54"/>
                         <autoresizingMask key="autoresizingMask"/>
                     </navigationBar>
                     <connections>
@@ -2504,10 +2504,10 @@
                         <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                         <prototypes>
                             <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="reuseCell" id="Pav-Pk-Qle">
-                                <rect key="frame" x="0.0" y="55.5" width="414" height="43.5"/>
+                                <rect key="frame" x="0.0" y="55.5" width="414" height="51"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Pav-Pk-Qle" id="pJW-b9-oFZ">
-                                    <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                 </tableViewCellContentView>
                                 <connections>
@@ -2538,10 +2538,10 @@
                         <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                         <prototypes>
                             <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="reuseCell" id="D0S-Cs-tKI">
-                                <rect key="frame" x="0.0" y="55.5" width="414" height="43.5"/>
+                                <rect key="frame" x="0.0" y="55.5" width="414" height="51"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="D0S-Cs-tKI" id="bHv-cf-3wj">
-                                    <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                 </tableViewCellContentView>
                                 <connections>
@@ -2572,10 +2572,10 @@
                         <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                         <prototypes>
                             <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="reuseIdentifierContact" id="T7c-Gy-ZCh">
-                                <rect key="frame" x="0.0" y="50" width="414" height="43.5"/>
+                                <rect key="frame" x="0.0" y="50" width="414" height="51"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="T7c-Gy-ZCh" id="efe-Ef-u3N">
-                                    <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                 </tableViewCellContentView>
                                 <connections>
@@ -2583,10 +2583,10 @@
                                 </connections>
                             </tableViewCell>
                             <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="reuseIdentifierGroup" id="KzB-f3-raJ">
-                                <rect key="frame" x="0.0" y="93.5" width="414" height="43.5"/>
+                                <rect key="frame" x="0.0" y="101" width="414" height="51"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="KzB-f3-raJ" id="DdU-Cy-zh3">
-                                    <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                    <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                     <autoresizingMask key="autoresizingMask"/>
                                 </tableViewCellContentView>
                                 <connections>
@@ -2621,6 +2621,13 @@
                                 <rect key="frame" x="0.0" y="0.0" width="414" height="766"/>
                                 <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                             </tableView>
+                            <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="-1" sectionFooterHeight="-1" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="UoU-li-T7q">
+                                <rect key="frame" x="0.0" y="836" width="414" height="150"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="150" id="qhs-ce-c7x"/>
+                                </constraints>
+                            </tableView>
                             <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yLm-Hp-3ZU">
                                 <rect key="frame" x="0.0" y="776" width="414" height="60"/>
                                 <subviews>
@@ -2745,7 +2752,10 @@
                             <constraint firstItem="yLm-Hp-3ZU" firstAttribute="top" secondItem="tSE-6b-2zD" secondAttribute="bottom" constant="10" id="6PR-yi-4lY"/>
                             <constraint firstItem="Xda-XC-yEA" firstAttribute="trailing" secondItem="4DG-z5-IE7" secondAttribute="trailing" id="Odw-hD-SS5"/>
                             <constraint firstItem="yLm-Hp-3ZU" firstAttribute="leading" secondItem="4DG-z5-IE7" secondAttribute="leading" id="RCA-U3-JT8"/>
+                            <constraint firstAttribute="bottom" secondItem="UoU-li-T7q" secondAttribute="bottom" constant="-90" id="XSB-nC-5jT"/>
+                            <constraint firstItem="UoU-li-T7q" firstAttribute="leading" secondItem="4DG-z5-IE7" secondAttribute="leading" id="YtJ-Up-V4d"/>
                             <constraint firstItem="tSE-6b-2zD" firstAttribute="leading" secondItem="4DG-z5-IE7" secondAttribute="leading" id="ZTb-c1-RCd"/>
+                            <constraint firstItem="UoU-li-T7q" firstAttribute="trailing" secondItem="4DG-z5-IE7" secondAttribute="trailing" id="eII-up-SI9"/>
                             <constraint firstItem="Xda-XC-yEA" firstAttribute="top" secondItem="yLm-Hp-3ZU" secondAttribute="bottom" id="kBx-ys-A1s"/>
                             <constraint firstItem="tSE-6b-2zD" firstAttribute="trailing" secondItem="4DG-z5-IE7" secondAttribute="trailing" id="nHx-Iz-cds"/>
                             <constraint firstItem="mBd-UJ-S23" firstAttribute="leading" secondItem="tRl-GA-sdt" secondAttribute="leading" id="t9S-wa-41x"/>
@@ -2768,8 +2778,11 @@
                         <outlet property="constraintLeftTextField" destination="jx0-o5-Ja0" id="1hP-FQ-qYY"/>
                         <outlet property="constraintTopTextField" destination="43A-hi-qkj" id="UCq-4N-QAW"/>
                         <outlet property="constraintViewTextField" destination="kBx-ys-A1s" id="A9C-IX-cZ2"/>
+                        <outlet property="contraintBottomMention" destination="XSB-nC-5jT" id="flK-GZ-Mxb"/>
+                        <outlet property="heightTableMention" destination="qhs-ce-c7x" id="Cxw-Qc-OqK"/>
                         <outlet property="heightTextFieldSend" destination="BM5-gS-VIN" id="Ioh-Xm-Kd0"/>
                         <outlet property="tableChatView" destination="tSE-6b-2zD" id="qeC-k9-MJz"/>
+                        <outlet property="tableMention" destination="UoU-li-T7q" id="gTJ-2L-wjl"/>
                         <outlet property="textFieldSend" destination="Zwh-BN-IXY" id="Y3X-Y9-Tg4"/>
                         <outlet property="viewAttachment" destination="UMZ-Cg-DEH" id="oNr-Nt-Yjk"/>
                         <outlet property="viewButton" destination="Xda-XC-yEA" id="SfN-gB-RKH"/>
@@ -2976,10 +2989,10 @@
                             <tableViewSection id="SKZ-sY-c65">
                                 <cells>
                                     <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="u65-KT-3JE">
-                                        <rect key="frame" x="0.0" y="18" width="414" height="43.5"/>
+                                        <rect key="frame" x="0.0" y="18" width="414" height="51"/>
                                         <autoresizingMask key="autoresizingMask"/>
                                         <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="u65-KT-3JE" id="uw4-V9-z0P">
-                                            <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
+                                            <rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
                                             <autoresizingMask key="autoresizingMask"/>
                                             <subviews>
                                                 <textField opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Name" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="kJb-e9-XoJ">
@@ -3087,7 +3100,7 @@
                                         <buttonConfiguration key="configuration" style="plain" title="Alpha"/>
                                     </button>
                                     <slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="100" minValue="0.0" maxValue="100" translatesAutoresizingMaskIntoConstraints="NO" id="BPs-KH-mSQ">
-                                        <rect key="frame" x="65.5" y="0.0" width="136.5" height="31"/>
+                                        <rect key="frame" x="67.5" y="0.0" width="132.5" height="30"/>
                                         <connections>
                                             <action selector="onAlphaChanged:" destination="m7A-yE-OFx" eventType="valueChanged" id="X0j-xb-PBe"/>
                                         </connections>
@@ -3215,7 +3228,7 @@
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
                             <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="w21-oX-k1B">
-                                <rect key="frame" x="0.0" y="140" width="414" height="688"/>
+                                <rect key="frame" x="0.0" y="150" width="414" height="678"/>
                                 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                 <prototypes>
                                     <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="seminarListCell" rowHeight="60" id="fKY-DZ-Ct6" customClass="SeminarListCell" customModule="NexilisLite" customModuleProvider="target">
@@ -3342,7 +3355,7 @@
                 <navigationController storyboardIdentifier="seminarListNav" automaticallyAdjustsScrollViewInsets="NO" id="fLe-EJ-GeO" sceneMemberID="viewController">
                     <toolbarItems/>
                     <navigationBar key="navigationBar" contentMode="scaleToFill" id="ESA-C7-dc0">
-                        <rect key="frame" x="0.0" y="96" width="414" height="44"/>
+                        <rect key="frame" x="0.0" y="96" width="414" height="54"/>
                         <autoresizingMask key="autoresizingMask"/>
                     </navigationBar>
                     <nil name="viewControllers"/>
@@ -3443,7 +3456,7 @@
         <image name="gearshape.fill" catalog="system" width="128" height="123"/>
         <image name="ic_internal" width="128" height="128"/>
         <image name="message.circle.fill" catalog="system" width="128" height="123"/>
-        <image name="message.fill" catalog="system" width="128" height="114"/>
+        <image name="message.fill" catalog="system" width="128" height="104"/>
         <image name="mic.slash.fill" catalog="system" width="108" height="128"/>
         <image name="pb_cd_person" width="512" height="512"/>
         <image name="pb_seminar_speaking" width="512" height="512"/>
@@ -3470,37 +3483,37 @@
             <color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
         </systemColor>
         <systemColor name="secondarySystemBackgroundColor">
-            <color red="0.94901960784313721" green="0.94901960784313721" blue="0.96862745098039216" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <color red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
         </systemColor>
         <systemColor name="systemBackgroundColor">
             <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
         </systemColor>
         <systemColor name="systemBlueColor">
-            <color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <color red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
         </systemColor>
         <systemColor name="systemGray2Color">
-            <color red="0.68235294117647061" green="0.68235294117647061" blue="0.69803921568627447" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <color red="0.68235294120000001" green="0.68235294120000001" blue="0.69803921570000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
         </systemColor>
         <systemColor name="systemGray3Color">
-            <color red="0.7803921568627451" green="0.7803921568627451" blue="0.80000000000000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <color red="0.78039215689999997" green="0.78039215689999997" blue="0.80000000000000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
         </systemColor>
         <systemColor name="systemGray4Color">
-            <color red="0.81960784313725488" green="0.81960784313725488" blue="0.83921568627450982" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <color red="0.81960784310000001" green="0.81960784310000001" blue="0.83921568629999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
         </systemColor>
         <systemColor name="systemGrayColor">
-            <color red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <color red="0.5568627451" green="0.5568627451" blue="0.57647058819999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
         </systemColor>
         <systemColor name="systemGreenColor">
-            <color red="0.20392156862745098" green="0.7803921568627451" blue="0.34901960784313724" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <color red="0.20392156859999999" green="0.78039215689999997" blue="0.34901960780000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
         </systemColor>
         <systemColor name="systemIndigoColor">
-            <color red="0.34509803921568627" green="0.33725490196078434" blue="0.83921568627450982" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <color red="0.34509803919999998" green="0.33725490200000002" blue="0.83921568629999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
         </systemColor>
         <systemColor name="systemRedColor">
-            <color red="1" green="0.23137254901960785" blue="0.18823529411764706" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <color red="1" green="0.23137254900000001" blue="0.18823529410000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
         </systemColor>
         <systemColor name="tintColor">
-            <color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <color red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
         </systemColor>
     </resources>
 </document>

+ 1 - 0
NexilisLite/NexilisLite/Source/CoreMessage_TMessageKey.swift

@@ -527,4 +527,5 @@ public class CoreMessage_TMessageKey {
     public static let ACT_TIME = "ACTMS";
     
     public static let TOTP = "TOTP";
+    public static let IS_BOT = "ibot";
 }

+ 3 - 1
NexilisLite/NexilisLite/Source/Database.swift

@@ -118,6 +118,7 @@ public class Database {
                 addColumnIfNeeded(database: fmdb, tableName: "MESSAGE", columnName: "story_thumb", columnType: "TEXT", defaultValue: "")
                 addColumnIfNeeded(database: fmdb, tableName: "MESSAGE", columnName: "story_pin", columnType: "TEXT", defaultValue: "")
                 addColumnIfNeeded(database: fmdb, tableName: "MESSAGE", columnName: "attachment_speciality", columnType: "TEXT", defaultValue: "")
+                addColumnIfNeeded(database: fmdb, tableName: "MESSAGE", columnName: "is_bot", columnType: "INTEGER", defaultValue: "0")
                 
                 //COMMUNITY
                 changeNameColumn(database: fmdb, tableName: "COMMUNITY", oldColumnName: "group_type", newColumnName: "community_type")
@@ -365,7 +366,8 @@ public class Database {
                                "'story_thumb' TEXT," +
                                "'story_pin' TEXT," +
                                "'is_pinned' INTEGER DEFAULT 0," +
-                               "'attachment_speciality' TEXT" +
+                               "'attachment_speciality' TEXT," +
+                               "'is_bot' INTEGER DEFAULT 0" +
                                 ")", values: nil)
         
         try fmdb.executeUpdate("CREATE INDEX IF NOT EXISTS index_m_opposite on MESSAGE (opposite_pin, chat_id)", values: nil)

+ 2 - 2
NexilisLite/NexilisLite/Source/Extension.swift

@@ -1096,7 +1096,7 @@ extension String {
     }
 
     private func processMentions(in text: NSMutableAttributedString, groupID: String, isEditing: Bool, listMentionInTextField: [User] = []) {
-        let regex = try? NSRegularExpression(pattern: "@(\\w+)", options: [])
+        let regex = try? NSRegularExpression(pattern: "@([\\w-]+)", options: [])
         let matches = regex?.matches(in: text.string, options: [], range: NSRange(location: 0, length: text.length)) ?? []
 
         for match in matches.reversed() {
@@ -1116,7 +1116,7 @@ extension String {
                 if let member = Member.getMember(f_pin: username) {
                     let fullName = "\(member.fullName)".trimmingCharacters(in: .whitespaces)
                     text.replaceCharacters(in: range, with: fullName)
-                    if !groupID.isEmpty, Member.getMemberInGroup(f_pin: username, group_id: groupID) != nil {
+                    if ((!groupID.isEmpty && Member.getMemberInGroup(f_pin: username, group_id: groupID) != nil) || username == "-997") {
                         let newRange = (text.string as NSString).range(of: "@\(fullName)")
                         text.addAttribute(.foregroundColor, value: UIColor.gray, range: NSRange(location: newRange.lowerBound, length: 1))
                         text.addAttribute(.foregroundColor, value: UIColor.mentionColor, range: NSRange(location: newRange.lowerBound + 1, length: fullName.count))

+ 12 - 7
NexilisLite/NexilisLite/Source/Model/Chat.swift

@@ -34,6 +34,7 @@ public class Chat: Model {
     public var isSelected: Bool
     public var isParent: Bool
     public var pinned: Int64
+    public var isBot: Int
     public var isFolPinned: Bool
     
     public init(pin: String) {
@@ -62,6 +63,7 @@ public class Chat: Model {
         self.isSelected = false
         self.isParent = false
         self.pinned = 0
+        self.isBot = 0
         self.isFolPinned = false
     }
     
@@ -91,10 +93,11 @@ public class Chat: Model {
         self.isSelected = false
         self.isParent = false
         self.pinned = 0
+        self.isBot = 0
         self.isFolPinned = false
     }
     
-    public init(fpin:String, pin: String, messageId: String, counter: String, messageText: String, serverDate: String, image: String, video: String, file: String, attachmentFlag: String, messageScope: String, name: String, profile: String, official: String, status: String, credential: String, lock: String, thumb: String = "", audio: String = "", gif: String = "", groupId: String = "", groupName: String = "", isSelected: Bool = false, isParent: Bool = false, pinned: Int64 = 0, isFolPinned: Bool = false) {
+    public init(fpin:String, pin: String, messageId: String, counter: String, messageText: String, serverDate: String, image: String, video: String, file: String, attachmentFlag: String, messageScope: String, name: String, profile: String, official: String, status: String, credential: String, lock: String, thumb: String = "", audio: String = "", gif: String = "", groupId: String = "", groupName: String = "", isSelected: Bool = false, isParent: Bool = false, pinned: Int64 = 0, isBot: Int = 0, isFolPinned: Bool = false) {
         self.fpin = fpin
         self.pin = pin
         self.messageId = messageId
@@ -120,6 +123,7 @@ public class Chat: Model {
         self.isSelected = isSelected
         self.isParent = isParent
         self.pinned = pinned
+        self.isBot = isBot
         self.isFolPinned = isFolPinned
     }
     
@@ -278,15 +282,15 @@ public class Chat: Model {
                     lastQuery = "m.audio_id IS NOT NULL AND m.audio_id != ''"
                 }
                 var query = """
-                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, b.first_name || ' ' || ifnull(b.last_name, '') name, b.image_id profile, b.official_account, m.status, m.credential, m.lock, m.audio_id, m.gif_id, '' group_id, '' group_name, ms.pinned from MESSAGE_SUMMARY ms, MESSAGE m, BUDDY b where ms.l_pin = b.f_pin and ms.message_id = m.message_id and m.is_call_center = 0 \(isArchived ? "and ms.archived <> 0" : "and ms.archived = 0")
+                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, b.first_name || ' ' || ifnull(b.last_name, '') name, b.image_id profile, b.official_account, m.status, m.credential, m.lock, m.audio_id, m.gif_id, '' group_id, '' group_name, ms.pinned, m.is_bot from MESSAGE_SUMMARY ms, MESSAGE m, BUDDY b where ms.l_pin = b.f_pin and ms.message_id = m.message_id and m.is_call_center = 0 \(isArchived ? "and ms.archived <> 0" : "and ms.archived = 0")
                             union
-                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, 'Bot' name, '' profile, '', m.status, m.credential, m.lock, m.audio_id, m.gif_id, '' group_id, '' group_name, ms.pinned from MESSAGE_SUMMARY ms, MESSAGE m where ms.l_pin = '-999' and ms.message_id = m.message_id \(isArchived ? "and ms.archived <> 0" : "and ms.archived = 0")
+                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, 'Bot' name, '' profile, '', m.status, m.credential, m.lock, m.audio_id, m.gif_id, '' group_id, '' group_name, ms.pinned, m.is_bot from MESSAGE_SUMMARY ms, MESSAGE m where ms.l_pin = '-999' and ms.message_id = m.message_id \(isArchived ? "and ms.archived <> 0" : "and ms.archived = 0")
                             union
-                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, 'GPT SmartBot' name, '' profile, '', m.status, m.credential, m.lock, m.audio_id, m.gif_id, '' group_id, '' group_name, ms.pinned from MESSAGE_SUMMARY ms, MESSAGE m where ms.l_pin = '-997' and ms.message_id = m.message_id \(isArchived ? "and ms.archived <> 0" : "and ms.archived = 0")
+                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, 'GPT SmartBot' name, '' profile, '', m.status, m.credential, m.lock, m.audio_id, m.gif_id, '' group_id, '' group_name, ms.pinned, m.is_bot from MESSAGE_SUMMARY ms, MESSAGE m where ms.l_pin = '-997' and ms.message_id = m.message_id \(isArchived ? "and ms.archived <> 0" : "and ms.archived = 0")
                             union
-                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, '\("Lounge".localized())' name, b.image_id profile, b.official, m.status, m.credential, m.lock, m.audio_id, m.gif_id, b.group_id, b.f_name group_name, ms.pinned from MESSAGE_SUMMARY ms, MESSAGE m, GROUPZ b where ms.l_pin = b.group_id and ms.message_id = m.message_id and m.is_call_center = 0 \(isArchived ? "and ms.archived <> 0" : "and ms.archived = 0")
+                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, '\("Lounge".localized())' name, b.image_id profile, b.official, m.status, m.credential, m.lock, m.audio_id, m.gif_id, b.group_id, b.f_name group_name, ms.pinned, m.is_bot from MESSAGE_SUMMARY ms, MESSAGE m, GROUPZ b where ms.l_pin = b.group_id and ms.message_id = m.message_id and m.is_call_center = 0 \(isArchived ? "and ms.archived <> 0" : "and ms.archived = 0")
                             union
-                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, b.title, c.image_id profile, '', m.status, m.credential, m.lock, m.audio_id, m.gif_id, c.group_id, c.f_name group_name, ms.pinned from MESSAGE_SUMMARY ms, MESSAGE m, DISCUSSION_FORUM b, GROUPZ c where b.group_id = c.group_id and ms.l_pin = b.chat_id and ms.message_id = m.message_id and m.is_call_center = 0 \(isArchived ? "and ms.archived <> 0" : "and ms.archived = 0")
+                            select m.f_pin, ms.l_pin, ms.message_id, ms.counter, m.message_text, m.server_date, m.image_id, m.video_id, m.file_id, m.attachment_flag, m.message_scope_id, b.title, c.image_id profile, '', m.status, m.credential, m.lock, m.audio_id, m.gif_id, c.group_id, c.f_name group_name, ms.pinned, m.is_bot from MESSAGE_SUMMARY ms, MESSAGE m, DISCUSSION_FORUM b, GROUPZ c where b.group_id = c.group_id and ms.l_pin = b.chat_id and ms.message_id = m.message_id and m.is_call_center = 0 \(isArchived ? "and ms.archived <> 0" : "and ms.archived = 0")
                             order by 6 desc
                             """
                 if !lastQuery.isEmpty {
@@ -328,7 +332,8 @@ public class Chat: Model {
                                         gif: !lastQuery.isEmpty ? cursorData.string(forColumnIndex: 17) ?? "" : cursorData.string(forColumnIndex: 18) ?? "",
                                         groupId: cursorData.string(forColumnIndex: 19) ?? "",
                                         groupName: cursorData.string(forColumnIndex: 20) ?? "",
-                                        pinned: cursorData.longLongInt(forColumnIndex: 21))
+                                        pinned: cursorData.longLongInt(forColumnIndex: 21),
+                                        isBot: Int(cursorData.string(forColumnIndex: 22) ?? "0") ?? 0)
                         chats.append(chat)
                     }
                     cursorData.close()

+ 14 - 0
NexilisLite/NexilisLite/Source/Model/Group.swift

@@ -179,6 +179,13 @@ public class Member: User {
                                         thumb: cursor.string(forColumnIndex: 3) ?? "",
                                         position: cursor.string(forColumnIndex: 4) ?? "")
                     }
+                    if f_pin == "-997" {
+                        member = Member(pin: "-997",
+                                        firstName: "GPT SmartBot",
+                                        lastName: "",
+                                        thumb: "",
+                                        position: "")
+                    }
                     cursor.close()
                 }
             } catch {
@@ -201,6 +208,13 @@ public class Member: User {
                                         thumb: cursor.string(forColumnIndex: 3) ?? "",
                                         position: cursor.string(forColumnIndex: 4) ?? "")
                     }
+                    if f_pin == "-997" {
+                        member = Member(pin: "-997",
+                                        firstName: "GPT SmartBot",
+                                        lastName: "",
+                                        thumb: "",
+                                        position: "")
+                    }
                     cursor.close()
                 }
             } catch {

+ 7 - 0
NexilisLite/NexilisLite/Source/Model/User.swift

@@ -171,6 +171,13 @@ public class User: Model {
                             privacy_flag: "",
                             offline_mode: "",
                             ex_block: "")
+            } else if pin == "-997" {
+                user = User(pin: "-997",
+                            firstName: "GPT SmartBot",
+                            lastName: "",
+                            thumb: "",
+                            userType: "0",
+                            official: "1")
             } else {
                 user = User(pin: pin,
                             firstName: "User".localized(),

+ 5 - 3
NexilisLite/NexilisLite/Source/Nexilis.swift

@@ -19,7 +19,7 @@ import CryptoKit
 import WebKit
 
 public class Nexilis: NSObject {
-    public static var cpaasVersion = "5.0.64"
+    public static var cpaasVersion = "5.0.65"
     public static var sAPIKey = ""
     
     public static var ADDRESS = ""
@@ -1629,6 +1629,7 @@ public class Nexilis: NSObject {
                 let is_delete_retention = message.getBodyAsLong(key: CoreMessage_TMessageKey.IS_DELETED_RETENTION, default_value: 0)
                 let is_forwarded_message = message.getBodyAsLong(key: CoreMessage_TMessageKey.IS_FORWARDED_MESSAGE, default_value: 0)
                 let opposite_pin = message.getBody(key: CoreMessage_TMessageKey.OPPOSITE_PIN, default_value: "")
+                let is_bot = message.getBodyAsInteger(key: CoreMessage_TMessageKey.IS_BOT, default_value: 0)
                 //print("prepare save db")
                 do {
                     _ = try Database.shared.insertRecord(fmdb: fmdb, table: "MESSAGE", cvalues: [
@@ -1667,7 +1668,8 @@ public class Nexilis: NSObject {
                         "is_secret" : is_secret,
                         "is_deleted_retention" : is_delete_retention,
                         "is_forwarded_message" : is_forwarded_message,
-                        "attachment_speciality" : message.getBody(key: CoreMessage_TMessageKey.ATTACHMENT_SPECIALITY, default_value:  "")
+                        "attachment_speciality" : message.getBody(key: CoreMessage_TMessageKey.ATTACHMENT_SPECIALITY, default_value:  ""),
+                        "is_bot" : is_bot
                     ], replace: true)
                 } catch {
                     print("ERROR: \(error)")
@@ -1710,7 +1712,7 @@ public class Nexilis: NSObject {
                     }
                 }
                 if pin == me {
-                    pin = l_pin
+                    pin = l_pin != me ? l_pin : f_pin
                 }
                 var counter : Int? = nil
                 if !withStatus {

+ 1 - 1
NexilisLite/NexilisLite/Source/Utils.swift

@@ -4012,7 +4012,7 @@ public final class MessageGuardLite {
                           mime: "application/octet-stream",
                           data: nil)
         }
-        let pattern = "[\\p{C}\\u200B-\\u200F\\uFEFF\\u202A-\\u202E]"
+        let pattern = #"[\p{C}&&[^\t\n\r]][\u200B-\u200F\uFEFF\u202A-\u202E]"#
         let regex = try! NSRegularExpression(pattern: pattern)
         let clean = regex.stringByReplacingMatches(in: input,
                                                    options: [],

+ 6 - 2
NexilisLite/NexilisLite/Source/View/Call/CallLogVC.swift

@@ -70,8 +70,12 @@ public class CallLogVC: UIViewController, UITableViewDataSource, UITableViewDele
         let rightButton = UIButton(type: .system)
         let imageRight = UIImage(systemName: "plus", withConfiguration: UIImage.SymbolConfiguration(pointSize: 12, weight: .bold))
         rightButton.setImage(imageRight, for: .normal)
-        rightButton.tintColor = .white
-        rightButton.backgroundColor = .whatsappGreenColor
+        if #unavailable(iOS 26.0) {
+            rightButton.tintColor = .white
+            rightButton.backgroundColor = .whatsappGreenColor
+        } else {
+            rightButton.tintColor = .black
+        }
         rightButton.layer.cornerRadius = 15
         rightButton.clipsToBounds = true
         rightButton.frame = CGRect(x: 0, y: 0, width: 30, height: 30)

+ 8 - 3
NexilisLite/NexilisLite/Source/View/Chat/ChatWALikeVC.swift

@@ -162,8 +162,12 @@ public class ChatWALikeVC: UIViewController, UITableViewDataSource, UITableViewD
         let rightButton = UIButton(type: .system)
         let imageRight = UIImage(systemName: "plus", withConfiguration: UIImage.SymbolConfiguration(pointSize: 12, weight: .bold))
         rightButton.setImage(imageRight, for: .normal)
-        rightButton.tintColor = .white
-        rightButton.backgroundColor = .whatsappGreenColor
+        if #unavailable(iOS 26.0) {
+            rightButton.tintColor = .white
+            rightButton.backgroundColor = .whatsappGreenColor
+        } else {
+            rightButton.tintColor = .black
+        }
         rightButton.layer.cornerRadius = 15
         rightButton.clipsToBounds = true
         rightButton.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
@@ -214,7 +218,6 @@ public class ChatWALikeVC: UIViewController, UITableViewDataSource, UITableViewD
                 }
                 searchController.searchBar.isHidden = false
             }
-            self.isGettingData = false
         }
     }
     
@@ -230,6 +233,7 @@ public class ChatWALikeVC: UIViewController, UITableViewDataSource, UITableViewD
             DispatchQueue.main.async {
                 self.tableView.reloadData()
                 self.loadingData = false
+                self.isGettingData = false
                 completion()
             }
         }
@@ -326,6 +330,7 @@ public class ChatWALikeVC: UIViewController, UITableViewDataSource, UITableViewD
                 tempChats.insert(Chat(pin: "Archived"), at: 0)
             }
             self.chats = tempChats
+            self.tempChats = tempChats
             completion()
         }
     }

+ 41 - 6
NexilisLite/NexilisLite/Source/View/Chat/EditorGroup.swift

@@ -2000,10 +2000,10 @@ public class EditorGroup: UIViewController, CLLocationManagerDelegate {
                     if res2.verdict == .sanitized {
                         isSanitizedHtml = true
                     }
-                    if let clean2 = res.data, let str2 = String(data: clean, encoding: .utf8) {
+                    if let str2 = String(data: clean, encoding: .utf8), isSanitizedHtml {
                         message_text = str2
                     }
-                } else {
+                } else if isSanitizedText {
                     message_text = str
                 }
             }
@@ -2018,7 +2018,7 @@ public class EditorGroup: UIViewController, CLLocationManagerDelegate {
             
             if !protectionType.isEmpty {
                 DispatchQueue.main.async {
-                    self.view.makeToast("Your message is protected with sanitized \(protectionType) (Message Guard)".localized(), duration: 3)
+                    self.view.makeToast("Your message is protected with sanitized \(protectionType) (Message Guard)".localized(), duration: 3, position: .center)
                 }
             }
         }
@@ -3182,6 +3182,15 @@ extension EditorGroup: UITextViewDelegate, CustomTextViewPasteDelegate {
                             }
                         }
                     }
+                    if "GPT SmartBot".lowercased().contains(text.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()) || text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
+                        let gptUser = User(pin: "-997",
+                                        firstName: "GPT SmartBot",
+                                        lastName: "",
+                                        thumb: "",
+                                        userType: "0",
+                                        official: "1")
+                        listMentionWithText.insert(gptUser, at: 0)
+                    }
                     cursor.close()
                 }
                 listMentionWithText.removeAll(where: { listMentionInTextField.contains($0) })
@@ -4248,6 +4257,22 @@ extension EditorGroup: UIContextMenuInteractionDelegate {
                                 lastTextLength = oldTextForTextview.count
                             }
                             cursor.close()
+                        } else if pinRes == "-997" {
+                            let gptUser = User(pin: "-997",
+                                            firstName: "GPT SmartBot",
+                                            lastName: "",
+                                            thumb: "",
+                                            userType: "0",
+                                            official: "1")
+                            var indexAt = 0
+                            if let range = oldTextForTextview.range(of: result) {
+                                indexAt = oldTextForTextview.distance(from: oldTextForTextview.startIndex, to: range.lowerBound)
+                            }
+                            gptUser.ex_block = "\(indexAt + gptUser.fullName.count)"
+                            listMentionWithText.append(gptUser)
+                            listMentionInTextField.append(gptUser)
+                            oldTextForTextview = oldTextForTextview.replacingOccurrences(of: result, with: "@\(gptUser.fullName)")
+                            lastTextLength = oldTextForTextview.count
                         }
                     } catch {
                         rollback.pointee = true
@@ -5315,9 +5340,19 @@ extension EditorGroup: UITableViewDelegate, UITableViewDataSource, AVAudioPlayer
             content.imageProperties.tintColor = .black
             content.imageProperties.maximumSize = CGSize(width: 24, height: 24)
             if indexPath.row < listMentionWithText.count {
-                getImage(name: listMentionWithText[indexPath.row].thumb, placeholderImage: UIImage(systemName: "person"), isCircle: true, tableView: tableView, indexPath: indexPath, completion: { result, isDownloaded, image in
-                    content.image = image
-                })
+                if listMentionWithText[indexPath.row].pin == "-997" {
+                    if let urlGif = Bundle.resourceBundle(for: Nexilis.self).url(forResource: "pb_gpt_bot", withExtension: "gif"), let data = try? Data(contentsOf: urlGif), let source = CGImageSourceCreateWithData(data as CFData, nil), let cgImage = CGImageSourceCreateImageAtIndex(source, 0, nil) {
+                        let staticImage = UIImage(cgImage: cgImage)
+                        content.image = staticImage.circleMasked
+                    } else if let urlGif = Bundle.resourcesMediaBundle(for: Nexilis.self).url(forResource: "pb_gpt_bot", withExtension: "gif"), let data = try? Data(contentsOf: urlGif), let source = CGImageSourceCreateWithData(data as CFData, nil), let cgImage = CGImageSourceCreateImageAtIndex(source, 0, nil) {
+                        let staticImage = UIImage(cgImage: cgImage)
+                        content.image = staticImage.circleMasked
+                    }
+                } else {
+                    getImage(name: listMentionWithText[indexPath.row].thumb, placeholderImage: UIImage(systemName: "person"), isCircle: true, tableView: tableView, indexPath: indexPath, completion: { result, isDownloaded, image in
+                        content.image = image
+                    })
+                }
                 content.text = listMentionWithText[indexPath.row].firstName + " " + listMentionWithText[indexPath.row].lastName
             }
             cellMention.contentConfiguration = content

+ 499 - 24
NexilisLite/NexilisLite/Source/View/Chat/EditorPersonal.swift

@@ -38,6 +38,9 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
     @IBOutlet weak var constraintLeftTextField: NSLayoutConstraint!
     @IBOutlet weak var constraintBottomTableViewWithTextfield: NSLayoutConstraint!
     @IBOutlet weak var viewAttachment: UIStackView!
+    @IBOutlet weak var tableMention: UITableView!
+    @IBOutlet weak var heightTableMention: NSLayoutConstraint!
+    @IBOutlet weak var contraintBottomMention: NSLayoutConstraint!
     public var dataPerson: [String: String?] = [:]
     var dataMessages: [[String: Any?]] = []
     var dataDates: [String] = []
@@ -104,9 +107,16 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
     var multipleOffsetUp = 1
     var lastOffsetDown = 1
     var gettingDataMessage = true
+    var keyboardHeightForMention: CGFloat?
+    var listMentionWithText:[User] = []
+    var listMentionInTextField:[User] = []
+    var tempListMentionWithText:[User] = []
+    var tempListMentionInTextField:[User] = []
     var showingLink = ""
     var isAlwaysHideLinkPreview = false
     var timerCheckLink: Timer?
+    var lastPositionCursorMention = 0
+    var lastTextLength = 0
     var timerFakeProgress: Timer?
     var showMenuContext = false
     var touchedSubview = UIView()
@@ -144,6 +154,9 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
     var specFileString = ""
     var contextCC = ""
     
+    var tableMentionEdit = UITableView()
+    var heightTableEditMention: NSLayoutConstraint!
+    
     func offset() -> CGFloat{
         guard let fontSize = Int(SecureUserDefaults.shared.value(forKey: "font_size") ?? "0") else { return 0 }
         return CGFloat(fontSize)
@@ -306,6 +319,11 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
             dataMessageForward = nil
         }
         
+        tableMention.register(UITableViewCell.self, forCellReuseIdentifier: "cellMention")
+        tableMention.dataSource = self
+        tableMention.delegate = self
+        tableMention.contentInset = UIEdgeInsets(top: -25, left: 0, bottom: 0, right: 0)
+        
         if isContactCenter && !isRequestContactCenter && !onGoingCC {
             var companyName = ""
             Database.shared.database?.inTransaction({ fmdb, rollback in
@@ -662,8 +680,22 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
                        let dataJson = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: String] {
                         let last_m = dataJson["text"] ?? ""
                         let last_r = dataJson["reffId"] ?? ""
+                        let list_m = dataJson["list_mention"] as? [[String: String]] ?? []
+                        
+                        if list_m.count > 0 {
+                            for list in list_m {
+                                let f_pin = list["f_pin_mention"] ?? ""
+                                let upper = list["upper"] ?? ""
+                                let userFromBuddy = User.getData(pin: f_pin, lPin: l_pin)
+                                if userFromBuddy != nil {
+                                    userFromBuddy!.ex_block = upper
+                                    listMentionInTextField.append(userFromBuddy!)
+                                }
+                            }
+                        }
+                        
                         if !last_m.isEmpty {
-                            textFieldSend.attributedText = last_m.richText(isEditing: true)
+                            textFieldSend.attributedText = last_m.richText(isEditing: true, listMentionInTextField: listMentionInTextField)
                             textFieldSend.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : UIColor.black
                         }
                         
@@ -964,7 +996,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
     private func addDataMessage() {
         multipleOffsetUp += 1
         let queryCount = "SELECT COUNT(*) FROM MESSAGE where (f_pin='\(dataPerson["f_pin"]!!)' or l_pin='\(dataPerson["f_pin"]!!)') AND (message_scope_id = '\(MessageScope.WHISPER)' OR message_scope_id = '\(MessageScope.FORM)' OR message_scope_id = '\(MessageScope.CALL)' OR message_scope_id = '\(MessageScope.MISSED_CALL)') AND is_call_center = 0"
-        let query = "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared, blog_id, credential, is_call_center, call_center_id, opposite_pin, last_edited, gif_id, is_forwarded_message, attachment_speciality, is_pinned FROM MESSAGE where (f_pin='\(dataPerson["f_pin"]!!)' or l_pin='\(dataPerson["f_pin"]!!)') AND (message_scope_id = '\(MessageScope.WHISPER)' OR message_scope_id = '\(MessageScope.FORM)' OR message_scope_id = '\(MessageScope.CALL)' OR message_scope_id = '\(MessageScope.MISSED_CALL)') AND is_call_center = 0 order by server_date asc LIMIT CASE WHEN (\(queryCount))-\(dataMessages.count)>=20 THEN 20*\(multipleOffsetUp-1) ELSE (\(queryCount))-\(dataMessages.count) END OFFSET CASE WHEN (\(queryCount))>=\(20*multipleOffsetUp) THEN (\(queryCount))-\(20*multipleOffsetUp) ELSE 0 END"
+        let query = "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared, blog_id, credential, is_call_center, call_center_id, opposite_pin, last_edited, gif_id, is_forwarded_message, attachment_speciality, is_pinned, is_bot FROM MESSAGE where (f_pin='\(dataPerson["f_pin"]!!)' or l_pin='\(dataPerson["f_pin"]!!)') AND (message_scope_id = '\(MessageScope.WHISPER)' OR message_scope_id = '\(MessageScope.FORM)' OR message_scope_id = '\(MessageScope.CALL)' OR message_scope_id = '\(MessageScope.MISSED_CALL)') AND is_call_center = 0 order by server_date asc LIMIT CASE WHEN (\(queryCount))-\(dataMessages.count)>=20 THEN 20*\(multipleOffsetUp-1) ELSE (\(queryCount))-\(dataMessages.count) END OFFSET CASE WHEN (\(queryCount))>=\(20*multipleOffsetUp) THEN (\(queryCount))-\(20*multipleOffsetUp) ELSE 0 END"
         Database.shared.database?.inTransaction({ (fmdb, rollback) in
             do {
                 if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: query) {
@@ -999,6 +1031,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
                         row[TypeDataMessage.is_forwarded] = Int(cursorData.int(forColumnIndex: 25))
                         row[TypeDataMessage.spec_file] = cursorData.string(forColumnIndex: 26)
                         row[TypeDataMessage.is_pinned] = cursorData.string(forColumnIndex: 27)
+                        row[TypeDataMessage.is_bot] = cursorData.string(forColumnIndex: 28)
                         if let cursorStatus = Database.shared.getRecords(fmdb: fmdb, query: "SELECT status FROM MESSAGE_STATUS WHERE message_id='\(row["message_id"]  as? String ?? "")'") {
                             while cursorStatus.next() {
                                 row["status"] = cursorStatus.string(forColumnIndex: 0)
@@ -1110,7 +1143,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
     private func getData(offset: Int64 = 0) {
 //        let queryCount = "SELECT COUNT(*) FROM MESSAGE where (f_pin='\(dataPerson["f_pin"]!!)' or l_pin='\(dataPerson["f_pin"]!!)') AND (message_scope_id = '3' OR message_scope_id = '18') AND is_call_center = 0"
 //        var query = "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared, blog_id, credential FROM MESSAGE where (f_pin='\(dataPerson["f_pin"]!!)' or l_pin='\(dataPerson["f_pin"]!!)') AND (message_scope_id = '3' OR message_scope_id = '18') AND is_call_center = 0 order by server_date asc LIMIT CASE WHEN (\(queryCount))-\(dataMessages.count)>=20 THEN 20 ELSE (\(queryCount))-\(dataMessages.count) END OFFSET CASE WHEN (\(queryCount))>=\(20*multipleOffsetUp) THEN (\(queryCount))-\(20*multipleOffsetUp) ELSE 0 END"
-        var query = "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared, blog_id, credential, is_call_center, call_center_id, opposite_pin, last_edited, gif_id, is_forwarded_message, attachment_speciality, is_pinned FROM MESSAGE where (f_pin='\(dataPerson["f_pin"]!!)' or l_pin='\(dataPerson["f_pin"]!!)') AND (message_scope_id = '\(MessageScope.WHISPER)' OR message_scope_id = '\(MessageScope.FORM)' OR message_scope_id = '\(MessageScope.CALL)' OR message_scope_id = '\(MessageScope.MISSED_CALL)') AND is_call_center = 0 order by server_date asc LIMIT -1 OFFSET \(offset)"
+        var query = "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared, blog_id, credential, is_call_center, call_center_id, opposite_pin, last_edited, gif_id, is_forwarded_message, attachment_speciality, is_pinned, is_bot FROM MESSAGE where (f_pin='\(dataPerson["f_pin"]!!)' or l_pin='\(dataPerson["f_pin"]!!)') AND (message_scope_id = '\(MessageScope.WHISPER)' OR message_scope_id = '\(MessageScope.FORM)' OR message_scope_id = '\(MessageScope.CALL)' OR message_scope_id = '\(MessageScope.MISSED_CALL)') AND is_call_center = 0 order by server_date asc LIMIT -1 OFFSET \(offset)"
         if isContactCenter {
             if complaintId.isEmpty {
                 query = "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared FROM MESSAGE where (f_pin='\(dataPerson["f_pin"]!!)' or l_pin='\(dataPerson["f_pin"]!!)') AND message_scope_id = '\(MessageScope.CHATROOM)' AND broadcast_flag = 0 AND is_call_center = 1 order by server_date asc LIMIT -1 OFFSET \(offset)"
@@ -1180,6 +1213,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
                         row[TypeDataMessage.is_forwarded] = Int(cursorData.int(forColumnIndex: 25))
                         row[TypeDataMessage.spec_file] = cursorData.string(forColumnIndex: 26) ?? ""
                         row[TypeDataMessage.is_pinned] = cursorData.string(forColumnIndex: 27) ?? ""
+                        row[TypeDataMessage.is_bot] = Int (cursorData.string(forColumnIndex: 28) ?? "0")
                         if let cursorStatus = Database.shared.getRecords(fmdb: fmdb, query: "SELECT status FROM MESSAGE_STATUS WHERE message_id='\(row["message_id"] as? String ?? "")'") {
                             while cursorStatus.next() {
                                 row["status"] = cursorStatus.string(forColumnIndex: 0)
@@ -1772,6 +1806,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
                     row["is_stared"] = "0"
                     row[TypeDataMessage.spec_file] = chatData[CoreMessage_TMessageKey.ATTACHMENT_SPECIALITY]
                     row[TypeDataMessage.is_forwarded] = Int(chatData[CoreMessage_TMessageKey.IS_FORWARDED_MESSAGE] ?? "0")
+                    row[TypeDataMessage.is_bot] = Int(chatData[CoreMessage_TMessageKey.IS_BOT] ?? "0")
                     row["isSelected"] = false
                     if !self.dataDates.contains("Today".localized()) {
                         self.dataDates.append("Today".localized())
@@ -2029,7 +2064,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
     private func appendNewMessage(messageId: String) {
         var row: [String: Any?] = [:]
         Database.shared.database?.inTransaction({ (fmdb, rollback) in
-            if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared, blog_id, credential, is_call_center, call_center_id, opposite_pin, last_edited, gif_id, is_forwarded_message, attachment_speciality, is_pinned from MESSAGE where message_id = '\(messageId)'"), cursorData.next() {
+            if let cursorData = Database.shared.getRecords(fmdb: fmdb, query: "SELECT message_id, f_pin, l_pin, message_scope_id, server_date, status, message_text, audio_id, video_id, image_id, thumb_id, read_receipts, chat_id, file_id, attachment_flag, reff_id, lock, is_stared, blog_id, credential, is_call_center, call_center_id, opposite_pin, last_edited, gif_id, is_forwarded_message, attachment_speciality, is_pinned, is_bot from MESSAGE where message_id = '\(messageId)'"), cursorData.next() {
                 row["message_id"] = cursorData.string(forColumnIndex: 0)
                 row["f_pin"] = cursorData.string(forColumnIndex: 1)
                 row["l_pin"] = cursorData.string(forColumnIndex: 2)
@@ -2058,6 +2093,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
                 row[TypeDataMessage.is_forwarded] = Int(cursorData.int(forColumnIndex: 25))
                 row[TypeDataMessage.spec_file] = cursorData.string(forColumnIndex: 26)
                 row[TypeDataMessage.is_pinned] = cursorData.string(forColumnIndex: 27)
+                row[TypeDataMessage.is_bot] = Int (cursorData.string(forColumnIndex: 28) ?? "0")
                 row["progress"] = 0.0
                 row["isSelected"] = false
                 row["chat_date"] = "Today".localized()
@@ -2630,7 +2666,17 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
         self.removeFromParent()
         if !self.isContactCenter {
             let l_pin = self.dataPerson["f_pin"]!!
-            let data: [String: String] = ["text": self.textFieldSend.textColor != UIColor.lightGray ? self.textFieldSend.text! : "", "reffId": self.reffId ?? ""]
+            var data: [String: Any] = ["text": self.textFieldSend.textColor != UIColor.lightGray ? self.textFieldSend.text! : "", "reffId": self.reffId ?? ""]
+            if listMentionInTextField.count > 0 {
+                var dataMention: [[String: String]] = []
+                for list in listMentionInTextField {
+                    var dataTemp: [String: String] = [:]
+                    dataTemp["f_pin_mention"] = list.pin
+                    dataTemp["upper"] = list.ex_block
+                    dataMention.append(dataTemp)
+                }
+                data["list_mention"] = dataMention
+            }
             if let jsonData = try? JSONSerialization.data(withJSONObject: data, options: []),
                let jsonString = String(data: jsonData, encoding: .utf8) {
                 SecureUserDefaults.shared.set(jsonString, forKey: "new_saved_\(l_pin)")
@@ -2691,6 +2737,10 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
             self.constraintViewTextField.constant = 0
             self.constraintBottomAttachment.constant = 0
             self.constraintBottomContainerMultpileSelectSession.constant = 0
+            if self.contraintBottomMention.constant > 0 {
+                self.contraintBottomMention.constant = 25 + constraintBottomAttachment.constant + self.heightTextFieldSend.constant + self.viewTextfield.bounds.height
+            }
+            keyboardHeightForMention = nil
             UIView.animate(withDuration: TimeInterval(duration), animations: {
                 self.view.layoutIfNeeded()
             })
@@ -2714,6 +2764,10 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
             if self.constraintBottomAttachment.constant != keyboardHeight || self.constraintViewTextField.constant != keyboardHeight - 60 {
 //                self.constraintViewTextField.constant = keyboardHeight - 60
                 self.constraintBottomAttachment.constant = keyboardHeight
+                if self.contraintBottomMention.constant > 0 {
+                    self.contraintBottomMention.constant = 25 + constraintBottomAttachment.constant + self.heightTextFieldSend.constant + self.viewTextfield.bounds.height
+                }
+                self.keyboardHeightForMention = keyboardHeight
                 if isSearching {
                     self.constraintBottomContainerMultpileSelectSession.constant = -keyboardHeight
                 }
@@ -2812,7 +2866,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
         if isContactCenter {
             opposite_pin = ""
         } else {
-            opposite_pin = idMe ?? ""
+            opposite_pin = l_pin
         }
         var credential = credential
         if isConfidential {
@@ -2822,6 +2876,37 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
         if isAck {
             read_receipts = "8"
         }
+        if message_text.contains("@") && listMentionInTextField.count > 0 {
+            var diff: Int = 0
+            for i in 0..<listMentionInTextField.count {
+                let mention = listMentionInTextField[i]
+                guard let exBlockStr = mention.ex_block, let exBlock = Int(exBlockStr) else {
+                    continue // skip if ex_block is nil or not an integer
+                }
+                let nameWithMention = ("@" + mention.fullName).trimmingCharacters(in: .whitespaces)
+                let pinString = "@\(mention.pin)"
+                let upperBound = exBlock + diff
+                let lowerBound = upperBound - nameWithMention.count + 1
+                guard lowerBound >= 0, upperBound < message_text.count else {
+                    continue // prevent index out-of-range
+                }
+                var afterMention = ""
+                let nextCharIndex = message_text.index(message_text.startIndex, offsetBy: upperBound + 1, limitedBy: message_text.endIndex)
+                if let index = nextCharIndex, index < message_text.endIndex {
+                    let nextChar = message_text[index]
+                    if nextChar != "\n" && nextChar != " " {
+                        afterMention = " "
+                    }
+                }
+                let startIndex = message_text.index(message_text.startIndex, offsetBy: lowerBound)
+                let endIndex = message_text.index(message_text.startIndex, offsetBy: upperBound + 1)
+                let range = startIndex..<endIndex
+                if message_text[range] == nameWithMention {
+                    message_text.replaceSubrange(range, with: pinString + afterMention)
+                    diff += (pinString + afterMention).count - nameWithMention.count
+                }
+            }
+        }
         var is_secret = is_secret
         if isSecret {
             is_secret = 1
@@ -2840,10 +2925,10 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
                     if res2.verdict == .sanitized {
                         isSanitizedHtml = true
                     }
-                    if let clean2 = res.data, let str2 = String(data: clean, encoding: .utf8) {
+                    if let str2 = String(data: clean, encoding: .utf8), isSanitizedHtml {
                         message_text = str2
                     }
-                } else {
+                } else if isSanitizedText {
                     message_text = str
                 }
             }
@@ -2858,7 +2943,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
             
             if !protectionType.isEmpty {
                 DispatchQueue.main.async {
-                    self.view.makeToast("Your message is protected with sanitized \(protectionType) (Message Guard)".localized(), duration: 3)
+                    self.view.makeToast("Your message is protected with sanitized \(protectionType) (Message Guard)".localized(), duration: 3, position: .center)
                 }
             }
             
@@ -2900,6 +2985,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
         row[TypeDataMessage.opposite_pin] = opposite_pin
         row[TypeDataMessage.spec_file] = specFileString
         specFileString = ""
+        lastTextLength = 0
         if !dataDates.contains("Today".localized()) {
             dataDates.append("Today".localized())
             tableChatView.insertSections(IndexSet(integer: dataDates.count - 1), with: .none)
@@ -2954,6 +3040,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
         }
         deleteReplyView()
         deleteLinkPreview()
+        listMentionInTextField.removeAll()
         NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadTabChats"), object: nil, userInfo: nil)
         self.tableChatView.scrollToBottom()
         if self.markerCounter != nil {
@@ -4282,6 +4369,31 @@ extension EditorPersonal: UITextViewDelegate, CustomTextViewPasteDelegate {
     }
     
     public func textViewDidChangeSelection(_ textView: UITextView) {
+        lastPositionCursorMention = textView.selectedRange.location
+        var isShowMention = false
+
+        let fulltextForMention = textView.text.prefix(lastPositionCursorMention)
+        let lines = fulltextForMention.split(separator: "\n")
+        if let lastLineIndex = lines.lastIndex(where: { !$0.isEmpty }) {
+            let words = lines[lastLineIndex].split(separator: " ")
+            if let lastWordIndex = words.lastIndex(where: { !$0.isEmpty }) {
+                let mentionText = words[lastWordIndex]
+                let lastChar = fulltextForMention.last
+                if lastChar != "\n" && lastChar != " " {
+                    if mentionText.starts(with: "@") || (mentionText.count >= 2 && (self.textFieldSend.textColor != UIColor.lightGray || heightTableEditMention != nil) && extractFromAtIfSymbolsBefore(String(mentionText)) == nil) {
+                        showMention(text: mentionText.starts(with: "@") ? String(mentionText.dropFirst()) : String(mentionText))
+                        isShowMention = true
+                    } else if let textM = extractFromAtIfSymbolsBefore(String(mentionText)) {
+                        showMention(text: String(textM.dropFirst()))
+                        isShowMention = true
+                    }
+                }
+            }
+        }
+        
+        if !isShowMention {
+            hideMention()
+        }
         if var nowTextFieldSend = self.textFieldSend {
             if isEditingMessage {
                 nowTextFieldSend = editTextView
@@ -4342,7 +4454,6 @@ extension EditorPersonal: UITextViewDelegate, CustomTextViewPasteDelegate {
         let cursorPositionIndent = textView.selectedRange.location
 
         // Prevent moving cursor before the 2-space indent
-        let lines = text.components(separatedBy: "\n")
         var adjustedCursorPosition = cursorPositionIndent
         
         for line in lines {
@@ -4364,6 +4475,21 @@ extension EditorPersonal: UITextViewDelegate, CustomTextViewPasteDelegate {
         }
     }
     
+    func extractFromAtIfSymbolsBefore(_ text: String) -> String? {
+        guard let atIndex = text.firstIndex(of: "@") else {
+            return nil
+        }
+        
+        let beforeAt = text[..<atIndex]
+        let afterAt = text[atIndex...]
+
+        // Define symbols as anything that's not a letter or digit
+        let symbolSet = CharacterSet.letters.union(.decimalDigits).inverted
+        let isAllSymbols = beforeAt.unicodeScalars.allSatisfy { symbolSet.contains($0) }
+
+        return isAllSymbols ? String(afterAt) : nil
+    }
+    
     public func textViewDidChange(_ textView: UITextView) {
         if textView.text.count == 0 {
             isAlwaysHideLinkPreview = false
@@ -4387,6 +4513,26 @@ extension EditorPersonal: UITextViewDelegate, CustomTextViewPasteDelegate {
         let text = textView.text ?? ""
         let cursorPosition = textView.selectedRange.location
         
+        let tempListMention = listMentionInTextField
+        if listMentionInTextField.count > 0 {
+            for j in 0..<listMentionInTextField.count {
+                var index = j
+                if tempListMention.count != listMentionInTextField.count {
+                    index = j - (tempListMention.count - listMentionInTextField.count)
+                }
+                var upper = (Int(listMentionInTextField[index].ex_block ?? "0") ?? 0)
+                if cursorPosition <= upper {
+                    upper += text.count - lastTextLength
+                    listMentionInTextField[index].ex_block = "\(upper)"
+                }
+                let lower = upper - listMentionInTextField[index].fullName.count
+                let name = listMentionInTextField[index].fullName.trimmingCharacters(in: .whitespaces)
+                if textView.text.substring(from: lower, to: upper) != "@\(name)" {
+                    listMentionInTextField.remove(at: index)
+                }
+            }
+        }
+        
         // Handle Bullets (- [space] + letter → • )
         let bulletPattern = #"(?<=\n|^)- (\S)"#
         if let match = text.range(of: bulletPattern, options: .regularExpression) {
@@ -4418,6 +4564,72 @@ extension EditorPersonal: UITextViewDelegate, CustomTextViewPasteDelegate {
         }
         
         handleRichText(textView)
+        lastTextLength = text.count
+    }
+    
+    private func showMention(text: String) {
+        if self.contraintBottomMention.constant < 0 {
+            if !isEditingMessage {
+                self.contraintBottomMention.constant = 25 + constraintBottomAttachment.constant + self.heightTextFieldSend.constant + self.viewTextfield.bounds.height
+                UIView.animate(withDuration: 0.5, animations: {
+                    self.view.layoutIfNeeded()
+                })
+            }
+        }
+        listMentionWithText.removeAll()
+        Database.shared.database?.inTransaction({ fmdb, rollback in
+            do {
+                if "GPT SmartBot".lowercased().contains(text.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()) || text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
+                    let gptUser = User(pin: "-997",
+                                    firstName: "GPT SmartBot",
+                                    lastName: "",
+                                    thumb: "",
+                                    userType: "0",
+                                    official: "1")
+                    listMentionWithText.insert(gptUser, at: 0)
+                }
+                listMentionWithText.removeAll(where: { listMentionInTextField.contains($0) })
+                var nowTableMention = tableMention!
+                var nowHeightTableMention = heightTableMention!
+                if isEditingMessage {
+                    nowTableMention = tableMentionEdit
+                    if heightTableEditMention != nil {
+                        nowHeightTableMention = heightTableEditMention
+                    } else {
+                        return
+                    }
+                }
+                if listMentionWithText.count > 0 {
+                    if listMentionWithText.count < 5 {
+                        nowHeightTableMention.constant = CGFloat(44 * listMentionWithText.count)
+                    } else {
+                        nowHeightTableMention.constant = 44 * 4
+                    }
+                    nowTableMention.reloadData()
+                } else {
+                    nowHeightTableMention.constant = 44
+                    self.hideMention()
+                }
+            } catch {
+                rollback.pointee = true
+                print("Access database error: \(error.localizedDescription)")
+            }
+        })
+    }
+    
+    private func hideMention() {
+        if self.contraintBottomMention.constant > 0 {
+            listMentionWithText.removeAll()
+            tableMention.reloadData()
+            self.contraintBottomMention.constant = 0 - self.heightTableMention.constant
+            UIView.animate(withDuration: 0.5, animations: {
+                self.view.layoutIfNeeded()
+            })
+        } else if self.heightTableEditMention != nil && self.heightTableEditMention.constant != 0 {
+            listMentionWithText.removeAll()
+            tableMentionEdit.reloadData()
+            self.heightTableEditMention.constant = 0
+        }
     }
     
     private func checkLink(fullText: String) {
@@ -4565,6 +4777,9 @@ extension EditorPersonal: UITextViewDelegate, CustomTextViewPasteDelegate {
         if !self.viewTextfield.subviews.contains(self.containerLink){
             UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseInOut, animations: {
                 self.constraintTopTextField.constant = self.constraintTopTextField.constant + 80
+                if self.contraintBottomMention.constant > 0 {
+                    self.contraintBottomMention.constant = self.contraintBottomMention.constant + 80 + self.heightTextFieldSend.constant
+                }
             }, completion: nil)
         }
         
@@ -4664,6 +4879,38 @@ extension EditorPersonal: UITextViewDelegate, CustomTextViewPasteDelegate {
     }
     
     public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
+        if listMentionInTextField.count > 0 {
+            for i in 0..<listMentionInTextField.count {
+                if lastPositionCursorMention == Int(listMentionInTextField[i].ex_block!)! + 1 {
+                    let fulltextForMention = textView.text.substring(from: 0, to: lastPositionCursorMention - 1)
+                    let diff = textView.text.count - fulltextForMention.count
+                    var text = textView.text ?? ""
+                    let nameMention = listMentionInTextField[i].fullName.trimmingCharacters(in: .whitespaces)
+                    let rangeReplacement = NSRange(location: lastPositionCursorMention - nameMention.count - 1, length: nameMention.count + 1)
+                    let replacementText = ""
+                    
+                    let copyAttributedText = text.richText(isEditing: true, listMentionInTextField: listMentionInTextField)
+                    copyAttributedText.removeAttribute(.foregroundColor, range: rangeReplacement)
+                    
+                    textView.attributedText = copyAttributedText
+
+                    // Replace the old text with the new text using the replaceSubrange(_:with:) method
+                    if let startIndex = text.index(text.startIndex, offsetBy: rangeReplacement.location, limitedBy: text.endIndex),
+                       let endIndex = text.index(startIndex, offsetBy: rangeReplacement.length, limitedBy: text.endIndex) {
+                        text.replaceSubrange(startIndex..<endIndex, with: replacementText)
+                    }
+                    listMentionInTextField.remove(at: i)
+                    
+                    textView.attributedText = text.richText(isEditing: true, listMentionInTextField: listMentionInTextField)
+                    
+                    let newPosition = textView.position(from: textView.beginningOfDocument, offset: textView.text.count - diff)
+                    textView.selectedTextRange = textView.textRange(from: newPosition!, to: newPosition!)
+                    textViewDidChangeSelection(textView)
+                    handleRichText(textView)
+                    return false
+                }
+            }
+        }
         let indent = handleIndent(textView, range, text)
         if !indent {
             handleRichText(textView)
@@ -4740,7 +4987,7 @@ extension EditorPersonal: UITextViewDelegate, CustomTextViewPasteDelegate {
     
     private func handleRichText(_ textView: UITextView) {
         textView.preserveCursorPosition(withChanges: { _ in
-            textView.attributedText = textView.text.richText(isEditing: true)
+            textView.attributedText = textView.text.richText(isEditing: true, listMentionInTextField: self.listMentionInTextField)
             return .preserveCursor
         })
     }
@@ -5323,8 +5570,72 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
     }
     
     func showEditMessageView(at indexPath: IndexPath) {
+        tempListMentionWithText = listMentionWithText
+        tempListMentionInTextField = listMentionInTextField
+        listMentionWithText.removeAll()
+        listMentionInTextField.removeAll()
         let dataMessages = self.dataMessages.filter({ $0["chat_date"]  as? String ?? "" == dataDates[indexPath.section]})
         let oldText = dataMessages[indexPath.row][TypeDataMessage.message_text]  as? String ?? ""
+        var oldTextForTextview = oldText
+        let pattern = "@[\\w]+"
+        do {
+            let regex = try NSRegularExpression(pattern: pattern)
+            let nsrange = NSRange(oldText.startIndex..., in: oldText)
+            let matches = regex.matches(in: oldText, range: nsrange)
+            
+            let results = matches.map {
+                String(oldText[Range($0.range, in: oldText)!])
+            }
+            for result in results {
+                let pinRes = result.components(separatedBy: "@")[1]
+                Database.shared.database?.inTransaction({ fmdb, rollback in
+                    do {
+                        if let cursor = Database.shared.getRecords(fmdb: fmdb, query: "SELECT f_pin, first_name || ' ' || ifnull(last_name, '') name FROM GROUPZ_MEMBER where f_pin = '\(pinRes)'"), cursor.next() {
+                            let user = User(pin: "")
+                            user.pin = cursor.string(forColumnIndex: 0) ?? ""
+                            user.firstName = cursor.string(forColumnIndex: 1) ?? ""
+                            if !user.pin.isEmpty {
+                                var fixUser = User.getDataCanNil(pin: user.pin, fmdb: fmdb)
+                                if fixUser == nil {
+                                    fixUser = user
+                                }
+                                var indexAt = 0
+                                if let range = oldTextForTextview.range(of: result) {
+                                    indexAt = oldTextForTextview.distance(from: oldTextForTextview.startIndex, to: range.lowerBound)
+                                }
+                                fixUser?.ex_block = "\(indexAt + fixUser!.fullName.count)"
+                                listMentionWithText.append(fixUser!)
+                                listMentionInTextField.append(fixUser!)
+                                oldTextForTextview = oldTextForTextview.replacingOccurrences(of: result, with: "@\(fixUser!.fullName)")
+                                lastTextLength = oldTextForTextview.count
+                            }
+                            cursor.close()
+                        } else if pinRes == "-997" {
+                            let gptUser = User(pin: "-997",
+                                            firstName: "GPT SmartBot",
+                                            lastName: "",
+                                            thumb: "",
+                                            userType: "0",
+                                            official: "1")
+                            var indexAt = 0
+                            if let range = oldTextForTextview.range(of: result) {
+                                indexAt = oldTextForTextview.distance(from: oldTextForTextview.startIndex, to: range.lowerBound)
+                            }
+                            gptUser.ex_block = "\(indexAt + gptUser.fullName.count)"
+                            listMentionWithText.append(gptUser)
+                            listMentionInTextField.append(gptUser)
+                            oldTextForTextview = oldTextForTextview.replacingOccurrences(of: result, with: "@\(gptUser.fullName)")
+                            lastTextLength = oldTextForTextview.count
+                        }
+                    } catch {
+                        rollback.pointee = true
+                        print("Access database error: \(error.localizedDescription)")
+                    }
+                })
+            }
+        } catch {
+            print("Invalid regex pattern")
+        }
         editVC = UIViewController()
         if let view = editVC.view {
             view.backgroundColor = .clear
@@ -5359,7 +5670,7 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
             constraintHeighteditTextView = editTextView.heightAnchor.constraint(equalToConstant: 40)
             constraintBottomeditTextView.isActive = true
             constraintHeighteditTextView.isActive = true
-            editTextView.attributedText = oldText.richText(isEditing: true)
+            editTextView.attributedText = oldText.richText(isEditing: true, listMentionInTextField: listMentionInTextField)
             editTextView.becomeFirstResponder()
             
             buttonSendEdit.setImage(resizeImage(image: self.traitCollection.userInterfaceStyle == .dark ? UIImage(named: "Send-(White)", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!.withTintColor(.blackDarkMode) : UIImage(named: "Send-(White)", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withRenderingMode(.alwaysOriginal), for: .normal)
@@ -5367,7 +5678,38 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
             buttonSendEdit.isEnabled = true
             buttonSendEdit.actionHandle(controlEvents: .touchUpInside,
              ForAction:{() -> Void in
-                let newText = self.editTextView.text ?? ""
+                var newText = self.editTextView.text ?? ""
+                if newText.contains("@") && self.listMentionInTextField.count > 0 {
+                    var diff: Int = 0
+                    for i in 0..<self.listMentionInTextField.count {
+                        let mention = self.listMentionInTextField[i]
+                        guard let exBlockStr = mention.ex_block, let exBlock = Int(exBlockStr) else {
+                            continue // skip if ex_block is nil or not an integer
+                        }
+                        let nameWithMention = ("@" + mention.firstName + " " + mention.lastName).trimmingCharacters(in: .whitespaces)
+                        let pinString = "@\(mention.pin)"
+                        let upperBound = exBlock + diff
+                        let lowerBound = upperBound - nameWithMention.count + 1
+                        guard lowerBound >= 0, upperBound < newText.count else {
+                            continue // prevent index out-of-range
+                        }
+                        var afterMention = ""
+                        let nextCharIndex = newText.index(newText.startIndex, offsetBy: upperBound + 1, limitedBy: newText.endIndex)
+                        if let index = nextCharIndex, index < newText.endIndex {
+                            let nextChar = newText[index]
+                            if nextChar != "\n" && nextChar != " " {
+                                afterMention = " "
+                            }
+                        }
+                        let startIndex = newText.index(newText.startIndex, offsetBy: lowerBound)
+                        let endIndex = newText.index(newText.startIndex, offsetBy: upperBound + 1)
+                        let range = startIndex..<endIndex
+                        if newText[range] == nameWithMention {
+                            newText.replaceSubrange(range, with: pinString + afterMention)
+                            diff += (pinString + afterMention).count - nameWithMention.count
+                        }
+                    }
+                }
                 if !newText.isEmpty && newText.trimmingCharacters(in: .whitespacesAndNewlines) != oldText {
                     let lastEdited = Int64(Date().currentTimeMillis())
                     let message = CoreMessage_TMessageBank.editMessage(message_id: dataMessages[indexPath.row][TypeDataMessage.message_id]  as? String ?? "", l_pin: dataMessages[indexPath.row][TypeDataMessage.l_pin]  as? String ?? "", message_scope_id: dataMessages[indexPath.row][TypeDataMessage.message_scope_id]  as? String ?? "", status: "1", message_text: newText, credential: dataMessages[indexPath.row][TypeDataMessage.credential]  as? String ?? "", attachment_flag: dataMessages[indexPath.row][TypeDataMessage.attachment_flag]  as? String ?? "", ex_blog_id: dataMessages[indexPath.row][TypeDataMessage.blog_id]  as? String ?? "", message_large_text: "", ex_format: "", image_id: dataMessages[indexPath.row][TypeDataMessage.image_id]  as? String ?? "", audio_id: dataMessages[indexPath.row][TypeDataMessage.audio_id]  as? String ?? "", video_id: dataMessages[indexPath.row][TypeDataMessage.video_id]  as? String ?? "", file_id: dataMessages[indexPath.row][TypeDataMessage.file_id]  as? String ?? "", thumb_id: dataMessages[indexPath.row][TypeDataMessage.thumb_id]  as? String ?? "", reff_id: dataMessages[indexPath.row][TypeDataMessage.reff_id]  as? String ?? "", read_receipts: dataMessages[indexPath.row][TypeDataMessage.read_receipts]  as? String ?? "", chat_id: dataMessages[indexPath.row][TypeDataMessage.chat_id]  as? String ?? "", is_call_center: dataMessages[indexPath.row][TypeDataMessage.is_call_center]  as? String ?? "", call_center_id: dataMessages[indexPath.row][TypeDataMessage.call_center_id]  as? String ?? "", opposite_pin: dataMessages[indexPath.row][TypeDataMessage.opposite_pin]  as? String ?? "", server_date: dataMessages[indexPath.row][TypeDataMessage.server_date]  as? String ?? "", local_time_stamp: dataMessages[indexPath.row][TypeDataMessage.server_date]  as? String ?? "", last_edit: lastEdited)
@@ -5394,6 +5736,10 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
                     }
                 }
                 self.isEditingMessage = false
+                self.listMentionWithText = self.tempListMentionWithText
+                self.listMentionInTextField = self.tempListMentionWithText
+                self.lastTextLength = self.textFieldSend.text?.count ?? 0
+                self.heightTableEditMention = nil
                 self.editVC.dismiss(animated: true)
              })
             buttonSendEdit.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor
@@ -5434,6 +5780,17 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
             messageText.textColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .black
             messageText.font = .systemFont(ofSize: 12 + offset())
             messageText.attributedText = oldText.richText()
+            
+            tableMentionEdit = UITableView()
+            tableMentionEdit.register(UITableViewCell.self, forCellReuseIdentifier: "cellEditMention")
+            tableMentionEdit.dataSource = self
+            tableMentionEdit.delegate = self
+            tableMentionEdit.contentInset = UIEdgeInsets(top: -25, left: 0, bottom: 0, right: 0)
+            tableMentionEdit.backgroundColor = .white
+            view.addSubview(tableMentionEdit)
+            tableMentionEdit.anchor(left: view.leftAnchor, bottom: editTextView.topAnchor, right: view.rightAnchor)
+            heightTableEditMention = tableMentionEdit.heightAnchor.constraint(equalToConstant: 0)
+            self.heightTableEditMention.isActive = true
         }
         editVC.modalTransitionStyle = .crossDissolve
         editVC.modalPresentationStyle = .overFullScreen
@@ -5448,16 +5805,25 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
     @objc func dismissEditVC(_ sender: ObjectGesture) {
         if editTextView.text == sender.message_id {
             self.isEditingMessage = false
+            listMentionWithText = tempListMentionWithText
+            listMentionInTextField = tempListMentionWithText
+            lastTextLength = textFieldSend.text?.count ?? 0
+            heightTableEditMention = nil
             editVC.dismiss(animated: true)
         } else if self.isEditingMessage {
             let alert = LibAlertController(title: "".localized(), message: "Discard edit?".localized(), preferredStyle: .alert)
             alert.addAction(UIAlertAction(title: "Cancel".localized(), style: UIAlertAction.Style.cancel, handler: nil))
             alert.addAction(UIAlertAction(title: "Discard".localized(), style: UIAlertAction.Style.default, handler: {(_) in
                 self.isEditingMessage = false
+                self.listMentionWithText = self.tempListMentionWithText
+                self.listMentionInTextField = self.tempListMentionWithText
+                self.lastTextLength = self.textFieldSend.text?.count ?? 0
+                self.heightTableEditMention = nil
                 self.editVC.dismiss(animated: true)
             }))
             editVC.present(alert, animated: true, completion: nil)
         } else {
+            lastTextLength = self.textFieldSend.text?.count ?? 0
             editVC.dismiss(animated: true)
         }
     }
@@ -6019,6 +6385,9 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
             self.reffId = nil
             UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseInOut, animations: {
                 self.constraintTopTextField.constant = self.constraintTopTextField.constant - 50 - (self.offset()*3)
+                if self.contraintBottomMention.constant > 0 {
+                    self.contraintBottomMention.constant = self.contraintBottomMention.constant - 50
+                }
             }, completion: nil)
         }
     }
@@ -6035,6 +6404,9 @@ extension EditorPersonal: UIContextMenuInteractionDelegate {
             self.containerLink.removeFromSuperview()
             UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseInOut, animations: {
                 self.constraintTopTextField.constant = self.constraintTopTextField.constant - 80
+                if self.contraintBottomMention.constant > 0 {
+                    self.contraintBottomMention.constant = self.contraintBottomMention.constant - 80
+                }
             }, completion: nil)
             self.showingLink = ""
         }
@@ -6137,6 +6509,50 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
             tableView.reloadData()
             return
         }
+        if tableView == tableMention || tableView == tableMentionEdit {
+            tableView.deselectRow(at: indexPath, animated: true)
+            var nowTextField = textFieldSend!
+            if tableView == tableMentionEdit {
+                nowTextField = editTextView
+            }
+            let fulltextForMention = nowTextField.text.substring(from: 0, to: lastPositionCursorMention - 1)
+            let diff = nowTextField.text.count - fulltextForMention.count
+            let lines = fulltextForMention.split(separator: "\n")
+            if let lastLineIndex = lines.lastIndex(where: { !$0.isEmpty }) {
+                let words = lines[lastLineIndex].split(separator: " ")
+                if let lastWordIndex = words.lastIndex(where: { !$0.isEmpty }) {
+                    var lastWord = words[lastWordIndex]
+                    if let textM = extractFromAtIfSymbolsBefore(String(lastWord)) {
+                        lastWord = textM[textM.startIndex..<textM.endIndex]
+                    }
+                    if let rangeLastWord = fulltextForMention.range(of: lastWord, options: .backwards) {
+                        listMentionInTextField.append(listMentionWithText[indexPath.row])
+                        
+                        var addSpaceAfterReplacement = ""
+                        if diff == 0 {
+                            addSpaceAfterReplacement = " "
+                        }
+                        
+                        var text = nowTextField.text ?? ""
+                        let nameMention = listMentionWithText[indexPath.row].fullName.trimmingCharacters(in: .whitespaces)
+                        listMentionInTextField.last?.ex_block = "\(fulltextForMention.distance(from: fulltextForMention.startIndex, to: rangeLastWord.lowerBound) + nameMention.count)" //upperbound
+                        let replacementText = "@\(nameMention)"
+                        
+                        // Replace the old text with the new text using the replaceSubrange(_:with:) method
+                        text.replaceSubrange(rangeLastWord, with: replacementText + addSpaceAfterReplacement)
+                        
+                        nowTextField.attributedText = text.richText(isEditing: true, listMentionInTextField: listMentionInTextField)
+                        
+                        let newPosition = nowTextField.position(from: nowTextField.beginningOfDocument, offset: nowTextField.text.count - diff)
+                        nowTextField.selectedTextRange = nowTextField.textRange(from: newPosition!, to: newPosition!)
+                        
+                        hideMention()
+                        lastTextLength = nowTextField.text.count
+                        return
+                    }
+                }
+            }
+        }
         if isContactCenter && indexPath.row == 0 && isRequestContactCenter {
             return
         }
@@ -6268,6 +6684,9 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
         if tableView == tableViewConfigFile {
             return nil
         }
+        if tableView == tableMention || tableView == tableMentionEdit {
+            return .none
+        }
         let containerView = UIView()
         containerView.backgroundColor = .clear
         
@@ -6309,7 +6728,7 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
     }
     
     public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
-        if tableView == tableViewConfigFile {
+        if tableView == tableMention || tableView == tableMentionEdit || tableView == tableViewConfigFile {
             return 0
         }
         return 30
@@ -6336,6 +6755,31 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
             cell.tintColor = .black
             return cell
         }
+        if tableView == tableMention || tableView == tableMentionEdit {
+            let cellMention = tableView.dequeueReusableCell(withIdentifier: tableView == tableMention ? "cellMention" : "cellEditMention", for: indexPath as IndexPath)
+            var content = cellMention.defaultContentConfiguration()
+            content.textProperties.font = UIFont.systemFont(ofSize: 11 + offset())
+            content.imageProperties.tintColor = .black
+            content.imageProperties.maximumSize = CGSize(width: 24, height: 24)
+            if indexPath.row < listMentionWithText.count {
+                if listMentionWithText[indexPath.row].pin == "-997" {
+                    if let urlGif = Bundle.resourceBundle(for: Nexilis.self).url(forResource: "pb_gpt_bot", withExtension: "gif"), let data = try? Data(contentsOf: urlGif), let source = CGImageSourceCreateWithData(data as CFData, nil), let cgImage = CGImageSourceCreateImageAtIndex(source, 0, nil) {
+                        let staticImage = UIImage(cgImage: cgImage)
+                        content.image = staticImage.circleMasked
+                    } else if let urlGif = Bundle.resourcesMediaBundle(for: Nexilis.self).url(forResource: "pb_gpt_bot", withExtension: "gif"), let data = try? Data(contentsOf: urlGif), let source = CGImageSourceCreateWithData(data as CFData, nil), let cgImage = CGImageSourceCreateImageAtIndex(source, 0, nil) {
+                        let staticImage = UIImage(cgImage: cgImage)
+                        content.image = staticImage.circleMasked
+                    }
+                } else {
+                    getImage(name: listMentionWithText[indexPath.row].thumb, placeholderImage: UIImage(systemName: "person"), isCircle: true, tableView: tableView, indexPath: indexPath, completion: { result, isDownloaded, image in
+                        content.image = image
+                    })
+                }
+                content.text = listMentionWithText[indexPath.row].firstName + " " + listMentionWithText[indexPath.row].lastName
+            }
+            cellMention.contentConfiguration = content
+            return cellMention
+        }
         let idMe = User.getMyPin() as String?
         let dataMessages = dataMessages.filter({$0["chat_date"]  as? String ?? "" == dataDates[indexPath.section]})
         let profileMessage = UIImageView()
@@ -6563,12 +7007,13 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
         let audioChat = (dataMessages[indexPath.row]["audio_id"] as? String) ?? ""
         let gifChat = (dataMessages[indexPath.row]["gif_id"] as? String) ?? ""
         let dataTimer = listTimerCredential[(dataMessages[indexPath.row]["message_id"]  as? String ?? "")]
+        let is_bot = (dataMessages[indexPath.row][TypeDataMessage.is_bot] as? Int) ?? 0
         
         cell.backgroundColor = .clear
         cell.selectionStyle = .none
         let nameSender = UILabel()
         
-        if isContactCenter {
+        if isContactCenter || is_bot == 1 {
             profileMessage.frame.size = CGSize(width: 35, height: 35)
             cell.contentView.addSubview(profileMessage)
             profileMessage.translatesAutoresizingMaskIntoConstraints = false
@@ -6590,9 +7035,33 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
             profileMessage.image = UIImage(systemName: "person")
             profileMessage.tintColor = .white
             profileMessage.contentMode = .scaleAspectFit
-            let user = User.getData(pin: dataMessages[indexPath.row]["f_pin"] as? String)
-            getImage(name: user?.thumb ?? "", placeholderImage: UIImage(systemName: "person.circle.fill")!, tableView: tableView, indexPath: indexPath) { result, isDownloaded, image in
-                profileMessage.image = image
+            if is_bot == 1 {
+                if let urlGif = Bundle.resourceBundle(for: Nexilis.self).url(forResource: "pb_gpt_bot", withExtension: "gif") {
+                    profileMessage.sd_setImage(with: urlGif) { (image, error, cacheType, imageURL) in
+                        if error == nil {
+                            profileMessage.animationImages = image?.images
+                            profileMessage.animationDuration = image?.duration ?? 0.0
+                            profileMessage.animationRepeatCount = 0
+                            profileMessage.startAnimating()
+                        }
+                    }
+                } else if let urlGif = Bundle.resourcesMediaBundle(for: Nexilis.self).url(forResource: "pb_gpt_bot", withExtension: "gif") {
+                    profileMessage.sd_setImage(with: urlGif) { (image, error, cacheType, imageURL) in
+                        if error == nil {
+                            profileMessage.animationImages = image?.images
+                            profileMessage.animationDuration = image?.duration ?? 0.0
+                            profileMessage.animationRepeatCount = 0
+                            profileMessage.startAnimating()
+                        }
+                    }
+                }
+                nameSender.text = "GPT SmartBot"
+            } else {
+                let user = User.getData(pin: dataMessages[indexPath.row]["f_pin"] as? String)
+                getImage(name: user?.thumb ?? "", placeholderImage: UIImage(systemName: "person.circle.fill")!, tableView: tableView, indexPath: indexPath) { result, isDownloaded, image in
+                    profileMessage.image = image
+                }
+                nameSender.text = user?.fullName ?? ""
             }
             profileMessage.contentMode = .scaleAspectFill
             
@@ -6604,7 +7073,6 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
                 nameSender.topAnchor.constraint(equalTo: cell.contentView.topAnchor, constant: 5).isActive = true
             }
             nameSender.font = UIFont.systemFont(ofSize: 12 + offset(), weight: UIFont.Weight(800))
-            nameSender.text = user?.fullName ?? ""
             nameSender.textAlignment = .right
             if (dataMessages[indexPath.row]["f_pin"] as? String == idMe) {
                 nameSender.trailingAnchor.constraint(equalTo:profileMessage.leadingAnchor, constant: -5).isActive = true
@@ -6707,7 +7175,7 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
         
         if (dataMessages[indexPath.row]["f_pin"] as? String == idMe) {
             containerMessage.leadingAnchor.constraint(greaterThanOrEqualTo: cell.contentView.leadingAnchor, constant: 60).isActive = true
-            if isContactCenter {
+            if isContactCenter || is_bot == 1 {
                 containerMessage.topAnchor.constraint(equalTo: nameSender.bottomAnchor).isActive = true
                 containerMessage.trailingAnchor.constraint(equalTo: profileMessage.leadingAnchor, constant: -5).isActive = true
             } else {
@@ -6750,7 +7218,7 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
             
         } else {
             if markerCounter != nil && dataMessages[indexPath.row]["message_id"] as? String == markerCounter {
-                if isContactCenter {
+                if isContactCenter || is_bot == 1 {
                     containerMessage.topAnchor.constraint(equalTo: nameSender.bottomAnchor).isActive = true
                 } else {
                     containerMessage.topAnchor.constraint(equalTo: cell.contentView.topAnchor, constant: 35).isActive = true
@@ -6785,13 +7253,13 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
                 labelNewMessages.text = "Unread Messages".localized()
                 
             } else {
-                if isContactCenter {
+                if isContactCenter || is_bot == 1 {
                     containerMessage.topAnchor.constraint(equalTo: nameSender.bottomAnchor).isActive = true
                 } else {
                     containerMessage.topAnchor.constraint(equalTo: cell.contentView.topAnchor, constant: 5).isActive = true
                 }
             }
-            if isContactCenter {
+            if isContactCenter || is_bot == 1 {
                 containerMessage.leadingAnchor.constraint(equalTo: profileMessage.trailingAnchor, constant: 5).isActive = true
             } else {
                 if copySession || forwardSession || deleteSession {
@@ -8580,13 +9048,16 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
 //    }
     
     public func numberOfSections(in tableView: UITableView) -> Int {
-        if tableView == tableViewConfigFile {
+        if tableView == tableMention || tableView == tableMentionEdit || tableView == tableViewConfigFile {
             return 1
         }
         return dataDates.count
     }
     
     public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+        if tableView == tableMention || tableView == tableMentionEdit {
+            return listMentionWithText.count
+        }
         if tableView == tableViewConfigFile {
             return 2
         }
@@ -9256,6 +9727,9 @@ extension EditorPersonal: UITableViewDelegate, UITableViewDataSource, AVAudioPla
         }
         UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseInOut, animations: {
             self.constraintTopTextField.constant = self.constraintTopTextField.constant + 50 + (self.offset()*3)
+            if self.contraintBottomMention.constant > 0 {
+                self.contraintBottomMention.constant = self.contraintBottomMention.constant + self.heightTextFieldSend.constant
+            }
         }, completion: nil)
         if (self.currentIndexpath != nil) {
             DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
@@ -9664,6 +10138,7 @@ public class TypeDataMessage {
     public static let is_pinned = "is_pinned"
     public static let is_secret = "is_secret"
     public static let spec_file = "spec_file"
+    public static let is_bot = "is_bot"
 }
 
 extension String {

+ 3 - 0
NexilisLite/NexilisLite/Source/View/Chat/PreviewAttachmentImageVideo.swift

@@ -940,6 +940,9 @@ extension PreviewAttachmentImageVideo: UITableViewDelegate, UITableViewDataSourc
     }
     
     func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+        if tableView == tableViewConfigFile {
+            return 2
+        }
         return listMentionWithText.count
     }
     

+ 3 - 0
NexilisLite/NexilisLite/Source/View/Control/ContactChatViewController.swift

@@ -1624,6 +1624,9 @@ extension ContactChatViewController {
                                 }
                                 stringMessage.append(NSAttributedString(string: fullname + ": ", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12 + String.offset(), weight: .medium)]))
                             }
+                            if data.messageScope == MessageScope.WHISPER && data.isBot == 1 {
+                                stringMessage.append(NSAttributedString(string: "GPT SmartBot" + ": ", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12 + String.offset(), weight: .medium)]))
+                            }
                             if data.lock == "1" {
                                 stringMessage.append(("🚫 _"+"This message was deleted".localized()+"_").richText())
                             } else {