That fuck shit the fascists are using
1package org.tm.archive.help;
2
3import android.content.Intent;
4import android.net.Uri;
5import android.os.Bundle;
6import android.view.LayoutInflater;
7import android.view.View;
8import android.view.ViewGroup;
9import android.view.animation.AnimationUtils;
10import android.widget.AdapterView;
11import android.widget.ArrayAdapter;
12import android.widget.CheckBox;
13import android.widget.EditText;
14import android.widget.Spinner;
15import android.widget.Toast;
16
17import androidx.annotation.IdRes;
18import androidx.annotation.NonNull;
19import androidx.annotation.Nullable;
20import androidx.annotation.StringRes;
21import androidx.lifecycle.ViewModelProvider;
22
23import com.annimon.stream.Stream;
24
25import org.signal.core.util.ResourceUtil;
26import org.tm.archive.LoggingFragment;
27import org.tm.archive.R;
28import org.tm.archive.components.emoji.EmojiImageView;
29import org.tm.archive.util.CommunicationActions;
30import org.tm.archive.util.SupportEmailUtil;
31import org.tm.archive.util.Util;
32import org.tm.archive.util.text.AfterTextChanged;
33import org.tm.archive.util.views.CircularProgressMaterialButton;
34
35import java.util.ArrayList;
36import java.util.List;
37
38public class HelpFragment extends LoggingFragment {
39
40 public static final String START_CATEGORY_INDEX = "start_category_index";
41 public static final int PAYMENT_INDEX = 6;
42 public static final int DONATION_INDEX = 7;
43 public static final int SMS_EXPORT_INDEX = 8;
44
45 private EditText problem;
46 private CheckBox includeDebugLogs;
47 private View debugLogInfo;
48 private View faq;
49 private CircularProgressMaterialButton next;
50 private View toaster;
51 private List<EmojiImageView> emoji;
52 private HelpViewModel helpViewModel;
53 private Spinner categorySpinner;
54 private ArrayAdapter<CharSequence> categoryAdapter;
55
56 @Override
57 public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
58 return inflater.inflate(R.layout.help_fragment, container, false);
59 }
60
61 @Override
62 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
63 initializeViewModels();
64 initializeViews(view);
65 initializeListeners();
66 initializeObservers();
67 }
68
69 @Override
70 public void onResume() {
71 super.onResume();
72
73 next.cancelSpinning();
74 problem.setEnabled(true);
75 }
76
77 private void initializeViewModels() {
78 helpViewModel = new ViewModelProvider(this).get(HelpViewModel.class);
79 }
80
81 private void initializeViews(@NonNull View view) {
82 problem = view.findViewById(R.id.help_fragment_problem);
83 includeDebugLogs = view.findViewById(R.id.help_fragment_debug);
84 debugLogInfo = view.findViewById(R.id.help_fragment_debug_info);
85 faq = view.findViewById(R.id.help_fragment_faq);
86 next = view.findViewById(R.id.help_fragment_next);
87 toaster = view.findViewById(R.id.help_fragment_next_toaster);
88 categorySpinner = view.findViewById(R.id.help_fragment_category);
89 emoji = new ArrayList<>(Feeling.values().length);
90
91 for (Feeling feeling : Feeling.values()) {
92 EmojiImageView emojiView = view.findViewById(feeling.getViewId());
93 emojiView.setImageEmoji(feeling.getEmojiCode());
94 emoji.add(view.findViewById(feeling.getViewId()));
95 }
96
97 categoryAdapter = ArrayAdapter.createFromResource(requireContext(), R.array.HelpFragment__categories_5, android.R.layout.simple_spinner_item);
98 categoryAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
99
100 categorySpinner.setAdapter(categoryAdapter);
101
102 Bundle args = getArguments();
103 if (args != null) {
104 categorySpinner.setSelection(Util.clamp(args.getInt(START_CATEGORY_INDEX, 0), 0, categorySpinner.getCount() - 1));
105 }
106 }
107
108 private void initializeListeners() {
109 problem.addTextChangedListener(new AfterTextChanged(e -> helpViewModel.onProblemChanged(e.toString())));
110 Stream.of(emoji).forEach(view -> view.setOnClickListener(this::handleEmojiClicked));
111 faq.setOnClickListener(v -> launchFaq());
112 debugLogInfo.setOnClickListener(v -> launchDebugLogInfo());
113 next.setOnClickListener(v -> submitForm());
114 toaster.setOnClickListener(v -> {
115 if (helpViewModel.getCategoryIndex() == 0) {
116 categorySpinner.startAnimation(AnimationUtils.loadAnimation(requireContext(), R.anim.shake_horizontal));
117 }
118
119 Toast.makeText(requireContext(), R.string.HelpFragment__please_be_as_descriptive_as_possible, Toast.LENGTH_LONG).show();
120 });
121 categorySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
122 @Override
123 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
124 helpViewModel.onCategorySelected(position);
125 }
126
127 @Override
128 public void onNothingSelected(AdapterView<?> parent) {
129 }
130 });
131 }
132
133 private void initializeObservers() {
134 //noinspection CodeBlock2Expr
135 helpViewModel.isFormValid().observe(getViewLifecycleOwner(), isValid -> {
136 next.setEnabled(isValid);
137 toaster.setVisibility(isValid ? View.GONE : View.VISIBLE);
138 });
139 }
140
141 private void handleEmojiClicked(@NonNull View clicked) {
142 if (clicked.isSelected()) {
143 clicked.setSelected(false);
144 } else {
145 Stream.of(emoji).forEach(view -> view.setSelected(false));
146 clicked.setSelected(true);
147 }
148 }
149
150 private void launchFaq() {
151 Uri data = Uri.parse(getString(R.string.HelpFragment__link__faq));
152 Intent intent = new Intent(Intent.ACTION_VIEW, data);
153
154 startActivity(intent);
155 }
156
157 private void launchDebugLogInfo() {
158 Uri data = Uri.parse(getString(R.string.HelpFragment__link__debug_info));
159 Intent intent = new Intent(Intent.ACTION_VIEW, data);
160
161 startActivity(intent);
162 }
163
164 private void submitForm() {
165 next.setSpinning();
166 problem.setEnabled(false);
167
168 helpViewModel.onSubmitClicked(includeDebugLogs.isChecked()).observe(getViewLifecycleOwner(), result -> {
169 if (result.getDebugLogUrl().isPresent()) {
170 submitFormWithDebugLog(result.getDebugLogUrl().get());
171 } else if (result.isError()) {
172 submitFormWithDebugLog(getString(R.string.HelpFragment__could_not_upload_logs));
173 } else {
174 submitFormWithDebugLog(null);
175 }
176 });
177 }
178
179 private void submitFormWithDebugLog(@Nullable String debugLog) {
180 Feeling feeling = Stream.of(emoji)
181 .filter(View::isSelected)
182 .map(view -> Feeling.getByViewId(view.getId()))
183 .findFirst().orElse(null);
184
185
186 CommunicationActions.openEmail(requireContext(),
187 SupportEmailUtil.getSupportEmailAddress(requireContext()),
188 getEmailSubject(),
189 getEmailBody(debugLog, feeling));
190 }
191
192 private String getEmailSubject() {
193 return getString(R.string.HelpFragment__signal_android_support_request);
194 }
195
196 private String getEmailBody(@Nullable String debugLog, @Nullable Feeling feeling) {
197 StringBuilder suffix = new StringBuilder();
198
199 if (debugLog != null) {
200 suffix.append("\n");
201 suffix.append(getString(R.string.HelpFragment__debug_log));
202 suffix.append(" ");
203 suffix.append(debugLog);
204 }
205
206 if (feeling != null) {
207 suffix.append("\n\n");
208 suffix.append(feeling.getEmojiCode());
209 suffix.append("\n");
210 suffix.append(getString(feeling.getStringId()));
211 }
212
213 String[] englishCategories = ResourceUtil.getEnglishResources(requireContext()).getStringArray(R.array.HelpFragment__categories_5);
214 String category = (helpViewModel.getCategoryIndex() >= 0 && helpViewModel.getCategoryIndex() < englishCategories.length) ? englishCategories[helpViewModel.getCategoryIndex()]
215 : categoryAdapter.getItem(helpViewModel.getCategoryIndex()).toString();
216
217 return SupportEmailUtil.generateSupportEmailBody(requireContext(),
218 R.string.HelpFragment__signal_android_support_request,
219 " - " + category,
220 problem.getText().toString() + "\n\n",
221 suffix.toString());
222 }
223
224 private enum Feeling {
225 ECSTATIC(R.id.help_fragment_emoji_5, R.string.HelpFragment__emoji_5, "\ud83d\ude00"),
226 HAPPY(R.id.help_fragment_emoji_4, R.string.HelpFragment__emoji_4, "\ud83d\ude42"),
227 AMBIVALENT(R.id.help_fragment_emoji_3, R.string.HelpFragment__emoji_3, "\ud83d\ude10"),
228 UNHAPPY(R.id.help_fragment_emoji_2, R.string.HelpFragment__emoji_2, "\ud83d\ude41"),
229 ANGRY(R.id.help_fragment_emoji_1, R.string.HelpFragment__emoji_1, "\ud83d\ude20");
230
231 private final @IdRes int viewId;
232 private final @StringRes int stringId;
233 private final CharSequence emojiCode;
234
235 Feeling(@IdRes int viewId, @StringRes int stringId, @NonNull CharSequence emojiCode) {
236 this.viewId = viewId;
237 this.stringId = stringId;
238 this.emojiCode = emojiCode;
239 }
240
241 public @IdRes int getViewId() {
242 return viewId;
243 }
244
245 public @StringRes int getStringId() {
246 return stringId;
247 }
248
249 public @NonNull CharSequence getEmojiCode() {
250 return emojiCode;
251 }
252
253 static Feeling getByViewId(@IdRes int viewId) {
254 for (Feeling feeling : values()) {
255 if (feeling.viewId == viewId) {
256 return feeling;
257 }
258 }
259
260 throw new AssertionError();
261 }
262 }
263}