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 startActivity(intent);
59 }
60 Toast.makeText(PublishProfilePictureActivity.this,
61 R.string.avatar_has_been_published,
62 Toast.LENGTH_SHORT).show();
63 finish();
64 });
65 }
66
67 @Override
68 public void onAvatarPublicationFailed(int res) {
69 runOnUiThread(() -> {
70 hintOrWarning.setText(res);
71 hintOrWarning.setTextAppearance(this,R.style.TextAppearance_Conversations_Body1_Warning);
72 hintOrWarning.setVisibility(View.VISIBLE);
73 publishing = false;
74 togglePublishButton(true, R.string.publish);
75 });
76 }
77
78 @Override
79 public void onCreate(Bundle savedInstanceState) {
80 super.onCreate(savedInstanceState);
81 setContentView(R.layout.activity_publish_profile_picture);
82 setSupportActionBar(findViewById(R.id.toolbar));
83
84 this.avatar = findViewById(R.id.account_image);
85 this.cancelButton = findViewById(R.id.cancel_button);
86 this.publishButton = findViewById(R.id.publish_button);
87 this.hintOrWarning = findViewById(R.id.hint_or_warning);
88 this.secondaryHint = findViewById(R.id.secondary_hint);
89 this.publishButton.setOnClickListener(v -> {
90 if (avatarUri != null) {
91 publishing = true;
92 togglePublishButton(false, R.string.publishing);
93 xmppConnectionService.publishAvatar(account, avatarUri, this);
94 }
95 });
96 this.cancelButton.setOnClickListener(v -> {
97 if (mInitialAccountSetup) {
98 Intent intent = new Intent(getApplicationContext(), StartConversationActivity.class);
99 if (xmppConnectionService != null && xmppConnectionService.getAccounts().size() == 1) {
100 StartConversationActivity.addInviteUri(intent, getIntent());
101 intent.putExtra("init", true);
102 }
103 startActivity(intent);
104 }
105 finish();
106 });
107 this.avatar.setOnClickListener(v -> chooseAvatar());
108 this.defaultUri = PhoneHelper.getProfilePictureUri(getApplicationContext());
109 if (savedInstanceState != null) {
110 this.avatarUri = savedInstanceState.getParcelable("uri");
111 this.handledExternalUri.set(savedInstanceState.getBoolean("handle_external_uri",false));
112 }
113 }
114
115 @Override
116 public void onSaveInstanceState(Bundle outState) {
117 if (this.avatarUri != null) {
118 outState.putParcelable("uri", this.avatarUri);
119 }
120 outState.putBoolean("handle_external_uri", handledExternalUri.get());
121 super.onSaveInstanceState(outState);
122 }
123
124
125 @Override
126 public void onActivityResult(int requestCode, int resultCode, Intent data) {
127 if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) {
128 CropImage.ActivityResult result = CropImage.getActivityResult(data);
129 if (resultCode == RESULT_OK) {
130 this.avatarUri = result.getUri();
131 if (xmppConnectionServiceBound) {
132 loadImageIntoPreview(this.avatarUri);
133 }
134 } else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE) {
135 Exception error = result.getError();
136 if (error != null) {
137 Toast.makeText(this, error.getMessage(), Toast.LENGTH_SHORT).show();
138 }
139 }
140 }
141 }
142
143 private void chooseAvatar() {
144 CropImage.activity()
145 .setOutputCompressFormat(Bitmap.CompressFormat.PNG)
146 .setAspectRatio(1, 1)
147 .setMinCropResultSize(Config.AVATAR_SIZE, Config.AVATAR_SIZE)
148 .start(this);
149 }
150
151 @Override
152 protected void onBackendConnected() {
153 this.account = extractAccount(getIntent());
154 if (this.account != null) {
155 reloadAvatar();
156 }
157 }
158
159 private void reloadAvatar() {
160 this.support = this.account.getXmppConnection() != null && this.account.getXmppConnection().getFeatures().pep();
161 if (this.avatarUri == null) {
162 if (this.account.getAvatar() != null || this.defaultUri == null) {
163 loadImageIntoPreview(null);
164 } else {
165 this.avatarUri = this.defaultUri;
166 loadImageIntoPreview(this.defaultUri);
167 }
168 } else {
169 loadImageIntoPreview(avatarUri);
170 }
171 }
172
173 @Override
174 protected void onStart() {
175 super.onStart();
176 final Intent intent = getIntent();
177 this.mInitialAccountSetup = intent != null && intent.getBooleanExtra("setup", false);
178
179 final Uri uri = intent != null ? intent.getData() : null;
180
181 if (uri != null && handledExternalUri.compareAndSet(false,true)) {
182 CropImage.activity(uri).setOutputCompressFormat(Bitmap.CompressFormat.PNG)
183 .setAspectRatio(1, 1)
184 .setMinCropResultSize(Config.AVATAR_SIZE, Config.AVATAR_SIZE)
185 .start(this);
186 return;
187 }
188
189 if (this.mInitialAccountSetup) {
190 this.cancelButton.setText(R.string.skip);
191 }
192 configureActionBar(getSupportActionBar(), !this.mInitialAccountSetup && !handledExternalUri.get());
193 }
194
195 protected void loadImageIntoPreview(Uri uri) {
196
197 Bitmap bm = null;
198 if (uri == null) {
199 bm = avatarService().get(account, (int) getResources().getDimension(R.dimen.publish_avatar_size));
200 } else {
201 try {
202 bm = xmppConnectionService.getFileBackend().cropCenterSquare(uri, (int) getResources().getDimension(R.dimen.publish_avatar_size));
203 } catch (Exception e) {
204 Log.d(Config.LOGTAG, "unable to load bitmap into image view", e);
205 }
206 }
207
208 if (bm == null) {
209 togglePublishButton(false, R.string.publish);
210 this.hintOrWarning.setVisibility(View.VISIBLE);
211 this.hintOrWarning.setTextAppearance(this,R.style.TextAppearance_Conversations_Body1_Warning);
212 this.hintOrWarning.setText(R.string.error_publish_avatar_converting);
213 return;
214 }
215 this.avatar.setImageBitmap(bm);
216 if (support) {
217 togglePublishButton(uri != null, R.string.publish);
218 this.hintOrWarning.setVisibility(View.INVISIBLE);
219 } else {
220 togglePublishButton(false, R.string.publish);
221 this.hintOrWarning.setVisibility(View.VISIBLE);
222 this.hintOrWarning.setTextAppearance(this,R.style.TextAppearance_Conversations_Body1_Warning);
223 if (account.getStatus() == Account.State.ONLINE) {
224 this.hintOrWarning.setText(R.string.error_publish_avatar_no_server_support);
225 } else {
226 this.hintOrWarning.setText(R.string.error_publish_avatar_offline);
227 }
228 }
229 if (this.defaultUri == null || this.defaultUri.equals(uri)) {
230 this.secondaryHint.setVisibility(View.INVISIBLE);
231 this.avatar.setOnLongClickListener(null);
232 } else if (this.defaultUri != null) {
233 this.secondaryHint.setVisibility(View.VISIBLE);
234 this.avatar.setOnLongClickListener(this.backToDefaultListener);
235 }
236 }
237
238 protected void togglePublishButton(boolean enabled, @StringRes int res) {
239 final boolean status = enabled && !publishing;
240 this.publishButton.setText(publishing ? R.string.publishing : res);
241 this.publishButton.setEnabled(status);
242 }
243
244 public void refreshUiReal() {
245 if (this.account != null) {
246 reloadAvatar();
247 }
248 }
249
250 @Override
251 public void onAccountUpdate() {
252 refreshUi();
253 }
254
255}