Skip to content

Instantly share code, notes, and snippets.

@yanzm
Last active May 1, 2023 09:03
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save yanzm/1d2fa37e2375cf4dee6f to your computer and use it in GitHub Desktop.
Save yanzm/1d2fa37e2375cf4dee6f to your computer and use it in GitHub Desktop.
package net.yanzm.profileapplication;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioGroup;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import com.squareup.picasso.Picasso;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class MainActivity extends Activity {
private static final int REQUEST_CODE_PICK_IMAGE = 1;
private ImageView thumbnailView;
private EditText nameEditText;
private EditText bioEditText;
private Spinner experienceSpinner;
private RadioGroup eventGroup;
private LinearLayout dessertContainer;
private Button sendButton;
private View progressView;
private View profileContainer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
assert getActionBar() != null;
getActionBar().setDisplayHomeAsUpEnabled(true);
// ビューの設定
progressView = findViewById(R.id.progress);
profileContainer = findViewById(R.id.profile_container);
thumbnailView = (ImageView) findViewById(R.id.thumbnail);
thumbnailView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE);
}
});
nameEditText = (EditText) findViewById(R.id.name);
experienceSpinner = (Spinner) findViewById(R.id.experience);
bioEditText = (EditText) findViewById(R.id.bio);
eventGroup = (RadioGroup) findViewById(R.id.event);
dessertContainer = (LinearLayout) findViewById(R.id.dessert_container);
findViewById(R.id.add_dessert_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final String[] desserts = getResources().getStringArray(R.array.desserts);
new AlertDialog.Builder(MainActivity.this)
.setItems(desserts, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String item = desserts[which];
final int childCount = dessertContainer.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = dessertContainer.getChildAt(i);
String dessert = ((TextView) child).getText().toString();
if (dessert.equals(item)) {
Toast.makeText(MainActivity.this, "すでに選択されています", Toast.LENGTH_SHORT).show();
return;
}
}
final TextView tv = (TextView) getLayoutInflater()
.inflate(R.layout.dessert_item, dessertContainer, false);
tv.setText(desserts[which]);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new AlertDialog.Builder(MainActivity.this)
.setMessage("削除しますか?")
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dessertContainer.removeView(tv);
}
})
.setNegativeButton(android.R.string.cancel, null)
.show();
}
});
dessertContainer.addView(tv);
}
})
.show();
}
});
sendButton = (Button) findViewById(R.id.send_button);
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// バリデーション
if (validate()) {
send();
}
}
});
// 画面回転対応
if (savedInstanceState != null) {
progressView.setVisibility(View.GONE);
return;
}
// プログレスを表示
progressView.setVisibility(View.VISIBLE);
// (同期)編集フォームを非表示or無効化
profileContainer.setVisibility(View.GONE);
// 1. サーバーからプロフィールデータを取得
AsyncTask<Void, Void, ProfileData> task = new AsyncTask<Void, Void, ProfileData>() {
@Override
protected ProfileData doInBackground(Void... params) {
return getProfileData();
}
@Override
protected void onPostExecute(ProfileData profileData) {
// 2. プロフィールデータを表示
if (!TextUtils.isEmpty(profileData.imageUrl)) {
Picasso.with(MainActivity.this).load(profileData.imageUrl).into(thumbnailView);
}
nameEditText.setText(profileData.name);
bioEditText.setText(profileData.bio);
experienceSpinner.setSelection(profileData.experience);
int id = -1;
switch (profileData.eventStatus) {
case 0:
id = R.id.attend;
break;
case 1:
id = R.id.not_attend;
break;
case 2:
id = R.id.attend;
break;
}
eventGroup.check(id);
for (String dessert : profileData.favoriteDessert) {
LayoutInflater inflater = getLayoutInflater();
final TextView tv = (TextView) inflater.inflate(R.layout.dessert_item, dessertContainer, false);
tv.setText(dessert);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new AlertDialog.Builder(MainActivity.this)
.setMessage("削除しますか?")
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dessertContainer.removeView(tv);
}
})
.setNegativeButton(android.R.string.cancel, null)
.show();
}
});
dessertContainer.addView(tv);
}
// 編集フォームを表示or有効化
profileContainer.setVisibility(View.VISIBLE);
final AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(
ObjectAnimator.ofFloat(profileContainer, "alpha", 0f, 1f),
ObjectAnimator.ofFloat(progressView, "alpha", 1f, 0f)
);
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
animatorSet.removeListener(this);
// プログレスを非表示
progressView.setVisibility(View.GONE);
}
});
animatorSet.start();
}
}.execute();
}
private static final String KEY_IMAGE_URI = "image_uri";
private static final String KEY_DESSERT_LIST = "dessert_list";
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Uri uri = (Uri) thumbnailView.getTag();
if (uri != null) {
outState.putString(KEY_IMAGE_URI, uri.toString());
}
ArrayList<String> dessertList = new ArrayList<>();
final int childCount = dessertContainer.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = dessertContainer.getChildAt(i);
if (child instanceof TextView) {
dessertList.add(((TextView) child).getText().toString());
}
}
outState.putStringArrayList(KEY_DESSERT_LIST, dessertList);
}
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
final String uriString = savedInstanceState.getString(KEY_IMAGE_URI);
if (!TextUtils.isEmpty(uriString)) {
Uri uri = Uri.parse(uriString);
getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
Bitmap bmp = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
thumbnailView.setImageBitmap(bmp);
thumbnailView.setTag(uri);
} catch (Exception e) {
e.printStackTrace();
}
}
ArrayList<String> dessertList = savedInstanceState.getStringArrayList(KEY_DESSERT_LIST);
for (String dessert : dessertList) {
LayoutInflater inflater = getLayoutInflater();
final TextView tv = (TextView) inflater.inflate(R.layout.dessert_item, dessertContainer, false);
tv.setText(dessert);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new AlertDialog.Builder(MainActivity.this)
.setMessage("削除しますか?")
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dessertContainer.removeView(tv);
}
})
.setNegativeButton(android.R.string.cancel, null)
.show();
}
});
dessertContainer.addView(tv);
}
}
private boolean validate() {
// バリデーション失敗: エラーメッセージ表示
final String name = nameEditText.getText().toString();
if (TextUtils.isEmpty(name)) {
Toast.makeText(MainActivity.this, "名前が入力されていません", Toast.LENGTH_SHORT).show();
return false;
}
final int id = eventGroup.getCheckedRadioButtonId();
if (id != R.id.attend && id != R.id.not_attend && id != R.id.unknown) {
Toast.makeText(MainActivity.this, "DroidKaigiが選択されていません", Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
private void send() {
final Uri imageUri = (Uri) thumbnailView.getTag();
final ProfileData profileData = new ProfileData();
profileData.name = nameEditText.getText().toString();
profileData.bio = bioEditText.getText().toString();
final int position = experienceSpinner.getSelectedItemPosition();
switch (position) {
case 0:
profileData.experience = ProfileData.EXPERIENCE_U1;
break;
case 1:
profileData.experience = ProfileData.EXPERIENCE_U2;
break;
case 2:
profileData.experience = ProfileData.EXPERIENCE_U3;
break;
case 3:
profileData.experience = ProfileData.EXPERIENCE_U4;
break;
case 4:
profileData.experience = ProfileData.EXPERIENCE_U5;
break;
case 5:
profileData.experience = ProfileData.EXPERIENCE_O5;
break;
default:
return;
}
final int id = eventGroup.getCheckedRadioButtonId();
switch (id) {
case R.id.attend:
profileData.eventStatus = ProfileData.EVENT_STATUS_ATTEND;
break;
case R.id.not_attend:
profileData.eventStatus = ProfileData.EVENT_STATUS_NOT_ATTEND;
break;
case R.id.unknown:
profileData.eventStatus = ProfileData.EVENT_STATUS_UNKNOWN;
break;
default:
return;
}
List<String> favoriteDessert = new ArrayList<>();
final int childCount = dessertContainer.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = dessertContainer.getChildAt(i);
if (child instanceof TextView) {
favoriteDessert.add(((TextView) child).getText().toString());
}
}
profileData.favoriteDessert = favoriteDessert;
// 送信ボタン無効化
sendButton.setEnabled(false);
// プログレスを表示
progressView.setVisibility(View.VISIBLE);
progressView.animate().alpha(1f);
// 5. データの更新をサーバーに送信
AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
@Override
protected Boolean doInBackground(Void... params) {
if (imageUri != null) {
String imageUrl = sendImage(imageUri);
if (TextUtils.isEmpty(imageUrl)) {
return false;
}
profileData.imageUrl = imageUrl;
}
return sendProfileData(profileData);
}
@Override
protected void onPostExecute(Boolean result) {
if (isFinishing()) {
return;
}
if (result) {
Toast.makeText(MainActivity.this, "更新しました", Toast.LENGTH_SHORT).show();
finish();
} else {
Toast.makeText(MainActivity.this, "更新できませんでした", Toast.LENGTH_SHORT).show();
// 送信ボタン有効化
sendButton.setEnabled(true);
final ObjectAnimator animator = ObjectAnimator.ofFloat(progressView, "alpha", 1f, 0f);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
animator.removeListener(this);
// プログレスを非表示
progressView.setVisibility(View.GONE);
}
});
animator.start();
}
}
}.execute();
}
private String sendImage(Uri imageUri) {
// ネットワーク通信をダミーするためにスリープ
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "https://pbs.twimg.com/profile_images/542953617108398081/Gs_eKy2k.jpeg";
}
Random random = new Random();
private ProfileData getProfileData() {
// ネットワーク通信をダミーするためにスリープ
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ProfileData profileData = new ProfileData();
profileData.name = random.nextBoolean() ? "Droid" : "";
if (!TextUtils.isEmpty(profileData.name)) {
profileData.imageUrl = "https://dl.dropboxusercontent.com/u/7053182/ic_yanzm.jpeg";
profileData.bio = random.nextBoolean() ? "世界をまたにかけるAndroid開発者" : "";
int experience = random.nextInt(6); // 0 〜 5;
switch (experience) {
case 0:
profileData.experience = ProfileData.EXPERIENCE_U1;
break;
case 1:
profileData.experience = ProfileData.EXPERIENCE_U2;
break;
case 2:
profileData.experience = ProfileData.EXPERIENCE_U3;
break;
case 3:
profileData.experience = ProfileData.EXPERIENCE_U4;
break;
case 4:
profileData.experience = ProfileData.EXPERIENCE_U5;
break;
case 5:
profileData.experience = ProfileData.EXPERIENCE_O5;
break;
}
int eventStatus = random.nextInt(3); // 0 〜 2;
switch (eventStatus) {
case 0:
profileData.eventStatus = ProfileData.EVENT_STATUS_ATTEND;
break;
case 1:
profileData.eventStatus = ProfileData.EVENT_STATUS_NOT_ATTEND;
break;
case 2:
profileData.eventStatus = ProfileData.EVENT_STATUS_UNKNOWN;
break;
}
final String[] desserts = getResources().getStringArray(R.array.desserts);
int start = random.nextInt(desserts.length);
int size = random.nextInt(desserts.length);
List<String> favoriteDessert = new ArrayList<>();
for (int i = start; i < start + size && i < desserts.length; i++) {
favoriteDessert.add(desserts[i]);
}
profileData.favoriteDessert = favoriteDessert;
}
return profileData;
}
private boolean sendProfileData(ProfileData profileData) {
// ネットワーク通信をダミーするためにスリープ
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return random.nextBoolean();
}
public static class ProfileData {
@Retention(RetentionPolicy.SOURCE)
@IntDef({EVENT_STATUS_ATTEND, EVENT_STATUS_NOT_ATTEND, EVENT_STATUS_UNKNOWN})
public @interface EventStatus {
}
public static final int EVENT_STATUS_ATTEND = 0;
public static final int EVENT_STATUS_NOT_ATTEND = 1;
public static final int EVENT_STATUS_UNKNOWN = 2;
@Retention(RetentionPolicy.SOURCE)
@IntDef({EXPERIENCE_U1, EXPERIENCE_U2, EXPERIENCE_U3, EXPERIENCE_U4, EXPERIENCE_U5, EXPERIENCE_O5})
public @interface Experience {
}
public static final int EXPERIENCE_U1 = 0;
public static final int EXPERIENCE_U2 = 1;
public static final int EXPERIENCE_U3 = 2;
public static final int EXPERIENCE_U4 = 3;
public static final int EXPERIENCE_U5 = 4;
public static final int EXPERIENCE_O5 = 5;
String imageUrl;
String name;
String bio;
@Experience
int experience = 0;
@EventStatus
int eventStatus = -1;
List<String> favoriteDessert = new ArrayList<>();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE_PICK_IMAGE) {
if (resultCode != RESULT_OK) {
return;
}
final Uri uri = data.getData();
getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
Bitmap bmp = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
thumbnailView.setImageBitmap(bmp);
thumbnailView.setTag(uri);
} catch (Exception e) {
e.printStackTrace();
}
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment