package com.dark98.santoku.components; import android.content.Context; import android.content.Intent; import android.graphics.drawable.GradientDrawable; import android.net.Uri; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.Scroller; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.core.graphics.ColorUtils; import androidx.viewpager.widget.PagerAdapter; import androidx.viewpager.widget.ViewPager; import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetDialog; import org.json.JSONObject; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; import ru.ytkab0bp.eventbus.EventHandler; import com.dark98.santoku.BeamServerData; import com.dark98.santoku.R; import com.dark98.santoku.Santoku; import com.dark98.santoku.events.BeamServerDataUpdatedEvent; import com.dark98.santoku.theme.ThemesRepo; import com.dark98.santoku.utils.ViewUtils; import com.dark98.santoku.view.BeamButton; import com.dark98.santoku.view.BoostySubsView; public class ChangeLogBottomSheet extends BottomSheetDialog { private BoostySubsView subsView; private ScrollView scrollView; private ViewPager pager; public ChangeLogBottomSheet(@NonNull Context context) { super(context); LinearLayout ll = new LinearLayout(context); ll.setOrientation(LinearLayout.VERTICAL); GradientDrawable gd = new GradientDrawable(); gd.setCornerRadii(new float[] { ViewUtils.dp(28), ViewUtils.dp(28), ViewUtils.dp(28), ViewUtils.dp(28), 0, 0, 0, 0 }); gd.setColor(ThemesRepo.getColor(R.attr.dialogBackground)); ll.setBackground(gd); ll.setPadding(0, ViewUtils.dp(12), 0, ViewUtils.dp(12)); FrameLayout fl = new FrameLayout(context); TextView titleA = new TextView(context); titleA.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); titleA.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); titleA.setText(R.string.Changelog); titleA.setTextColor(ThemesRepo.getColor(android.R.attr.textColorPrimary)); titleA.setGravity(Gravity.CENTER); titleA.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) {{ leftMargin = rightMargin = ViewUtils.dp(21); }}); fl.addView(titleA); TextView titleB = new TextView(context); titleB.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); titleB.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); titleB.setText(R.string.ChangelogBoosty); titleB.setTextColor(ThemesRepo.getColor(R.attr.textColorOnAccent)); titleB.setGravity(Gravity.CENTER); titleB.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) {{ leftMargin = rightMargin = ViewUtils.dp(21); }}); titleB.setAlpha(0f); fl.addView(titleB); ll.addView(fl); scrollView = new ScrollView(context); TextView text = new TextView(context); text.setTextColor(ThemesRepo.getColor(android.R.attr.textColorPrimary)); text.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); text.setPadding(ViewUtils.dp(16), ViewUtils.dp(12), ViewUtils.dp(16), ViewUtils.dp(12)); try { InputStream in = getContext().getAssets().open("update.json"); ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] buffer = new byte[10240]; int c; while ((c = in.read(buffer)) != -1) { bos.write(buffer, 0, c); } bos.close(); in.close(); JSONObject obj = new JSONObject(bos.toString()); String code = Locale.getDefault().getLanguage(); if (obj.has(code)) { text.setText(obj.getString(code)); } else { text.setText(obj.getString("en")); } } catch (Exception e) { Log.e("Changelog", "Failed to open update file", e); } scrollView.addView(text); DisplayMetrics dm = context.getResources().getDisplayMetrics(); pager = new ViewPager(context) {{ try { Field scroller = ViewPager.class.getDeclaredField("mScroller"); scroller.setAccessible(true); Scroller mScroller = new Scroller(getContext(), ViewUtils.CUBIC_INTERPOLATOR::getInterpolation); scroller.set(this, mScroller); } catch (Exception ignored) {} }}; pager.setAdapter(new PagerAdapter() { @Override public int getCount() { return BeamServerData.isBoostyAvailable() ? 2 : 1; } @NonNull @Override public Object instantiateItem(@NonNull ViewGroup container, int position) { View v; if (position == 0) { v = scrollView; } else { LinearLayout ll = new LinearLayout(context); ll.setOrientation(LinearLayout.VERTICAL); TextView subtitle = new TextView(context); subtitle.setTextColor(ThemesRepo.getColor(R.attr.textColorOnAccent)); subtitle.setText(R.string.ChangelogBoostyDescription); subtitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); subtitle.setGravity(Gravity.CENTER); subtitle.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); subtitle.setPadding(ViewUtils.dp(12), 0, ViewUtils.dp(12), 0); ll.addView(subtitle); subsView = new BoostySubsView(context); if (Santoku.SERVER_DATA != null) { List list = new ArrayList<>(Santoku.SERVER_DATA.boostySubscribers); Collections.shuffle(list); subsView.setStrings(list); } ll.addView(subsView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f)); TextView subscribeButton = new TextView(context); subscribeButton.setText(R.string.IntroBoostySupport); subscribeButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); subscribeButton.setTextColor(ThemesRepo.getColor(R.attr.boostyColorTop)); subscribeButton.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); subscribeButton.setGravity(Gravity.CENTER); subscribeButton.setPadding(ViewUtils.dp(12), ViewUtils.dp(8), ViewUtils.dp(12), ViewUtils.dp(8)); subscribeButton.setOnClickListener(v2 -> context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://boosty.to/ytkab0bp")))); ll.addView(subscribeButton, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); v = ll; } container.addView(v); return v; } @Override public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { container.removeView((View) object); } @Override public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { return view == object; } }); BeamButton btn = new BeamButton(context); pager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { super.onPageSelected(position); if (position == pager.getAdapter().getCount() - 1) { btn.setText(R.string.ChangelogOK); } else { btn.setText(R.string.ChangelogNext); } } private int[] colors = new int[2]; @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { float pr = position == 0 ? positionOffset : 1f; colors[0] = ColorUtils.blendARGB(ThemesRepo.getColor(R.attr.dialogBackground), ThemesRepo.getColor(R.attr.boostyColorTop), pr); colors[1] = ColorUtils.blendARGB(ThemesRepo.getColor(R.attr.dialogBackground), ThemesRepo.getColor(R.attr.boostyColorBottom), pr); gd.setColors(colors); titleA.setAlpha(1f - pr); titleA.setTranslationX(-titleA.getWidth() * 0.25f * pr); titleB.setAlpha(pr); titleB.setTranslationX(titleB.getWidth() * 0.25f * (1f - pr)); btn.setColor(ColorUtils.blendARGB(ThemesRepo.getColor(android.R.attr.colorAccent), ThemesRepo.getColor(R.attr.boostyColorTop), pr)); } }); ll.addView(pager, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) (dm.heightPixels * 0.45f))); btn.setText(R.string.ChangelogNext); btn.setOnClickListener(v -> { if (pager.getCurrentItem() != pager.getAdapter().getCount() - 1) { pager.setCurrentItem(pager.getCurrentItem() + 1); } else { dismiss(); } }); ll.addView(btn, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(48)) {{ leftMargin = topMargin = rightMargin = bottomMargin = ViewUtils.dp(12); }}); ll.setFitsSystemWindows(true); setContentView(ll); Santoku.EVENT_BUS.registerListener(this); setOnDismissListener(dialog -> Santoku.EVENT_BUS.unregisterListener(this)); } @EventHandler(runOnMainThread = true) public void onDataUpdated(BeamServerDataUpdatedEvent e) { if (Santoku.SERVER_DATA != null) { List list = new ArrayList<>(Santoku.SERVER_DATA.boostySubscribers); Collections.shuffle(list); subsView.setStrings(list); } pager.getAdapter().notifyDataSetChanged(); } @Override public void show() { super.show(); getBehavior().setState(BottomSheetBehavior.STATE_EXPANDED); } }