kevin 5 месяцев назад
Родитель
Сommit
57f09c28d6
36 измененных файлов с 528 добавлено и 40 удалено
  1. 15 7
      AppBuilder/AppBuilder/FourthTabViewController.swift
  2. 13 12
      AppBuilder/AppBuilder/ViewController.swift
  3. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp1.imageset/Contents.json
  4. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp1.imageset/pb_chatwp1.jpg
  5. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp10.imageset/Contents.json
  6. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp10.imageset/pb_chatwp10.jpg
  7. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp11.imageset/Contents.json
  8. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp11.imageset/pb_chatwp11.jpg
  9. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp12.imageset/Contents.json
  10. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp12.imageset/pb_chatwp12.jpg
  11. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp2.imageset/Contents.json
  12. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp2.imageset/pb_chatwp2.jpg
  13. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp3.imageset/Contents.json
  14. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp3.imageset/pb_chatwp3.jpg
  15. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp4.imageset/Contents.json
  16. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp4.imageset/pb_chatwp4.jpg
  17. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp5.imageset/Contents.json
  18. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp5.imageset/pb_chatwp5.jpg
  19. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp6.imageset/Contents.json
  20. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp6.imageset/pb_chatwp6.jpg
  21. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp7.imageset/Contents.json
  22. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp7.imageset/pb_chatwp7.jpg
  23. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp8.imageset/Contents.json
  24. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp8.imageset/pb_chatwp8.jpg
  25. 21 0
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp9.imageset/Contents.json
  26. BIN
      NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp9.imageset/pb_chatwp9.jpg
  27. 31 0
      NexilisLite/NexilisLite/Resource/Palio.storyboard
  28. 2 2
      NexilisLite/NexilisLite/Resource/id.lproj/Localizable.strings
  29. 16 0
      NexilisLite/NexilisLite/Source/APIS.swift
  30. 1 1
      NexilisLite/NexilisLite/Source/View/Call/QmeraAudioViewController.swift
  31. 1 1
      NexilisLite/NexilisLite/Source/View/Call/QmeraVideoViewController.swift
  32. 8 8
      NexilisLite/NexilisLite/Source/View/Chat/ChatGPTBotView.swift
  33. 4 0
      NexilisLite/NexilisLite/Source/View/Chat/EditorGroup.swift
  34. 4 1
      NexilisLite/NexilisLite/Source/View/Chat/EditorPersonal.swift
  35. 163 0
      NexilisLite/NexilisLite/Source/View/Control/ChatWallpaperViewController.swift
  36. 18 8
      NexilisLite/NexilisLite/Source/View/Control/SettingTableViewController.swift

+ 15 - 7
AppBuilder/AppBuilder/FourthTabViewController.swift

@@ -147,7 +147,7 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
             Item.menus["Personal"] = [
                 Item(icon: UIImage(systemName: "person"), title: "Personal Information".localized()),
                 Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
-                Item(icon: UIImage(systemName: "textformat.size"), title: "Change Font Size".localized()),
+                Item(icon: UIImage(systemName: "textformat.size"), title: "Chat Font Size".localized()),
                 Item(icon: UIImage(systemName: "arrow.up.and.person.rectangle.portrait"), title: "Sign-Up/Sign-In".localized()),
             ]
         } else {
@@ -158,7 +158,8 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                         Item.menus["Personal"] = [
                             Item(icon: UIImage(systemName: "person"), title: "Personal Information".localized()),
                             Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
-                            Item(icon: UIImage(systemName: "textformat.size"), title: "Change Font Size".localized()),
+                            Item(icon: UIImage(systemName: "textformat.size"), title: "Chat Font Size".localized()),
+                            Item(icon: UIImage(systemName: "photo"), title: "Chat Wallpaper".localized()),
 //                            Item(icon: UIImage(systemName: "person.crop.rectangle"), title: "Change Admin / Internal Password".localized()),
                             Item(icon: UIImage(systemName: "laptopcomputer.and.iphone"), title: "Sign-In to Web".localized()),
 //                            Item(icon: UIImage(named: "ic_internal", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, title: "Set Internal Account".localized()),
@@ -168,14 +169,16 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                         Item.menus["Personal"] = [
                             Item(icon: UIImage(systemName: "person"), title: "Personal Information".localized()),
                             Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
-                            Item(icon: UIImage(systemName: "textformat.size"), title: "Change Font Size".localized()),
+                            Item(icon: UIImage(systemName: "textformat.size"), title: "Chat Font Size".localized()),
+                            Item(icon: UIImage(systemName: "photo"), title: "Chat Wallpaper".localized()),
                             Item(icon: UIImage(systemName: "laptopcomputer.and.iphone"), title: "Sign-In to Web".localized()),
                         ]
                     } else {
                         Item.menus["Personal"] = [
                             Item(icon: UIImage(systemName: "person"), title: "Personal Information".localized()),
                             Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
-                            Item(icon: UIImage(systemName: "textformat.size"), title: "Change Font Size".localized()),
+                            Item(icon: UIImage(systemName: "textformat.size"), title: "Chat Font Size".localized()),
+                            Item(icon: UIImage(systemName: "photo"), title: "Chat Wallpaper".localized()),
 //                            Item(icon: UIImage(systemName: "person.badge.key"), title: "Access Admin / Internal Features".localized()),
                         ]
                     }
@@ -229,7 +232,8 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                     Item.menus["Personal"] = [
                         Item(icon: UIImage(systemName: "person"), title: "Personal Information".localized()),
                         Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
-                        Item(icon: UIImage(systemName: "textformat.size"), title: "Change Font Size".localized()),
+                        Item(icon: UIImage(systemName: "textformat.size"), title: "Chat Font Size".localized()),
+                        Item(icon: UIImage(systemName: "photo"), title: "Chat Wallpaper".localized()),
 //                        Item(icon: UIImage(systemName: "person.badge.key"), title: "Access Admin / Internal Features".localized()),
                     ]
                     Item.menus["Personal"]?.append(Item(icon: UIImage(systemName: "arrow.up.and.person.rectangle.portrait"), title: "Sign-Up/Sign-In".localized()))
@@ -507,7 +511,9 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                 cell.accessoryType = .disclosureIndicator
             case "Change Language".localized():
                 cell.accessoryType = .disclosureIndicator
-            case "Change Font Size".localized():
+            case "Chat Font Size".localized():
+                cell.accessoryType = .disclosureIndicator
+            case "Chat Wallpaper".localized():
                 cell.accessoryType = .disclosureIndicator
             case "Set Internal Account".localized():
                 cell.accessoryType = .disclosureIndicator
@@ -663,7 +669,7 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                 self.tableView.reloadData()
             }))
             self.present(alert, animated: true, completion: nil)
-        } else if item.title == "Change Font Size".localized() {
+        } else if item.title == "Chat Font Size".localized() {
             let vc = UIViewController()
             vc.preferredContentSize = CGSize(width: UIScreen.main.bounds.width - 10, height: 150)
             fontSizePickerView = UIPickerView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width - 10, height: 150))
@@ -701,6 +707,8 @@ public class FourthTabViewController: UIViewController, UITableViewDelegate, UIT
                 self.tableView.reloadData()
             }))
             self.present(alert, animated: true, completion: nil)
+        } else if item.title == "Chat Wallpaper".localized() {
+            APIS.openChatWallpaper()
         } else if item.title == "Sign-In".localized() {
             let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "changeDevice") as! ChangeDeviceViewController
             controller.isDismiss = { newThumb in

+ 13 - 12
AppBuilder/AppBuilder/ViewController.swift

@@ -580,13 +580,14 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
     
     @objc func longPressMidBtn(gestureRecognizer: UILongPressGestureRecognizer) {
         if gestureRecognizer.state == .began {
-            if self.viewControllers?.firstIndex(of: fourthTab!) == nil {
-                let vc = fourthTab!
-                vc.notInTab = true
-                self.navigationController?.show(vc, sender: nil)
-            } else {
-                self.selectedIndex = (self.viewControllers?.firstIndex(of: fourthTab!))!
-            }
+            APIS.openSetting()
+//            if self.viewControllers?.firstIndex(of: fourthTab!) == nil {
+//                let vc = fourthTab!
+//                vc.notInTab = true
+//                self.navigationController?.show(vc, sender: nil)
+//            } else {
+//                self.selectedIndex = (self.viewControllers?.firstIndex(of: fourthTab!))!
+//            }
         }
     }
     
@@ -1108,15 +1109,15 @@ class ViewController: UITabBarController, UITabBarControllerDelegate, SettingMAB
                                 let urlString = PrefsUtil.getURLBase() + "get_file_from_path?img=\(icon)"
                                 if let cachedImage = ImageCache.shared.image(forKey: urlString) {
                                     if i == 0 {
-//                                        ViewController.chatButton.setBackgroundImage(cachedImage, for: .normal)
+                                      ViewController.chatButton.setBackgroundImage(cachedImage, for: .normal)
                                     } else if i == 1 {
-//                                        ViewController.callButton.setBackgroundImage(cachedImage, for: .normal)
+                                      ViewController.callButton.setBackgroundImage(cachedImage, for: .normal)
                                     }  else if i == 2 {
-//                                        ViewController.ccButton.setBackgroundImage(cachedImage, for: .normal)
+                                      ViewController.ccButton.setBackgroundImage(cachedImage, for: .normal)
                                     }  else if i == 3 {
-//                                        ViewController.postButton.setBackgroundImage(cachedImage, for: .normal)
+                                      ViewController.postButton.setBackgroundImage(cachedImage, for: .normal)
                                     }  else if i == 4 {
-//                                        ViewController.streamingButton.setBackgroundImage(cachedImage, for: .normal)
+                                      ViewController.streamingButton.setBackgroundImage(cachedImage, for: .normal)
                                     }
                                     return
                                 }

+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp1.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "pb_chatwp1.jpg",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp1.imageset/pb_chatwp1.jpg


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp10.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "pb_chatwp10.jpg",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp10.imageset/pb_chatwp10.jpg


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp11.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "pb_chatwp11.jpg",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp11.imageset/pb_chatwp11.jpg


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp12.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "pb_chatwp12.jpg",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp12.imageset/pb_chatwp12.jpg


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp2.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "pb_chatwp2.jpg",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp2.imageset/pb_chatwp2.jpg


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp3.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "pb_chatwp3.jpg",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp3.imageset/pb_chatwp3.jpg


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp4.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "pb_chatwp4.jpg",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp4.imageset/pb_chatwp4.jpg


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp5.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "pb_chatwp5.jpg",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp5.imageset/pb_chatwp5.jpg


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp6.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "pb_chatwp6.jpg",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp6.imageset/pb_chatwp6.jpg


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp7.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "pb_chatwp7.jpg",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp7.imageset/pb_chatwp7.jpg


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp8.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "pb_chatwp8.jpg",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp8.imageset/pb_chatwp8.jpg


+ 21 - 0
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp9.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "pb_chatwp9.jpg",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
NexilisLite/NexilisLite/Resource/Assets.xcassets/pb_chatwp9.imageset/pb_chatwp9.jpg


+ 31 - 0
NexilisLite/NexilisLite/Resource/Palio.storyboard

@@ -2614,6 +2614,9 @@
                         <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" insetsLayoutMarginsFromSafeArea="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mBd-UJ-S23">
+                                <rect key="frame" x="0.0" y="-100" width="414" height="1026"/>
+                            </imageView>
                             <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" indicatorStyle="black" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="tSE-6b-2zD">
                                 <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"/>
@@ -2736,6 +2739,8 @@
                         </subviews>
                         <viewLayoutGuide key="safeArea" id="4DG-z5-IE7"/>
                         <constraints>
+                            <constraint firstItem="mBd-UJ-S23" firstAttribute="top" secondItem="tRl-GA-sdt" secondAttribute="top" constant="-100" id="0ds-7D-aB7"/>
+                            <constraint firstAttribute="trailing" secondItem="mBd-UJ-S23" secondAttribute="trailing" id="4QM-MB-AgD"/>
                             <constraint firstItem="4DG-z5-IE7" firstAttribute="trailing" secondItem="yLm-Hp-3ZU" secondAttribute="trailing" id="5qq-yP-taB"/>
                             <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"/>
@@ -2743,9 +2748,11 @@
                             <constraint firstItem="tSE-6b-2zD" firstAttribute="leading" secondItem="4DG-z5-IE7" secondAttribute="leading" id="ZTb-c1-RCd"/>
                             <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"/>
                             <constraint firstAttribute="bottom" secondItem="Xda-XC-yEA" secondAttribute="bottom" id="tbE-PI-oI9"/>
                             <constraint firstItem="Xda-XC-yEA" firstAttribute="leading" secondItem="4DG-z5-IE7" secondAttribute="leading" id="uXf-ex-84J"/>
                             <constraint firstItem="tSE-6b-2zD" firstAttribute="top" secondItem="tRl-GA-sdt" secondAttribute="top" id="vs9-ge-PTA"/>
+                            <constraint firstAttribute="bottom" secondItem="mBd-UJ-S23" secondAttribute="bottom" constant="-30" id="vsN-pj-z4S"/>
                         </constraints>
                     </view>
                     <navigationItem key="navigationItem" id="ttN-eC-x85"/>
@@ -2767,6 +2774,7 @@
                         <outlet property="viewAttachment" destination="UMZ-Cg-DEH" id="oNr-Nt-Yjk"/>
                         <outlet property="viewButton" destination="Xda-XC-yEA" id="SfN-gB-RKH"/>
                         <outlet property="viewTextfield" destination="yLm-Hp-3ZU" id="oLC-X1-VKP"/>
+                        <outlet property="wallpaperView" destination="mBd-UJ-S23" id="PyM-J5-GZb"/>
                     </connections>
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="8ng-Me-Tf1" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
@@ -2781,6 +2789,9 @@
                         <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
+                            <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" insetsLayoutMarginsFromSafeArea="NO" translatesAutoresizingMaskIntoConstraints="NO" id="D8S-zx-ZUT">
+                                <rect key="frame" x="0.0" y="-100" width="414" height="1026"/>
+                            </imageView>
                             <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="pVj-YY-BAA">
                                 <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"/>
@@ -2908,18 +2919,22 @@
                         <viewLayoutGuide key="safeArea" id="kcu-H8-MOl"/>
                         <constraints>
                             <constraint firstAttribute="bottom" secondItem="rs3-vX-pDB" secondAttribute="bottom" id="7cj-we-UtI"/>
+                            <constraint firstAttribute="bottom" secondItem="D8S-zx-ZUT" secondAttribute="bottom" constant="-30" id="BEN-cd-1Fh"/>
                             <constraint firstItem="pVj-YY-BAA" firstAttribute="leading" secondItem="kcu-H8-MOl" secondAttribute="leading" id="Boh-wY-vBg"/>
                             <constraint firstItem="kcu-H8-MOl" firstAttribute="trailing" secondItem="pVj-YY-BAA" secondAttribute="trailing" id="FBS-Wa-HbT"/>
                             <constraint firstItem="kcu-H8-MOl" firstAttribute="trailing" secondItem="1vz-q2-vEl" secondAttribute="trailing" id="GKY-2n-FNs"/>
                             <constraint firstItem="pVj-YY-BAA" firstAttribute="top" secondItem="UqO-mX-4jX" secondAttribute="top" id="JcX-k3-BwQ"/>
+                            <constraint firstItem="D8S-zx-ZUT" firstAttribute="top" secondItem="UqO-mX-4jX" secondAttribute="top" constant="-100" id="Kzv-lM-4Ah"/>
                             <constraint firstItem="fnQ-OG-1Lg" firstAttribute="top" secondItem="pVj-YY-BAA" secondAttribute="bottom" constant="10" id="LOl-kg-Tex"/>
                             <constraint firstItem="kcu-H8-MOl" firstAttribute="trailing" secondItem="rs3-vX-pDB" secondAttribute="trailing" id="MMd-8d-bIy"/>
+                            <constraint firstItem="D8S-zx-ZUT" firstAttribute="trailing" secondItem="UqO-mX-4jX" secondAttribute="trailing" id="Mqf-0j-8s1"/>
                             <constraint firstItem="1vz-q2-vEl" firstAttribute="leading" secondItem="kcu-H8-MOl" secondAttribute="leading" id="Skg-0N-h9e"/>
                             <constraint firstAttribute="bottom" secondItem="1vz-q2-vEl" secondAttribute="bottom" constant="-90" id="XGF-zq-0GX"/>
                             <constraint firstItem="rs3-vX-pDB" firstAttribute="top" secondItem="fnQ-OG-1Lg" secondAttribute="bottom" id="bT4-KC-g5c"/>
                             <constraint firstItem="rs3-vX-pDB" firstAttribute="leading" secondItem="kcu-H8-MOl" secondAttribute="leading" id="o4K-LT-Opo"/>
                             <constraint firstItem="fnQ-OG-1Lg" firstAttribute="trailing" secondItem="kcu-H8-MOl" secondAttribute="trailing" id="rRs-Ah-lAB"/>
                             <constraint firstItem="fnQ-OG-1Lg" firstAttribute="leading" secondItem="kcu-H8-MOl" secondAttribute="leading" id="uXr-gh-G2e"/>
+                            <constraint firstItem="D8S-zx-ZUT" firstAttribute="leading" secondItem="UqO-mX-4jX" secondAttribute="leading" id="wYf-Yw-yOJ"/>
                         </constraints>
                     </view>
                     <connections>
@@ -2942,6 +2957,7 @@
                         <outlet property="viewAttachment" destination="ZXb-nM-tPm" id="Bbu-bM-wLZ"/>
                         <outlet property="viewButton" destination="rs3-vX-pDB" id="4yF-Hx-qVU"/>
                         <outlet property="viewTextfield" destination="fnQ-OG-1Lg" id="KTx-21-3J7"/>
+                        <outlet property="wallpaperView" destination="D8S-zx-ZUT" id="A5u-TK-eLJ"/>
                     </connections>
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="e94-v4-EpE" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
@@ -3304,6 +3320,21 @@
             </objects>
             <point key="canvasLocation" x="9367" y="1550"/>
         </scene>
+        <!--Chat Wallpaper View Controller-->
+        <scene sceneID="8cy-m7-l4c">
+            <objects>
+                <viewController storyboardIdentifier="chatWallpaper" useStoryboardIdentifierAsRestorationIdentifier="YES" id="Edq-zt-404" customClass="ChatWallpaperViewController" customModule="NexilisLite" customModuleProvider="target" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="mqC-D7-zdj">
+                        <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <viewLayoutGuide key="safeArea" id="zOG-rA-o4S"/>
+                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="WJ9-E0-hcH" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="10566" y="1561"/>
+        </scene>
         <!--Navigation Controller-->
         <scene sceneID="QZB-X2-3Cl">
             <objects>

+ 2 - 2
NexilisLite/NexilisLite/Resource/id.lproj/Localizable.strings

@@ -77,7 +77,7 @@
 "Change Admin / Internal Password" = "Ubah Sandi Admin / Internal";
 "Change Device" = "Ubah Perangkat";
 "Change Language" = "Ubah Bahasa";
-"Change Font Size" = "Ubah Ukuran Font";
+"Chat Font Size" = "Ukuran Font Chat";
 "Notification Message(s)" = "Pesan Notifikasi";
 "Notification Message(s) Group" = "Grup Pesan Notifikasi";
 "Vibrate Mode" = "Mode Getar";
@@ -395,4 +395,4 @@
 "Enable Notification" = "Aktifkan Notifikasi";
 "Go to Settings" = "Buka Pengaturan";
 "To stay updated, please enable notification in the Settings." = "Untuk tetap mendapatkan informasi terbaru, harap aktifkan notifikasi di Pengaturan.";
-"Change Font Size" = "Ubah Ukuran Font";
+"Chat Font Size" = "Ukuran Font Chat";

+ 16 - 0
NexilisLite/NexilisLite/Source/APIS.swift

@@ -573,6 +573,22 @@ public class APIS: NSObject {
         }
     }
     
+    public static func openChatWallpaper(){
+        let isChangeProfile = Utils.getSetProfile()
+        if !isChangeProfile {
+            APIS.showChangeProfile()
+            return
+        }
+        let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "chatWallpaper") as! ChatWallpaperViewController
+        let navigationController = CustomNavigationController(rootViewController: controller)
+        navigationController.defaultStyle()
+        if UIApplication.shared.visibleViewController?.navigationController != nil {
+            UIApplication.shared.visibleViewController?.navigationController?.present(navigationController, animated: true, completion: nil)
+        } else {
+            UIApplication.shared.visibleViewController?.present(navigationController, animated: true, completion: nil)
+        }
+    }
+    
     public static func openWhiteboard() {
         let isChangeProfile = Utils.getSetProfile()
         if !isChangeProfile {

+ 1 - 1
NexilisLite/NexilisLite/Source/View/Call/QmeraAudioViewController.swift

@@ -855,6 +855,7 @@ class QmeraAudioViewController: UIViewController {
     }
     
     @objc func didAccept(sender: Any?) {
+        Nexilis.stopRingtoneCall()
         NSLayoutConstraint.deactivate(stack.constraints)
         stack.subviews.forEach { subview in
             subview.removeFromSuperview()
@@ -927,7 +928,6 @@ class QmeraAudioViewController: UIViewController {
                 }
             } else if state == Nexilis.AUDIO_CALL_OFFHOOK || (!ticketId.isEmpty && state == Nexilis.VIDEO_CALL_OFFHOOK) {
                 DispatchQueue.main.async {
-                    Nexilis.stopRingtoneCall()
                     Nexilis.stopRingbacktoneCall()
                 }
                 if users.count == 1 && firstCall {

+ 1 - 1
NexilisLite/NexilisLite/Source/View/Call/QmeraVideoViewController.swift

@@ -810,6 +810,7 @@ class QmeraVideoViewController: UIViewController {
     }
     
     func addToolbarAfterAccept() {
+        Nexilis.stopRingtoneCall()
         view.addSubview(self.stackViewToolbar)
         self.stackViewToolbar.translatesAutoresizingMaskIntoConstraints = false
         constraintBottomStackViewToolbar = self.stackViewToolbar.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -60.0)
@@ -1133,7 +1134,6 @@ class QmeraVideoViewController: UIViewController {
         }
         else if (state == Nexilis.VIDEO_CALL_OFFHOOK) {
             DispatchQueue.main.async {
-                Nexilis.stopRingtoneCall()
                 Nexilis.stopRingbacktoneCall()
             }
             let channel = arrayMessage[3]

+ 8 - 8
NexilisLite/NexilisLite/Source/View/Chat/ChatGPTBotView.swift

@@ -1741,7 +1741,7 @@ extension ChatGPTBotView: UITableViewDelegate, UITableViewDataSource {
         topAnchor = dateView.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 10.0)
         NSLayoutConstraint.activate([
             topAnchor,
-            dateView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
+            dateView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -20.0),
             dateView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor),
             dateView.heightAnchor.constraint(equalToConstant: 30),
             dateView.widthAnchor.constraint(greaterThanOrEqualToConstant: 60)
@@ -1773,7 +1773,7 @@ extension ChatGPTBotView: UITableViewDelegate, UITableViewDataSource {
     }
     
     public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
-        return 40
+        return 80
     }
     
     public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
@@ -1793,18 +1793,18 @@ extension ChatGPTBotView: UITableViewDelegate, UITableViewDataSource {
         cell.contentView.addSubview(timeMessage)
         timeMessage.translatesAutoresizingMaskIntoConstraints = false
         if (dataMessages[indexPath.row]["read_receipts"] as? String) == "8" || ((dataMessages[indexPath.row]["credential"] as? String) == "1" && dataMessages[indexPath.row]["lock"] as? String != "2") {
-            timeMessage.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -40).isActive = true
+            timeMessage.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -40 - 20).isActive = true
         } else {
-            timeMessage.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -5).isActive = true
+            timeMessage.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -5 - 20).isActive = true
         }
         
         let statusMessage = UIImageView()
         if (dataMessages[indexPath.row]["f_pin"] as? String == idMe) {
             containerMessage.leadingAnchor.constraint(greaterThanOrEqualTo: cell.contentView.leadingAnchor, constant: 60).isActive = true
             if (dataMessages[indexPath.row]["read_receipts"] as? String) == "8" || ((dataMessages[indexPath.row]["credential"] as? String) == "1" && dataMessages[indexPath.row]["lock"] as? String != "2") {
-                containerMessage.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -40).isActive = true
+                containerMessage.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -40 - 20).isActive = true
             } else {
-                containerMessage.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -5).isActive = true
+                containerMessage.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -5 - 20).isActive = true
             }
             containerMessage.topAnchor.constraint(equalTo: cell.contentView.topAnchor, constant: 5).isActive = true
             containerMessage.trailingAnchor.constraint(equalTo: cell.contentView.trailingAnchor, constant: -15).isActive = true
@@ -1878,9 +1878,9 @@ extension ChatGPTBotView: UITableViewDelegate, UITableViewDataSource {
                 containerMessage.leadingAnchor.constraint(equalTo: cell.contentView.leadingAnchor, constant: 15).isActive = true
             }
             if (dataMessages[indexPath.row]["read_receipts"] as? String) == "8" || ((dataMessages[indexPath.row]["credential"] as? String) == "1" && dataMessages[indexPath.row]["lock"] as? String != "2") {
-                containerMessage.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -40).isActive = true
+                containerMessage.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -40 - 20).isActive = true
             } else {
-                containerMessage.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -5).isActive = true
+                containerMessage.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -5 - 20).isActive = true
             }
             containerMessage.trailingAnchor.constraint(lessThanOrEqualTo: cell.contentView.trailingAnchor, constant: -60).isActive = true
             containerMessage.widthAnchor.constraint(greaterThanOrEqualToConstant: 46).isActive = true

+ 4 - 0
NexilisLite/NexilisLite/Source/View/Chat/EditorGroup.swift

@@ -17,6 +17,7 @@ import SDWebImage
 import PhotosUI
 
 public class EditorGroup: UIViewController, CLLocationManagerDelegate {
+    @IBOutlet var wallpaperView: UIImageView!
     @IBOutlet var viewButton: UIView!
     @IBOutlet var constraintViewTextField: NSLayoutConstraint!
     @IBOutlet var buttonVoice: UIButton!
@@ -177,6 +178,7 @@ public class EditorGroup: UIViewController, CLLocationManagerDelegate {
         super.viewDidLoad()
 //        navigationController?.navigationBar.topItem?.title = ""
         Utils.addBackground(view: contactChatNav.view)
+        wallpaperView.image = UIImage(data: UserDefaults.standard.data(forKey: "chatWallpaper")!)
         if Nexilis.fromMAB {
             Nexilis.floatingButton.isHidden = true
         }
@@ -188,6 +190,7 @@ public class EditorGroup: UIViewController, CLLocationManagerDelegate {
         viewButton.addTopBorder(with: UIColor.lightGray, andWidth: 1.0)
         
 //        buttonVoice.setImage(resizeImage(image: UIImage(named: "Voice-Record", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)), for: .normal)
+        viewAttachment.backgroundColor = .white
         buttonSendImage.setImage(resizeImage(image: UIImage(named: "Send-Image", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor), for: .normal)
         buttonSendPhoto.setImage(resizeImage(image: UIImage(named: "Camera", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor), for: .normal)
         buttonSendSticker.setImage(resizeImage(image: UIImage(named: "Sticker---Emoji", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor), for: .normal)
@@ -202,6 +205,7 @@ public class EditorGroup: UIViewController, CLLocationManagerDelegate {
         buttonAckConfidential.addTarget(self, action: #selector(showChooserACKConfidential), for: .touchUpInside)
         buttonAckConfidential.tintColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .white
         buttonAckConfidential.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor
+        textFieldSend.backgroundColor = .white
         textFieldSend.layer.cornerRadius = textFieldSend.maxCornerRadius()
         textFieldSend.layer.borderWidth = 1.0
         textFieldSend.text = "Send message".localized()

+ 4 - 1
NexilisLite/NexilisLite/Source/View/Chat/EditorPersonal.swift

@@ -17,6 +17,7 @@ import SDWebImage
 import PhotosUI
 
 public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestureRecognizerDelegate, CLLocationManagerDelegate {
+    @IBOutlet var wallpaperView: UIImageView!
     @IBOutlet var viewButton: UIView!
     @IBOutlet var constraintViewTextField: NSLayoutConstraint!
     @IBOutlet var buttonVoice: UIButton!
@@ -171,7 +172,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
         super.viewDidLoad()
 //        navigationController?.navigationBar.topItem?.title = ""
         Utils.addBackground(view: contactChatNav.view)
-        
+        wallpaperView.image = UIImage(data: UserDefaults.standard.data(forKey: "chatWallpaper")!)
         if Nexilis.fromMAB {
             Nexilis.floatingButton.isHidden = true
         }
@@ -183,6 +184,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
         viewButton.addTopBorder(with: UIColor.lightGray, andWidth: 1.0)
         
 //        buttonVoice.setImage(resizeImage(image: UIImage(named: "Voice-Record", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)), for: .normal)
+        viewAttachment.backgroundColor = .white
         buttonSendImage.setImage(resizeImage(image: UIImage(named: "Send-Image", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor), for: .normal)
         buttonSendPhoto.setImage(resizeImage(image: UIImage(named: "Camera", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor), for: .normal)
         buttonSendSticker.setImage(resizeImage(image: UIImage(named: "Sticker---Emoji", in: Bundle.resourceBundle(for: Nexilis.self), with: nil)!, targetSize: CGSize(width: 30, height: 30)).withTintColor(self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor), for: .normal)
@@ -202,6 +204,7 @@ public class EditorPersonal: UIViewController, ImageVideoPickerDelegate, UIGestu
             buttonAckConfidential.tintColor = self.traitCollection.userInterfaceStyle == .dark ? .blackDarkMode : .white
             buttonAckConfidential.backgroundColor = self.traitCollection.userInterfaceStyle == .dark ? .white : .mainColor
         }
+        textFieldSend.backgroundColor = .white
         textFieldSend.layer.cornerRadius = textFieldSend.maxCornerRadius()
         textFieldSend.layer.borderWidth = 1.0
         textFieldSend.text = "Send message".localized()

+ 163 - 0
NexilisLite/NexilisLite/Source/View/Control/ChatWallpaperViewController.swift

@@ -0,0 +1,163 @@
+//
+//  ChatWallpaperViewController.swift
+//  NexilisLite
+//
+//  Created by Maronakins on 13/03/25.
+//
+
+import Foundation
+import UIKit
+import PhotosUI
+
+class ChatWallpaperViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, PHPickerViewControllerDelegate {
+
+    // MARK: - Properties
+    private let wallpapers: [UIImage] = {
+        let imageNames = ["pb_chatwp1", "pb_chatwp2", "pb_chatwp3", "pb_chatwp4", "pb_chatwp5", "pb_chatwp6", "pb_chatwp7", "pb_chatwp8", "pb_chatwp9", "pb_chatwp10", "pb_chatwp11", "pb_chatwp12"]
+        return imageNames.compactMap { UIImage(named: $0, in: Bundle.resourceBundle(for: Nexilis.self), with: nil) }
+    }() // Add your predefined wallpapers here
+
+    private var selectedWallpaper: UIImage?
+    private let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
+
+    // MARK: - Lifecycle
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        setupUI()
+    }
+
+    // MARK: - UI Setup
+    private func setupUI() {
+        view.backgroundColor = .systemBackground
+        title = "Choose Wallpaper"
+
+        // Configure Collection View
+        collectionView.dataSource = self
+        collectionView.delegate = self
+        collectionView.register(WallpaperCell.self, forCellWithReuseIdentifier: WallpaperCell.identifier)
+        collectionView.backgroundColor = .clear
+
+        let layout = UICollectionViewFlowLayout()
+        layout.itemSize = CGSize(width: 120, height: 200)
+        layout.minimumInteritemSpacing = 10
+        layout.minimumLineSpacing = 10
+        collectionView.collectionViewLayout = layout
+
+        view.addSubview(collectionView)
+        collectionView.translatesAutoresizingMaskIntoConstraints = false
+        NSLayoutConstraint.activate([
+            collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
+            collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
+            collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
+            collectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -60)
+        ])
+
+        // Add Custom Wallpaper Button
+        let customWallpaperButton = UIButton(type: .system)
+        customWallpaperButton.setTitle("Choose Custom Wallpaper", for: .normal)
+        customWallpaperButton.addTarget(self, action: #selector(openPhotoLibrary), for: .touchUpInside)
+        customWallpaperButton.backgroundColor = .systemBlue
+        customWallpaperButton.setTitleColor(.white, for: .normal)
+        customWallpaperButton.layer.cornerRadius = 8
+
+        view.addSubview(customWallpaperButton)
+        customWallpaperButton.translatesAutoresizingMaskIntoConstraints = false
+        NSLayoutConstraint.activate([
+            customWallpaperButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
+            customWallpaperButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
+            customWallpaperButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -16),
+            customWallpaperButton.heightAnchor.constraint(equalToConstant: 50)
+        ])
+    }
+
+    // MARK: - Collection View Data Source
+    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+        return wallpapers.count
+    }
+
+    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: WallpaperCell.identifier, for: indexPath) as! WallpaperCell
+        cell.configure(with: wallpapers[indexPath.item])
+        return cell
+    }
+
+    // MARK: - Collection View Delegate
+    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
+        selectedWallpaper = wallpapers[indexPath.item]
+        saveAndDismiss()
+    }
+
+    // MARK: - Custom Wallpaper Selection
+    @objc private func openPhotoLibrary() {
+        var configuration = PHPickerConfiguration()
+        configuration.filter = .images
+        configuration.selectionLimit = 1
+
+        let picker = PHPickerViewController(configuration: configuration)
+        picker.delegate = self
+        present(picker, animated: true)
+    }
+
+    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
+        picker.dismiss(animated: true)
+
+        guard let result = results.first else { return }
+        result.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] (object, error) in
+            if let image = object as? UIImage {
+                DispatchQueue.main.async {
+                    self?.selectedWallpaper = image
+                    self?.saveAndDismiss()
+                }
+            }
+        }
+    }
+
+    // MARK: - Save and Dismiss
+    private func saveAndDismiss() {
+        guard let selectedWallpaper = selectedWallpaper else { return }
+
+        // Save the selected wallpaper (e.g., to UserDefaults or a shared data model)
+        UserDefaults.standard.set(selectedWallpaper.pngData(), forKey: "chatWallpaper")
+
+        // Notify the chat view to update the wallpaper
+        NotificationCenter.default.post(name: Notification.Name("WallpaperDidChange"), object: nil)
+
+        // Dismiss the view controller
+        dismiss(animated: true)
+    }
+}
+
+// MARK: - Wallpaper Cell
+class WallpaperCell: UICollectionViewCell {
+    static let identifier = "WallpaperCell"
+
+    private let imageView = UIImageView()
+
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        setupUI()
+    }
+
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    private func setupUI() {
+        imageView.contentMode = .scaleAspectFill
+        imageView.clipsToBounds = true
+        imageView.layer.cornerRadius = 8
+
+        contentView.addSubview(imageView)
+        imageView.translatesAutoresizingMaskIntoConstraints = false
+        NSLayoutConstraint.activate([
+            imageView.topAnchor.constraint(equalTo: contentView.topAnchor),
+            imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
+            imageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
+            imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
+        ])
+    }
+
+    func configure(with image: UIImage) {
+        imageView.image = image
+    }
+}

+ 18 - 8
NexilisLite/NexilisLite/Source/View/Control/SettingTableViewController.swift

@@ -105,8 +105,6 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
         if Database.shared.database == nil {
             Item.menus["Personal"] = [
                 Item(icon: UIImage(systemName: "person"), title: "Personal Information".localized()),
-                Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
-                Item(icon: UIImage(systemName: "textformat.size"), title: "Change Font Size".localized()),
                 Item(icon: UIImage(systemName: "arrow.up.and.person.rectangle.portrait"), title: "Sign-Up/Sign-In".localized()),
             ]
         } else {
@@ -118,7 +116,9 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
                             Item.menus["Personal"] = [
                                 Item(icon: UIImage(systemName: "person"), title: "Personal Information".localized()),
                                 Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
-                                Item(icon: UIImage(systemName: "textformat.size"), title: "Change Font Size".localized()),
+                                Item(icon: UIImage(systemName: "textformat.size"), title: "Chat Font Size".localized()),
+                                Item(icon: UIImage(systemName: "photo"),
+                                     title: "Chat Wallpaper".localized()),
                                 Item(icon: UIImage(systemName: "lock"), title: "Secure Folder"),
 //                                Item(icon: UIImage(systemName: "person.crop.rectangle"), title: "Change Admin / Internal Password".localized()),
                                 Item(icon: UIImage(systemName: "laptopcomputer.and.iphone"), title: "Sign-In to Web".localized()),
@@ -129,7 +129,9 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
                             Item.menus["Personal"] = [
                                 Item(icon: UIImage(systemName: "person"), title: "Personal Information".localized()),
                                 Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
-                                Item(icon: UIImage(systemName: "textformat.size"), title: "Change Font Size".localized()),
+                                Item(icon: UIImage(systemName: "textformat.size"), title: "Chat Font Size".localized()),
+                                Item(icon: UIImage(systemName: "photo"),
+                                     title: "Chat Wallpaper".localized()),
                                 Item(icon: UIImage(systemName: "lock"), title: "Secure Folder"),
                                 Item(icon: UIImage(systemName: "laptopcomputer.and.iphone"), title: "Sign-In to Web".localized()),
                             ]
@@ -137,7 +139,9 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
                             Item.menus["Personal"] = [
                                 Item(icon: UIImage(systemName: "person"), title: "Personal Information".localized()),
                                     Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
-                                Item(icon: UIImage(systemName: "textformat.size"), title: "Change Font Size".localized()),
+                                Item(icon: UIImage(systemName: "textformat.size"), title: "Chat Font Size".localized()),
+                                Item(icon: UIImage(systemName: "photo"),
+                                     title: "Chat Wallpaper".localized()),
                                 Item(icon: UIImage(systemName: "lock"), title: "Secure Folder"),
 //                                Item(icon: UIImage(systemName: "person.badge.key"), title: "Access Admin / Internal Features".localized()),
                             ]
@@ -192,7 +196,9 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
                         Item.menus["Personal"] = [
                             Item(icon: UIImage(systemName: "person"), title: "Personal Information".localized()),
                                 Item(icon: UIImage(systemName: "textformat.abc"), title: "Change Language".localized()),
-                            Item(icon: UIImage(systemName: "textformat.size"), title: "Change Font Size".localized()),
+                            Item(icon: UIImage(systemName: "textformat.size"), title: "Chat Font Size".localized()),
+                            Item(icon: UIImage(systemName: "photo"),
+                                 title: "Chat Wallpaper".localized()),
                             Item(icon: UIImage(systemName: "lock"), title: "Secure Folder"),
 //                            Item(icon: UIImage(systemName: "person.badge.key"), title: "Access Admin / Internal Features".localized()),
                         ]
@@ -352,7 +358,9 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
                 cell.accessoryType = .disclosureIndicator
             case "Change Language".localized():
                 cell.accessoryType = .disclosureIndicator
-            case "Change Font Size".localized():
+            case "Chat Font Size".localized():
+                cell.accessoryType = .disclosureIndicator
+            case "Chat Wallpaper".localized():
                 cell.accessoryType = .disclosureIndicator
             case "Set Internal Account".localized():
                 cell.accessoryType = .disclosureIndicator
@@ -510,7 +518,7 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
                 self.tableView.reloadData()
             }))
             self.present(alert, animated: true, completion: nil)
-        } else if item.title == "Change Font Size".localized() {
+        } else if item.title == "Chat Font Size".localized() {
             let vc = UIViewController()
             vc.preferredContentSize = CGSize(width: UIScreen.main.bounds.width - 10, height: 150)
             fontSizePickerView = UIPickerView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width - 10, height: 150))
@@ -548,6 +556,8 @@ public class SettingTableViewController: UITableViewController, UIGestureRecogni
                 self.tableView.reloadData()
             }))
             self.present(alert, animated: true, completion: nil)
+        } else if item.title == "Chat Wallpaper".localized() {
+            APIS.openChatWallpaper()
         } else if item.title == "Sign-In".localized() {
             let controller = AppStoryBoard.Palio.instance.instantiateViewController(withIdentifier: "changeDevice") as! ChangeDeviceViewController
             controller.isDismiss = { newThumb in