增加换肤功能
21
TUIKit/TUICore/NSDictionary+TUISafe.h
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// NSDictionary+TUISafe.h
|
||||
// lottie-ios
|
||||
//
|
||||
// Created by kayev on 2021/8/9.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSDictionary (TUISafe)
|
||||
|
||||
- (id)tui_objectForKey:(NSString *)aKey conformProtocol:(Protocol *)pro;
|
||||
|
||||
- (id)tui_objectForKey:(NSString *)aKey asClass:(Class)cls;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
35
TUIKit/TUICore/NSDictionary+TUISafe.m
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// NSDictionary+TUISafe.m
|
||||
// lottie-ios
|
||||
//
|
||||
// Created by kayev on 2021/8/9.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSDictionary+TUISafe.h"
|
||||
|
||||
@implementation NSDictionary (TUISafe)
|
||||
|
||||
- (id)tui_objectForKey:(NSString *)aKey conformProtocol:(Protocol *)pro {
|
||||
NSParameterAssert(aKey);
|
||||
NSParameterAssert(pro);
|
||||
|
||||
NSObject *value = [self objectForKey:aKey];
|
||||
if (value && ![value conformsToProtocol:pro]) {
|
||||
NSAssert(NO, @"value not conforms this protocol");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
- (id)tui_objectForKey:(NSString *)aKey asClass:(Class)cls {
|
||||
NSParameterAssert(aKey);
|
||||
NSParameterAssert(cls);
|
||||
|
||||
NSObject *value = [self objectForKey:aKey];
|
||||
if (value && ![value isKindOfClass:cls]) {
|
||||
NSAssert(NO, @"value's class is error");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@end
|
||||
111
TUIKit/TUICore/NSString+TUIUtil.h
Normal file
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// NSString+TUICommon.h
|
||||
//
|
||||
// Created by Alexi on 12-11-5.
|
||||
// Copyright (c) 2012 . All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
char tui_pinyinFirstLetter(unsigned short hanzi);
|
||||
|
||||
@interface NSString (TUIUtil)
|
||||
|
||||
/**
|
||||
* Hash the string using md5
|
||||
*/
|
||||
+ (NSString *)md5String:(NSString *)str;
|
||||
- (NSString *)md5;
|
||||
|
||||
/**
|
||||
* Get the first letter of Pinyin
|
||||
*/
|
||||
- (NSString *)firstPinYin;
|
||||
|
||||
- (NSString *)safePathString;
|
||||
|
||||
+ (BOOL)isEmpty:(NSString *)string;
|
||||
|
||||
/**
|
||||
* compare two version
|
||||
*
|
||||
* @param sourVersion *.*.*.*
|
||||
* @param desVersion *.*.*.*
|
||||
* @returns No,sourVersion is less than desVersion; YES, the statue is opposed
|
||||
*/
|
||||
+ (BOOL)compareVerison:(NSString *)sourVersion withDes:(NSString *)desVersion;
|
||||
|
||||
/**
|
||||
* Whether the current string contains only whitespace and newlines
|
||||
*/
|
||||
- (BOOL)isWhitespaceAndNewlines;
|
||||
|
||||
/**
|
||||
* Remove whitespace before and after a string, excluding newlines
|
||||
*/
|
||||
- (NSString *)trim;
|
||||
|
||||
/**
|
||||
* Remove all whitespace from a string
|
||||
*/
|
||||
- (NSString *)removeWhiteSpace;
|
||||
- (NSString *)removeNewLine;
|
||||
|
||||
/**
|
||||
* The string with URL-Encoding
|
||||
*/
|
||||
- (NSString *)stringByUrlEncoding;
|
||||
|
||||
/**
|
||||
* Convert the first letter of a string to uppercase
|
||||
*/
|
||||
- (NSString *)capitalize;
|
||||
|
||||
/**
|
||||
* Determines whether a string starts with the given string, ignoring case
|
||||
*/
|
||||
- (BOOL)startsWith:(NSString *)str;
|
||||
- (BOOL)startsWith:(NSString *)str Options:(NSStringCompareOptions)compareOptions;
|
||||
|
||||
/**
|
||||
* Determines whether a string ends with the given string, ignoring case
|
||||
*/
|
||||
- (BOOL)endsWith:(NSString *)str;
|
||||
- (BOOL)endsWith:(NSString *)str Options:(NSStringCompareOptions)compareOptions;
|
||||
|
||||
/**
|
||||
* Determines whether a string contains the given string, ignoring case
|
||||
*/
|
||||
- (BOOL)tui_containsString:(NSString *)str;
|
||||
- (BOOL)tui_containsString:(NSString *)str Options:(NSStringCompareOptions)compareOptions;
|
||||
|
||||
/**
|
||||
* Determines whether a string equals with the given string, ignoring case
|
||||
*/
|
||||
- (BOOL)equalsString:(NSString *)str;
|
||||
|
||||
- (NSString *)emjoiText;
|
||||
|
||||
#pragma mark Hashing
|
||||
#if kSupportGTM64
|
||||
- (NSString *)base64Encoding;
|
||||
#endif
|
||||
|
||||
- (NSString *)valueOfLabel:(NSString *)label;
|
||||
|
||||
- (NSString *)substringAtRange:(NSRange)rang;
|
||||
|
||||
- (NSUInteger)utf8Length;
|
||||
|
||||
- (BOOL)isContainsEmoji;
|
||||
|
||||
- (NSString *)cutBeyondTextInLength:(NSInteger)maxLenth;
|
||||
|
||||
- (CGSize)textSizeIn:(CGSize)size font:(UIFont *)font;
|
||||
- (CGSize)textSizeIn:(CGSize)size font:(UIFont *)font breakMode:(NSLineBreakMode)breakMode;
|
||||
- (CGSize)textSizeIn:(CGSize)size font:(UIFont *)font breakMode:(NSLineBreakMode)breakMode align:(NSTextAlignment)alignment;
|
||||
|
||||
- (CGFloat)widthFromFont:(UIFont *)font;
|
||||
|
||||
@end
|
||||
631
TUIKit/TUICore/NSString+TUIUtil.m
Normal file
@@ -0,0 +1,631 @@
|
||||
//
|
||||
// NSString+Common.m
|
||||
//
|
||||
//
|
||||
// Created by Alexi on 12-11-5.
|
||||
// Copyright (c) 2012 . All rights reserved.
|
||||
//
|
||||
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
#import "NSString+TUIUtil.h"
|
||||
// #import "pinyin.h"
|
||||
#if kSupportGTM64
|
||||
#import "GTMBase64.h"
|
||||
#endif
|
||||
|
||||
#define HANZI_START 19968
|
||||
#define HANZI_COUNT 20902
|
||||
|
||||
static char gFirstLetterArray[HANZI_COUNT] = "ydkqsxnwzssxjbymgcczqpssqbycdscdqldylybssjgyqzjjfgcclzznwdwzjljpfyynnjjtmynzwzhflzppqhgccyynmjqyxxgd"
|
||||
"nnsnsjnjnsnnmlnrxyfsngnnnnqzggllyjlnyzssecykyyhqwjssggyxyqyjtwktjhychmnxjtlhjyqbyxdldwrrjnwysrldzjpc"
|
||||
"bzjjbrcfslnczstzfxxchtrqggddlyccssymmrjcyqzpwwjjyfcrwfdfzqpyddwyxkyjawjffxjbcftzyhhycyswccyxsclcxxwz"
|
||||
"cxnbgnnxbxlzsqsbsjpysazdhmdzbqbscwdzzyytzhbtsyyfzgntnxjywqnknphhlxgybfmjnbjhhgqtjcysxstkzglyckglysmz"
|
||||
"xyalmeldccxgzyrjxjzlnjzcqkcnnjwhjczccqljststbnhbtyxceqxkkwjyflzqlyhjxspsfxlmpbysxxxytccnylllsjxfhjxp"
|
||||
"jbtffyabyxbcczbzyclwlczggbtssmdtjcxpthyqtgjjxcjfzkjzjqnlzwlslhdzbwjncjzyzsqnycqynzcjjwybrtwpyftwexcs"
|
||||
"kdzctbyhyzqyyjxzcfbzzmjyxxsdczottbzljwfckscsxfyrlrygmbdthjxsqjccsbxyytswfbjdztnbcnzlcyzzpsacyzzsqqcs"
|
||||
"hzqydxlbpjllmqxqydzxsqjtzpxlcglqdcwzfhctdjjsfxjejjtlbgxsxjmyjjqpfzasyjnsydjxkjcdjsznbartcclnjqmwnqnc"
|
||||
"lllkbdbzzsyhqcltwlccrshllzntylnewyzyxczxxgdkdmtcedejtsyyssdqdfmxdbjlkrwnqlybglxnlgtgxbqjdznyjsjyjcjm"
|
||||
"rnymgrcjczgjmzmgxmmryxkjnymsgmzzymknfxmbdtgfbhcjhkylpfmdxlxjjsmsqgzsjlqdldgjycalcmzcsdjllnxdjffffjcn"
|
||||
"fnnffpfkhkgdpqxktacjdhhzdddrrcfqyjkqccwjdxhwjlyllzgcfcqjsmlzpbjjblsbcjggdckkdezsqcckjgcgkdjtjllzycxk"
|
||||
"lqccgjcltfpcqczgwbjdqyzjjbyjhsjddwgfsjgzkcjctllfspkjgqjhzzljplgjgjjthjjyjzccmlzlyqbgjwmljkxzdznjqsyz"
|
||||
"mljlljkywxmkjlhskjhbmclyymkxjqlbmllkmdxxkwyxwslmlpsjqqjqxyqfjtjdxmxxllcrqbsyjbgwynnggbcnxpjtgpapfgdj"
|
||||
"qbhbncfjyzjkjkhxqfgqckfhygkhdkllsdjqxpqyaybnqsxqnszswhbsxwhxwbzzxdmndjbsbkbbzklylxgwxjjwaqzmywsjqlsj"
|
||||
"xxjqwjeqxnchetlzalyyyszzpnkyzcptlshtzcfycyxyljsdcjqagyslcllyyysslqqqnldxzsccscadycjysfsgbfrsszqsbxjp"
|
||||
"sjysdrckgjlgtkzjzbdktcsyqpyhstcldjnhmymcgxyzhjdctmhltxzhylamoxyjcltyfbqqjpfbdfehthsqhzywwcncxcdwhowg"
|
||||
"yjlegmdqcwgfjhcsntmydolbygnqwesqpwnmlrydzszzlyqpzgcwxhnxpyxshmdqjgztdppbfbhzhhjyfdzwkgkzbldnzsxhqeeg"
|
||||
"zxylzmmzyjzgszxkhkhtxexxgylyapsthxdwhzydpxagkydxbhnhnkdnjnmyhylpmgecslnzhkxxlbzzlbmlsfbhhgsgyyggbhsc"
|
||||
"yajtxglxtzmcwzydqdqmngdnllszhngjzwfyhqswscelqajynytlsxthaznkzzsdhlaxxtwwcjhqqtddwzbcchyqzflxpslzqgpz"
|
||||
"sznglydqtbdlxntctajdkywnsyzljhhdzckryyzywmhychhhxhjkzwsxhdnxlyscqydpslyzwmypnkxyjlkchtyhaxqsyshxasmc"
|
||||
"hkdscrsgjpwqsgzjlwwschsjhsqnhnsngndantbaalczmsstdqjcjktscjnxplggxhhgoxzcxpdmmhldgtybynjmxhmrzplxjzck"
|
||||
"zxshflqxxcdhxwzpckczcdytcjyxqhlxdhypjqxnlsyydzozjnhhqezysjyayxkypdgxddnsppyzndhthrhxydpcjjhtcnnctlhb"
|
||||
"ynyhmhzllnnxmylllmdcppxhmxdkycyrdltxjchhznxclcclylnzsxnjzzlnnnnwhyqsnjhxynttdkyjpychhyegkcwtwlgjrlgg"
|
||||
"tgtygyhpyhylqyqgcwyqkpyyettttlhyylltyttsylnyzwgywgpydqqzzdqnnkcqnmjjzzbxtqfjkdffbtkhzkbxdjjkdjjtlbwf"
|
||||
"zpptkqtztgpdwntpjyfalqmkgxbcclzfhzcllllanpnxtjklcclgyhdzfgyddgcyyfgydxkssendhykdndknnaxxhbpbyyhxccga"
|
||||
"pfqyjjdmlxcsjzllpcnbsxgjyndybwjspcwjlzkzddtacsbkzdyzypjzqsjnkktknjdjgyepgtlnyqnacdntcyhblgdzhbbydmjr"
|
||||
"egkzyheyybjmcdtafzjzhgcjnlghldwxjjkytcyksssmtwcttqzlpbszdtwcxgzagyktywxlnlcpbclloqmmzsslcmbjcsdzkydc"
|
||||
"zjgqjdsmcytzqqlnzqzxssbpkdfqmddzzsddtdmfhtdycnaqjqkypbdjyyxtljhdrqxlmhkydhrnlklytwhllrllrcxylbnsrnzz"
|
||||
"symqzzhhkyhxksmzsyzgcxfbnbsqlfzxxnnxkxwymsddyqnggqmmyhcdzttfgyyhgsbttybykjdnkyjbelhdypjqnfxfdnkzhqks"
|
||||
"byjtzbxhfdsbdaswpawajldyjsfhblcnndnqjtjnchxfjsrfwhzfmdrfjyxwzpdjkzyjympcyznynxfbytfyfwygdbnzzzdnytxz"
|
||||
"emmqbsqehxfznbmflzzsrsyqjgsxwzjsprytjsjgskjjgljjynzjjxhgjkymlpyyycxycgqzswhwlyrjlpxslcxmnsmwklcdnkny"
|
||||
"npsjszhdzeptxmwywxyysywlxjqcqxzdclaeelmcpjpclwbxsqhfwrtfnjtnqjhjqdxhwlbyccfjlylkyynldxnhycstyywncjtx"
|
||||
"ywtrmdrqnwqcmfjdxzmhmayxnwmyzqtxtlmrspwwjhanbxtgzypxyyrrclmpamgkqjszycymyjsnxtplnbappypylxmyzkynldgy"
|
||||
"jzcchnlmzhhanqnbgwqtzmxxmllhgdzxnhxhrxycjmffxywcfsbssqlhnndycannmtcjcypnxnytycnnymnmsxndlylysljnlxys"
|
||||
"sqmllyzlzjjjkyzzcsfbzxxmstbjgnxnchlsnmcjscyznfzlxbrnnnylmnrtgzqysatswryhyjzmgdhzgzdwybsscskxsyhytsxg"
|
||||
"cqgxzzbhyxjscrhmkkbsczjyjymkqhzjfnbhmqhysnjnzybknqmcjgqhwlsnzswxkhljhyybqcbfcdsxdldspfzfskjjzwzxsddx"
|
||||
"jseeegjscssygclxxnwwyllymwwwgydkzjggggggsycknjwnjpcxbjjtqtjwdsspjxcxnzxnmelptfsxtllxcljxjjljsxctnswx"
|
||||
"lennlyqrwhsycsqnybyaywjejqfwqcqqcjqgxaldbzzyjgkgxbltqyfxjltpydkyqhpmatlcndnkxmtxynhklefxdllegqtymsaw"
|
||||
"hzmljtkynxlyjzljeeyybqqffnlyxhdsctgjhxywlkllxqkcctnhjlqmkkzgcyygllljdcgydhzwypysjbzjdzgyzzhywyfqdtyz"
|
||||
"szyezklymgjjhtsmqwyzljyywzcsrkqyqltdxwcdrjalwsqzwbdcqyncjnnszjlncdcdtlzzzacqqzzddxyblxcbqjylzllljddz"
|
||||
"jgyqyjzyxnyyyexjxksdaznyrdlzyyynjlslldyxjcykywnqcclddnyyynycgczhjxcclgzqjgnwnncqqjysbzzxyjxjnxjfzbsb"
|
||||
"dsfnsfpzxhdwztdmpptflzzbzdmyypqjrsdzsqzsqxbdgcpzswdwcsqzgmdhzxmwwfybpngphdmjthzsmmbgzmbzjcfzhfcbbnmq"
|
||||
"dfmbcmcjxlgpnjbbxgyhyyjgptzgzmqbqdcgybjxlwnkydpdymgcftpfxyztzxdzxtgkptybbclbjaskytssqyymscxfjhhlslls"
|
||||
"jpqjjqaklyldlycctsxmcwfgngbqxllllnyxtyltyxytdpjhnhgnkbyqnfjyyzbyyessessgdyhfhwtcqbsdzjtfdmxhcnjzymqw"
|
||||
"srxjdzjqbdqbbsdjgnfbknbxdkqhmkwjjjgdllthzhhyyyyhhsxztyyyccbdbpypzyccztjpzywcbdlfwzcwjdxxhyhlhwczxjtc"
|
||||
"nlcdpxnqczczlyxjjcjbhfxwpywxzpcdzzbdccjwjhmlxbqxxbylrddgjrrctttgqdczwmxfytmmzcwjwxyywzzkybzcccttqnhx"
|
||||
"nwxxkhkfhtswoccjybcmpzzykbnnzpbthhjdlszddytyfjpxyngfxbyqxzbhxcpxxtnzdnnycnxsxlhkmzxlthdhkghxxsshqyhh"
|
||||
"cjyxglhzxcxnhekdtgqxqypkdhentykcnymyyjmkqyyyjxzlthhqtbyqhxbmyhsqckwwyllhcyylnneqxqwmcfbdccmljggxdqkt"
|
||||
"lxkknqcdgcjwyjjlyhhqyttnwchhxcxwherzjydjccdbqcdgdnyxzdhcqrxcbhztqcbxwgqwyybxhmbymykdyecmqkyaqyngyzsl"
|
||||
"fnkkqgyssqyshngjctxkzycssbkyxhyylstycxqthysmnscpmmgcccccmnztasmgqzjhklosjylswtmqzyqkdzljqqyplzycztcq"
|
||||
"qpbbcjzclpkhqcyyxxdtdddsjcxffllchqxmjlwcjcxtspycxndtjshjwhdqqqckxyamylsjhmlalygxcyydmamdqmlmcznnyybz"
|
||||
"xkyflmcncmlhxrcjjhsylnmtjggzgywjxsrxcwjgjqhqzdqjdcjjskjkgdzcgjjyjylxzxxcdqhhheslmhlfsbdjsyyshfyssczq"
|
||||
"lpbdrfnztzdkykhsccgkwtqzckmsynbcrxqbjyfaxpzzedzcjykbcjwhyjbqzzywnyszptdkzpfpbaztklqnhbbzptpptyzzybhn"
|
||||
"ydcpzmmcycqmcjfzzdcmnlfpbplngqjtbttajzpzbbdnjkljqylnbzqhksjznggqstzkcxchpzsnbcgzkddzqanzgjkdrtlzldwj"
|
||||
"njzlywtxndjzjhxnatncbgtzcsskmljpjytsnwxcfjwjjtkhtzplbhsnjssyjbhbjyzlstlsbjhdnwqpslmmfbjdwajyzccjtbnn"
|
||||
"nzwxxcdslqgdsdpdzgjtqqpsqlyyjzlgyhsdlctcbjtktyczjtqkbsjlgnnzdncsgpynjzjjyyknhrpwszxmtncszzyshbyhyzax"
|
||||
"ywkcjtllckjjtjhgcssxyqyczbynnlwqcglzgjgqyqcczssbcrbcskydznxjsqgxssjmecnstjtpbdlthzwxqwqczexnqczgwesg"
|
||||
"ssbybstscslccgbfsdqnzlccglllzghzcthcnmjgyzazcmsksstzmmzckbjygqljyjppldxrkzyxccsnhshhdznlzhzjjcddcbcj"
|
||||
"xlbfqbczztpqdnnxljcthqzjgylklszzpcjdscqjhjqkdxgpbajynnsmjtzdxlcjyryynhjbngzjkmjxltbsllrzpylssznxjhll"
|
||||
"hyllqqzqlsymrcncxsljmlzltzldwdjjllnzggqxppskyggggbfzbdkmwggcxmcgdxjmcjsdycabxjdlnbcddygskydqdxdjjyxh"
|
||||
"saqazdzfslqxxjnqzylblxxwxqqzbjzlfbblylwdsljhxjyzjwtdjcyfqzqzzdzsxzzqlzcdzfxhwspynpqzmlpplffxjjnzzyls"
|
||||
"jnyqzfpfzgsywjjjhrdjzzxtxxglghtdxcskyswmmtcwybazbjkshfhgcxmhfqhyxxyzftsjyzbxyxpzlchmzmbxhzzssyfdmncw"
|
||||
"dabazlxktcshhxkxjjzjsthygxsxyyhhhjwxkzxssbzzwhhhcwtzzzpjxsyxqqjgzyzawllcwxznxgyxyhfmkhydwsqmnjnaycys"
|
||||
"pmjkgwcqhylajgmzxhmmcnzhbhxclxdjpltxyjkdyylttxfqzhyxxsjbjnayrsmxyplckdnyhlxrlnllstycyyqygzhhsccsmcct"
|
||||
"zcxhyqfpyyrpbflfqnntszlljmhwtcjqyzwtlnmlmdwmbzzsnzrbpdddlqjjbxtcsnzqqygwcsxfwzlxccrszdzmcyggdyqsgtnn"
|
||||
"nlsmymmsyhfbjdgyxccpshxczcsbsjyygjmpbwaffyfnxhydxzylremzgzzyndsznlljcsqfnxxkptxzgxjjgbmyyssnbtylbnlh"
|
||||
"bfzdcyfbmgqrrmzszxysjtznnydzzcdgnjafjbdknzblczszpsgcycjszlmnrznbzzldlnllysxsqzqlcxzlsgkbrxbrbzcycxzj"
|
||||
"zeeyfgklzlnyhgzcgzlfjhgtgwkraajyzkzqtsshjjxdzyznynnzyrzdqqhgjzxsszbtkjbbfrtjxllfqwjgclqtymblpzdxtzag"
|
||||
"bdhzzrbgjhwnjtjxlkscfsmwlldcysjtxkzscfwjlbnntzlljzllqblcqmqqcgcdfpbphzczjlpyyghdtgwdxfczqyyyqysrclqz"
|
||||
"fklzzzgffcqnwglhjycjjczlqzzyjbjzzbpdcsnnjgxdqnknlznnnnpsntsdyfwwdjzjysxyyczcyhzwbbyhxrylybhkjksfxtjj"
|
||||
"mmchhlltnyymsxxyzpdjjycsycwmdjjkqyrhllngpngtlyycljnnnxjyzfnmlrgjjtyzbsyzmsjyjhgfzqmsyxrszcytlrtqzsst"
|
||||
"kxgqkgsptgxdnjsgcqcqhmxggztqydjjznlbznxqlhyqgggthqscbyhjhhkyygkggcmjdzllcclxqsftgjslllmlcskctbljszsz"
|
||||
"mmnytpzsxqhjcnnqnyexzqzcpshkzzyzxxdfgmwqrllqxrfztlystctmjcsjjthjnxtnrztzfqrhcgllgcnnnnjdnlnnytsjtlny"
|
||||
"xsszxcgjzyqpylfhdjsbbdczgjjjqzjqdybssllcmyttmqnbhjqmnygjyeqyqmzgcjkpdcnmyzgqllslnclmholzgdylfzslncnz"
|
||||
"lylzcjeshnyllnxnjxlyjyyyxnbcljsswcqqnnyllzldjnllzllbnylnqchxyyqoxccqkyjxxxyklksxeyqhcqkkkkcsnyxxyqxy"
|
||||
"gwtjohthxpxxhsnlcykychzzcbwqbbwjqcscszsslcylgddsjzmmymcytsdsxxscjpqqsqylyfzychdjynywcbtjsydchcyddjlb"
|
||||
"djjsodzyqyskkyxdhhgqjyohdyxwgmmmazdybbbppbcmnnpnjzsmtxerxjmhqdntpjdcbsnmssythjtslmltrcplzszmlqdsdmjm"
|
||||
"qpnqdxcfrnnfsdqqyxhyaykqyddlqyyysszbydslntfgtzqbzmchdhczcwfdxtmqqsphqwwxsrgjcwnntzcqmgwqjrjhtqjbbgwz"
|
||||
"fxjhnqfxxqywyyhyscdydhhqmrmtmwctbszppzzglmzfollcfwhmmsjzttdhlmyffytzzgzyskjjxqyjzqbhmbzclyghgfmshpcf"
|
||||
"zsnclpbqsnjyzslxxfpmtyjygbxlldlxpzjyzjyhhzcywhjylsjexfszzywxkzjlnadymlymqjpwxxhxsktqjezrpxxzghmhwqpw"
|
||||
"qlyjjqjjzszcnhjlchhnxjlqwzjhbmzyxbdhhypylhlhlgfwlcfyytlhjjcwmscpxstkpnhjxsntyxxtestjctlsslstdlllwwyh"
|
||||
"dnrjzsfgxssyczykwhtdhwjglhtzdqdjzxxqgghltzphcsqfclnjtclzpfstpdynylgmjllycqhynspchylhqyqtmzymbywrfqyk"
|
||||
"jsyslzdnjmpxyyssrhzjnyqtqdfzbwwdwwrxcwggyhxmkmyyyhmxmzhnksepmlqqmtcwctmxmxjpjjhfxyyzsjzhtybmstsyjznq"
|
||||
"jnytlhynbyqclcycnzwsmylknjxlggnnpjgtysylymzskttwlgsmzsylmpwlcwxwqcssyzsyxyrhssntsrwpccpwcmhdhhxzdzyf"
|
||||
"jhgzttsbjhgyglzysmyclllxbtyxhbbzjkssdmalhhycfygmqypjyjqxjllljgclzgqlycjcctotyxmtmshllwlqfxymzmklpszz"
|
||||
"cxhkjyclctyjcyhxsgyxnnxlzwpyjpxhjwpjpwxqqxlxsdhmrslzzydwdtcxknstzshbsccstplwsscjchjlcgchssphylhfhhxj"
|
||||
"sxallnylmzdhzxylsxlmzykcldyahlcmddyspjtqjzlngjfsjshctsdszlblmssmnyymjqbjhrzwtyydchjljapzwbgqxbkfnbjd"
|
||||
"llllyylsjydwhxpsbcmljpscgbhxlqhyrljxyswxhhzlldfhlnnymjljyflyjycdrjlfsyzfsllcqyqfgqyhnszlylmdtdjcnhbz"
|
||||
"llnwlqxygyyhbmgdhxxnhlzzjzxczzzcyqzfngwpylcpkpykpmclgkdgxzgxwqbdxzzkzfbddlzxjtpjpttbythzzdwslcpnhslt"
|
||||
"jxxqlhyxxxywzyswttzkhlxzxzpyhgzhknfsyhntjrnxfjcpjztwhplshfcrhnslxxjxxyhzqdxqwnnhyhmjdbflkhcxcwhjfyjc"
|
||||
"fpqcxqxzyyyjygrpynscsnnnnchkzdyhflxxhjjbyzwttxnncyjjymswyxqrmhxzwfqsylznggbhyxnnbwttcsybhxxwxyhhxyxn"
|
||||
"knyxmlywrnnqlxbbcljsylfsytjzyhyzawlhorjmnsczjxxxyxchcyqryxqzddsjfslyltsffyxlmtyjmnnyyyxltzcsxqclhzxl"
|
||||
"wyxzhnnlrxkxjcdyhlbrlmbrdlaxksnlljlyxxlynrylcjtgncmtlzllcyzlpzpzyawnjjfybdyyzsepckzzqdqpbpsjpdyttbdb"
|
||||
"bbyndycncpjmtmlrmfmmrwyfbsjgygsmdqqqztxmkqwgxllpjgzbqrdjjjfpkjkcxbljmswldtsjxldlppbxcwkcqqbfqbccajzg"
|
||||
"mykbhyhhzykndqzybpjnspxthlfpnsygyjdbgxnhhjhzjhstrstldxskzysybmxjlxyslbzyslzxjhfybqnbylljqkygzmcyzzym"
|
||||
"ccslnlhzhwfwyxzmwyxtynxjhbyymcysbmhysmydyshnyzchmjjmzcaahcbjbbhblytylsxsnxgjdhkxxtxxnbhnmlngsltxmrhn"
|
||||
"lxqqxmzllyswqgdlbjhdcgjyqyymhwfmjybbbyjyjwjmdpwhxqldyapdfxxbcgjspckrssyzjmslbzzjfljjjlgxzgyxyxlszqkx"
|
||||
"bexyxhgcxbpndyhwectwwcjmbtxchxyqqllxflyxlljlssnwdbzcmyjclwswdczpchqekcqbwlcgydblqppqzqfnqdjhymmcxtxd"
|
||||
"rmzwrhxcjzylqxdyynhyyhrslnrsywwjjymtltllgtqcjzyabtckzcjyccqlysqxalmzynywlwdnzxqdllqshgpjfjljnjabcqzd"
|
||||
"jgthhsstnyjfbswzlxjxrhgldlzrlzqzgsllllzlymxxgdzhgbdphzpbrlwnjqbpfdwonnnhlypcnjccndmbcpbzzncyqxldomzb"
|
||||
"lzwpdwyygdstthcsqsccrsssyslfybnntyjszdfndpdhtqzmbqlxlcmyffgtjjqwftmnpjwdnlbzcmmcngbdzlqlpnfhyymjylsd"
|
||||
"chdcjwjcctljcldtljjcbddpndsszycndbjlggjzxsxnlycybjjxxcbylzcfzppgkcxqdzfztjjfjdjxzbnzyjqctyjwhdyczhym"
|
||||
"djxttmpxsplzcdwslshxypzgtfmlcjtacbbmgdewycyzxdszjyhflystygwhkjyylsjcxgywjcbllcsnddbtzbsclyzczzssqdll"
|
||||
"mjyyhfllqllxfdyhabxggnywyypllsdldllbjcyxjznlhljdxyyqytdlllbngpfdfbbqbzzmdpjhgclgmjjpgaehhbwcqxajhhhz"
|
||||
"chxyphjaxhlphjpgpzjqcqzgjjzzgzdmqyybzzphyhybwhazyjhykfgdpfqsdlzmljxjpgalxzdaglmdgxmmzqwtxdxxpfdmmssy"
|
||||
"mpfmdmmkxksyzyshdzkjsysmmzzzmdydyzzczxbmlstmdyemxckjmztyymzmzzmsshhdccjewxxkljsthwlsqlyjzllsjssdppmh"
|
||||
"nlgjczyhmxxhgncjmdhxtkgrmxfwmckmwkdcksxqmmmszzydkmsclcmpcjmhrpxqpzdsslcxkyxtwlkjyahzjgzjwcjnxyhmmbml"
|
||||
"gjxmhlmlgmxctkzmjlyscjsyszhsyjzjcdajzhbsdqjzgwtkqxfkdmsdjlfmnhkzqkjfeypzyszcdpynffmzqykttdzzefmzlbnp"
|
||||
"plplpbpszalltnlkckqzkgenjlwalkxydpxnhsxqnwqnkxqclhyxxmlnccwlymqyckynnlcjnszkpyzkcqzqljbdmdjhlasqlbyd"
|
||||
"wqlwdgbqcryddztjybkbwszdxdtnpjdtcnqnfxqqmgnseclstbhpwslctxxlpwydzklnqgzcqapllkqcylbqmqczqcnjslqzdjxl"
|
||||
"ddhpzqdljjxzqdjyzhhzlkcjqdwjppypqakjyrmpzbnmcxkllzllfqpylllmbsglzysslrsysqtmxyxzqzbscnysyztffmzzsmzq"
|
||||
"hzssccmlyxwtpzgxzjgzgsjzgkddhtqggzllbjdzlsbzhyxyzhzfywxytymsdnzzyjgtcmtnxqyxjscxhslnndlrytzlryylxqht"
|
||||
"xsrtzcgyxbnqqzfhykmzjbzymkbpnlyzpblmcnqyzzzsjztjctzhhyzzjrdyzhnfxklfzslkgjtctssyllgzrzbbjzzklpkbczys"
|
||||
"nnyxbjfbnjzzxcdwlzyjxzzdjjgggrsnjkmsmzjlsjywqsnyhqjsxpjztnlsnshrnynjtwchglbnrjlzxwjqxqkysjycztlqzybb"
|
||||
"ybyzjqdwgyzcytjcjxckcwdkkzxsnkdnywwyyjqyytlytdjlxwkcjnklccpzcqqdzzqlcsfqchqqgssmjzzllbjjzysjhtsjdysj"
|
||||
"qjpdszcdchjkjzzlpycgmzndjxbsjzzsyzyhgxcpbjydssxdzncglqmbtsfcbfdzdlznfgfjgfsmpnjqlnblgqcyyxbqgdjjqsrf"
|
||||
"kztjdhczklbsdzcfytplljgjhtxzcsszzxstjygkgckgynqxjplzbbbgcgyjzgczqszlbjlsjfzgkqqjcgycjbzqtldxrjnbsxxp"
|
||||
"zshszycfwdsjjhxmfczpfzhqhqmqnknlyhtycgfrzgnqxcgpdlbzcsczqlljblhbdcypscppdymzzxgyhckcpzjgslzlnscnsldl"
|
||||
"xbmsdlddfjmkdqdhslzxlsznpqpgjdlybdskgqlbzlnlkyyhzttmcjnqtzzfszqktlljtyyllnllqyzqlbdzlslyyzxmdfszsnxl"
|
||||
"xznczqnbbwskrfbcylctnblgjpmczzlstlxshtzcyzlzbnfmqnlxflcjlyljqcbclzjgnsstbrmhxzhjzclxfnbgxgtqncztmsfz"
|
||||
"kjmssncljkbhszjntnlzdntlmmjxgzjyjczxyhyhwrwwqnztnfjscpyshzjfyrdjsfscjzbjfzqzchzlxfxsbzqlzsgyftzdcszx"
|
||||
"zjbjpszkjrhxjzcgbjkhcggtxkjqglxbxfgtrtylxqxhdtsjxhjzjjcmzlcqsbtxwqgxtxxhxftsdkfjhzyjfjxnzldlllcqsqqz"
|
||||
"qwqxswqtwgwbzcgcllqzbclmqjtzgzyzxljfrmyzflxnsnxxjkxrmjdzdmmyxbsqbhgzmwfwygmjlzbyytgzyccdjyzxsngnyjyz"
|
||||
"nbgpzjcqsyxsxrtfyzgrhztxszzthcbfclsyxzlzqmzlmplmxzjssfsbysmzqhxxnxrxhqzzzsslyflczjrcrxhhzxqndshxsjjh"
|
||||
"qcjjbcynsysxjbqjpxzqplmlxzkyxlxcnlcycxxzzlxdlllmjyhzxhyjwkjrwyhcpsgnrzlfzwfzznsxgxflzsxzzzbfcsyjdbrj"
|
||||
"krdhhjxjljjtgxjxxstjtjxlyxqfcsgswmsbctlqzzwlzzkxjmltmjyhsddbxgzhdlbmyjfrzfcgclyjbpmlysmsxlszjqqhjzfx"
|
||||
"gfqfqbphngyyqxgztnqwyltlgwgwwhnlfmfgzjmgmgbgtjflyzzgzyzaflsspmlbflcwbjztljjmzlpjjlymqtmyyyfbgygqzgly"
|
||||
"zdxqyxrqqqhsxyyqxygjtyxfsfsllgnqcygycwfhcccfxpylypllzqxxxxxqqhhsshjzcftsczjxspzwhhhhhapylqnlpqafyhxd"
|
||||
"ylnkmzqgggddesrenzltzgchyppcsqjjhclljtolnjpzljlhymhezdydsqycddhgznndzclzywllznteydgnlhslpjjbdgwxpcnn"
|
||||
"tycklkclwkllcasstknzdnnjttlyyzssysszzryljqkcgdhhyrxrzydgrgcwcgzqffbppjfzynakrgywyjpqxxfkjtszzxswzddf"
|
||||
"bbqtbgtzkznpzfpzxzpjszbmqhkyyxyldkljnypkyghgdzjxxeaxpnznctzcmxcxmmjxnkszqnmnlwbwwqjjyhclstmcsxnjcxxt"
|
||||
"pcnfdtnnpglllzcjlspblpgjcdtnjjlyarscffjfqwdpgzdwmrzzcgodaxnssnyzrestyjwjyjdbcfxnmwttbqlwstszgybljpxg"
|
||||
"lbnclgpcbjftmxzljylzxcltpnclcgxtfzjshcrxsfysgdkntlbyjcyjllstgqcbxnhzxbxklylhzlqzlnzcqwgzlgzjncjgcmnz"
|
||||
"zgjdzxtzjxycyycxxjyyxjjxsssjstsstdppghtcsxwzdcsynptfbchfbblzjclzzdbxgcjlhpxnfzflsyltnwbmnjhszbmdnbcy"
|
||||
"sccldnycndqlyjjhmqllcsgljjsyfpyyccyltjantjjpwycmmgqyysxdxqmzhszxbftwwzqswqrfkjlzjqqyfbrxjhhfwjgzyqac"
|
||||
"myfrhcyybynwlpexcczsyyrlttdmqlrkmpbgmyyjprkznbbsqyxbhyzdjdnghpmfsgbwfzmfqmmbzmzdcgjlnnnxyqgmlrygqccy"
|
||||
"xzlwdkcjcggmcjjfyzzjhycfrrcmtznzxhkqgdjxccjeascrjthpljlrzdjrbcqhjdnrhylyqjsymhzydwcdfryhbbydtssccwbx"
|
||||
"glpzmlzjdqsscfjmmxjcxjytycghycjwynsxlfemwjnmkllswtxhyyyncmmcyjdqdjzglljwjnkhpzggflccsczmcbltbhbqjxqd"
|
||||
"jpdjztghglfjawbzyzjltstdhjhctcbchflqmpwdshyytqwcnntjtlnnmnndyyyxsqkxwyyflxxnzwcxypmaelyhgjwzzjbrxxaq"
|
||||
"jfllpfhhhytzzxsgqjmhspgdzqwbwpjhzjdyjcqwxkthxsqlzyymysdzgnqckknjlwpnsyscsyzlnmhqsyljxbcxtlhzqzpcycyk"
|
||||
"pppnsxfyzjjrcemhszmnxlxglrwgcstlrsxbygbzgnxcnlnjlclynymdxwtzpalcxpqjcjwtcyyjlblxbzlqmyljbghdslssdmxm"
|
||||
"bdczsxyhamlczcpjmcnhjyjnsykchskqmczqdllkablwjqsfmocdxjrrlyqchjmybyqlrhetfjzfrfksryxfjdwtsxxywsqjysly"
|
||||
"xwjhsdlxyyxhbhawhwjcxlmyljcsqlkydttxbzslfdxgxsjkhsxxybssxdpwncmrptqzczenygcxqfjxkjbdmljzmqqxnoxslyxx"
|
||||
"lylljdzptymhbfsttqqwlhsgynlzzalzxclhtwrrqhlstmypyxjjxmnsjnnbryxyjllyqyltwylqyfmlkljdnlltfzwkzhljmlhl"
|
||||
"jnljnnlqxylmbhhlnlzxqchxcfxxlhyhjjgbyzzkbxscqdjqdsndzsygzhhmgsxcsymxfepcqwwrbpyyjqryqcyjhqqzyhmwffhg"
|
||||
"zfrjfcdbxntqyzpcyhhjlfrzgpbxzdbbgrqstlgdgylcqmgchhmfywlzyxkjlypjhsywmqqggzmnzjnsqxlqsyjtcbehsxfszfxz"
|
||||
"wfllbcyyjdytdthwzsfjmqqyjlmqsxlldttkghybfpwdyysqqrnqwlgwdebzwcyygcnlkjxtmxmyjsxhybrwfymwfrxyymxysctz"
|
||||
"ztfykmldhqdlgyjnlcryjtlpsxxxywlsbrrjwxhqybhtydnhhxmmywytycnnmnssccdalwztcpqpyjllqzyjswjwzzmmglmxclmx"
|
||||
"nzmxmzsqtzppjqblpgxjzhfljjhycjsrxwcxsncdlxsyjdcqzxslqyclzxlzzxmxqrjmhrhzjbhmfljlmlclqnldxzlllfyprgjy"
|
||||
"nxcqqdcmqjzzxhnpnxzmemmsxykynlxsxtljxyhwdcwdzhqyybgybcyscfgfsjnzdrzzxqxrzrqjjymcanhrjtldbpyzbstjhxxz"
|
||||
"ypbdwfgzzrpymnnkxcqbyxnbnfyckrjjcmjegrzgyclnnzdnkknsjkcljspgyyclqqjybzssqlllkjftbgtylcccdblsppfylgyd"
|
||||
"tzjqjzgkntsfcxbdkdxxhybbfytyhbclnnytgdhryrnjsbtcsnyjqhklllzslydxxwbcjqsbxnpjzjzjdzfbxxbrmladhcsnclbj"
|
||||
"dstblprznswsbxbcllxxlzdnzsjpynyxxyftnnfbhjjjgbygjpmmmmsszljmtlyzjxswxtyledqpjmpgqzjgdjlqjwjqllsdgjgy"
|
||||
"gmscljjxdtygjqjjjcjzcjgdzdshqgzjggcjhqxsnjlzzbxhsgzxcxyljxyxyydfqqjhjfxdhctxjyrxysqtjxyefyyssyxjxncy"
|
||||
"zxfxcsxszxyyschshxzzzgzzzgfjdldylnpzgsjaztyqzpbxcbdztzczyxxyhhscjshcggqhjhgxhsctmzmehyxgebtclzkkwytj"
|
||||
"zrslekestdbcyhqqsayxcjxwwgsphjszsdncsjkqcxswxfctynydpccczjqtcwjqjzzzqzljzhlsbhpydxpsxshhezdxfptjqyzc"
|
||||
"xhyaxncfzyyhxgnqmywntzsjbnhhgymxmxqcnssbcqsjyxxtyyhybcqlmmszmjzzllcogxzaajzyhjmchhcxzsxsdznleyjjzjbh"
|
||||
"zwjzsqtzpsxzzdsqjjjlnyazphhyysrnqzthzhnyjyjhdzxzlswclybzyecwcycrylchzhzydzydyjdfrjjhtrsqtxyxjrjhojyn"
|
||||
"xelxsfsfjzghpzsxzszdzcqzbyyklsgsjhczshdgqgxyzgxchxzjwyqwgyhksseqzzndzfkwyssdclzstsymcdhjxxyweyxczayd"
|
||||
"mpxmdsxybsqmjmzjmtjqlpjyqzcgqhyjhhhqxhlhdldjqcfdwbsxfzzyyschtytyjbhecxhjkgqfxbhyzjfxhwhbdzfyzbchpnpg"
|
||||
"dydmsxhkhhmamlnbyjtmpxejmcthqbzyfcgtyhwphftgzzezsbzegpbmdskftycmhbllhgpzjxzjgzjyxzsbbqsczzlzscstpgxm"
|
||||
"jsfdcczjzdjxsybzlfcjsazfgszlwbczzzbyztzynswyjgxzbdsynxlgzbzfygczxbzhzftpbgzgejbstgkdmfhyzzjhzllzzgjq"
|
||||
"zlsfdjsscbzgpdlfzfzszyzyzsygcxsnxxchczxtzzljfzgqsqqxcjqccccdjcdszzyqjccgxztdlgscxzsyjjqtcclqdqztqchq"
|
||||
"qyzynzzzpbkhdjfcjfztypqyqttynlmbdktjcpqzjdzfpjsbnjlgyjdxjdcqkzgqkxclbzjtcjdqbxdjjjstcxnxbxqmslyjcxnt"
|
||||
"jqwwcjjnjjlllhjcwqtbzqqczczpzzdzyddcyzdzccjgtjfzdprntctjdcxtqzdtjnplzbcllctdsxkjzqdmzlbznbtjdcxfczdb"
|
||||
"czjjltqqpldckztbbzjcqdcjwynllzlzccdwllxwzlxrxntqjczxkjlsgdnqtddglnlajjtnnynkqlldzntdnycygjwyxdxfrsqs"
|
||||
"tcdenqmrrqzhhqhdldazfkapbggpzrebzzykyqspeqjjglkqzzzjlysyhyzwfqznlzzlzhwcgkypqgnpgblplrrjyxcccgyhsfzf"
|
||||
"wbzywtgzxyljczwhncjzplfflgskhyjdeyxhlpllllcygxdrzelrhgklzzyhzlyqszzjzqljzflnbhgwlczcfjwspyxzlzlxgccp"
|
||||
"zbllcxbbbbnbbcbbcrnnzccnrbbnnldcgqyyqxygmqzwnzytyjhyfwtehznjywlccntzyjjcdedpwdztstnjhtymbjnyjzlxtsst"
|
||||
"phndjxxbyxqtzqddtjtdyztgwscszqflshlnzbcjbhdlyzjyckwtydylbnydsdsycctyszyyebgexhqddwnygyclxtdcystqnygz"
|
||||
"ascsszzdzlcclzrqxyywljsbymxshzdembbllyyllytdqyshymrqnkfkbfxnnsbychxbwjyhtqbpbsbwdzylkgzskyghqzjxhxjx"
|
||||
"gnljkzlyycdxlfwfghljgjybxblybxqpqgntzplncybxdjyqydymrbeyjyyhkxxstmxrczzjwxyhybmcflyzhqyzfwxdbxbcwzms"
|
||||
"lpdmyckfmzklzcyqycclhxfzlydqzpzygyjyzmdxtzfnnyttqtzhgsfcdmlccytzxjcytjmkslpzhysnwllytpzctzccktxdhxxt"
|
||||
"qcyfksmqccyyazhtjplylzlyjbjxtfnyljyynrxcylmmnxjsmybcsysslzylljjgyldzdlqhfzzblfndsqkczfyhhgqmjdsxyctt"
|
||||
"xnqnjpyybfcjtyyfbnxejdgyqbjrcnfyyqpghyjsyzngrhtknlnndzntsmgklbygbpyszbydjzsstjztsxzbhbscsbzczptqfzlq"
|
||||
"flypybbjgszmnxdjmtsyskkbjtxhjcegbsmjyjzcstmljyxrczqscxxqpyzhmkyxxxjcljyrmyygadyskqlnadhrskqxzxztcggz"
|
||||
"dlmlwxybwsyctbhjhcfcwzsxwwtgzlxqshnyczjxemplsrcgltnzntlzjcyjgdtclglbllqpjmzpapxyzlaktkdwczzbncctdqqz"
|
||||
"qyjgmcdxltgcszlmlhbglkznnwzndxnhlnmkydlgxdtwcfrjerctzhydxykxhwfzcqshknmqqhzhhymjdjskhxzjzbzzxympajnm"
|
||||
"ctbxlsxlzynwrtsqgscbptbsgzwyhtlkssswhzzlyytnxjgmjrnsnnnnlskztxgxlsammlbwldqhylakqcqctmycfjbslxclzjcl"
|
||||
"xxknbnnzlhjphqplsxsckslnhpsfqcytxjjzljldtzjjzdlydjntptnndskjfsljhylzqqzlbthydgdjfdbyadxdzhzjnthqbykn"
|
||||
"xjjqczmlljzkspldsclbblnnlelxjlbjycxjxgcnlcqplzlznjtsljgyzdzpltqcssfdmnycxgbtjdcznbgbqyqjwgkfhtnbyqzq"
|
||||
"gbkpbbyzmtjdytblsqmbsxtbnpdxklemyycjynzdtldykzzxtdxhqshygmzsjycctayrzlpwltlkxslzcggexclfxlkjrtlqjaqz"
|
||||
"ncmbqdkkcxglczjzxjhptdjjmzqykqsecqzdshhadmlzfmmzbgntjnnlhbyjbrbtmlbyjdzxlcjlpldlpcqdhlhzlycblcxccjad"
|
||||
"qlmzmmsshmybhbnkkbhrsxxjmxmdznnpklbbrhgghfchgmnklltsyyycqlcskymyehywxnxqywbawykqldnntndkhqcgdqktgpkx"
|
||||
"hcpdhtwnmssyhbwcrwxhjmkmzngwtmlkfghkjyldyycxwhyyclqhkqhtdqkhffldxqwytyydesbpkyrzpjfyyzjceqdzzdlattpb"
|
||||
"fjllcxdlmjsdxegwgsjqxcfbssszpdyzcxznyxppzydlyjccpltxlnxyzyrscyyytylwwndsahjsygyhgywwaxtjzdaxysrltdps"
|
||||
"syxfnejdxyzhlxlllzhzsjnyqyqyxyjghzgjcyjchzlycdshhsgczyjscllnxzjjyyxnfsmwfpyllyllabmddhwzxjmcxztzpmlq"
|
||||
"chsfwzynctlndywlslxhymmylmbwwkyxyaddxylldjpybpwnxjmmmllhafdllaflbnhhbqqjqzjcqjjdjtffkmmmpythygdrjrdd"
|
||||
"wrqjxnbysrmzdbyytbjhpymyjtjxaahggdqtmystqxkbtzbkjlxrbyqqhxmjjbdjntgtbxpgbktlgqxjjjcdhxqdwjlwrfmjgwqh"
|
||||
"cnrxswgbtgygbwhswdwrfhwytjjxxxjyzyslphyypyyxhydqpxshxyxgskqhywbdddpplcjlhqeewjgsyykdpplfjthkjltcyjhh"
|
||||
"jttpltzzcdlyhqkcjqysteeyhkyzyxxyysddjkllpymqyhqgxqhzrhbxpllnqydqhxsxxwgdqbshyllpjjjthyjkyphthyyktyez"
|
||||
"yenmdshlzrpqfbnfxzbsftlgxsjbswyysksflxlpplbbblnsfbfyzbsjssylpbbffffsscjdstjsxtryjcyffsyzyzbjtlctsbsd"
|
||||
"hrtjjbytcxyyeylycbnebjdsysyhgsjzbxbytfzwgenhhhthjhhxfwgcstbgxklstyymtmbyxjskzscdyjrcythxzfhmymcxlzns"
|
||||
"djtxtxrycfyjsbsdyerxhljxbbdeynjghxgckgscymblxjmsznskgxfbnbbthfjyafxwxfbxmyfhdttcxzzpxrsywzdlybbktyqw"
|
||||
"qjbzypzjznjpzjlztfysbttslmptzrtdxqsjehbnylndxljsqmlhtxtjecxalzzspktlzkqqyfsyjywpcpqfhjhytqxzkrsgtksq"
|
||||
"czlptxcdyyzsslzslxlzmacpcqbzyxhbsxlzdltztjtylzjyytbzypltxjsjxhlbmytxcqrblzssfjzztnjytxmyjhlhpblcyxqj"
|
||||
"qqkzzscpzkswalqsplczzjsxgwwwygyatjbbctdkhqhkgtgpbkqyslbxbbckbmllndzstbklggqkqlzbkktfxrmdkbftpzfrtppm"
|
||||
"ferqnxgjpzsstlbztpszqzsjdhljqlzbpmsmmsxlqqnhknblrddnhxdkddjcyyljfqgzlgsygmjqjkhbpmxyxlytqwlwjcpbmjxc"
|
||||
"yzydrjbhtdjyeqshtmgsfyplwhlzffnynnhxqhpltbqpfbjwjdbygpnxtbfzjgnnntjshxeawtzylltyqbwjpgxghnnkndjtmszs"
|
||||
"qynzggnwqtfhclssgmnnnnynzqqxncjdqgzdlfnykljcjllzlmzznnnnsshthxjlzjbbhqjwwycrdhlyqqjbeyfsjhthnrnwjhwp"
|
||||
"slmssgzttygrqqwrnlalhmjtqjsmxqbjjzjqzyzkxbjqxbjxshzssfglxmxnxfghkzszggslcnnarjxhnlllmzxelglxydjytlfb"
|
||||
"kbpnlyzfbbhptgjkwetzhkjjxzxxglljlstgshjjyqlqzfkcgnndjsszfdbctwwseqfhqjbsaqtgypjlbxbmmywxgslzhglsgnyf"
|
||||
"ljbyfdjfngsfmbyzhqffwjsyfyjjphzbyyzffwotjnlmftwlbzgyzqxcdjygzyyryzynyzwegazyhjjlzrthlrmgrjxzclnnnljj"
|
||||
"yhtbwjybxxbxjjtjteekhwslnnlbsfazpqqbdlqjjtyyqlyzkdksqjnejzldqcgjqnnjsncmrfqthtejmfctyhypymhydmjncfgy"
|
||||
"yxwshctxrljgjzhzcyyyjltkttntmjlzclzzayyoczlrlbszywjytsjyhbyshfjlykjxxtmzyyltxxypslqyjzyzyypnhmymdyyl"
|
||||
"blhlsyygqllnjjymsoycbzgdlyxylcqyxtszegxhzglhwbljheyxtwqmakbpqcgyshhegqcmwyywljyjhyyzlljjylhzyhmgsljl"
|
||||
"jxcjjyclycjbcpzjzjmmwlcjlnqljjjlxyjmlszljqlycmmgcfmmfpqqmfxlqmcffqmmmmhnznfhhjgtthxkhslnchhyqzxtmmqd"
|
||||
"cydyxyqmyqylddcyaytazdcymdydlzfffmmycqcwzzmabtbyctdmndzggdftypcgqyttssffwbdttqssystwnjhjytsxxylbyyhh"
|
||||
"whxgzxwznnqzjzjjqjccchykxbzszcnjtllcqxynjnckycynccqnxyewyczdcjycchyjlbtzyycqwlpgpyllgktltlgkgqbgychj"
|
||||
"xy";
|
||||
|
||||
char tui_pinyinFirstLetter(unsigned short hanzi) {
|
||||
int index = hanzi - HANZI_START;
|
||||
if (index >= 0 && index <= HANZI_COUNT) {
|
||||
return gFirstLetterArray[index];
|
||||
} else {
|
||||
return '[';
|
||||
}
|
||||
}
|
||||
|
||||
@implementation NSString (TUIUtil)
|
||||
|
||||
+ (NSString *)md5String:(NSString *)str;
|
||||
{
|
||||
const char *cStr = [str UTF8String];
|
||||
unsigned char result[CC_MD5_DIGEST_LENGTH];
|
||||
CC_MD5(cStr, (uint32_t)strlen(cStr), result);
|
||||
return [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", result[0], result[1], result[2], result[3],
|
||||
result[4], result[5], result[6], result[7], result[8], result[9], result[10], result[11], result[12], result[13],
|
||||
result[14], result[15]];
|
||||
}
|
||||
|
||||
- (NSString *)md5 {
|
||||
return [NSString md5String:self];
|
||||
}
|
||||
|
||||
- (NSString *)firstPinYin {
|
||||
if ([self length] == 0) {
|
||||
return [NSString stringWithFormat:@"%c", '['];
|
||||
}
|
||||
|
||||
if ([self canBeConvertedToEncoding:NSASCIIStringEncoding]) { // it is english words
|
||||
return [self substringToIndex:1];
|
||||
}
|
||||
|
||||
unichar ch = [self characterAtIndex:0];
|
||||
char firstPinYin = ch;
|
||||
if (ch < 'A' || ch > 'z' || (ch > 'Z' && ch < 'a')) {
|
||||
firstPinYin = tui_pinyinFirstLetter(ch);
|
||||
}
|
||||
|
||||
return [NSString stringWithFormat:@"%c", firstPinYin];
|
||||
}
|
||||
|
||||
#pragma mark - Utils
|
||||
+ (BOOL)isEmpty:(NSString *)string {
|
||||
return string == nil || string.length == 0;
|
||||
}
|
||||
|
||||
- (BOOL)isWhitespaceAndNewlines {
|
||||
NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
|
||||
for (NSInteger i = 0; i < self.length; ++i) {
|
||||
unichar c = [self characterAtIndex:i];
|
||||
if (![whitespace characterIsMember:c]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSString *)trim {
|
||||
return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
}
|
||||
|
||||
- (NSString *)removeWhiteSpace {
|
||||
return [[self componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] componentsJoinedByString:@""];
|
||||
}
|
||||
|
||||
- (NSString *)removeNewLine {
|
||||
return [[self componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] componentsJoinedByString:@""];
|
||||
}
|
||||
|
||||
- (NSString *)stringByUrlEncoding {
|
||||
NSString *url = (NSString *)CFBridgingRelease(
|
||||
CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)self, NULL, (CFStringRef) @"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8));
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
- (NSString *)capitalize {
|
||||
if (self == nil || [self length] == 0) return self;
|
||||
return [[self substringToIndex:1].uppercaseString stringByAppendingString:[self substringFromIndex:1]];
|
||||
}
|
||||
|
||||
- (BOOL)startsWith:(NSString *)str {
|
||||
return [self startsWith:str Options:NSCaseInsensitiveSearch];
|
||||
}
|
||||
|
||||
- (BOOL)startsWith:(NSString *)str Options:(NSStringCompareOptions)compareOptions {
|
||||
return (str != nil) && ([str length] > 0) && ([self length] >= [str length]) && ([self rangeOfString:str options:compareOptions].location == 0);
|
||||
}
|
||||
|
||||
- (BOOL)endsWith:(NSString *)str {
|
||||
return [self endsWith:str Options:NSCaseInsensitiveSearch];
|
||||
}
|
||||
|
||||
- (BOOL)endsWith:(NSString *)str Options:(NSStringCompareOptions)compareOptions {
|
||||
return (str != nil) && ([str length] > 0) && ([self length] >= [str length]) &&
|
||||
([self rangeOfString:str options:(compareOptions | NSBackwardsSearch)].location == ([self length] - [str length]));
|
||||
}
|
||||
|
||||
- (BOOL)tui_containsString:(NSString *)str {
|
||||
return [self tui_containsString:str Options:NSCaseInsensitiveSearch];
|
||||
}
|
||||
|
||||
- (BOOL)tui_containsString:(NSString *)str Options:(NSStringCompareOptions)compareOptions {
|
||||
return (str != nil) && ([str length] > 0) && ([self length] >= [str length]) && ([self rangeOfString:str options:compareOptions].location != NSNotFound);
|
||||
}
|
||||
|
||||
- (BOOL)equalsString:(NSString *)str {
|
||||
return (str != nil) && ([self length] == [str length]) && ([self rangeOfString:str options:NSCaseInsensitiveSearch].location == 0);
|
||||
}
|
||||
|
||||
#pragma mark XML Extensions
|
||||
+ (NSString *)encodeXMLCharactersIn:(NSString *)source {
|
||||
if (![source isKindOfClass:[NSString class]] || !source) {
|
||||
return @"";
|
||||
}
|
||||
|
||||
NSString *result = [NSString stringWithString:source];
|
||||
|
||||
if ([result rangeOfString:@"&"].location != NSNotFound) {
|
||||
result = [[result componentsSeparatedByString:@"&"] componentsJoinedByString:@"&"];
|
||||
}
|
||||
|
||||
if ([result rangeOfString:@"<"].location != NSNotFound) {
|
||||
result = [[result componentsSeparatedByString:@"<"] componentsJoinedByString:@"<"];
|
||||
}
|
||||
|
||||
if ([result rangeOfString:@">"].location != NSNotFound) {
|
||||
result = [[result componentsSeparatedByString:@">"] componentsJoinedByString:@">"];
|
||||
}
|
||||
|
||||
if ([result rangeOfString:@"\""].location != NSNotFound) {
|
||||
result = [[result componentsSeparatedByString:@"\""] componentsJoinedByString:@"""];
|
||||
}
|
||||
|
||||
if ([result rangeOfString:@"'"].location != NSNotFound) {
|
||||
result = [[result componentsSeparatedByString:@"'"] componentsJoinedByString:@"'"];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (NSString *)decodeXMLCharactersIn:(NSString *)source {
|
||||
if (![source isKindOfClass:[NSString class]] || !source) {
|
||||
return @"";
|
||||
}
|
||||
|
||||
NSString *result = [NSString stringWithString:source];
|
||||
|
||||
if ([result rangeOfString:@"&"].location != NSNotFound) {
|
||||
result = [[result componentsSeparatedByString:@"&"] componentsJoinedByString:@"&"];
|
||||
}
|
||||
|
||||
if ([result rangeOfString:@"<"].location != NSNotFound) {
|
||||
result = [[result componentsSeparatedByString:@"<"] componentsJoinedByString:@"<"];
|
||||
}
|
||||
|
||||
if ([result rangeOfString:@">"].location != NSNotFound) {
|
||||
result = [[result componentsSeparatedByString:@">"] componentsJoinedByString:@">"];
|
||||
}
|
||||
|
||||
if ([result rangeOfString:@"""].location != NSNotFound) {
|
||||
result = [[result componentsSeparatedByString:@"""] componentsJoinedByString:@"\""];
|
||||
}
|
||||
|
||||
if ([result rangeOfString:@"'"].location != NSNotFound) {
|
||||
result = [[result componentsSeparatedByString:@"'"] componentsJoinedByString:@"'"];
|
||||
}
|
||||
|
||||
if ([result rangeOfString:@" "].location != NSNotFound) {
|
||||
result = [[result componentsSeparatedByString:@" "] componentsJoinedByString:@" "];
|
||||
}
|
||||
|
||||
if ([result rangeOfString:@"“"].location != NSNotFound) {
|
||||
result = [[result componentsSeparatedByString:@"“"] componentsJoinedByString:@"\""];
|
||||
}
|
||||
|
||||
if ([result rangeOfString:@"”"].location != NSNotFound) {
|
||||
result = [[result componentsSeparatedByString:@"”"] componentsJoinedByString:@"\""];
|
||||
}
|
||||
|
||||
if ([result rangeOfString:@"'"].location != NSNotFound) {
|
||||
result = [[result componentsSeparatedByString:@"'"] componentsJoinedByString:@"'"];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
compare two version
|
||||
@param sourVersion *.*.*.*
|
||||
@param desVersion *.*.*.*
|
||||
@returns No,sourVersion is less than desVersion; YES, the statue is opposed
|
||||
*/
|
||||
+ (BOOL)compareVerison:(NSString *)sourVersion withDes:(NSString *)desVersion {
|
||||
NSArray *sourArr = [sourVersion componentsSeparatedByString:@"."];
|
||||
NSArray *desArr = [desVersion componentsSeparatedByString:@"."];
|
||||
int sourInt, desInt;
|
||||
NSMutableString *sourStr = [[NSMutableString alloc] init];
|
||||
NSMutableString *desStr = [[NSMutableString alloc] init];
|
||||
|
||||
if ([sourArr count] < [desArr count]) {
|
||||
return YES;
|
||||
} else {
|
||||
}
|
||||
|
||||
for (int i = 0; i < [sourArr count]; i++) {
|
||||
[sourStr appendFormat:@"%@", [sourArr objectAtIndex:i]];
|
||||
[desStr appendFormat:@"%@", [desArr objectAtIndex:i]];
|
||||
}
|
||||
sourInt = [sourStr intValue];
|
||||
desInt = [desStr intValue];
|
||||
if (sourInt < desInt) {
|
||||
return YES;
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
#if kSupportGTM64
|
||||
#pragma mark - hashing
|
||||
- (NSString *)base64Encoding {
|
||||
NSData *stringData = [self dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSString *encodedString = [GTMBase64 stringByEncodingData:stringData];
|
||||
|
||||
return encodedString;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if kSupportNSDataCommon
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Calculate the md5 hash using CC_MD5.
|
||||
*
|
||||
* @returns md5 hash of this string.
|
||||
*/
|
||||
- (NSString *)md5Hash {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding] md5Hash];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Calculate the SHA1 hash using CommonCrypto CC_SHA1.
|
||||
*
|
||||
* @returns SHA1 hash of this string.
|
||||
*/
|
||||
- (NSString *)sha1Hash {
|
||||
return [[self dataUsingEncoding:NSUTF8StringEncoding] sha1Hash];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (NSString *)valueOfLabel:(NSString *)label {
|
||||
NSError *error = nil;
|
||||
|
||||
NSString *reg = [NSString stringWithFormat:@"(?<=%@\\>).*(?=</%@)", label, label];
|
||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:reg options:0 error:&error];
|
||||
|
||||
if (regex != nil) {
|
||||
NSTextCheckingResult *firstMatch = [regex firstMatchInString:self options:0 range:NSMakeRange(0, [self length])];
|
||||
|
||||
if (firstMatch) {
|
||||
NSRange resultRange = [firstMatch rangeAtIndex:0];
|
||||
NSString *result = [self substringAtRange:resultRange];
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)substringAtRange:(NSRange)rang {
|
||||
if ([NSString isEmpty:self]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (rang.location > self.length) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (rang.location + rang.length > self.length) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [self substringWithRange:rang];
|
||||
}
|
||||
|
||||
- (NSString *)emjoiText {
|
||||
if (self.length) {
|
||||
NSData *data = [self dataUsingEncoding:NSNonLossyASCIIStringEncoding];
|
||||
NSString *valueUnicode = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
NSData *dataa = [valueUnicode dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSString *valueEmoj = [[NSString alloc] initWithData:dataa encoding:NSNonLossyASCIIStringEncoding];
|
||||
return valueEmoj;
|
||||
} else {
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSUInteger)utf8Length {
|
||||
size_t length = strlen([self UTF8String]);
|
||||
return length;
|
||||
}
|
||||
|
||||
- (BOOL)isContainsEmoji;
|
||||
{
|
||||
__block BOOL returnValue = NO;
|
||||
|
||||
[self enumerateSubstringsInRange:NSMakeRange(0, [self length])
|
||||
options:NSStringEnumerationByComposedCharacterSequences
|
||||
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
|
||||
const unichar hs = [substring characterAtIndex:0];
|
||||
if (0xd800 <= hs && hs <= 0xdbff) {
|
||||
if (substring.length > 1) {
|
||||
const unichar ls = [substring characterAtIndex:1];
|
||||
const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
|
||||
if (0x1d000 <= uc && uc <= 0x1f77f) {
|
||||
returnValue = YES;
|
||||
}
|
||||
}
|
||||
} else if (substring.length > 1) {
|
||||
const unichar ls = [substring characterAtIndex:1];
|
||||
if (ls == 0x20e3) {
|
||||
returnValue = YES;
|
||||
}
|
||||
} else {
|
||||
if (0x2100 <= hs && hs <= 0x27ff) {
|
||||
returnValue = YES;
|
||||
} else if (0x2B05 <= hs && hs <= 0x2b07) {
|
||||
returnValue = YES;
|
||||
} else if (0x2934 <= hs && hs <= 0x2935) {
|
||||
returnValue = YES;
|
||||
} else if (0x3297 <= hs && hs <= 0x3299) {
|
||||
returnValue = YES;
|
||||
} else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b ||
|
||||
hs == 0x2b50) {
|
||||
returnValue = YES;
|
||||
}
|
||||
}
|
||||
|
||||
*stop = returnValue;
|
||||
}];
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
- (NSString *)cutBeyondTextInLength:(NSInteger)maxLenth {
|
||||
size_t length = strlen([self UTF8String]);
|
||||
if (length > maxLenth) {
|
||||
NSString *text = [self substringToIndex:self.length - 1];
|
||||
return [text cutBeyondTextInLength:maxLenth];
|
||||
} else {
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
- (CGSize)textSizeIn:(CGSize)size font:(UIFont *)font {
|
||||
return [self textSizeIn:size font:font breakMode:NSLineBreakByWordWrapping];
|
||||
}
|
||||
|
||||
- (CGSize)textSizeIn:(CGSize)size font:(UIFont *)afont breakMode:(NSLineBreakMode)breakMode {
|
||||
return [self textSizeIn:size font:afont breakMode:NSLineBreakByWordWrapping align:NSTextAlignmentLeft];
|
||||
}
|
||||
|
||||
- (CGSize)textSizeIn:(CGSize)size font:(UIFont *)afont breakMode:(NSLineBreakMode)abreakMode align:(NSTextAlignment)alignment {
|
||||
NSLineBreakMode breakMode = abreakMode;
|
||||
UIFont *font = afont ? afont : [UIFont systemFontOfSize:14];
|
||||
|
||||
CGSize contentSize = CGSizeZero;
|
||||
|
||||
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
|
||||
paragraphStyle.lineBreakMode = breakMode;
|
||||
paragraphStyle.alignment = alignment;
|
||||
|
||||
NSDictionary *attributes = @{NSFontAttributeName : font, NSParagraphStyleAttributeName : paragraphStyle};
|
||||
contentSize = [self boundingRectWithSize:size
|
||||
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
|
||||
attributes:attributes
|
||||
context:nil]
|
||||
.size;
|
||||
contentSize = CGSizeMake((int)contentSize.width + 1, (int)contentSize.height + 1);
|
||||
return contentSize;
|
||||
}
|
||||
|
||||
- (NSString *)safePathString {
|
||||
NSString *homePrefix = [NSHomeDirectory() stringByDeletingLastPathComponent];
|
||||
if ([self hasPrefix:homePrefix]) {
|
||||
return [NSHomeDirectory() stringByAppendingString:[self substringFromIndex:[NSHomeDirectory() length]]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CGFloat)widthFromFont:(UIFont *)font {
|
||||
if (self.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
return [self boundingRectWithSize:CGSizeMake(0, font.lineHeight)
|
||||
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading | NSStringDrawingUsesDeviceMetrics
|
||||
attributes:@{NSFontAttributeName : font}
|
||||
context:nil]
|
||||
.size.width;
|
||||
}
|
||||
@end
|
||||
52
TUIKit/TUICore/OfflinePushExtBusinessInfo.h
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// OfflinePushExtBusinessInfo.h
|
||||
// TUICore
|
||||
//
|
||||
// Created by cologne on 2024/3/19.
|
||||
// Copyright © 2024 Tencent. All rights reserved.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// Common feature function class instance
|
||||
@interface OfflinePushExtBusinessInfo : NSObject
|
||||
|
||||
/**
|
||||
* Set the version number of offline messages
|
||||
*/
|
||||
@property(nonatomic, assign) NSInteger version;
|
||||
/**
|
||||
* Set the chat type of offline messages sent by the identifier (1: Single chat; 2: Group chat)
|
||||
*/
|
||||
@property(nonatomic, assign) NSInteger chatType;
|
||||
/**
|
||||
* Set the type of offline messages sent by the identity (1:Chat Message; 2: Call Message)
|
||||
*/
|
||||
@property(nonatomic, assign) NSInteger action;
|
||||
/**
|
||||
* Set the sender ID that identifies offline messages (the userID or groupID of the sender can identify the chatID of the chat)
|
||||
*/
|
||||
@property(nonatomic, copy) NSString *sender;
|
||||
/**
|
||||
* Identifies the sender nickname of offline messages
|
||||
*/
|
||||
@property(nonatomic, copy) NSString *nickname;
|
||||
/**
|
||||
* Sender avatar for offline messages
|
||||
*/
|
||||
@property(nonatomic, copy) NSString *faceUrl;
|
||||
/**
|
||||
* Display fields for offline messages
|
||||
*/
|
||||
@property(nonatomic, copy) NSString *content;
|
||||
/**
|
||||
* Set custom data (will be completely transparently transmitted to the receiving end)
|
||||
*/
|
||||
@property(nonatomic, strong) NSData *customData;
|
||||
|
||||
- (void)configWithEntityDic:(NSDictionary *)entityDic;
|
||||
- (NSDictionary *)toReportData;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
98
TUIKit/TUICore/OfflinePushExtBusinessInfo.m
Normal file
@@ -0,0 +1,98 @@
|
||||
//
|
||||
// OfflinePushExtBusinessInfo.m
|
||||
// TUICore
|
||||
//
|
||||
// Created by cologne on 2024/3/19.
|
||||
// Copyright © 2024 Tencent. All rights reserved.
|
||||
|
||||
#import "OfflinePushExtBusinessInfo.h"
|
||||
|
||||
@implementation OfflinePushExtBusinessInfo
|
||||
|
||||
- (void)configWithEntityDic:(NSDictionary *)entityDic {
|
||||
if (entityDic == nil || ![entityDic isKindOfClass:NSDictionary.class]) {
|
||||
return ;
|
||||
}
|
||||
|
||||
if ([entityDic.allKeys containsObject:@"version"]) {
|
||||
NSInteger version = 0;
|
||||
version = [entityDic[@"version"] integerValue];
|
||||
self.version = version;
|
||||
}
|
||||
|
||||
if ([entityDic.allKeys containsObject:@"chatType"]) {
|
||||
NSInteger chatType = 0;
|
||||
chatType = [entityDic[@"chatType"] integerValue];
|
||||
self.chatType = chatType;
|
||||
}
|
||||
|
||||
if ([entityDic.allKeys containsObject:@"action"]) {
|
||||
NSInteger action = 0;
|
||||
action = [entityDic[@"action"] integerValue];
|
||||
self.action = action;
|
||||
}
|
||||
|
||||
if ([entityDic.allKeys containsObject:@"sender"]) {
|
||||
NSString *sender = entityDic[@"sender"];
|
||||
if (sender.length > 0) {
|
||||
self.sender = sender;
|
||||
}
|
||||
}
|
||||
|
||||
if ([entityDic.allKeys containsObject:@"nickname"]) {
|
||||
NSString *nickname = entityDic[@"nickname"];
|
||||
if (nickname.length > 0) {
|
||||
self.nickname = nickname;
|
||||
}
|
||||
}
|
||||
|
||||
if ([entityDic.allKeys containsObject:@"faceUrl"]) {
|
||||
NSString *faceUrl = entityDic[@"faceUrl"];
|
||||
if (faceUrl.length > 0) {
|
||||
self.faceUrl = faceUrl;
|
||||
}
|
||||
}
|
||||
|
||||
if ([entityDic.allKeys containsObject:@"content"]) {
|
||||
NSString *content = entityDic[@"content"];
|
||||
if (content.length > 0) {
|
||||
self.content = content;
|
||||
}
|
||||
}
|
||||
|
||||
if ([entityDic.allKeys containsObject:@"customData"]) {
|
||||
NSData *customData = entityDic[@"customData"];
|
||||
if (customData) {
|
||||
self.customData = customData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSDictionary *)toReportData {
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
||||
dict[@"version"] = @(self.version);
|
||||
dict[@"chatType"] = @(self.chatType);
|
||||
dict[@"action"] = @(self.action);
|
||||
if (self.sender.length > 0) {
|
||||
dict[@"sender"] = self.sender;
|
||||
}
|
||||
|
||||
if (self.nickname.length > 0) {
|
||||
dict[@"nickname"] = self.nickname;
|
||||
}
|
||||
|
||||
if (self.faceUrl.length > 0) {
|
||||
dict[@"faceUrl"] = self.faceUrl;
|
||||
}
|
||||
|
||||
if (self.content.length > 0) {
|
||||
dict[@"content"] = self.content;
|
||||
}
|
||||
|
||||
if (self.customData) {
|
||||
dict[@"customData"] = self.customData;
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
@end
|
||||
26
TUIKit/TUICore/OfflinePushExtConfigInfo.h
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// OfflinePushExtConfigInfo.h
|
||||
// TUICore
|
||||
//
|
||||
// Created by cologne on 2024/3/19.
|
||||
// Copyright © 2024 Tencent. All rights reserved.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
// Entrance to features and functions supported by the TIMPush plug-in
|
||||
@interface OfflinePushExtConfigInfo : NSObject
|
||||
/**
|
||||
* In the FCM channel data mode, set whether the notification bar message is popped up by a plug-in or thrown out by the business implementation (0: TIMPush implementation, 1: Throwing business implementation by itself)
|
||||
*/
|
||||
@property(nonatomic, assign) NSInteger fcmPushType;
|
||||
/**
|
||||
* In FCM channel data mode, get the notification bar message whether it is a plug-in pop-up or a throw-out business implementation pop-up (0: TIMPush implementation; 1: throw-out business implementation)
|
||||
*/
|
||||
@property(nonatomic, assign) NSInteger fcmNotificationType;
|
||||
|
||||
- (void)configWithTIMPushFeaturesDic:(NSDictionary *)featuresDic;
|
||||
- (NSDictionary *)toReportData;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
49
TUIKit/TUICore/OfflinePushExtConfigInfo.m
Normal file
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// OfflinePushExtConfigInfo.m
|
||||
// TUICore
|
||||
//
|
||||
// Created by cologne on 2024/3/19.
|
||||
// Copyright © 2024 Tencent. All rights reserved.
|
||||
|
||||
#import "OfflinePushExtConfigInfo.h"
|
||||
|
||||
@implementation OfflinePushExtConfigInfo
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
[self setupData];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setupData {
|
||||
self.fcmPushType = 0;
|
||||
self.fcmNotificationType = 0;
|
||||
}
|
||||
|
||||
- (void)configWithTIMPushFeaturesDic:(NSDictionary *)featuresDic {
|
||||
if (featuresDic == nil || ![featuresDic isKindOfClass:NSDictionary.class]) {
|
||||
return ;
|
||||
}
|
||||
|
||||
if ([featuresDic.allKeys containsObject:@"fcmPushType"]) {
|
||||
int fcmPushType = 0;
|
||||
fcmPushType = [featuresDic[@"fcmPushType"] integerValue];
|
||||
self.fcmPushType = fcmPushType;
|
||||
}
|
||||
|
||||
if ([featuresDic.allKeys containsObject:@"fcmNotificationType"]) {
|
||||
int fcmNotificationType = 0;
|
||||
fcmNotificationType = [featuresDic[@"fcmNotificationType"] integerValue];
|
||||
self.fcmNotificationType = fcmNotificationType;
|
||||
}
|
||||
|
||||
}
|
||||
- (NSDictionary *)toReportData {
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
||||
dict[@"fcmPushType"] = @(self.fcmPushType);
|
||||
dict[@"fcmNotificationType"] = @(self.fcmNotificationType);
|
||||
return dict;
|
||||
}
|
||||
|
||||
@end
|
||||
32
TUIKit/TUICore/OfflinePushExtInfo.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// OfflinePushExtInfo.h
|
||||
// TUICore
|
||||
//
|
||||
// Created by cologne on 2024/3/19.
|
||||
// Copyright © 2024 Tencent. All rights reserved.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "OfflinePushExtBusinessInfo.h"
|
||||
#import "OfflinePushExtConfigInfo.h"
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OfflinePushExtInfo : NSObject
|
||||
// Common feature function class instance
|
||||
@property (nonatomic, strong) OfflinePushExtBusinessInfo *entity;
|
||||
// Entrance to features and functions supported by the TIMPush plug-in
|
||||
@property (nonatomic, strong) OfflinePushExtConfigInfo *timPushFeatures;
|
||||
|
||||
/**
|
||||
* If you need to customize the parsing of the received remote push, you need to implement the `- onRemoteNotificationReceived` method in the AppDelegate.m file;
|
||||
* You can convert ext to the OfflinePushExtInfo model according to the passed parameters for customized operations.
|
||||
*/
|
||||
+ (OfflinePushExtInfo *)createWithExtString:(NSString *)ext;
|
||||
|
||||
/**
|
||||
* If you need to customize the parsing of the received remote push, you need to implement the `- onRemoteNotificationReceived` method in the AppDelegate.m file;
|
||||
* You can convert ext to the OfflinePushExtInfo model according to the passed parameters for customized operations.
|
||||
*/
|
||||
- (NSString *)toReportExtString;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
100
TUIKit/TUICore/OfflinePushExtInfo.m
Normal file
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// OfflinePushExtInfo.m
|
||||
// TUICore
|
||||
//
|
||||
// Created by cologne on 2024/3/19.
|
||||
// Copyright © 2024 Tencent. All rights reserved.
|
||||
|
||||
#import "OfflinePushExtInfo.h"
|
||||
|
||||
@implementation OfflinePushExtInfo
|
||||
|
||||
+ (nonnull OfflinePushExtInfo *)createWithExtString:(nonnull NSString *)ext {
|
||||
if (ext == nil || ![ext isKindOfClass:NSString.class] || ext.length == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSDictionary *extDict = nil;
|
||||
BOOL flag = [self.class convertJsonString:ext toObject:&extDict];
|
||||
if (!flag || extDict == nil ||
|
||||
![extDict isKindOfClass:NSDictionary.class] ||
|
||||
![extDict.allKeys containsObject:@"entity"]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
OfflinePushExtInfo * extInfo = [[OfflinePushExtInfo alloc] init];
|
||||
OfflinePushExtBusinessInfo * entity = extInfo.entity;
|
||||
OfflinePushExtConfigInfo * timPushFeatures = extInfo.timPushFeatures;
|
||||
|
||||
NSDictionary *entityDic = extDict[@"entity"];
|
||||
if (entityDic) {
|
||||
[entity configWithEntityDic:entityDic];
|
||||
}
|
||||
NSDictionary *featuresDic = extDict[@"timPushFeatures"];
|
||||
|
||||
if (featuresDic) {
|
||||
[timPushFeatures configWithTIMPushFeaturesDic:featuresDic];
|
||||
}
|
||||
|
||||
return extInfo;
|
||||
}
|
||||
|
||||
|
||||
- (OfflinePushExtBusinessInfo *)entity {
|
||||
if (!_entity) {
|
||||
_entity = [[OfflinePushExtBusinessInfo alloc] init];
|
||||
}
|
||||
return _entity;
|
||||
}
|
||||
|
||||
|
||||
- (OfflinePushExtConfigInfo *)timPushFeatures {
|
||||
if (!_timPushFeatures) {
|
||||
_timPushFeatures = [[OfflinePushExtConfigInfo alloc] init];
|
||||
}
|
||||
return _timPushFeatures;
|
||||
}
|
||||
|
||||
- (NSDictionary *)toReportData {
|
||||
NSMutableDictionary *extDic = [NSMutableDictionary dictionary];
|
||||
NSDictionary *entityDict = nil;
|
||||
if (_entity) {
|
||||
entityDict = [_entity toReportData];
|
||||
[extDic setValue:entityDict forKey:@"entity"];
|
||||
}
|
||||
|
||||
NSDictionary *timPushFeaturesDict = nil;
|
||||
if (_timPushFeatures) {
|
||||
timPushFeaturesDict = [_timPushFeatures toReportData];
|
||||
[extDic setValue:timPushFeaturesDict forKey:@"timPushFeatures"];
|
||||
}
|
||||
|
||||
if (extDic) {
|
||||
return extDic;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)toReportExtString {
|
||||
NSDictionary * extDic = [self toReportData];
|
||||
NSData *data = [NSJSONSerialization dataWithJSONObject:extDic options:NSJSONWritingPrettyPrinted error:nil];
|
||||
NSString *ext = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
return ext;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+ (BOOL)convertJsonString:(NSString *)jsonString toObject:(NSObject **)object {
|
||||
if (jsonString == nil) {
|
||||
return NO;
|
||||
}
|
||||
NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSError *err = nil;
|
||||
*object = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&err];
|
||||
if (err) {
|
||||
NSLog(@"json decode failed, error:%@, json:%@", err, jsonString);
|
||||
}
|
||||
return (err == nil);
|
||||
}
|
||||
@end
|
||||
36
TUIKit/TUICore/Resources/PrivacyInfo.xcprivacy
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyTracking</key>
|
||||
<false/>
|
||||
<key>NSPrivacyTrackingDomains</key>
|
||||
<array/>
|
||||
<key>NSPrivacyCollectedDataTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>NSPrivacyCollectedDataType</key>
|
||||
<string>NSPrivacyCollectedDataTypeUserID</string>
|
||||
<key>NSPrivacyCollectedDataTypeLinked</key>
|
||||
<false/>
|
||||
<key>NSPrivacyCollectedDataTypeTracking</key>
|
||||
<false/>
|
||||
<key>NSPrivacyCollectedDataTypePurposes</key>
|
||||
<array>
|
||||
<string>NSPrivacyCollectedDataTypePurposeProductPersonalization</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>CA92.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
BIN
TUIKit/TUICore/Resources/TUICore.bundle/default_c2c_head@2x.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
BIN
TUIKit/TUICore/Resources/TUICore.bundle/more@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
TUIKit/TUICore/Resources/TUICore.bundle/more_group_note@2x.png
Normal file
|
After Width: | Height: | Size: 812 B |
BIN
TUIKit/TUICore/Resources/TUICore.bundle/more_group_note@3x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
TUIKit/TUICore/Resources/TUICore.bundle/more_poll@2x.png
Normal file
|
After Width: | Height: | Size: 738 B |
BIN
TUIKit/TUICore/Resources/TUICore.bundle/more_poll@3x.png
Normal file
|
After Width: | Height: | Size: 1013 B |
BIN
TUIKit/TUICore/Resources/TUICore.bundle/more_video_call@2x.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
TUIKit/TUICore/Resources/TUICore.bundle/more_video_call@3x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
TUIKit/TUICore/Resources/TUICore.bundle/more_voice_call@2x.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
TUIKit/TUICore/Resources/TUICore.bundle/more_voice_call@3x.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
TUIKit/TUICore/Resources/TUICore.bundle/nav_back@3x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>id</key>
|
||||
<string>dark</string>
|
||||
<key>name</key>
|
||||
<string>黑夜</string>
|
||||
<key>name_en</key>
|
||||
<string>Dark</string>
|
||||
<key>primary_color</key>
|
||||
<string>#FFFFFF</string>
|
||||
<key>primary_bg_color</key>
|
||||
<string>#F2F3F5</string>
|
||||
<key>primary_theme_color</key>
|
||||
<string>#2170B1</string>
|
||||
<key>common_switch_on_color</key>
|
||||
<string>#2170B1</string>
|
||||
<key>head_bg_gradient_start_color</key>
|
||||
<string>#111111</string>
|
||||
<key>default_group_head_public_img</key>
|
||||
<string>default_group_head_public.png</string>
|
||||
<key>default_group_head_meeting_img</key>
|
||||
<string>default_group_head_meeting.png</string>
|
||||
<key>default_group_head_avchatroom_img</key>
|
||||
<string>default_group_head_avchatroom.png</string>
|
||||
<key>default_group_head_community_img</key>
|
||||
<string>default_group_head_community.png</string>
|
||||
<key>default_group_head_img</key>
|
||||
<string>default_group_head.png</string>
|
||||
<key>default_c2c_head_img</key>
|
||||
<string>default_c2c_head.png</string>
|
||||
<key>search_textfield_bg_color</key>
|
||||
<string>#292929</string>
|
||||
<key>service_more_video_call_img</key>
|
||||
<string>service_more_video_call.png</string>
|
||||
<key>service_more_voice_call_img</key>
|
||||
<string>service_more_voice_call.png</string>
|
||||
<key>nav_back_img</key>
|
||||
<string>nav_back.png</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 979 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>id</key>
|
||||
<string>light</string>
|
||||
<key>name</key>
|
||||
<string>轻量</string>
|
||||
<key>name_en</key>
|
||||
<string>Light</string>
|
||||
<key>primary_color</key>
|
||||
<string>#FFFFFF</string>
|
||||
<key>primary_bg_color</key>
|
||||
<string>#F2F3F5</string>
|
||||
<key>primary_theme_color</key>
|
||||
<string>#147AFF</string>
|
||||
<key>common_switch_on_color</key>
|
||||
<string>#34C759</string>
|
||||
<key>head_bg_gradient_start_color</key>
|
||||
<string>#EBF0F6</string>
|
||||
<key>head_bg_gradient_end_color</key>
|
||||
<string>#EBF0F6</string>
|
||||
<key>default_group_head_public_img</key>
|
||||
<string>default_group_head_public.png</string>
|
||||
<key>default_group_head_meeting_img</key>
|
||||
<string>default_group_head_meeting.png</string>
|
||||
<key>default_group_head_avchatroom_img</key>
|
||||
<string>default_group_head_avchatroom.png</string>
|
||||
<key>default_group_head_community_img</key>
|
||||
<string>default_group_head_community.png</string>
|
||||
<key>default_group_head_img</key>
|
||||
<string>default_group_head.png</string>
|
||||
<key>default_c2c_head_img</key>
|
||||
<string>default_c2c_head.png</string>
|
||||
<key>search_textfield_bg_color</key>
|
||||
<string>#FEFEFE</string>
|
||||
<key>service_more_video_call_img</key>
|
||||
<string>service_more_video_call.png</string>
|
||||
<key>service_more_voice_call_img</key>
|
||||
<string>service_more_voice_call.png</string>
|
||||
<key>nav_back_img</key>
|
||||
<string>nav_back.png</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>id</key>
|
||||
<string>lively</string>
|
||||
<key>name</key>
|
||||
<string>活泼</string>
|
||||
<key>name_en</key>
|
||||
<string>Lively</string>
|
||||
<key>primary_color</key>
|
||||
<string>#FFFFFF</string>
|
||||
<key>primary_bg_color</key>
|
||||
<string>#F2F3F5</string>
|
||||
<key>primary_theme_color</key>
|
||||
<string>#FF8E82</string>
|
||||
<key>common_switch_on_color</key>
|
||||
<string>#FF8E82</string>
|
||||
<key>head_bg_gradient_start_color</key>
|
||||
<string>#FF7B7B</string>
|
||||
<key>head_bg_gradient_end_color</key>
|
||||
<string>#FFA88B</string>
|
||||
<key>default_group_head_public_img</key>
|
||||
<string>default_group_head_public.png</string>
|
||||
<key>default_group_head_meeting_img</key>
|
||||
<string>default_group_head_meeting.png</string>
|
||||
<key>default_group_head_avchatroom_img</key>
|
||||
<string>default_group_head_avchatroom.png</string>
|
||||
<key>default_group_head_community_img</key>
|
||||
<string>default_group_head_community.png</string>
|
||||
<key>default_group_head_img</key>
|
||||
<string>default_group_head.png</string>
|
||||
<key>default_c2c_head_img</key>
|
||||
<string>default_c2c_head.png</string>
|
||||
<key>search_textfield_bg_color</key>
|
||||
<string>#FEFEFE</string>
|
||||
<key>service_more_video_call_img</key>
|
||||
<string>service_more_video_call.png</string>
|
||||
<key>service_more_voice_call_img</key>
|
||||
<string>service_more_voice_call.png</string>
|
||||
<key>nav_back_img</key>
|
||||
<string>nav_back.png</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 979 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>id</key>
|
||||
<string>serious</string>
|
||||
<key>name</key>
|
||||
<string>严肃</string>
|
||||
<key>name_en</key>
|
||||
<string>Business</string>
|
||||
<key>primary_color</key>
|
||||
<string>#FFFFFF</string>
|
||||
<key>primary_bg_color</key>
|
||||
<string>#F2F3F5</string>
|
||||
<key>primary_theme_color</key>
|
||||
<string>#0052FF</string>
|
||||
<key>common_switch_on_color</key>
|
||||
<string>#0052FF</string>
|
||||
<key>head_bg_gradient_start_color</key>
|
||||
<string>#6395FF</string>
|
||||
<key>head_bg_gradient_end_color</key>
|
||||
<string>#0052FF</string>
|
||||
<key>default_group_head_public_img</key>
|
||||
<string>default_group_head_public.png</string>
|
||||
<key>default_group_head_meeting_img</key>
|
||||
<string>default_group_head_meeting.png</string>
|
||||
<key>default_group_head_avchatroom_img</key>
|
||||
<string>default_group_head_avchatroom.png</string>
|
||||
<key>default_group_head_community_img</key>
|
||||
<string>default_group_head_community.png</string>
|
||||
<key>default_group_head_img</key>
|
||||
<string>default_group_head.png</string>
|
||||
<key>default_c2c_head_img</key>
|
||||
<string>default_c2c_head.png</string>
|
||||
<key>search_textfield_bg_color</key>
|
||||
<string>#FEFEFE</string>
|
||||
<key>service_more_video_call_img</key>
|
||||
<string>service_more_video_call.png</string>
|
||||
<key>service_more_voice_call_img</key>
|
||||
<string>service_more_voice_call.png</string>
|
||||
<key>nav_back_img</key>
|
||||
<string>nav_back.png</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 979 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>id</key>
|
||||
<string>dark</string>
|
||||
<key>name</key>
|
||||
<string>黑夜</string>
|
||||
<key>name_en</key>
|
||||
<string>Dark</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>id</key>
|
||||
<string>light</string>
|
||||
<key>name</key>
|
||||
<string>轻量</string>
|
||||
<key>name_en</key>
|
||||
<string>Light</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>id</key>
|
||||
<string>lively</string>
|
||||
<key>name</key>
|
||||
<string>活泼</string>
|
||||
<key>name_en</key>
|
||||
<string>Lively</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>id</key>
|
||||
<string>serious</string>
|
||||
<key>name</key>
|
||||
<string>严肃</string>
|
||||
<key>name_en</key>
|
||||
<string>Business</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
Localizable.strings
|
||||
Chinese Simplized
|
||||
|
||||
Created by harvy on 2020/10/9.
|
||||
|
||||
*/
|
||||
|
||||
/***************************** 日期格式化 Start *************************/
|
||||
"YesterdayDateFormat" = "aHH:mm";
|
||||
/***************************** 日期格式化 End *************************/
|
||||
|
||||
"TUIKitMoreVideoCall" = "مكالمة فيديو";
|
||||
"TUIKitMoreVoiceCall" = "مكالمة صوتية";
|
||||
"Make-a-call" = "إجراء مكالمة";
|
||||
"TUIKitNoSelfSignature" = "لا يوجد توقيع شخصي";
|
||||
"TUIKitSelfSignatureFormat" = "التوقيع الشخصي: %@";
|
||||
"TUIKitAllowTypeAcceptOne" = "السماح لأي مستخدم بإضافة صديق";
|
||||
"TUIKitAllowTypeNeedConfirm" = "يحتاج التحقق";
|
||||
"TUIKitAllowTypeDeclineAll" = "رفض أي شخص يريد إضافة صديق";
|
||||
"Male" = "ذكر";
|
||||
"Female" = "أنثى";
|
||||
"Unsetted" = "غير محدد";
|
||||
|
||||
"TUIKitErrorInProcess" = "جاري التنفيذ";
|
||||
"TUIKitErrorInvalidParameters" = "معلمات غير صالحة";
|
||||
"TUIKitErrorIOOperateFaild" = "فشل عملية الإدخال/الإخراج المحلية";
|
||||
"TUIKitErrorInvalidJson" = "تنسيق JSON غير صالح";
|
||||
"TUIKitErrorOutOfMemory" = "نفاد الذاكرة";
|
||||
"TUIKitErrorParseResponseFaild" = "فشل تحليل PB";
|
||||
"TUIKitErrorSerializeReqFaild" = "فشل تسلسل PB";
|
||||
"TUIKitErrorSDKNotInit" = "SDK IM غير مهيأ";
|
||||
"TUIKitErrorLoadMsgFailed" = "فشل تحميل عملية قاعدة البيانات المحلية";
|
||||
"TUIKitErrorDatabaseOperateFailed" = "فشل عملية قاعدة البيانات المحلية";
|
||||
"TUIKitErrorCrossThread" = "خطأ عبر الخيوط";
|
||||
"TUIKitErrorTinyIdEmpty" = "معلومات المستخدم فارغة";
|
||||
"TUIKitErrorInvalidIdentifier" = "معرف غير صالح";
|
||||
"TUIKitErrorFileNotFound" = "الملف غير موجود";
|
||||
"TUIKitErrorFileTooLarge" = "حجم الملف أكبر من الحد المسموح به";
|
||||
"TUIKitErrorEmptyFile" = "ملف فارغ";
|
||||
"TUIKitErrorFileOpenFailed" = "فشل فتح الملف";
|
||||
"TUIKitErrorNotLogin" = "لم يتم تسجيل الدخول إلى SDK IM";
|
||||
"TUIKitErrorNoPreviousLogin" = "لم يتم تسجيل الدخول بهذا المستخدم من قبل";
|
||||
"TUIKitErrorUserSigExpired" = "انتهت صلاحية UserSig";
|
||||
"TUIKitErrorLoginKickedOffByOther" = "تم تسجيل الدخول بواسطة جهاز آخر";
|
||||
"TUIKitErrorTLSSDKInit" = "فشل تهيئة SDK TLS";
|
||||
"TUIKitErrorTLSSDKUninit" = "SDK TLS غير مهيأ";
|
||||
|
||||
"TUIKitErrorTLSSDKTRANSPackageFormat" = "تنسيق حزمة TLS SDK TRANS غير صالح";
|
||||
|
||||
|
||||
"TUIKitErrorTLSDecrypt" = "فشل فك تشفير SDK TLS";
|
||||
"TUIKitErrorTLSSDKRequest" = "فشل طلب SDK TLS";
|
||||
"TUIKitErrorTLSSDKRequestTimeout" = "انتهت مهلة طلب SDK TLS";
|
||||
"TUIKitErrorInvalidConveration" = "المحادثة غير صالحة";
|
||||
"TUIKitErrorFileTransAuthFailed" = "فشل مصادقة نقل الملفات";
|
||||
"TUIKitErrorFileTransNoServer" = "فشل الحصول على قائمة الخوادم لنقل الملفات";
|
||||
"TUIKitErrorFileTransUploadFailed" = "فشل تحميل نقل الملفات، يرجى التحقق من اتصال الشبكة";
|
||||
"TUIKitErrorFileTransUploadFailedNotImage" = "فشل تحميل نقل الملفات، يرجى التحقق من قدرة فتح الصورة المراد تحميلها";
|
||||
"TUIKitErrorFileTransDownloadFailed" = "فشل تنزيل نقل الملفات، يرجى التحقق من الشبكة أو صلاحية الملف أو الصوت";
|
||||
|
||||
"TUIKitErrorHTTPRequestFailed" = "فشل طلب HTTP";
|
||||
"TUIKitErrorInvalidMsgElem" = "عنصر رسالة IM SDK غير صالح";
|
||||
"TUIKitErrorInvalidSDKObject" = "كائن غير صالح";
|
||||
"TUIKitSDKMsgBodySizeLimit" = "تجاوز حد طول الرسالة";
|
||||
"TUIKitErrorSDKMsgKeyReqDifferRsp" = "خطأ في مفتاح الرسالة";
|
||||
"TUIKitErrorSDKGroupInvalidID" = "معرف المجموعة غير صالح، يجب أن يكون معرف المجموعة المخصص قابلًا للطباعة ويتكون من أحرف ASCII (0x20-0x7e)، ويصل طوله إلى 48 بايتًا، ولا يمكن أن يبدأ بالبادئة @TGS#";
|
||||
"TUIKitErrorSDKGroupInvalidName" = "اسم المجموعة غير صالح، يصل طوله إلى 30 بايتًا";
|
||||
"TUIKitErrorSDKGroupInvalidIntroduction" = "مقدمة المجموعة غير صالحة، يصل طولها إلى 240 بايتًا";
|
||||
"TUIKitErrorSDKGroupInvalidNotification" = "إشعار المجموعة غير صالح، يصل طوله إلى 300 بايتًا";
|
||||
"TUIKitErrorSDKGroupInvalidFaceURL" ="عنوان URL للصورة الرمزية للمجموعة غير قانوني ، والحد الأقصى لطول عنوان URL للصورة الرمزية للمجموعة هو 100 بايت";
|
||||
"TUIKitErrorSDKGroupInvalidNameCard" = "بطاقة اسم المجموعة غير صالحة، يصل طولها إلى 50 بايتًا";
|
||||
"TUIKitErrorSDKGroupMemberCountLimit" = "تجاوز حد عدد أعضاء المجموعة";
|
||||
|
||||
"TUIKitErrorSDKGroupJoinPrivateGroupDeny" = "غير مسموح بطلب الانضمام إلى مجموعة خاصة";
|
||||
"TUIKitErrorSDKGroupInviteSuperDeny" = "غير مسموح بدعوة أعضاء يمتلكون دور المالك في المجموعة";
|
||||
"TUIKitErrorSDKGroupInviteNoMember" = "غير مسموح بدعوة أي أعضاء";
|
||||
"TUIKitErrorSDKFriendShipInvalidProfileKey" = "حقل الملف الشخصي غير صالح";
|
||||
"TUIKitErrorSDKFriendshipInvalidAddRemark" = "حقل الملاحظات غير صالح، يصل طوله إلى 96 بايتًا";
|
||||
"TUIKitErrorSDKFriendshipInvalidAddWording" = "حقل شرح طلب إضافة صديق غير صالح، يصل طوله إلى 120 بايتًا";
|
||||
"TUIKitErrorSDKFriendshipInvalidAddSource" = "حقل مصدر طلب إضافة صديق غير صالح، يجب أن يبدأ المصدر بالبادئة 'AddSource_Type_'";
|
||||
"TUIKitErrorSDKFriendshipFriendGroupEmpty" = "حقل مجموعة الأصدقاء غير صالح، يجب أن لا يكون فارغًا ويصل طول اسم كل مجموعة إلى 30 بايتًا";
|
||||
"TUIKitErrorSDKNetEncodeFailed" = "فشل تشفير الاتصال بالشبكة";
|
||||
"TUIKitErrorSDKNetDecodeFailed" = "فشل فك تشفير الاتصال بالشبكة";
|
||||
"TUIKitErrorSDKNetAuthInvalid" = "لم يتم استكمال التوثيق للاتصال بالشبكة";
|
||||
"TUIKitErrorSDKNetCompressFailed" = "فشل ضغط حزمة البيانات";
|
||||
"TUIKitErrorSDKNetUncompressFaile" = "فشل فك ضغط حزمة البيانات";
|
||||
"TUIKitErrorSDKNetFreqLimit" = "تم تحديد حد التردد، يمكن إجراء حد أقصى من 5 طلبات في الثانية الواحدة";
|
||||
"TUIKitErrorSDKnetReqCountLimit" = "تم تجاوز حد الطلبات المتزامنة، يمكن إجراء حد أقصى من 1000 طلب في نفس الوقت";
|
||||
"TUIKitErrorSDKNetDisconnect" = "تم فصل الاتصال بالشبكة، لم يتم إنشاء اتصال أو تم الكشف عن عدم وجود اتصال بالشبكة أثناء إنشاء اتصال socket";
|
||||
"TUIKitErrorSDKNetAllreadyConn" = "تم بالفعل إنشاء اتصال بالشبكة، لا يمكن إنشاء اتصال مكرر";
|
||||
"TUIKitErrorSDKNetConnTimeout" = "انتهت مهلة إنشاء اتصال الشبكة، يرجى المحاولة مرة أخرى بعد استعادة الاتصال بالشبكة.";
|
||||
"TUIKitErrorSDKNetConnRefuse" = "تم رفض اتصال الشبكة، يتم رفض الطلب بسبب التكرار الزائد، يرفض الخادم الخدمة.";
|
||||
"TUIKitErrorSDKNetNetUnreach" = "لا توجد طرق شبكة متاحة للوصول إلى الشبكة، يرجى المحاولة مرة أخرى بعد استعادة الاتصال بالشبكة.";
|
||||
"TUIKitErrorSDKNetSocketNoBuff" = "لا توجد موارد مساحة تخزين مؤقت كافية في النظام لإكمال الاستدعاء، النظام مشغول جدًا، خطأ داخلي.";
|
||||
"TUIKitERRORSDKNetResetByPeer" = "تم إعادة تعيين الاتصال بواسطة الطرف الآخر";
|
||||
"TUIKitErrorSDKNetSOcketInvalid" = "socket القابس غير صالح";
|
||||
|
||||
"TUIKitErrorSDKNetHostGetAddressFailed" = "IP العنوان فشل في الحصول على العنوان";
|
||||
"TUIKitErrorSDKNetConnectReset" = "تم إعادة تعيين اتصال الشبكة إلى العقدة الوسيطة أو الخادم";
|
||||
"TUIKitErrorSDKNetWaitInQueueTimeout" = "تجاوزت حزمة الطلبات المهلة الزمنية للانتظار في قائمة الانتظار للإرسال";
|
||||
"TUIKitErrorSDKNetWaitSendTimeout" = "الطلب قد دخل قائمة الانتظار للإرسال، في انتظار دخول البيانات في الـ buffer الشبكي في النظام وقد تجاوزت المهلة الزمنية";
|
||||
"TUIKitErrorSDKNetConnectReset" = "تم إعادة تعيين اتصال الشبكة إلى الـ server أو العقدة الوسيطة";
|
||||
"TUIKitErrorSDKNetWaitInQueueTimeout" = "تجاوزت حزمة الطلبات المهلة الزمنية للانتظار في قائمة الانتظار للإرسال";
|
||||
"TUIKitErrorSDKNetWaitAckTimeut" = "تجاوزت حزمة الطلبات المهلة الزمنية للانتظار في ذاكرة التخزين المؤقتة للشبكة في النظام، في انتظار استلام الرد من الـ server";
|
||||
"TUIKitErrorSDKWaitSendRemainingTimeout" =
|
||||
"لقد دخلت حزمة الطلب في قائمة الانتظار المراد إرسالها، وتم إرسال جزء من البيانات. تحدث مهلة أثناء انتظار إرسال الجزء المتبقي. قد يكون عرض النطاق الترددي للوصلة الصاعدة غير كاف. يرجى التحقق مما إذا كانت الشبكة سلسة. عندما حدث خطأ في رد الاتصال، وتم اكتشاف وجود اتصال بالإنترنت. خطأ داخلي";
|
||||
"TUIKitErrorSDKNetPKGSizeLimit" = "طول حزمة الطلب أكبر من الحد الأقصى، والحد الأقصى المدعوم هو 1 ميجابايت.";
|
||||
"TUIKitErrorSDKNetWaitSendTimeoutNoNetwork" = "طول حزمة الطلب أكبر من الحد الأقصى، والحد الأقصى المدعوم هو 1 ميجابايت. لقد دخلت حزمة الطلب في قائمة الانتظار ليتم إرسالها. انتهت مهلة المخزن المؤقت للشبكة الذي ينتظر الدخول إلى النظام. يوجد عدد كبير جدًا من حزم البيانات أو لا يمكن لمؤشر الترابط المرسل معالجتها. عند استدعاء رمز الخطأ مرة أخرى، تم اكتشاف وجود لا يوجد اتصال بالإنترنت.";
|
||||
"TUIKitErrorSDKNetWaitAckTimeoutNoNetwork" = "دخلت حزمة الطلب إلى المخزن المؤقت لشبكة النظام، وانتهت مهلة انتظار حزمة الإرجاع من الخادم، ربما لم تترك حزمة الطلب الجهاز الطرفي، وقد تجاهلها المسار الوسيط، وفقد الخادم عن طريق الخطأ الحزمة، أو تم تجاهل حزمة الإرجاع بواسطة طبقة شبكة النظام. لم يتم اكتشاف رمز خطأ عند معاودة الاتصال بالشبكة.";
|
||||
"TUIKitErrorSDKNetRemainingTimeoutNoNetwork" = "لقد دخلت حزمة الطلب في قائمة الانتظار ليتم إرسالها، وتم إرسال جزء من البيانات. تحدث مهلة أثناء انتظار إرسال الجزء المتبقي. قد يكون عرض النطاق الترددي للوصلة الصاعدة غير كاف. يرجى التحقق مما إذا كانت الشبكة سلسة. عند الاتصال مرة أخرى رمز الخطأ، تم الكشف عن عدم وجود اتصال بالإنترنت.";
|
||||
"TUIKitErrorSDKSVRSSOConnectLimit" = "تجاوز عدد اتصالات الـ server الحد المسموح به، يرفض الـ server الخدمة";
|
||||
"TUIKitErrorSDKSVRSSOVCode" = "تجاوز مهلة إرسال رمز التحقق";
|
||||
"TUIKitErrorSVRSSOD2Expired" = "انتهت صلاحية الـ Key. الـ Key هو تذكرة داخلية تم إنشاؤها بناءً على UserSig، وصلاحية الـ Key أقل من أو تساوي صلاحية UserSig. يرجى استدعاء واجهة تسجيل الدخول TIMManager.getInstance().login مرة أخرى لتوليد Key جديد";
|
||||
"TUIKitErrorSVRA2UpInvalid" = "انتهت صلاحية الـ ticket. الـ ticket هي تذكرة داخلية تم إنشاؤها بناءً على UserSig، وصلاحية الـ ticket أقل من أو تساوي صلاحية UserSig. يرجى استدعاء واجهة تسجيل الدخول TIMManager.getInstance().login مرة أخرى لتوليد ticket جديدة";
|
||||
"TUIKitErrorSVRA2DownInvalid" = "فشل التحقق من الـ ticket أو تعرضت لهجوم أمان. يرجى استدعاء واجهة تسجيل الدخول TIMManager.getInstance().login مرة أخرى لتوليد ticket جديدة";
|
||||
"TUIKitErrorSVRSSOEmpeyKey" = "لا يُسمح بترك الـ Key فارغًا.";
|
||||
"TUIKitErrorSVRSSOUinInvalid" = "حساب الـ Uin في الـ Key لا يتطابق مع حساب رأس الطلب.";
|
||||
"TUIKitErrorSVRSSOVCodeTimeout" = "تجاوز مهلة إرسال رمز التحقق.";
|
||||
"TUIKitErrorSVRSSONoImeiAndA2" = "الرجاء إرفاق الـ Key والـ Ticket.";
|
||||
"TUIKitErrorSVRSSOCookieInvalid" = "فشل التحقق من تطابق الـ Cookie.";
|
||||
"TUIKitErrorSVRSSODownTips" = "رسالة تلميح للتنزيل، انتهت صلاحية الـ Key.";
|
||||
"TUIKitErrorSVRSSODisconnect" = "فصل الاتصال وقفل الشاشة.";
|
||||
"TUIKitErrorSVRSSOIdentifierInvalid" = "هوية غير صالحة.";
|
||||
"TUIKitErrorSVRSSOClientClose" = "إغلاق تلقائي للعميل.";
|
||||
"TUIKitErrorSVRSSOMSFSDKQuit" = "إغلاق تلقائي لـ MSFSDK.";
|
||||
"TUIKitErrorSVRSSOD2KeyWrong" = "فشل فك التشفير للمفتاح عدة مرات تجاوز الحد المسموح به، يُطلب إعادة تعيينه، يرجى استدعاء واجهة تسجيل الدخول TIMManager.getInstance().login مرة أخرى لتوليد مفتاح جديد.";
|
||||
"TUIKitErrorSVRSSOUnsupport" = "غير مدعوم للتجميع، يتم إرجاع رمز خطأ موحد للعميل. يتوقف التجميع على العميل على هذه الاتصال الطويل للـ TCP.";
|
||||
"TUIKitErrorSVRSSOPrepaidArrears" = "تأخير في الدفع المسبق.";
|
||||
"TUIKitErrorSVRSSOPacketWrong" = "تنسيق حزمة الطلبات غير صحيح.";
|
||||
"TUIKitErrorSVRSSOAppidBlackList" = "قائمة الـ SDKAppID السوداء.";
|
||||
"TUIKitErrorSVRSSOCmdBlackList" = "قائمة الأوامر السوداء لـ service cmd في SDKAppID.";
|
||||
"TUIKitErrorSVRSSOAppidWithoutUsing" = "SDKAppID متوقف عن الاستخدام.";
|
||||
"TUIKitErrorSVRSSOFreqLimit" = "حد التردد (للمستخدم)، حد التردد هو الحد الذي يتم تعيينه لعدد الطلبات في الثانية لبروتوكول معين.";
|
||||
"TUIKitErrorSVRSSOOverload" = "فائض الحمولة (النظام)، يتعامل الـ server المتصل بالاتصال بعدد كبير من الطلبات ولا يستطيع التعامل معها، ويتم رفض الخدمة.";
|
||||
"TUIKitErrorSVRResNotFound" = "الملف المورد الذي يتم إرساله غير موجود.";
|
||||
"TUIKitErrorSVRResAccessDeny" = "لا يُسمح بالوصول إلى الملف المورد الذي يتم إرساله.";
|
||||
"TUIKitErrorSVRResSizeLimit"= "تجاوز حجم الملف الحد المسموح به.";
|
||||
"TUIKitErrorSVRResSendCancel" = "تم إلغاء إرسال المستخدم، مثل تسجيل الخروج أثناء عملية الإرسال وما إلى ذلك.";
|
||||
"TUIKitErrorSVRResReadFailed" = "فشل قراءة محتوى الملف.";
|
||||
"TUIKitErrorSVRResTransferTimeout" = "انتهت مهلة نقل الملف المورد.";
|
||||
"TUIKitErrorSVRResInvalidParameters" = "معلمات غير صالحة.";
|
||||
"TUIKitErrorSVRResInvalidFileMd5" = "فشل التحقق من صحة MD5 للملف.";
|
||||
"TUIKitErrorSVRResInvalidPartMd5" = "فشل التحقق من صحة MD5 للجزء المقسم.";
|
||||
"TUIKitErrorSVRCommonInvalidHttpUrl" = "خطأ في تحليل عنوان URL للطلب HTTP، يرجى التحقق من تنسيق عنوان URL للطلب.";
|
||||
"TUIKitErrorSVRCommomReqJsonParseFailed" = "فشل تحليل JSON للطلب HTTP، يرجى التحقق من تنسيق JSON.";
|
||||
"TUIKitErrorSVRCommonInvalidAccount" = "خطأ في معرف أو UserSig في عنوان URI أو جسم JSON للطلب.";
|
||||
"TUIKitErrorSVRCommonInvalidSdkappid" = "SDKAppID غير صالح، يرجى التحقق من صحة SDKAppID.";
|
||||
"TUIKitErrorSVRCommonRestFreqLimit" = "تجاوز حد التردد لاستدعاء واجهة REST، يرجى تقليل تردد الطلبات.";
|
||||
"TUIKitErrorSVRCommonRequestTimeout" = "انتهت مهلة الطلب أو يوجد خطأ في تنسيق الطلب HTTP، يرجى التحقق وإعادة المحاولة.";
|
||||
"TUIKitErrorSVRCommonInvalidRes" = "خطأ في طلب المورد، يرجى التحقق من عنوان URL للطلب.";
|
||||
"TUIKitErrorSVRCommonIDNotAdmin" = "يرجى استخدام حساب المسؤول في حقل المعرف في طلب واجهة REST.";
|
||||
"TUIKitErrorSVRCommonSdkappidFreqLimit" = "تجاوز حد التردد لـ SDKAppID، يرجى تقليل تردد الطلبات.";
|
||||
"TUIKitErrorSVRCommonSdkappidMiss" = "واجهة REST تحتاج إلى توفير SDKAppID، يرجى التحقق من وجود SDKAppID في عنوان URL للطلب.";
|
||||
"TUIKitErrorSVRCommonRspJsonParseFailed" = "فشل تحليل JSON لحزمة الاستجابة HTTP.";
|
||||
"TUIKitErrorSVRCommonExchangeAccountTimeout" = "انتهت مهلة تبديل الحساب.";
|
||||
"TUIKitErrorSVRCommonInvalidIdFormat" = "نوع المعرف في جسم الطلب غير صحيح، يرجى التأكد من أن المعرف هو سلسلة نصية.";
|
||||
"TUIKitErrorSVRCommonSDkappidForbidden" = "SDKAppID محظور.";
|
||||
"TUIKitErrorSVRCommonReqForbidden" = "الطلب محظور.";
|
||||
"TUIKitErrorSVRCommonReqFreqLimit" = "الطلب متكرر للغاية، يرجى المحاولة مرة أخرى لاحقًا.";
|
||||
"TUIKitErrorSVRCommonInvalidService" = "انتهت صلاحية حزمة الاشتراك الخاصة بك وتم تعطيلها، يرجى تسجيل الدخول إلى صفحة شراء خدمة الدردشة الفورية IM وشراء حزمة جديدة. ستصبح الحزمة الجديدة نشطة بعد 5 دقائق.";
|
||||
"TUIKitErrorSVRCommonSensitiveText" = "هجوم على النص الآمن، قد يحتوي النص على كلمات حساسة.";
|
||||
"TUIKitErrorSVRCommonBodySizeLimit" = "حجم حزمة إرسال الرسالة طويل جدًا، يتم دعم حجم حزمة الرسالة حتى 12 كيلوبايت، يرجى تقليل حجم الحزمة وإعادة المحاولة.";
|
||||
"TUIKitErrorSVRAccountUserSigExpired" = "انتهت صلاحية UserSig، يرجى إعادة توليد UserSig.";
|
||||
"TUIKitErrorSVRAccountUserSigEmpty" = "طول UserSig يساوي 0.";
|
||||
"TUIKitErrorSVRAccountUserSigCheckFailed" = "فشل التحقق من صحة UserSig.";
|
||||
"TUIKitErrorSVRAccountUserSigMismatchPublicKey" = "فشل التحقق من صحة UserSig باستخدام المفتاح العام.";
|
||||
"TUIKitErrorSVRAccountUserSigMismatchId" = "المعرف المطلوب في الطلب لا يتطابق مع المعرف المستخدم في إنشاء UserSig.";
|
||||
"TUIKitErrorSVRAccountUserSigMismatchSdkAppid" = "SDKAppID المطلوب في الطلب لا يتطابق مع SDKAppID المستخدم في إنشاء UserSig.";
|
||||
"TUIKitErrorSVRAccountUserSigPublicKeyNotFound" = "فشل العثور على المفتاح العام أثناء التحقق من صحة UserSig.";
|
||||
"TUIKitErrorSVRAccountUserSigSdkAppidNotFount" = "لم يتم العثور على SDKAppID، يرجى التحقق من معلومات التطبيق في وحدة التحكم لـ IM الخاصة بالاتصال السحابي.";
|
||||
"TUIKitErrorSVRAccountInvalidUserSig" = "انتهت صلاحية UserSig، يرجى إعادة توليد UserSig والمحاولة مرة أخرى.";
|
||||
"TUIKitErrorSVRAccountNotFound" = "حساب المستخدم المطلوب غير موجود.";
|
||||
"TUIKitErrorSVRAccountSecRstr" = "تم تقييد الوصول لأسباب أمان.";
|
||||
"TUIKitErrorSVRAccountInternalTimeout" = "انتهت مهلة الخادم الداخلية، يرجى إعادة المحاولة.";
|
||||
"TUIKitErrorSVRAccountInvalidCount" = "الكمية المجمعة في الطلب غير صالحة.";
|
||||
"TUIkitErrorSVRAccountINvalidParameters" = "معلمات غير صالحة في الطلب، يرجى التحقق من ملء الحقول المطلوبة ومطابقة متطلبات البروتوكول.";
|
||||
"TUIKitErrorSVRAccountAdminRequired" = "الطلب يتطلب صلاحيات المسؤول في التطبيق.";
|
||||
"TUIKitErrorSVRAccountLowSDKVersion" = "إصدار SDK الخاص بك قديم جدًا، يرجى الترقية إلى أحدث إصدار.";
|
||||
"TUIKitErrorSVRAccountFreqLimit" = "تم تقييد الطلب بسبب الفشل المتكرر وعدد محاولات إعادة المحاولة الكثيرة، يرجى الت";
|
||||
|
||||
"TUIKitErrorSVRAccountBlackList" = "تم إدراج الحساب في القائمة السوداء.";
|
||||
"TUIKitErrorSVRAccountCountLimit" = "تجاوز الحد الأقصى لعدد الحسابات المسموح به في الإصدار التجريبي المجاني، يرجى الترقية إلى الإصدار المتخصص.";
|
||||
"TUIKitErrorSVRAccountInternalError" = "خطأ داخلي في الخادم، يرجى إعادة المحاولة لاحقًا.";
|
||||
"TUIKitErrorSVRProfileInvalidParameters" = "معلمات طلب غير صالحة، يرجى التحقق من صحة الطلب وفقًا لوصف الخطأ.";
|
||||
"TUIKitErrorSVRProfileAccountMiss" = "معلمات الطلب غير صالحة، لم يتم تحديد حساب المستخدم الذي يجب جلب بياناته.";
|
||||
"TUIKitErrorSVRProfileAccountNotFound" = "حساب المستخدم المطلوب غير موجود.";
|
||||
"TUIKitErrorSVRProfileAdminRequired" = "الطلب يتطلب صلاحيات المسؤول في التطبيق.";
|
||||
"TUIKitErrorSVRProfileSensitiveText" = "يحتوي حقل البيانات على كلمات حساسة.";
|
||||
"TUIKitErrorSVRProfileInternalError" = "خطأ داخلي في الخادم، يرجى إعادة المحاولة لاحقًا.";
|
||||
"TUIKitErrorSVRProfileReadWritePermissionRequired" = "لا يوجد إذن لقراءة حقل البيانات، يرجى الرجوع إلى وصف حقل البيانات.";
|
||||
"TUIKitErrorSVRProfileTagNotFound" = "لا يوجد علامة لحقل البيانات.";
|
||||
"TUIKitErrorSVRProfileSizeLimit" = "تجاوز طول قيمة حقل البيانات الحد الأقصى المسموح به والذي يبلغ 500 بايت.";
|
||||
"TUIKitErrorSVRProfileValueError" = "قيمة حقل البيانات القياسية غير صحيحة، يرجى الرجوع إلى وصف حقل البيانات القياسية.";
|
||||
"TUIKitErrorSVRProfileInvalidValueFormat" = "نوع قيمة حقل البيانات غير متطابق، يرجى الرجوع إلى وصف حقل البيانات القياسية.";
|
||||
"TUIKitErrorSVRFriendshipInvalidParameters" = "معلمات الطلب غير صالحة، يرجى التحقق من صحة الطلب وفقًا لوصف الخطأ.";
|
||||
"TUIKitErrorSVRFriendshipInvalidSdkAppid" = "SDKAppID غير متطابق.";
|
||||
"TUIKitErrorSVRFriendshipAccountNotFound" = "حساب المستخدم المطلوب غير موجود.";
|
||||
"TUIKitErrorSVRFriendshipAdminRequired" = "الطلب يتطلب صلاحيات المسؤول في التطبيق.";
|
||||
"TUIKitErrorSVRFriendshipSensitiveText" = "يحتوي حقل علاقة الأصدقاء على كلمات حساسة.";
|
||||
"TUIKitErrorSVRFriendshipNetTimeout" = "انتهت مهلة الشبكة، يرجى إعادة المحاولة لاحقًا.";
|
||||
"TUIKitErrorSVRFriendshipWriteConflict" = "تعارض الكتابة المتزامنة يؤدي إلى تعارض الكتابة، يرجى استخدام الطريقة الدفعية.";
|
||||
"TUIKitErrorSVRFriendshipAddFriendDeny" = "تم منع المستخدم من إرسال طلبات صداقة من الخلفية.";
|
||||
"TUIkitErrorSVRFriendshipCountLimit" = "لقد وصلت إلى الحد الأقصى لعدد الأصدقاء في النظام.";
|
||||
"TUIKitErrorSVRFriendshipGroupCountLimit" = "لقد وصلت إلى الحد الأقصى لعدد المجموعات في النظام.";
|
||||
"TUIKitErrorSVRFriendshipPendencyLimit" = "لقد وصلت إلى الحد الأقصى لعدد الطلبات المعلقة في النظام.";
|
||||
"TUIKitErrorSVRFriendshipBlacklistLimit" = "لقد وصلت إلى الحد الأقصى لعدد الأشخاص في القائمة السوداء في النظام.";
|
||||
"TUIKitErrorSVRFriendshipPeerFriendLimit" = "لقد وصل الصديق الخاص بك إلى الحد الأقصى لعدد الأصدقاء في النظام.";
|
||||
"TUIKitErrorSVRFriendshipAlreadyFriends" = "بالفعل أصدقاء";
|
||||
"TUIKitErrorSVRFriendshipInSelfBlacklist" = "الشخص الذي تحاول إضافته في القائمة السوداء الخاصة بك، لا يسمح بإضافته كصديق.";
|
||||
"TUIKitErrorSVRFriendshipAllowTypeDenyAny" = "الشخص الذي تحاول إضافته كصديق، لا يسمح بإضافته كصديق لأي شخص.";
|
||||
"TUIKitErrorSVRFriendshipInPeerBlackList" = "أنت في القائمة السوداء الخاصة بالشخص الذي تحاول إضافته كصديق، لا يسمح بإضافته كصديق.";
|
||||
"TUIKitErrorSVRFriendshipAllowTypeNeedConfirm" = "تم إرسال الطلب ويتم انتظار الموافقة من الشخص الآخر.";
|
||||
"TUIKitErrorSVRFriendshipAddFriendSecRstr" = "تم منع طلب الصداقة بسبب سياسة الأمان، يرجى عدم إرسال طلبات صداقة بشكل متكرر.";
|
||||
"TUIKitErrorSVRFriendshipPendencyNotFound" = "الطلب المعلق المطلوب غير موجود.";
|
||||
"TUIKitErrorSVRFriendshipDelFriendSecRstr" = "تم منع طلب حذف الصديق بسبب سياسة الأمان، يرجى عدم إرسال طلبات حذف الصديق بشكل متكرر.";
|
||||
|
||||
"TUIKirErrorSVRFriendAccountNotFoundEx" = "حساب المستخدم المطلوب غير موجود.";
|
||||
"TUIKitErrorSVRMsgPkgParseFailed" = "فشل تحليل حزمة الطلب.";
|
||||
"TUIKitErrorSVRMsgInternalAuthFailed" = "فشل المصادقة الداخلية.";
|
||||
"TUIKitErrorSVRMsgInvalidId" = "معرف غير صالح.";
|
||||
"TUIKitErrorSVRMsgNetError" = "خطأ في الشبكة، يرجى إعادة المحاولة.";
|
||||
"TUIKitErrorSVRMsgPushDeny" = "تم منع إرسال رسالة الدردشة الفردية قبل تنفيذها، تطبيق الخلفية يمنع إرسال هذه الرسالة.";
|
||||
"TUIKitErrorSVRMsgInPeerBlackList" = "تم حظر إرسال رسالة الدردشة الفردية بواسطة الشخص الآخر، يمنع إرسالها.";
|
||||
"TUIKitErrorSVRMsgBothNotFriend" = "الشخصين اللذين يحاولان إرسال رسالة الدردشة الفردية ليسا صديقين، يمنع إرسالها.";
|
||||
"TUIKitErrorSVRMsgNotPeerFriend" = "تم إرسال رسالة الدردشة الفردية وأنت لست صديق الشخص الآخر (علاقة من جانب واحد)، يمنع إرسالها.";
|
||||
"TUIkitErrorSVRMsgNotSelfFriend" = "تم إرسال رسالة الدردشة الفردية والشخص الآخر ليس صديقك (علاقة من جانب واحد)، يمنع إرسالها.";
|
||||
"TUIKitErrorSVRMsgShutupDeny" = "تم منع إرسال الرسائل بسبب الحظر عن الكلام.";
|
||||
"TUIKitErrorSVRMsgRevokeTimeLimit" = "تم تجاوز الحد الزمني لسحب الرسالة (الافتراضي 2 دقيقة).";
|
||||
"TUIKitErrorSVRMsgDelRambleInternalError" = "خطأ داخلي في حذف الرسائل المتجولة.";
|
||||
"TUIKitErrorSVRMsgJsonParseFailed" = "فشل تحليل تنسيق JSON، يرجى التحقق من صحة حزمة الطلب وفقًا لوصف JSON.";
|
||||
"TUIKitErrorSVRMsgInvalidJsonBodyFormat" = "تنسيق حزمة الطلب JSON غير صحيح، يرجى التحقق من صحة حقل MsgBody وفقًا لوصف تنسيق الرسالة.";
|
||||
"TUIKitErrorSVRMsgInvalidToAccount" = "حقل To_Account مفقود أو ليس من نوع Integer في حزمة الطلب بتنسيق JSON.";
|
||||
"TUIKitErrorSVRMsgInvalidRand" = "حقل MsgRandom مفقود أو ليس من نوع Integer في حزمة الطلب بتنسيق JSON.";
|
||||
"TUIKitErrorSVRMsgInvalidTimestamp" = "حقل MsgTimeStamp مفقود أو ليس من نوع Integer في حزمة الطلب بتنسيق JSON.";
|
||||
"TUIKitErrorSVRMsgBodyNotArray" = "نوع حقل MsgBody في حزمة الطلب بتنسيق JSON ليس من نوع Array.";
|
||||
"TUIKitErrorSVRMsgInvalidJsonFormat" = "حزمة الطلب بتنسيق JSON لا تتوافق مع وصف تنسيق الرسالة.";
|
||||
"TUIKitErrorSVRMsgToAccountCountLimit" = "عدد حسابات الوجهة في إرسال الرسائل الجماعية تجاوز الحد الأقصى (500).";
|
||||
"TUIKitErrorSVRMsgToAccountNotFound" = "حساب To_Account غير مسجل أو غير موجود.";
|
||||
"TUIKitErrorSVRMsgTimeLimit" = "خطأ في وقت تخزين الرسالة غير المتصلة (لا يمكن أن يتجاوز 7 أيام).";
|
||||
"TUIKitErrorSVRMsgInvalidSyncOtherMachine" = "حقل SyncOtherMachine في حزمة الطلب بتنسيق JSON ليس من نوع Integer.";
|
||||
"TUIkitErrorSVRMsgInvalidMsgLifeTime" = "حقل MsgLifeTime في حزمة الطلب بتنسيق JSON ليس من نوع Integer.";
|
||||
"TUIKitErrorSVRMsgBodySizeLimit" = "حزمة بيانات JSON طويلة جدًا، يرجى عدم تجاوز حجم حزمة الرسالة 12 كيلوبايت.";
|
||||
"TUIKitErrorSVRmsgLongPollingCountLimit" = "تم طرد الاستعلام الطويل على الويب (تم تجاوز الحد الأقصى لعدد الجلسات المتصلة في الويب).";
|
||||
"TUIKitErrorSVRGroupApiNameError" = "اسم الواجهة في الطلب غير صحيح.";
|
||||
"TUIKitErrorSVRGroupAccountCountLimit" = "عدد الحسابات المرفقة في حزمة الطلب كثير جدًا.";
|
||||
"TUIkitErrorSVRGroupFreqLimit" = "تم تقييد تكرار العملية، يرجى محاولة تقليل تكرار الاستدعاء.";
|
||||
"TUIKitErrorSVRGroupPermissionDeny" = "ليس لديك صلاحيات كافية للقيام بالعملية.";
|
||||
"TUIKitErrorSVRGroupInvalidReq" = "طلب غير صالح.";
|
||||
"TUIKitErrorSVRGroupSuperNotAllowQuit" = "لا يُسمح لمالك المجموعة بالخروج من المجموعة بنفسه.";
|
||||
"TUIKitErrorSVRGroupNotFound" = "المجموعة غير موجودة.";
|
||||
"TUIKitErrorSVRGroupJsonParseFailed" = "فشل تحليل حزمة JSON، يرجى التحقق من تنسيق الحزمة.";
|
||||
"TUIKitErrorSVRGroupInvalidId" = "معرف المستخدم الذي يقوم بالعملية غير صالح، يرجى التحقق من صحة معرف المستخدم الذي يقوم بالعملية.";
|
||||
"TUIKitErrorSVRGroupAllreadyMember" = "عضو في المجموعة بالفعل";
|
||||
"TUIKitErrorSVRGroupFullMemberCount" = "المجموعة مكتملة العدد، لا يمكن إضافة المستخدمين المحددين في الطلب إلى المجموعة.";
|
||||
"TUIKitErrorSVRGroupInvalidGroupId" = "معرف المجموعة غير صالح، يرجى التحقق من صحة معرف المجموعة.";
|
||||
"TUIKitErrorSVRGroupRejectFromThirdParty" = "تم رفض العملية من قبل خلفية التطبيق من خلال رد فعل طرف ثالث.";
|
||||
"TUIKitErrorSVRGroupShutDeny" = "لا يمكن إرسال الرسائل بسبب الحظر عن الكلام، يرجى التحقق مما إذا كان المرسل محظورًا عن الكلام.";
|
||||
"TUIKitErrorSVRGroupRspSizeLimit" = "تجاوز طول حزمة الاستجابة الحد الأقصى.";
|
||||
"TUIKitErrorSVRGroupAccountNotFound" = "حساب المستخدم المطلوب غير موجود.";
|
||||
"TUIKitErrorSVRGroupGroupIdInUse" = "معرف المجموعة قيد الاستخدام، يرجى اختيار معرف مجموعة آخر.";
|
||||
"TUIKitErrorSVRGroupSendMsgFreqLimit" = "تجاوز تكرار إرسال الرسائل، يرجى زيادة الفاصل الزمني بين إرسال الرسائل.";
|
||||
"TUIKitErrorSVRGroupReqAllreadyBeenProcessed" = "تم معالجة طلب الدعوة أو الطلب هذا بالفعل.";
|
||||
"TUIKitErrorSVRGroupGroupIdUserdForSuper" = "معرف المجموعة قيد الاستخدام والمستخدم هو المالك، يمكن استخدامه مباشرة.";
|
||||
"TUIKitErrorSVRGroupSDkAppidDeny" = "تم تعطيل كلمة الأمر المطلوبة من قبل SDKAppID المطلوب.";
|
||||
"TUIKitErrorSVRGroupRevokeMsgNotFound" = "الرسالة المطلوبة للإلغاء غير موجودة.";
|
||||
"TUIKitErrorSVRGroupRevokeMsgTimeLimit" = "تجاوز الوقت المحدد لإلغاء الرسالة (الافتراضي 2 دقيقة).";
|
||||
"TUIKitErrorSVRGroupRevokeMsgDeny" = "الرسالة المطلوبة للإلغاء لا تدعم عملية الإلغاء.";
|
||||
"TUIKitErrorSVRGroupNotAllowRevokeMsg" = "نوع المجموعة لا يدعم عملية إلغاء الرسالة.";
|
||||
"TUIKitErrorSVRGroupRemoveMsgDeny" = "نوع الرسالة غير مدعوم لعملية الحذف.";
|
||||
"TUIKitErrorSVRGroupNotAllowRemoveMsg" = "غرفة الدردشة الصوتية والفيديو والبث الكبير للأعضاء المتصلين لا تدعم حذف الرسائل.";
|
||||
"TUIKitErrorSVRGroupAvchatRoomCountLimit" = "تجاوز الحد الأقصى لعدد غرف الدردشة الصوتية والفيديو المنشأة.";
|
||||
"TUIKitErrorSVRGroupCountLimit" = "تجاوز الحد الأقصى لعدد المجموعات التي يمكن للمستخدم الفردي إنشاؤها والانضمام إليها.";
|
||||
"TUIKitErrorSVRGroupMemberCountLimit" = "تجاوز الحد الأقصى لعدد أعضاء المجموعة.";
|
||||
"TUIKitErrorSVRNoSuccessResult" = "لا توجد نتائج ناجحة للعملية المجمعة.";
|
||||
"TUIKitErrorSVRToUserInvalid" = "IM: المستلم غير صالح.";
|
||||
"TUIKitErrorSVRRequestTimeout" = "انتهت مهلة الطلب.";
|
||||
"TUIKitErrorSVRInitCoreFail" = "فشل في تهيئة وحدة INIT CORE.";
|
||||
"TUIKitErrorSVRConvGroupNameLengthLimit" = "تجاوز طول اسم مجموعة الدردشة الجماعية الحد الأقصى.";
|
||||
"TUIKitErrorExpiredSessionNode" = "SessionNode غير موجود.";
|
||||
"TUIKitErrorLoggedOutBeforeLoginFinished" = "تم تسجيل الخروج قبل انتهاء عملية تسجيل الدخول (تم الرد عند تسجيل الدخول).";
|
||||
"TUIKitErrorTLSSDKNotInitialized" = "لم يتم تهيئة tlssdk بعد.";
|
||||
"TUIKitErrorTLSSDKUserNotFound" = "لم يتم العثور على معلومات المستخدم المطلوبة في TLSSDK.";
|
||||
"TUIKitErrorBindFaildRegTimeout" = "انتهت مهلة التسجيل.";
|
||||
"TUIKitErrorBindFaildIsBinding" = "جاري عملية الربط حاليًا.";
|
||||
"TUIKitErrorPacketFailUnknown" = "خطأ غير معروف في إرسال الحزمة.";
|
||||
"TUIKitErrorPacketFailReqNoNet" = "لا يوجد اتصال بالشبكة أثناء إرسال حزمة الطلب، يتم تحويلها إلى حالة ERR_REQ_NO_NET_ON_REQ عند المعالجة.";
|
||||
"TUIKitErrorPacketFailRespNoNet" = "لا يوجد اتصال بالشبكة أثناء إرسال حزمة الرد، يتم تحويلها إلى حالة ERR_REQ_NO_NET_ON_RSP عند المعالجة.";
|
||||
"TUIKitErrorPacketFailReqNoAuth" = "لا يوجد صلاحيات أثناء إرسال حزمة الطلب.";
|
||||
"TUIKitErrorPacketFailSSOErr" = "خطأ في SSO.";
|
||||
"TUIKitErrorPacketFailRespTimeout" = "انتهت مهلة الرد.";
|
||||
"TUIKitErrorFriendshipProxySyncing" = "لم يكتمل تزامن بيانات proxy_manager مع الخادم.";
|
||||
"TUIKitErrorFriendshipProxySyncedFail" = "فشل في تزامن بيانات proxy_manager.";
|
||||
"TUIKitErrorFriendshipProxyLocalCheckErr" = "معلمات طلب proxy_manager غير صالحة في التحقق المحلي.";
|
||||
"TUIKitErrorGroupInvalidField" = "تحتوي حقل غير محدد في طلب مساعد المجموعة";
|
||||
"TUIKitErrorGroupStoreageDisabled" = "تم تعطيل تخزين معلومات المجموعة المحلي لمساعد المجموعة";
|
||||
"TUIKitErrorLoadGrpInfoFailed" = "فشل تحميل معلومات المجموعة من التخزين";
|
||||
"TUIKitErrorReqNoNetOnReq" = "لا يوجد اتصال بالشبكة أثناء الطلب.";
|
||||
"TUIKitErrorReqNoNetOnResp" = "لا يوجد اتصال بالشبكة أثناء الاستجابة.";
|
||||
"TUIKitErrorServiceNotReady" = "خدمة QALSDK غير جاهزة بعد.";
|
||||
"TUIKitErrorLoginAuthFailed" = "فشلت عملية المصادقة على الحساب (فشل في الحصول على معلومات المستخدم).";
|
||||
"TUIKitErrorNeverConnectAfterLaunch" = "لم يتم محاولة الاتصال بالإنترنت بعد تشغيل التطبيق.";
|
||||
"TUIKitErrorReqFailed" = "فشل تنفيذ الطلب في QAL.";
|
||||
"TUIKitErrorReqInvaidReq" = "طلب غير صالح، toMsgService غير صالح.";
|
||||
"TUIKitErrorReqOnverLoaded" = "طابور الطلبات مكتظ.";
|
||||
"TUIKitErrorReqKickOff" = "تم تسجيل الخروج من جهاز آخر.";
|
||||
"TUIKitErrorReqServiceSuspend" = "تم إيقاف الخدمة مؤقتًا.";
|
||||
"TUIKitErrorReqInvalidSign" = "توقيع SSO غير صالح.";
|
||||
"TUIKitErrorReqInvalidCookie" = "ملف تعريف الارتباط SSO غير صالح.";
|
||||
"TUIKitErrorLoginTlsRspParseFailed" = "فشل في التحقق من صحة حزمة الاستجابة TLS أثناء تسجيل الدخول، طول البيانات غير صحيح.";
|
||||
"TUIKitErrorLoginOpenMsgTimeout" = "انتهت مهلة تقرير حالة OPENSTATSVC إلى OPENMSG أثناء تسجيل الدخول.";
|
||||
"TUIKitErrorLoginOpenMsgRspParseFailed" = "فشل في تحليل حزمة الاستجابة أثناء تقرير حالة OPENSTATSVC إلى OPENMSG أثناء تسجيل الدخول.";
|
||||
"TUIKitErrorLoginTslDecryptFailed" = "فشل في فك تشفير TLS أثناء تسجيل الدخول.";
|
||||
"TUIKitErrorWifiNeedAuth" = "يتطلب wifi المصادقة";
|
||||
"TUIKitErrorUserCanceled" = "ألغى المستخدم";
|
||||
"TUIkitErrorRevokeTimeLimitExceed" = "تجاوزت إعادة الرسالة الحد الزمني (الافتراضي 2 دقيقة)";
|
||||
"TUIKitErrorLackUGExt" = "يفتقر إلى حزمة Multimedia الموسعة";
|
||||
"TUIKitErrorAutoLoginNeedUserSig" = "تسجيل الدخول التلقائي، انتهت صلاحية التذكرة المحلية، يتطلب تسجيل الدخول اليدوي باستخدام userSig";
|
||||
"TUIKitErrorQALNoShortConneAvailable" = "لا يوجد اتصال قصير SSO متاح";
|
||||
"TUIKitErrorReqContentAttach" = "ضربة أمنية لمحتوى الرسالة";
|
||||
"TUIKitErrorLoginSigExpire" = "انتهت صلاحية التذكرة المحلية عند تسجيل الدخول";
|
||||
"TUIKitErrorSDKHadInit" = "تم تهيئة SDK بالفعل ولا يلزم إعادة التهيئة";
|
||||
"TUIKitErrorOpenBDHBase" = "خطأ في openbdh";
|
||||
"TUIKitErrorRequestNoNetOnReq" = "لا يوجد اتصال بالشبكة أثناء الطلب، يرجى المحاولة مرة أخرى بعد استعادة الاتصال بالشبكة";
|
||||
"TUIKitErrorRequestNoNetOnRsp" = "لا يوجد اتصال بالشبكة أثناء الاستجابة، يرجى المحاولة مرة أخرى بعد استعادة الاتصال بالشبكة";
|
||||
"TUIKitErrorRequestOnverLoaded" = "طابور الطلبات ممتلئ";
|
||||
"TUIKitErrorUnsupporInterface" = "هذه الميزة متاحة فقط في الإصدار الرئيسي، يرجى الترقية إلى الإصدار الرئيسي.";
|
||||
"TUIKitErrorUnsupporInterfaceSuffix" = "هذه الميزة متاحة فقط في الإصدار الرئيسي، يرجى الترقية إلى الإصدار الرئيسي.";
|
||||
"TUIKitErrorUnsupportIntefaceSearch" = "البحث";
|
||||
"TUIKitErrorUnsupportIntefaceMessageRead" = "إيصال قراءة الرسالة";
|
||||
"TUIKitErrorUnsupportIntefaceCommunity" = "المجتمع";
|
||||
"TUIKitErrorUnsupportIntefaceDesc" = "هذه الميزة متاحة فقط في الإصدار الرئيسي لـ IM، يمكن استخدامها بعد شراء حزمة الإصدار الرئيسي، يرجى الرجوع إلى تفاصيل الأسعار.";
|
||||
"TUIKitErrorValueAddedUnsupportIntefaceDesc" = "هذه الميزة هي ميزة دفع إضافية وتقع حاليًا في مرحلة الاختبار الداخلي، يرجى الاتصال بفريق الأعمال في Tencent Cloud لتفعيلها واستخدامها.";
|
||||
"TUIKitErrorUnsupportIntefaceCommunityDesc" = "\nملاحظة: يمكن أن يستوعب المجتمع ملايين الأعضاء ويمكن تقسيمه إلى مجموعات ومواضيع، وهو مناسب لتبادل الاهتمامات والتواصل الاجتماعي في الألعاب وإدارة المعجبين وإدارة المنظمات وما إلى ذلك.";
|
||||
"TUIKitErrorUnsupportIntefaceGuidelines" = "تفاصيل الأسعار";
|
||||
"TUIKitErrorUnsupportIntefaceTitle" = "تنبيه";
|
||||
"TUIKitErrorUnsupportIntefaceIGotIt" = "فهمت";
|
||||
"TUIKitErrorUnsupportIntefaceNoMoreAlert" = "لا تذكرني مرة أخرى";
|
||||
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
Localizable.strings
|
||||
English
|
||||
|
||||
Created by harvy on 2020/10/9.
|
||||
|
||||
*/
|
||||
/***************************** 日期格式化 Start *************************/
|
||||
"YesterdayDateFormat" = "HH:mma"; // 英文是 HH:mma 不要动
|
||||
/***************************** 日期格式化 End ***************************/
|
||||
"TUIKitMoreVideoCall" = "Video Call";
|
||||
"TUIKitMoreVoiceCall" = "Voice Call";
|
||||
"Make-a-call" = "Start Call";
|
||||
"TUIKitNoSelfSignature" = "No status";
|
||||
"TUIKitSelfSignatureFormat" = "Status: %@";
|
||||
"TUIKitAllowTypeAcceptOne" = "Allow any user to add you as friend";
|
||||
"TUIKitAllowTypeNeedConfirm" = "Anyone upon Request";
|
||||
"TUIKitAllowTypeDeclineAll" = "Decline friend request from any user";
|
||||
"Male" = "Male";
|
||||
"Female" = "Female";
|
||||
"Unsetted" = "Not set";
|
||||
|
||||
"TUIKitErrorInProcess" = "Executing";
|
||||
"TUIKitErrorInvalidParameters" = "Invalid parameter";
|
||||
"TUIKitErrorIOOperateFaild" = "Local IO operation error";
|
||||
"TUIKitErrorInvalidJson" = "Invalid JSON format";
|
||||
"TUIKitErrorOutOfMemory" = "Out of storage";
|
||||
"TUIKitErrorParseResponseFaild" = "PB parsing failed";
|
||||
"TUIKitErrorSerializeReqFaild" = "PB serialization failed";
|
||||
"TUIKitErrorSDKNotInit" = "IM SDK is not initialized.";
|
||||
"TUIKitErrorLoadMsgFailed" = "Failed to load local database";
|
||||
"TUIKitErrorDatabaseOperateFailed" = "Local database operation failed";
|
||||
"TUIKitErrorCrossThread" = "Cross-thread error";
|
||||
"TUIKitErrorTinyIdEmpty" = "User info is empty.";
|
||||
"TUIKitErrorInvalidIdentifier" = "Invalid identifier";
|
||||
"TUIKitErrorFileNotFound" = "File not found";
|
||||
"TUIKitErrorFileTooLarge" = "File size exceeds the limit.";
|
||||
"TUIKitErrorEmptyFile" = "Empty file";
|
||||
"TUIKitErrorFileOpenFailed" = "Failed to open file";
|
||||
"TUIKitErrorNotLogin" = "Not logged in to IM SDK";
|
||||
"TUIKitErrorNoPreviousLogin" = "Not logged in to the user's account.";
|
||||
"TUIKitErrorUserSigExpired" = "UserSig expired";
|
||||
"TUIKitErrorLoginKickedOffByOther" = "Log in to the same account on other devices";
|
||||
"TUIKitErrorTLSSDKInit" = "TLS SDK initialization failed";
|
||||
"TUIKitErrorTLSSDKUninit" = "TLS SDK is not initialized.";
|
||||
"TUIKitErrorTLSSDKTRANSPackageFormat" = "Invalid TLS SDK TRANS packet format";
|
||||
"TUIKitErrorTLSDecrypt" = "TLS SDK decryption failed";
|
||||
"TUIKitErrorTLSSDKRequest" = "TLS SDK request failed";
|
||||
"TUIKitErrorTLSSDKRequestTimeout" = "TLS SDK request timed out";
|
||||
"TUIKitErrorInvalidConveration" = "Invalid session";
|
||||
"TUIKitErrorFileTransAuthFailed" = "Authentication failed during file transfer.";
|
||||
"TUIKitErrorFileTransNoServer" = "Failed to get the server list via FTP.";
|
||||
"TUIKitErrorFileTransUploadFailed" = "Failed to upload the file via FTP. Check your network connection.";
|
||||
"TUIKitErrorFileTransUploadFailedNotImage" = "Failed to upload the file via FTP. Check if the uploaded image can be opened normally.";
|
||||
"TUIKitErrorFileTransDownloadFailed" = "Failed to download the file via FTP. Check whether your network is connected or the file or audio has expired.";
|
||||
"TUIKitErrorHTTPRequestFailed" = "HTTP request failed";
|
||||
"TUIKitErrorInvalidMsgElem" = "Invalid IM SDK message elem";
|
||||
"TUIKitErrorInvalidSDKObject" = "Invalid object";
|
||||
"TUIKitSDKMsgBodySizeLimit" = "Message length exceeds the limit.";
|
||||
"TUIKitErrorSDKMsgKeyReqDifferRsp" = "Message key error";
|
||||
"TUIKitErrorSDKGroupInvalidID" = "Invalid group ID. Custom group ID must be printable ASCII characters (0x20-0x7e), with maximum length of 48 bytes, and cannot be prefixed with @TGS#.";
|
||||
"TUIKitErrorSDKGroupInvalidName" = "Group name is invalid, which cannot exceed 30 bytes.";
|
||||
"TUIKitErrorSDKGroupInvalidIntroduction" = "Group description is invalid, which cannot exceed 240 bytes.";
|
||||
"TUIKitErrorSDKGroupInvalidNotification" = "Group notice is invalid, which cannot exceed 300 bytes.";
|
||||
"TUIKitErrorSDKGroupInvalidFaceURL" = "Group profile photo URL is invalid, which should not exceed 100 bytes.";
|
||||
"TUIKitErrorSDKGroupInvalidNameCard" = "Group card is invalid, which cannot exceed 50 bytes.";
|
||||
"TUIKitErrorSDKGroupMemberCountLimit" = "The maximum number of group members is exceeded.";
|
||||
"TUIKitErrorSDKGroupJoinPrivateGroupDeny" = "Request to join private groups is not allowed.";
|
||||
"TUIKitErrorSDKGroupInviteSuperDeny" = "Group owners cannot be invited.";
|
||||
"TUIKitErrorSDKGroupInviteNoMember" = "The number of members to be invited cannot be 0.";
|
||||
"TUIKitErrorSDKFriendShipInvalidProfileKey" = "Invalid data field";
|
||||
"TUIKitErrorSDKFriendshipInvalidAddRemark" = "The remark field exceeds the limit of 96 bytes.";
|
||||
"TUIKitErrorSDKFriendshipInvalidAddWording" = "The description field in the friend request is invalid, which should not exceed 120 bytes.";
|
||||
"TUIKitErrorSDKFriendshipInvalidAddSource" = "The source field in the friend request is invalid, which should be prefixed with \"AddSource_Type_\".";
|
||||
"TUIKitErrorSDKFriendshipFriendGroupEmpty" = "The friend list field is invalid. It is required with each list name of 30 bytes at most.";
|
||||
"TUIKitErrorSDKNetEncodeFailed" = "Network link encryption failed";
|
||||
"TUIKitErrorSDKNetDecodeFailed" = "Network link decryption failed";
|
||||
"TUIKitErrorSDKNetAuthInvalid" = "Network link authentication not completed";
|
||||
"TUIKitErrorSDKNetCompressFailed" = "Unable to compress data packet";
|
||||
"TUIKitErrorSDKNetUncompressFaile" = "Packet decompression failed";
|
||||
"TUIKitErrorSDKNetFreqLimit" = "Call frequency is limited, with up to 5 requests per second.";
|
||||
"TUIKitErrorSDKnetReqCountLimit" = "Request queue is full. The number of concurrent requests exceeds the limit of 1000.";
|
||||
"TUIKitErrorSDKNetDisconnect" = "Network disconnected. No connection is established, or no network is detected when a socket connection is established.";
|
||||
"TUIKitErrorSDKNetAllreadyConn" = "Network connection has been established.";
|
||||
"TUIKitErrorSDKNetConnTimeout" = "Network connection timed out. Try again once network connection is restored.";
|
||||
"TUIKitErrorSDKNetConnRefuse" = "Network connection denied. Too many attempts. Service denied by the server.";
|
||||
"TUIKitErrorSDKNetNetUnreach" = "No available route to the network. Try again once network connection is restored.";
|
||||
"TUIKitErrorSDKNetSocketNoBuff" = "Call failed to due to insufficient buffer resources in the system. System busy. Internal error.";
|
||||
"TUIKitERRORSDKNetResetByPeer" = "The peer resets the connection.";
|
||||
"TUIKitErrorSDKNetSOcketInvalid" = "Invalid socket";
|
||||
"TUIKitErrorSDKNetHostGetAddressFailed" = "IP address resolution failed";
|
||||
"TUIKitErrorSDKNetConnectReset" = "Network is connected to an intermediate node or connection to the server is reset.";
|
||||
"TUIKitErrorSDKNetWaitInQueueTimeout" = "Timed out waiting for request packet to enter the to-be-sent queue.";
|
||||
"TUIKitErrorSDKNetWaitSendTimeout" = "Request packet has entered the to-be-sent queue. Timed out waiting to enter the network buffer of the system.";
|
||||
"TUIKitErrorSDKNetWaitAckTimeut" = "Request packet has entered the network buffer of the system. Timed out waiting for response from server.";
|
||||
"TUIKitErrorSDKWaitSendRemainingTimeout" =
|
||||
"The request packet has entered the queue to be sent, and part of the data has been sent. A timeout occurs while waiting for the remaining part to be sent. The uplink bandwidth may be insufficient. Please check whether the network is smooth. When the callback error occurs, it is detected that there is an Internet connection. Internal error";
|
||||
"TUIKitErrorSDKNetPKGSizeLimit" = "The request packet length is greater than the limit, the maximum supported is 1MB.";
|
||||
"TUIKitErrorSDKNetWaitSendTimeoutNoNetwork" = "The request packet length is greater than the limit, the maximum supported is 1MB. The request packet has entered the queue to be sent. The network buffer waiting to enter the system has timed out. There are too many data packets or the sending thread cannot process them. When the error code is called back, it is detected that there is no Internet connection.";
|
||||
"TUIKitErrorSDKNetWaitAckTimeoutNoNetwork" = "The request packet has entered the network buffer of the system, and the wait for the return packet from the server has timed out. The request packet may not have left the terminal device, the intermediate route has discarded it, the server has accidentally lost the packet, or the return packet has been discarded by the system network layer. There is no error code detected when calling back. networking.";
|
||||
"TUIKitErrorSDKNetRemainingTimeoutNoNetwork" = "The request packet has entered the queue to be sent, and part of the data has been sent. A timeout occurs while waiting for the remaining part to be sent. The uplink bandwidth may be insufficient. Please check whether the network is smooth. When calling back the error code, it is detected that there is no Internet connection.";
|
||||
|
||||
"TUIKitErrorSDKSVRSSOConnectLimit" = "The number of Server connections exceeds the limit. Service denied by the server.";
|
||||
"TUIKitErrorSDKSVRSSOVCode" = "Sending verification code timeout.";
|
||||
"TUIKitErrorSVRSSOD2Expired" = "Key expired. Key is an internal bill generated according to usersig. The validity period of the key is less than or equal to the validity period of usersig. Please call timmanager again getInstance(). The login interface generates a new key.";
|
||||
"TUIKitErrorSVRA2UpInvalid" = "Ticket expired. Ticket is an internal bill generated according to usersig. The validity period of ticket is less than or equal to that of usersig. Please call timmanager again getInstance(). The login interface generates a new ticket.";
|
||||
"TUIKitErrorSVRA2DownInvalid" = "The bill failed verification or was hit by security. Please call timmanager again getInstance(). The login interface generates a new ticket.";
|
||||
"TUIKitErrorSVRSSOEmpeyKey" = "Empty key is not allowed.";
|
||||
"TUIKitErrorSVRSSOUinInvalid" = "The account in the key does not match the account in the request header.";
|
||||
"TUIKitErrorSVRSSOVCodeTimeout" = "Timed out sending verification code.";
|
||||
"TUIKitErrorSVRSSONoImeiAndA2" = "You need to bring your key and ticket.";
|
||||
"TUIKitErrorSVRSSOCookieInvalid" = "Cookie check mismatch.";
|
||||
"TUIKitErrorSVRSSODownTips" = "Send a prompt: Key expired.";
|
||||
"TUIKitErrorSVRSSODisconnect" = "Link disconnected and screen locked.";
|
||||
"TUIKitErrorSVRSSOIdentifierInvalid" = "Invalid identity.";
|
||||
"TUIKitErrorSVRSSOClientClose" = "The device automatically logs out.";
|
||||
"TUIKitErrorSVRSSOMSFSDKQuit" = "MSFSDK automatically logs out.";
|
||||
"TUIKitErrorSVRSSOD2KeyWrong" = "the number of decryption failures exceeds the threshold, notify the terminal that it needs to be reset, please call timmanager again getInstance(). The login interface generates a new key.";
|
||||
"TUIKitErrorSVRSSOUnsupport" = "Aggregation is not supported. A unified error code is returned to devices. The device stops aggregation on the persistent TCP connection.";
|
||||
"TUIKitErrorSVRSSOPrepaidArrears" = "Prepaid service is in arrears.";
|
||||
"TUIKitErrorSVRSSOPacketWrong" = "Invalid request packet format.";
|
||||
"TUIKitErrorSVRSSOAppidBlackList" = "SDKAppID blocked list.";
|
||||
"TUIKitErrorSVRSSOCmdBlackList" = "SDKAppID sets the service cmd blocked list.";
|
||||
"TUIKitErrorSVRSSOAppidWithoutUsing" = "SDKAppID is disabled.";
|
||||
"TUIKitErrorSVRSSOFreqLimit" = "Frequency limit (user), which is to limit the number of requests per second of a protocol.";
|
||||
"TUIKitErrorSVRSSOOverload" = "Packet loss due to overload (system). Service denied by the connected server that failed to process too many requests.";
|
||||
"TUIKitErrorSVRResNotFound" = "The resource file to be sent does not exist.";
|
||||
"TUIKitErrorSVRResAccessDeny" = "Unable to access the resource file to be sent.";
|
||||
"TUIKitErrorSVRResSizeLimit"= "File size exceeds the limit.";
|
||||
"TUIKitErrorSVRResSendCancel" = "Sending is canceled by the user due to reasons like logging out when sending a message.";
|
||||
"TUIKitErrorSVRResReadFailed" = "Failed to access the file content.";
|
||||
"TUIKitErrorSVRResTransferTimeout" = "Timed out transferring the resource file.";
|
||||
"TUIKitErrorSVRResInvalidParameters" = "Invalid parameter.";
|
||||
"TUIKitErrorSVRResInvalidFileMd5" = "File MD5 verification failed.";
|
||||
"TUIKitErrorSVRResInvalidPartMd5" = "Sharding MD5 verification failed.";
|
||||
"TUIKitErrorSVRCommonInvalidHttpUrl" = "HTTP parsing error. Check the HTTP request URL format.";
|
||||
"TUIKitErrorSVRCommomReqJsonParseFailed" = "JSON parsing error in the HTTP request. Check the JSON format.";
|
||||
"TUIKitErrorSVRCommonInvalidAccount" = "The Identifier or UserSig in the request URI or JSON packet is incorrect.";
|
||||
"TUIKitErrorSVRCommonInvalidSdkappid" = "Invalid SDKAppID. Check the SDKAppID validity.";
|
||||
"TUIKitErrorSVRCommonRestFreqLimit" = "The REST API call frequency exceeds the limit. Reduce the request rate.";
|
||||
"TUIKitErrorSVRCommonRequestTimeout" = "The service request timed out or the HTTP request format is incorrect. Check the error and try again.";
|
||||
"TUIKitErrorSVRCommonInvalidRes" = "Requested resource error. Check the request URL.";
|
||||
"TUIKitErrorSVRCommonIDNotAdmin" = "Fill in the Identifier field of the REST API request with the app admin's account.";
|
||||
"TUIKitErrorSVRCommonSdkappidFreqLimit" = "SDKAppID request rate exceeds the limit. Reduce the request rate.";
|
||||
"TUIKitErrorSVRCommonSdkappidMiss" = "SDKAppID is required for the REST API. Check the SDKAppID in the request URL.";
|
||||
"TUIKitErrorSVRCommonRspJsonParseFailed" = "JSON parsing error in the HTTP response packet.";
|
||||
"TUIKitErrorSVRCommonExchangeAccountTimeout" = "Account switching timed out.";
|
||||
"TUIKitErrorSVRCommonInvalidIdFormat" = "The Identifier type of the request packet body is incorrect. Confirm that the Identifier is a string.";
|
||||
"TUIKitErrorSVRCommonSDkappidForbidden" = "SDKAppID is disabled.";
|
||||
"TUIKitErrorSVRCommonReqForbidden" = "Request is disabled.";
|
||||
"TUIKitErrorSVRCommonReqFreqLimit" = "Too many requests. Try again later.";
|
||||
"TUIKitErrorSVRCommonInvalidService" = "Your professional package has expired and been deactivated. Please log in to the im purchase page to re purchase the package. After purchase, it will take effect in 5 minutes.";
|
||||
"TUIKitErrorSVRCommonSensitiveText" = "Text is filtered due to security reasons, which may contain sensitive words.";
|
||||
"TUIKitErrorSVRCommonBodySizeLimit" = "The sending message package is too long. Currently, the maximum 12K message package length is supported. Please reduce the package size and try again.";
|
||||
"TUIKitErrorSVRAccountUserSigExpired" = "UserSig has expired. Generate a new one.";
|
||||
"TUIKitErrorSVRAccountUserSigEmpty" = "UserSig length is 0.";
|
||||
"TUIKitErrorSVRAccountUserSigCheckFailed" = "UserSig verification failed.";
|
||||
"TUIKitErrorSVRAccountUserSigMismatchPublicKey" = "Failed to verify UserSig with public key";
|
||||
"TUIKitErrorSVRAccountUserSigMismatchId" = "The requested Identifier does not match the Identifier that is used to generate the UserSig.";
|
||||
"TUIKitErrorSVRAccountUserSigMismatchSdkAppid" = "The requested SDKAppID does not match the SDKAppID of the generated UserSig.";
|
||||
"TUIKitErrorSVRAccountUserSigPublicKeyNotFound" = "Public key does not exist when verifying UserSig.";
|
||||
"TUIKitErrorSVRAccountUserSigSdkAppidNotFount" = "SDKAppID not found. Check the app information in the IM console.";
|
||||
"TUIKitErrorSVRAccountInvalidUserSig" = "UserSig has expired. Generate a new one and try again.";
|
||||
"TUIKitErrorSVRAccountNotFound" = "Requested user account not found.";
|
||||
"TUIKitErrorSVRAccountSecRstr" = "Restricted for security reasons.";
|
||||
"TUIKitErrorSVRAccountInternalTimeout" = "Internal server timeout. Try again.";
|
||||
"TUIKitErrorSVRAccountInvalidCount" = "Invalid batch quantity in the request.";
|
||||
"TUIkitErrorSVRAccountINvalidParameters" = "Invalid parameter. Check whether the fields are entered as required in the protocol.";
|
||||
"TUIKitErrorSVRAccountAdminRequired" = "The request requires app admin permissions.";
|
||||
"TUIKitErrorSVRAccountLowSDKVersion" = "Your sdk version is too low, Please upgrade to the latest version.";
|
||||
"TUIKitErrorSVRAccountFreqLimit" = "Restricted due to too many failures and retries. Check if the UserSig is correct and try again after one minute.";
|
||||
"TUIKitErrorSVRAccountBlackList" = "The account is added to the blocked list.";
|
||||
"TUIKitErrorSVRAccountCountLimit" = "The number of accounts created exceeds that allowed in the free trial version. Upgrade to the professional version.";
|
||||
"TUIKitErrorSVRAccountInternalError" = "Internal server error. Try again.";
|
||||
"TUIKitErrorSVRProfileInvalidParameters" = "Request parameter error. Check if the request is correct according to the error message.";
|
||||
"TUIKitErrorSVRProfileAccountMiss" = "Request parameter error. No user account specified to pull data.";
|
||||
"TUIKitErrorSVRProfileAccountNotFound" = "Requested user account not found.";
|
||||
"TUIKitErrorSVRProfileAdminRequired" = "The request requires app admin permissions.";
|
||||
"TUIKitErrorSVRProfileSensitiveText" = "The data field contains sensitive words.";
|
||||
"TUIKitErrorSVRProfileInternalError" = "Server internal error. Try again later.";
|
||||
"TUIKitErrorSVRProfileReadWritePermissionRequired" = "You have no permission to read the data field. See the data field for details.";
|
||||
"TUIKitErrorSVRProfileTagNotFound" = "The tag of the data field does not exist.";
|
||||
"TUIKitErrorSVRProfileSizeLimit" = "The value of the data field exceeds 500 bytes.";
|
||||
"TUIKitErrorSVRProfileValueError" = "The value of the standard data field is incorrect. See the standard data field for details.";
|
||||
"TUIKitErrorSVRProfileInvalidValueFormat" = "The value type of the data field does not match. See the standard data field for details.";
|
||||
"TUIKitErrorSVRFriendshipInvalidParameters" = "Request parameter error. Check if the request is correct according to the error message.";
|
||||
"TUIKitErrorSVRFriendshipInvalidSdkAppid" = "SDKAppID does not match.";
|
||||
"TUIKitErrorSVRFriendshipAccountNotFound" = "Requested user account not found.";
|
||||
"TUIKitErrorSVRFriendshipAdminRequired" = "The request requires app admin permissions.";
|
||||
"TUIKitErrorSVRFriendshipSensitiveText" = "The relation chain field contains sensitive words.";
|
||||
"TUIKitErrorSVRFriendshipNetTimeout" = "Network timed out. Try again later.";
|
||||
"TUIKitErrorSVRFriendshipWriteConflict" = "A write conflict occurred due to concurrent writes. The batch mode is recommended.";
|
||||
"TUIKitErrorSVRFriendshipAddFriendDeny" = "The backend blocks the user from initiating friend requests.";
|
||||
"TUIkitErrorSVRFriendshipCountLimit" = "The number of your friends exceeds the limit.";
|
||||
"TUIKitErrorSVRFriendshipGroupCountLimit" = "The number of lists exceeds the limit.";
|
||||
"TUIKitErrorSVRFriendshipPendencyLimit" = "You have reached the limit of pending friend requests.";
|
||||
"TUIKitErrorSVRFriendshipBlacklistLimit" = "The number of accounts in the blocked list exceeds the limit.";
|
||||
"TUIKitErrorSVRFriendshipPeerFriendLimit" = "The number of the other user's friends exceeds the limit.";
|
||||
"TUIKitErrorSVRFriendshipAlreadyFriends" = "Already a friend relationship";
|
||||
"TUIKitErrorSVRFriendshipInSelfBlacklist" = "You have blocked the other user. Unable to send friend request.";
|
||||
"TUIKitErrorSVRFriendshipAllowTypeDenyAny" = "The other user's friend request verification mode is \"Decline friend request from any user\".";
|
||||
"TUIKitErrorSVRFriendshipInPeerBlackList" = "You are blocked by the other user. Unable to send friend request.";
|
||||
"TUIKitErrorSVRFriendshipAllowTypeNeedConfirm" = "Request sent. Wait for acceptance.";
|
||||
"TUIKitErrorSVRFriendshipAddFriendSecRstr" = "The friend request was filtered by the security policy. Do not initiate friend requests too frequently.";
|
||||
"TUIKitErrorSVRFriendshipPendencyNotFound" = "The pending friend request does not exist.";
|
||||
"TUIKitErrorSVRFriendshipDelFriendSecRstr" = "The friend deletion request was filtered by the security policy. Do not initiate friend deletion requests too frequently.";
|
||||
"TUIKirErrorSVRFriendAccountNotFoundEx" = "Requested user account not found.";
|
||||
"TUIKitErrorSVRMsgPkgParseFailed" = "Failed to parse the request packet.";
|
||||
"TUIKitErrorSVRMsgInternalAuthFailed" = "Internal authentication failed.";
|
||||
"TUIKitErrorSVRMsgInvalidId" = "Invalid identifier";
|
||||
"TUIKitErrorSVRMsgNetError" = "Network error. Try again.";
|
||||
"TUIKitErrorSVRMsgPushDeny" = "A callback is triggered before sending a message in the private chat, and the App backend returns \"The message is prohibited from sending\".";
|
||||
"TUIKitErrorSVRMsgInPeerBlackList" = "Unable to send messages in the private chat as you are blocked by the other user.";
|
||||
"TUIKitErrorSVRMsgBothNotFriend" = "You are not a friend of this user. Unable to send messages.";
|
||||
"TUIKitErrorSVRMsgNotPeerFriend" = "Unable to send messages in the private chat as you are not the other user's friend (one-way friend).";
|
||||
"TUIkitErrorSVRMsgNotSelfFriend" = "Unable to send messages in the private chat as the other user is not your friend (one-way friend).";
|
||||
"TUIKitErrorSVRMsgShutupDeny" = "Blocked from posting. Unable to send messages.";
|
||||
"TUIKitErrorSVRMsgRevokeTimeLimit" = "Timed out recalling the message (default is 2 min).";
|
||||
"TUIKitErrorSVRMsgDelRambleInternalError" = "An internal error occurred while deleting roaming messages.";
|
||||
"TUIKitErrorSVRMsgJsonParseFailed" = "Failed to parse the JSON packet. Check whether the request packet meets the JSON specifications.";
|
||||
"TUIKitErrorSVRMsgInvalidJsonBodyFormat" = "MsgBody in the JSON request packet does not conform to the message format description.";
|
||||
"TUIKitErrorSVRMsgInvalidToAccount" = "The To_Account field is missing from the JSON request packet body or the type of the To_Account field is not Integer.";
|
||||
"TUIKitErrorSVRMsgInvalidRand" = "The MsgRandom field is missing from the JSON request packet body or the type of the MsgRandom field is not Integer.";
|
||||
"TUIKitErrorSVRMsgInvalidTimestamp" = "The MsgTimeStamp field is missing from the JSON request packet body or the type of the MsgTimeStamp field is not Integer.";
|
||||
"TUIKitErrorSVRMsgBodyNotArray" = "The MsgBody type in the JSON request packet body is not Array.";
|
||||
"TUIKitErrorSVRMsgInvalidJsonFormat" = "The JSON request packet does not conform to the message format description.";
|
||||
"TUIKitErrorSVRMsgToAccountCountLimit" = "The number of accounts to which messages are sent in batch exceeds 500.";
|
||||
"TUIKitErrorSVRMsgToAccountNotFound" = "To_Account is not registered or does not exist.";
|
||||
"TUIKitErrorSVRMsgTimeLimit" = "Invalid offline message storage time (up to 7 days).";
|
||||
"TUIKitErrorSVRMsgInvalidSyncOtherMachine" = "The type of the SyncOtherMachine field in the JSON request packet body is not Integer.";
|
||||
"TUIkitErrorSVRMsgInvalidMsgLifeTime" = "The type of the MsgLifeTime field in the JSON request packet body is not Integer.";
|
||||
"TUIKitErrorSVRMsgBodySizeLimit" = "The length of JSON data packet exceeds the limit. The message packet body shall not exceed 12 KB.";
|
||||
"TUIKitErrorSVRmsgLongPollingCountLimit" = "Forced logout on the Web page during long polling (the number of online instances on the Web page exceeds the limit).";
|
||||
"TUIKitErrorSVRGroupApiNameError" = "The API name in the request is incorrect.";
|
||||
"TUIKitErrorSVRGroupAccountCountLimit" = "The number of accounts in the request packet body exceeds the limit.";
|
||||
"TUIkitErrorSVRGroupFreqLimit" = "Call frequency is limited. Reduce the call frequency.";
|
||||
"TUIKitErrorSVRGroupPermissionDeny" = "Insufficient operation permissions";
|
||||
"TUIKitErrorSVRGroupInvalidReq" = "Invalid request";
|
||||
"TUIKitErrorSVRGroupSuperNotAllowQuit" = "Group owner is not allowed to leave this group.";
|
||||
"TUIKitErrorSVRGroupNotFound" = "The group does not exist.";
|
||||
"TUIKitErrorSVRGroupJsonParseFailed" = "Failed to parse the JSON packet. Check whether the packet body conforms to the JSON format.";
|
||||
"TUIKitErrorSVRGroupInvalidId" = "The identifier that is used to initiated the operation is invalid. Check whether the identifier of the user who initiated the operation is correct.";
|
||||
"TUIKitErrorSVRGroupAllreadyMember" = "Already a group member";
|
||||
"TUIKitErrorSVRGroupFullMemberCount" = "The number of group members has reached the limit. Unable to add the user in the request to the group.";
|
||||
"TUIKitErrorSVRGroupInvalidGroupId" = "Invalid group ID. Check whether the group ID is correct.";
|
||||
"TUIKitErrorSVRGroupRejectFromThirdParty" = "The app backend rejected this operation via a third-party callback.";
|
||||
"TUIKitErrorSVRGroupShutDeny" = "This user is blocked from posting and thus cannot send messages. Check whether the sender is blocked from posting.";
|
||||
"TUIKitErrorSVRGroupRspSizeLimit" = "The response packet length exceeds the limit.";
|
||||
"TUIKitErrorSVRGroupAccountNotFound" = "Requested user account not found.";
|
||||
"TUIKitErrorSVRGroupGroupIdInUse" = "The group ID has been used. Select another one.";
|
||||
"TUIKitErrorSVRGroupSendMsgFreqLimit" = "The frequency of sending messages exceeds the limit. Extend the interval between sending messages.";
|
||||
"TUIKitErrorSVRGroupReqAllreadyBeenProcessed" = "This invitation or request has been processed.";
|
||||
"TUIKitErrorSVRGroupGroupIdUserdForSuper" = "The group ID has been used by the group owner. It can be used directly.";
|
||||
"TUIKitErrorSVRGroupSDkAppidDeny" = "The command word used in the SDKAppID request has been disabled.";
|
||||
"TUIKitErrorSVRGroupRevokeMsgNotFound" = "This message does not exist.";
|
||||
"TUIKitErrorSVRGroupRevokeMsgTimeLimit" = "Timed out recalling the message (default is 2 min).";
|
||||
"TUIKitErrorSVRGroupRevokeMsgDeny" = "Unable to recall this message.";
|
||||
"TUIKitErrorSVRGroupNotAllowRevokeMsg" = "Unable to recall messages in groups of this type.";
|
||||
"TUIKitErrorSVRGroupRemoveMsgDeny" = "Unable to delete messages of this type.";
|
||||
"TUIKitErrorSVRGroupNotAllowRemoveMsg" = "Unable to delete messages in the voice/video chat room and the broadcast group of online members.";
|
||||
"TUIKitErrorSVRGroupAvchatRoomCountLimit" = "The number of created voice/video chat rooms exceeds the limit.";
|
||||
"TUIKitErrorSVRGroupCountLimit" = "The number of groups that a single user can create and join exceeds the limit.";
|
||||
"TUIKitErrorSVRGroupMemberCountLimit" = "The number of group members exceeds the limit.";
|
||||
"TUIKitErrorSVRNoSuccessResult" = "No success result returned for the batch operation.";
|
||||
"TUIKitErrorSVRToUserInvalid" = "IM: Invalid recipient";
|
||||
"TUIKitErrorSVRRequestTimeout" = "Request timeout";
|
||||
"TUIKitErrorSVRInitCoreFail" = "INIT CORE module failed";
|
||||
"TUIKitErrorSVRConvGroupNameLengthLimit" = "conversation group name length exceeds the maximum limit";
|
||||
"TUIKitErrorExpiredSessionNode" = "SessionNode is null.";
|
||||
"TUIKitErrorLoggedOutBeforeLoginFinished" = "Logged out before login (returned at login time)";
|
||||
"TUIKitErrorTLSSDKNotInitialized" = "tlssdk is not initialized.";
|
||||
"TUIKitErrorTLSSDKUserNotFound" = "The user information for TLSSDK was not found.";
|
||||
"TUIKitErrorBindFaildRegTimeout" = "Registration timed out";
|
||||
"TUIKitErrorBindFaildIsBinding" = "The bind operation in progress.";
|
||||
"TUIKitErrorPacketFailUnknown" = "Unknown error occurred while sending packet";
|
||||
"TUIKitErrorPacketFailReqNoNet" = "No network connection when sending request packet, which is converted to case ERR_REQ_NO_NET_ON_REQ:";
|
||||
"TUIKitErrorPacketFailRespNoNet" = "No network connection when sending response packet, which is converted to case ERR_REQ_NO_NET_ON_RSP:";
|
||||
"TUIKitErrorPacketFailReqNoAuth" = "No permission when sending request packet";
|
||||
"TUIKitErrorPacketFailSSOErr" = "SSO error";
|
||||
"TUIKitErrorPacketFailRespTimeout" = "Response timed out";
|
||||
"TUIKitErrorFriendshipProxySyncing" = "proxy_manager failed to sync SVR data";
|
||||
"TUIKitErrorFriendshipProxySyncedFail" = "proxy_manager sync failed";
|
||||
"TUIKitErrorFriendshipProxyLocalCheckErr" = "proxy_manager request parameter is invalid in local check.";
|
||||
"TUIKitErrorGroupInvalidField" = "group assistant request field contains non-preset fields.";
|
||||
"TUIKitErrorGroupStoreageDisabled" = "Local storage of group assistant group data is disabled.";
|
||||
"TUIKitErrorLoadGrpInfoFailed" = "Failed to load groupinfo from storage";
|
||||
"TUIKitErrorReqNoNetOnReq" = "No network connection when sending request";
|
||||
"TUIKitErrorReqNoNetOnResp" = "No network connection when sending response";
|
||||
"TUIKitErrorServiceNotReady" = "QALSDK service is not ready.";
|
||||
"TUIKitErrorLoginAuthFailed" = "Account verification failed (user info get failed)";
|
||||
"TUIKitErrorNeverConnectAfterLaunch" = "Failed to connect network when the app is lunched.";
|
||||
"TUIKitErrorReqFailed" = "QAL execution failed";
|
||||
"TUIKitErrorReqInvaidReq" = "Invalid request. Invalid toMsgService.";
|
||||
"TUIKitErrorReqOnverLoaded" = "Request queue is full.";
|
||||
"TUIKitErrorReqKickOff" = "Forced logout on another device";
|
||||
"TUIKitErrorReqServiceSuspend" = "Service suspended";
|
||||
"TUIKitErrorReqInvalidSign" = "SSO signature error";
|
||||
"TUIKitErrorReqInvalidCookie" = "Invalid SSO cookie";
|
||||
"TUIKitErrorLoginTlsRspParseFailed" = "TSL response packet is verified at login time. Packet length error.";
|
||||
"TUIKitErrorLoginOpenMsgTimeout" = "Timeout occurred when OPENSTATSVC attempted to report status to OPENMSG during login.";
|
||||
"TUIKitErrorLoginOpenMsgRspParseFailed" = "Response parsing failed when OPENSTATSVC reports status to OPENMSG during login.";
|
||||
"TUIKitErrorLoginTslDecryptFailed" = "TLS decryption failed at login time.";
|
||||
"TUIKitErrorWifiNeedAuth" = "Verification is required for Wi-Fi connection.";
|
||||
"TUIKitErrorUserCanceled" = "Canceled by user";
|
||||
"TUIkitErrorRevokeTimeLimitExceed" = "Timed out recalling the message (default is 2 min).";
|
||||
"TUIKitErrorLackUGExt" = "Missing Multimedia extension pack";
|
||||
"TUIKitErrorAutoLoginNeedUserSig" = "Local ticket for auto login expired. userSig is required for manual login.";
|
||||
"TUIKitErrorQALNoShortConneAvailable" = "No available SSO for short connections.";
|
||||
"TUIKitErrorReqContentAttach" = "Message content is filtered due to security reasons.";
|
||||
"TUIKitErrorLoginSigExpire" = "Returned at login time. Ticket expired.";
|
||||
"TUIKitErrorSDKHadInit" = "SDK has been initialized. Do not initialize again.";
|
||||
"TUIKitErrorOpenBDHBase" = "Openbdh error";
|
||||
"TUIKitErrorRequestNoNetOnReq" = "No network connection when sending request. Try again once network connection is restored.";
|
||||
"TUIKitErrorRequestNoNetOnRsp" = "No network connection when sending response. Try again once network connection is restored.";
|
||||
"TUIKitErrorRequestOnverLoaded" = "Request queue is full.";
|
||||
"TUIKitErrorUnsupporInterface" = "This feature is available only to the Ultimate edition. Please upgrade.";
|
||||
"TUIKitErrorUnsupporInterfaceSuffix" = " feature is available only to the Ultimate edition. Please upgrade.";
|
||||
"TUIKitErrorUnsupportIntefaceSearch" = "Search";
|
||||
"TUIKitErrorUnsupportIntefaceMessageRead" = "Message Read Receipt";
|
||||
"TUIKitErrorUnsupportIntefaceCommunity" = "Community";
|
||||
"TUIKitErrorUnsupportIntefaceDesc" = " feature is only available to the Ultimate edition, which can be used after purchasing the Ultimate Edition. See the price guidelines for details.";
|
||||
"TUIKitErrorValueAddedUnsupportIntefaceContactDesc" = " is a value-added payment feature, which is currently in the internal testing stage. Click to enter [Tencent Cloud Instant messaging IM Group] to apply for activation and trial.";
|
||||
"TUIKitErrorValueAddedUnsupportIntefacePurchaseDesc" = " is a value-added payment feature, Please go to Tencent Cloud console [Plug-in Market] for trial or purchase and activate";
|
||||
"TUIKitErrorValueAddedUnsupportIntefaceContactDescHighlight" = "[Tencent Cloud Instant messaging IM Group]";
|
||||
"TUIKitErrorValueAddedUnsupportIntefacePurchaseDescHighlight" = "[Plug-in Market]";
|
||||
"TUIKitErrorUnsupportIntefaceCommunityDesc" = "\nNote: The community can accommodate millions of members, and can be divided into groups and topics. It is suitable for interest making friends, game social networking, fan operation, organization management and other scenarios.";
|
||||
"TUIKitErrorUnsupportIntefaceGuidelines" = "price guidelines";
|
||||
"TUIKitErrorUnsupportIntefaceTitle" = "Tips";
|
||||
"TUIKitErrorUnsupportIntefaceIGotIt" = "I got it";
|
||||
"TUIKitErrorUnsupportIntefaceNoMoreAlert" = "No more reminders";
|
||||
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
Localizable.strings
|
||||
Chinese Simplized
|
||||
|
||||
Created by harvy on 2020/10/9.
|
||||
|
||||
*/
|
||||
|
||||
/***************************** 日期格式化 Start *************************/
|
||||
"YesterdayDateFormat" = "aHH:mm";
|
||||
/***************************** 日期格式化 End *************************/
|
||||
|
||||
"TUIKitMoreVideoCall" = "视频通话";
|
||||
"TUIKitMoreVoiceCall" = "语音通话";
|
||||
"Make-a-call" = "发起呼叫";
|
||||
"TUIKitNoSelfSignature" = "暂无个性签名";
|
||||
"TUIKitSelfSignatureFormat" = "个性签名:%@";
|
||||
"TUIKitAllowTypeAcceptOne" = "同意任何用户加好友";
|
||||
"TUIKitAllowTypeNeedConfirm" = "需要验证";
|
||||
"TUIKitAllowTypeDeclineAll" = "拒绝任何人加好友";
|
||||
"Male" = "男";
|
||||
"Female" = "女";
|
||||
"Unsetted" = "未设置";
|
||||
|
||||
"TUIKitErrorInProcess" = "执行中";
|
||||
"TUIKitErrorInvalidParameters" = "参数无效";
|
||||
"TUIKitErrorIOOperateFaild" = "操作本地 IO 错误";
|
||||
"TUIKitErrorInvalidJson" = "错误的 JSON 格式";
|
||||
"TUIKitErrorOutOfMemory" = "内存不足";
|
||||
"TUIKitErrorParseResponseFaild" = "PB 解析失败";
|
||||
"TUIKitErrorSerializeReqFaild" = "PB 序列化失败";
|
||||
"TUIKitErrorSDKNotInit" = "IM SDK 未初始化";
|
||||
"TUIKitErrorLoadMsgFailed" = "加载本地数据库操作失败";
|
||||
"TUIKitErrorDatabaseOperateFailed" = "本地数据库操作失败";
|
||||
"TUIKitErrorCrossThread" = "跨线程错误";
|
||||
"TUIKitErrorTinyIdEmpty" = "用户信息为空";
|
||||
"TUIKitErrorInvalidIdentifier" = "Identifier 非法";
|
||||
"TUIKitErrorFileNotFound" = "文件不存在";
|
||||
"TUIKitErrorFileTooLarge" = "文件大小超出了限制";
|
||||
"TUIKitErrorEmptyFile" = "空文件";
|
||||
"TUIKitErrorFileOpenFailed" = "文件打开失败";
|
||||
"TUIKitErrorNotLogin" = "IM SDK 未登陆";
|
||||
"TUIKitErrorNoPreviousLogin" = "并没有登录过该用户";
|
||||
"TUIKitErrorUserSigExpired" = "UserSig 过期";
|
||||
"TUIKitErrorLoginKickedOffByOther" = "其他终端登录同一账号";
|
||||
"TUIKitErrorTLSSDKInit" = "TLS SDK 初始化失败";
|
||||
"TUIKitErrorTLSSDKUninit" = "TLS SDK 未初始化";
|
||||
"TUIKitErrorTLSSDKTRANSPackageFormat" = "TLS SDK TRANS 包格式错误";
|
||||
"TUIKitErrorTLSDecrypt" = "TLS SDK 解密失败";
|
||||
"TUIKitErrorTLSSDKRequest" = "TLS SDK 请求失败";
|
||||
"TUIKitErrorTLSSDKRequestTimeout" = "TLS SDK 请求超时";
|
||||
"TUIKitErrorInvalidConveration" = "会话无效";
|
||||
"TUIKitErrorFileTransAuthFailed" = "文件传输鉴权失败";
|
||||
"TUIKitErrorFileTransNoServer" = "文件传输获取 Server 列表失败";
|
||||
"TUIKitErrorFileTransUploadFailed" = "文件传输上传失败,请检查网络是否连接";
|
||||
"TUIKitErrorFileTransUploadFailedNotImage" = "文件传输上传失败,请检查上传的图片是否能够正常打开";
|
||||
"TUIKitErrorFileTransDownloadFailed" = "文件传输下载失败,请检查网络,或者文件、语音是否已经过期";
|
||||
"TUIKitErrorHTTPRequestFailed" = "HTTP 请求失败";
|
||||
"TUIKitErrorInvalidMsgElem" = "IM SDK 无效消息 elem";
|
||||
"TUIKitErrorInvalidSDKObject" = "无效的对象";
|
||||
"TUIKitSDKMsgBodySizeLimit" = "消息长度超出限制";
|
||||
"TUIKitErrorSDKMsgKeyReqDifferRsp" = "消息 KEY 错误";
|
||||
"TUIKitErrorSDKGroupInvalidID" = "群组 ID 非法,自定义群组 ID 必须为可打印 ASCII 字符(0x20-0x7e),最长48个字节,且前缀不能为 @TGS#";
|
||||
"TUIKitErrorSDKGroupInvalidName" = "群名称非法,群名称最长30字节";
|
||||
"TUIKitErrorSDKGroupInvalidIntroduction" = "群简介非法,群简介最长240字节";
|
||||
"TUIKitErrorSDKGroupInvalidNotification" = "群公告非法,群公告最长300字节";
|
||||
"TUIKitErrorSDKGroupInvalidFaceURL" = "群头像 URL 非法,群头像 URL 最长100字节";
|
||||
"TUIKitErrorSDKGroupInvalidNameCard" = "群名片非法,群名片最长50字节";
|
||||
"TUIKitErrorSDKGroupMemberCountLimit" = "超过群组成员数的限制";
|
||||
"TUIKitErrorSDKGroupJoinPrivateGroupDeny" = "不允许申请加入 Private 群组";
|
||||
"TUIKitErrorSDKGroupInviteSuperDeny" = "不允许邀请角色为群主的成员";
|
||||
"TUIKitErrorSDKGroupInviteNoMember" = "不允许邀请0个成员";
|
||||
"TUIKitErrorSDKFriendShipInvalidProfileKey" = "资料字段非法";
|
||||
"TUIKitErrorSDKFriendshipInvalidAddRemark" = "备注字段非法,最大96字节";
|
||||
"TUIKitErrorSDKFriendshipInvalidAddWording" = "请求添加好友的请求说明字段非法,最大120字节";
|
||||
"TUIKitErrorSDKFriendshipInvalidAddSource" = "请求添加好友的添加来源字段非法,来源需要添加“AddSource_Type_”前缀。";
|
||||
"TUIKitErrorSDKFriendshipFriendGroupEmpty" = "好友分组字段非法,必须不为空,每个分组的名称最长30字节";
|
||||
"TUIKitErrorSDKNetEncodeFailed" = "网络链接加密失败";
|
||||
"TUIKitErrorSDKNetDecodeFailed" = "网络链接解密失败";
|
||||
"TUIKitErrorSDKNetAuthInvalid" = "网络链接未完成鉴权";
|
||||
"TUIKitErrorSDKNetCompressFailed" = "数据包压缩失败";
|
||||
"TUIKitErrorSDKNetUncompressFaile" = "数据包解压失败";
|
||||
"TUIKitErrorSDKNetFreqLimit" = "调用频率限制,最大每秒发起 5 次请求";
|
||||
"TUIKitErrorSDKnetReqCountLimit" = "请求队列満,超过同时请求的数量限制,最大同时发起1000个请求。";
|
||||
"TUIKitErrorSDKNetDisconnect" = "网络已断开,未建立连接,或者建立 socket 连接时,检测到无网络。";
|
||||
"TUIKitErrorSDKNetAllreadyConn" = "网络连接已建立,重复创建连接";
|
||||
"TUIKitErrorSDKNetConnTimeout" = "建立网络连接超时,请等网络恢复后重试。";
|
||||
"TUIKitErrorSDKNetConnRefuse" = "网络连接已被拒绝,请求过于频繁,服务端拒绝服务。";
|
||||
"TUIKitErrorSDKNetNetUnreach" = "没有到达网络的可用路由,请等网络恢复后重试。";
|
||||
"TUIKitErrorSDKNetSocketNoBuff" = "系统中没有足够的缓冲区空间资源可用来完成调用,系统过于繁忙,内部错误。";
|
||||
"TUIKitERRORSDKNetResetByPeer" = "对端重置了连接";
|
||||
"TUIKitErrorSDKNetSOcketInvalid" = "socket 套接字无效";
|
||||
"TUIKitErrorSDKNetHostGetAddressFailed" = "IP 地址解析失败";
|
||||
"TUIKitErrorSDKNetConnectReset" = "网络连接到中间节点或服务端重置";
|
||||
"TUIKitErrorSDKNetWaitInQueueTimeout" = "请求包等待进入待发送队列超时";
|
||||
"TUIKitErrorSDKNetWaitSendTimeout" = "请求包已进入待发送队列,等待进入系统的网络 buffer 超时";
|
||||
"TUIKitErrorSDKNetWaitAckTimeut" = "请求包已进入系统的网络 buffer ,等待服务端回包超时";
|
||||
"TUIKitErrorSDKWaitSendRemainingTimeout" =
|
||||
"请求包已进入待发送队列,部分数据已发送,等待发送剩余部分出现超时,可能上行带宽不足,请检查网络是否畅通,在回调错误时检测有联网,内部错误";
|
||||
"TUIKitErrorSDKNetPKGSizeLimit" = "请求包长度大于限制,最大支持 1MB 。";
|
||||
"TUIKitErrorSDKNetWaitSendTimeoutNoNetwork" = "请求包已进入待发送队列,等待进入系统的网络 buffer 超时,数据包较多 或 发送线程处理不过来,在回调错误码时检测到没有联网。";
|
||||
"TUIKitErrorSDKNetWaitAckTimeoutNoNetwork" = "请求包已进入系统的网络 buffer ,等待服务端回包超时,可能请求包没离开终端设备、中间路由丢弃、服务端意外丢包或回包被系统网络层丢弃,在回调错误码时检测到没有联网。";
|
||||
"TUIKitErrorSDKNetRemainingTimeoutNoNetwork" = "请求包已进入待发送队列,部分数据已发送,等待发送剩余部分出现超时,可能上行带宽不足,请检查网络是否畅通,在回调错误码时检测到没有联网。";
|
||||
"TUIKitErrorSDKSVRSSOConnectLimit" = "Server 的连接数量超出限制,服务端拒绝服务。";
|
||||
"TUIKitErrorSDKSVRSSOVCode" = "验证码下发超时。";
|
||||
"TUIKitErrorSVRSSOD2Expired" = "Key 过期。Key 是根据 UserSig 生成的内部票据,Key 的有效期小于或等于 UserSig 的有效期。请重新调用 TIMManager.getInstance().login 登录接口生成新的 Key。";
|
||||
"TUIKitErrorSVRA2UpInvalid" = "Ticket 过期。Ticket 是根据 UserSig 生成的内部票据,Ticket 的有效期小于或等于 UserSig 的有效期。请重新调用 TIMManager.getInstance().login 登录接口生成新的 Ticket。";
|
||||
"TUIKitErrorSVRA2DownInvalid" = "票据验证没通过或者被安全打击。请重新调用 TIMManager.getInstance().login 登录接口生成新的票据。";
|
||||
"TUIKitErrorSVRSSOEmpeyKey" = "不允许空 Key。";
|
||||
"TUIKitErrorSVRSSOUinInvalid" = "Key 中的账号和请求包头的账号不匹配。";
|
||||
"TUIKitErrorSVRSSOVCodeTimeout" = "验证码下发超时。";
|
||||
"TUIKitErrorSVRSSONoImeiAndA2" = "需要带上 Key 和 Ticket。";
|
||||
"TUIKitErrorSVRSSOCookieInvalid" = "Cookie 检查不匹配。";
|
||||
"TUIKitErrorSVRSSODownTips" = "下发提示语,Key 过期。";
|
||||
"TUIKitErrorSVRSSODisconnect" = "断链锁屏。";
|
||||
"TUIKitErrorSVRSSOIdentifierInvalid" = "失效身份。";
|
||||
"TUIKitErrorSVRSSOClientClose" = "终端自动退出。";
|
||||
"TUIKitErrorSVRSSOMSFSDKQuit" = "MSFSDK 自动退出。";
|
||||
"TUIKitErrorSVRSSOD2KeyWrong" = "解密失败次数超过阈值,通知终端需要重置,请重新调用 TIMManager.getInstance().login 登录接口生成新的 Key。";
|
||||
"TUIKitErrorSVRSSOUnsupport" = "不支持聚合,给终端返回统一的错误码。终端在该 TCP 长连接上停止聚合。";
|
||||
"TUIKitErrorSVRSSOPrepaidArrears" = "预付费欠费。";
|
||||
"TUIKitErrorSVRSSOPacketWrong" = "请求包格式错误。";
|
||||
"TUIKitErrorSVRSSOAppidBlackList" = "SDKAppID 黑名单。";
|
||||
"TUIKitErrorSVRSSOCmdBlackList" = "SDKAppID 设置 service cmd 黑名单。";
|
||||
"TUIKitErrorSVRSSOAppidWithoutUsing" = "SDKAppID 停用。";
|
||||
"TUIKitErrorSVRSSOFreqLimit" = "频率限制(用户),频率限制是设置针对某一个协议的每秒请求数的限制。";
|
||||
"TUIKitErrorSVRSSOOverload" = "过载丢包(系统),连接的服务端处理过多请求,处理不过来,拒绝服务。";
|
||||
"TUIKitErrorSVRResNotFound" = "要发送的资源文件不存在。";
|
||||
"TUIKitErrorSVRResAccessDeny" = "要发送的资源文件不允许访问。";
|
||||
"TUIKitErrorSVRResSizeLimit"= "文件大小超过限制。";
|
||||
"TUIKitErrorSVRResSendCancel" = "用户取消发送,如发送过程中登出等原因。";
|
||||
"TUIKitErrorSVRResReadFailed" = "读取文件内容失败。";
|
||||
"TUIKitErrorSVRResTransferTimeout" = "资源文件传输超时";
|
||||
"TUIKitErrorSVRResInvalidParameters" = "参数非法。";
|
||||
"TUIKitErrorSVRResInvalidFileMd5" = "文件 MD5 校验失败。";
|
||||
"TUIKitErrorSVRResInvalidPartMd5" = "分片 MD5 校验失败。";
|
||||
"TUIKitErrorSVRCommonInvalidHttpUrl" = "HTTP 解析错误 ,请检查 HTTP 请求 URL 格式。";
|
||||
"TUIKitErrorSVRCommomReqJsonParseFailed" = "HTTP 请求 JSON 解析错误,请检查 JSON 格式。";
|
||||
"TUIKitErrorSVRCommonInvalidAccount" = "请求 URI 或 JSON 包体中 Identifier 或 UserSig 错误。";
|
||||
"TUIKitErrorSVRCommonInvalidSdkappid" = "SDKAppID 失效,请核对 SDKAppID 有效性。";
|
||||
"TUIKitErrorSVRCommonRestFreqLimit" = "REST 接口调用频率超过限制,请降低请求频率。";
|
||||
"TUIKitErrorSVRCommonRequestTimeout" = "服务请求超时或 HTTP 请求格式错误,请检查并重试。";
|
||||
"TUIKitErrorSVRCommonInvalidRes" = "请求资源错误,请检查请求 URL。";
|
||||
"TUIKitErrorSVRCommonIDNotAdmin" = "REST API 请求的 Identifier 字段请填写 App 管理员账号。";
|
||||
"TUIKitErrorSVRCommonSdkappidFreqLimit" = "SDKAppID 请求频率超限,请降低请求频率。";
|
||||
"TUIKitErrorSVRCommonSdkappidMiss" = "REST 接口需要带 SDKAppID,请检查请求 URL 中的 SDKAppID。";
|
||||
"TUIKitErrorSVRCommonRspJsonParseFailed" = "HTTP 响应包 JSON 解析错误。";
|
||||
"TUIKitErrorSVRCommonExchangeAccountTimeout" = "置换账号超时。";
|
||||
"TUIKitErrorSVRCommonInvalidIdFormat" = "请求包体 Identifier 类型错误,请确认 Identifier 为字符串格式。";
|
||||
"TUIKitErrorSVRCommonSDkappidForbidden" = "SDKAppID 被禁用";
|
||||
"TUIKitErrorSVRCommonReqForbidden" = "请求被禁用";
|
||||
"TUIKitErrorSVRCommonReqFreqLimit" = "请求过于频繁,请稍后重试。";
|
||||
"TUIKitErrorSVRCommonInvalidService" = "您的专业版套餐包已到期并停用,请登录 即时通信 IM 购买页面 重新购买套餐包。购买后,将在5分钟后生效。";
|
||||
"TUIKitErrorSVRCommonSensitiveText" = "文本安全打击,文本中可能包含敏感词汇。";
|
||||
"TUIKitErrorSVRCommonBodySizeLimit" = "发消息包体过长,目前支持最大12k消息包体长度,请减少包体大小重试。";
|
||||
"TUIKitErrorSVRAccountUserSigExpired" = "UserSig 已过期,请重新生成 UserSig";
|
||||
"TUIKitErrorSVRAccountUserSigEmpty" = "UserSig 长度为0";
|
||||
"TUIKitErrorSVRAccountUserSigCheckFailed" = "UserSig 校验失败";
|
||||
"TUIKitErrorSVRAccountUserSigMismatchPublicKey" = "用公钥验证 UserSig 失败";
|
||||
"TUIKitErrorSVRAccountUserSigMismatchId" = "请求的 Identifier 与生成 UserSig 的 Identifier 不匹配。";
|
||||
"TUIKitErrorSVRAccountUserSigMismatchSdkAppid" = "请求的 SDKAppID 与生成 UserSig 的 SDKAppID 不匹配。";
|
||||
"TUIKitErrorSVRAccountUserSigPublicKeyNotFound" = "验证 UserSig 时公钥不存在";
|
||||
"TUIKitErrorSVRAccountUserSigSdkAppidNotFount" = "SDKAppID 未找到,请在云通信 IM 控制台确认应用信息。";
|
||||
"TUIKitErrorSVRAccountInvalidUserSig" = "UserSig 已经失效,请重新生成,再次尝试。";
|
||||
"TUIKitErrorSVRAccountNotFound" = "请求的用户账号不存在。";
|
||||
"TUIKitErrorSVRAccountSecRstr" = "安全原因被限制。";
|
||||
"TUIKitErrorSVRAccountInternalTimeout" = "服务端内部超时,请重试。";
|
||||
"TUIKitErrorSVRAccountInvalidCount" = "请求中批量数量不合法。";
|
||||
"TUIkitErrorSVRAccountINvalidParameters" = "参数非法,请检查必填字段是否填充,或者字段的填充是否满足协议要求。";
|
||||
"TUIKitErrorSVRAccountAdminRequired" = "请求需要 App 管理员权限。";
|
||||
"TUIKitErrorSVRAccountLowSDKVersion" = "您的SDK版本过低,请升级到最新版本。";
|
||||
"TUIKitErrorSVRAccountFreqLimit" = "因失败且重试次数过多导致被限制,请检查 UserSig 是否正确,一分钟之后再试。";
|
||||
"TUIKitErrorSVRAccountBlackList" = "账号被拉入黑名单。";
|
||||
"TUIKitErrorSVRAccountCountLimit" = "创建账号数量超过免费体验版数量限制,请升级为专业版。";
|
||||
"TUIKitErrorSVRAccountInternalError" = "服务端内部错误,请重试。";
|
||||
"TUIKitErrorSVRProfileInvalidParameters" = "请求参数错误,请根据错误描述检查请求是否正确。";
|
||||
"TUIKitErrorSVRProfileAccountMiss" = "请求参数错误,没有指定需要拉取资料的用户账号。";
|
||||
"TUIKitErrorSVRProfileAccountNotFound" = "请求的用户账号不存在。";
|
||||
"TUIKitErrorSVRProfileAdminRequired" = "请求需要 App 管理员权限。";
|
||||
"TUIKitErrorSVRProfileSensitiveText" = "资料字段中包含敏感词。";
|
||||
"TUIKitErrorSVRProfileInternalError" = "服务端内部错误,请稍后重试。";
|
||||
"TUIKitErrorSVRProfileReadWritePermissionRequired" = "没有资料字段的读权限,详情可参见 资料字段。";
|
||||
"TUIKitErrorSVRProfileTagNotFound" = "资料字段的 Tag 不存在。";
|
||||
"TUIKitErrorSVRProfileSizeLimit" = "资料字段的 Value 长度超过500字节。";
|
||||
"TUIKitErrorSVRProfileValueError" = "标配资料字段的 Value 错误,详情可参见 标配资料字段。";
|
||||
"TUIKitErrorSVRProfileInvalidValueFormat" = "资料字段的 Value 类型不匹配,详情可参见 标配资料字段。";
|
||||
"TUIKitErrorSVRFriendshipInvalidParameters" = "请求参数错误,请根据错误描述检查请求是否正确。";
|
||||
"TUIKitErrorSVRFriendshipInvalidSdkAppid" = "SDKAppID 不匹配。";
|
||||
"TUIKitErrorSVRFriendshipAccountNotFound" = "请求的用户账号不存在。";
|
||||
"TUIKitErrorSVRFriendshipAdminRequired" = "请求需要 App 管理员权限。";
|
||||
"TUIKitErrorSVRFriendshipSensitiveText" = "关系链字段中包含敏感词。";
|
||||
"TUIKitErrorSVRFriendshipNetTimeout" = "网络超时,请稍后重试。";
|
||||
"TUIKitErrorSVRFriendshipWriteConflict" = "并发写导致写冲突,建议使用批量方式。";
|
||||
"TUIKitErrorSVRFriendshipAddFriendDeny" = "后台禁止该用户发起加好友请求。";
|
||||
"TUIkitErrorSVRFriendshipCountLimit" = "您的好友数已达系统上限。";
|
||||
"TUIKitErrorSVRFriendshipGroupCountLimit" = "分组已达系统上限。";
|
||||
"TUIKitErrorSVRFriendshipPendencyLimit" = "未决数已达系统上限。";
|
||||
"TUIKitErrorSVRFriendshipBlacklistLimit" = "黑名单数已达系统上限。";
|
||||
"TUIKitErrorSVRFriendshipPeerFriendLimit" = "对方的好友数已达系统上限。";
|
||||
"TUIKitErrorSVRFriendshipAlreadyFriends" = "已经存在好友关系。";
|
||||
"TUIKitErrorSVRFriendshipInSelfBlacklist" = "对方在自己的黑名单中,不允许加好友。";
|
||||
"TUIKitErrorSVRFriendshipAllowTypeDenyAny" = "对方的加好友验证方式是不允许任何人添加自己为好友。";
|
||||
"TUIKitErrorSVRFriendshipInPeerBlackList" = "自己在对方的黑名单中,不允许加好友。";
|
||||
"TUIKitErrorSVRFriendshipAllowTypeNeedConfirm" = "请求已发送,等待对方同意";
|
||||
"TUIKitErrorSVRFriendshipAddFriendSecRstr" = "添加好友请求被安全策略打击,请勿频繁发起添加好友请求。";
|
||||
"TUIKitErrorSVRFriendshipPendencyNotFound" = "请求的未决不存在。";
|
||||
"TUIKitErrorSVRFriendshipDelFriendSecRstr" = "删除好友请求被安全策略打击,请勿频繁发起删除好友请求。";
|
||||
"TUIKirErrorSVRFriendAccountNotFoundEx" = "请求的用户账号不存在。";
|
||||
"TUIKitErrorSVRMsgPkgParseFailed" = "解析请求包失败。";
|
||||
"TUIKitErrorSVRMsgInternalAuthFailed" = "内部鉴权失败。";
|
||||
"TUIKitErrorSVRMsgInvalidId" = "Identifier 无效";
|
||||
"TUIKitErrorSVRMsgNetError" = "网络异常,请重试。";
|
||||
"TUIKitErrorSVRMsgPushDeny" = "触发发送单聊消息之前回调,App 后台返回禁止下发该消息。";
|
||||
"TUIKitErrorSVRMsgInPeerBlackList" = "发送单聊消息,被对方拉黑,禁止发送。";
|
||||
"TUIKitErrorSVRMsgBothNotFriend" = "消息发送双方互相不是好友,禁止发送。";
|
||||
"TUIKitErrorSVRMsgNotPeerFriend" = "发送单聊消息,自己不是对方的好友(单向关系),禁止发送。";
|
||||
"TUIkitErrorSVRMsgNotSelfFriend" = "发送单聊消息,对方不是自己的好友(单向关系),禁止发送。";
|
||||
"TUIKitErrorSVRMsgShutupDeny" = "因禁言,禁止发送消息。";
|
||||
"TUIKitErrorSVRMsgRevokeTimeLimit" = "消息撤回超过了时间限制(默认2分钟)。";
|
||||
"TUIKitErrorSVRMsgDelRambleInternalError" = "删除漫游内部错误。";
|
||||
"TUIKitErrorSVRMsgJsonParseFailed" = "JSON 格式解析失败,请检查请求包是否符合 JSON 规范。";
|
||||
"TUIKitErrorSVRMsgInvalidJsonBodyFormat" = "JSON 格式请求包中 MsgBody 不符合消息格式描述";
|
||||
"TUIKitErrorSVRMsgInvalidToAccount" = "JSON 格式请求包体中缺少 To_Account 字段或者 To_Account 字段不是 Integer 类型";
|
||||
"TUIKitErrorSVRMsgInvalidRand" = "JSON 格式请求包体中缺少 MsgRandom 字段或者 MsgRandom 字段不是 Integer 类型";
|
||||
"TUIKitErrorSVRMsgInvalidTimestamp" = "JSON 格式请求包体中缺少 MsgTimeStamp 字段或者 MsgTimeStamp 字段不是 Integer 类型";
|
||||
"TUIKitErrorSVRMsgBodyNotArray" = "JSON 格式请求包体中 MsgBody 类型不是 Array 类型";
|
||||
"TUIKitErrorSVRMsgInvalidJsonFormat" = "JSON 格式请求包不符合消息格式描述";
|
||||
"TUIKitErrorSVRMsgToAccountCountLimit" = "批量发消息目标账号超过500";
|
||||
"TUIKitErrorSVRMsgToAccountNotFound" = "To_Account 没有注册或不存在";
|
||||
"TUIKitErrorSVRMsgTimeLimit" = "消息离线存储时间错误(最多不能超过7天)。";
|
||||
"TUIKitErrorSVRMsgInvalidSyncOtherMachine" = "JSON 格式请求包体中 SyncOtherMachine 字段不是 Integer 类型";
|
||||
"TUIkitErrorSVRMsgInvalidMsgLifeTime" = "JSON 格式请求包体中 MsgLifeTime 字段不是 Integer 类型";
|
||||
"TUIKitErrorSVRMsgBodySizeLimit" = "JSON 数据包超长,消息包体请不要超过12k。";
|
||||
"TUIKitErrorSVRmsgLongPollingCountLimit" = "Web 端长轮询被踢(Web 端同时在线实例个数超出限制)。";
|
||||
"TUIKitErrorSVRGroupApiNameError" = "请求中的接口名称错误";
|
||||
"TUIKitErrorSVRGroupAccountCountLimit" = "请求包体中携带的账号数量过多。";
|
||||
"TUIkitErrorSVRGroupFreqLimit" = "操作频率限制,请尝试降低调用的频率。";
|
||||
"TUIKitErrorSVRGroupPermissionDeny" = "操作权限不足";
|
||||
"TUIKitErrorSVRGroupInvalidReq" = "请求非法";
|
||||
"TUIKitErrorSVRGroupSuperNotAllowQuit" = "该群不允许群主主动退出。";
|
||||
"TUIKitErrorSVRGroupNotFound" = "群组不存在";
|
||||
"TUIKitErrorSVRGroupJsonParseFailed" = "解析 JSON 包体失败,请检查包体的格式是否符合 JSON 格式。";
|
||||
"TUIKitErrorSVRGroupInvalidId" = "发起操作的 Identifier 非法,请检查发起操作的用户 Identifier 是否填写正确。";
|
||||
"TUIKitErrorSVRGroupAllreadyMember" = "已经是群成员。";
|
||||
"TUIKitErrorSVRGroupFullMemberCount" = "群已满员,无法将请求中的用户加入群组";
|
||||
"TUIKitErrorSVRGroupInvalidGroupId" = "群组 ID 非法,请检查群组 ID 是否填写正确。";
|
||||
"TUIKitErrorSVRGroupRejectFromThirdParty" = "App 后台通过第三方回调拒绝本次操作。";
|
||||
"TUIKitErrorSVRGroupShutDeny" = "因被禁言而不能发送消息,请检查发送者是否被设置禁言。";
|
||||
"TUIKitErrorSVRGroupRspSizeLimit" = "应答包长度超过最大包长";
|
||||
"TUIKitErrorSVRGroupAccountNotFound" = "请求的用户账号不存在。";
|
||||
"TUIKitErrorSVRGroupGroupIdInUse" = "群组 ID 已被使用,请选择其他的群组 ID。";
|
||||
"TUIKitErrorSVRGroupSendMsgFreqLimit" = "发消息的频率超限,请延长两次发消息时间的间隔。";
|
||||
"TUIKitErrorSVRGroupReqAllreadyBeenProcessed" = "此邀请或者申请请求已经被处理。";
|
||||
"TUIKitErrorSVRGroupGroupIdUserdForSuper" = "群组 ID 已被使用,并且操作者为群主,可以直接使用。";
|
||||
"TUIKitErrorSVRGroupSDkAppidDeny" = "该 SDKAppID 请求的命令字已被禁用";
|
||||
"TUIKitErrorSVRGroupRevokeMsgNotFound" = "请求撤回的消息不存在。";
|
||||
"TUIKitErrorSVRGroupRevokeMsgTimeLimit" = "消息撤回超过了时间限制(默认2分钟)。";
|
||||
"TUIKitErrorSVRGroupRevokeMsgDeny" = "请求撤回的消息不支持撤回操作。";
|
||||
"TUIKitErrorSVRGroupNotAllowRevokeMsg" = "群组类型不支持消息撤回操作。";
|
||||
"TUIKitErrorSVRGroupRemoveMsgDeny" = "该消息类型不支持删除操作。";
|
||||
"TUIKitErrorSVRGroupNotAllowRemoveMsg" = "音视频聊天室和在线成员广播大群不支持删除消息。";
|
||||
"TUIKitErrorSVRGroupAvchatRoomCountLimit" = "音视频聊天室创建数量超过了限制";
|
||||
"TUIKitErrorSVRGroupCountLimit" = "单个用户可创建和加入的群组数量超过了限制”。";
|
||||
"TUIKitErrorSVRGroupMemberCountLimit" = "群成员数量超过限制";
|
||||
"TUIKitErrorSVRNoSuccessResult" = "批量操作无成功结果";
|
||||
"TUIKitErrorSVRToUserInvalid" = "IM: 无效接收方";
|
||||
"TUIKitErrorSVRRequestTimeout" = "请求超时";
|
||||
"TUIKitErrorSVRInitCoreFail" = "INIT CORE模块失败";
|
||||
"TUIKitErrorSVRConvGroupNameLengthLimit" = "会话分组名长度超过最大限制";
|
||||
"TUIKitErrorExpiredSessionNode" = "SessionNode为null";
|
||||
"TUIKitErrorLoggedOutBeforeLoginFinished" = "在登录完成前进行了登出(在登录时返回)";
|
||||
"TUIKitErrorTLSSDKNotInitialized" = "tlssdk未初始化";
|
||||
"TUIKitErrorTLSSDKUserNotFound" = "TLSSDK没有找到相应的用户信息";
|
||||
"TUIKitErrorBindFaildRegTimeout" = "注册超时";
|
||||
"TUIKitErrorBindFaildIsBinding" = "正在bind操作中";
|
||||
"TUIKitErrorPacketFailUnknown" = "发包未知错误";
|
||||
"TUIKitErrorPacketFailReqNoNet" = "发送请求包时没有网络,处理时转换成case ERR_REQ_NO_NET_ON_REQ:";
|
||||
"TUIKitErrorPacketFailRespNoNet" = "发送回复包时没有网络,处理时转换成case ERR_REQ_NO_NET_ON_RSP:";
|
||||
"TUIKitErrorPacketFailReqNoAuth" = "发送请求包时没有权限";
|
||||
"TUIKitErrorPacketFailSSOErr" = "SSO错误";
|
||||
"TUIKitErrorPacketFailRespTimeout" = "回复超时";
|
||||
"TUIKitErrorFriendshipProxySyncing" = "proxy_manager没有完成svr数据同步";
|
||||
"TUIKitErrorFriendshipProxySyncedFail" = "proxy_manager同步失败";
|
||||
"TUIKitErrorFriendshipProxyLocalCheckErr" = "proxy_manager请求参数,在本地检查不合法";
|
||||
"TUIKitErrorGroupInvalidField" = "group assistant请求字段中包含非预设字段";
|
||||
"TUIKitErrorGroupStoreageDisabled" = "group assistant群资料本地存储没有开启";
|
||||
"TUIKitErrorLoadGrpInfoFailed" = "无法从存储中加载groupinfo";
|
||||
"TUIKitErrorReqNoNetOnReq" = "请求的时候没有网络";
|
||||
"TUIKitErrorReqNoNetOnResp" = "响应的时候没有网络";
|
||||
"TUIKitErrorServiceNotReady" = "QALSDK服务未就绪";
|
||||
"TUIKitErrorLoginAuthFailed" = "账号认证失败(用户信息获取失败)";
|
||||
"TUIKitErrorNeverConnectAfterLaunch" = "在应用启动后没有尝试联网";
|
||||
"TUIKitErrorReqFailed" = "QAL执行失败";
|
||||
"TUIKitErrorReqInvaidReq" = "请求非法,toMsgService非法";
|
||||
"TUIKitErrorReqOnverLoaded" = "请求队列满";
|
||||
"TUIKitErrorReqKickOff" = "已经被其他终端踢了";
|
||||
"TUIKitErrorReqServiceSuspend" = "服务被暂停";
|
||||
"TUIKitErrorReqInvalidSign" = "SSO签名错误";
|
||||
"TUIKitErrorReqInvalidCookie" = "SSO cookie无效";
|
||||
"TUIKitErrorLoginTlsRspParseFailed" = "登录时TLS回包校验,包体长度错误";
|
||||
"TUIKitErrorLoginOpenMsgTimeout" = "登录时OPENSTATSVC向OPENMSG上报状态超时";
|
||||
"TUIKitErrorLoginOpenMsgRspParseFailed" = "登录时OPENSTATSVC向OPENMSG上报状态时解析回包失败";
|
||||
"TUIKitErrorLoginTslDecryptFailed" = "登录时TLS解密失败";
|
||||
"TUIKitErrorWifiNeedAuth" = "wifi需要认证";
|
||||
"TUIKitErrorUserCanceled" = "用户已取消";
|
||||
"TUIkitErrorRevokeTimeLimitExceed" = "消息撤回超过了时间限制(默认2分钟)";
|
||||
"TUIKitErrorLackUGExt" = "缺少Multimedia扩展包";
|
||||
"TUIKitErrorAutoLoginNeedUserSig" = "自动登录,本地票据过期,需要userSig手动登录";
|
||||
"TUIKitErrorQALNoShortConneAvailable" = "没有可用的短连接sso";
|
||||
"TUIKitErrorReqContentAttach" = "消息内容安全打击";
|
||||
"TUIKitErrorLoginSigExpire" = "登录返回,票据过期";
|
||||
"TUIKitErrorSDKHadInit" = "SDK 已经初始化无需重复初始化";
|
||||
"TUIKitErrorOpenBDHBase" = "openbdh 错误码";
|
||||
"TUIKitErrorRequestNoNetOnReq" = "请求时没有网络,请等网络恢复后重试";
|
||||
"TUIKitErrorRequestNoNetOnRsp" = "响应时没有网络,请等网络恢复后重试";
|
||||
"TUIKitErrorRequestOnverLoaded" = "请求队列満";
|
||||
"TUIKitErrorUnsupporInterface" = "该功能仅限旗舰版使用,请升级至旗舰版。";
|
||||
"TUIKitErrorUnsupporInterfaceSuffix" = "功能仅限旗舰版使用,请升级至旗舰版。";
|
||||
"TUIKitErrorUnsupportIntefaceSearch" = "搜索";
|
||||
"TUIKitErrorUnsupportIntefaceMessageRead" = "消息已读回执";
|
||||
"TUIKitErrorUnsupportIntefaceCommunity" = "社群";
|
||||
"TUIKitErrorUnsupportIntefaceDesc" = "功能为 IM 旗舰版功能,购买旗舰版套餐包后可使用,详见价格说明。";
|
||||
"TUIKitErrorValueAddedUnsupportIntefaceContactDesc" = "是增值付费功能,当前处于内测阶段,请点击进入[腾讯云即时通信 IM 群]申请开通试用";
|
||||
"TUIKitErrorValueAddedUnsupportIntefacePurchaseDesc" = "是增值付费功能,请在腾讯云控制台[插件市场]领取试用或者购买开通使用";
|
||||
"TUIKitErrorValueAddedUnsupportIntefaceContactDescHighlight" = "[腾讯云即时通信 IM 群]";
|
||||
"TUIKitErrorValueAddedUnsupportIntefacePurchaseDescHighlight" = "[插件市场]";
|
||||
"TUIKitErrorUnsupportIntefaceCommunityDesc" = "\n备注: 社群可容纳百万成员,可划分分组、话题,适用于兴趣交友、游戏社交、粉丝运营、组织管理等场景。";
|
||||
"TUIKitErrorUnsupportIntefaceGuidelines" = "价格说明";
|
||||
"TUIKitErrorUnsupportIntefaceTitle" = "提示";
|
||||
"TUIKitErrorUnsupportIntefaceIGotIt" = "我知道了";
|
||||
"TUIKitErrorUnsupportIntefaceNoMoreAlert" = "不再提醒";
|
||||
|
||||
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
Localizable.strings
|
||||
Chinese Simplized
|
||||
|
||||
Created by harvy on 2024/10/9.
|
||||
|
||||
*/
|
||||
|
||||
/***************************** 日期格式化 Start *************************/
|
||||
"YesterdayDateFormat" = "aHH:mm";
|
||||
/***************************** 日期格式化 End *************************/
|
||||
|
||||
"TUIKitMoreVideoCall" = "視頻通話";
|
||||
"TUIKitMoreVoiceCall" = "語音通話";
|
||||
"Make-a-call" = "發起呼叫";
|
||||
"TUIKitNoSelfSignature" = "暫無個性簽名";
|
||||
"TUIKitSelfSignatureFormat" = "個性簽名:%@";
|
||||
"TUIKitAllowTypeAcceptOne" = "同意任何用戶加好友";
|
||||
"TUIKitAllowTypeNeedConfirm" = "需要驗證";
|
||||
"TUIKitAllowTypeDeclineAll" = "拒絕任何人加好友";
|
||||
"Male" = "男";
|
||||
"Female" = "女";
|
||||
"Unsetted" = "未設置";
|
||||
"TUIKitErrorInProcess" = "執行中";
|
||||
"TUIKitErrorInvalidParameters" = "參數無效";
|
||||
"TUIKitErrorIOOperateFaild" = "操作本地 IO 錯誤";
|
||||
"TUIKitErrorInvalidJson" = "錯誤的 JSON 格式";
|
||||
"TUIKitErrorOutOfMemory" = "內存不足";
|
||||
"TUIKitErrorParseResponseFaild" = "PB 解析失敗";
|
||||
"TUIKitErrorSerializeReqFaild" = "PB 序列化失敗";
|
||||
"TUIKitErrorSDKNotInit" = "IM SDK 未初始化";
|
||||
"TUIKitErrorLoadMsgFailed" = "加載本地數據庫操作失敗";
|
||||
"TUIKitErrorDatabaseOperateFailed" = "本地數據庫操作失敗";
|
||||
"TUIKitErrorCrossThread" = "跨線程錯誤";
|
||||
"TUIKitErrorTinyIdEmpty" = "用戶信息為空";
|
||||
"TUIKitErrorInvalidIdentifier" = "Identifier 非法";
|
||||
"TUIKitErrorFileNotFound" = "文件不存在";
|
||||
"TUIKitErrorFileTooLarge" = "文件大小超出了限制";
|
||||
"TUIKitErrorEmptyFile" = "空文件";
|
||||
"TUIKitErrorFileOpenFailed" = "文件打開失敗";
|
||||
"TUIKitErrorNotLogin" = "IM SDK 未登錄";
|
||||
"TUIKitErrorNoPreviousLogin" = "並沒有登錄過該用戶";
|
||||
"TUIKitErrorUserSigExpired" = "UserSig 過期";
|
||||
"TUIKitErrorLoginKickedOffByOther" = "其他終端登錄同一賬號";
|
||||
"TUIKitErrorTLSSDKInit" = "TLS SDK 初始化失敗";
|
||||
"TUIKitErrorTLSSDKUninit" = "TLS SDK 未初始化";
|
||||
"TUIKitErrorTLSSDKTRANSPackageFormat" = "TLS SDK TRANS 包格式錯誤";
|
||||
"TUIKitErrorTLSDecrypt" = "TLS SDK 解密失敗";
|
||||
"TUIKitErrorTLSSDKRequest" = "TLS SDK 請求失敗";
|
||||
"TUIKitErrorTLSSDKRequestTimeout" = "TLS SDK 請求超時";
|
||||
"TUIKitErrorInvalidConveration" = "會話無效";
|
||||
"TUIKitErrorFileTransAuthFailed" = "文件傳輸鑑權失敗";
|
||||
"TUIKitErrorFileTransNoServer" = "文件傳輸獲取 Server 列表失敗";
|
||||
"TUIKitErrorFileTransUploadFailed" = "文件傳輸上傳失敗,請檢查網絡是否連接";
|
||||
"TUIKitErrorFileTransUploadFailedNotImage" = "文件傳輸上傳失敗,請檢查上傳的圖片是否能夠正常打開";
|
||||
"TUIKitErrorFileTransDownloadFailed" = "文件傳輸下載失敗,請檢查網絡,或者文件、語音是否已經過期";
|
||||
"TUIKitErrorHTTPRequestFailed" = "HTTP 請求失敗";
|
||||
"TUIKitErrorInvalidMsgElem" = "IM SDK 無效消息 elem";
|
||||
"TUIKitErrorInvalidSDKObject" = "無效的對象";
|
||||
"TUIKitSDKMsgBodySizeLimit" = "消息長度超出限制";
|
||||
"TUIKitErrorSDKMsgKeyReqDifferRsp" = "消息 KEY 錯誤";
|
||||
"TUIKitErrorSDKGroupInvalidID" = "群組 ID 非法,自定義群組 ID 必須為可打印 ASCII 字符(0x20-0x7e),最長48個字節,且前綴不能為 @TGS#";
|
||||
"TUIKitErrorSDKGroupInvalidName" = "群名稱非法,群名稱最長30字節";
|
||||
"TUIKitErrorSDKGroupInvalidIntroduction" = "群簡介非法,群簡介最長240字節";
|
||||
"TUIKitErrorSDKGroupInvalidNotification" = "群公告非法,群公告最長300字節";
|
||||
"TUIKitErrorSDKGroupInvalidFaceURL" = "群頭像 URL 非法,群頭像 URL 最長100字節";
|
||||
"TUIKitErrorSDKGroupInvalidNameCard" = "群名片非法,群名片最長50字節";
|
||||
"TUIKitErrorSDKGroupMemberCountLimit" = "超過群組成員數的限制";
|
||||
"TUIKitErrorSDKGroupJoinPrivateGroupDeny" = "不允許申請加入 Private 群組";
|
||||
"TUIKitErrorSDKGroupInviteSuperDeny" = "不允許邀請角色為群主的成員";
|
||||
"TUIKitErrorSDKGroupInviteNoMember" = "不允許邀請0個成員";
|
||||
"TUIKitErrorSDKFriendShipInvalidProfileKey" = "資料字段非法";
|
||||
"TUIKitErrorSDKFriendshipInvalidAddRemark" = "備註字段非法,最大96字節";
|
||||
"TUIKitErrorSDKFriendshipInvalidAddWording" = "請求添加好友的請求說明字段非法,最大120字節";
|
||||
"TUIKitErrorSDKFriendshipInvalidAddSource" = "請求添加好友的添加來源字段非法,來源需要添加“AddSource_Type_”前綴。";
|
||||
"TUIKitErrorSDKFriendshipFriendGroupEmpty" = "好友分組字段非法,必須不為空,每個分組的名稱最長30字節";
|
||||
"TUIKitErrorSDKNetEncodeFailed" = "網絡鏈接加密失敗";
|
||||
"TUIKitErrorSDKNetDecodeFailed" = "網絡鏈接解密失敗";
|
||||
"TUIKitErrorSDKNetAuthInvalid" = "網絡鏈接未完成鑑權";
|
||||
"TUIKitErrorSDKNetCompressFailed" = "數據包壓縮失敗";
|
||||
"TUIKitErrorSDKNetUncompressFaile" = "數據包解壓失敗";
|
||||
"TUIKitErrorSDKNetFreqLimit" = "調用頻率限制,最大每秒發起 5 次請求";
|
||||
"TUIKitErrorSDKnetReqCountLimit" = "請求隊列滿,超過同時請求的數量限制,最大同時發起1000個請求。";
|
||||
"TUIKitErrorSDKNetDisconnect" = "網絡已斷開,未建立連接,或者建立 socket 連接時,檢測到無網絡。";
|
||||
"TUIKitErrorSDKNetAllreadyConn" = "網絡連接已建立,重複創建連接";
|
||||
"TUIKitErrorSDKNetConnTimeout" = "建立網絡連接超時,請等網絡恢復後重試。";
|
||||
"TUIKitErrorSDKNetConnRefuse" = "網絡連接已被拒絕,請求過於頻繁,服務端拒絕服務。";
|
||||
"TUIKitErrorSDKNetNetUnreach" = "沒有到達網絡的可用路由,請等網絡恢復後重試。";
|
||||
"TUIKitErrorSDKNetSocketNoBuff" = "系統中沒有足夠的緩衝區空間資源可用來完成調用,系統過於繁忙,內部錯誤。";
|
||||
"TUIKitERRORSDKNetResetByPeer" = "對端重置了連接";
|
||||
"TUIKitErrorSDKNetSOcketInvalid" = "socket 套接字無效";
|
||||
"TUIKitErrorSDKNetHostGetAddressFailed" = "IP 地址解析失敗";
|
||||
"TUIKitErrorSDKNetConnectReset" = "網絡連接到中間節點或服務端重置";
|
||||
"TUIKitErrorSDKNetWaitInQueueTimeout" = "請求包等待進入待發送隊列超時";
|
||||
"TUIKitErrorSDKNetWaitSendTimeout" = "請求包已進入待發送隊列,等待進入系統的網絡 buffer 超時";
|
||||
"TUIKitErrorSDKNetWaitAckTimeut" = "請求包已進入系統的網絡 buffer ,等待服務端回包超時";
|
||||
"TUIKitErrorSDKWaitSendRemainingTimeout" =
|
||||
"請求包已進入待發送隊列,部分數據已發送,等待發送剩餘部分出現超時,可能上行帶寬不足,請檢查網絡是否暢通,在回調錯誤時檢測有聯網,內部錯誤";
|
||||
"TUIKitErrorSDKNetPKGSizeLimit" = "請求包長度大於限制,最大支持 1MB 。";
|
||||
"TUIKitErrorSDKNetWaitSendTimeoutNoNetwork" = "請求包已進入待發送隊列,等待進入系統的網絡 buffer 超時,數據包較多 或 發送線程處理不過來,在回調錯誤碼時檢測到沒有聯網。";
|
||||
"TUIKitErrorSDKNetWaitAckTimeoutNoNetwork" = "請求包已進入系統的網絡 buffer ,等待服務端回包超時,可能請求包沒離開終端設備、中間路由丟棄、服務端意外丟包或回包被系統網絡層丟棄,在回調錯誤碼時檢測到沒有聯網。";
|
||||
"TUIKitErrorSDKNetRemainingTimeoutNoNetwork" = "請求包已進入待發送隊列,部分數據已發送,等待發送剩餘部分出現超時,可能上行帶寬不足,請檢查網絡是否暢通,在回調錯誤碼時檢測到沒有聯網。";
|
||||
"TUIKitErrorSDKSVRSSOConnectLimit" = "Server 的連接數量超出限制,服務端拒絕服務。";
|
||||
"TUIKitErrorSDKSVRSSOVCode" = "驗證碼下發超時。";
|
||||
"TUIKitErrorSVRSSOD2Expired" = "Key 過期。Key 是根據 UserSig 生成的內部票據,Key 的有效期小於或等於 UserSig 的有效期。請重新調用 TIMManager.getInstance().login 登錄接口生成新的 Key。";
|
||||
"TUIKitErrorSVRA2UpInvalid" = "Ticket 過期。Ticket 是根據 UserSig 生成的內部票據,Ticket 的有效期小於或等於 UserSig 的有效期。請重新調用 TIMManager.getInstance().login 登錄接口生成新的 Ticket。";
|
||||
"TUIKitErrorSVRA2DownInvalid" = "票據驗證沒通過或者被安全打擊。請重新調用 TIMManager.getInstance().login 登錄接口生成新的票據。";
|
||||
"TUIKitErrorSVRSSOEmpeyKey" = "不允許空 Key。";
|
||||
"TUIKitErrorSVRSSOUinInvalid" = "Key 中的帳號和請求包頭的帳號不匹配。";
|
||||
"TUIKitErrorSVRSSOVCodeTimeout" = "驗證碼下發超時。";
|
||||
"TUIKitErrorSVRSSONoImeiAndA2" = "需要帶上 Key 和 Ticket。";
|
||||
"TUIKitErrorSVRSSOCookieInvalid" = "Cookie 檢查不匹配。";
|
||||
"TUIKitErrorSVRSSODownTips" = "下发提示語,Key 過期。";
|
||||
"TUIKitErrorSVRSSODisconnect" = "斷鏈鎖屏。";
|
||||
"TUIKitErrorSVRSSOIdentifierInvalid" = "失效身份。";
|
||||
"TUIKitErrorSVRSSOClientClose" = "終端自動退出。";
|
||||
"TUIKitErrorSVRSSOMSFSDKQuit" = "MSFSDK 自動退出。";
|
||||
"TUIKitErrorSVRSSOD2KeyWrong" = "解密失敗次數超過閾值,通知終端需要重置,請重新調用 TIMManager.getInstance().login 登錄接口生成新的 Key。";
|
||||
"TUIKitErrorSVRSSOUnsupport" = "不支持聚合,給終端返回統一的錯誤碼。終端在該 TCP 長連接上停止聚合。";
|
||||
"TUIKitErrorSVRSSOPrepaidArrears" = "預付費欠費。";
|
||||
"TUIKitErrorSVRSSOPacketWrong" = "請求包格式錯誤。";
|
||||
"TUIKitErrorSVRSSOAppidBlackList" = "SDKAppID 黑名單。";
|
||||
"TUIKitErrorSVRSSOCmdBlackList" = "SDKAppID 設置 service cmd 黑名單。";
|
||||
"TUIKitErrorSVRSSOAppidWithoutUsing" = "SDKAppID 停用。";
|
||||
"TUIKitErrorSVRSSOFreqLimit" = "頻率限制(用戶),頻率限制是設置針對某一个协议的每秒請求數的限制。";
|
||||
"TUIKitErrorSVRSSOOverload" = "過載丟包(系統),連接的服務端處理過多請求,處理不過來,拒絕服務。";
|
||||
"TUIKitErrorSVRResNotFound" = "要發送的資源文件不存在。";
|
||||
"TUIKitErrorSVRResAccessDeny" = "要發送的資源文件不允許訪問。";
|
||||
"TUIKitErrorSVRResSizeLimit" = "文件大小超过限制。";
|
||||
"TUIKitErrorSVRResSendCancel" = "用户取消发送,如发送过程中登出等原因。";
|
||||
"TUIKitErrorSVRResReadFailed" = "读取文件内容失败。";
|
||||
"TUIKitErrorSVRResTransferTimeout" = "资源文件传输超时";
|
||||
"TUIKitErrorSVRResInvalidParameters" = "参数非法。";
|
||||
"TUIKitErrorSVRResInvalidFileMd5" = "文件 MD5 校驗失敗。";
|
||||
"TUIKitErrorSVRResInvalidPartMd5" = "分片 MD5 校驗失敗。";
|
||||
"TUIKitErrorSVRCommonInvalidHttpUrl" = "HTTP 解析错误 ,請檢查 HTTP 請求 URL 格式。";
|
||||
"TUIKitErrorSVRCommomReqJsonParseFailed" = "HTTP 請求 JSON 解析错误,請檢查 JSON 格式。";
|
||||
"TUIKitErrorSVRCommonInvalidAccount" = "請求 URI 或 JSON 包體中 Identifier 或 UserSig 錯誤。";
|
||||
"TUIKitErrorSVRCommonInvalidSdkappid" = "SDKAppID 失效,請核對 SDKAppID 有效性。";
|
||||
"TUIKitErrorSVRCommonRestFreqLimit" = "REST 接口调用頻率超過限制,請降低請求頻率。";
|
||||
"TUIKitErrorSVRCommonRequestTimeout" = "服务请求超时或 HTTP 請求格式錯誤,請檢查並重試。";
|
||||
"TUIKitErrorSVRCommonInvalidRes" = "請求资源錯誤,請檢查請求 URL。";
|
||||
"TUIKitErrorSVRCommonIDNotAdmin" = "REST API 請求的 Identifier 字段請填寫 App 管理員帳號。";
|
||||
"TUIKitErrorSVRCommonSdkappidFreqLimit" = "SDKAppID 請求頻率超限,請降低請求頻率。";
|
||||
"TUIKitErrorSVRCommonSdkappidMiss" = "REST 接口需要帶 SDKAppID,請檢查請求 URL 中的 SDKAppID。";
|
||||
"TUIKitErrorSVRCommonRspJsonParseFailed" = "HTTP 响應包 JSON 解析错误。";
|
||||
"TUIKitErrorSVRCommonExchangeAccountTimeout" = "置换账号超时。";
|
||||
"TUIKitErrorSVRCommonInvalidIdFormat" = "請求包體 Identifier 類型錯誤,請確認 Identifier 為字符串格式。";
|
||||
"TUIKitErrorSVRCommonSDkappidForbidden" = "SDKAppID 被禁用";
|
||||
"TUIKitErrorSVRCommonReqForbidden" = "請求被禁用";
|
||||
"TUIKitErrorSVRCommonReqFreqLimit" = "請求過于頻繁,請稍后重試。";
|
||||
"TUIKitErrorSVRCommonInvalidService" = "您的專業版套餐包已到期並停用,請登錄 即時通信 IM 購買頁面 重新購買套餐包。購買後,將在5分鐘后生效。";
|
||||
"TUIKitErrorSVRCommonSensitiveText" = "文本安全打擊,文本中可能包含敏感詞彙。";
|
||||
"TUIKitErrorSVRCommonBodySizeLimit" = "發消息包體過長,目前支持最大12k消息包體長度,請減少包體大小重試。";
|
||||
"TUIKitErrorSVRAccountUserSigExpired" = "UserSig 已过期,請重新生成 UserSig";
|
||||
"TUIKitErrorSVRAccountUserSigEmpty" = "UserSig 長度為0";
|
||||
"TUIKitErrorSVRAccountUserSigCheckFailed" = "UserSig 校驗失敗";
|
||||
"TUIKitErrorSVRAccountUserSigMismatchPublicKey" = "用公钥驗證 UserSig 失敗";
|
||||
"TUIKitErrorSVRAccountUserSigMismatchId" = "請求的 Identifier 與生成 UserSig 的 Identifier 不匹配。";
|
||||
"TUIKitErrorSVRAccountUserSigMismatchSdkAppid" = "請求的 SDKAppID 與生成 UserSig 的 SDKAppID 不匹配。";
|
||||
"TUIKitErrorSVRAccountUserSigPublicKeyNotFound" = "驗證 UserSig 時公钥不存在";
|
||||
"TUIKitErrorSVRAccountUserSigSdkAppidNotFount" = "SDKAppID 未找到,請在雲通信 IM 控制台確認應用信息。";
|
||||
"TUIKitErrorSVRAccountInvalidUserSig" = "UserSig 已經失效,請重新生成,再次嘗試。";
|
||||
"TUIKitErrorSVRAccountNotFound" = "請求的用戶帳號不存在。";
|
||||
"TUIKitErrorSVRAccountSecRstr" = "安全原因被限制。";
|
||||
"TUIKitErrorSVRAccountInternalTimeout" = "服务端内部超时,請重试。";
|
||||
"TUIKitErrorSVRAccountInvalidCount" = "請求中批量數量不合法。";
|
||||
"TUIkitErrorSVRAccountINvalidParameters" = "参数非法,請檢查必填字段是否填充,或者字段的填充是否滿足協議要求。";
|
||||
"TUIKitErrorSVRAccountAdminRequired" = "請求需要 App 管理員權限。";
|
||||
"TUIKitErrorSVRAccountLowSDKVersion" = "您的SDK版本过低,請升級到最新版本。";
|
||||
"TUIKitErrorSVRAccountFreqLimit" = "因失敗且重試次數過多導致被限制,請檢查 UserSig 是否正確,一分鐘之后再試。";
|
||||
"TUIKitErrorSVRAccountBlackList" = "帳號被拉入黑名單。";
|
||||
"TUIKitErrorSVRAccountCountLimit" = "創建帳號數量超過免費體驗版數量限制,請升級為專業版。";
|
||||
"TUIKitErrorSVRAccountInternalError" = "服务端内部錯誤,請重試。";
|
||||
"TUIKitErrorSVRProfileInvalidParameters" = "請求参数錯誤,請根據錯誤描述檢查請求是否正確。";
|
||||
"TUIKitErrorSVRProfileAccountMiss" = "請求参数錯誤,沒有指定需要拉取資料的用戶帳號。";
|
||||
"TUIKitErrorSVRProfileAccountNotFound" = "請求的用戶帳號不存在。";
|
||||
"TUIKitErrorSVRProfileAdminRequired" = "請求需要 App 管理員權限。";
|
||||
"TUIKitErrorSVRProfileSensitiveText" = "資料字段中包含敏感詞。";
|
||||
"TUIKitErrorSVRProfileInternalError" = "服务端内部錯誤,請稍后重試。";
|
||||
"TUIKitErrorSVRProfileReadWritePermissionRequired" = "沒有資料字段的讀权限,詳情可參見 資料字段。";
|
||||
"TUIKitErrorSVRProfileTagNotFound" = "資料字段的 Tag 不存在。";
|
||||
"TUIKitErrorSVRProfileSizeLimit" = "資料字段的 Value 長度超過500字節。";
|
||||
"TUIKitErrorSVRProfileValueError" = "標配資料字段的 Value 錯誤,詳情可參見 標配資料字段。";
|
||||
"TUIKitErrorSVRProfileInvalidValueFormat" = "資料字段的 Value 類型不匹配,詳情可參見 標配資料字段。";
|
||||
"TUIKitErrorSVRFriendshipInvalidParameters" = "請求参数錯誤,請根據錯誤描述檢查請求是否正確。";
|
||||
"TUIKitErrorSVRFriendshipInvalidSdkAppid" = "SDKAppID 不匹配。";
|
||||
"TUIKitErrorSVRFriendshipAccountNotFound" = "請求的用戶帳號不存在。";
|
||||
"TUIKitErrorSVRFriendshipAdminRequired" = "請求需要 App 管理員權限。";
|
||||
"TUIKitErrorSVRFriendshipSensitiveText" = "關係鏈字段中包含敏感詞。";
|
||||
"TUIKitErrorSVRFriendshipNetTimeout" = "網絡超時,請稍后重試。";
|
||||
"TUIKitErrorSVRFriendshipWriteConflict" = "並發寫導致寫衝突,建議使用批量方式。";
|
||||
"TUIKitErrorSVRFriendshipAddFriendDeny" = "后台禁止該用户發起加好友請求。";
|
||||
"TUIkitErrorSVRFriendshipCountLimit" = "您的好友數已達系統上限。";
|
||||
"TUIKitErrorSVRFriendshipGroupCountLimit" = "分組已達系統上限。";
|
||||
"TUIKitErrorSVRFriendshipPendencyLimit" = "未決數已達系統上限。";
|
||||
"TUIKitErrorSVRFriendshipBlacklistLimit" = "黑名單數已達系統上限。";
|
||||
"TUIKitErrorSVRFriendshipPeerFriendLimit" = "對方的好友數已達系統上限。";
|
||||
"TUIKitErrorSVRFriendshipAlreadyFriends" = "已經存在好友關係。";
|
||||
"TUIKitErrorSVRFriendshipInSelfBlacklist" = "對方在自己的黑名單中,不允許加好友。";
|
||||
"TUIKitErrorSVRFriendshipAllowTypeDenyAny" = "對方的加好友驗證方式是不允許任何人添加自己為好友。";
|
||||
"TUIKitErrorSVRFriendshipInPeerBlackList" = "自己在對方的黑名單中,不允許加好友。";
|
||||
"TUIKitErrorSVRFriendshipAllowTypeNeedConfirm" = "請求已發送,等待對方同意";
|
||||
"TUIKitErrorSVRFriendshipAddFriendSecRstr" = "添加好友請求被安全策略打擊,請勿頻繁發起添加好友請求。";
|
||||
"TUIKitErrorSVRFriendshipPendencyNotFound" = "請求的未決不存在。";
|
||||
"TUIKitErrorSVRFriendshipDelFriendSecRstr" = "删除好友請求被安全策略打擊,請勿頻繁發起删除好友請求。";
|
||||
"TUIKirErrorSVRFriendAccountNotFoundEx" = "請求的用戶帳號不存在。";
|
||||
"TUIKitErrorSVRMsgPkgParseFailed" = "解析請求包失敗。";
|
||||
"TUIKitErrorSVRMsgInternalAuthFailed" = "内部鉴权失敗。";
|
||||
"TUIKitErrorSVRMsgInvalidId" = "Identifier 無效";
|
||||
"TUIKitErrorSVRMsgNetError" = "網絡異常,請重試。";
|
||||
"TUIKitErrorSVRMsgPushDeny" = "觸發發送單聊消息之前回調,App 後台返回禁止下发該消息。";
|
||||
"TUIKitErrorSVRMsgInPeerBlackList" = "發送單聊消息,被對方拉黑,禁止發送。";
|
||||
"TUIKitErrorSVRMsgBothNotFriend" = "消息發送雙方互相不是好友,禁止發送。";
|
||||
"TUIKitErrorSVRMsgNotPeerFriend" = "發送單聊消息,自己不是對方的好友(單向關係),禁止發送。";
|
||||
"TUIkitErrorSVRMsgNotSelfFriend" = "發送單聊消息,對方不是自己的好友(單向關係),禁止發送。";
|
||||
"TUIKitErrorSVRMsgShutupDeny" = "因禁言,禁止發送消息。";
|
||||
"TUIKitErrorSVRMsgRevokeTimeLimit" = "消息撤回超过了時間限制(默認2分鐘)。";
|
||||
"TUIKitErrorSVRMsgDelRambleInternalError" = "删除漫游内部錯誤。";
|
||||
"TUIKitErrorSVRMsgJsonParseFailed" = "JSON 格式解析失敗,請檢查請求包是否符合 JSON 規範。";
|
||||
"TUIKitErrorSVRMsgInvalidJsonBodyFormat" = "JSON 格式請求包中 MsgBody 不符合消息格式描述";
|
||||
"TUIKitErrorSVRMsgInvalidToAccount" = "JSON 格式請求包體中缺少 To_Account 字段或者 To_Account 字段不是 Integer 類型";
|
||||
"TUIKitErrorSVRMsgInvalidRand" = "JSON 格式請求包體中缺少 MsgRandom 字段或者 MsgRandom 字段不是 Integer 類型";
|
||||
"TUIKitErrorSVRMsgInvalidTimestamp" = "JSON 格式請求包體中缺少 MsgTimeStamp 字段或者 MsgTimeStamp 字段不是 Integer 類型";
|
||||
"TUIKitErrorSVRMsgBodyNotArray" = "JSON 格式請求包體中 MsgBody 類型不是 Array 類型";
|
||||
"TUIKitErrorSVRMsgInvalidJsonFormat" = "JSON 格式請求包不符合消息格式描述";
|
||||
"TUIKitErrorSVRMsgToAccountCountLimit" = "批量發消息目標帳號超過500";
|
||||
"TUIKitErrorSVRMsgToAccountNotFound" = "To_Account 沒有註冊或不存在";
|
||||
"TUIKitErrorSVRMsgTimeLimit" = "消息離線存储時間错误(最多不能超过7天)。";
|
||||
"TUIKitErrorSVRMsgInvalidSyncOtherMachine" = "JSON 格式請求包體中 SyncOtherMachine 字段不是 Integer 類型";
|
||||
"TUIkitErrorSVRMsgInvalidMsgLifeTime" = "JSON 格式請求包體中 MsgLifeTime 字段不是 Integer 類型";
|
||||
"TUIKitErrorSVRMsgBodySizeLimit" = "JSON 數據包超長,消息包體請不要超過12k。";
|
||||
"TUIKitErrorSVRmsgLongPollingCountLimit" = "Web 端長輪詢被踢(Web 端同時在線實例個數超出限制)。";
|
||||
"TUIKitErrorSVRGroupApiNameError" = "請求中的接口名稱錯誤";
|
||||
"TUIKitErrorSVRGroupAccountCountLimit" = "請求包體中攜帶的帳號數量過多。";
|
||||
"TUIkitErrorSVRGroupFreqLimit" = "操作頻率限制,請嘗試降低調用的頻率。";
|
||||
"TUIKitErrorSVRGroupPermissionDeny" = "操作權限不足";
|
||||
"TUIKitErrorSVRGroupInvalidReq" = "請求非法";
|
||||
"TUIKitErrorSVRGroupSuperNotAllowQuit" = "該群不允許群主主動退出。";
|
||||
"TUIKitErrorSVRGroupNotFound" = "群組不存在";
|
||||
"TUIKitErrorSVRGroupJsonParseFailed" = "解析 JSON 包體失敗,請檢查包體的格式是否符合 JSON 格式。";
|
||||
"TUIKitErrorSVRGroupInvalidId" = "發起操作的 Identifier 非法,請檢查發起操作的用户 Identifier 是否填寫正確。";
|
||||
"TUIKitErrorSVRGroupAllreadyMember" = "已經是群成員。";
|
||||
"TUIKitErrorSVRGroupFullMemberCount" = "群已滿員,無法將請求中的用戶加入群組";
|
||||
"TUIKitErrorSVRGroupInvalidGroupId" = "群組 ID 非法,請檢查群組 ID 是否填寫正確。";
|
||||
"TUIKitErrorSVRGroupRejectFromThirdParty" = "App 後台通過第三方回調拒絕本次操作。";
|
||||
"TUIKitErrorSVRGroupShutDeny" = "因被禁言而不能發送消息,請檢查發送者是否被設置禁言。";
|
||||
"TUIKitErrorSVRGroupRspSizeLimit" = "應答包長度超過最大包長";
|
||||
"TUIKitErrorSVRGroupAccountNotFound" = "請求的用戶帳號不存在。";
|
||||
"TUIKitErrorSVRGroupGroupIdInUse" = "群組 ID 已被使用,請選擇其他的群組 ID。";
|
||||
"TUIKitErrorSVRGroupSendMsgFreqLimit" = "發消息的頻率超限,請延長兩次發消息時間的間隔。";
|
||||
"TUIKitErrorSVRGroupReqAllreadyBeenProcessed" = "此邀請或者申請請求已經被處理。";
|
||||
"TUIKitErrorSVRGroupGroupIdUserdForSuper" = "群組 ID 已被使用,並且操作者為群主,可以直接使用。";
|
||||
"TUIKitErrorSVRGroupSDkAppidDeny" = "該 SDKAppID 請求的命令字已被禁用";
|
||||
"TUIKitErrorSVRGroupRevokeMsgNotFound" = "請求撤回的消息不存在。";
|
||||
"TUIKitErrorSVRGroupRevokeMsgTimeLimit" = "消息撤回超过了時間限制(默認2分鐘)。";
|
||||
"TUIKitErrorSVRGroupRevokeMsgDeny" = "請求撤回的消息不支持撤回操作。";
|
||||
"TUIKitErrorSVRGroupRemoveMsgDeny" = "該消息類型不支持刪除操作。";
|
||||
"TUIKitErrorSVRGroupNotAllowRemoveMsg" = "音視頻聊天室和在線成員廣播大群不支持刪除消息。";
|
||||
"TUIKitErrorSVRGroupAvchatRoomCountLimit" = "音視頻聊天室創建數量超過了限制";
|
||||
"TUIKitErrorSVRGroupCountLimit" = "單個用戶可創建和加入的群組數量超過了限制”。";
|
||||
"TUIKitErrorSVRGroupMemberCountLimit" = "群成員數量超過限制";
|
||||
"TUIKitErrorSVRNoSuccessResult" = "批量操作無成功結果";
|
||||
"TUIKitErrorSVRToUserInvalid" = "IM: 無效接收方";
|
||||
"TUIKitErrorSVRRequestTimeout" = "請求超時";
|
||||
"TUIKitErrorSVRInitCoreFail" = "INIT CORE模塊失敗";
|
||||
"TUIKitErrorSVRConvGroupNameLengthLimit" = "會話分組名長度超過最大限制";
|
||||
"TUIKitErrorExpiredSessionNode" = "SessionNode為null";
|
||||
"TUIKitErrorLoggedOutBeforeLoginFinished" = "在登錄完成前進行了登出(在登錄時返回)";
|
||||
"TUIKitErrorTLSSDKNotInitialized" = "tlssdk未初始化";
|
||||
"TUIKitErrorTLSSDKUserNotFound" = "TLSSDK沒有找到相應的用戶信息";
|
||||
"TUIKitErrorBindFaildRegTimeout" = "註冊超時";
|
||||
"TUIKitErrorBindFaildIsBinding" = "正在bind操作中";
|
||||
"TUIKitErrorPacketFailUnknown" = "發包未知錯誤";
|
||||
"TUIKitErrorPacketFailReqNoNet" = "發送請求包時沒有網絡,處理時轉換成case ERR_REQ_NO_NET_ON_REQ:";
|
||||
"TUIKitErrorPacketFailRespNoNet" = "發送回復包時沒有網絡,處理時轉換成case ERR_REQ_NO_NET_ON_RSP:";
|
||||
"TUIKitErrorPacketFailReqNoAuth" = "發送請求包時沒有權限";
|
||||
"TUIKitErrorPacketFailSSOErr" = "SSO錯誤";
|
||||
"TUIKitErrorPacketFailRespTimeout" = "回復超時";
|
||||
"TUIKitErrorFriendshipProxySyncing" = "proxy_manager沒有完成svr數據同步";
|
||||
"TUIKitErrorFriendshipProxySyncedFail" = "proxy_manager同步失敗";
|
||||
"TUIKitErrorFriendshipProxyLocalCheckErr" = "proxy_manager請求參數,在本地檢查不合法";
|
||||
"TUIKitErrorGroupInvalidField" = "group assistant請求字段中包含非預設字段";
|
||||
"TUIKitErrorGroupStoreageDisabled" = "group assistant群資料本地存儲沒有開啟";
|
||||
"TUIKitErrorLoadGrpInfoFailed" = "無法從存儲中加載groupinfo";
|
||||
"TUIKitErrorReqNoNetOnReq" = "請求的時候沒有網絡";
|
||||
"TUIKitErrorReqNoNetOnResp" = "響應的時候沒有網絡";
|
||||
"TUIKitErrorServiceNotReady" = "QALSDK服務未就緒";
|
||||
"TUIKitErrorLoginAuthFailed" = "帳號認證失敗(用戶信息獲取失敗)";
|
||||
"TUIKitErrorNeverConnectAfterLaunch" = "在應用啟動後沒有嘗試聯網";
|
||||
"TUIKitErrorReqFailed" = "QAL執行失敗";
|
||||
"TUIKitErrorReqInvaidReq" = "請求非法,toMsgService非法";
|
||||
"TUIKitErrorReqOnverLoaded" = "請求隊列滿";
|
||||
"TUIKitErrorReqKickOff" = "已經被其他終端踢了";
|
||||
"TUIKitErrorReqServiceSuspend" = "服務被暫停";
|
||||
"TUIKitErrorReqInvalidSign" = "SSO簽名錯誤";
|
||||
"TUIKitErrorReqInvalidCookie" = "SSO cookie無效";
|
||||
"TUIKitErrorLoginTlsRspParseFailed" = "登錄時TLS回包校驗,包體長度錯誤";
|
||||
"TUIKitErrorLoginOpenMsgTimeout" = "登錄時OPENSTATSVC向OPENMSG上報狀態超時";
|
||||
"TUIKitErrorLoginOpenMsgRspParseFailed" = "登錄時OPENSTATSVC向OPENMSG上報狀態時解析回包失敗";
|
||||
"TUIKitErrorLoginTslDecryptFailed" = "登錄時TLS解密失敗";
|
||||
"TUIKitErrorWifiNeedAuth" = "wifi需要認證";
|
||||
"TUIKitErrorUserCanceled" = "用戶已取消";
|
||||
"TUIkitErrorRevokeTimeLimitExceed" = "消息撤回超過了時間限制(默認2分鐘)";
|
||||
"TUIKitErrorLackUGExt" = "缺少UGC擴展包";
|
||||
"TUIKitErrorAutoLoginNeedUserSig" = "自動登錄,本地票據過期,需要userSig手動登錄";
|
||||
"TUIKitErrorQALNoShortConneAvailable" = "沒有可用的短連接sso";
|
||||
"TUIKitErrorReqContentAttach" = "消息內容安全打擊";
|
||||
"TUIKitErrorLoginSigExpire" = "登錄返回,票據過期";
|
||||
"TUIKitErrorSDKHadInit" = "SDK 已經初始化無需重複初始化";
|
||||
"TUIKitErrorOpenBDHBase" = "openbdh 錯誤碼";
|
||||
"TUIKitErrorRequestNoNetOnReq" = "請求時沒有網絡,請等網絡恢復後重試";
|
||||
"TUIKitErrorRequestNoNetOnRsp" = "響應時沒有網絡,請等網絡恢復後重試";
|
||||
"TUIKitErrorRequestOnverLoaded" = "請求隊列滿";
|
||||
"TUIKitErrorUnsupporInterface" = "該功能僅限旗艦版使用,請升級至旗艦版。";
|
||||
"TUIKitErrorUnsupporInterfaceSuffix" = "功能僅限旗艦版使用,請升級至旗艦版。";
|
||||
"TUIKitErrorUnsupportIntefaceSearch" = "搜索";
|
||||
"TUIKitErrorUnsupportIntefaceMessageRead" = "消息已讀回執";
|
||||
"TUIKitErrorUnsupportIntefaceCommunity" = "社群";
|
||||
"TUIKitErrorUnsupportIntefaceDesc" = "功能為 IM 旗艦版功能,購買旗艦版套餐包後可使用,詳見價格說明。";
|
||||
"TUIKitErrorValueAddedUnsupportIntefaceContactDesc" = "是增值付費功能,當前處於內測階段,請點擊進入[騰訊雲即時通信 IM 群]申請開通試用";
|
||||
"TUIKitErrorValueAddedUnsupportIntefacePurchaseDesc" = "是增值付費功能,請在騰訊雲控制台[插件市場]領取試用或者購買開通使用";
|
||||
"TUIKitErrorValueAddedUnsupportIntefaceContactDescHighlight" = "[騰訊雲即時通信 IM 群]";
|
||||
"TUIKitErrorValueAddedUnsupportIntefacePurchaseDescHighlight" = "[插件市場]";
|
||||
"TUIKitErrorUnsupportIntefaceCommunityDesc" = "
|
||||
備註: 社群可容納百萬成員,可劃分分組、話題,適用於興趣交友、遊戲社交、粉絲運營、組織管理等場景。";
|
||||
"TUIKitErrorUnsupportIntefaceGuidelines" = "價格說明";
|
||||
"TUIKitErrorUnsupportIntefaceTitle" = "提示";
|
||||
"TUIKitErrorUnsupportIntefaceIGotIt" = "我知道了";
|
||||
"TUIKitErrorUnsupportIntefaceNoMoreAlert" = "不再提醒";
|
||||
|
||||
149
TUIKit/TUICore/TUICommonModel.h
Normal file
@@ -0,0 +1,149 @@
|
||||
//
|
||||
// TCommonCell.h
|
||||
// TXIMSDK_TUIKit_iOS
|
||||
//
|
||||
// Created by annidyfeng on 2019/5/6.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TUIDarkModel.h"
|
||||
|
||||
@import ImSDK_Plus;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TUIUserFullInfo
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
@interface V2TIMUserFullInfo (TUIUserFullInfo)
|
||||
- (NSString *)showName;
|
||||
- (NSString *)showGender;
|
||||
- (NSString *)showSignature;
|
||||
- (NSString *)showAllowType;
|
||||
@end
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TUIUserModel
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
@interface TUIUserModel : NSObject <NSCopying>
|
||||
@property(nonatomic, copy) NSString *userId;
|
||||
@property(nonatomic, copy) NSString *name;
|
||||
@property(nonatomic, copy) NSString *avatar;
|
||||
@end
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TUIScrollView
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@interface TUIScrollView : UIScrollView
|
||||
@property(strong, nonatomic) UIImageView *imageView;
|
||||
@end
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TUIGroupAvatar
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
@interface TUIGroupAvatar : NSObject
|
||||
|
||||
/**
|
||||
*
|
||||
* Obtain the latest group avatar in real time according to the group id. After the avatar is updated, it will be cached locally. This interface will request
|
||||
* the network This interface will not use the cache. If you need to read the cache, please use getCacheGroupAvatar:imageCallback or getCacheAvatarForGroup:
|
||||
* number:
|
||||
*/
|
||||
+ (void)fetchGroupAvatars:(NSString *)groupID placeholder:(UIImage *)placeholder callback:(void (^)(BOOL success, UIImage *image, NSString *groupID))callback;
|
||||
|
||||
/**
|
||||
* Create a group avatar based on the given url array
|
||||
*/
|
||||
+ (void)createGroupAvatar:(NSArray *)group finished:(void (^)(UIImage *groupAvatar))finished;
|
||||
|
||||
/**
|
||||
* Cache avatars based on group ID and number of group members
|
||||
*/
|
||||
+ (void)cacheGroupAvatar:(UIImage *)avatar number:(UInt32)memberNum groupID:(NSString *)groupID;
|
||||
|
||||
/**
|
||||
* Get the cached avatar asynchronously, this interface will request the interface to get the current number of group members, and return the avatar
|
||||
* corresponding to the local cache
|
||||
*/
|
||||
+ (void)getCacheGroupAvatar:(NSString *)groupID callback:(void (^)(UIImage *, NSString *groupID))imageCallBack;
|
||||
|
||||
/**
|
||||
* Get the cached avatar synchronously, this interface does not request the network
|
||||
*/
|
||||
+ (UIImage *)getCacheAvatarForGroup:(NSString *)groupId number:(UInt32)memberNum;
|
||||
|
||||
/**
|
||||
*
|
||||
* Clear the avatar cache of the specified group
|
||||
*/
|
||||
+ (void)asyncClearCacheAvatarForGroup:(NSString *)groupID;
|
||||
|
||||
@end
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TUIImageCache
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
@interface TUIImageCache : NSObject
|
||||
|
||||
+ (instancetype)sharedInstance;
|
||||
|
||||
- (void)addResourceToCache:(NSString *)path;
|
||||
- (UIImage *)getResourceFromCache:(NSString *)path;
|
||||
|
||||
- (void)addFaceToCache:(NSString *)path;
|
||||
- (UIImage *)getFaceFromCache:(NSString *)path;
|
||||
|
||||
@end
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TUINavigationController
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
@class TUINavigationController;
|
||||
@protocol TUINavigationControllerDelegate <NSObject>
|
||||
@optional
|
||||
- (void)navigationControllerDidClickLeftButton:(TUINavigationController *)controller;
|
||||
- (void)navigationControllerDidSideSlideReturn:(TUINavigationController *)controller fromViewController:(UIViewController *)fromViewController;
|
||||
@end
|
||||
|
||||
@interface TUINavigationController : UINavigationController <UINavigationControllerDelegate, UIGestureRecognizerDelegate>
|
||||
|
||||
@property(nonatomic, weak) UIViewController *currentShowVC;
|
||||
@property(nonatomic, weak) id<TUINavigationControllerDelegate> uiNaviDelegate;
|
||||
@property(nonatomic, strong) UIImage *navigationItemBackArrowImage;
|
||||
@property(nonatomic, strong) UIColor *navigationBackColor;
|
||||
@end
|
||||
|
||||
@interface UIAlertController (TUITheme)
|
||||
|
||||
- (void)tuitheme_addAction:(UIAlertAction *)action;
|
||||
|
||||
@end
|
||||
|
||||
typedef void (^TUIValueCallbck)(NSDictionary *param);
|
||||
typedef void (^TUINonValueCallbck)(void);
|
||||
|
||||
typedef NSString *TUIExtVauleType;
|
||||
|
||||
@interface NSObject (TUIExtValue)
|
||||
|
||||
@property(nonatomic, copy) TUIValueCallbck tui_valueCallback;
|
||||
|
||||
@property(nonatomic, copy) TUINonValueCallbck tui_nonValueCallback;
|
||||
|
||||
@property(nonatomic, strong) id tui_extValueObj;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
807
TUIKit/TUICore/TUICommonModel.m
Normal file
@@ -0,0 +1,807 @@
|
||||
//
|
||||
// TCommonCell.m
|
||||
// TXIMSDK_TUIKit_iOS
|
||||
//
|
||||
// Created by annidyfeng on 2019/5/6.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUICommonModel.h"
|
||||
#import <objc/runtime.h>
|
||||
#import "NSString+TUIUtil.h"
|
||||
#import "TUIDarkModel.h"
|
||||
#import "TUIGlobalization.h"
|
||||
#import "TUIThemeManager.h"
|
||||
#import "TUITool.h"
|
||||
#import "UIView+TUILayout.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TUIUserFullInfo
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
@implementation V2TIMUserFullInfo (TUIUserFullInfo)
|
||||
|
||||
- (NSString *)showName {
|
||||
if ([NSString isEmpty:self.nickName]) return self.userID;
|
||||
return self.nickName;
|
||||
}
|
||||
|
||||
- (NSString *)showGender {
|
||||
if (self.gender == V2TIM_GENDER_MALE) return TUIKitLocalizableString(Male);
|
||||
if (self.gender == V2TIM_GENDER_FEMALE) return TUIKitLocalizableString(Female);
|
||||
return TUIKitLocalizableString(Unsetted);
|
||||
}
|
||||
|
||||
- (NSString *)showSignature {
|
||||
if (self.selfSignature == nil) return TUIKitLocalizableString(TUIKitNoSelfSignature);
|
||||
return [NSString stringWithFormat:TUIKitLocalizableString(TUIKitSelfSignatureFormat), self.selfSignature];
|
||||
}
|
||||
|
||||
- (NSString *)showAllowType {
|
||||
if (self.allowType == V2TIM_FRIEND_ALLOW_ANY) {
|
||||
return TUIKitLocalizableString(TUIKitAllowTypeAcceptOne);
|
||||
}
|
||||
if (self.allowType == V2TIM_FRIEND_NEED_CONFIRM) {
|
||||
return TUIKitLocalizableString(TUIKitAllowTypeNeedConfirm);
|
||||
}
|
||||
if (self.allowType == V2TIM_FRIEND_DENY_ANY) {
|
||||
return TUIKitLocalizableString(TUIKitAllowTypeDeclineAll);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
@end
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TUIUserModel
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
@implementation TUIUserModel
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
TUIUserModel *model = [[TUIUserModel alloc] init];
|
||||
model.userId = self.userId;
|
||||
model.name = self.name;
|
||||
model.avatar = self.avatar;
|
||||
return model;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TUIScrollView
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void *gScrollViewBoundsChangeNotificationContext = &gScrollViewBoundsChangeNotificationContext;
|
||||
|
||||
@interface TUIScrollView ()
|
||||
|
||||
@property(nonatomic, readonly) CGFloat imageAspectRatio;
|
||||
@property(nonatomic) CGRect initialImageFrame;
|
||||
@property(strong, nonatomic, readonly) UITapGestureRecognizer *tap;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIScrollView
|
||||
|
||||
@synthesize tap = _tap;
|
||||
|
||||
#pragma mark - Tap to Zoom
|
||||
|
||||
- (UITapGestureRecognizer *)tap {
|
||||
if (_tap == nil) {
|
||||
_tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapToZoom:)];
|
||||
_tap.numberOfTapsRequired = 2;
|
||||
}
|
||||
return _tap;
|
||||
}
|
||||
|
||||
- (void)tapToZoom:(UIGestureRecognizer *)gestureRecognizer {
|
||||
if (self.zoomScale > self.minimumZoomScale) {
|
||||
[self setZoomScale:self.minimumZoomScale animated:YES];
|
||||
} else {
|
||||
CGPoint tapLocation = [gestureRecognizer locationInView:self.imageView];
|
||||
CGFloat zoomRectWidth = self.imageView.frame.size.width / self.maximumZoomScale;
|
||||
CGFloat zoomRectHeight = self.imageView.frame.size.height / self.maximumZoomScale;
|
||||
CGFloat zoomRectX = tapLocation.x - zoomRectWidth * 0.5;
|
||||
CGFloat zoomRectY = tapLocation.y - zoomRectHeight * 0.5;
|
||||
CGRect zoomRect = CGRectMake(zoomRectX, zoomRectY, zoomRectWidth, zoomRectHeight);
|
||||
[self zoomToRect:zoomRect animated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private Methods
|
||||
|
||||
- (void)configure {
|
||||
self.showsVerticalScrollIndicator = NO;
|
||||
self.showsHorizontalScrollIndicator = NO;
|
||||
[self startObservingBoundsChange];
|
||||
}
|
||||
|
||||
- (void)setImageView:(UIImageView *)imageView {
|
||||
if (_imageView.superview == self) {
|
||||
[_imageView removeGestureRecognizer:self.tap];
|
||||
[_imageView removeFromSuperview];
|
||||
}
|
||||
if (imageView) {
|
||||
_imageView = imageView;
|
||||
_initialImageFrame = CGRectNull;
|
||||
_imageView.userInteractionEnabled = YES;
|
||||
[_imageView addGestureRecognizer:self.tap];
|
||||
[self addSubview:imageView];
|
||||
}
|
||||
}
|
||||
|
||||
- (CGFloat)imageAspectRatio {
|
||||
if (self.imageView.image) {
|
||||
return self.imageView.image.size.width / self.imageView.image.size.height;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (CGSize)rectSizeForAspectRatio:(CGFloat)ratio thatFitsSize:(CGSize)size {
|
||||
CGFloat containerWidth = size.width;
|
||||
CGFloat containerHeight = size.height;
|
||||
CGFloat resultWidth = 0;
|
||||
CGFloat resultHeight = 0;
|
||||
|
||||
if ((ratio <= 0) || (containerHeight <= 0)) {
|
||||
return size;
|
||||
}
|
||||
|
||||
if (containerWidth / containerHeight >= ratio) {
|
||||
resultHeight = containerHeight;
|
||||
resultWidth = containerHeight * ratio;
|
||||
} else {
|
||||
resultWidth = containerWidth;
|
||||
resultHeight = containerWidth / ratio;
|
||||
}
|
||||
|
||||
return CGSizeMake(resultWidth, resultHeight);
|
||||
}
|
||||
|
||||
- (void)scaleImageForScrollViewTransitionFromBounds:(CGRect)oldBounds toBounds:(CGRect)newBounds {
|
||||
CGPoint oldContentOffset = CGPointMake(oldBounds.origin.x, oldBounds.origin.y);
|
||||
CGSize oldSize = oldBounds.size;
|
||||
CGSize newSize = newBounds.size;
|
||||
|
||||
CGSize containedImageSizeOld = [self rectSizeForAspectRatio:self.imageAspectRatio thatFitsSize:oldSize];
|
||||
|
||||
CGSize containedImageSizeNew = [self rectSizeForAspectRatio:self.imageAspectRatio thatFitsSize:newSize];
|
||||
|
||||
if (containedImageSizeOld.height <= 0) {
|
||||
containedImageSizeOld = containedImageSizeNew;
|
||||
}
|
||||
|
||||
CGFloat orientationRatio = (containedImageSizeNew.height / containedImageSizeOld.height);
|
||||
|
||||
CGAffineTransform t = CGAffineTransformMakeScale(orientationRatio, orientationRatio);
|
||||
|
||||
self.imageView.frame = CGRectApplyAffineTransform(self.imageView.frame, t);
|
||||
|
||||
self.contentSize = self.imageView.frame.size;
|
||||
|
||||
CGFloat xOffset = (oldContentOffset.x + oldSize.width * 0.5) * orientationRatio - newSize.width * 0.5;
|
||||
CGFloat yOffset = (oldContentOffset.y + oldSize.height * 0.5) * orientationRatio - newSize.height * 0.5;
|
||||
|
||||
xOffset -= MAX(xOffset + newSize.width - self.contentSize.width, 0);
|
||||
yOffset -= MAX(yOffset + newSize.height - self.contentSize.height, 0);
|
||||
xOffset += MAX(-xOffset, 0);
|
||||
yOffset += MAX(-yOffset, 0);
|
||||
|
||||
self.contentOffset = CGPointMake(xOffset, yOffset);
|
||||
}
|
||||
|
||||
- (void)setupInitialImageFrame {
|
||||
if (self.imageView.image && CGRectEqualToRect(self.initialImageFrame, CGRectNull)) {
|
||||
CGSize imageViewSize = [self rectSizeForAspectRatio:self.imageAspectRatio thatFitsSize:self.bounds.size];
|
||||
self.initialImageFrame = CGRectMake(0, 0, imageViewSize.width, imageViewSize.height);
|
||||
self.imageView.frame = self.initialImageFrame;
|
||||
self.contentSize = self.initialImageFrame.size;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - KVO
|
||||
|
||||
- (void)startObservingBoundsChange {
|
||||
[self addObserver:self
|
||||
forKeyPath:@"bounds"
|
||||
options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
|
||||
context:gScrollViewBoundsChangeNotificationContext];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context {
|
||||
if (context == gScrollViewBoundsChangeNotificationContext) {
|
||||
CGRect oldRect = ((NSValue *)change[NSKeyValueChangeOldKey]).CGRectValue;
|
||||
CGRect newRect = ((NSValue *)change[NSKeyValueChangeNewKey]).CGRectValue;
|
||||
if (!CGSizeEqualToSize(oldRect.size, newRect.size)) {
|
||||
[self scaleImageForScrollViewTransitionFromBounds:oldRect toBounds:newRect];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self removeObserver:self forKeyPath:@"bounds"];
|
||||
}
|
||||
|
||||
#pragma mark - UIScrollView
|
||||
|
||||
- (void)setContentOffset:(CGPoint)contentOffset {
|
||||
const CGSize contentSize = self.contentSize;
|
||||
const CGSize scrollViewSize = self.bounds.size;
|
||||
|
||||
if (contentSize.width < scrollViewSize.width) {
|
||||
contentOffset.x = -(scrollViewSize.width - contentSize.width) * 0.5;
|
||||
}
|
||||
|
||||
if (contentSize.height < scrollViewSize.height) {
|
||||
contentOffset.y = -(scrollViewSize.height - contentSize.height) * 0.5;
|
||||
}
|
||||
|
||||
[super setContentOffset:contentOffset];
|
||||
}
|
||||
|
||||
#pragma mark - UIView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self configure];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
self = [super initWithCoder:aDecoder];
|
||||
if (self) {
|
||||
[self configure];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
[self setupInitialImageFrame];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TUIGroupAvatar
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
#define groupAvatarWidth (48 * [[UIScreen mainScreen] scale])
|
||||
@implementation TUIGroupAvatar
|
||||
|
||||
+ (void)createGroupAvatar:(NSArray *)group finished:(void (^)(UIImage *groupAvatar))finished {
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
NSInteger avatarCount = group.count > 9 ? 9 : group.count;
|
||||
CGFloat width = groupAvatarWidth / 3 * 0.90;
|
||||
CGFloat space3 = (groupAvatarWidth - width * 3) / 4;
|
||||
CGFloat space2 = (groupAvatarWidth - width * 2 + space3) / 2;
|
||||
CGFloat space1 = (groupAvatarWidth - width) / 2;
|
||||
__block CGFloat y = avatarCount > 6 ? space3 : (avatarCount > 3 ? space2 : space1);
|
||||
__block CGFloat x = avatarCount % 3 == 0 ? space3 : (avatarCount % 3 == 2 ? space2 : space1);
|
||||
width = avatarCount > 4 ? width : (avatarCount > 1 ? (groupAvatarWidth - 3 * space3) / 2 : groupAvatarWidth);
|
||||
|
||||
if (avatarCount == 1) {
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
if (avatarCount == 2) {
|
||||
x = space3;
|
||||
} else if (avatarCount == 3) {
|
||||
x = (groupAvatarWidth - width) / 2;
|
||||
y = space3;
|
||||
} else if (avatarCount == 4) {
|
||||
x = space3;
|
||||
y = space3;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, groupAvatarWidth, groupAvatarWidth)];
|
||||
[view setBackgroundColor:[UIColor colorWithWhite:0.8 alpha:0.6]];
|
||||
view.layer.cornerRadius = 6;
|
||||
__block NSInteger count = 0;
|
||||
for (NSInteger i = avatarCount - 1; i >= 0; i--) {
|
||||
NSString *avatarUrl = [group objectAtIndex:i];
|
||||
|
||||
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(x, y, width, width)];
|
||||
[view addSubview:imageView];
|
||||
[imageView sd_setImageWithURL:[NSURL URLWithString:avatarUrl]
|
||||
placeholderImage:DefaultAvatarImage
|
||||
completed:^(UIImage *_Nullable image, NSError *_Nullable error, SDImageCacheType cacheType, NSURL *_Nullable imageURL) {
|
||||
count++;
|
||||
if (count == avatarCount) {
|
||||
UIGraphicsBeginImageContextWithOptions(view.frame.size, NO, 2.0);
|
||||
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndPDFContext();
|
||||
CGImageRef imageRef = image.CGImage;
|
||||
CGImageRef imageRefRect =
|
||||
CGImageCreateWithImageInRect(imageRef, CGRectMake(0, 0, view.frame.size.width * 2, view.frame.size.height * 2));
|
||||
UIImage *ansImage = [[UIImage alloc] initWithCGImage:imageRefRect];
|
||||
CGImageRelease(imageRefRect);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (finished) {
|
||||
finished(ansImage);
|
||||
}
|
||||
});
|
||||
}
|
||||
}];
|
||||
|
||||
if (avatarCount == 3) {
|
||||
if (i == 2) {
|
||||
y = width + space3 * 2;
|
||||
x = space3;
|
||||
} else {
|
||||
x += width + space3;
|
||||
}
|
||||
} else if (avatarCount == 4) {
|
||||
if (i % 2 == 0) {
|
||||
y += width + space3;
|
||||
x = space3;
|
||||
} else {
|
||||
x += width + space3;
|
||||
}
|
||||
} else {
|
||||
if (i % 3 == 0) {
|
||||
y += (width + space3);
|
||||
x = space3;
|
||||
} else {
|
||||
x += (width + space3);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
+ (void)fetchGroupAvatars:(NSString *)groupID placeholder:(UIImage *)placeholder callback:(void (^)(BOOL success, UIImage *image, NSString *groupID))callback {
|
||||
@tui_weakify(self);
|
||||
[[V2TIMManager sharedInstance] getGroupMemberList:groupID
|
||||
filter:V2TIM_GROUP_MEMBER_FILTER_ALL
|
||||
nextSeq:0
|
||||
succ:^(uint64_t nextSeq, NSArray<V2TIMGroupMemberFullInfo *> *memberList) {
|
||||
@tui_strongify(self);
|
||||
int i = 0;
|
||||
NSMutableArray *groupMemberAvatars = [NSMutableArray arrayWithCapacity:1];
|
||||
for (V2TIMGroupMemberFullInfo *member in memberList) {
|
||||
if (member.faceURL.length > 0) {
|
||||
[groupMemberAvatars addObject:member.faceURL];
|
||||
} else {
|
||||
[groupMemberAvatars addObject:@"http://placeholder"];
|
||||
}
|
||||
if (++i == 9) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i <= 1) {
|
||||
[self asyncClearCacheAvatarForGroup:groupID];
|
||||
if (callback) {
|
||||
callback(NO, placeholder, groupID);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *key = [NSString stringWithFormat:@"TUIConversationLastGroupMember_%@", groupID];
|
||||
[NSUserDefaults.standardUserDefaults setInteger:groupMemberAvatars.count forKey:key];
|
||||
[NSUserDefaults.standardUserDefaults synchronize];
|
||||
|
||||
[TUIGroupAvatar createGroupAvatar:groupMemberAvatars
|
||||
finished:^(UIImage *groupAvatar) {
|
||||
@tui_strongify(self);
|
||||
UIImage *avatar = groupAvatar;
|
||||
[self cacheGroupAvatar:avatar number:(UInt32)groupMemberAvatars.count groupID:groupID];
|
||||
|
||||
if (callback) {
|
||||
callback(YES, avatar, groupID);
|
||||
}
|
||||
}];
|
||||
}
|
||||
fail:^(int code, NSString *msg) {
|
||||
if (callback) {
|
||||
callback(NO, placeholder, groupID);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+ (void)cacheGroupAvatar:(UIImage *)avatar number:(UInt32)memberNum groupID:(NSString *)groupID {
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
if (groupID == nil || groupID.length == 0) {
|
||||
return;
|
||||
}
|
||||
NSString *tempPath = NSTemporaryDirectory();
|
||||
NSString *filePath = [NSString stringWithFormat:@"%@groupAvatar_%@_%d.png", tempPath, groupID, memberNum];
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
// check to delete old file
|
||||
NSNumber *oldValue = [defaults objectForKey:groupID];
|
||||
if (oldValue != nil) {
|
||||
UInt32 oldMemberNum = [oldValue unsignedIntValue];
|
||||
NSString *oldFilePath = [NSString stringWithFormat:@"%@groupAvatar_%@_%d.png", tempPath, groupID, oldMemberNum];
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
[fileManager removeItemAtPath:oldFilePath error:nil];
|
||||
}
|
||||
|
||||
// Save image.
|
||||
BOOL success = [UIImagePNGRepresentation(avatar) writeToFile:filePath atomically:YES];
|
||||
if (success) {
|
||||
[defaults setObject:@(memberNum) forKey:groupID];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+ (void)getCacheGroupAvatar:(NSString *)groupID callback:(void (^)(UIImage *, NSString *groupID))imageCallBack {
|
||||
if (groupID == nil || groupID.length == 0) {
|
||||
if (imageCallBack) {
|
||||
imageCallBack(nil, groupID);
|
||||
}
|
||||
return;
|
||||
}
|
||||
[[V2TIMManager sharedInstance] getGroupsInfo:@[ groupID ]
|
||||
succ:^(NSArray<V2TIMGroupInfoResult *> *groupResultList) {
|
||||
V2TIMGroupInfoResult *groupInfo = groupResultList.firstObject;
|
||||
if (!groupInfo) {
|
||||
imageCallBack(nil, groupID);
|
||||
return;
|
||||
}
|
||||
UInt32 memberNum = groupInfo.info.memberCount;
|
||||
memberNum = MAX(1, memberNum);
|
||||
memberNum = MIN(memberNum, 9);
|
||||
;
|
||||
NSString *tempPath = NSTemporaryDirectory();
|
||||
NSString *filePath = [NSString stringWithFormat:@"%@groupAvatar_%@_%u.png", tempPath, groupID, (unsigned int)memberNum];
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
UIImage *avatar = nil;
|
||||
BOOL success = [fileManager fileExistsAtPath:filePath];
|
||||
|
||||
if (success) {
|
||||
avatar = [[UIImage alloc] initWithContentsOfFile:filePath];
|
||||
NSString *key = [NSString stringWithFormat:@"TUIConversationLastGroupMember_%@", groupID];
|
||||
[NSUserDefaults.standardUserDefaults setInteger:memberNum forKey:key];
|
||||
[NSUserDefaults.standardUserDefaults synchronize];
|
||||
}
|
||||
imageCallBack(avatar, groupInfo.info.groupID);
|
||||
}
|
||||
fail:^(int code, NSString *msg) {
|
||||
imageCallBack(nil, groupID);
|
||||
}];
|
||||
}
|
||||
|
||||
+ (UIImage *)getCacheAvatarForGroup:(NSString *)groupId number:(UInt32)memberNum {
|
||||
memberNum = MAX(1, memberNum);
|
||||
memberNum = MIN(memberNum, 9);
|
||||
;
|
||||
NSString *tempPath = NSTemporaryDirectory();
|
||||
NSString *filePath = [NSString stringWithFormat:@"%@groupAvatar_%@_%u.png", tempPath, groupId, (unsigned int)memberNum];
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
UIImage *avatar = nil;
|
||||
BOOL success = [fileManager fileExistsAtPath:filePath];
|
||||
|
||||
if (success) {
|
||||
avatar = [[UIImage alloc] initWithContentsOfFile:filePath];
|
||||
}
|
||||
return avatar;
|
||||
}
|
||||
|
||||
+ (void)asyncClearCacheAvatarForGroup:(NSString *)groupID {
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
NSString *tempPath = NSTemporaryDirectory();
|
||||
for (int i = 0; i < 9; i++) {
|
||||
NSString *filePath = [NSString stringWithFormat:@"%@groupAvatar_%@_%d.png", tempPath, groupID, (i + 1)];
|
||||
if ([NSFileManager.defaultManager fileExistsAtPath:filePath]) {
|
||||
[NSFileManager.defaultManager removeItemAtPath:filePath error:nil];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TUIImageCache
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
@interface TUIImageCache ()
|
||||
@property(nonatomic, strong) NSMutableDictionary *resourceCache;
|
||||
@property(nonatomic, strong) NSMutableDictionary *faceCache;
|
||||
@end
|
||||
|
||||
@implementation TUIImageCache
|
||||
|
||||
+ (instancetype)sharedInstance {
|
||||
static dispatch_once_t onceToken;
|
||||
static TUIImageCache *instance;
|
||||
dispatch_once(&onceToken, ^{
|
||||
instance = [[TUIImageCache alloc] init];
|
||||
[UIImage d_fixResizableImage];
|
||||
});
|
||||
return instance;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_resourceCache = [NSMutableDictionary dictionary];
|
||||
_faceCache = [NSMutableDictionary dictionary];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addResourceToCache:(NSString *)path {
|
||||
__weak typeof(self) ws = self;
|
||||
[TUITool asyncDecodeImage:path
|
||||
complete:^(NSString *key, UIImage *image) {
|
||||
__strong __typeof(ws) strongSelf = ws;
|
||||
if (key && image) {
|
||||
[strongSelf.resourceCache setValue:image forKey:key];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (UIImage *)getResourceFromCache:(NSString *)path {
|
||||
if (path.length == 0) {
|
||||
return nil;
|
||||
}
|
||||
UIImage *image = [_resourceCache objectForKey:path];
|
||||
if (!image) {
|
||||
image = [UIImage d_imagePath:path];
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
- (void)addFaceToCache:(NSString *)path {
|
||||
__weak typeof(self) ws = self;
|
||||
[TUITool asyncDecodeImage:path
|
||||
complete:^(NSString *key, UIImage *image) {
|
||||
__strong __typeof(ws) strongSelf = ws;
|
||||
if (key && image) {
|
||||
[strongSelf.faceCache setValue:image forKey:key];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (UIImage *)getFaceFromCache:(NSString *)path {
|
||||
if (path.length == 0) {
|
||||
return nil;
|
||||
}
|
||||
UIImage *image = [_faceCache objectForKey:path];
|
||||
if (!image) {
|
||||
// gif extion
|
||||
if ([path tui_containsString:@".gif"]) {
|
||||
image = [UIImage sd_imageWithGIFData:[NSData dataWithContentsOfFile:path]];
|
||||
}
|
||||
else {
|
||||
image = [UIImage imageWithContentsOfFile:path];
|
||||
if (!image) {
|
||||
// gif
|
||||
NSString *formatPath = [path stringByAppendingString:@".gif"];
|
||||
image = [UIImage sd_imageWithGIFData:[NSData dataWithContentsOfFile:formatPath]];
|
||||
}
|
||||
}
|
||||
if (!image) {
|
||||
image = [_faceCache objectForKey:TUIChatFaceImagePath(@"ic_unknown_image")];
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
@end
|
||||
@interface IUCoreView : UIView
|
||||
@property(nonatomic, strong) UIView *view;
|
||||
@end
|
||||
|
||||
@implementation IUCoreView
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
|
||||
[self addSubview:self.view];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation TUINavigationController
|
||||
|
||||
- (instancetype)initWithRootViewController:(UIViewController *)rootViewController {
|
||||
if (self = [super initWithRootViewController:rootViewController]) {
|
||||
self.interactivePopGestureRecognizer.delegate = self;
|
||||
self.delegate = self;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
if (@available(iOS 13.0, *)) {
|
||||
UINavigationBarAppearance *appearance = [UINavigationBarAppearance new];
|
||||
[appearance configureWithDefaultBackground];
|
||||
appearance.shadowColor = nil;
|
||||
appearance.backgroundEffect = nil;
|
||||
appearance.backgroundColor = self.navigationBackColor;
|
||||
self.navigationBar.backgroundColor = self.navigationBackColor;
|
||||
self.navigationBar.barTintColor = self.navigationBackColor;
|
||||
self.navigationBar.shadowImage = [UIImage new];
|
||||
self.navigationBar.standardAppearance = appearance;
|
||||
self.navigationBar.scrollEdgeAppearance = appearance;
|
||||
|
||||
} else {
|
||||
self.navigationBar.backgroundColor = self.navigationBackColor;
|
||||
self.navigationBar.barTintColor = self.navigationBackColor;
|
||||
self.navigationBar.shadowImage = [UIImage new];
|
||||
}
|
||||
}
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.delegate = self;
|
||||
}
|
||||
|
||||
- (void)back {
|
||||
if ([self.uiNaviDelegate respondsToSelector:@selector(navigationControllerDidClickLeftButton:)]) {
|
||||
[self.uiNaviDelegate navigationControllerDidClickLeftButton:self];
|
||||
}
|
||||
[self popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (UIColor *)navigationBackColor {
|
||||
if (!_navigationBackColor) {
|
||||
_navigationBackColor = [self tintColor];
|
||||
}
|
||||
return _navigationBackColor;
|
||||
}
|
||||
|
||||
- (UIColor *)tintColor {
|
||||
return TUICoreDynamicColor(@"head_bg_gradient_start_color", @"#EBF0F6");
|
||||
}
|
||||
|
||||
|
||||
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
|
||||
if (self.viewControllers.count != 0) {
|
||||
viewController.hidesBottomBarWhenPushed = YES;
|
||||
self.tabBarController.tabBar.hidden = YES;
|
||||
|
||||
UIImage *image = self.navigationItemBackArrowImage;
|
||||
image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
|
||||
UIBarButtonItem *back = [[UIBarButtonItem alloc] initWithImage:image style:UIBarButtonItemStylePlain target:self action:@selector(back)];
|
||||
viewController.navigationItem.leftBarButtonItems = @[ back ];
|
||||
viewController.navigationItem.leftItemsSupplementBackButton = NO;
|
||||
}
|
||||
[super pushViewController:viewController animated:animated];
|
||||
}
|
||||
|
||||
- (UIImage *)navigationItemBackArrowImage {
|
||||
if (!_navigationItemBackArrowImage) {
|
||||
_navigationItemBackArrowImage = TUICoreDynamicImage(@"nav_back_img", [UIImage imageNamed:TUICoreImagePath(@"nav_back")]);
|
||||
}
|
||||
return _navigationItemBackArrowImage;
|
||||
}
|
||||
|
||||
// fix: https://developer.apple.com/forums/thread/660750
|
||||
- (NSArray<__kindof UIViewController *> *)popToRootViewControllerAnimated:(BOOL)animated {
|
||||
if (@available(iOS 14.0, *)) {
|
||||
for (UIViewController *vc in self.viewControllers) {
|
||||
vc.hidesBottomBarWhenPushed = NO;
|
||||
self.tabBarController.tabBar.hidden = NO;
|
||||
}
|
||||
}
|
||||
return [super popToRootViewControllerAnimated:animated];
|
||||
}
|
||||
|
||||
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
|
||||
if (navigationController.viewControllers.count == 1) {
|
||||
/**
|
||||
* If the number of view controllers in the stack is 1, it means only the root controller, clear the currentShowVC, and disable the swipe gesture for
|
||||
* the following method
|
||||
*/
|
||||
self.currentShowVC = Nil;
|
||||
} else {
|
||||
/**
|
||||
* Assign the pushed view controller to currentShowVC
|
||||
*/
|
||||
self.currentShowVC = viewController;
|
||||
}
|
||||
|
||||
if ([navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
|
||||
if (self.viewControllers.count == 1) {
|
||||
/**
|
||||
* Forbid the sliding back of the home page
|
||||
*/
|
||||
navigationController.interactivePopGestureRecognizer.enabled = NO;
|
||||
} else {
|
||||
navigationController.interactivePopGestureRecognizer.enabled = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
|
||||
/**
|
||||
* Listen to the event returned by the side slide
|
||||
*/
|
||||
__weak typeof(self) weakSelf = self;
|
||||
if (@available(iOS 10.0, *)) {
|
||||
[viewController.transitionCoordinator notifyWhenInteractionChangesUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
|
||||
__strong typeof(weakSelf) strongSelf = weakSelf;
|
||||
[strongSelf handleSideSlideReturnIfNeeded:context];
|
||||
}];
|
||||
} else {
|
||||
[viewController.transitionCoordinator notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
|
||||
__strong typeof(weakSelf) strongSelf = weakSelf;
|
||||
[strongSelf handleSideSlideReturnIfNeeded:context];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
|
||||
if (gestureRecognizer == self.interactivePopGestureRecognizer) {
|
||||
if (self.currentShowVC == self.topViewController) {
|
||||
/**
|
||||
* If currentShowVC exists, it means that the number of controllers in the stack is greater than 1, allowing the side slide gesture to be activated
|
||||
*/
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)handleSideSlideReturnIfNeeded:(id<UIViewControllerTransitionCoordinatorContext>)context {
|
||||
if (context.isCancelled) {
|
||||
return;
|
||||
}
|
||||
UIViewController *fromVc = [context viewControllerForKey:UITransitionContextFromViewControllerKey];
|
||||
if ([self.uiNaviDelegate respondsToSelector:@selector(navigationControllerDidSideSlideReturn:fromViewController:)]) {
|
||||
[self.uiNaviDelegate navigationControllerDidSideSlideReturn:self fromViewController:fromVc];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIAlertController (TUITheme)
|
||||
|
||||
- (void)tuitheme_addAction:(UIAlertAction *)action {
|
||||
if (action.style == UIAlertActionStyleDefault || action.style == UIAlertActionStyleCancel) {
|
||||
UIColor *tempColor = TUICoreDynamicColor(@"primary_theme_color", @"#147AFF");
|
||||
[action setValue:tempColor forKey:@"_titleTextColor"];
|
||||
}
|
||||
[self addAction:action];
|
||||
}
|
||||
|
||||
@end
|
||||
static const void *tui_valueCallbackKey = @"tui_valueCallbackKey";
|
||||
static const void *tui_nonValueCallbackKey = @"tui_nonValueCallbackKey";
|
||||
static const void *tui_extValueObjKey = @"tui_extValueObjKey";
|
||||
|
||||
@implementation NSObject (TUIExtValue)
|
||||
|
||||
- (void)setTui_valueCallback:(TUIValueCallbck)tui_valueCallback {
|
||||
objc_setAssociatedObject(self, tui_valueCallbackKey, tui_valueCallback, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
}
|
||||
|
||||
- (TUIValueCallbck)tui_valueCallback {
|
||||
return objc_getAssociatedObject(self, tui_valueCallbackKey);
|
||||
}
|
||||
|
||||
- (void)setTui_nonValueCallback:(TUINonValueCallbck)tui_nonValueCallback {
|
||||
objc_setAssociatedObject(self, tui_nonValueCallbackKey, tui_nonValueCallback, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
}
|
||||
|
||||
- (TUINonValueCallbck)tui_nonValueCallback {
|
||||
return objc_getAssociatedObject(self, tui_nonValueCallbackKey);
|
||||
}
|
||||
|
||||
- (void)setTui_extValueObj:(id)tui_extValueObj {
|
||||
objc_setAssociatedObject(self, tui_extValueObjKey, tui_extValueObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
- (id)tui_extValueObj {
|
||||
return objc_getAssociatedObject(self, tui_extValueObjKey);
|
||||
}
|
||||
|
||||
@end
|
||||
88
TUIKit/TUICore/TUIConfig.h
Normal file
@@ -0,0 +1,88 @@
|
||||
//
|
||||
// TUIConfig.h
|
||||
// TUIKit
|
||||
//
|
||||
// Created by kennethmiao on 2018/11/5.
|
||||
// Copyright © 2018 Tencent. All rights reserved.
|
||||
//
|
||||
/**
|
||||
*
|
||||
*
|
||||
* This class depends on the implementation of Tencent Cloud Chat SDK
|
||||
*
|
||||
* TUIConfig implements the default initialization of the configuration file, you can change the default configuration here according to your needs
|
||||
* Configuration file include emoticons, default icons, and more
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TUICommonModel.h"
|
||||
|
||||
#define DefaultAvatarImage ([TUIConfig defaultConfig].defaultAvatarImage)
|
||||
#define DefaultGroupAvatarImage ([TUIConfig defaultConfig].defaultGroupAvatarImage)
|
||||
#define DefaultGroupAvatarImageByGroupType(groupType) ([[TUIConfig defaultConfig] getGroupAvatarImageByGroupType:groupType])
|
||||
|
||||
typedef NS_ENUM(NSInteger, TUIKitAvatarType) {
|
||||
TAvatarTypeNone,
|
||||
TAvatarTypeRounded,
|
||||
TAvatarTypeRadiusCorner,
|
||||
};
|
||||
|
||||
@interface TUIConfig : NSObject
|
||||
|
||||
+ (TUIConfig *)defaultConfig;
|
||||
/**
|
||||
* Type of avatar
|
||||
*/
|
||||
@property(nonatomic, assign) TUIKitAvatarType avatarType;
|
||||
|
||||
/**
|
||||
* The size of the rounded corners of the avatar
|
||||
*/
|
||||
@property(nonatomic, assign) CGFloat avatarCornerRadius;
|
||||
|
||||
/**
|
||||
* Default user avatar
|
||||
*/
|
||||
@property(nonatomic, strong) UIImage *defaultAvatarImage;
|
||||
|
||||
/**
|
||||
* Default group avatar
|
||||
*/
|
||||
@property(nonatomic, strong) UIImage *defaultGroupAvatarImage;
|
||||
|
||||
/**
|
||||
* When sending a message, the flag used to identify whether the current message is not counted as unread, the default is NO
|
||||
*/
|
||||
@property(nonatomic, assign) BOOL isExcludedFromUnreadCount;
|
||||
|
||||
/**
|
||||
* When sending a message, the flag used to identify whether the current message does not update the lastMessage of the conversation, the default is NO
|
||||
*/
|
||||
@property(nonatomic, assign) BOOL isExcludedFromLastMessage;
|
||||
|
||||
/**
|
||||
* Whether to allow default pop-up prompts inside TUIKit
|
||||
*/
|
||||
@property(nonatomic, assign) BOOL enableToast;
|
||||
|
||||
/**
|
||||
* Whether to enable custom ringtone (only valid for Android)
|
||||
*/
|
||||
@property(nonatomic, assign) BOOL enableCustomRing;
|
||||
|
||||
/**
|
||||
* Display users' online status in session and contact list. NO in default.
|
||||
*/
|
||||
@property(nonatomic, assign) BOOL displayOnlineStatusIcon;
|
||||
|
||||
/**
|
||||
* Group avatar, allows to display avatars in the nine-square grid style, default is YES
|
||||
*/
|
||||
@property(nonatomic, assign) BOOL enableGroupGridAvatar;
|
||||
|
||||
- (UIImage *)getGroupAvatarImageByGroupType:(NSString *)groupType;
|
||||
|
||||
- (void)setSceneOptimizParams:(NSString *)path; //(For RTC,Don't delete)
|
||||
|
||||
@end
|
||||
115
TUIKit/TUICore/TUIConfig.m
Normal file
@@ -0,0 +1,115 @@
|
||||
//
|
||||
// TUIConfig.m
|
||||
// TUIKit
|
||||
//
|
||||
// Created by kennethmiao on 2018/11/5.
|
||||
// Copyright © 2018 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIConfig.h"
|
||||
#import "TUICommonModel.h"
|
||||
#import "TUIDefine.h"
|
||||
#import "TUILogin.h"
|
||||
#import "TUIThemeManager.h"
|
||||
|
||||
@interface TUIConfig ()
|
||||
|
||||
@property(nonatomic, strong) UIImage *defaultGroupAvatarImage_Public;
|
||||
@property(nonatomic, strong) UIImage *defaultGroupAvatarImage_Meeting;
|
||||
@property(nonatomic, strong) UIImage *defaultGroupAvatarImage_AVChatRoom;
|
||||
@property(nonatomic, strong) UIImage *defaultGroupAvatarImage_Community;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIConfig
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_avatarCornerRadius = 5.f;
|
||||
_defaultAvatarImage = TUICoreBundleThemeImage(@"default_c2c_head_img", @"default_c2c_head");
|
||||
_defaultGroupAvatarImage = TUICoreBundleThemeImage(@"default_group_head_img", @"default_group_head");
|
||||
_defaultGroupAvatarImage_Public = TUICoreBundleThemeImage(@"default_group_head_public_img", @"default_group_head_public");
|
||||
_defaultGroupAvatarImage_Meeting = TUICoreBundleThemeImage(@"default_group_head_meeting_img", @"default_group_head_meeting");
|
||||
_defaultGroupAvatarImage_AVChatRoom = TUICoreBundleThemeImage(@"default_group_head_avchatroom_img", @"default_group_head_avchatRoom");
|
||||
_defaultGroupAvatarImage_Community = TUICoreBundleThemeImage(@"", @"default_group_head_community");
|
||||
|
||||
_isExcludedFromUnreadCount = NO;
|
||||
_isExcludedFromLastMessage = NO;
|
||||
_enableToast = YES;
|
||||
_displayOnlineStatusIcon = NO;
|
||||
_enableGroupGridAvatar = YES;
|
||||
_avatarType = TAvatarTypeRounded;
|
||||
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(onChangeTheme) name:TUIDidApplyingThemeChangedNotfication object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id)defaultConfig {
|
||||
static dispatch_once_t onceToken;
|
||||
static TUIConfig *config;
|
||||
dispatch_once(&onceToken, ^{
|
||||
config = [[TUIConfig alloc] init];
|
||||
});
|
||||
return config;
|
||||
}
|
||||
|
||||
- (void)onChangeTheme {
|
||||
self.defaultAvatarImage = TUICoreBundleThemeImage(@"default_c2c_head_img", @"default_c2c_head");
|
||||
self.defaultGroupAvatarImage = TUICoreBundleThemeImage(@"default_group_head_img", @"default_group_head");
|
||||
self.defaultGroupAvatarImage_Public = TUICoreBundleThemeImage(@"default_group_head_public_img", @"default_group_head_public");
|
||||
self.defaultGroupAvatarImage_Meeting = TUICoreBundleThemeImage(@"default_group_head_meeting_img", @"default_group_head_meeting");
|
||||
self.defaultGroupAvatarImage_AVChatRoom = TUICoreBundleThemeImage(@"default_group_head_avchatroom_img", @"default_group_head_avchatroom");
|
||||
self.defaultGroupAvatarImage_Community = TUICoreBundleThemeImage(@"default_group_head_community_img", @"default_group_head_community");
|
||||
}
|
||||
|
||||
- (UIImage *)getGroupAvatarImageByGroupType:(NSString *)groupType {
|
||||
if ([groupType isEqualToString:GroupType_Work]) {
|
||||
return self.defaultGroupAvatarImage;
|
||||
} else if ([groupType isEqualToString:GroupType_Public]) {
|
||||
return self.defaultGroupAvatarImage_Public;
|
||||
} else if ([groupType isEqualToString:GroupType_Meeting]) {
|
||||
return self.defaultGroupAvatarImage_Meeting;
|
||||
} else if ([groupType isEqualToString:GroupType_AVChatRoom]) {
|
||||
return self.defaultGroupAvatarImage_AVChatRoom;
|
||||
} else if ([groupType isEqualToString:GroupType_Community]) {
|
||||
return self.defaultGroupAvatarImage_Community;
|
||||
} else {
|
||||
return self.defaultGroupAvatarImage;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Sence
|
||||
- (void)setSceneOptimizParams:(NSString *)path {
|
||||
NSURL *url = [NSURL URLWithString:@"https://demos.trtc.tencent-cloud.com/prod/base/v1/events/stat"];
|
||||
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
|
||||
req.HTTPMethod = @"POST";
|
||||
NSDictionary *msgData =
|
||||
@{@"sdkappid" : @([TUILogin getSdkAppID]), @"bundleId" : NSBundle.mainBundle.bundleIdentifier ?: @"", @"package" : @"", @"component" : path};
|
||||
NSString* userId =[TUILogin getUserID];
|
||||
NSDictionary *param = @{@"userid" : (userId?:@""), @"event" : @"useScenario", @"msg" : msgData};
|
||||
NSData *data = [NSJSONSerialization dataWithJSONObject:param options:NSJSONWritingPrettyPrinted error:nil];
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
req.HTTPBody = data;
|
||||
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
config.HTTPAdditionalHeaders = @{@"api-key" : @"API_KEY", @"Content-Type" : @"application/json"};
|
||||
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
|
||||
[[session dataTaskWithRequest:req
|
||||
completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
|
||||
if (data) {
|
||||
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
|
||||
long code = [dic[@"errorCode"] longValue];
|
||||
if (code == 0) {
|
||||
NSLog(@"scene param [%@] success", path);
|
||||
} else {
|
||||
NSString *msg = dic[@"errorMessage"];
|
||||
NSLog(@"scene param [%@] failed: [%ld] %@", path, code, msg);
|
||||
}
|
||||
} else {
|
||||
NSLog(@"scene param [%@] error: res data nil", path);
|
||||
}
|
||||
}] resume];
|
||||
}
|
||||
@end
|
||||
217
TUIKit/TUICore/TUICore.h
Normal file
@@ -0,0 +1,217 @@
|
||||
|
||||
// Created by Tencent on 2023/06/09.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
/**
|
||||
* TUICore
|
||||
* This module is mainly responsible for data transfer, event notification and extension between TUI components.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@protocol TUIServiceProtocol;
|
||||
@protocol TUIObjectProtocol;
|
||||
@protocol TUINotificationProtocol;
|
||||
@protocol TUIExtensionProtocol;
|
||||
@class TUIExtensionInfo;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef void (^TUICallServiceResultCallback)(NSInteger errorCode, NSString *errorMessage, NSDictionary *param);
|
||||
|
||||
#pragma mark - TUICore
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Definition of TUICore, APIs
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@interface TUICore : NSObject
|
||||
|
||||
+ (void)registerService:(NSString *)serviceName object:(id<TUIServiceProtocol>)object;
|
||||
+ (void)unregisterService:(NSString *)serviceName;
|
||||
+ (nullable id<TUIServiceProtocol>)getService:(NSString *)serviceName;
|
||||
+ (nullable id)callService:(NSString *)serviceName method:(NSString *)method param:(nullable NSDictionary *)param;
|
||||
+ (nullable id)callService:(NSString *)serviceName
|
||||
method:(NSString *)method
|
||||
param:(nullable NSDictionary *)param
|
||||
resultCallback:(nullable TUICallServiceResultCallback)resultCallback;
|
||||
|
||||
+ (void)registerEvent:(NSString *)key subKey:(NSString *)subKey object:(id<TUINotificationProtocol>)object;
|
||||
+ (void)unRegisterEventByObject:(id<TUINotificationProtocol>)object;
|
||||
+ (void)unRegisterEvent:(nullable NSString *)key subKey:(nullable NSString *)subKey object:(nullable id<TUINotificationProtocol>)object;
|
||||
+ (void)notifyEvent:(NSString *)key subKey:(nullable NSString *)subKey object:(nullable id)anObject param:(nullable NSDictionary *)param;
|
||||
|
||||
+ (void)registerExtension:(NSString *)extensionID object:(id<TUIExtensionProtocol>)object;
|
||||
+ (void)unRegisterExtension:(NSString *)extensionID object:(id<TUIExtensionProtocol>)object;
|
||||
+ (NSArray<TUIExtensionInfo *> *)getExtensionList:(NSString *)extensionID param:(nullable NSDictionary *)param;
|
||||
+ (BOOL)raiseExtension:(NSString *)extensionID parentView:(UIView *)parentView param:(nullable NSDictionary *)param;
|
||||
// deprecated
|
||||
+ (nullable NSDictionary *)getExtensionInfo:(NSString *)extensionID
|
||||
param:(nullable NSDictionary *)param __attribute__((deprecated("use getExtensionList:param: instead")));
|
||||
|
||||
+ (void)registerObjectFactory:(NSString *)factoryName objectFactory:(id<TUIObjectProtocol>)objectFactory;
|
||||
+ (void)unRegisterObjectFactory:(NSString *)factoryName;
|
||||
+ (nullable id)createObject:(NSString *)factoryName key:(NSString *)method param:(nullable NSDictionary *)param;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - TUIRoute
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Definition of TUIRoute, APIs
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef void (^TUIValueResultCallback)(NSDictionary *param);
|
||||
|
||||
@interface NSObject (TUIRoute)
|
||||
|
||||
@property(nonatomic, copy) TUIValueResultCallback navigateValueCallback;
|
||||
|
||||
@end
|
||||
|
||||
@interface UIViewController (TUIRoute)
|
||||
|
||||
- (void)pushViewController:(NSString *)viewControllerKey param:(nullable NSDictionary *)param forResult:(nullable TUIValueResultCallback)callback;
|
||||
|
||||
- (void)presentViewController:(NSString *)viewControllerKey param:(nullable NSDictionary *)param forResult:(nullable TUIValueResultCallback)callback;
|
||||
- (void)presentViewController:(NSString *)viewControllerKey
|
||||
param:(nullable NSDictionary *)param
|
||||
embbedIn:(nullable UINavigationController *)navigationVC
|
||||
forResult:(nullable TUIValueResultCallback)callback;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - TUIService
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Definition of TUIService, APIs
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@protocol TUIServiceProtocol <NSObject>
|
||||
|
||||
@optional
|
||||
- (nullable id)onCall:(NSString *)method param:(nullable NSDictionary *)param;
|
||||
- (nullable id)onCall:(NSString *)method param:(nullable NSDictionary *)param resultCallback:(TUICallServiceResultCallback)resultCallback;
|
||||
|
||||
@end
|
||||
|
||||
@interface TUIServiceManager : NSObject
|
||||
|
||||
+ (instancetype)shareInstance;
|
||||
|
||||
- (void)registerService:(NSString *)serviceName service:(id<TUIServiceProtocol>)service;
|
||||
- (void)unregisterService:(NSString *)serviceName;
|
||||
|
||||
- (nullable id<TUIServiceProtocol>)getService:(NSString *)serviceName;
|
||||
|
||||
- (nullable id)callService:(NSString *)serviceName
|
||||
method:(NSString *)method
|
||||
param:(nullable NSDictionary *)param
|
||||
resultCallback:(nullable TUICallServiceResultCallback)resultCallback;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - TUIEvent
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Definition of TUIEvent, APIs
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@protocol TUINotificationProtocol <NSObject>
|
||||
@optional
|
||||
- (void)onNotifyEvent:(NSString *)key subKey:(NSString *)subKey object:(nullable id)anObject param:(nullable NSDictionary *)param;
|
||||
|
||||
@end
|
||||
|
||||
@interface TUIEventManager : NSObject
|
||||
|
||||
+ (instancetype)shareInstance;
|
||||
|
||||
- (void)registerEvent:(NSString *)key subKey:(NSString *)subKey object:(id<TUINotificationProtocol>)object;
|
||||
- (void)unRegisterEvent:(id<TUINotificationProtocol>)object;
|
||||
- (void)unRegisterEvent:(nullable NSString *)key subKey:(nullable NSString *)subKey object:(nullable id<TUINotificationProtocol>)object;
|
||||
|
||||
- (void)notifyEvent:(NSString *)key subKey:(nullable NSString *)subKey object:(nullable id)object param:(nullable NSDictionary *)param;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - TUIExtension
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Definition of TUIExtension, APIs
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef void (^TUIExtensionClickCallback)(NSDictionary *param);
|
||||
|
||||
@interface TUIExtensionInfo : NSObject
|
||||
|
||||
@property(nonatomic, assign) NSInteger weight;
|
||||
@property(nonatomic, strong, nullable) UIImage *icon;
|
||||
@property(nonatomic, copy, nullable) NSString *text;
|
||||
@property(nonatomic, strong, nullable) NSDictionary *data;
|
||||
@property(nonatomic, copy, nullable) TUIExtensionClickCallback onClicked;
|
||||
|
||||
@end
|
||||
|
||||
@protocol TUIExtensionProtocol <NSObject>
|
||||
@optional
|
||||
|
||||
- (nullable NSArray<TUIExtensionInfo *> *)onGetExtension:(NSString *)extensionID param:(nullable NSDictionary *)param;
|
||||
|
||||
// If there exist responser, return YES
|
||||
- (BOOL)onRaiseExtension:(NSString *)extensionID parentView:(UIView *)parentView param:(nullable NSDictionary *)param;
|
||||
|
||||
// deprecated
|
||||
- (nullable NSDictionary *)onGetExtensionInfo:(NSString *)extensionID
|
||||
param:(nullable NSDictionary *)param __attribute__((deprecated("use onGetExtension:param: instead")));
|
||||
|
||||
@end
|
||||
|
||||
@interface TUIExtensionManager : NSObject
|
||||
|
||||
+ (instancetype)shareInstance;
|
||||
|
||||
- (void)registerExtension:(NSString *)extensionID extension:(id<TUIExtensionProtocol>)extension;
|
||||
- (void)unRegisterExtension:(NSString *)extensionID extension:(id<TUIExtensionProtocol>)extension;
|
||||
|
||||
- (NSArray<TUIExtensionInfo *> *)getExtensionList:(NSString *)extensionID param:(nullable NSDictionary *)param;
|
||||
|
||||
- (BOOL)raiseExtension:(NSString *)extensionID parentView:(UIView *)parentView param:(nullable NSDictionary *)param;
|
||||
|
||||
// deprecated
|
||||
- (nullable NSDictionary *)getExtensionInfo:(NSString *)extensionID
|
||||
param:(nullable NSDictionary *)param __attribute__((deprecated("use getExtensionList:param: instead")));
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - TUIObjectFactory
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Definition of TUIObjectFactory, APIs
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@protocol TUIObjectProtocol <NSObject>
|
||||
@optional
|
||||
- (nullable id)onCreateObject:(NSString *)method param:(nullable NSDictionary *)param;
|
||||
|
||||
@end
|
||||
|
||||
@interface TUIObjectFactoryManager : NSObject
|
||||
|
||||
+ (instancetype)shareInstance;
|
||||
|
||||
- (void)registerObjectFactory:(NSString *)factoryName objectFactory:(id<TUIObjectProtocol>)objectFactory;
|
||||
- (void)unRegisterObjectFactory:(NSString *)factoryName;
|
||||
|
||||
- (nullable id)createObject:(NSString *)factoryName method:(NSString *)method param:(nullable NSDictionary *)param;
|
||||
|
||||
- (nullable id)createObject:(NSString *)method param:(NSDictionary *)param;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
565
TUIKit/TUICore/TUICore.m
Normal file
@@ -0,0 +1,565 @@
|
||||
|
||||
// Created by Tencent on 2023/06/09.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
#import "TUICore.h"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#import "TUIDefine.h"
|
||||
#import "TUIThemeManager.h"
|
||||
#import "TUIWeakProxy.h"
|
||||
|
||||
@implementation TUICore
|
||||
|
||||
+ (void)initialize {
|
||||
TUIRegisterThemeResourcePath(TUICoreThemePath, TUIThemeModuleCore);
|
||||
TUIRegisterThemeResourcePath(TUIBundlePath(@"TUICoreTheme_Minimalist", TUICoreBundle_Key_Class), TUIThemeModuleCore_Minimalist);
|
||||
}
|
||||
|
||||
+ (void)registerService:(NSString *)serviceName object:(id<TUIServiceProtocol>)object {
|
||||
[TUIServiceManager.shareInstance registerService:serviceName service:object];
|
||||
}
|
||||
|
||||
+ (void)unregisterService:(NSString *)serviceName {
|
||||
[TUIServiceManager.shareInstance unregisterService:serviceName];
|
||||
}
|
||||
|
||||
+ (id<TUIServiceProtocol>)getService:(NSString *)serviceName {
|
||||
return [TUIServiceManager.shareInstance getService:serviceName];
|
||||
}
|
||||
|
||||
+ (id)callService:(NSString *)serviceName method:(NSString *)method param:(nullable NSDictionary *)param {
|
||||
return [TUIServiceManager.shareInstance callService:serviceName method:method param:param resultCallback:nil];
|
||||
}
|
||||
|
||||
+ (id)callService:(NSString *)serviceName
|
||||
method:(NSString *)method
|
||||
param:(nullable NSDictionary *)param
|
||||
resultCallback:(nullable TUICallServiceResultCallback)resultCallback {
|
||||
return [TUIServiceManager.shareInstance callService:serviceName method:method param:param resultCallback:resultCallback];
|
||||
}
|
||||
|
||||
+ (void)registerEvent:(NSString *)key subKey:(NSString *)subKey object:(id<TUINotificationProtocol>)object {
|
||||
[TUIEventManager.shareInstance registerEvent:key subKey:subKey object:object];
|
||||
}
|
||||
|
||||
+ (void)unRegisterEventByObject:(id<TUINotificationProtocol>)object {
|
||||
[TUIEventManager.shareInstance unRegisterEvent:object];
|
||||
}
|
||||
+ (void)unRegisterEvent:(nullable NSString *)key subKey:(nullable NSString *)subKey object:(nullable id<TUINotificationProtocol>)object {
|
||||
[TUIEventManager.shareInstance unRegisterEvent:key subKey:subKey object:object];
|
||||
}
|
||||
|
||||
+ (void)notifyEvent:(NSString *)key subKey:(NSString *)subKey object:(nullable id)anObject param:(nullable NSDictionary *)param {
|
||||
[TUIEventManager.shareInstance notifyEvent:key subKey:subKey object:anObject param:param];
|
||||
}
|
||||
|
||||
+ (void)registerExtension:(NSString *)extensionID object:(id<TUIExtensionProtocol>)object {
|
||||
[TUIExtensionManager.shareInstance registerExtension:extensionID extension:object];
|
||||
}
|
||||
|
||||
+ (void)unRegisterExtension:(NSString *)extensionID object:(id<TUIExtensionProtocol>)object {
|
||||
[TUIExtensionManager.shareInstance unRegisterExtension:extensionID extension:object];
|
||||
}
|
||||
|
||||
+ (NSDictionary *)getExtensionInfo:(NSString *)extensionID param:(nullable NSDictionary *)param {
|
||||
return [TUIExtensionManager.shareInstance getExtensionInfo:extensionID param:param];
|
||||
}
|
||||
|
||||
+ (NSArray<TUIExtensionInfo *> *)getExtensionList:(NSString *)extensionID param:(nullable NSDictionary *)param {
|
||||
return [TUIExtensionManager.shareInstance getExtensionList:extensionID param:param];
|
||||
}
|
||||
|
||||
+ (BOOL)raiseExtension:(NSString *)extensionID parentView:(UIView *)parentView param:(nullable NSDictionary *)param {
|
||||
return [TUIExtensionManager.shareInstance raiseExtension:extensionID parentView:parentView param:param];
|
||||
}
|
||||
|
||||
+ (void)registerObjectFactory:(NSString *)factoryName objectFactory:(id<TUIObjectProtocol>)objectFactory {
|
||||
[TUIObjectFactoryManager.shareInstance registerObjectFactory:factoryName objectFactory:objectFactory];
|
||||
}
|
||||
|
||||
+ (void)unRegisterObjectFactory:(NSString *)factoryName {
|
||||
[TUIObjectFactoryManager.shareInstance unRegisterObjectFactory:factoryName];
|
||||
}
|
||||
|
||||
+ (id)createObject:(NSString *)factoryName key:(NSString *)key param:(NSDictionary *)param {
|
||||
return [TUIObjectFactoryManager.shareInstance createObject:factoryName method:key param:param];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - TUIRoute
|
||||
|
||||
static const void *navigateValueCallback = @"navigateValueCallback";
|
||||
|
||||
@implementation NSObject (TUIRoute)
|
||||
|
||||
- (void)setNavigateValueCallback:(TUIValueResultCallback)callback {
|
||||
objc_setAssociatedObject(self, navigateValueCallback, callback, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
}
|
||||
|
||||
- (TUIValueResultCallback)navigateValueCallback {
|
||||
return objc_getAssociatedObject(self, navigateValueCallback);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIViewController (TUIRoute)
|
||||
|
||||
- (void)pushViewController:(NSString *)viewControllerKey param:(nullable NSDictionary *)param forResult:(nullable TUIValueResultCallback)callback {
|
||||
NSAssert([self isKindOfClass:UINavigationController.class], @"self must be a navigation controller");
|
||||
UIViewController *vc = [TUIObjectFactoryManager.shareInstance createObject:viewControllerKey param:param];
|
||||
if ([vc isKindOfClass:UIViewController.class]) {
|
||||
vc.navigateValueCallback = callback;
|
||||
[(UINavigationController *)self pushViewController:vc animated:YES];
|
||||
} else {
|
||||
NSAssert(false, @"viewControllerKey not exists or invalid");
|
||||
}
|
||||
}
|
||||
|
||||
- (void)presentViewController:(NSString *)viewControllerKey param:(nullable NSDictionary *)param forResult:(nullable TUIValueResultCallback)callback {
|
||||
[self presentViewController:viewControllerKey param:param embbedIn:nil forResult:callback];
|
||||
}
|
||||
|
||||
- (void)presentViewController:(NSString *)viewControllerKey
|
||||
param:(nullable NSDictionary *)param
|
||||
embbedIn:(nullable UINavigationController *)navigationVC
|
||||
forResult:(nullable TUIValueResultCallback)callback {
|
||||
UIViewController *vc = [TUIObjectFactoryManager.shareInstance createObject:viewControllerKey param:param];
|
||||
if ([vc isKindOfClass:UIViewController.class]) {
|
||||
vc.navigateValueCallback = callback;
|
||||
if (navigationVC) {
|
||||
if ([navigationVC isKindOfClass:UINavigationController.class]) {
|
||||
NSMutableArray *arrayM = [NSMutableArray array];
|
||||
if (navigationVC.viewControllers.count > 0) {
|
||||
[arrayM addObjectsFromArray:navigationVC.viewControllers];
|
||||
}
|
||||
[arrayM addObject:vc];
|
||||
navigationVC.viewControllers = [NSArray arrayWithArray:arrayM];
|
||||
[self presentViewController:navigationVC animated:YES completion:nil];
|
||||
} else {
|
||||
NSAssert(false, @"navigationVC must be a navigation controller");
|
||||
}
|
||||
} else {
|
||||
[self presentViewController:vc animated:YES completion:nil];
|
||||
}
|
||||
} else {
|
||||
NSAssert(false, @"viewControllerKey not exists or invalid");
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - TUIService
|
||||
|
||||
@interface TUIServiceManager ()
|
||||
|
||||
@property(nonatomic, strong) NSMapTable<NSString *, id<TUIServiceProtocol>> *serviceMap;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIServiceManager
|
||||
|
||||
+ (instancetype)shareInstance {
|
||||
static id instance = nil;
|
||||
if (instance == nil) {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
instance = [[self alloc] init];
|
||||
});
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
- (void)registerService:(NSString *)serviceName service:(id<TUIServiceProtocol>)service {
|
||||
NSAssert(serviceName.length > 0, @"invalid service name");
|
||||
NSAssert(service != nil, @"invalid service");
|
||||
|
||||
if (serviceName && service) {
|
||||
@synchronized(self.serviceMap) {
|
||||
[self.serviceMap setObject:service forKey:serviceName];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unregisterService:(NSString *)serviceName {
|
||||
NSAssert(serviceName.length > 0, @"invalid service name");
|
||||
|
||||
if (serviceName) {
|
||||
@synchronized(self.serviceMap) {
|
||||
[self.serviceMap removeObjectForKey:serviceName];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (nullable id<TUIServiceProtocol>)getService:(NSString *)serviceName {
|
||||
id<TUIServiceProtocol> service = nil;
|
||||
@synchronized(self.serviceMap) {
|
||||
service = [self.serviceMap objectForKey:serviceName];
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
- (nullable id)callService:(NSString *)serviceName
|
||||
method:(NSString *)method
|
||||
param:(nullable NSDictionary *)param
|
||||
resultCallback:(nullable TUICallServiceResultCallback)resultCallback {
|
||||
NSAssert(serviceName.length > 0, @"invalid service name");
|
||||
NSAssert(method.length > 0, @"invalid method");
|
||||
|
||||
id<TUIServiceProtocol> service = [self getService:serviceName];
|
||||
id result = nil;
|
||||
if (resultCallback) {
|
||||
if (service && [service respondsToSelector:@selector(onCall:param:resultCallback:)]) {
|
||||
result = [service onCall:method param:param resultCallback:resultCallback];
|
||||
}
|
||||
} else {
|
||||
if (service && [service respondsToSelector:@selector(onCall:param:)]) {
|
||||
result = [service onCall:method param:param];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSMapTable<NSString *, id<TUIServiceProtocol>> *)serviceMap {
|
||||
if (_serviceMap == nil) {
|
||||
_serviceMap = [NSMapTable strongToWeakObjectsMapTable];
|
||||
}
|
||||
return _serviceMap;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - TUIEvent
|
||||
|
||||
@interface TUIEventManager ()
|
||||
|
||||
@property(nonatomic, strong) NSMutableArray<NSDictionary *> *eventList;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIEventManager
|
||||
|
||||
+ (instancetype)shareInstance {
|
||||
static id instance = nil;
|
||||
if (instance == nil) {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
instance = [[self alloc] init];
|
||||
});
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
- (void)registerEvent:(NSString *)key subKey:(NSString *)subKey object:(id<TUINotificationProtocol>)object {
|
||||
NSAssert(key.length > 0, @"invalid key");
|
||||
NSAssert(object != nil, @"invalid object");
|
||||
|
||||
if (subKey.length == 0) {
|
||||
subKey = @"";
|
||||
}
|
||||
|
||||
if (key && subKey && object) {
|
||||
NSDictionary *event = @{@"key" : [key copy], @"subKey" : [subKey copy], @"object" : [TUIWeakProxy proxyWithTarget:object]};
|
||||
|
||||
@synchronized(self.eventList) {
|
||||
[self.eventList addObject:event];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unRegisterEvent:(id<TUINotificationProtocol>)object {
|
||||
[self unRegisterEvent:nil subKey:nil object:object];
|
||||
}
|
||||
|
||||
- (void)unRegisterEvent:(nullable NSString *)key subKey:(nullable NSString *)subKey object:(nullable id<TUINotificationProtocol>)object {
|
||||
@synchronized(self.eventList) {
|
||||
NSMutableArray *removeEventList = [NSMutableArray array];
|
||||
for (NSDictionary *event in self.eventList) {
|
||||
NSString *pkey = [event objectForKey:@"key"];
|
||||
NSString *pSubKey = [event objectForKey:@"subKey"];
|
||||
id pObject = [event objectForKey:@"object"];
|
||||
|
||||
if (pObject == nil || [(TUIWeakProxy *)pObject target] == nil) {
|
||||
[removeEventList addObject:event];
|
||||
}
|
||||
if (key == nil && subKey == nil && pObject == object) {
|
||||
[removeEventList addObject:event];
|
||||
} else if ([pkey isEqualToString:key] && subKey == nil && object == nil) {
|
||||
[removeEventList addObject:event];
|
||||
} else if ([pkey isEqualToString:key] && [subKey isEqualToString:pSubKey] && object == nil) {
|
||||
[removeEventList addObject:event];
|
||||
} else if ([pkey isEqualToString:key] && [subKey isEqualToString:pSubKey] && pObject == object) {
|
||||
[removeEventList addObject:event];
|
||||
}
|
||||
}
|
||||
[self.eventList removeObjectsInArray:removeEventList];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)notifyEvent:(NSString *)key subKey:(NSString *)subKey object:(nullable id)object param:(nullable NSDictionary *)param {
|
||||
NSAssert(key.length > 0, @"invalid key");
|
||||
|
||||
if (subKey.length == 0) {
|
||||
subKey = @"";
|
||||
}
|
||||
|
||||
@synchronized(self.eventList) {
|
||||
for (NSDictionary *event in self.eventList) {
|
||||
NSString *pkey = [event objectForKey:@"key"];
|
||||
NSString *pSubKey = [event objectForKey:@"subKey"];
|
||||
|
||||
if ([pkey isEqualToString:key] && [pSubKey isEqualToString:subKey]) {
|
||||
id<TUINotificationProtocol> pObject = [event objectForKey:@"object"];
|
||||
if (pObject) {
|
||||
[pObject onNotifyEvent:key subKey:subKey object:object param:param];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSMutableArray<NSDictionary *> *)eventList {
|
||||
if (_eventList == nil) {
|
||||
_eventList = [NSMutableArray array];
|
||||
}
|
||||
return _eventList;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - TUIExtension
|
||||
|
||||
@implementation TUIExtensionInfo
|
||||
|
||||
@end
|
||||
|
||||
@interface TUIExtensionManager ()
|
||||
|
||||
@property(nonatomic, strong) NSMutableDictionary<NSString *, NSHashTable<id<TUIExtensionProtocol>> *> *extensionMap;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIExtensionManager
|
||||
|
||||
+ (instancetype)shareInstance {
|
||||
static id instance = nil;
|
||||
if (instance == nil) {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
instance = [[self alloc] init];
|
||||
});
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
- (void)registerExtension:(NSString *)extensionID extension:(id<TUIExtensionProtocol>)extension {
|
||||
NSAssert(extensionID.length > 0, @"invalid extension id");
|
||||
NSAssert(extension != nil, @"invalid extension");
|
||||
|
||||
if (extensionID && extension) {
|
||||
@synchronized(self.extensionMap) {
|
||||
NSHashTable *list = [self.extensionMap objectForKey:extensionID];
|
||||
if (list == nil) {
|
||||
list = [NSHashTable weakObjectsHashTable];
|
||||
}
|
||||
[list addObject:extension];
|
||||
[self.extensionMap setObject:list forKey:extensionID];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unRegisterExtension:(NSString *)extensionID extension:(id<TUIExtensionProtocol>)extension {
|
||||
NSAssert(extensionID.length > 0, @"invalid extension id");
|
||||
NSAssert(extension != nil, @"invalid extension");
|
||||
|
||||
if (extensionID && extension) {
|
||||
@synchronized(self.extensionMap) {
|
||||
NSHashTable *list = [self.extensionMap objectForKey:extensionID];
|
||||
if (list == nil) {
|
||||
list = [NSHashTable weakObjectsHashTable];
|
||||
}
|
||||
[list removeObject:extension];
|
||||
[self.extensionMap setObject:list forKey:extensionID];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray<TUIExtensionInfo *> *)getExtensionList:(NSString *)extensionID param:(nullable NSDictionary *)param {
|
||||
NSAssert(extensionID.length > 0, @"invalid extension id");
|
||||
|
||||
NSHashTable *list = nil;
|
||||
@synchronized(self.extensionMap) {
|
||||
list = [self.extensionMap objectForKey:extensionID];
|
||||
}
|
||||
if (list == nil || list.count == 0) {
|
||||
return @[];
|
||||
}
|
||||
|
||||
// get
|
||||
NSMutableArray *resultExtensionInfoList = [NSMutableArray array];
|
||||
for (id<TUIExtensionProtocol> observer in list) {
|
||||
if (observer && [observer respondsToSelector:@selector(onGetExtension:param:)]) {
|
||||
NSArray<TUIExtensionInfo *> *infoList = [observer onGetExtension:extensionID param:param];
|
||||
if (infoList) {
|
||||
[resultExtensionInfoList addObjectsFromArray:infoList];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sort
|
||||
NSArray *result = [resultExtensionInfoList sortedArrayUsingComparator:^NSComparisonResult(TUIExtensionInfo *obj1, TUIExtensionInfo *obj2) {
|
||||
if (obj1.weight > obj2.weight) {
|
||||
return NSOrderedAscending;
|
||||
} else {
|
||||
return NSOrderedDescending;
|
||||
}
|
||||
}];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (BOOL)raiseExtension:(NSString *)extensionID parentView:(UIView *)parentView param:(nullable NSDictionary *)param {
|
||||
NSAssert(extensionID.length > 0, @"invalid extension id");
|
||||
NSAssert(parentView != nil, @"invalid parent view");
|
||||
|
||||
NSHashTable *list = nil;
|
||||
@synchronized(self.extensionMap) {
|
||||
list = [self.extensionMap objectForKey:extensionID];
|
||||
}
|
||||
if (list == nil || list.count == 0) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
BOOL isResponserExist = NO;
|
||||
for (id<TUIExtensionProtocol> observer in list) {
|
||||
if (observer && [observer respondsToSelector:@selector(onRaiseExtension:parentView:param:)]) {
|
||||
isResponserExist = [observer onRaiseExtension:extensionID parentView:parentView param:param];
|
||||
if (isResponserExist) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isResponserExist;
|
||||
}
|
||||
|
||||
- (NSDictionary *)getExtensionInfo:(NSString *)extensionID param:(nullable NSDictionary *)param {
|
||||
NSAssert(extensionID.length > 0, @"invalid extension id");
|
||||
|
||||
NSHashTable *list = nil;
|
||||
@synchronized(self.extensionMap) {
|
||||
list = [self.extensionMap objectForKey:extensionID];
|
||||
}
|
||||
if (list == nil || list.count == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
for (id<TUIExtensionProtocol> observer in list) {
|
||||
if (observer && [observer respondsToSelector:@selector(onGetExtensionInfo:param:)]) {
|
||||
NSDictionary *info = [observer onGetExtensionInfo:extensionID param:param];
|
||||
if (info) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary<NSString *, NSHashTable<id<TUIExtensionProtocol>> *> *)extensionMap {
|
||||
if (_extensionMap == nil) {
|
||||
_extensionMap = [NSMutableDictionary dictionary];
|
||||
}
|
||||
return _extensionMap;
|
||||
}
|
||||
@end
|
||||
|
||||
#pragma mark - TUIObjectFactory
|
||||
|
||||
@interface TUIObjectFactoryManager ()
|
||||
|
||||
@property(nonatomic, strong) NSMapTable<NSString *, id<TUIObjectProtocol>> *objectFactoryMap;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIObjectFactoryManager : NSObject
|
||||
|
||||
+ (instancetype)shareInstance {
|
||||
static id instance = nil;
|
||||
if (instance == nil) {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
instance = [[self alloc] init];
|
||||
});
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
- (void)registerObjectFactory:(NSString *)factoryName objectFactory:(id<TUIObjectProtocol>)objectFactory {
|
||||
NSAssert(factoryName.length > 0, @"invalid factory name");
|
||||
NSAssert(objectFactory != nil, @"invalid object factory");
|
||||
|
||||
if (factoryName && objectFactory) {
|
||||
@synchronized(self.objectFactoryMap) {
|
||||
[self.objectFactoryMap setObject:objectFactory forKey:factoryName];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unRegisterObjectFactory:(NSString *)factoryName {
|
||||
NSAssert(factoryName.length > 0, @"invalid factory name");
|
||||
|
||||
if (factoryName) {
|
||||
@synchronized(self.objectFactoryMap) {
|
||||
[self.objectFactoryMap removeObjectForKey:factoryName];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (nullable id)createObject:(NSString *)factoryName method:(NSString *)method param:(nullable NSDictionary *)param {
|
||||
NSAssert(factoryName.length > 0, @"invalid factory name");
|
||||
NSAssert(method.length > 0, @"invalid method");
|
||||
|
||||
id<TUIObjectProtocol> factory = nil;
|
||||
@synchronized(self.objectFactoryMap) {
|
||||
factory = [self.objectFactoryMap objectForKey:factoryName];
|
||||
}
|
||||
|
||||
if (factory && [factory respondsToSelector:@selector(onCreateObject:param:)]) {
|
||||
return [factory onCreateObject:method param:param];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (nullable id)createObject:(NSString *)method param:(NSDictionary *)param {
|
||||
NSAssert(method.length > 0, @"invalid method");
|
||||
|
||||
NSArray<id<TUIObjectProtocol>> *list = nil;
|
||||
@synchronized(self.objectFactoryMap) {
|
||||
list = self.objectFactoryMap.objectEnumerator.allObjects;
|
||||
}
|
||||
if (list == nil || list.count == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
for (id<TUIObjectProtocol> factory in list) {
|
||||
if (factory && [factory respondsToSelector:@selector(onCreateObject:param:)]) {
|
||||
id obj = [factory onCreateObject:method param:param];
|
||||
if (obj) {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSMapTable<NSString *, id<TUIObjectProtocol>> *)objectFactoryMap {
|
||||
if (_objectFactoryMap == nil) {
|
||||
_objectFactoryMap = [NSMapTable strongToWeakObjectsMapTable];
|
||||
}
|
||||
return _objectFactoryMap;
|
||||
}
|
||||
|
||||
@end
|
||||
35
TUIKit/TUICore/TUICore.podspec
Normal file
@@ -0,0 +1,35 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = 'TUICore'
|
||||
spec.version = '8.5.6864'
|
||||
spec.platform = :ios
|
||||
spec.ios.deployment_target = '9.0'
|
||||
spec.license = { :type => 'Proprietary',
|
||||
:text => <<-LICENSE
|
||||
copyright 2017 tencent Ltd. All rights reserved.
|
||||
LICENSE
|
||||
}
|
||||
spec.homepage = 'https://cloud.tencent.com/document/product/269/3794'
|
||||
spec.source = { :git => './'}
|
||||
spec.documentation_url = 'https://cloud.tencent.com/document/product/269/9147'
|
||||
spec.authors = 'tencent video cloud'
|
||||
spec.summary = 'TUICore'
|
||||
spec.dependency 'SDWebImage'
|
||||
|
||||
spec.requires_arc = true
|
||||
spec.default_subspec = 'ImSDK_Plus'
|
||||
|
||||
spec.subspec 'ImSDK_Plus' do |plus|
|
||||
plus.dependency 'TXIMSDK_Plus_iOS_XCFramework'
|
||||
plus.dependency 'TUICore/Base'
|
||||
end
|
||||
|
||||
spec.subspec 'Base' do |base|
|
||||
base.source_files = '*.{h,m,mm,c}'
|
||||
base.resource = ['Resources/*.bundle']
|
||||
end
|
||||
|
||||
spec.resource_bundle = {
|
||||
"#{spec.module_name}_Privacy" => 'Resources/PrivacyInfo.xcprivacy'
|
||||
}
|
||||
|
||||
end
|
||||
49
TUIKit/TUICore/TUIDarkModel.h
Normal file
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// TUIDarkModel.h
|
||||
// TUICore
|
||||
//
|
||||
// Created by xiangzhang on 2021/9/9.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@import UIKit;
|
||||
|
||||
@interface UIColor (TUIDarkModel)
|
||||
|
||||
+ (UIColor *)d_colorWithColorLight:(UIColor *)light dark:(UIColor *)dark __attribute__((deprecated("use TUICoreDynamicColor()")));
|
||||
+ (UIColor *)d_systemGrayColor __attribute__((deprecated("use TUICoreDynamicColor()")));
|
||||
+ (UIColor *)d_systemRedColor __attribute__((deprecated("use TUICoreDynamicColor()")));
|
||||
+ (UIColor *)d_systemBlueColor __attribute__((deprecated("use TUICoreDynamicColor()")));
|
||||
|
||||
@end
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dark Mode
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@interface UIImage (TUIDarkModel)
|
||||
/**
|
||||
* path: normal image path (without @x.png suffix), dark image path must be "normal image path_dark"
|
||||
*/
|
||||
+ (UIImage *)d_imagePath:(NSString *)path __attribute__((deprecated("use TUIDemoBundleThemeImage(imageKey,defaultImageName)")));
|
||||
|
||||
/**
|
||||
*
|
||||
* imageName: common image name, dark image name must be "ordinary image name_dark"
|
||||
* bundleName: bundleName where the image is stored
|
||||
*/
|
||||
+ (UIImage *)d_imageNamed:(NSString *)imageName
|
||||
bundle:(NSString *)bundleName __attribute__((deprecated("use TUIDemoBundleThemeImage(imageKey,defaultImageName)")));
|
||||
|
||||
+ (UIImage *)d_imageWithImageLight:(NSString *)lightImagePath
|
||||
dark:(NSString *)darkImagePath __attribute__((deprecated("use TUIDemoBundleThemeImage(imageKey,defaultImageName)")));
|
||||
|
||||
+ (void)d_fixResizableImage;
|
||||
|
||||
+ (UIImage *)d_imageWithImageLightImg:(UIImage *)lightImage
|
||||
dark:(UIImage *)darkImage __attribute__((deprecated("use TUIDemoBundleThemeImage(imageKey,defaultImageName)")));
|
||||
@end
|
||||
210
TUIKit/TUICore/TUIDarkModel.m
Normal file
@@ -0,0 +1,210 @@
|
||||
//
|
||||
// TUIDarkModel.m
|
||||
// TUICore
|
||||
//
|
||||
// Created by xiangzhang on 2021/9/9.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIDarkModel.h"
|
||||
#import <objc/message.h>
|
||||
#import "TUIDefine.h"
|
||||
|
||||
@implementation UIColor (TUIDarkModel)
|
||||
|
||||
+ (UIColor *)d_colorWithColorLight:(UIColor *)light dark:(UIColor *)dark {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
return [self colorWithDynamicProvider:^UIColor *_Nonnull(UITraitCollection *_Nonnull traitCollection) {
|
||||
switch (traitCollection.userInterfaceStyle) {
|
||||
case UIUserInterfaceStyleDark:
|
||||
return dark;
|
||||
case UIUserInterfaceStyleLight:
|
||||
case UIUserInterfaceStyleUnspecified:
|
||||
default:
|
||||
return light;
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
return light;
|
||||
}
|
||||
}
|
||||
|
||||
+ (UIColor *)d_systemBlackColor {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
return [self systemBackgroundColor];
|
||||
} else {
|
||||
return [UIColor whiteColor];
|
||||
}
|
||||
}
|
||||
|
||||
+ (UIColor *)d_systemGrayColor {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
return [self systemGrayColor];
|
||||
} else {
|
||||
return [UIColor grayColor];
|
||||
}
|
||||
}
|
||||
|
||||
+ (UIColor *)d_systemRedColor {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
return [self systemRedColor];
|
||||
} else {
|
||||
return [UIColor redColor];
|
||||
}
|
||||
}
|
||||
|
||||
+ (UIColor *)d_systemBlueColor {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
return [self systemBlueColor];
|
||||
} else {
|
||||
return [UIColor blueColor];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIImage (TUIDarkModel)
|
||||
|
||||
+ (UIImage *)d_imagePath:(NSString *)path {
|
||||
UIImage *image = [UIImage d_imageWithImageLight:path dark:[NSString stringWithFormat:@"%@_dark", path]];
|
||||
return image;
|
||||
}
|
||||
|
||||
+ (UIImage *)d_imageNamed:(NSString *)imageName bundle:(NSString *)bundleName;
|
||||
{
|
||||
NSString *path = nil;
|
||||
if ([bundleName isEqualToString:TUIDemoBundle]) {
|
||||
path = TUIDemoImagePath(imageName);
|
||||
} else if ([bundleName isEqualToString:TUICoreBundle]) {
|
||||
path = TUICoreImagePath(imageName);
|
||||
} else if ([bundleName isEqualToString:TUIChatBundle]) {
|
||||
path = TUIChatImagePath(imageName);
|
||||
} else if ([bundleName isEqualToString:TUIChatFaceBundle]) {
|
||||
path = TUIChatFaceImagePath(imageName);
|
||||
} else if ([bundleName isEqualToString:TUIConversationBundle]) {
|
||||
path = TUIConversationImagePath(imageName);
|
||||
} else if ([bundleName isEqualToString:TUIContactBundle]) {
|
||||
path = TUIContactImagePath(imageName);
|
||||
} else if ([bundleName isEqualToString:TUISearchBundle]) {
|
||||
path = TUISearchImagePath(imageName);
|
||||
}
|
||||
if (path) {
|
||||
return [UIImage d_imageWithImageLight:path dark:[NSString stringWithFormat:@"%@_dark", path]];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (void)d_fixResizableImage {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
Class klass = UIImage.class;
|
||||
SEL selector = @selector(resizableImageWithCapInsets:resizingMode:);
|
||||
Method method = class_getInstanceMethod(klass, selector);
|
||||
if (method == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
IMP originalImp = class_getMethodImplementation(klass, selector);
|
||||
if (!originalImp) {
|
||||
return;
|
||||
}
|
||||
|
||||
IMP dynamicColorCompatibleImp = imp_implementationWithBlock(^UIImage *(UIImage *_self, UIEdgeInsets insets, UIImageResizingMode resizingMode) {
|
||||
UITraitCollection *lightTrait = [self lightTrait];
|
||||
UITraitCollection *darkTrait = [self darkTrait];
|
||||
|
||||
UIImage *resizable = ((UIImage * (*)(UIImage *, SEL, UIEdgeInsets, UIImageResizingMode)) originalImp)(_self, selector, insets, resizingMode);
|
||||
UIImage *resizableInLight = [_self.imageAsset imageWithTraitCollection:lightTrait];
|
||||
UIImage *resizableInDark = [_self.imageAsset imageWithTraitCollection:darkTrait];
|
||||
|
||||
if (resizableInLight) {
|
||||
[resizable.imageAsset registerImage:((UIImage * (*)(UIImage *, SEL, UIEdgeInsets, UIImageResizingMode)) originalImp)(resizableInLight, selector,
|
||||
insets, resizingMode)
|
||||
withTraitCollection:lightTrait];
|
||||
}
|
||||
if (resizableInDark) {
|
||||
[resizable.imageAsset registerImage:((UIImage * (*)(UIImage *, SEL, UIEdgeInsets, UIImageResizingMode)) originalImp)(resizableInDark, selector,
|
||||
insets, resizingMode)
|
||||
withTraitCollection:darkTrait];
|
||||
}
|
||||
return resizable;
|
||||
});
|
||||
|
||||
class_replaceMethod(klass, selector, dynamicColorCompatibleImp, method_getTypeEncoding(method));
|
||||
}
|
||||
}
|
||||
|
||||
+ (UITraitCollection *)lightTrait API_AVAILABLE(ios(13.0)) {
|
||||
static UITraitCollection *trait = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
trait = [UITraitCollection traitCollectionWithTraitsFromCollections:@[
|
||||
[UITraitCollection traitCollectionWithDisplayScale:UIScreen.mainScreen.scale],
|
||||
[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight]
|
||||
]];
|
||||
});
|
||||
|
||||
return trait;
|
||||
}
|
||||
|
||||
+ (UITraitCollection *)darkTrait API_AVAILABLE(ios(13.0)) {
|
||||
static UITraitCollection *trait = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
trait = [UITraitCollection traitCollectionWithTraitsFromCollections:@[
|
||||
[UITraitCollection traitCollectionWithDisplayScale:UIScreen.mainScreen.scale],
|
||||
[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark]
|
||||
]];
|
||||
});
|
||||
|
||||
return trait;
|
||||
}
|
||||
|
||||
+ (UIImage *)d_imageWithImageLight:(NSString *)lightImagePath dark:(NSString *)darkImagePath {
|
||||
UIImage *lightImage = [UIImage imageNamed:lightImagePath];
|
||||
if (!lightImage) {
|
||||
return nil;
|
||||
}
|
||||
if (@available(iOS 13.0, *)) {
|
||||
UIImage *darkImage = [UIImage imageNamed:darkImagePath];
|
||||
UITraitCollection *const scaleTraitCollection = [UITraitCollection currentTraitCollection];
|
||||
UITraitCollection *const darkUnscaledTraitCollection = [UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark];
|
||||
UITraitCollection *const darkScaledTraitCollection =
|
||||
[UITraitCollection traitCollectionWithTraitsFromCollections:@[ scaleTraitCollection, darkUnscaledTraitCollection ]];
|
||||
UIImage *image = [lightImage
|
||||
imageWithConfiguration:[lightImage.configuration
|
||||
configurationWithTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight]]];
|
||||
darkImage = [darkImage
|
||||
imageWithConfiguration:[darkImage.configuration
|
||||
configurationWithTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark]]];
|
||||
[image.imageAsset registerImage:darkImage withTraitCollection:darkScaledTraitCollection];
|
||||
return image;
|
||||
} else {
|
||||
return lightImage;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (UIImage *)d_imageWithImageLightImg:(UIImage *)lightImage dark:(UIImage *)darkImage {
|
||||
if (!lightImage) {
|
||||
return nil;
|
||||
}
|
||||
if (@available(iOS 13.0, *)) {
|
||||
UITraitCollection *const scaleTraitCollection = [UITraitCollection currentTraitCollection];
|
||||
UITraitCollection *const darkUnscaledTraitCollection = [UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark];
|
||||
UITraitCollection *const darkScaledTraitCollection =
|
||||
[UITraitCollection traitCollectionWithTraitsFromCollections:@[ scaleTraitCollection, darkUnscaledTraitCollection ]];
|
||||
UIImage *image = [lightImage
|
||||
imageWithConfiguration:[lightImage.configuration
|
||||
configurationWithTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight]]];
|
||||
darkImage = [darkImage
|
||||
imageWithConfiguration:[darkImage.configuration
|
||||
configurationWithTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark]]];
|
||||
[image.imageAsset registerImage:darkImage withTraitCollection:darkScaledTraitCollection];
|
||||
return image;
|
||||
} else {
|
||||
return lightImage;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
1309
TUIKit/TUICore/TUIDefine.h
Normal file
62
TUIKit/TUICore/TUIGlobalization.h
Normal file
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// NSBundle+TUIKIT.h
|
||||
// Pods
|
||||
//
|
||||
// Created by harvy on 2020/10/9.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "TUIDefine.h"
|
||||
|
||||
/**
|
||||
* Get localized strings in TUIKit
|
||||
*/
|
||||
#define TUIKitLocalizableString(key) [TUIGlobalization getLocalizedStringForKey:@"" #key "" bundle:TUIKitLocalizableBundle]
|
||||
|
||||
#define TUICoreLocalizableString(key) [TUIGlobalization getLocalizedStringForKey:@"" #key "" bundle:TUICoreLocalizableBundle]
|
||||
|
||||
#define TUIChatLocalizableString(key) [TUIGlobalization getLocalizedStringForKey:@"" #key "" bundle:TUIChatLocalizableBundle]
|
||||
|
||||
#define TUIConversationLocalizableString(key) [TUIGlobalization getLocalizedStringForKey:@"" #key "" bundle:TUIConversationLocalizableBundle]
|
||||
|
||||
#define TUIContactLocalizableString(key) [TUIGlobalization getLocalizedStringForKey:@"" #key "" bundle:TUIContactLocalizableBundle]
|
||||
|
||||
#define TUISearchLocalizableString(key) [TUIGlobalization getLocalizedStringForKey:@"" #key "" bundle:TUISearchLocalizableBundle]
|
||||
|
||||
#define TIMCommonLocalizableString(key) [TUIGlobalization getLocalizedStringForKey:@"" #key "" bundle:TIMCommonLocalizableBundle]
|
||||
|
||||
#define isRTL() [TUIGlobalization getRTLOption]
|
||||
|
||||
#define TUICustomLanguageKey @"TUICustomLanguageKey"
|
||||
#define TUIChangeLanguageNotification @"TUIChangeLanguageNotification"
|
||||
|
||||
#define TUIKitGlobalizationRTLOptionKey @"TUIKitGlobalizationRTLOptionKey"
|
||||
|
||||
@interface TUIGlobalization : NSObject
|
||||
|
||||
/**
|
||||
* Get localized string
|
||||
*/
|
||||
+ (NSString *)getLocalizedStringForKey:(NSString *)key bundle:(NSString *)bundleName;
|
||||
|
||||
/**
|
||||
* Get preferred language
|
||||
*/
|
||||
+ (NSString *)getPreferredLanguage;
|
||||
|
||||
/**
|
||||
* Set the preferred language to the specified value.
|
||||
*/
|
||||
+ (void)setPreferredLanguage:(NSString *)language;
|
||||
|
||||
+ (void)setRTLOption:(BOOL)op;
|
||||
|
||||
+ (BOOL)getRTLOption;
|
||||
|
||||
#pragma mark - Deprecated
|
||||
+ (NSString *)g_localizedStringForKey:(NSString *)key bundle:(NSString *)bundleName __attribute__((deprecated("use getLocalizedStringForKey:bundle:")));
|
||||
+ (NSString *)tk_localizableLanguageKey __attribute__((deprecated("use getPreferredLanguage")));
|
||||
+ (void)ignoreTraditionChinese:(BOOL)ignore __attribute__((deprecated("traditional chinese is now supported by the TUIKit component, and the current API has been deprecated")));
|
||||
|
||||
@end
|
||||
176
TUIKit/TUICore/TUIGlobalization.m
Normal file
@@ -0,0 +1,176 @@
|
||||
//
|
||||
// NSBundle+TUIKIT.m
|
||||
// Pods
|
||||
//
|
||||
// Created by harvy on 2020/10/9.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIGlobalization.h"
|
||||
#import <objc/runtime.h>
|
||||
#import "TUIDefine.h"
|
||||
|
||||
@implementation TUIGlobalization
|
||||
|
||||
+ (void)load {
|
||||
NSString *language = [TUIGlobalization getPreferredLanguage];
|
||||
if([language hasPrefix:@"ar"]) {
|
||||
[TUIGlobalization setRTLOption:YES];
|
||||
}
|
||||
else {
|
||||
[TUIGlobalization setRTLOption:NO];
|
||||
}
|
||||
}
|
||||
|
||||
static NSString *gCustomLanguage = nil;
|
||||
static BOOL gRTLOption = NO;
|
||||
|
||||
+ (NSString *)getLocalizedStringForKey:(NSString *)key bundle:(NSString *)bundleName {
|
||||
return [self getLocalizedStringForKey:key value:nil bundle:bundleName];
|
||||
}
|
||||
|
||||
+ (NSString *)getLocalizedStringForKey:(NSString *)key value:(nullable NSString *)value bundle:(nonnull NSString *)bundleName {
|
||||
static NSMutableDictionary *bundleCache = nil;
|
||||
if (bundleCache == nil) {
|
||||
bundleCache = [NSMutableDictionary dictionary];
|
||||
}
|
||||
NSString *language = [self getPreferredLanguage];
|
||||
language = [@"Localizable" stringByAppendingPathComponent:language];
|
||||
NSString *cacheKey = [NSString stringWithFormat:@"%@_%@", bundleName, language];
|
||||
NSBundle *bundle = [bundleCache objectForKey:cacheKey];
|
||||
if (bundle == nil) {
|
||||
bundle = [NSBundle bundleWithPath:[TUIKitLocalizable(bundleName) pathForResource:language ofType:@"lproj"]];
|
||||
if (bundle) {
|
||||
[bundleCache setObject:bundle forKey:cacheKey];
|
||||
}
|
||||
}
|
||||
value = [bundle localizedStringForKey:key value:value table:nil];
|
||||
|
||||
// It's not necessary to query at main bundle, cause it's a long-time operation
|
||||
// NSString *resultStr = [[NSBundle mainBundle] localizedStringForKey:key value:value table:nil];
|
||||
return value ?: @"";
|
||||
}
|
||||
|
||||
+ (NSString *)getPreferredLanguage {
|
||||
// Custom language in app
|
||||
if (gCustomLanguage == nil) {
|
||||
gCustomLanguage = [NSUserDefaults.standardUserDefaults objectForKey:TUICustomLanguageKey];
|
||||
}
|
||||
if (gCustomLanguage.length > 0) {
|
||||
return gCustomLanguage;
|
||||
}
|
||||
|
||||
// Follow system changes by default
|
||||
NSString *language = [NSLocale preferredLanguages].firstObject;
|
||||
if ([language hasPrefix:@"en"]) {
|
||||
language = @"en";
|
||||
} else if ([language hasPrefix:@"zh"]) {
|
||||
if ([language rangeOfString:@"Hans"].location != NSNotFound) {
|
||||
// Simplified Chinese
|
||||
language = @"zh-Hans";
|
||||
} else {
|
||||
// Traditional Chinese
|
||||
language = @"zh-Hant";
|
||||
}
|
||||
} else if ([language hasPrefix:@"ar"]) {
|
||||
language = @"ar";
|
||||
}
|
||||
else {
|
||||
language = @"en";
|
||||
}
|
||||
|
||||
return language;
|
||||
}
|
||||
|
||||
+ (void)setPreferredLanguage:(NSString *)language {
|
||||
gCustomLanguage = language;
|
||||
[NSUserDefaults.standardUserDefaults setObject:language ?: @"" forKey:TUICustomLanguageKey];
|
||||
[NSUserDefaults.standardUserDefaults synchronize];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:TUIChangeLanguageNotification object:nil];
|
||||
});
|
||||
}
|
||||
|
||||
+ (void)ignoreTraditionChinese:(BOOL)ignore {
|
||||
#ifdef DEBUG
|
||||
NSAssert(false, @"traditional chinese is now supported by the TUIKit component, and the current API has been deprecated");
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (void)setRTLOption:(BOOL)op {
|
||||
gRTLOption = op;
|
||||
[UIView appearance].semanticContentAttribute = op?UISemanticContentAttributeForceRightToLeft:UISemanticContentAttributeForceLeftToRight;
|
||||
[UISearchBar appearance].semanticContentAttribute = op?UISemanticContentAttributeForceRightToLeft:UISemanticContentAttributeForceLeftToRight;
|
||||
[UICollectionView appearance].semanticContentAttribute = op?UISemanticContentAttributeForceRightToLeft:UISemanticContentAttributeForceLeftToRight;
|
||||
[UISwitch appearance].semanticContentAttribute = op?UISemanticContentAttributeForceRightToLeft:UISemanticContentAttributeForceLeftToRight;
|
||||
|
||||
[NSUserDefaults.standardUserDefaults setBool:op forKey:TUIKitGlobalizationRTLOptionKey];
|
||||
[NSUserDefaults.standardUserDefaults synchronize];
|
||||
}
|
||||
|
||||
+ (BOOL)getRTLOption {
|
||||
return gRTLOption;
|
||||
}
|
||||
|
||||
#pragma mark - Deprecated
|
||||
+ (NSString *)g_localizedStringForKey:(NSString *)key bundle:(nonnull NSString *)bundleName {
|
||||
return [self getLocalizedStringForKey:key value:nil bundle:bundleName];
|
||||
}
|
||||
|
||||
+ (NSString *)tk_localizableLanguageKey {
|
||||
return [self getPreferredLanguage];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface TUIBundle : NSBundle
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIBundle
|
||||
|
||||
- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName {
|
||||
if ([TUIBundle private_mainBundle]) {
|
||||
return [[TUIBundle private_mainBundle] localizedStringForKey:key value:value table:tableName];
|
||||
} else {
|
||||
return [super localizedStringForKey:key value:value table:tableName];
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSBundle *)private_mainBundle {
|
||||
static NSMutableDictionary *bundleCache;
|
||||
if (bundleCache == nil) {
|
||||
bundleCache = [NSMutableDictionary dictionary];
|
||||
}
|
||||
NSString *customLanguage = [TUIGlobalization getPreferredLanguage];
|
||||
if (customLanguage.length) {
|
||||
NSString *path = [[NSBundle mainBundle] pathForResource:customLanguage ofType:@"lproj"] ?: @"";
|
||||
NSBundle *bundle = [bundleCache objectForKey:path];
|
||||
if (bundle == nil) {
|
||||
bundle = [NSBundle bundleWithPath:path];
|
||||
if (bundle) {
|
||||
[bundleCache setObject:bundle forKey:path];
|
||||
}
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface NSBundle (Localization)
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSBundle (Localization)
|
||||
|
||||
+ (void)load {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
object_setClass([NSBundle mainBundle], [TUIBundle class]);
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
172
TUIKit/TUICore/TUILogin.h
Normal file
@@ -0,0 +1,172 @@
|
||||
|
||||
// Created by Tencent on 2023/06/09.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
/**
|
||||
* TUILogin
|
||||
* This module is mainly responsible for the login logic of IM and TRTC
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef void (^TFail)(int code, NSString * __nullable msg);
|
||||
typedef void (^TSucc)(void);
|
||||
typedef NS_ENUM(NSInteger, TUILogLevel) {
|
||||
/**
|
||||
* < Do not output any SDK logs
|
||||
*/
|
||||
TUI_LOG_NONE = 0,
|
||||
/**
|
||||
* < Output logs at the DEBUG, INFO, WARNING, and ERROR levels
|
||||
*/
|
||||
TUI_LOG_DEBUG = 3,
|
||||
/**
|
||||
* < Output logs at the INFO, WARNING, and ERROR levels
|
||||
*/
|
||||
TUI_LOG_INFO = 4,
|
||||
/**
|
||||
* < Output logs at the WARNING and ERROR levels
|
||||
*/
|
||||
TUI_LOG_WARN = 5,
|
||||
/**
|
||||
* < Output logs at the ERROR level
|
||||
*/
|
||||
TUI_LOG_ERROR = 6,
|
||||
};
|
||||
|
||||
/**
|
||||
* Status in different kinds of business scene
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, TUIBusinessScene) {
|
||||
None = 0,
|
||||
InRecording = 1,
|
||||
InCallingRoom = 2,
|
||||
InMeetingRoom = 3,
|
||||
InLivingRoom = 4,
|
||||
};
|
||||
|
||||
/// Enumeration definition of login account type
|
||||
typedef NS_ENUM(NSInteger, TUILoginAccountType) {
|
||||
TUI_ACCOUNT_TYPE_UNKOWN = 0, ///< Unkown
|
||||
TUI_ACCOUNT_TYPE_IM = 1, ///< IM
|
||||
TUI_ACCOUNT_TYPE_PUSH = 2, ///< Push
|
||||
};
|
||||
|
||||
/**
|
||||
* Notification for init im sdk succeed
|
||||
*/
|
||||
FOUNDATION_EXTERN NSString *const TUIInitSdkSuccessNotification;
|
||||
|
||||
/**
|
||||
* Notification for init im sdk failed
|
||||
*/
|
||||
FOUNDATION_EXTERN NSString *const TUIInitSdkFailNotification;
|
||||
|
||||
/**
|
||||
* Notification for log-in succeed
|
||||
*/
|
||||
FOUNDATION_EXTERN NSString *const TUILoginSuccessNotification;
|
||||
|
||||
/**
|
||||
* Notification for log-in failed
|
||||
*/
|
||||
FOUNDATION_EXTERN NSString *const TUILoginFailNotification;
|
||||
|
||||
/**
|
||||
* Notification for log-out succeed
|
||||
*/
|
||||
FOUNDATION_EXTERN NSString *const TUILogoutSuccessNotification;
|
||||
|
||||
/**
|
||||
* Notification for log-out failed
|
||||
*/
|
||||
FOUNDATION_EXTERN NSString *const TUILogoutFailNotification;
|
||||
|
||||
@protocol TUILoginListener <NSObject>
|
||||
|
||||
/**
|
||||
* Callback that the SDK is connecting to the server
|
||||
*/
|
||||
- (void)onConnecting;
|
||||
|
||||
/**
|
||||
* Callback that the SDK has successfully connected to the server
|
||||
*/
|
||||
- (void)onConnectSuccess;
|
||||
|
||||
/**
|
||||
* Callback for SDK connection to server failure
|
||||
*/
|
||||
- (void)onConnectFailed:(int)code err:(NSString * __nullable)err;
|
||||
|
||||
/**
|
||||
* The callback of the current user being kicked off, the user can be prompted on the UI at this time, and the login() function of V2TIMManager can be called
|
||||
* again to log in again.
|
||||
*/
|
||||
- (void)onKickedOffline;
|
||||
|
||||
/**
|
||||
* The callback of the login credentials expired when online, you need to generate a new userSig and call the login() function of V2TIMManager again to log in
|
||||
* again.
|
||||
*/
|
||||
- (void)onUserSigExpired;
|
||||
|
||||
@end
|
||||
|
||||
@interface TUILoginConfig : NSObject
|
||||
|
||||
@property(nonatomic, assign) TUILogLevel logLevel;
|
||||
|
||||
@property(nonatomic, copy, nullable) void (^onLog)(NSInteger logLevel, NSString * __nullable logContent);
|
||||
|
||||
@property(nonatomic, assign) BOOL initLocalStorageOnly;
|
||||
|
||||
@end
|
||||
|
||||
@interface TUILogin : NSObject
|
||||
|
||||
+ (void)initWithSdkAppID:(int)sdkAppID __attribute__((deprecated("use login:userID:userSig:succ:fail:")));
|
||||
|
||||
+ (void)login:(NSString *)userID
|
||||
userSig:(NSString *)userSig
|
||||
succ:(__nullable TSucc)succ
|
||||
fail:(__nullable TFail)fail __attribute__((deprecated("use login:userID:userSig:succ:fail:")));
|
||||
|
||||
+ (void)login:(int)sdkAppID
|
||||
userID:(NSString *)userID
|
||||
userSig:(NSString *)userSig
|
||||
succ:(__nullable TSucc)succ
|
||||
fail:(__nullable TFail)fail;
|
||||
|
||||
+ (void)login:(int)sdkAppID
|
||||
userID:(NSString *)userID
|
||||
userSig:(NSString *)userSig
|
||||
config:(TUILoginConfig * __nullable)config
|
||||
succ:(__nullable TSucc)succ
|
||||
fail:(__nullable TFail)fail;
|
||||
|
||||
+ (void)logout:(__nullable TSucc)succ
|
||||
fail:(__nullable TFail)fail;
|
||||
|
||||
+ (void)addLoginListener:(id<TUILoginListener>)listener;
|
||||
+ (void)removeLoginListener:(id<TUILoginListener>)listener;
|
||||
|
||||
+ (int)getSdkAppID;
|
||||
+ (BOOL)isUserLogined;
|
||||
|
||||
+ (NSString * __nullable)getUserID;
|
||||
+ (NSString * __nullable)getUserSig;
|
||||
|
||||
+ (NSString * __nullable)getNickName;
|
||||
+ (NSString * __nullable)getFaceUrl;
|
||||
|
||||
/**
|
||||
* No-thread-safe
|
||||
*/
|
||||
+ (void)setCurrentBusinessScene:(TUIBusinessScene)scene;
|
||||
+ (TUIBusinessScene)getCurrentBusinessScene;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
436
TUIKit/TUICore/TUILogin.m
Normal file
@@ -0,0 +1,436 @@
|
||||
|
||||
// Created by Tencent on 2023/06/09.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
|
||||
#import "TUILogin.h"
|
||||
#import "TUICore.h"
|
||||
#import "TUIDefine.h"
|
||||
|
||||
@import ImSDK_Plus;
|
||||
|
||||
NSString *const TUIInitSdkSuccessNotification = @"TUIInitSdkSuccessNotification";
|
||||
NSString *const TUIInitSdkFailNotification = @"TUIInitSdkFailNotification";
|
||||
NSString *const TUILoginSuccessNotification = @"TUILoginSuccessNotification";
|
||||
NSString *const TUILoginFailNotification = @"TUILoginFailNotification";
|
||||
NSString *const TUILogoutSuccessNotification = @"TUILogoutSuccessNotification";
|
||||
NSString *const TUILogoutFailNotification = @"TUILogoutFailNotification";
|
||||
|
||||
@implementation TUILoginConfig
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
self.logLevel = TUI_LOG_INFO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface TUILogin () <V2TIMSDKListener>
|
||||
|
||||
@property(nonatomic, strong) NSHashTable *loginListenerSet;
|
||||
|
||||
@property(nonatomic, assign) int sdkAppID;
|
||||
@property(nonatomic, copy) NSString *userID;
|
||||
@property(nonatomic, copy) NSString *userSig;
|
||||
@property(nonatomic, copy) NSString *nickName;
|
||||
@property(nonatomic, copy) NSString *faceUrl;
|
||||
@property(nonatomic, assign) BOOL loginWithInit;
|
||||
@property(nonatomic, assign) TUIBusinessScene currentBusinessScene;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUILogin
|
||||
|
||||
#pragma mark - API
|
||||
+ (void)initWithSdkAppID:(int)sdkAppID {
|
||||
[TUILogin.shareInstance initWithSdkAppID:sdkAppID];
|
||||
}
|
||||
|
||||
+ (void)login:(NSString *)userID userSig:(NSString *)userSig succ:(TSucc)succ fail:(TFail)fail {
|
||||
[TUILogin.shareInstance login:userID userSig:userSig succ:succ fail:fail];
|
||||
}
|
||||
|
||||
+ (void)login:(int)sdkAppID userID:(NSString *)userID userSig:(NSString *)userSig succ:(TSucc)succ fail:(TFail)fail {
|
||||
[TUILogin.shareInstance login:sdkAppID userID:userID userSig:userSig config:nil succ:succ fail:fail];
|
||||
}
|
||||
|
||||
+ (void)login:(int)sdkAppID userID:(NSString *)userID userSig:(NSString *)userSig config:(TUILoginConfig *)config succ:(TSucc)succ fail:(TFail)fail {
|
||||
[TUILogin.shareInstance login:sdkAppID userID:userID userSig:userSig config:config succ:succ fail:fail];
|
||||
}
|
||||
|
||||
+ (void)getSelfUserInfo {
|
||||
[TUILogin.shareInstance getSelfUserInfo];
|
||||
}
|
||||
|
||||
+ (void)logout:(TSucc)succ fail:(TFail)fail {
|
||||
[TUILogin.shareInstance logout:succ fail:fail];
|
||||
}
|
||||
|
||||
+ (void)addLoginListener:(id<TUILoginListener>)listener {
|
||||
[TUILogin.shareInstance addLoginListener:listener];
|
||||
}
|
||||
|
||||
+ (void)removeLoginListener:(id<TUILoginListener>)listener {
|
||||
[TUILogin.shareInstance removeLoginListener:listener];
|
||||
}
|
||||
|
||||
+ (int)getSdkAppID {
|
||||
return [TUILogin.shareInstance getSdkAppID];
|
||||
}
|
||||
|
||||
+ (BOOL)isUserLogined {
|
||||
return [V2TIMManager sharedInstance].getLoginStatus == V2TIM_STATUS_LOGINED;
|
||||
}
|
||||
|
||||
+ (NSString *)getUserID {
|
||||
return [TUILogin.shareInstance getUserID];
|
||||
}
|
||||
|
||||
+ (NSString *)getUserSig {
|
||||
return [TUILogin.shareInstance getUserSig];
|
||||
}
|
||||
|
||||
+ (NSString *)getNickName {
|
||||
return [TUILogin.shareInstance getNickName];
|
||||
}
|
||||
|
||||
+ (NSString *)getFaceUrl {
|
||||
return [TUILogin.shareInstance getFaceUrl];
|
||||
}
|
||||
|
||||
+ (void)setCurrentBusinessScene:(TUIBusinessScene)scene {
|
||||
TUILogin.shareInstance.currentBusinessScene = scene;
|
||||
}
|
||||
|
||||
+ (TUIBusinessScene)getCurrentBusinessScene {
|
||||
return TUILogin.shareInstance.currentBusinessScene;
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
+ (instancetype)shareInstance {
|
||||
static id gShareInstance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
gShareInstance = [[self alloc] init];
|
||||
});
|
||||
return gShareInstance;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_loginListenerSet = [NSHashTable weakObjectsHashTable];
|
||||
_sdkAppID = 0;
|
||||
_userID = nil;
|
||||
_userSig = nil;
|
||||
_nickName = nil;
|
||||
_faceUrl = nil;
|
||||
_loginWithInit = NO;
|
||||
_currentBusinessScene = None;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initWithSdkAppID:(int)sdkAppID {
|
||||
if (0 != self.sdkAppID && sdkAppID != self.sdkAppID) {
|
||||
[self logout:nil fail:nil];
|
||||
[[V2TIMManager sharedInstance] unInitSDK];
|
||||
}
|
||||
self.sdkAppID = sdkAppID;
|
||||
V2TIMSDKConfig *config = [[V2TIMSDKConfig alloc] init];
|
||||
config.logLevel = V2TIM_LOG_INFO;
|
||||
|
||||
if ([[V2TIMManager sharedInstance] initSDK:sdkAppID config:config listener:nil]) {
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:TUIInitSdkSuccessNotification object:nil];
|
||||
} else {
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:TUIInitSdkFailNotification object:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)login:(NSString *)userID userSig:(NSString *)userSig succ:(TSucc)succ fail:(TFail)fail {
|
||||
self.userID = userID;
|
||||
self.userSig = userSig;
|
||||
self.loginWithInit = NO;
|
||||
self.currentBusinessScene = None;
|
||||
if ([[[V2TIMManager sharedInstance] getLoginUser] isEqualToString:userID]) {
|
||||
if (succ) {
|
||||
succ();
|
||||
}
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:TUILoginSuccessNotification object:nil];
|
||||
} else {
|
||||
__weak __typeof(self) weakSelf = self;
|
||||
[[V2TIMManager sharedInstance] login:userID
|
||||
userSig:userSig
|
||||
succ:^{
|
||||
__strong __typeof(weakSelf) strongSelf = weakSelf;
|
||||
[strongSelf getSelfUserInfo];
|
||||
if (succ) {
|
||||
succ();
|
||||
}
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:TUILoginSuccessNotification object:nil];
|
||||
}
|
||||
fail:^(int code, NSString *desc) {
|
||||
if (fail) {
|
||||
fail(code, desc);
|
||||
}
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:TUILoginFailNotification object:nil];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)login:(int)sdkAppID userID:(NSString *)userID userSig:(NSString *)userSig config:(TUILoginConfig *)config succ:(TSucc)succ fail:(TFail)fail {
|
||||
self.loginWithInit = YES;
|
||||
self.currentBusinessScene = None;
|
||||
if (0 != self.sdkAppID && sdkAppID != self.sdkAppID) {
|
||||
[self logout:nil fail:nil];
|
||||
[[V2TIMManager sharedInstance] unInitSDK];
|
||||
}
|
||||
|
||||
self.sdkAppID = sdkAppID;
|
||||
self.userID = userID;
|
||||
self.userSig = userSig;
|
||||
|
||||
V2TIMSDKConfig *sdkConfig = [[V2TIMSDKConfig alloc] init];
|
||||
if (config != nil) {
|
||||
sdkConfig.logLevel = (V2TIMLogLevel)config.logLevel;
|
||||
sdkConfig.logListener = ^(V2TIMLogLevel logLevel, NSString *logContent) {
|
||||
if (config.onLog) {
|
||||
config.onLog(logLevel, logContent);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
sdkConfig.logLevel = V2TIM_LOG_INFO;
|
||||
}
|
||||
|
||||
if ([[V2TIMManager sharedInstance] initSDK:sdkAppID config:sdkConfig]) {
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:TUIInitSdkSuccessNotification object:nil];
|
||||
} else {
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:TUIInitSdkFailNotification object:nil];
|
||||
}
|
||||
|
||||
[V2TIMManager.sharedInstance addIMSDKListener:self];
|
||||
|
||||
[[V2TIMManager sharedInstance] callExperimentalAPI:@"getLoginAccountType" param:nil succ:^(NSObject *result) {
|
||||
int accountType = [((NSNumber *)result) intValue];
|
||||
[TUILogin.shareInstance loginImpl:accountType userID:userID userSig:userSig config:config succ:succ fail:fail];
|
||||
} fail:^(int code, NSString *desc) {
|
||||
[TUILogin.shareInstance loginImpl:TUI_ACCOUNT_TYPE_UNKOWN userID:userID userSig:userSig config:config succ:succ fail:fail];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)loginImpl:(int)loginAccountType userID:(NSString *)userID userSig:(NSString *)userSig
|
||||
config:(TUILoginConfig *)config succ:(TSucc)succ fail:(TFail)fail {
|
||||
if ([[[V2TIMManager sharedInstance] getLoginUser] isEqualToString:userID] && loginAccountType == TUI_ACCOUNT_TYPE_IM) {
|
||||
if (succ) {
|
||||
succ();
|
||||
}
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:TUILoginSuccessNotification object:nil];
|
||||
return;
|
||||
}
|
||||
|
||||
if (config && config.initLocalStorageOnly) {
|
||||
[[V2TIMManager sharedInstance] callExperimentalAPI:@"initLocalStorage" param:self.userID succ:^(NSObject *result) {
|
||||
if (succ) {
|
||||
succ();
|
||||
}
|
||||
} fail:^(int code, NSString *desc) {
|
||||
if (fail) {
|
||||
fail(code, desc);
|
||||
}
|
||||
}];
|
||||
return;
|
||||
}
|
||||
|
||||
__weak __typeof(self) weakSelf = self;
|
||||
[[V2TIMManager sharedInstance] login:userID
|
||||
userSig:userSig
|
||||
succ:^{
|
||||
__strong __typeof(weakSelf) strongSelf = weakSelf;
|
||||
[strongSelf getSelfUserInfo];
|
||||
if (succ) {
|
||||
succ();
|
||||
}
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:TUILoginSuccessNotification object:nil];
|
||||
}
|
||||
fail:^(int code, NSString *desc) {
|
||||
self.loginWithInit = NO;
|
||||
if (fail) {
|
||||
fail(code, desc);
|
||||
}
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:TUILoginFailNotification object:nil];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)getSelfUserInfo {
|
||||
if (self.userID == nil) {
|
||||
return;
|
||||
}
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[[V2TIMManager sharedInstance] getUsersInfo:@[ self.userID ]
|
||||
succ:^(NSArray<V2TIMUserFullInfo *> *infoList) {
|
||||
V2TIMUserFullInfo *info = infoList.firstObject;
|
||||
weakSelf.nickName = info.nickName;
|
||||
weakSelf.faceUrl = info.faceURL;
|
||||
}
|
||||
fail:nil];
|
||||
}
|
||||
|
||||
- (void)logout:(TSucc)succ fail:(TFail)fail {
|
||||
self.userID = @"";
|
||||
self.userSig = @"";
|
||||
self.currentBusinessScene = None;
|
||||
[[V2TIMManager sharedInstance]
|
||||
logout:^{
|
||||
if (succ) {
|
||||
succ();
|
||||
}
|
||||
if (self.loginWithInit) {
|
||||
// The new interface is currently used to log in. When logging out, you need to deinitialize and remove the listener.
|
||||
[V2TIMManager.sharedInstance removeIMSDKListener:self];
|
||||
[V2TIMManager.sharedInstance unInitSDK];
|
||||
self.sdkAppID = 0;
|
||||
}
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:TUILogoutSuccessNotification object:nil];
|
||||
}
|
||||
fail:^(int code, NSString *desc) {
|
||||
if (fail) {
|
||||
fail(code, desc);
|
||||
}
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:TUILogoutFailNotification object:nil];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)addLoginListener:(id<TUILoginListener>)listener {
|
||||
if (listener == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
@synchronized(self) {
|
||||
if (![_loginListenerSet.allObjects containsObject:listener]) {
|
||||
[_loginListenerSet addObject:listener];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeLoginListener:(id<TUILoginListener>)listener {
|
||||
if (listener == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
@synchronized(self) {
|
||||
if ([_loginListenerSet.allObjects containsObject:listener]) {
|
||||
[_loginListenerSet removeObject:listener];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (int)getSdkAppID {
|
||||
return self.sdkAppID;
|
||||
}
|
||||
|
||||
- (NSString *)getUserID {
|
||||
return self.userID;
|
||||
}
|
||||
|
||||
- (NSString *)getUserSig {
|
||||
return self.userSig;
|
||||
}
|
||||
|
||||
- (NSString *)getNickName {
|
||||
return self.nickName;
|
||||
}
|
||||
|
||||
- (NSString *)getFaceUrl {
|
||||
return self.faceUrl;
|
||||
}
|
||||
|
||||
- (void)doInMainThread:(dispatch_block_t)callback {
|
||||
if ([NSThread isMainThread]) {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue(), callback);
|
||||
}
|
||||
|
||||
#pragma mark - V2TIMSDKListener
|
||||
- (void)onConnecting {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self doInMainThread:^{
|
||||
for (id<TUILoginListener> listener in weakSelf.loginListenerSet) {
|
||||
if ([listener respondsToSelector:@selector(onConnecting)]) {
|
||||
[listener onConnecting];
|
||||
}
|
||||
}
|
||||
[TUICore notifyEvent:TUICore_NetworkConnection_EVENT_CONNECTION_STATE_CHANGED
|
||||
subKey:TUICore_NetworkConnection_EVENT_SUB_KEY_CONNECTING
|
||||
object:nil
|
||||
param:nil];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)onConnectSuccess {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self doInMainThread:^{
|
||||
for (id<TUILoginListener> listener in weakSelf.loginListenerSet) {
|
||||
if ([listener respondsToSelector:@selector(onConnectSuccess)]) {
|
||||
[listener onConnectSuccess];
|
||||
}
|
||||
}
|
||||
[TUICore notifyEvent:TUICore_NetworkConnection_EVENT_CONNECTION_STATE_CHANGED
|
||||
subKey:TUICore_NetworkConnection_EVENT_SUB_KEY_CONNECT_SUCCESS
|
||||
object:nil
|
||||
param:nil];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)onConnectFailed:(int)code err:(NSString *)err {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self doInMainThread:^{
|
||||
for (id<TUILoginListener> listener in weakSelf.loginListenerSet) {
|
||||
if ([listener respondsToSelector:@selector(onConnectFailed:err:)]) {
|
||||
[listener onConnectFailed:code err:err];
|
||||
}
|
||||
}
|
||||
[TUICore notifyEvent:TUICore_NetworkConnection_EVENT_CONNECTION_STATE_CHANGED
|
||||
subKey:TUICore_NetworkConnection_EVENT_SUB_KEY_CONNECT_FAILED
|
||||
object:nil
|
||||
param:nil];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)onKickedOffline {
|
||||
self.currentBusinessScene = None;
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self doInMainThread:^{
|
||||
for (id<TUILoginListener> listener in weakSelf.loginListenerSet) {
|
||||
if ([listener respondsToSelector:@selector(onKickedOffline)]) {
|
||||
[listener onKickedOffline];
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)onUserSigExpired {
|
||||
self.currentBusinessScene = None;
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self doInMainThread:^{
|
||||
for (id<TUILoginListener> listener in weakSelf.loginListenerSet) {
|
||||
if ([listener respondsToSelector:@selector(onUserSigExpired)]) {
|
||||
[listener onUserSigExpired];
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)onSelfInfoUpdated:(V2TIMUserFullInfo *)info {
|
||||
if (self.userID && self.userID.length > 0 && [self.userID isEqualToString:info.userID]) {
|
||||
self.nickName = info.nickName;
|
||||
self.faceUrl = info.faceURL;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
212
TUIKit/TUICore/TUIThemeManager.h
Normal file
@@ -0,0 +1,212 @@
|
||||
//
|
||||
// TUIThemeManager.h
|
||||
// TUICore
|
||||
//
|
||||
// Created by harvy on 2022/1/5.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
/**
|
||||
*
|
||||
* Storage structure of theme for each module
|
||||
* | The root path of the theme resource(ThemeResourcePath)
|
||||
* |
|
||||
* |------ Theme one(named with theme identifier)
|
||||
* | |
|
||||
* | |------- manifest.plist (configuration information for the theme)
|
||||
* | |------- resource
|
||||
* |-------Theme two
|
||||
* | |
|
||||
* | |------ manifest.plist (configuration information for the theme)
|
||||
* | |------ resource
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "TUIDefine.h"
|
||||
|
||||
@class TUITheme;
|
||||
@class TUIThemeManager;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#define TUIShareThemeManager TUIThemeManager.shareManager
|
||||
|
||||
/**
|
||||
* Notifications when the app's theme has changed
|
||||
*/
|
||||
#define TUIDidApplyingThemeChangedNotfication @"TUIDidApplyingThemeChangedNotfication"
|
||||
#define TUIDidApplyingThemeChangedNotficationThemeKey @"TUIDidApplyingThemeChangedNotficationThemeKey"
|
||||
#define TUIDidApplyingThemeChangedNotficationModuleKey @"TUIDidApplyingThemeChangedNotficationModuleKey"
|
||||
|
||||
/**
|
||||
* Register the theme resource root path of the module
|
||||
*/
|
||||
#define TUIRegisterThemeResourcePath(path, module) [TUIShareThemeManager registerThemeResourcePath:path forModule:module];
|
||||
|
||||
/**
|
||||
* Get the theme used by the module
|
||||
*/
|
||||
#define TUICurrentTheme(module) [TUIShareThemeManager currentThemeForModule:module]
|
||||
|
||||
/**
|
||||
* Get the dark night theme of the module
|
||||
*/
|
||||
#define TUIDarkTheme(module) [TUIShareThemeManager darkThemeForModule:module]
|
||||
|
||||
/**
|
||||
* Get dynamic colors that change with theme
|
||||
*/
|
||||
#define TUIDynamicColor(colorKey, themeModule, defaultHex) [TUITheme dynamicColor:colorKey module:themeModule defaultColor:defaultHex]
|
||||
#define TUIDemoDynamicColor(colorKey, defaultHex) TUIDynamicColor(colorKey, TUIThemeModuleDemo, defaultHex)
|
||||
#define TUICoreDynamicColor(colorKey, defaultHex) TUIDynamicColor(colorKey, TUIThemeModuleCore, defaultHex)
|
||||
#define TUIChatDynamicColor(colorKey, defaultHex) TUIDynamicColor(colorKey, TUIThemeModuleChat, defaultHex)
|
||||
#define TUIConversationDynamicColor(colorKey, defaultHex) TUIDynamicColor(colorKey, TUIThemeModuleConversation, defaultHex)
|
||||
#define TUIConversationGroupDynamicColor(colorKey, defaultHex) TUIDynamicColor(colorKey, TUIThemeModuleConversationGroup, defaultHex)
|
||||
#define TUIContactDynamicColor(colorKey, defaultHex) TUIDynamicColor(colorKey, TUIThemeModuleContact, defaultHex)
|
||||
#define TUISearchDynamicColor(colorKey, defaultHex) TUIDynamicColor(colorKey, TUIThemeModuleSearch, defaultHex)
|
||||
#define TUICallKitDynamicColor(colorKey, defaultHex) TUIDynamicColor(colorKey, TUIThemeModuleCalling, defaultHex)
|
||||
#define TUIPollDynamicColor(colorKey, defaultHex) TUIDynamicColor(colorKey, TUIThemeModulePoll, defaultHex)
|
||||
#define TUIGroupNoteDynamicColor(colorKey, defaultHex) TUIDynamicColor(colorKey, TUIThemeModuleGroupNote, defaultHex)
|
||||
#define TIMCommonDynamicColor(colorKey, defaultHex) TUIDynamicColor(colorKey, TUIThemeModuleTIMCommon, defaultHex)
|
||||
#define TUITranslationDynamicColor(colorKey, defaultHex) TUIDynamicColor(colorKey, TUIThemeModuleTranslation, defaultHex)
|
||||
#define TUIVoiceToTextDynamicColor(colorKey, defaultHex) TUIDynamicColor(colorKey, TUIThemeModuleVoiceToText, defaultHex)
|
||||
#define TUICustomerServicePluginDynamicColor(colorKey, defaultHex) TUIDynamicColor(colorKey, TUIThemeModuleCustomerService, defaultHex)
|
||||
#define TUIMultimediaPluginDynamicColor(colorKey, defaultHex) TUIDynamicColor(colorKey, TUIThemeModuleMultimedia, defaultHex)
|
||||
|
||||
/**
|
||||
* Get dynamic image that change with theme
|
||||
*/
|
||||
#define TUIDemoBundleThemeImage(imageKey, defaultImageName) TUIDemoDynamicImage(imageKey, TUIDemoCommonBundleImage(defaultImageName))
|
||||
#define TUICoreBundleThemeImage(imageKey, defaultImageName) TUICoreDynamicImage(imageKey, TUICoreCommonBundleImage(defaultImageName))
|
||||
#define TUIChatBundleThemeImage(imageKey, defaultImageName) TUIChatDynamicImage(imageKey, TUIChatCommonBundleImage(defaultImageName))
|
||||
#define TUIConversationBundleThemeImage(imageKey, defaultImageName) TUIConversationDynamicImage(imageKey, TUIConversationCommonBundleImage(defaultImageName))
|
||||
#define TUIContactBundleThemeImage(imageKey, defaultImageName) TUIContactDynamicImage(imageKey, TUIContactCommonBundleImage(defaultImageName))
|
||||
#define TUISearchBundleThemeImage(imageKey, defaultImageName) TUISearchDynamicImage(imageKey, TUISearchCommonBundleImage(defaultImageName))
|
||||
#define TUICallingBundleThemeImage(imageKey, defaultImageName) TUICallingDynamicImage(imageKey, TUICallingCommonBundleImage(defaultImageName))
|
||||
#define TUIPollBundleThemeImage(imageKey, defaultImageName) TUIPollDynamicImage(imageKey, TUIPollCommonBundleImage(defaultImageName))
|
||||
#define TUIGroupNoteBundleThemeImage(imageKey, defaultImageName) TUIGroupNoteDynamicImage(imageKey, TUIGroupNoteCommonBundleImage(defaultImageName))
|
||||
#define TIMCommonBundleThemeImage(imageKey, defaultImageName) TIMCommonDynamicImage(imageKey, TIMCommonBundleImage(defaultImageName))
|
||||
#define TUITranslationBundleThemeImage(imageKey, defaultImageName) TUITranslationDynamicImage(imageKey, TUITranslationCommonBundleImage(defaultImageName))
|
||||
#define TUIVoiceToTextBundleThemeImage(imageKey, defaultImageName) TUIVoiceToTextDynamicImage(imageKey, TUIVoiceToTextCommonBundleImage(defaultImageName))
|
||||
#define TUICustomerServicePluginBundleThemeImage(imageKey,defaultImageName) \
|
||||
TUICustomerServicePluginDynamicImage(imageKey,TUICustomerServicePluginCommonBundleImage(defaultImageName))
|
||||
#define TUIMultimediaPluginBundleThemeImage(imageKey, defaultImageName) \
|
||||
TUIMultimediaPluginDynamicImage(imageKey, TUIMultimediaPluginCommonBundleImage(defaultImageName))
|
||||
|
||||
#define TUIDynamicImage(imageKey, themeModule, defaultImg) [TUITheme dynamicImage:imageKey module:themeModule defaultImage:defaultImg]
|
||||
#define TUIDemoDynamicImage(imageKey, defaultImg) TUIDynamicImage(imageKey, TUIThemeModuleDemo, defaultImg)
|
||||
#define TUICoreDynamicImage(imageKey, defaultImg) TUIDynamicImage(imageKey, TUIThemeModuleCore, defaultImg)
|
||||
#define TUIChatDynamicImage(imageKey, defaultImg) TUIDynamicImage(imageKey, TUIThemeModuleChat, defaultImg)
|
||||
#define TUIConversationDynamicImage(imageKey, defaultImg) TUIDynamicImage(imageKey, TUIThemeModuleConversation, defaultImg)
|
||||
#define TUIConversationGroupDynamicImage(imageKey, defaultImg) TUIDynamicImage(imageKey, TUIThemeModuleConversationGroup, defaultImg)
|
||||
#define TUIContactDynamicImage(imageKey, defaultImg) TUIDynamicImage(imageKey, TUIThemeModuleContact, defaultImg)
|
||||
#define TUISearchDynamicImage(imageKey, defaultImg) TUIDynamicImage(imageKey, TUIThemeModuleSearch, defaultImg)
|
||||
#define TUICallingDynamicImage(imageKey, defaultImg) TUIDynamicImage(imageKey, TUIThemeModuleCalling, defaultImg)
|
||||
#define TUIPollDynamicImage(imageKey, defaultImg) TUIDynamicImage(imageKey, TUIThemeModulePoll, defaultImg)
|
||||
#define TUIGroupNoteDynamicImage(imageKey, defaultImg) TUIDynamicImage(imageKey, TUIThemeModuleGroupNote, defaultImg)
|
||||
#define TIMCommonDynamicImage(imageKey, defaultImg) TUIDynamicImage(imageKey, TUIThemeModuleTIMCommon, defaultImg)
|
||||
#define TUITranslationDynamicImage(imageKey, defaultImg) TUIDynamicImage(imageKey, TUIThemeModuleTranslation, defaultImg)
|
||||
#define TUIVoiceToTextDynamicImage(imageKey, defaultImg) TUIDynamicImage(imageKey, TUIThemeModuleVoiceToText, defaultImg)
|
||||
#define TUICustomerServicePluginDynamicImage(imageKey, defaultImg) TUIDynamicImage(imageKey, TUIThemeModuleCustomerService, defaultImg)
|
||||
#define TUIMultimediaPluginDynamicImage(imageKey, defaultImg) TUIDynamicImage(imageKey, TUIThemeModuleMultimedia, defaultImg)
|
||||
|
||||
#define __TUIDefaultBundleImage(imageBundlePath) [UIImage imageWithContentsOfFile:imageBundlePath]
|
||||
#define TUIDemoCommonBundleImage(imageName) __TUIDefaultBundleImage(TUIDemoImagePath(imageName))
|
||||
#define TUICoreCommonBundleImage(imageName) __TUIDefaultBundleImage(TUICoreImagePath(imageName))
|
||||
#define TUIChatCommonBundleImage(imageName) __TUIDefaultBundleImage(TUIChatImagePath(imageName))
|
||||
#define TUIConversationCommonBundleImage(imageName) __TUIDefaultBundleImage(TUIConversationImagePath(imageName))
|
||||
#define TUIContactCommonBundleImage(imageName) __TUIDefaultBundleImage(TUIContactImagePath(imageName))
|
||||
#define TUISearchCommonBundleImage(imageName) __TUIDefaultBundleImage(TUISearchImagePath(imageName))
|
||||
#define TUICallingCommonBundleImage(imageName) __TUIDefaultBundleImage(TUICallingImagePath(imageName))
|
||||
#define TUIPollCommonBundleImage(imageName) __TUIDefaultBundleImage(TUIPollImagePath(imageName))
|
||||
#define TUIGroupNoteCommonBundleImage(imageName) __TUIDefaultBundleImage(TUIGroupNoteImagePath(imageName))
|
||||
#define TIMCommonBundleImage(imageName) __TUIDefaultBundleImage(TIMCommonImagePath(imageName))
|
||||
#define TUITranslationCommonBundleImage(imageName) __TUIDefaultBundleImage(TUITranslationImagePath(imageName))
|
||||
#define TUIVoiceToTextCommonBundleImage(imageName) __TUIDefaultBundleImage(TUIVoiceToTextImagePath(imageName))
|
||||
#define TUICustomerServicePluginCommonBundleImage(imageName) __TUIDefaultBundleImage(TUICustomerServicePluginImagePath(imageName))
|
||||
#define TUIMultimediaPluginCommonBundleImage(imageName) __TUIDefaultBundleImage(TUIMultimediaPluginImagePath(imageName))
|
||||
|
||||
/**
|
||||
* The module of the theme
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, TUIThemeModule) {
|
||||
TUIThemeModuleAll = 0xFFFFFF,
|
||||
TUIThemeModuleDemo = 0x1 << 0,
|
||||
TUIThemeModuleCore = 0x1 << 1,
|
||||
TUIThemeModuleChat = 0x1 << 2,
|
||||
TUIThemeModuleConversation = 0x1 << 3,
|
||||
TUIThemeModuleContact = 0x1 << 4,
|
||||
TUIThemeModuleGroup = 0x1 << 5, // The TUIGroup component has been removed in version 8.4
|
||||
TUIThemeModuleSearch = 0x1 << 6,
|
||||
TUIThemeModuleCalling = 0x1 << 7,
|
||||
|
||||
TUIThemeModuleDemo_Minimalist = 0x1 << 8,
|
||||
TUIThemeModuleCore_Minimalist = 0x1 << 9,
|
||||
TUIThemeModuleChat_Minimalist = 0x1 << 10,
|
||||
TUIThemeModuleConversation_Minimalist = 0x1 << 11,
|
||||
TUIThemeModuleContact_Minimalist = 0x1 << 12,
|
||||
TUIThemeModuleGroup_Minimalist = 0x1 << 13, // The TUIGroup component has been removed in version 8.4
|
||||
TUIThemeModuleSearch_Minimalist = 0x1 << 14,
|
||||
TUIThemeModuleCalling_Minimalist = 0x1 << 15,
|
||||
|
||||
// UI Plugins
|
||||
TUIThemeModulePoll = 0x1 << 16,
|
||||
TUIThemeModuleGroupNote = 0x1 << 17,
|
||||
TUIThemeModuleTIMCommon = 0x1 << 18,
|
||||
TUIThemeModuleTranslation = 0x1 << 19,
|
||||
TUIThemeModuleConversationGroup = 0x1 << 20,
|
||||
TUIThemeModuleVoiceToText = 0x1 << 21,
|
||||
TUIThemeModuleCustomerService = 0x1 << 22,
|
||||
TUIThemeModuleChatBot = 0x1 << 23,
|
||||
|
||||
TUIThemeModuleRoomKit = 0x1 << 24,
|
||||
|
||||
TUIThemeModuleMultimedia = 0x1 << 25,
|
||||
};
|
||||
|
||||
@interface TUITheme : NSObject
|
||||
|
||||
@property(nonatomic, copy) NSString *themeID;
|
||||
@property(nonatomic, assign) TUIThemeModule module;
|
||||
@property(nonatomic, copy, nullable) NSString *themeDesc;
|
||||
@property(nonatomic, strong) NSDictionary *manifest;
|
||||
@property(nonatomic, copy) NSString *resourcePath;
|
||||
|
||||
+ (UIColor *__nullable)dynamicColor:(NSString *)colorKey module:(TUIThemeModule)module defaultColor:(NSString *)hex;
|
||||
+ (UIImage *__nullable)dynamicImage:(NSString *)imageKey module:(TUIThemeModule)module defaultImage:(UIImage *)image;
|
||||
|
||||
@end
|
||||
|
||||
@protocol TUIThemeManagerListener <NSObject>
|
||||
|
||||
/**
|
||||
* Callback for theme changes, you can also listen to the notification named TUIDidApplyingThemeChangedNotfication
|
||||
*/
|
||||
- (void)onApplyTheme:(TUITheme *)theme module:(TUIThemeModule)module;
|
||||
|
||||
- (void)onError:(NSInteger)code message:(NSString *)message userInfo:(NSString *)userInfo;
|
||||
|
||||
@end
|
||||
|
||||
@interface TUIThemeManager : NSObject
|
||||
|
||||
+ (instancetype)shareManager;
|
||||
|
||||
- (void)addListener:(id<TUIThemeManagerListener>)listener;
|
||||
- (void)removeListener:(id<TUIThemeManagerListener>)listener;
|
||||
|
||||
/**
|
||||
* Register the theme resource root path of the module
|
||||
* If the ID of the dark theme is not specified, @"dark" is used internally by default to indicate the dark mode
|
||||
*/
|
||||
- (void)registerThemeResourcePath:(NSString *)path forModule:(TUIThemeModule)module;
|
||||
- (void)registerThemeResourcePath:(NSString *)path darkThemeID:(NSString *)darkThemeID forModule:(TUIThemeModule)module;
|
||||
|
||||
- (TUITheme *)currentThemeForModule:(TUIThemeModule)module;
|
||||
- (TUITheme *)darkThemeForModule:(TUIThemeModule)module;
|
||||
|
||||
- (void)applyTheme:(NSString *)themeID forModule:(TUIThemeModule)module;
|
||||
- (void)unApplyThemeForModule:(TUIThemeModule)module;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
525
TUIKit/TUICore/TUIThemeManager.m
Normal file
@@ -0,0 +1,525 @@
|
||||
//
|
||||
// TUIThemeManager.m
|
||||
// TUICore
|
||||
//
|
||||
// Created by harvy on 2022/1/5.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TUIThemeManager.h"
|
||||
#import "UIColor+TUIHexColor.h"
|
||||
|
||||
@interface TUIDarkThemeRootVC : UIViewController
|
||||
|
||||
@end
|
||||
@implementation TUIDarkThemeRootVC
|
||||
- (BOOL)shouldAutorotate {
|
||||
return NO;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface TUIDarkWindow : UIWindow
|
||||
@property(nonatomic, readonly, class) TUIDarkWindow *sharedInstance;
|
||||
@property(nonatomic, strong) UIWindow *previousKeyWindow;
|
||||
@end
|
||||
@implementation TUIDarkWindow
|
||||
|
||||
+ (void)load {
|
||||
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(windowDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
|
||||
}
|
||||
|
||||
+ (void)windowDidBecomeActive {
|
||||
UIWindow *darkWindow = [self sharedInstance];
|
||||
if (@available(iOS 13.0, *)) {
|
||||
UIScene *scene = UIApplication.sharedApplication.connectedScenes.anyObject;
|
||||
if (scene) {
|
||||
darkWindow.windowScene = (UIWindowScene *)scene;
|
||||
}
|
||||
}
|
||||
[darkWindow setRootViewController:[TUIDarkThemeRootVC new]];
|
||||
darkWindow.hidden = NO;
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)becomeKeyWindow {
|
||||
_previousKeyWindow = [self appKeyWindow];
|
||||
[super becomeKeyWindow];
|
||||
}
|
||||
|
||||
- (void)resignKeyWindow {
|
||||
[super resignKeyWindow];
|
||||
[_previousKeyWindow makeKeyWindow];
|
||||
_previousKeyWindow = nil;
|
||||
}
|
||||
|
||||
- (UIWindow *)appKeyWindow {
|
||||
UIWindow *keywindow = UIApplication.sharedApplication.keyWindow;
|
||||
if (keywindow == nil) {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
for (UIWindowScene *scene in UIApplication.sharedApplication.connectedScenes) {
|
||||
if (scene.activationState == UISceneActivationStateForegroundActive) {
|
||||
UIWindow *tmpWindow = nil;
|
||||
if (@available(iOS 15.0, *)) {
|
||||
tmpWindow = scene.keyWindow;
|
||||
}
|
||||
if (tmpWindow == nil) {
|
||||
for (UIWindow *window in scene.windows) {
|
||||
if (window.windowLevel == UIWindowLevelNormal && window.hidden == NO &&
|
||||
CGRectEqualToRect(window.bounds, UIScreen.mainScreen.bounds)) {
|
||||
tmpWindow = window;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (keywindow == nil) {
|
||||
for (UIWindow *window in UIApplication.sharedApplication.windows) {
|
||||
if (window.windowLevel == UIWindowLevelNormal && window.hidden == NO && CGRectEqualToRect(window.bounds, UIScreen.mainScreen.bounds)) {
|
||||
keywindow = window;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return keywindow;
|
||||
}
|
||||
|
||||
+ (instancetype)sharedInstance {
|
||||
static TUIDarkWindow *shareWindow = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
shareWindow = [[self alloc] init];
|
||||
shareWindow.frame = UIScreen.mainScreen.bounds;
|
||||
shareWindow.userInteractionEnabled = YES;
|
||||
shareWindow.windowLevel = UIWindowLevelNormal - 1;
|
||||
shareWindow.hidden = YES;
|
||||
shareWindow.opaque = NO;
|
||||
shareWindow.backgroundColor = [UIColor clearColor];
|
||||
shareWindow.layer.backgroundColor = [UIColor clearColor].CGColor;
|
||||
});
|
||||
return shareWindow;
|
||||
}
|
||||
|
||||
- (void)setOverrideUserInterfaceStyle:(UIUserInterfaceStyle)overrideUserInterfaceStyle {
|
||||
}
|
||||
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
|
||||
[super traitCollectionDidChange:previousTraitCollection];
|
||||
if (@available(iOS 13.0, *)) {
|
||||
if ([self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection:previousTraitCollection]) {
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:TUIDidApplyingThemeChangedNotfication object:nil];
|
||||
if ([TUIThemeManager.shareManager respondsToSelector:@selector(allListenerExcuteonApplyThemeMethod:module:)]) {
|
||||
[TUIThemeManager.shareManager performSelector:@selector(allListenerExcuteonApplyThemeMethod:module:) withObject:nil withObject:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation TUITheme
|
||||
|
||||
+ (UIColor *)dynamicColor:(NSString *)colorKey module:(TUIThemeModule)module defaultColor:(NSString *)hex {
|
||||
TUITheme *theme = TUICurrentTheme(module);
|
||||
TUITheme *darkTheme = TUIDarkTheme(module);
|
||||
if (theme) {
|
||||
return [theme dynamicColor:colorKey defaultColor:hex];
|
||||
} else {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
return [UIColor colorWithDynamicProvider:^UIColor *_Nonnull(UITraitCollection *_Nonnull traitCollection) {
|
||||
switch (traitCollection.userInterfaceStyle) {
|
||||
case UIUserInterfaceStyleDark:
|
||||
if(darkTheme){
|
||||
return [darkTheme dynamicColor:colorKey defaultColor:hex];
|
||||
}
|
||||
case UIUserInterfaceStyleLight:
|
||||
case UIUserInterfaceStyleUnspecified:
|
||||
default:
|
||||
return [UIColor tui_colorWithHex:hex];
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
return [UIColor tui_colorWithHex:hex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (UIColor *)dynamicColor:(NSString *)colorKey defaultColor:(NSString *)hex {
|
||||
UIColor *color = nil;
|
||||
|
||||
NSString *colorHex = [self.manifest objectForKey:colorKey];
|
||||
if (colorHex && [colorHex isKindOfClass:NSString.class]) {
|
||||
color = [UIColor tui_colorWithHex:colorHex];
|
||||
}
|
||||
|
||||
if (color == nil) {
|
||||
color = [UIColor tui_colorWithHex:hex];
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
+ (UIImage *)dynamicImage:(NSString *)imageKey module:(TUIThemeModule)module defaultImage:(UIImage *)image {
|
||||
TUITheme *theme = TUICurrentTheme(module);
|
||||
TUITheme *darkTheme = TUIDarkTheme(module);
|
||||
if (theme) {
|
||||
return [theme dynamicImage:imageKey defaultImage:image];
|
||||
} else {
|
||||
UIImage *lightImage = image;
|
||||
UIImage *darkImage = [darkTheme dynamicImage:imageKey defaultImage:image];
|
||||
return [self imageWithImageLight:lightImage dark:darkImage];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage *)dynamicImage:(NSString *)imageKey defaultImage:(UIImage *)image {
|
||||
UIImage *dynamic = nil;
|
||||
|
||||
NSString *imageName = [self.manifest objectForKey:imageKey];
|
||||
if ([imageName isKindOfClass:NSString.class]) {
|
||||
imageName = [self.resourcePath stringByAppendingPathComponent:imageName];
|
||||
dynamic = [UIImage imageWithContentsOfFile:imageName];
|
||||
}
|
||||
|
||||
if (dynamic == nil) {
|
||||
dynamic = image;
|
||||
}
|
||||
|
||||
return dynamic;
|
||||
}
|
||||
|
||||
+ (UIImage *)imageWithImageLight:(UIImage *)lightImage dark:(UIImage *)darkImage {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
UITraitCollection *const scaleTraitCollection = [UITraitCollection currentTraitCollection];
|
||||
UITraitCollection *const darkUnscaledTraitCollection = [UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark];
|
||||
UITraitCollection *const darkScaledTraitCollection =
|
||||
[UITraitCollection traitCollectionWithTraitsFromCollections:@[ scaleTraitCollection, darkUnscaledTraitCollection ]];
|
||||
UIImage *image = [lightImage
|
||||
imageWithConfiguration:[lightImage.configuration
|
||||
configurationWithTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight]]];
|
||||
darkImage = [darkImage
|
||||
imageWithConfiguration:[darkImage.configuration
|
||||
configurationWithTraitCollection:[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark]]];
|
||||
[image.imageAsset registerImage:darkImage withTraitCollection:darkScaledTraitCollection];
|
||||
return image;
|
||||
} else {
|
||||
return lightImage;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface TUIThemeManager ()
|
||||
|
||||
/**
|
||||
* The theme resource path of each module, module: theme path
|
||||
*/
|
||||
@property(nonatomic, strong) NSMutableDictionary<NSNumber *, NSString *> *themeResourcePathCache;
|
||||
|
||||
/**
|
||||
* The theme currently used by module, module: theme
|
||||
*/
|
||||
@property(nonatomic, strong) NSMutableDictionary<NSNumber *, TUITheme *> *currentThemeCache;
|
||||
|
||||
/**
|
||||
* The dark theme for each module, if any
|
||||
*/
|
||||
@property(nonatomic, strong) NSMutableDictionary<NSNumber *, TUITheme *> *darkThemeCache;
|
||||
|
||||
@property(nonatomic, strong) NSHashTable *listeners;
|
||||
|
||||
- (void)allListenerExcuteonApplyThemeMethod:(TUITheme *)theme module:(TUIThemeModule)module;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TUIThemeManager
|
||||
#ifdef TUIThreadSafe
|
||||
dispatch_queue_t _queue;
|
||||
dispatch_queue_t _read_write_queue;
|
||||
#endif
|
||||
static id gShareInstance;
|
||||
|
||||
+ (instancetype)shareManager {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
gShareInstance = [[self alloc] init];
|
||||
});
|
||||
return gShareInstance;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
#ifdef TUIThreadSafe
|
||||
_queue = dispatch_queue_create("theme_manager_queue", DISPATCH_QUEUE_SERIAL);
|
||||
_read_write_queue = dispatch_queue_create("read_write_secure_queue", DISPATCH_QUEUE_CONCURRENT);
|
||||
#endif
|
||||
_themeResourcePathCache = [NSMutableDictionary dictionary];
|
||||
_currentThemeCache = [NSMutableDictionary dictionary];
|
||||
_darkThemeCache = [NSMutableDictionary dictionary];
|
||||
_listeners = [NSHashTable weakObjectsHashTable];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addListener:(id<TUIThemeManagerListener>)listener {
|
||||
#ifdef TUIThreadSafe
|
||||
dispatch_async(_queue, ^{
|
||||
#endif
|
||||
if (![self.listeners containsObject:listener]) {
|
||||
[self.listeners addObject:listener];
|
||||
}
|
||||
#ifdef TUIThreadSafe
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)removeListener:(id<TUIThemeManagerListener>)listener {
|
||||
#ifdef TUIThreadSafe
|
||||
dispatch_async(_queue, ^{
|
||||
#endif
|
||||
if ([self.listeners containsObject:listener]) {
|
||||
[self.listeners removeObject:listener];
|
||||
}
|
||||
#ifdef TUIThreadSafe
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)registerThemeResourcePath:(NSString *)path darkThemeID:(NSString *)darkThemeID forModule:(TUIThemeModule)module {
|
||||
if (path.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TUIThreadSafe
|
||||
dispatch_async(_queue, ^{
|
||||
#endif
|
||||
[self.themeResourcePathCache setObject:path forKey:@(module)];
|
||||
|
||||
TUITheme *theme = [self loadTheme:darkThemeID module:module];
|
||||
if (theme) {
|
||||
[self setDarkTheme:theme forModule:module];
|
||||
}
|
||||
#ifdef TUIThreadSafe
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)registerThemeResourcePath:(NSString *)path forModule:(TUIThemeModule)module {
|
||||
[self registerThemeResourcePath:path darkThemeID:@"dark" forModule:module];
|
||||
}
|
||||
|
||||
- (TUITheme *)currentThemeForModule:(TUIThemeModule)module {
|
||||
__block TUITheme *theme = nil;
|
||||
#ifdef TUIThreadSafe
|
||||
dispatch_sync(_read_write_queue, ^{
|
||||
#endif
|
||||
theme = [self.currentThemeCache objectForKey:@(module)];
|
||||
#ifdef TUIThreadSafe
|
||||
});
|
||||
#endif
|
||||
return theme;
|
||||
}
|
||||
|
||||
- (void)setCurrentTheme:(TUITheme *)theme forModule:(TUIThemeModule)module {
|
||||
#ifdef TUIThreadSafe
|
||||
dispatch_barrier_async(_read_write_queue, ^{
|
||||
#endif
|
||||
if ([self.currentThemeCache.allKeys containsObject:@(module)]) {
|
||||
[self.currentThemeCache removeObjectForKey:@(module)];
|
||||
}
|
||||
if (theme) {
|
||||
[self.currentThemeCache setObject:theme forKey:@(module)];
|
||||
}
|
||||
#ifdef TUIThreadSafe
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
- (TUITheme *)darkThemeForModule:(TUIThemeModule)module {
|
||||
__block TUITheme *theme = nil;
|
||||
#ifdef TUIThreadSafe
|
||||
dispatch_sync(_read_write_queue, ^{
|
||||
#endif
|
||||
if ([self.darkThemeCache.allKeys containsObject:@(module)]) {
|
||||
theme = [self.darkThemeCache objectForKey:@(module)];
|
||||
}
|
||||
#ifdef TUIThreadSafe
|
||||
});
|
||||
#endif
|
||||
return theme;
|
||||
}
|
||||
|
||||
- (void)setDarkTheme:(TUITheme *)theme forModule:(TUIThemeModule)module {
|
||||
#ifdef TUIThreadSafe
|
||||
dispatch_barrier_async(_read_write_queue, ^{
|
||||
#endif
|
||||
if ([self.darkThemeCache.allKeys containsObject:@(module)]) {
|
||||
[self.darkThemeCache removeObjectForKey:@(module)];
|
||||
}
|
||||
if (theme) {
|
||||
[self.darkThemeCache setObject:theme forKey:@(module)];
|
||||
}
|
||||
#ifdef TUIThreadSafe
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)applyTheme:(NSString *)themeID forModule:(TUIThemeModule)module {
|
||||
if (themeID.length == 0) {
|
||||
NSLog(@"[theme][applyTheme] invalid themeID, module:%zd", module);
|
||||
return;
|
||||
}
|
||||
#ifdef TUIThreadSafe
|
||||
dispatch_async(_queue, ^{
|
||||
#endif
|
||||
BOOL isAll = NO;
|
||||
NSMutableArray *allKeys = [NSMutableArray arrayWithArray:self.themeResourcePathCache.allKeys];
|
||||
if (module == TUIThemeModuleAll || ((module & TUIThemeModuleAll) == TUIThemeModuleAll)) {
|
||||
isAll = YES;
|
||||
}
|
||||
|
||||
if (isAll) {
|
||||
for (NSNumber *moduleObject in allKeys) {
|
||||
TUIThemeModule tmpModue = (TUIThemeModule)[moduleObject integerValue];
|
||||
[self doApplyTheme:themeID forSingleModule:tmpModue];
|
||||
}
|
||||
} else {
|
||||
for (NSNumber *moduleObject in allKeys) {
|
||||
TUIThemeModule tmpModue = (TUIThemeModule)[moduleObject integerValue];
|
||||
if ((module & tmpModue) == tmpModue) {
|
||||
[self doApplyTheme:themeID forSingleModule:tmpModue];
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef TUIThreadSafe
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)unApplyThemeForModule:(TUIThemeModule)module {
|
||||
#ifdef TUIThreadSafe
|
||||
dispatch_async(_queue, ^{
|
||||
#endif
|
||||
BOOL isAll = NO;
|
||||
NSMutableArray *allKeys = [NSMutableArray arrayWithArray:self.themeResourcePathCache.allKeys];
|
||||
if (module == TUIThemeModuleAll || ((module & TUIThemeModuleAll) == TUIThemeModuleAll)) {
|
||||
isAll = YES;
|
||||
}
|
||||
|
||||
if (isAll) {
|
||||
for (NSNumber *moduleObject in allKeys) {
|
||||
TUIThemeModule tmpModue = (TUIThemeModule)[moduleObject integerValue];
|
||||
[self setCurrentTheme:nil forModule:tmpModue];
|
||||
}
|
||||
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:TUIDidApplyingThemeChangedNotfication object:nil userInfo:nil];
|
||||
} else {
|
||||
for (NSNumber *moduleObject in allKeys) {
|
||||
TUIThemeModule tmpModue = (TUIThemeModule)[moduleObject integerValue];
|
||||
if ((module & tmpModue) == tmpModue) {
|
||||
[self setCurrentTheme:nil forModule:tmpModue];
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef TUIThreadSafe
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma mark - Not thread safe
|
||||
|
||||
- (void)doApplyTheme:(NSString *)themeID forSingleModule:(TUIThemeModule)module {
|
||||
TUITheme *theme = [self loadTheme:themeID module:module];
|
||||
if (theme == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self setCurrentTheme:theme forModule:module];
|
||||
|
||||
[self notifyApplyTheme:theme module:module];
|
||||
}
|
||||
|
||||
- (TUITheme *)loadTheme:(NSString *)themeID module:(TUIThemeModule)module {
|
||||
NSString *themeResourcePath = [self themeResourcePathForModule:module];
|
||||
if (themeResourcePath.length == 0) {
|
||||
NSLog(@"[theme][applyTheme] theme resurce path not set, themeID:%@, module:%zd", themeID, module);
|
||||
return nil;
|
||||
}
|
||||
|
||||
themeResourcePath = [themeResourcePath stringByAppendingPathComponent:themeID];
|
||||
{
|
||||
BOOL isDirectory = NO;
|
||||
BOOL exist = [NSFileManager.defaultManager fileExistsAtPath:themeResourcePath isDirectory:&isDirectory];
|
||||
if (!exist || !isDirectory) {
|
||||
NSLog(@"[theme][applyTheme] invalid theme resurce, themeID:%@, module:%zd", themeID, module);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
NSString *manifestPath = [themeResourcePath stringByAppendingPathComponent:@"manifest.plist"];
|
||||
{
|
||||
BOOL isDirectory = NO;
|
||||
BOOL exist = [NSFileManager.defaultManager fileExistsAtPath:manifestPath isDirectory:&isDirectory];
|
||||
if (!exist || isDirectory) {
|
||||
NSLog(@"[theme][applyTheme] invalid manifest, themeID:%@, module:%zd", themeID, module);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
NSString *resourcePath = [themeResourcePath stringByAppendingPathComponent:@"resource"];
|
||||
{
|
||||
BOOL isDirectory = NO;
|
||||
BOOL exist = [NSFileManager.defaultManager fileExistsAtPath:resourcePath isDirectory:&isDirectory];
|
||||
if (!exist || !isDirectory) {
|
||||
NSLog(@"[theme][applyTheme] invalid resurce, themeID:%@, module:%zd", themeID, module);
|
||||
}
|
||||
}
|
||||
|
||||
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:manifestPath];
|
||||
if (dict == nil) {
|
||||
NSLog(@"[theme][applyTheme] manifest is null");
|
||||
return nil;
|
||||
}
|
||||
TUITheme *theme = [[TUITheme alloc] init];
|
||||
theme.themeID = themeID;
|
||||
theme.module = module;
|
||||
theme.themeDesc = [NSString stringWithFormat:@"theme_%@_%zd", themeID, module];
|
||||
theme.resourcePath = resourcePath;
|
||||
theme.manifest = dict;
|
||||
|
||||
return theme;
|
||||
}
|
||||
|
||||
- (void)notifyApplyTheme:(TUITheme *)theme module:(TUIThemeModule)module {
|
||||
if (theme == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (![NSThread isMainThread]) {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[weakSelf notifyApplyTheme:theme module:module];
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
[self allListenerExcuteonApplyThemeMethod:theme module:module];
|
||||
|
||||
NSDictionary *userInfo = @{TUIDidApplyingThemeChangedNotficationModuleKey : @(module), TUIDidApplyingThemeChangedNotficationThemeKey : theme};
|
||||
[NSNotificationCenter.defaultCenter postNotificationName:TUIDidApplyingThemeChangedNotfication object:nil userInfo:userInfo];
|
||||
}
|
||||
|
||||
- (void)allListenerExcuteonApplyThemeMethod:(TUITheme *)theme module:(TUIThemeModule)module {
|
||||
for (id<TUIThemeManagerListener> listener in self.listeners) {
|
||||
if ([listener respondsToSelector:@selector(onApplyTheme:module:)]) {
|
||||
[listener onApplyTheme:theme module:module];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)themeResourcePathForModule:(TUIThemeModule)module {
|
||||
if ([self.themeResourcePathCache.allKeys containsObject:@(module)]) {
|
||||
return [self.themeResourcePathCache objectForKey:@(module)];
|
||||
}
|
||||
return @"";
|
||||
}
|
||||
|
||||
@end
|
||||
67
TUIKit/TUICore/TUITool.h
Normal file
@@ -0,0 +1,67 @@
|
||||
|
||||
// Created by Tencent on 2023/06/09.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#define IS_NOT_EMPTY_NSSTRING(__X__) (__X__ && [__X__ isKindOfClass:[NSString class]] && ![__X__ isEqualToString:@""])
|
||||
|
||||
typedef void (^TAsyncImageComplete)(NSString *path, UIImage *image);
|
||||
|
||||
@interface TUITool : NSObject
|
||||
// json & str & data
|
||||
+ (NSData *)dictionary2JsonData:(NSDictionary *)dict;
|
||||
+ (NSString *)dictionary2JsonStr:(NSDictionary *)dict;
|
||||
+ (NSDictionary *)jsonSring2Dictionary:(NSString *)jsonString;
|
||||
+ (NSDictionary *)jsonData2Dictionary:(NSData *)jsonData;
|
||||
|
||||
// toast
|
||||
+ (void)makeToast:(NSString *)str;
|
||||
+ (void)makeToast:(NSString *)str duration:(NSTimeInterval)duration;
|
||||
+ (void)makeToast:(NSString *)str duration:(NSTimeInterval)duration position:(CGPoint)position;
|
||||
+ (void)makeToast:(NSString *)str duration:(NSTimeInterval)duration idposition:(id)position;
|
||||
+ (void)makeToastError:(NSInteger)error msg:(NSString *)msg;
|
||||
+ (void)hideToast;
|
||||
+ (void)makeToastActivity;
|
||||
+ (void)hideToastActivity;
|
||||
|
||||
+ (void)dispatchMainAsync:(dispatch_block_t)block;
|
||||
|
||||
// date
|
||||
+ (NSString *)convertDateToStr:(NSDate *)date;
|
||||
+ (NSString *)convertDateToHMStr:(NSDate *)date;
|
||||
|
||||
// msg code convert
|
||||
+ (NSString *)convertIMError:(NSInteger)code msg:(NSString *)msg;
|
||||
+ (void)configIMErrorMap;
|
||||
|
||||
+ (NSString *)genImageName:(NSString *)uuid;
|
||||
+ (NSString *)genImageExtenionName:(UIImage *)image;
|
||||
+ (NSString *)genSnapshotName:(NSString *)uuid;
|
||||
+ (NSString *)genVideoName:(NSString *)uuid;
|
||||
+ (NSString *)genFileName:(NSString *)uuid;
|
||||
+ (NSString *)genVoiceName:(NSString *)uuid withExtension:(NSString *)extent;
|
||||
+ (void)asyncDecodeImage:(NSString *)path complete:(TAsyncImageComplete)complete;
|
||||
|
||||
+ (NSString *)deviceModel;
|
||||
+ (NSString *)deviceVersion;
|
||||
+ (NSString *)deviceName;
|
||||
|
||||
+ (void)openLinkWithURL:(NSURL *)url;
|
||||
|
||||
+ (void)showUnsupportAlertOfService:(NSString *)service onVC:(UIViewController *)vc;
|
||||
+ (void)postUnsupportNotificationOfService:(NSString *)service;
|
||||
+ (void)postUnsupportNotificationOfService:(NSString *)service serviceDesc:(NSString *)serviceDesc debugOnly:(BOOL)debugOnly;
|
||||
+ (void)addUnsupportNotificationInVC:(UIViewController *)vc;
|
||||
+ (void)addUnsupportNotificationInVC:(UIViewController *)vc debugOnly:(BOOL)debugOnly;
|
||||
|
||||
+ (void)addValueAddedUnsupportNeedContactNotificationInVC:(UIViewController *)vc debugOnly:(BOOL)debugOnly;
|
||||
+ (void)addValueAddedUnsupportNeedPurchaseNotificationInVC:(UIViewController *)vc debugOnly:(BOOL)debugOnly;
|
||||
+ (void)postValueAddedUnsupportNeedContactNotification:(NSString *)service;
|
||||
+ (void)postValueAddedUnsupportNeedPurchaseNotification:(NSString *)service;
|
||||
|
||||
+ (void)checkCommercialAbility:(long long)param succ:(void (^)(BOOL enabled))succ fail:(void (^)(int code, NSString *desc))fail;
|
||||
|
||||
+ (UIWindow *)applicationKeywindow;
|
||||
|
||||
@end
|
||||
1090
TUIKit/TUICore/TUITool.m
Normal file
21
TUIKit/TUICore/TUIWeakProxy.h
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// TUIWeakProxy.h
|
||||
// TUICore
|
||||
//
|
||||
// Created by harvy on 2023/4/17.
|
||||
// Copyright (c) 2023 Tencent. All rights reserved.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TUIWeakProxy : NSProxy
|
||||
|
||||
@property(nonatomic, weak, readonly, nullable) id target;
|
||||
|
||||
- (nonnull instancetype)initWithTarget:(nonnull id)target;
|
||||
+ (nonnull instancetype)proxyWithTarget:(nonnull id)target;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
78
TUIKit/TUICore/TUIWeakProxy.m
Normal file
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// TUIWeakProxy.m
|
||||
// TUICore
|
||||
//
|
||||
// Created by harvy on 2023/4/17.
|
||||
// Copyright (c) 2023 Tencent. All rights reserved.
|
||||
|
||||
#import "TUIWeakProxy.h"
|
||||
|
||||
@implementation TUIWeakProxy
|
||||
|
||||
- (instancetype)initWithTarget:(id)target {
|
||||
_target = target;
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)proxyWithTarget:(id)target {
|
||||
return [[self alloc] initWithTarget:target];
|
||||
}
|
||||
|
||||
- (id)forwardingTargetForSelector:(SEL)selector {
|
||||
return _target;
|
||||
}
|
||||
|
||||
- (void)forwardInvocation:(NSInvocation *)invocation {
|
||||
void *null = NULL;
|
||||
[invocation setReturnValue:&null];
|
||||
}
|
||||
|
||||
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
|
||||
return [NSObject instanceMethodSignatureForSelector:@selector(init)];
|
||||
}
|
||||
|
||||
- (BOOL)respondsToSelector:(SEL)aSelector {
|
||||
return [_target respondsToSelector:aSelector];
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
return [_target isEqual:object];
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
return [_target hash];
|
||||
}
|
||||
|
||||
- (Class)superclass {
|
||||
return [_target superclass];
|
||||
}
|
||||
|
||||
- (Class)class {
|
||||
return [_target class];
|
||||
}
|
||||
|
||||
- (BOOL)isKindOfClass:(Class)aClass {
|
||||
return [_target isKindOfClass:aClass];
|
||||
}
|
||||
|
||||
- (BOOL)isMemberOfClass:(Class)aClass {
|
||||
return [_target isMemberOfClass:aClass];
|
||||
}
|
||||
|
||||
- (BOOL)conformsToProtocol:(Protocol *)aProtocol {
|
||||
return [_target conformsToProtocol:aProtocol];
|
||||
}
|
||||
|
||||
- (BOOL)isProxy {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [_target description];
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription {
|
||||
return [_target debugDescription];
|
||||
}
|
||||
|
||||
@end
|
||||