1package eu.siacs.conversations.ui;
2
3import android.content.Intent;
4import android.graphics.Bitmap;
5import android.net.Uri;
6import android.os.Bundle;
7import android.support.annotation.StringRes;
8import android.util.Log;
9import android.view.View;
10import android.view.View.OnLongClickListener;
11import android.widget.Button;
12import android.widget.ImageView;
13import android.widget.TextView;
14import android.widget.Toast;
15
16import com.theartofdev.edmodo.cropper.CropImage;
17
18import java.util.concurrent.atomic.AtomicBoolean;
19
20import eu.siacs.conversations.Config;
21import eu.siacs.conversations.R;
22import eu.siacs.conversations.entities.Account;
23import eu.siacs.conversations.services.XmppConnectionService;
24import eu.siacs.conversations.ui.interfaces.OnAvatarPublication;
25import eu.siacs.conversations.utils.PhoneHelper;
26
27public class PublishProfilePictureActivity extends XmppActivity implements XmppConnectionService.OnAccountUpdate, OnAvatarPublication {
28
29 private ImageView avatar;
30 private TextView hintOrWarning;
31 private TextView secondaryHint;
32 private Button cancelButton;
33 private Button publishButton;
34 private Uri avatarUri;
35 private Uri defaultUri;
36 private Account account;
37 private boolean support = false;
38 private boolean publishing = false;
39 private AtomicBoolean handledExternalUri = new AtomicBoolean(false);
40 private OnLongClickListener backToDefaultListener = new OnLongClickListener() {
41
42 @Override
43 public boolean onLongClick(View v) {
44 avatarUri = defaultUri;
45 loadImageIntoPreview(defaultUri);
46 return true;
47 }
48 };
49 private boolean mInitialAccountSetup;
50
51 @Override
52 public void onAvatarPublicationSucceeded() {
53 runOnUiThread(() -> {
54 if (mInitialAccountSetup) {
55 Intent intent = new Intent(getApplicationContext(), StartConversationActivity.class);
56 StartConversationActivity.addInviteUri(intent, getIntent());
57 intent.putExtra("init", true);
58 intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString());
59 startActivity(intent);
60 }
61 Toast.makeText(PublishProfilePictureActivity.this,
62 R.string.avatar_has_been_published,
63 Toast.LENGTH_SHORT).show();
64 finish();
65 });
66 }
67
68 @Override
69 public void onAvatarPublicationFailed(int res) {
70 runOnUiThread(() -> {
71 hintOrWarning.setText(res);
72 hintOrWarning.setTextAppearance(this,R.style.TextAppearance_Conversations_Body1_Warning);
73 hintOrWarning.setVisibility(View.VISIBLE);
74 publishing = false;
75 togglePublishButton(true, R.string.publish);
76 });
77 }
78
79 @Override
80 public void onCreate(Bundle savedInstanceState) {
81 super.onCreate(savedInstanceState);
82 setContentView(R.layout.activity_publish_profile_picture);
83 setSupportActionBar(findViewById(R.id.toolbar));
84
85 this.avatar = findViewById(R.id.account_image);
86 this.cancelButton = findViewById(R.id.cancel_button);
87 this.publishButton = findViewById(R.id.publish_button);
88 this.hintOrWarning = findViewById(R.id.hint_or_warning);
89 this.secondaryHint = findViewById(R.id.secondary_hint);
90 this.publishButton.setOnClickListener(v -> {
91 if (avatarUri != null) {
92 publishing = true;
93 togglePublishButton(false, R.string.publishing);
94 xmppConnectionService.publishAvatar(account, avatarUri, this);
95 }
96 });
97 this.cancelButton.setOnClickListener(v -> {
98 if (mInitialAccountSetup) {
99 final Intent intent = new Intent(getApplicationContext(), StartConversationActivity.class);
100 if (xmppConnectionService != null && xmppConnectionService.getAccounts().size() == 1) {
101 intent.putExtra("init", true);
102 }
103 StartConversationActivity.addInviteUri(intent, getIntent());
104 intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString());
105 startActivity(intent);
106 }
107 finish();
108 });
109 this.avatar.setOnClickListener(v -> chooseAvatar());
110 this.defaultUri = PhoneHelper.getProfilePictureUri(getApplicationContext());
111 if (savedInstanceState != null) {
112 this.avatarUri = savedInstanceState.getParcelable("uri");
113 this.handledExternalUri.set(savedInstanceState.getBoolean("handle_external_uri",false));
114 }
115 }
116
117 @Override
118 public void onSaveInstanceState(Bundle outState) {
119 if (this.avatarUri != null) {
120 outState.putParcelable("uri", this.avatarUri);
121 }
122 outState.putBoolean("handle_external_uri", handledExternalUri.get());
123 super.onSaveInstanceState(outState);
124 }
125
126
127 @Override
128 public void onActivityResult(int requestCode, int resultCode, Intent data) {
129 if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) {
130 CropImage.ActivityResult result = CropImage.getActivityResult(data);
131 if (resultCode == RESULT_OK) {
132 this.avatarUri = result.getUri();
133 if (xmppConnectionServiceBound) {
134 loadImageIntoPreview(this.avatarUri);
135 }
136 } else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE) {
137 Exception error = result.getError();
138 if (error != null) {
139 Toast.makeText(this, error.getMessage(), Toast.LENGTH_SHORT).show();
140 }
141 }
142 }
143 }
144
145 private void chooseAvatar() {
146 CropImage.activity()
147 .setOutputCompressFormat(Bitmap.CompressFormat.PNG)
148 .setAspectRatio(1, 1)
149 .setMinCropResultSize(Config.AVATAR_SIZE, Config.AVATAR_SIZE)
150 .start(this);
151 }
152
153 @Override
154 protected void onBackendConnected() {
155 this.account = extractAccount(getIntent());
156 if (this.account != null) {
157 reloadAvatar();
158 }
159 }
160
161 private void reloadAvatar() {
162 this.support = this.account.getXmppConnection() != null && this.account.getXmppConnection().getFeatures().pep();
163 if (this.avatarUri == null) {
164 if (this.account.getAvatar() != null || this.defaultUri == null) {
165 loadImageIntoPreview(null);
166 } else {
167 this.avatarUri = this.defaultUri;
168 loadImageIntoPreview(this.defaultUri);
169 }
170 } else {
171 loadImageIntoPreview(avatarUri);
172 }
173 }
174
175 @Override
176 protected void onStart() {
177 super.onStart();
178 final Intent intent = getIntent();
179 this.mInitialAccountSetup = intent != null && intent.getBooleanExtra("setup", false);
180
181 final Uri uri = intent != null ? intent.getData() : null;
182
183 if (uri != null && handledExternalUri.compareAndSet(false,true)) {
184 CropImage.activity(uri).setOutputCompressFormat(Bitmap.CompressFormat.PNG)
185 .setAspectRatio(1, 1)
186 .setMinCropResultSize(Config.AVATAR_SIZE, Config.AVATAR_SIZE)
187 .start(this);
188 return;
189 }
190
191 if (this.mInitialAccountSetup) {
192 this.cancelButton.setText(R.string.skip);
193 }
194 configureActionBar(getSupportActionBar(), !this.mInitialAccountSetup && !handledExternalUri.get());
195 }
196
197 protected void loadImageIntoPreview(Uri uri) {
198
199 Bitmap bm = null;
200 if (uri == null) {
201 bm = avatarService().get(account, (int) getResources().getDimension(R.dimen.publish_avatar_size));
202 } else {
203 try {
204 bm = xmppConnectionService.getFileBackend().cropCenterSquare(uri, (int) getResources().getDimension(R.dimen.publish_avatar_size));
205 } catch (Exception e) {
206 Log.d(Config.LOGTAG, "unable to load bitmap into image view", e);
207 }
208 }
209
210 if (bm == null) {
211 togglePublishButton(false, R.string.publish);
212 this.hintOrWarning.setVisibility(View.VISIBLE);
213 this.hintOrWarning.setTextAppearance(this,R.style.TextAppearance_Conversations_Body1_Warning);
214 this.hintOrWarning.setText(R.string.error_publish_avatar_converting);
215 return;
216 }
217 this.avatar.setImageBitmap(bm);
218 if (support) {
219 togglePublishButton(uri != null, R.string.publish);
220 this.hintOrWarning.setVisibility(View.INVISIBLE);
221 } else {
222 togglePublishButton(false, R.string.publish);
223 this.hintOrWarning.setVisibility(View.VISIBLE);
224 this.hintOrWarning.setTextAppearance(this,R.style.TextAppearance_Conversations_Body1_Warning);
225 if (account.getStatus() == Account.State.ONLINE) {
226 this.hintOrWarning.setText(R.string.error_publish_avatar_no_server_support);
227 } else {
228 this.hintOrWarning.setText(R.string.error_publish_avatar_offline);
229 }
230 }
231 if (this.defaultUri == null || this.defaultUri.equals(uri)) {
232 this.secondaryHint.setVisibility(View.INVISIBLE);
233 this.avatar.setOnLongClickListener(null);
234 } else if (this.defaultUri != null) {
235 this.secondaryHint.setVisibility(View.VISIBLE);
236 this.avatar.setOnLongClickListener(this.backToDefaultListener);
237 }
238 }
239
240 protected void togglePublishButton(boolean enabled, @StringRes int res) {
241 final boolean status = enabled && !publishing;
242 this.publishButton.setText(publishing ? R.string.publishing : res);
243 this.publishButton.setEnabled(status);
244 }
245
246 public void refreshUiReal() {
247 if (this.account != null) {
248 reloadAvatar();
249 }
250 }
251
252 @Override
253 public void onAccountUpdate() {
254 refreshUi();
255 }
256
257}