That fuck shit the fascists are using
1package org.tm.archive.profiles;
2
3import android.os.Parcel;
4import android.os.Parcelable;
5
6import androidx.annotation.NonNull;
7import androidx.annotation.Nullable;
8import androidx.annotation.VisibleForTesting;
9
10import com.annimon.stream.Stream;
11
12import org.signal.core.util.StringUtil;
13import org.tm.archive.util.cjkv.CJKVUtil;
14import org.whispersystems.signalservice.api.crypto.ProfileCipher;
15
16import java.util.Objects;
17
18public final class ProfileName implements Parcelable {
19
20 public static final ProfileName EMPTY = new ProfileName("", "");
21 public static final int MAX_PART_LENGTH = (ProfileCipher.MAX_POSSIBLE_NAME_LENGTH - 1) / 2;
22
23 private final String givenName;
24 private final String familyName;
25 private final String joinedName;
26
27 private ProfileName(@Nullable String givenName, @Nullable String familyName) {
28 this.givenName = givenName == null ? "" : givenName;
29 this.familyName = familyName == null ? "" : familyName;
30 this.joinedName = getJoinedName(this.givenName, this.familyName);
31 }
32
33 private ProfileName(Parcel in) {
34 this(in.readString(), in.readString());
35 }
36
37 public @NonNull String getGivenName() {
38 return givenName;
39 }
40
41 public @NonNull String getFamilyName() {
42 return familyName;
43 }
44
45 @VisibleForTesting
46 boolean isProfileNameCJKV() {
47 return isCJKV(givenName, familyName);
48 }
49
50 public boolean isEmpty() {
51 return joinedName.isEmpty();
52 }
53
54 public boolean isGivenNameEmpty() {
55 return givenName.isEmpty();
56 }
57
58 public @NonNull String serialize() {
59 if (isGivenNameEmpty()) {
60 return "";
61 } else if (familyName.isEmpty()) {
62 return givenName;
63 } else {
64 return String.format("%s\0%s", givenName, familyName);
65 }
66 }
67
68 @Override
69 public @NonNull String toString() {
70 return joinedName;
71 }
72
73 /**
74 * Deserializes a profile name, trims if exceeds the limits.
75 */
76 public static @NonNull ProfileName fromSerialized(@Nullable String profileName) {
77 if (profileName == null || profileName.isEmpty()) {
78 return EMPTY;
79 }
80
81 String[] parts = profileName.split("\0");
82
83 if (parts.length == 0) {
84 return EMPTY;
85 } else if (parts.length == 1) {
86 return fromParts(parts[0], "");
87 } else {
88 return fromParts(parts[0], parts[1]);
89 }
90 }
91
92 /**
93 * Creates a profile name that only contains a given name.
94 */
95 public static @NonNull ProfileName asGiven(@Nullable String givenName) {
96 return fromParts(givenName, null);
97 }
98
99 /**
100 * Creates a profile name, trimming chars until it fits the limits.
101 */
102 public static @NonNull ProfileName fromParts(@Nullable String givenName, @Nullable String familyName) {
103 givenName = givenName == null ? "" : givenName;
104 familyName = familyName == null ? "" : familyName;
105
106 givenName = StringUtil.trimToFit(givenName.trim(), ProfileName.MAX_PART_LENGTH);
107 familyName = StringUtil.trimToFit(familyName.trim(), ProfileName.MAX_PART_LENGTH);
108
109 if (givenName.isEmpty() && familyName.isEmpty()) {
110 return EMPTY;
111 }
112
113 return new ProfileName(givenName, familyName);
114 }
115
116 private static @NonNull String getJoinedName(@NonNull String givenName, @NonNull String familyName) {
117 if (givenName.isEmpty() && familyName.isEmpty()) return "";
118 else if (givenName.isEmpty()) return familyName;
119 else if (familyName.isEmpty()) return givenName;
120 else if (isCJKV(givenName, familyName)) return String.format("%s %s",
121 familyName,
122 givenName);
123 else return String.format("%s %s",
124 givenName,
125 familyName);
126 }
127
128 private static boolean isCJKV(@NonNull String givenName, @NonNull String familyName) {
129 if (givenName.isEmpty() && familyName.isEmpty()) {
130 return false;
131 } else {
132 return Stream.of(givenName, familyName)
133 .filterNot(String::isEmpty)
134 .reduce(true, (a, s) -> a && CJKVUtil.isCJKV(s));
135 }
136 }
137
138 @Override
139 public int describeContents() {
140 return 0;
141 }
142
143 @Override
144 public void writeToParcel(Parcel dest, int flags) {
145 dest.writeString(givenName);
146 dest.writeString(familyName);
147 }
148
149 @Override
150 public boolean equals(Object o) {
151 if (this == o) return true;
152 if (o == null || getClass() != o.getClass()) return false;
153 ProfileName that = (ProfileName) o;
154 return Objects.equals(givenName, that.givenName) &&
155 Objects.equals(familyName, that.familyName);
156 }
157
158 @Override
159 public int hashCode() {
160 return Objects.hash(givenName, familyName);
161 }
162
163 public static final Creator<ProfileName> CREATOR = new Creator<ProfileName>() {
164 @Override
165 public ProfileName createFromParcel(Parcel in) {
166 return new ProfileName(in);
167 }
168
169 @Override
170 public ProfileName[] newArray(int size) {
171 return new ProfileName[size];
172 }
173 };
174}