Polish Android app UI

This commit is contained in:
2026-06-10 00:14:39 +09:00
parent ca09dcbd69
commit a98dc110e1

View File

@@ -12,7 +12,9 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
@@ -183,7 +185,11 @@ public class MainActivity extends Activity {
LinearLayout header = new LinearLayout(this); LinearLayout header = new LinearLayout(this);
header.setOrientation(LinearLayout.VERTICAL); header.setOrientation(LinearLayout.VERTICAL);
header.setPadding(dp(18), dp(18), dp(18), dp(12)); header.setPadding(dp(20), dp(20), dp(20), dp(14));
header.setBackgroundColor(palette.surface);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
header.setElevation(dp(1));
}
root.addView(header, new LinearLayout.LayoutParams( root.addView(header, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
@@ -208,30 +214,29 @@ public class MainActivity extends Activity {
TextView title = new TextView(this); TextView title = new TextView(this);
title.setText("유튜브 즐겨찾기 검색"); title.setText("유튜브 즐겨찾기 검색");
title.setTextColor(palette.textPrimary); title.setTextColor(palette.textPrimary);
title.setTextSize(24); title.setTextSize(22);
title.setTypeface(Typeface.DEFAULT, Typeface.BOLD); title.setTypeface(Typeface.DEFAULT, Typeface.BOLD);
title.setIncludeFontPadding(false);
titleColumn.addView(title); titleColumn.addView(title);
TextView guide = new TextView(this); TextView guide = new TextView(this);
guide.setTextColor(palette.textSecondary); guide.setTextColor(palette.textSecondary);
guide.setTextSize(13); guide.setTextSize(13);
guide.setText("탭으로 분류하고, 영상을 길게 눌러 여러 분류에 넣어두세요."); guide.setText("저장한 YouTube 영상을 분류별로 빠르게 찾으세요.");
guide.setLineSpacing(0, 1.08f);
LinearLayout.LayoutParams guideParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams guideParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
); );
guideParams.topMargin = dp(4); guideParams.topMargin = dp(6);
titleColumn.addView(guide, guideParams); titleColumn.addView(guide, guideParams);
Button themeButton = new Button(this); Button themeButton = createSmallButton("테마");
themeButton.setText("테마"); themeButton.setTextColor(palette.accent);
themeButton.setTextSize(13); themeButton.setBackground(softButtonBackground());
themeButton.setTextColor(Color.WHITE);
themeButton.setAllCaps(false);
themeButton.setBackground(buttonBackground(palette.accent));
themeButton.setOnClickListener(view -> showThemeDialog()); themeButton.setOnClickListener(view -> showThemeDialog());
LinearLayout.LayoutParams themeButtonParams = new LinearLayout.LayoutParams(dp(76), dp(44)); LinearLayout.LayoutParams themeButtonParams = new LinearLayout.LayoutParams(dp(72), dp(40));
themeButtonParams.leftMargin = dp(10); themeButtonParams.leftMargin = dp(12);
titleRow.addView(themeButton, themeButtonParams); titleRow.addView(themeButton, themeButtonParams);
LinearLayout urlRow = new LinearLayout(this); LinearLayout urlRow = new LinearLayout(this);
@@ -241,7 +246,7 @@ public class MainActivity extends Activity {
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
); );
urlRowParams.topMargin = dp(14); urlRowParams.topMargin = dp(16);
header.addView(urlRow, urlRowParams); header.addView(urlRow, urlRowParams);
urlInput = new EditText(this); urlInput = new EditText(this);
@@ -253,7 +258,7 @@ public class MainActivity extends Activity {
urlInput.setTextColor(palette.textPrimary); urlInput.setTextColor(palette.textPrimary);
urlInput.setHintTextColor(palette.textSecondary); urlInput.setHintTextColor(palette.textSecondary);
urlInput.setBackground(inputBackground()); urlInput.setBackground(inputBackground());
urlInput.setPadding(dp(12), 0, dp(12), 0); urlInput.setPadding(dp(14), 0, dp(14), 0);
urlInput.setText(pendingUrl); urlInput.setText(pendingUrl);
urlInput.setOnEditorActionListener((view, actionId, event) -> { urlInput.setOnEditorActionListener((view, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_DONE) { if (actionId == EditorInfo.IME_ACTION_DONE) {
@@ -262,28 +267,23 @@ public class MainActivity extends Activity {
} }
return false; return false;
}); });
LinearLayout.LayoutParams urlInputParams = new LinearLayout.LayoutParams(0, dp(48), 1f); LinearLayout.LayoutParams urlInputParams = new LinearLayout.LayoutParams(0, dp(50), 1f);
urlRow.addView(urlInput, urlInputParams); urlRow.addView(urlInput, urlInputParams);
Button pasteButton = new Button(this); Button pasteButton = createSmallButton("붙여넣기");
pasteButton.setText("붙여넣기");
pasteButton.setTextSize(13);
pasteButton.setTextColor(palette.accent); pasteButton.setTextColor(palette.accent);
pasteButton.setAllCaps(false); pasteButton.setBackground(secondaryButtonBackground());
pasteButton.setBackground(inputBackground());
pasteButton.setOnClickListener(view -> pasteFromClipboard()); pasteButton.setOnClickListener(view -> pasteFromClipboard());
LinearLayout.LayoutParams pasteParams = new LinearLayout.LayoutParams(dp(92), dp(48)); LinearLayout.LayoutParams pasteParams = new LinearLayout.LayoutParams(dp(94), dp(50));
pasteParams.leftMargin = dp(8); pasteParams.leftMargin = dp(8);
urlRow.addView(pasteButton, pasteParams); urlRow.addView(pasteButton, pasteParams);
Button addButton = new Button(this); Button addButton = createSmallButton("추가");
addButton.setText("추가");
addButton.setTextSize(13);
addButton.setTextColor(Color.WHITE); addButton.setTextColor(Color.WHITE);
addButton.setAllCaps(false); addButton.setTypeface(Typeface.DEFAULT, Typeface.BOLD);
addButton.setBackground(buttonBackground(palette.accent)); addButton.setBackground(buttonBackground(palette.accent));
addButton.setOnClickListener(view -> addVideoFromInput()); addButton.setOnClickListener(view -> addVideoFromInput());
LinearLayout.LayoutParams addParams = new LinearLayout.LayoutParams(dp(72), dp(48)); LinearLayout.LayoutParams addParams = new LinearLayout.LayoutParams(dp(74), dp(50));
addParams.leftMargin = dp(8); addParams.leftMargin = dp(8);
urlRow.addView(addButton, addParams); urlRow.addView(addButton, addParams);
@@ -291,11 +291,11 @@ public class MainActivity extends Activity {
searchInput.setSingleLine(true); searchInput.setSingleLine(true);
searchInput.setHint("검색어"); searchInput.setHint("검색어");
searchInput.setImeOptions(EditorInfo.IME_ACTION_SEARCH); searchInput.setImeOptions(EditorInfo.IME_ACTION_SEARCH);
searchInput.setTextSize(16); searchInput.setTextSize(15);
searchInput.setTextColor(palette.textPrimary); searchInput.setTextColor(palette.textPrimary);
searchInput.setHintTextColor(palette.textSecondary); searchInput.setHintTextColor(palette.textSecondary);
searchInput.setBackground(inputBackground()); searchInput.setBackground(inputBackground());
searchInput.setPadding(dp(12), 0, dp(12), 0); searchInput.setPadding(dp(14), 0, dp(14), 0);
searchInput.setText(pendingSearch); searchInput.setText(pendingSearch);
searchInput.setOnEditorActionListener((view, actionId, event) -> { searchInput.setOnEditorActionListener((view, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_DONE) { if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_DONE) {
@@ -320,9 +320,9 @@ public class MainActivity extends Activity {
}); });
LinearLayout.LayoutParams searchParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams searchParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
dp(48) dp(50)
); );
searchParams.topMargin = dp(10); searchParams.topMargin = dp(12);
header.addView(searchInput, searchParams); header.addView(searchInput, searchParams);
addSearchHistoryChips(header); addSearchHistoryChips(header);
@@ -339,7 +339,7 @@ public class MainActivity extends Activity {
listContainer = new LinearLayout(this); listContainer = new LinearLayout(this);
listContainer.setOrientation(LinearLayout.VERTICAL); listContainer.setOrientation(LinearLayout.VERTICAL);
listContainer.setPadding(dp(14), dp(4), dp(14), dp(24)); listContainer.setPadding(dp(16), dp(8), dp(16), dp(28));
scrollView.addView(listContainer, new ScrollView.LayoutParams( scrollView.addView(listContainer, new ScrollView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
@@ -365,7 +365,7 @@ public class MainActivity extends Activity {
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
); );
scrollParams.topMargin = dp(8); scrollParams.topMargin = dp(10);
header.addView(scrollView, scrollParams); header.addView(scrollView, scrollParams);
LinearLayout row = new LinearLayout(this); LinearLayout row = new LinearLayout(this);
@@ -387,7 +387,7 @@ public class MainActivity extends Activity {
}); });
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,
dp(34) dp(32)
); );
params.rightMargin = dp(8); params.rightMargin = dp(8);
row.addView(chip, params); row.addView(chip, params);
@@ -395,7 +395,7 @@ public class MainActivity extends Activity {
Button clearButton = createSmallButton("지우기"); Button clearButton = createSmallButton("지우기");
clearButton.setTextColor(palette.textSecondary); clearButton.setTextColor(palette.textSecondary);
clearButton.setBackground(inputBackground()); clearButton.setBackground(secondaryButtonBackground());
clearButton.setOnClickListener(view -> { clearButton.setOnClickListener(view -> {
searchHistory.clear(); searchHistory.clear();
saveSearchHistory(); saveSearchHistory();
@@ -403,20 +403,27 @@ public class MainActivity extends Activity {
}); });
row.addView(clearButton, new LinearLayout.LayoutParams( row.addView(clearButton, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,
dp(34) dp(32)
)); ));
} }
private void addControlBar(LinearLayout header) { private void addControlBar(LinearLayout header) {
LinearLayout row = new LinearLayout(this); HorizontalScrollView scrollView = new HorizontalScrollView(this);
row.setOrientation(LinearLayout.HORIZONTAL); scrollView.setHorizontalScrollBarEnabled(false);
row.setGravity(Gravity.CENTER_VERTICAL); LinearLayout.LayoutParams scrollParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams rowParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
); );
rowParams.topMargin = dp(10); scrollParams.topMargin = dp(12);
header.addView(row, rowParams); header.addView(scrollView, scrollParams);
LinearLayout row = new LinearLayout(this);
row.setOrientation(LinearLayout.HORIZONTAL);
row.setGravity(Gravity.CENTER_VERTICAL);
scrollView.addView(row, new HorizontalScrollView.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
dp(40)
));
if (selectionMode) { if (selectionMode) {
TextView countView = new TextView(this); TextView countView = new TextView(this);
@@ -424,16 +431,20 @@ public class MainActivity extends Activity {
countView.setTextColor(palette.textPrimary); countView.setTextColor(palette.textPrimary);
countView.setTextSize(14); countView.setTextSize(14);
countView.setTypeface(Typeface.DEFAULT, Typeface.BOLD); countView.setTypeface(Typeface.DEFAULT, Typeface.BOLD);
row.addView(countView, new LinearLayout.LayoutParams(0, dp(40), 1f)); countView.setGravity(Gravity.CENTER_VERTICAL);
countView.setIncludeFontPadding(false);
row.addView(countView, new LinearLayout.LayoutParams(dp(96), dp(38)));
Button applyButton = createToolbarButton("분류"); Button applyButton = createToolbarButton("분류");
applyButton.setTextColor(Color.WHITE); applyButton.setTextColor(Color.WHITE);
applyButton.setTypeface(Typeface.DEFAULT, Typeface.BOLD);
applyButton.setBackground(buttonBackground(palette.accent)); applyButton.setBackground(buttonBackground(palette.accent));
applyButton.setOnClickListener(view -> showBulkEditDialog()); applyButton.setOnClickListener(view -> showBulkEditDialog());
row.addView(applyButton, toolbarButtonParams(false)); row.addView(applyButton, toolbarButtonParams(false));
Button deleteButton = createToolbarButton("삭제"); Button deleteButton = createToolbarButton("삭제");
deleteButton.setTextColor(Color.WHITE); deleteButton.setTextColor(Color.WHITE);
deleteButton.setTypeface(Typeface.DEFAULT, Typeface.BOLD);
deleteButton.setBackground(buttonBackground(Color.rgb(214, 64, 64))); deleteButton.setBackground(buttonBackground(Color.rgb(214, 64, 64)));
deleteButton.setOnClickListener(view -> confirmDeleteSelectedVideos()); deleteButton.setOnClickListener(view -> confirmDeleteSelectedVideos());
row.addView(deleteButton, toolbarButtonParams(true)); row.addView(deleteButton, toolbarButtonParams(true));
@@ -454,7 +465,8 @@ public class MainActivity extends Activity {
Button filterButton = createToolbarButton("분류 없음"); Button filterButton = createToolbarButton("분류 없음");
filterButton.setTextColor(uncategorizedOnly ? Color.WHITE : palette.textPrimary); filterButton.setTextColor(uncategorizedOnly ? Color.WHITE : palette.textPrimary);
filterButton.setBackground(uncategorizedOnly ? buttonBackground(palette.accent) : inputBackground()); filterButton.setTypeface(Typeface.DEFAULT, uncategorizedOnly ? Typeface.BOLD : Typeface.NORMAL);
filterButton.setBackground(uncategorizedOnly ? buttonBackground(palette.accent) : secondaryButtonBackground());
filterButton.setOnClickListener(view -> { filterButton.setOnClickListener(view -> {
uncategorizedOnly = !uncategorizedOnly; uncategorizedOnly = !uncategorizedOnly;
if (uncategorizedOnly) { if (uncategorizedOnly) {
@@ -481,17 +493,17 @@ public class MainActivity extends Activity {
private Button createToolbarButton(String text) { private Button createToolbarButton(String text) {
Button button = createSmallButton(text); Button button = createSmallButton(text);
button.setTextColor(palette.textPrimary); button.setTextColor(palette.textPrimary);
button.setBackground(inputBackground()); button.setBackground(secondaryButtonBackground());
return button; return button;
} }
private LinearLayout.LayoutParams toolbarButtonParams(boolean withLeftMargin) { private LinearLayout.LayoutParams toolbarButtonParams(boolean withLeftMargin) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,
dp(40) dp(38)
); );
if (withLeftMargin) { if (withLeftMargin) {
params.leftMargin = dp(8); params.leftMargin = dp(6);
} }
return params; return params;
} }
@@ -503,7 +515,7 @@ public class MainActivity extends Activity {
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
); );
scrollParams.topMargin = dp(10); scrollParams.topMargin = dp(12);
header.addView(scrollView, scrollParams); header.addView(scrollView, scrollParams);
LinearLayout row = new LinearLayout(this); LinearLayout row = new LinearLayout(this);
@@ -536,7 +548,7 @@ public class MainActivity extends Activity {
addButton.setContentDescription("분류 추가"); addButton.setContentDescription("분류 추가");
addButton.setBackground(buttonBackground(palette.accent)); addButton.setBackground(buttonBackground(palette.accent));
addButton.setOnClickListener(view -> showCategoryDialog(null)); addButton.setOnClickListener(view -> showCategoryDialog(null));
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(dp(44), dp(40)); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(dp(42), dp(38));
params.leftMargin = dp(8); params.leftMargin = dp(8);
row.addView(addButton, params); row.addView(addButton, params);
} }
@@ -544,6 +556,7 @@ public class MainActivity extends Activity {
private Button createCategoryButton(String text, String categoryId, boolean selected, Category category) { private Button createCategoryButton(String text, String categoryId, boolean selected, Category category) {
Button button = createSmallButton(text); Button button = createSmallButton(text);
button.setTextColor(selected ? Color.WHITE : palette.textPrimary); button.setTextColor(selected ? Color.WHITE : palette.textPrimary);
button.setTypeface(Typeface.DEFAULT, selected ? Typeface.BOLD : Typeface.NORMAL);
button.setBackground(categoryTabBackground(selected)); button.setBackground(categoryTabBackground(selected));
button.setOnClickListener(view -> { button.setOnClickListener(view -> {
selectedCategoryId = categoryId; selectedCategoryId = categoryId;
@@ -561,7 +574,7 @@ public class MainActivity extends Activity {
} }
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,
dp(40) dp(38)
); );
params.rightMargin = dp(8); params.rightMargin = dp(8);
button.setLayoutParams(params); button.setLayoutParams(params);
@@ -574,11 +587,15 @@ public class MainActivity extends Activity {
button.setTextSize(13); button.setTextSize(13);
button.setAllCaps(false); button.setAllCaps(false);
button.setGravity(Gravity.CENTER); button.setGravity(Gravity.CENTER);
button.setIncludeFontPadding(false);
button.setMinWidth(0); button.setMinWidth(0);
button.setMinimumWidth(0); button.setMinimumWidth(0);
button.setMinHeight(0); button.setMinHeight(0);
button.setMinimumHeight(0); button.setMinimumHeight(0);
button.setPadding(dp(14), 0, dp(14), 0); button.setPadding(dp(14), 0, dp(14), 0);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
button.setStateListAnimator(null);
}
return button; return button;
} }
@@ -692,7 +709,7 @@ public class MainActivity extends Activity {
} }
} }
AlertDialog.Builder builder = new AlertDialog.Builder(this) AlertDialog.Builder builder = dialogBuilder()
.setTitle("이미 저장된 영상입니다") .setTitle("이미 저장된 영상입니다")
.setMessage(emptyFallback(video.title, video.url)) .setMessage(emptyFallback(video.title, video.url))
.setNegativeButton("취소", null) .setNegativeButton("취소", null)
@@ -767,7 +784,7 @@ public class MainActivity extends Activity {
ScrollView scrollView = new ScrollView(this); ScrollView scrollView = new ScrollView(this);
LinearLayout content = new LinearLayout(this); LinearLayout content = new LinearLayout(this);
content.setOrientation(LinearLayout.VERTICAL); content.setOrientation(LinearLayout.VERTICAL);
content.setPadding(dp(20), dp(8), dp(20), 0); content.setPadding(dp(20), dp(16), dp(20), dp(4));
scrollView.addView(content, new ScrollView.LayoutParams( scrollView.addView(content, new ScrollView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
@@ -787,16 +804,15 @@ public class MainActivity extends Activity {
for (Category category : categories) { for (Category category : categories) {
CheckBox checkBox = new CheckBox(this); CheckBox checkBox = new CheckBox(this);
checkBox.setText(category.name); checkBox.setText(category.name);
checkBox.setTextSize(15);
checkBox.setChecked(preselectedCategoryIds.contains(category.id)); checkBox.setChecked(preselectedCategoryIds.contains(category.id));
checkBox.setPadding(0, dp(4), 0, dp(4));
checkBox.setTag(category.id); checkBox.setTag(category.id);
styleCheckBox(checkBox);
checks.add(checkBox); checks.add(checkBox);
content.addView(checkBox); content.addView(checkBox);
} }
} }
new AlertDialog.Builder(this) dialogBuilder()
.setTitle("공유 영상 추가") .setTitle("공유 영상 추가")
.setView(scrollView) .setView(scrollView)
.setPositiveButton("저장", (dialogInterface, which) -> { .setPositiveButton("저장", (dialogInterface, which) -> {
@@ -945,12 +961,13 @@ public class MainActivity extends Activity {
} }
private View createVideoCard(FavoriteVideo video) { private View createVideoCard(FavoriteVideo video) {
boolean selected = selectionMode && selectedVideoIds.contains(video.id);
LinearLayout card = new LinearLayout(this); LinearLayout card = new LinearLayout(this);
card.setOrientation(LinearLayout.HORIZONTAL); card.setOrientation(LinearLayout.HORIZONTAL);
card.setGravity(Gravity.CENTER_VERTICAL); card.setGravity(Gravity.CENTER_VERTICAL);
card.setPadding(dp(12), dp(12), dp(12), dp(12)); card.setPadding(dp(14), dp(14), dp(14), dp(14));
card.setBackground(cardBackground()); card.setBackground(cardBackground(selected));
card.setMinimumHeight(dp(112)); card.setMinimumHeight(dp(116));
card.setClickable(true); card.setClickable(true);
card.setOnClickListener(view -> { card.setOnClickListener(view -> {
if (selectionMode) { if (selectionMode) {
@@ -965,35 +982,40 @@ public class MainActivity extends Activity {
return true; return true;
}); });
} }
card.setElevation(dp(1)); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
card.setElevation(selected ? dp(3) : dp(1));
}
LinearLayout.LayoutParams cardParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams cardParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
); );
cardParams.setMargins(0, dp(7), 0, dp(7)); cardParams.setMargins(0, dp(6), 0, dp(6));
card.setLayoutParams(cardParams); card.setLayoutParams(cardParams);
if (selectionMode) { if (selectionMode) {
CheckBox selectBox = new CheckBox(this); CheckBox selectBox = new CheckBox(this);
selectBox.setChecked(selectedVideoIds.contains(video.id)); selectBox.setChecked(selectedVideoIds.contains(video.id));
selectBox.setOnClickListener(view -> toggleSelectedVideo(video.id)); selectBox.setOnClickListener(view -> toggleSelectedVideo(video.id));
LinearLayout.LayoutParams selectParams = new LinearLayout.LayoutParams(dp(42), dp(74)); LinearLayout.LayoutParams selectParams = new LinearLayout.LayoutParams(dp(40), dp(72));
card.addView(selectBox, selectParams); card.addView(selectBox, selectParams);
} }
ImageView thumbnail = new ImageView(this); ImageView thumbnail = new ImageView(this);
thumbnail.setScaleType(ImageView.ScaleType.CENTER_CROP); thumbnail.setScaleType(ImageView.ScaleType.CENTER_CROP);
thumbnail.setBackgroundColor(palette.thumbnailPlaceholder); thumbnail.setBackground(roundedDrawable(palette.thumbnailPlaceholder, Color.TRANSPARENT, 0, 8));
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
thumbnail.setClipToOutline(true);
}
thumbnail.setContentDescription(emptyFallback(video.title, "YouTube thumbnail")); thumbnail.setContentDescription(emptyFallback(video.title, "YouTube thumbnail"));
thumbnail.setTag(video.id); thumbnail.setTag(video.id);
LinearLayout.LayoutParams thumbnailParams = new LinearLayout.LayoutParams(dp(132), dp(74)); LinearLayout.LayoutParams thumbnailParams = new LinearLayout.LayoutParams(dp(128), dp(72));
card.addView(thumbnail, thumbnailParams); card.addView(thumbnail, thumbnailParams);
loadThumbnail(video, thumbnail); loadThumbnail(video, thumbnail);
LinearLayout textColumn = new LinearLayout(this); LinearLayout textColumn = new LinearLayout(this);
textColumn.setOrientation(LinearLayout.VERTICAL); textColumn.setOrientation(LinearLayout.VERTICAL);
textColumn.setPadding(dp(12), 0, 0, 0); textColumn.setPadding(dp(14), 0, 0, 0);
card.addView(textColumn, new LinearLayout.LayoutParams( card.addView(textColumn, new LinearLayout.LayoutParams(
0, 0,
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,
@@ -1005,6 +1027,8 @@ public class MainActivity extends Activity {
videoTitle.setTextColor(palette.textPrimary); videoTitle.setTextColor(palette.textPrimary);
videoTitle.setTextSize(15); videoTitle.setTextSize(15);
videoTitle.setTypeface(Typeface.DEFAULT, Typeface.BOLD); videoTitle.setTypeface(Typeface.DEFAULT, Typeface.BOLD);
videoTitle.setIncludeFontPadding(false);
videoTitle.setLineSpacing(0, 1.06f);
videoTitle.setMaxLines(2); videoTitle.setMaxLines(2);
videoTitle.setEllipsize(TextUtils.TruncateAt.END); videoTitle.setEllipsize(TextUtils.TruncateAt.END);
textColumn.addView(videoTitle); textColumn.addView(videoTitle);
@@ -1014,15 +1038,16 @@ public class MainActivity extends Activity {
alias.setText(highlightSearchText(video.alias)); alias.setText(highlightSearchText(video.alias));
alias.setTextColor(palette.accent); alias.setTextColor(palette.accent);
alias.setTextSize(12); alias.setTextSize(12);
alias.setIncludeFontPadding(false);
alias.setSingleLine(true); alias.setSingleLine(true);
alias.setEllipsize(TextUtils.TruncateAt.END); alias.setEllipsize(TextUtils.TruncateAt.END);
alias.setPadding(dp(8), dp(3), dp(8), dp(3)); alias.setPadding(dp(9), dp(4), dp(9), dp(4));
alias.setBackground(chipBackground()); alias.setBackground(chipBackground());
LinearLayout.LayoutParams aliasParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams aliasParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
); );
aliasParams.topMargin = dp(6); aliasParams.topMargin = dp(8);
textColumn.addView(alias, aliasParams); textColumn.addView(alias, aliasParams);
} }
@@ -1031,13 +1056,14 @@ public class MainActivity extends Activity {
memoView.setText(highlightSearchText(video.memo)); memoView.setText(highlightSearchText(video.memo));
memoView.setTextColor(palette.textSecondary); memoView.setTextColor(palette.textSecondary);
memoView.setTextSize(12); memoView.setTextSize(12);
memoView.setLineSpacing(0, 1.08f);
memoView.setMaxLines(2); memoView.setMaxLines(2);
memoView.setEllipsize(TextUtils.TruncateAt.END); memoView.setEllipsize(TextUtils.TruncateAt.END);
LinearLayout.LayoutParams memoParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams memoParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
); );
memoParams.topMargin = dp(5); memoParams.topMargin = dp(6);
textColumn.addView(memoView, memoParams); textColumn.addView(memoView, memoParams);
} }
@@ -1047,13 +1073,14 @@ public class MainActivity extends Activity {
categoryView.setText(highlightSearchText(categoryText)); categoryView.setText(highlightSearchText(categoryText));
categoryView.setTextColor(palette.accent); categoryView.setTextColor(palette.accent);
categoryView.setTextSize(12); categoryView.setTextSize(12);
categoryView.setIncludeFontPadding(false);
categoryView.setSingleLine(true); categoryView.setSingleLine(true);
categoryView.setEllipsize(TextUtils.TruncateAt.END); categoryView.setEllipsize(TextUtils.TruncateAt.END);
LinearLayout.LayoutParams categoryParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams categoryParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
); );
categoryParams.topMargin = dp(5); categoryParams.topMargin = dp(7);
textColumn.addView(categoryView, categoryParams); textColumn.addView(categoryView, categoryParams);
} }
@@ -1063,29 +1090,30 @@ public class MainActivity extends Activity {
subtitle.setText(highlightSearchText(details)); subtitle.setText(highlightSearchText(details));
subtitle.setTextColor(palette.textSecondary); subtitle.setTextColor(palette.textSecondary);
subtitle.setTextSize(12); subtitle.setTextSize(12);
subtitle.setLineSpacing(0, 1.08f);
subtitle.setMaxLines(2); subtitle.setMaxLines(2);
subtitle.setEllipsize(TextUtils.TruncateAt.END); subtitle.setEllipsize(TextUtils.TruncateAt.END);
LinearLayout.LayoutParams subtitleParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams subtitleParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
); );
subtitleParams.topMargin = dp(5); subtitleParams.topMargin = dp(6);
textColumn.addView(subtitle, subtitleParams); textColumn.addView(subtitle, subtitleParams);
} }
if (!selectionMode) { if (!selectionMode) {
Button pinButton = createSmallButton(video.pinned ? "" : ""); Button pinButton = createSmallButton(video.pinned ? "" : "");
pinButton.setTextColor(video.pinned ? palette.accent : palette.textSecondary); pinButton.setTextColor(video.pinned ? palette.accent : palette.textSecondary);
pinButton.setTextSize(20); pinButton.setTextSize(19);
pinButton.setContentDescription(video.pinned ? "고정 해제" : "상단 고정"); pinButton.setContentDescription(video.pinned ? "고정 해제" : "상단 고정");
pinButton.setBackgroundColor(Color.TRANSPARENT); pinButton.setBackground(video.pinned ? softButtonBackground() : transparentTouchBackground());
pinButton.setOnClickListener(view -> { pinButton.setOnClickListener(view -> {
video.pinned = !video.pinned; video.pinned = !video.pinned;
saveVideos(); saveVideos();
renderList(); renderList();
}); });
LinearLayout.LayoutParams pinParams = new LinearLayout.LayoutParams(dp(42), dp(74)); LinearLayout.LayoutParams pinParams = new LinearLayout.LayoutParams(dp(38), dp(72));
pinParams.leftMargin = dp(6); pinParams.leftMargin = dp(8);
card.addView(pinButton, pinParams); card.addView(pinButton, pinParams);
} }
@@ -1145,7 +1173,7 @@ public class MainActivity extends Activity {
ScrollView scrollView = new ScrollView(this); ScrollView scrollView = new ScrollView(this);
LinearLayout content = new LinearLayout(this); LinearLayout content = new LinearLayout(this);
content.setOrientation(LinearLayout.VERTICAL); content.setOrientation(LinearLayout.VERTICAL);
content.setPadding(dp(20), dp(8), dp(20), 0); content.setPadding(dp(20), dp(16), dp(20), dp(4));
scrollView.addView(content, new ScrollView.LayoutParams( scrollView.addView(content, new ScrollView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
@@ -1162,6 +1190,7 @@ public class MainActivity extends Activity {
aliasInput.setHint("예: 순두부, 자취요리, 저녁메뉴"); aliasInput.setHint("예: 순두부, 자취요리, 저녁메뉴");
aliasInput.setSelectAllOnFocus(false); aliasInput.setSelectAllOnFocus(false);
aliasInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE); aliasInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
styleDialogInput(aliasInput, 46);
aliasInput.setSelection(aliasInput.getText().length()); aliasInput.setSelection(aliasInput.getText().length());
content.addView(aliasInput, new LinearLayout.LayoutParams( content.addView(aliasInput, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
@@ -1183,6 +1212,7 @@ public class MainActivity extends Activity {
memoInput.setText(video.memo); memoInput.setText(video.memo);
memoInput.setHint("예: 3분 20초부터 보기"); memoInput.setHint("예: 3분 20초부터 보기");
memoInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE); memoInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
styleDialogInput(memoInput, 88);
content.addView(memoInput, new LinearLayout.LayoutParams( content.addView(memoInput, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
@@ -1190,9 +1220,8 @@ public class MainActivity extends Activity {
CheckBox pinnedCheckBox = new CheckBox(this); CheckBox pinnedCheckBox = new CheckBox(this);
pinnedCheckBox.setText("상단에 고정"); pinnedCheckBox.setText("상단에 고정");
pinnedCheckBox.setTextSize(15);
pinnedCheckBox.setChecked(video.pinned); pinnedCheckBox.setChecked(video.pinned);
pinnedCheckBox.setPadding(0, dp(8), 0, dp(4)); styleCheckBox(pinnedCheckBox);
content.addView(pinnedCheckBox); content.addView(pinnedCheckBox);
Button refreshButton = createToolbarButton("제목 새로고침"); Button refreshButton = createToolbarButton("제목 새로고침");
@@ -1245,16 +1274,15 @@ public class MainActivity extends Activity {
checkBox.setText(suggestedCategoryIds.contains(category.id) checkBox.setText(suggestedCategoryIds.contains(category.id)
? category.name + " (추천)" ? category.name + " (추천)"
: category.name); : category.name);
checkBox.setTextSize(15);
checkBox.setChecked(video.categoryIds.contains(category.id)); checkBox.setChecked(video.categoryIds.contains(category.id));
checkBox.setPadding(0, dp(4), 0, dp(4));
checkBox.setTag(category.id); checkBox.setTag(category.id);
styleCheckBox(checkBox);
categoryChecks.add(checkBox); categoryChecks.add(checkBox);
content.addView(checkBox); content.addView(checkBox);
} }
} }
AlertDialog dialog = new AlertDialog.Builder(this) AlertDialog dialog = dialogBuilder()
.setTitle("영상 편집") .setTitle("영상 편집")
.setView(scrollView) .setView(scrollView)
.setPositiveButton("저장", (dialogInterface, which) -> { .setPositiveButton("저장", (dialogInterface, which) -> {
@@ -1279,7 +1307,7 @@ public class MainActivity extends Activity {
} }
private void confirmDelete(FavoriteVideo video, AlertDialog editDialog) { private void confirmDelete(FavoriteVideo video, AlertDialog editDialog) {
new AlertDialog.Builder(this) dialogBuilder()
.setTitle("삭제할까요?") .setTitle("삭제할까요?")
.setMessage(emptyFallback(video.title, video.url)) .setMessage(emptyFallback(video.title, video.url))
.setPositiveButton("삭제", (dialogInterface, which) -> { .setPositiveButton("삭제", (dialogInterface, which) -> {
@@ -1298,7 +1326,7 @@ public class MainActivity extends Activity {
return; return;
} }
new AlertDialog.Builder(this) dialogBuilder()
.setTitle("선택한 영상을 삭제할까요?") .setTitle("선택한 영상을 삭제할까요?")
.setMessage(String.format(Locale.ROOT, "%d개 영상이 삭제됩니다.", selectedVideoIds.size())) .setMessage(String.format(Locale.ROOT, "%d개 영상이 삭제됩니다.", selectedVideoIds.size()))
.setPositiveButton("삭제", (dialogInterface, which) -> { .setPositiveButton("삭제", (dialogInterface, which) -> {
@@ -1324,9 +1352,9 @@ public class MainActivity extends Activity {
input.setInputType(InputType.TYPE_CLASS_TEXT); input.setInputType(InputType.TYPE_CLASS_TEXT);
input.setText(editing ? category.name : ""); input.setText(editing ? category.name : "");
input.setSelectAllOnFocus(true); input.setSelectAllOnFocus(true);
input.setPadding(dp(20), 0, dp(20), 0); styleDialogInput(input, 48);
AlertDialog.Builder builder = new AlertDialog.Builder(this) AlertDialog.Builder builder = dialogBuilder()
.setTitle(editing ? "분류 수정" : "분류 추가") .setTitle(editing ? "분류 수정" : "분류 추가")
.setView(input) .setView(input)
.setPositiveButton("저장", null) .setPositiveButton("저장", null)
@@ -1365,7 +1393,7 @@ public class MainActivity extends Activity {
} }
private void confirmDeleteCategory(Category category, AlertDialog editDialog) { private void confirmDeleteCategory(Category category, AlertDialog editDialog) {
new AlertDialog.Builder(this) dialogBuilder()
.setTitle("분류를 삭제할까요?") .setTitle("분류를 삭제할까요?")
.setMessage(category.name) .setMessage(category.name)
.setPositiveButton("삭제", (dialogInterface, which) -> { .setPositiveButton("삭제", (dialogInterface, which) -> {
@@ -1401,7 +1429,7 @@ public class MainActivity extends Activity {
if (checked < SORT_LATEST || checked > SORT_RECENT) { if (checked < SORT_LATEST || checked > SORT_RECENT) {
checked = SORT_LATEST; checked = SORT_LATEST;
} }
new AlertDialog.Builder(this) dialogBuilder()
.setTitle("정렬") .setTitle("정렬")
.setSingleChoiceItems(labels, checked, (dialogInterface, which) -> { .setSingleChoiceItems(labels, checked, (dialogInterface, which) -> {
sortMode = which; sortMode = which;
@@ -1428,7 +1456,7 @@ public class MainActivity extends Activity {
private void showManageDialog() { private void showManageDialog() {
String[] actions = {"분류 순서 변경", "전체 제목 새로고침", "백업 내보내기", "백업 가져오기"}; String[] actions = {"분류 순서 변경", "전체 제목 새로고침", "백업 내보내기", "백업 가져오기"};
new AlertDialog.Builder(this) dialogBuilder()
.setTitle("관리") .setTitle("관리")
.setItems(actions, (dialogInterface, which) -> { .setItems(actions, (dialogInterface, which) -> {
if (which == 0) { if (which == 0) {
@@ -1453,10 +1481,10 @@ public class MainActivity extends Activity {
ArrayList<Category> workingCategories = new ArrayList<>(categories); ArrayList<Category> workingCategories = new ArrayList<>(categories);
LinearLayout content = new LinearLayout(this); LinearLayout content = new LinearLayout(this);
content.setOrientation(LinearLayout.VERTICAL); content.setOrientation(LinearLayout.VERTICAL);
content.setPadding(dp(16), dp(8), dp(16), 0); content.setPadding(dp(16), dp(14), dp(16), dp(4));
renderReorderRows(content, workingCategories); renderReorderRows(content, workingCategories);
new AlertDialog.Builder(this) dialogBuilder()
.setTitle("분류 순서 변경") .setTitle("분류 순서 변경")
.setView(content) .setView(content)
.setPositiveButton("저장", (dialogInterface, which) -> { .setPositiveButton("저장", (dialogInterface, which) -> {
@@ -1485,7 +1513,7 @@ public class MainActivity extends Activity {
row.setTextSize(16); row.setTextSize(16);
row.setGravity(Gravity.CENTER_VERTICAL); row.setGravity(Gravity.CENTER_VERTICAL);
row.setPadding(dp(14), 0, dp(14), 0); row.setPadding(dp(14), 0, dp(14), 0);
row.setBackground(cardBackground()); row.setBackground(cardBackground(false));
row.setTag(category.id); row.setTag(category.id);
row.setOnLongClickListener(view -> { row.setOnLongClickListener(view -> {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
@@ -1559,7 +1587,7 @@ public class MainActivity extends Activity {
ScrollView scrollView = new ScrollView(this); ScrollView scrollView = new ScrollView(this);
LinearLayout content = new LinearLayout(this); LinearLayout content = new LinearLayout(this);
content.setOrientation(LinearLayout.VERTICAL); content.setOrientation(LinearLayout.VERTICAL);
content.setPadding(dp(20), dp(8), dp(20), 0); content.setPadding(dp(20), dp(16), dp(20), dp(4));
scrollView.addView(content, new ScrollView.LayoutParams( scrollView.addView(content, new ScrollView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
@@ -1588,14 +1616,13 @@ public class MainActivity extends Activity {
for (Category category : categories) { for (Category category : categories) {
CheckBox checkBox = new CheckBox(this); CheckBox checkBox = new CheckBox(this);
checkBox.setText(category.name); checkBox.setText(category.name);
checkBox.setTextSize(15);
checkBox.setPadding(0, dp(4), 0, dp(4));
checkBox.setTag(category.id); checkBox.setTag(category.id);
styleCheckBox(checkBox);
checks.add(checkBox); checks.add(checkBox);
content.addView(checkBox); content.addView(checkBox);
} }
new AlertDialog.Builder(this) dialogBuilder()
.setTitle("일괄 분류 편집") .setTitle("일괄 분류 편집")
.setView(scrollView) .setView(scrollView)
.setPositiveButton("적용", (dialogInterface, which) -> { .setPositiveButton("적용", (dialogInterface, which) -> {
@@ -1639,7 +1666,7 @@ public class MainActivity extends Activity {
LinearLayout content = new LinearLayout(this); LinearLayout content = new LinearLayout(this);
content.setOrientation(LinearLayout.VERTICAL); content.setOrientation(LinearLayout.VERTICAL);
int sidePadding = dp(20); int sidePadding = dp(20);
content.setPadding(sidePadding, dp(8), sidePadding, 0); content.setPadding(sidePadding, dp(16), sidePadding, dp(4));
TextView modeLabel = dialogLabel("화면 모드"); TextView modeLabel = dialogLabel("화면 모드");
content.addView(modeLabel); content.addView(modeLabel);
@@ -1677,7 +1704,7 @@ public class MainActivity extends Activity {
colorRowParams.topMargin = dp(8); colorRowParams.topMargin = dp(8);
content.addView(colorRow, colorRowParams); content.addView(colorRow, colorRowParams);
AlertDialog dialog = new AlertDialog.Builder(this) AlertDialog dialog = dialogBuilder()
.setTitle("테마") .setTitle("테마")
.setView(content) .setView(content)
.setPositiveButton("닫기", null) .setPositiveButton("닫기", null)
@@ -1717,16 +1744,40 @@ public class MainActivity extends Activity {
private TextView dialogLabel(String text) { private TextView dialogLabel(String text) {
TextView label = new TextView(this); TextView label = new TextView(this);
label.setText(text); label.setText(text);
label.setTextColor(Color.rgb(80, 87, 102)); label.setTextColor(palette.textSecondary);
label.setTextSize(13); label.setTextSize(13);
label.setTypeface(Typeface.DEFAULT, Typeface.BOLD); label.setTypeface(Typeface.DEFAULT, Typeface.BOLD);
label.setIncludeFontPadding(false);
return label; return label;
} }
private AlertDialog.Builder dialogBuilder() {
int style = palette != null && palette.dark
? android.R.style.Theme_Material_Dialog_Alert
: android.R.style.Theme_Material_Light_Dialog_Alert;
return new AlertDialog.Builder(this, style);
}
private void styleDialogInput(EditText input, int minHeightDp) {
input.setTextSize(15);
input.setTextColor(palette.textPrimary);
input.setHintTextColor(palette.textSecondary);
input.setBackground(inputBackground());
input.setPadding(dp(14), dp(8), dp(14), dp(8));
input.setMinHeight(dp(minHeightDp));
}
private void styleCheckBox(CheckBox checkBox) {
checkBox.setTextColor(palette.textPrimary);
checkBox.setTextSize(15);
checkBox.setPadding(0, dp(5), 0, dp(5));
}
private RadioButton themeRadioButton(String text, int id) { private RadioButton themeRadioButton(String text, int id) {
RadioButton button = new RadioButton(this); RadioButton button = new RadioButton(this);
button.setText(text); button.setText(text);
button.setTextSize(15); button.setTextSize(15);
button.setTextColor(palette.textPrimary);
button.setId(id); button.setId(id);
button.setPadding(0, dp(4), 0, dp(4)); button.setPadding(0, dp(4), 0, dp(4));
return button; return button;
@@ -2080,42 +2131,77 @@ public class MainActivity extends Activity {
return TextUtils.isEmpty(value) ? fallback : value; return TextUtils.isEmpty(value) ? fallback : value;
} }
private GradientDrawable inputBackground() { private Drawable inputBackground() {
GradientDrawable drawable = new GradientDrawable(); return statefulBackground(
drawable.setColor(palette.input); roundedDrawable(palette.input, palette.border, 1, 8),
drawable.setCornerRadius(dp(8)); roundedDrawable(blend(palette.accent, palette.input, palette.dark ? 0.18f : 0.08f),
drawable.setStroke(dp(1), palette.border); blend(palette.accent, palette.border, 0.38f), 1, 8)
return drawable; );
} }
private GradientDrawable buttonBackground(int color) { private Drawable secondaryButtonBackground() {
GradientDrawable drawable = new GradientDrawable(); return statefulBackground(
drawable.setColor(color); roundedDrawable(palette.input, palette.border, 1, 8),
drawable.setCornerRadius(dp(8)); roundedDrawable(blend(palette.accent, palette.input, palette.dark ? 0.16f : 0.07f),
return drawable; blend(palette.accent, palette.border, 0.24f), 1, 8)
);
} }
private GradientDrawable categoryTabBackground(boolean selected) { private Drawable softButtonBackground() {
GradientDrawable drawable = new GradientDrawable(); int fill = blend(palette.accent, palette.surface, palette.dark ? 0.24f : 0.11f);
drawable.setColor(selected ? palette.accent : palette.surface); int pressed = blend(palette.accent, palette.surface, palette.dark ? 0.34f : 0.18f);
drawable.setCornerRadius(dp(8)); int stroke = blend(palette.accent, palette.border, 0.32f);
drawable.setStroke(dp(1), selected ? palette.accent : palette.border); return statefulBackground(
return drawable; roundedDrawable(fill, stroke, 1, 8),
roundedDrawable(pressed, stroke, 1, 8)
);
} }
private GradientDrawable cardBackground() { private Drawable transparentTouchBackground() {
GradientDrawable drawable = new GradientDrawable(); return statefulBackground(
drawable.setColor(palette.surface); roundedDrawable(Color.TRANSPARENT, Color.TRANSPARENT, 0, 8),
drawable.setCornerRadius(dp(8)); roundedDrawable(blend(palette.accent, palette.surface, palette.dark ? 0.20f : 0.10f),
drawable.setStroke(dp(1), palette.border); Color.TRANSPARENT, 0, 8)
return drawable; );
} }
private GradientDrawable chipBackground() { private Drawable buttonBackground(int color) {
GradientDrawable drawable = new GradientDrawable(); int pressed = palette.dark ? blend(Color.WHITE, color, 0.10f) : blend(Color.BLACK, color, 0.08f);
drawable.setColor(palette.chipBackground); return statefulBackground(
drawable.setCornerRadius(dp(8)); roundedDrawable(color, Color.TRANSPARENT, 0, 8),
return drawable; roundedDrawable(pressed, Color.TRANSPARENT, 0, 8)
);
}
private Drawable categoryTabBackground(boolean selected) {
if (selected) {
return buttonBackground(palette.accent);
}
return secondaryButtonBackground();
}
private Drawable cardBackground(boolean selected) {
if (selected) {
int fill = blend(palette.accent, palette.surface, palette.dark ? 0.22f : 0.10f);
return statefulBackground(
roundedDrawable(fill, palette.accent, 1, 8),
roundedDrawable(blend(palette.accent, palette.surface, palette.dark ? 0.30f : 0.15f),
palette.accent, 1, 8)
);
}
return statefulBackground(
roundedDrawable(palette.surface, palette.border, 1, 8),
roundedDrawable(blend(palette.accent, palette.surface, palette.dark ? 0.10f : 0.04f),
palette.border, 1, 8)
);
}
private Drawable chipBackground() {
return statefulBackground(
roundedDrawable(palette.chipBackground, Color.TRANSPARENT, 0, 8),
roundedDrawable(blend(palette.accent, palette.chipBackground, palette.dark ? 0.18f : 0.10f),
Color.TRANSPARENT, 0, 8)
);
} }
private GradientDrawable swatchBackground(int color, boolean selected) { private GradientDrawable swatchBackground(int color, boolean selected) {
@@ -2127,6 +2213,34 @@ public class MainActivity extends Activity {
return drawable; return drawable;
} }
private GradientDrawable roundedDrawable(int fill, int stroke, int strokeWidthDp, int radiusDp) {
GradientDrawable drawable = new GradientDrawable();
drawable.setColor(fill);
drawable.setCornerRadius(dp(radiusDp));
if (strokeWidthDp > 0) {
drawable.setStroke(dp(strokeWidthDp), stroke);
}
return drawable;
}
private StateListDrawable statefulBackground(Drawable normal, Drawable pressed) {
StateListDrawable drawable = new StateListDrawable();
drawable.addState(new int[]{android.R.attr.state_pressed}, pressed);
drawable.addState(new int[]{android.R.attr.state_focused}, pressed);
drawable.addState(new int[]{}, normal);
return drawable;
}
private int blend(int foreground, int background, float alpha) {
float clamped = Math.max(0f, Math.min(1f, alpha));
float inverse = 1f - clamped;
return Color.rgb(
Math.round(Color.red(foreground) * clamped + Color.red(background) * inverse),
Math.round(Color.green(foreground) * clamped + Color.green(background) * inverse),
Math.round(Color.blue(foreground) * clamped + Color.blue(background) * inverse)
);
}
private ThemePalette createPalette() { private ThemePalette createPalette() {
boolean dark = isDarkModeActive(); boolean dark = isDarkModeActive();
int accent = ACCENT_COLORS[Math.max(0, Math.min(accentIndex, ACCENT_COLORS.length - 1))]; int accent = ACCENT_COLORS[Math.max(0, Math.min(accentIndex, ACCENT_COLORS.length - 1))];
@@ -2134,27 +2248,27 @@ public class MainActivity extends Activity {
return new ThemePalette( return new ThemePalette(
true, true,
accent, accent,
Color.rgb(18, 20, 24), Color.rgb(16, 18, 23),
Color.rgb(31, 34, 40), Color.rgb(28, 32, 40),
Color.rgb(235, 238, 244), Color.rgb(238, 242, 247),
Color.rgb(165, 174, 190), Color.rgb(162, 171, 187),
Color.rgb(57, 63, 74), Color.rgb(52, 59, 70),
Color.rgb(39, 43, 51), Color.rgb(35, 40, 50),
Color.rgb(33, 44, 67), Color.rgb(35, 45, 65),
Color.rgb(48, 54, 65) Color.rgb(47, 54, 66)
); );
} }
return new ThemePalette( return new ThemePalette(
false, false,
accent, accent,
Color.rgb(246, 247, 250), Color.rgb(243, 245, 248),
Color.WHITE, Color.WHITE,
Color.rgb(31, 35, 44), Color.rgb(24, 32, 43),
Color.rgb(94, 103, 118), Color.rgb(96, 106, 122),
Color.rgb(217, 223, 235), Color.rgb(216, 224, 234),
Color.WHITE, Color.rgb(249, 251, 253),
Color.rgb(235, 241, 255), Color.rgb(238, 244, 255),
Color.rgb(226, 231, 240) Color.rgb(226, 232, 241)
); );
} }
@@ -2427,7 +2541,7 @@ public class MainActivity extends Activity {
} }
String rawJson = readText(stream); String rawJson = readText(stream);
BackupData backupData = parseBackup(rawJson); BackupData backupData = parseBackup(rawJson);
new AlertDialog.Builder(this) dialogBuilder()
.setTitle("백업을 가져올까요?") .setTitle("백업을 가져올까요?")
.setMessage("현재 저장된 영상과 분류가 백업 내용으로 교체됩니다.") .setMessage("현재 저장된 영상과 분류가 백업 내용으로 교체됩니다.")
.setPositiveButton("가져오기", (dialogInterface, which) -> applyBackup(backupData)) .setPositiveButton("가져오기", (dialogInterface, which) -> applyBackup(backupData))