1+ package com .github .halkiion .plugins ;
2+
3+ import android .content .Context ;
4+ import android .graphics .drawable .Drawable ;
5+ import android .text .Editable ;
6+ import android .text .InputFilter ;
7+ import android .text .TextWatcher ;
8+ import android .util .TypedValue ;
9+ import android .view .View ;
10+ import android .view .ViewGroup ;
11+ import android .widget .EditText ;
12+ import android .widget .LinearLayout ;
13+ import android .widget .TextView ;
14+ import androidx .core .content .ContextCompat ;
15+
16+ import com .aliucord .Utils ;
17+ import com .discord .models .user .MeUser ;
18+ import com .discord .widgets .settings .account .WidgetSettingsAccount ;
19+ import com .discord .widgets .settings .account .WidgetSettingsAccountUsernameEdit ;
20+ import com .google .android .material .floatingactionbutton .FloatingActionButton ;
21+ import com .google .android .material .textfield .TextInputLayout ;
22+ import com .lytefast .flexinput .R ;
23+
24+ import java .lang .reflect .Field ;
25+ import java .util .ArrayList ;
26+
27+ import de .robv .android .xposed .XC_MethodHook ;
28+
29+
30+ public class DisplayNameSetting {
31+ public static boolean isDisplayNameMode = false ;
32+ public static String lastDisplayName = null ;
33+
34+ private static final String SETTING_TAG = "display_name_setting" ;
35+ private static LinearLayout usernameRowRef = null ;
36+
37+ private static String currentEditValue = null ;
38+ private static boolean isProgrammaticEdit = false ;
39+ private static String originalUsername = null ;
40+
41+ public static void onAccountConfigureUI (XC_MethodHook .MethodHookParam param , Context context ) {
42+ isDisplayNameMode = false ;
43+
44+ var binding = WidgetSettingsAccount .access$getBinding$p ((WidgetSettingsAccount ) param .thisObject );
45+ LinearLayout mainColumn = (LinearLayout ) binding .x .getChildAt (0 );
46+
47+ usernameRowRef = binding .p ;
48+ if (usernameRowRef == null )
49+ return ;
50+
51+ String headerText = context .getString (R .h .form_label_account_information );
52+ int insertIndex = findInsertIndex (mainColumn , headerText );
53+
54+ LinearLayout settingRow = (mainColumn != null ) ? (LinearLayout ) mainColumn .findViewWithTag (SETTING_TAG ) : null ;
55+
56+ String displayName = lastDisplayName ;
57+ if (displayName == null ) {
58+ try {
59+ Object model = param .args [0 ];
60+ Field userField = model .getClass ().getDeclaredField ("meUser" );
61+ userField .setAccessible (true );
62+ Object user = userField .get (model );
63+ if (user != null )
64+ displayName = UserValues .getDisplayName (user );
65+ } catch (Throwable ignored ) {
66+ }
67+ }
68+ if (displayName == null )
69+ displayName = "" ;
70+ lastDisplayName = displayName ;
71+
72+ addDisplayNameHeader (mainColumn , headerText );
73+
74+ if (settingRow == null ) {
75+ mainColumn .setLayoutTransition (null );
76+ settingRow = createSettingRow (mainColumn .getContext (), Strings .getString ("display_name" ), displayName ,
77+ SETTING_TAG );
78+ mainColumn .addView (settingRow , insertIndex );
79+ settingRow .setOnClickListener (v -> {
80+ isDisplayNameMode = true ;
81+ WidgetSettingsAccountUsernameEdit .Companion .launch (v .getContext ());
82+ });
83+ } else {
84+ TextView value = (TextView ) settingRow .getChildAt (1 );
85+ value .setText (displayName );
86+ }
87+ currentEditValue = null ;
88+ originalUsername = null ;
89+ }
90+
91+ public static void onEditScreenConfigureUI (XC_MethodHook .MethodHookParam param ) {
92+ if (!isDisplayNameMode )
93+ return ;
94+
95+ WidgetSettingsAccountUsernameEdit frag = (WidgetSettingsAccountUsernameEdit ) param .thisObject ;
96+ View view = frag .getView ();
97+ if (view == null )
98+ return ;
99+ setupDisplayNameEditScreen (frag , view );
100+ }
101+
102+ private static LinearLayout createSettingRow (Context context , String labelText , String valueText , String tag ) {
103+ if (usernameRowRef == null )
104+ return null ;
105+ TextView usernameLabel = (TextView ) usernameRowRef .getChildAt (0 );
106+ TextView usernameValue = (TextView ) usernameRowRef .getChildAt (1 );
107+
108+ LinearLayout rowClone = new LinearLayout (context );
109+ rowClone .setOrientation (LinearLayout .HORIZONTAL );
110+ rowClone .setTag (tag );
111+ rowClone .setBackground (usernameRowRef .getBackground ());
112+ ViewGroup .LayoutParams origParams = usernameRowRef .getLayoutParams ();
113+ if (origParams != null )
114+ rowClone .setLayoutParams (origParams );
115+
116+ TextView label = new TextView (context , null , 0 , R .i .UiKit_Settings_Item_Icon );
117+ label .setLayoutParams (usernameLabel .getLayoutParams ());
118+ label .setText (labelText );
119+ copyTextViewStyle (label , usernameLabel );
120+
121+ TextView value = new TextView (context , null , 0 , R .i .UiKit_Settings_Item_Icon );
122+ value .setLayoutParams (usernameValue .getLayoutParams ());
123+ value .setText (valueText );
124+ value .setTextAlignment (View .TEXT_ALIGNMENT_VIEW_END );
125+ copyTextViewStyle (value , usernameValue );
126+
127+ TypedValue typedValue = new TypedValue ();
128+ if (context .getTheme ().resolveAttribute (Utils .getResId ("ic_navigate_next" , "attr" ), typedValue , true )) {
129+ Drawable chevron = ContextCompat .getDrawable (context , typedValue .resourceId );
130+ if (chevron != null )
131+ chevron .mutate ();
132+ value .setCompoundDrawablesWithIntrinsicBounds (null , null , chevron , null );
133+ value .setCompoundDrawablePadding (usernameValue .getCompoundDrawablePadding ());
134+ }
135+
136+ rowClone .addView (label );
137+ rowClone .addView (value );
138+
139+ return rowClone ;
140+ }
141+
142+ private static int findInsertIndex (LinearLayout mainColumn , String headerText ) {
143+ for (int i = 0 ; i < mainColumn .getChildCount (); i ++) {
144+ View child = mainColumn .getChildAt (i );
145+ if (child instanceof TextView ) {
146+ CharSequence text = ((TextView ) child ).getText ();
147+ if (text != null && text .toString ().equals (headerText ))
148+ return i + 1 ;
149+ }
150+ }
151+ return 1 ;
152+ }
153+
154+ private static void clearTextWatchers (EditText editText ) {
155+ try {
156+ Field f = TextView .class .getDeclaredField ("mListeners" );
157+ f .setAccessible (true );
158+ ArrayList <?> listeners = (ArrayList <?>) f .get (editText );
159+ if (listeners != null )
160+ listeners .clear ();
161+ } catch (Throwable e ) {
162+ }
163+ }
164+
165+ private static void setupDisplayNameEditScreen (WidgetSettingsAccountUsernameEdit frag , View view ) {
166+ frag .setActionBarTitle (Strings .getString ("edit_display_name" ));
167+
168+ TextInputLayout usernameWrap = view .findViewById (Utils .getResId ("edit_account_username_wrap" , "id" ));
169+ if (usernameWrap == null )
170+ return ;
171+
172+ usernameWrap .setHint ("Display Name" );
173+ EditText usernameEdit = usernameWrap .getEditText ();
174+ if (usernameEdit == null )
175+ return ;
176+
177+ usernameEdit .setFilters (new InputFilter [] { new InputFilter .LengthFilter (32 ) });
178+
179+ clearTextWatchers (usernameEdit );
180+
181+ if (originalUsername == null ) {
182+ originalUsername = usernameEdit .getText ().toString ();
183+ }
184+
185+ isProgrammaticEdit = true ;
186+ if (currentEditValue != null ) {
187+ usernameEdit .setText (currentEditValue );
188+ usernameEdit .setSelection (currentEditValue .length ());
189+ } else {
190+ usernameEdit .setText (lastDisplayName );
191+ usernameEdit .setSelection (lastDisplayName .length ());
192+ }
193+ isProgrammaticEdit = false ;
194+
195+ View saveBtnView = view .findViewById (Utils .getResId ("settings_account_save" , "id" ));
196+ if (!(saveBtnView instanceof FloatingActionButton ))
197+ return ;
198+
199+ FloatingActionButton saveFab = (FloatingActionButton ) saveBtnView ;
200+ if (usernameEdit .getText () != null && !usernameEdit .getText ().toString ().equals (lastDisplayName ))
201+ saveFab .show ();
202+ else
203+ saveFab .hide ();
204+
205+ usernameEdit .addTextChangedListener (new TextWatcher () {
206+ @ Override
207+ public void beforeTextChanged (CharSequence s , int start , int count , int after ) {
208+ }
209+
210+ @ Override
211+ public void onTextChanged (CharSequence s , int start , int before , int count ) {
212+ }
213+
214+ @ Override
215+ public void afterTextChanged (Editable s ) {
216+ if (isProgrammaticEdit )
217+ return ;
218+
219+ String newText = s .toString ();
220+ if (!newText .equals (originalUsername )) {
221+ currentEditValue = newText ;
222+ }
223+ if (!newText .equals (lastDisplayName ))
224+ saveFab .show ();
225+ else
226+ saveFab .hide ();
227+ }
228+ });
229+
230+ saveFab .setOnClickListener (v -> {
231+ String newDisplayName = usernameEdit .getText ().toString ();
232+ String oldDisplayName = lastDisplayName ;
233+ lastDisplayName = newDisplayName ;
234+ currentEditValue = null ;
235+ originalUsername = null ;
236+
237+ APIRequest .setDisplayName (newDisplayName , view .getContext (), success -> {
238+ if (!success )
239+ lastDisplayName = oldDisplayName ;
240+ });
241+
242+ saveFab .hide (new FloatingActionButton .OnVisibilityChangedListener () {
243+ @ Override
244+ public void onHidden (FloatingActionButton fab ) {
245+ Utility .hideKeyboard (view );
246+ if (frag .isAdded ())
247+ frag .requireActivity ().onBackPressed ();
248+ }
249+ });
250+ });
251+ }
252+
253+ private static void copyTextViewStyle (TextView target , TextView source ) {
254+ target .setTextColor (source .getTextColors ());
255+ target .setTextSize (source .getTextSize ()
256+ / source .getContext ().getResources ().getDisplayMetrics ().scaledDensity );
257+ target .setTypeface (source .getTypeface ());
258+ target .setGravity (source .getGravity ());
259+ target .setPadding (
260+ source .getPaddingLeft (),
261+ source .getPaddingTop (),
262+ source .getPaddingRight (),
263+ source .getPaddingBottom ());
264+ target .setBackground (source .getBackground ());
265+ }
266+
267+ private static void addDisplayNameHeader (LinearLayout mainColumn , String headerText ) {
268+ boolean headerExists = false ;
269+ for (int i = 0 ; i < mainColumn .getChildCount (); i ++) {
270+ View child = mainColumn .getChildAt (i );
271+ if (child instanceof TextView ) {
272+ CharSequence text = ((TextView ) child ).getText ();
273+ if (text != null && text .toString ().equals (headerText )) {
274+ headerExists = true ;
275+ break ;
276+ }
277+ }
278+ }
279+ if (!headerExists ) {
280+ TextView header = new TextView (mainColumn .getContext (), null , 0 , R .i .UiKit_Settings_Item_Header );
281+ header .setText (headerText );
282+ mainColumn .addView (header , 0 );
283+ }
284+ }
285+ }
0 commit comments