using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Text; using TMPro; [RequireComponent(typeof(Button))] public class Send : MonoBehaviour { public Text yournote; // ou TMP_Text si tu utilises TextMeshPro: public TMP_Text yournote; public Text designer; // idem : public TMP_Text designer; public InputField ClientName; public InputField ClientAddress; public InputField ClientEmail; public InputField ClientPhone; public InputField ClientNote; public InputField SendEmail; EmailValidator _sendEmailValidator; EmailValidator _clientEmailValidator; void Awake() { if (SendEmail != null) _sendEmailValidator = SendEmail.GetComponent(); if (ClientEmail != null) _clientEmailValidator = ClientEmail.GetComponent(); } void OnEnable() { if (SendEmail != null && !string.IsNullOrEmpty(_G.designerEmail)) SendEmail.text = _G.designerEmail; } // _G.Form pointe sur les 5 champs du formulaire. A appeler avant toute lecture de _G.Form : // chaque bouton (SaveWEB, OpenOnSoft, OpenEmailSender) peut etre le premier utilise. void FillForm() { _G.Form.Clear(); _G.Form.Add(ClientName);//0 _G.Form.Add(ClientAddress);//1 _G.Form.Add(ClientEmail);//2 _G.Form.Add(ClientPhone);//3 _G.Form.Add(ClientNote);//4 } // Le Text interne de l'InputField ClientNote, null s'il n'est pas branche. Text GetClientNoteText() { return ClientNote != null ? ClientNote.textComponent : null; } // Texte d'un champ, "" si le formulaire n'est pas rempli ou le champ pas branche. static string FormText(int i) { return _G.Form != null && i < _G.Form.Count && _G.Form[i] != null ? _G.Form[i].text : ""; } public void SaveWEB() { // 1) Construire le XML (si tu en as besoin) FillForm(); if (CheckAllInput()) { _G.ClientInfo["Name"]=_G.Form[0].text; _G.ClientInfo["Address"]=_G.Form[1].text; _G.ClientInfo["Email"]=_G.Form[2].text; _G.ClientInfo["Phone"]=_G.Form[3].text; _G.ClientInfo["Note"]=_G.Form[4].text; _G.FileName = _G.Form != null && _G.Form.Count > 2 ? _G.Form[2].text : "client"; byte[] bytes = SaveXML.BuildXmlBytes(); string xmls = Encoding.UTF8.GetString(bytes); // kitchengo enchaine sur sa page VIEWER ("Your design") au lieu de l'ecran THANKS, // et ne passe pas par la sauvegarde cloud : ses rendus viennent d'ailleurs. if (Starting.IsKitchenGo()) { Measure.ShowVIEWER(); } else { Save_WEB.SaveWEB(_G.Form[2].text, xmls, "ai_");// ce bouton seul sauvegarde en ai_ Measure.goTHANKS(_G.Form[0].text, _G.Form[2].text,SendEmail.text, "Email Send"); } } else { // Sans ce message le bouton semblait ne rien faire : CheckAllInput() sort en silence // des qu'un champ obligatoire est vide ou que le courriel est refuse par EmailValidator. print("----------Not All Input Feild-------------------"); _M.PH(16, 0, "898787", 1, 1);// "SVP remplir tous les champs." } // --- (Optionnel) Envoi serveur en parallèle pour journaliser --- //StartCoroutine(SendTextToFile(xmls, this.name)); } public void OpenOnSoft() { FillForm(); _G.FileName = _G.Form != null && _G.Form.Count > 2 ? _G.Form[2].text : "client"; byte[] bytes = SaveXML.BuildXmlBytes(); string xmls = Encoding.UTF8.GetString(bytes); if (_G.FileName != "" || _G.FileName != "FN") { Save_WEB.SaveWEB(_G.Form[2].text, xmls); // mt_ : c'est sous ce prefixe que la ligne au-dessus vient d'ecrire le fichier. Link.openLinkJSPlugin("https://ukitchenit.com/3d/?"+_G.PATH+"?mt_"+ClientEmail.GetComponent().text, "software"); } else { _M.PH(14, 0, "898787", 1, 1); } //Link.openLinkJSPlugin("https://ukitchenit.com/free/soft/?mt_hb@test.ca", "software"); } public void OpenEmailSender() { FillForm();// sinon _G.Form est vide si aucun autre bouton n'a ete utilise avant _G.FileName = FormText(2) != "" ? FormText(2) : "client"; byte[] bytes = SaveXML.BuildXmlBytes(); string xmls = Encoding.UTF8.GetString(bytes); // 2) Préparer message FR/EN string note = (_G.L == 1) ? "Hi, this is a request from a kitchen design" : "Bonjour, voici une demande pour un design de cuisine"; if (this.name == "software") {note = (_G.L == 1) ? "Hi, this is a client who opened a design?" : "Bonjour, voici un client qui a ouvert un design?";} // yournote est branche dans la scene sur le Text de l'InputField ClientNote : il ecrasait // le message d'intro par la note du client. Le message ci-dessus doit toujours ouvrir le // courriel, la note client reste dans sa propre section (voir BuildEmailBody). if (yournote != null && yournote != GetClientNoteText() && !string.IsNullOrEmpty(yournote.text)) {note = yournote.text; }// respecte ce que l’utilisateur a saisi // 3) Destinataire string to = (designer != null && !string.IsNullOrEmpty(designer.text)) ? designer.text.Trim() : "hb@udesignit.ca"; // 4) Sujet & corps string subject = (_G.L == 1) ? "U-kitchen-it client request" : "Demande client U-kitchen-it"; string body = BuildEmailBody(note, xmls); Save_WEB.SaveWEB(FormText(2), xmls); OpenMailClient(to, subject, body); Measure.goTHANKS(_G.Form[0].text, _G.Form[2].text,SendEmail.text, "Email Send"); } // Branche sur le clic de SENDING/"Button message ai" : la fonctionnalite n'existe pas encore. public void ComingSoon() { _M.PH(19, 0, "898787", 1, 1); } private static readonly Color _invalidColor = new(1f, 0.8f, 0.8f); // Couleur de fini retenue dans FINISHCOLORS. Les boutons s'appellent Stainless/Black/White/ // Gold/Coper et _G.PreferencesList garde ce nom brut : on le traduit via la cle "T_". private static string FinishColor(string Key) { if (_G.PreferencesList == null) return ""; if (!_G.PreferencesList.TryGetValue(Key, out string Name)) return ""; return TRANS.Safe(string.IsNullOrEmpty(Name) ? "" : "T_" + Name); } // _G.Island empile les noms bruts des boutons du panneau ISLAND ("Island-Stool-Sink") : // on traduit chaque morceau via sa cle "T_" => "Ilot / Tabouret / Evier". private static string IslandLabel(string Key) { if (string.IsNullOrEmpty(Key)) return ""; string[] Parts = Key.Split('-'); for (int i = 0; i < Parts.Length; i++) Parts[i] = TRANS.Safe("T_" + Parts[i]); return string.Join(" / ", Parts); } private static void SetInputColor(InputField input, bool valid) { var colors = input.colors; colors.normalColor = valid ? Color.white : _invalidColor; input.colors = colors; } private static string CleanInput(string s) { if (s == null) return ""; // Retire quelques “invisibles” courants + trim return s .Replace("\u200B", "") // zero-width space .Replace("\u00A0", " ") // no-break space -> espace normal .Trim(); } public bool CheckAllInput() { bool hasRequiredField = false; foreach (var input in _G.Form) { if (input == null) continue; Debug.Log($"{input.name} text=[{input.text}] len={input.text?.Length}"); // ✅ Exclure la note par référence (pas par nom) if (input == ClientNote) continue; hasRequiredField = true; Transform indicator = input.transform.Find("T_Indicator"); string value = CleanInput(input.text); bool filled = value.Length > 0; if (filled && input == ClientEmail && _clientEmailValidator != null) filled = _clientEmailValidator.IsValid(); if (indicator != null) indicator.gameObject.SetActive(!filled); SetInputColor(input, filled); if (!filled) { // Nomme le champ qui bloque : la boucle s'arrete au premier, donc la Console // ne montrait pas les suivants et on ne savait pas lequel etait en cause. Debug.LogWarning("[Send] BLOQUE PAR ==== " + input.name + (input == ClientEmail ? " (vide ou courriel invalide)" : " (vide)")); return false; } } if (!hasRequiredField) return false; // if (_sendEmailValidator != null) // { // if (!_sendEmailValidator.IsValid()) // { // Transform indicator = SendEmail.transform.Find("T_Indicator"); // if (indicator != null) indicator.gameObject.SetActive(true); // SetInputColor(SendEmail, false); // return false; // } // SetInputColor(SendEmail, true); // _G.designerEmail = SendEmail.text.Trim(); // } return true; } // Construit un corps lisible avec les infos disponibles private string BuildEmailBody(string note, string xml) { string CLIENT_INFO =ToUnicodeSansSerifBold(TRANS.This("T_Client Info").ToUpperInvariant()); string PREFERENCES=ToUnicodeSansSerifBold(TRANS.This("T_Preferences").ToUpperInvariant()); string OPTIONS=ToUnicodeSansSerifBold(TRANS.This("T_OptionsAdd").ToUpperInvariant()); string NOTES=ToUnicodeSansSerifBold(TRANS.This("T_Note").ToUpperInvariant()); string SOFTWARELINK=ToUnicodeSansSerifBold(TRANS.This("T_ClickLink").ToUpperInvariant()); var sb = new StringBuilder(); sb.AppendLine(note); sb.AppendLine(); sb.AppendLine($"{CLIENT_INFO} ;");//Informations client sb.AppendLine("- "+TRANS.This("T_Name") +": "+ FormText(0));//Name sb.AppendLine("- "+TRANS.This("T_Address") +": "+ FormText(1));//Address sb.AppendLine("- "+TRANS.This("T_Email") +": "+ FormText(2));//Email sb.AppendLine("- "+TRANS.This("T_Phone") +": "+ FormText(3));//Phone sb.AppendLine(); //string STYLE="Country,Scandinave"; string STYLE = string.Join(" / ", _G.Style); string DOORMODEL = string.Join(" / ", _G.DoorModel); // CounterTop et Island sont des chaines, pas des listes : string.Join les decouperait // caractere par caractere ("Island-Sink" => "I / s / l / a / n / d..."). // Le courriel affiche le libelle "Categorie / Couleur" (_G.CounterTopName), pas le code // "CERA.8?F7FBFD?..." qui lui part dans le XML. string COUNTERTOP = _G.CounterTopName ?? ""; string WALLCOLOR = string.Join(" / ", _G.RoomColor); string FLOOR = string.Join(" / ", _G.FloorStyle); string ISLAND = IslandLabel(_G.Island); string WALLSCABS = string.Join(" / ", _G.WallsCabs); // Couleurs des finis choisies dans le panneau FINISHCOLORS. string APPLIANCES = FinishColor("ApliancesColor"); string SINKFAUCET = FinishColor("SinkFaucetColor"); string KNOBS = FinishColor("KnobsColor"); sb.AppendLine($"{PREFERENCES} ;");//Preferences sb.AppendLine( "- "+TRANS.This("T_Style")+ " : " + STYLE);//Kitchen style sb.AppendLine( "- "+TRANS.This("T_DoorModel")+ " : " + DOORMODEL); sb.AppendLine( "- "+TRANS.This("T_CounterTop")+ " : " + COUNTERTOP); sb.AppendLine( "- "+TRANS.This("T_WallColor")+ " : " + WALLCOLOR); sb.AppendLine( "- "+TRANS.This("T_Floor")+ " : " + FLOOR ); sb.AppendLine( "- "+TRANS.This("T_Island")+ " : " + ISLAND); sb.AppendLine( "- "+TRANS.This("T_WallsCabs")+ " : " + WALLSCABS); sb.AppendLine( "- "+TRANS.This("T_APPLIANCES")+ " : " + APPLIANCES);//Electromenagers sb.AppendLine( "- "+TRANS.This("T_SIINKFAUCET")+ " : " + SINKFAUCET);//Evier et robinet sb.AppendLine( "- "+TRANS.This("T_KONBS")+ " : " + KNOBS);//Poignees sb.AppendLine(); // Options cochees dans le panneau OPTIONS : une par ligne, les libelles sont des phrases // entieres ("Ajouter portes vitrees si disponible") qui tiennent mal sur une seule ligne. if (_G.OptionsName != null && _G.OptionsName.Count > 0) { sb.AppendLine(OPTIONS+": ");//Options a ajouter foreach (string Option in _G.OptionsName) sb.AppendLine("- " + Option); sb.AppendLine(); } sb.AppendLine($"{NOTES} ;"); sb.AppendLine(FormText(4)); sb.AppendLine(); //SOFTWARE LINK sb.AppendLine($"{SOFTWARELINK} ; "); //sb.AppendLine(TRANS.This("T_SoftLinkInstruction")); //sb.AppendLine($"https://ukitchenit.com/free?mt_{_G.Form[2].text}"); string Endpath = "free"; if(_G.PATH!="free" && _G.PATH!="kitchensdepot"){Endpath="3d/?"+_G.PATH;} sb.AppendLine($"https://ukitchenit.com/"+Endpath+"?mt_"+FormText(2)); sb.AppendLine($"Cloud saved name: mt_{FormText(2)}"); sb.AppendLine(); return sb.ToString(); } // Ouvre le mailto avec encodage sûr private void OpenMailClient(string to, string subject, string body) { string enc(string s) => System.Uri.EscapeDataString(s ?? string.Empty); // Normaliser les retours à la ligne subject = subject?.Replace("\r\n", "\n").Replace("\r", "\n"); body = body?.Replace("\r\n", "\n").Replace("\r", "\n"); body = body?.Replace("\n", "\r\n"); string url = $"mailto:{to}?subject={enc(subject)}&body={enc(body)}"; Application.OpenURL(url); } public static string ToUnicodeSansSerifBold(string input) { if (string.IsNullOrEmpty(input)) return input; var sb = new StringBuilder(input.Length * 2); foreach (char c in input) { if (c >= 'A' && c <= 'Z') { // Mathematical Sans-Serif Bold Capital Letters int codePoint = 0x1D5D4 + (c - 'A'); // 𝗔..𝗭 sb.Append(char.ConvertFromUtf32(codePoint)); } else if (c >= 'a' && c <= 'z') { int codePoint = 0x1D5EE + (c - 'a'); // 𝗮..𝗹 sb.Append(char.ConvertFromUtf32(codePoint)); } else if (c >= '0' && c <= '9') { int codePoint = 0x1D7EC + (c - '0'); // 𝟬..𝟵 sb.Append(char.ConvertFromUtf32(codePoint)); } else { sb.Append(c); } } return sb.ToString(); } }