refactor: 用 kotlin 重写大量文件

This commit is contained in:
HuanChengFly 2020-08-22 11:16:42 +08:00
parent 28bb477355
commit bb91694edb
25 changed files with 739 additions and 846 deletions

View File

@ -252,14 +252,12 @@ class BaseApplication : Application() {
when (attrId) {
R.attr.colorPrimary -> {
if (ThemeUtil.THEME_CUSTOM == theme) {
val customPrimaryColorStr = SharedPreferencesUtil.get(context, SharedPreferencesUtil.SP_SETTINGS)
.getString(ThemeUtil.SP_CUSTOM_PRIMARY_COLOR, null)
val customPrimaryColorStr = context.appPreferences.customPrimaryColor
return if (customPrimaryColorStr != null) {
Color.parseColor(customPrimaryColorStr)
} else getColorByAttr(context, attrId, ThemeUtil.THEME_WHITE)
} else if (ThemeUtil.THEME_TRANSLUCENT == theme) {
val primaryColorStr = SharedPreferencesUtil.get(context, SharedPreferencesUtil.SP_SETTINGS)
.getString(ThemeUtil.SP_TRANSLUCENT_PRIMARY_COLOR, null)
val primaryColorStr = context.appPreferences.translucentPrimaryColor
return if (primaryColorStr != null) {
Color.parseColor(primaryColorStr)
} else getColorByAttr(context, attrId, ThemeUtil.THEME_WHITE)
@ -278,8 +276,7 @@ class BaseApplication : Application() {
return context.getColorCompat(R.color.transparent)
}
if (ThemeUtil.THEME_CUSTOM == theme) {
val primary = SharedPreferencesUtil.get(context, SharedPreferencesUtil.SP_SETTINGS)
.getBoolean(ThemeUtil.SP_CUSTOM_TOOLBAR_PRIMARY_COLOR, true)
val primary = context.appPreferences.customToolbarPrimaryColor
return if (primary) {
getColorByAttr(context, R.attr.colorPrimary, theme)
} else context.getColorCompat(R.color.white)

View File

@ -49,6 +49,10 @@ fun Context.toastShort(text: String) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
}
fun Context.toastShort(resId: Int) {
Toast.makeText(this, resId, Toast.LENGTH_SHORT).show()
}
inline fun <reified T : Activity> Activity.goToActivity(pre: (Intent) -> Intent) {
startActivity(pre(Intent(this, T::class.java)))
}

View File

@ -14,10 +14,10 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import butterknife.BindView
import butterknife.OnClick
import com.huanchengfly.tieba.post.api.TiebaApi
import com.huanchengfly.tieba.post.api.models.SubFloorListBean
import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.adapters.RecyclerFloorAdapter
import com.huanchengfly.tieba.post.api.TiebaApi
import com.huanchengfly.tieba.post.api.models.SubFloorListBean
import com.huanchengfly.tieba.post.components.MyLinearLayoutManager
import com.huanchengfly.tieba.post.components.dividers.ThreadDivider
import com.huanchengfly.tieba.post.models.ReplyInfoBean
@ -156,7 +156,7 @@ class FloorActivity : BaseActivity() {
dataBean!!.post!!.id,
dataBean!!.post!!.floor,
dataBean!!.post!!.author.nameShow,
AccountUtil.getLoginInfo(this).nameShow).setPn(pn.toString()).toString()))
AccountUtil.getLoginInfo(this)!!.nameShow).setPn(pn.toString()).toString()))
}
private fun refresh() {

View File

@ -35,15 +35,14 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
import com.huanchengfly.tieba.post.ui.theme.utils.ThemeUtils
import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.adapters.FragmentTabViewPagerAdapter
import com.huanchengfly.tieba.post.api.ForumSortType
import com.huanchengfly.tieba.post.api.TiebaApi
import com.huanchengfly.tieba.post.api.models.CommonResponse
import com.huanchengfly.tieba.post.api.models.ForumPageBean
import com.huanchengfly.tieba.post.api.models.LikeForumResultBean
import com.huanchengfly.tieba.post.api.models.SignResultBean
import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.adapters.FragmentTabViewPagerAdapter
import com.huanchengfly.tieba.post.fragments.ForumFragment
import com.huanchengfly.tieba.post.fragments.ForumFragment.OnRefreshedListener
import com.huanchengfly.tieba.post.fragments.ForumInfoFragment
@ -51,12 +50,13 @@ import com.huanchengfly.tieba.post.interfaces.Refreshable
import com.huanchengfly.tieba.post.interfaces.ScrollTopable
import com.huanchengfly.tieba.post.models.PhotoViewBean
import com.huanchengfly.tieba.post.models.database.History
import com.huanchengfly.tieba.post.toDp
import com.huanchengfly.tieba.post.ui.theme.utils.ThemeUtils
import com.huanchengfly.tieba.post.utils.*
import com.huanchengfly.tieba.post.utils.preload.PreloadUtil
import com.huanchengfly.tieba.post.widgets.MyViewPager
import com.huanchengfly.tieba.post.widgets.theme.TintProgressBar
import com.huanchengfly.tieba.post.widgets.theme.TintToolbar
import com.huanchengfly.tieba.post.toDp
import com.lapism.searchview.widget.SearchView
import retrofit2.Call
import retrofit2.Callback
@ -151,8 +151,7 @@ class ForumActivity : BaseActivity(), View.OnClickListener, OnRefreshedListener
}
private fun getSortType(): ForumSortType {
val defaultSortType = SharedPreferencesUtil.get(this, SharedPreferencesUtil.SP_SETTINGS)
.getString("default_sort_type", ForumSortType.REPLY_TIME.toString())!!.toInt()
val defaultSortType = appPreferences.defaultSortType!!.toInt()
return ForumSortType.valueOf(SharedPreferencesUtil.get(this, SharedPreferencesUtil.SP_SETTINGS)
.getInt(forumName + "_sort_type", defaultSortType))
}

View File

@ -70,8 +70,7 @@ open class MainActivity : BaseActivity(), BottomNavigationView.OnNavigationItemS
private var mSearchAdapter: MainSearchAdapter? = null
public override fun onResume() {
val reason = ThemeUtil.getSharedPreferences(this).getString(ThemeUtil.SP_SWITCH_REASON, null)
val followSystemNight = SharedPreferencesUtil.get(this, SharedPreferencesUtil.SP_SETTINGS)
.getBoolean("follow_system_night", false) && !TextUtils.equals(reason, ThemeUtil.REASON_MANUALLY)
val followSystemNight = appPreferences.followSystemNight
if (followSystemNight) {
if (BaseApplication.isSystemNight && !ThemeUtil.isNightMode(this)) {
SharedPreferencesUtil.put(ThemeUtil.getSharedPreferences(this), SP_SHOULD_SHOW_SNACKBAR, true)
@ -369,7 +368,7 @@ open class MainActivity : BaseActivity(), BottomNavigationView.OnNavigationItemS
instance!!.newCheckUpdate(object : CommonAPICallback<NewUpdateBean?> {
override fun onSuccess(data: NewUpdateBean?) {
if (data != null) {
if (data.isHasUpdate!!) {
if (data.isHasUpdate) {
val cancelable = data.result?.isCancelable
val ignored = SharedPreferencesUtil.get(this@MainActivity, SharedPreferencesUtil.SP_IGNORE_VERSIONS)
.getBoolean(data.result?.versionName + "_" + (data.result?.versionCode), false)

View File

@ -1,406 +0,0 @@
package com.huanchengfly.tieba.post.activities;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.text.Html;
import android.text.Spanned;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import androidx.palette.graphics.Palette;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import com.gyf.immersionbar.ImmersionBar;
import com.huanchengfly.tieba.post.BaseApplication;
import com.huanchengfly.tieba.post.R;
import com.huanchengfly.tieba.post.adapters.ThemeColorAdapter;
import com.huanchengfly.tieba.post.components.MyImageEngine;
import com.huanchengfly.tieba.post.components.MyLinearLayoutManager;
import com.huanchengfly.tieba.post.components.transformations.BlurTransformation;
import com.huanchengfly.tieba.post.ui.theme.utils.ThemeUtils;
import com.huanchengfly.tieba.post.utils.ImageUtil;
import com.huanchengfly.tieba.post.utils.PermissionUtil;
import com.huanchengfly.tieba.post.utils.SharedPreferencesUtil;
import com.huanchengfly.tieba.post.utils.ThemeUtil;
import com.jrummyapps.android.colorpicker.ColorPickerDialog;
import com.jrummyapps.android.colorpicker.ColorPickerDialogListener;
import com.yalantis.ucrop.UCrop;
import com.yanzhenjie.permission.Action;
import com.yanzhenjie.permission.runtime.Permission;
import com.zhihu.matisse.Matisse;
import com.zhihu.matisse.MimeType;
import java.io.File;
import java.util.List;
import static com.huanchengfly.tieba.post.utils.ColorUtils.getDarkerColor;
import static com.huanchengfly.tieba.post.utils.ThemeUtil.SP_TRANSLUCENT_PRIMARY_COLOR;
import static com.huanchengfly.tieba.post.utils.ThemeUtil.THEME_TRANSLUCENT;
public class TranslucentThemeActivity extends BaseActivity implements View.OnClickListener, SeekBar.OnSeekBarChangeListener, ColorPickerDialogListener {
public static final String TAG = TranslucentThemeActivity.class.getSimpleName();
public static final int REQUEST_CODE_CHOOSE = 2;
private Uri mUri;
private int alpha;
private int blur;
private Palette mPalette;
private View mSelectColor;
private ThemeColorAdapter mAdapter;
private View mProgress;
public static String toString(int alpha, int red, int green, int blue) {
String hr = Integer.toHexString(red);
String hg = Integer.toHexString(green);
String hb = Integer.toHexString(blue);
String ha = Integer.toHexString(alpha);
return "#" + fixHexString(ha) + fixHexString(hr) + fixHexString(hg) + fixHexString(hb);
}
public static String fixHexString(String hexString) {
if (hexString.length() < 1) {
hexString = "00";
}
if (hexString.length() == 1) {
hexString = "0" + hexString;
}
if (hexString.length() > 2) {
hexString = hexString.substring(0, 2);
}
return hexString;
}
public static String toString(@ColorInt int color) {
return toString(Color.alpha(color), Color.red(color), Color.green(color), Color.blue(color));
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_CHOOSE && resultCode == RESULT_OK) {
Uri sourceUri = Matisse.obtainResult(data).get(0);
Glide.with(this)
.asDrawable()
.load(sourceUri)
.into(new SimpleTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
Bitmap bitmap = ImageUtil.drawableToBitmap(resource);
File file = ImageUtil.bitmapToFile(bitmap, new File(getCacheDir(), "origin_background.jpg"));
Uri sourceUri = Uri.fromFile(file);
Uri destUri = Uri.fromFile(new File(getCacheDir(), "cropped_background.jpg"));
float height = (float) BaseApplication.ScreenInfo.EXACT_SCREEN_HEIGHT;
float width = (float) BaseApplication.ScreenInfo.EXACT_SCREEN_WIDTH;
UCrop.Options uCropOptions = new UCrop.Options();
uCropOptions.setShowCropFrame(true);
uCropOptions.setShowCropGrid(true);
uCropOptions.setStatusBarColor(getDarkerColor(ThemeUtils.getColorByAttr(TranslucentThemeActivity.this, R.attr.colorPrimary)));
uCropOptions.setToolbarColor(ThemeUtils.getColorByAttr(TranslucentThemeActivity.this, R.attr.colorPrimary));
uCropOptions.setToolbarWidgetColor(ThemeUtils.getColorByAttr(TranslucentThemeActivity.this, R.attr.colorTextOnPrimary));
uCropOptions.setActiveWidgetColor(ThemeUtils.getColorByAttr(TranslucentThemeActivity.this, R.attr.colorAccent));
uCropOptions.setActiveControlsWidgetColor(ThemeUtils.getColorByAttr(TranslucentThemeActivity.this, R.attr.colorAccent));
uCropOptions.setLogoColor(ThemeUtils.getColorByAttr(TranslucentThemeActivity.this, R.attr.colorPrimary));
uCropOptions.setCompressionFormat(Bitmap.CompressFormat.JPEG);
UCrop.of(sourceUri, destUri)
.withAspectRatio(width / height, 1)
.withOptions(uCropOptions)
.start(TranslucentThemeActivity.this);
}
});
} else if (resultCode == RESULT_OK && requestCode == UCrop.REQUEST_CROP) {
mUri = UCrop.getOutput(data);
invalidateOptionsMenu();
refreshBackground();
} else if (resultCode == UCrop.RESULT_ERROR) {
final Throwable cropError = UCrop.getError(data);
cropError.printStackTrace();
}
}
private void refreshBackground() {
mProgress.setVisibility(View.VISIBLE);
if (mUri == null) {
findViewById(R.id.background).setBackgroundColor(Color.BLACK);
mProgress.setVisibility(View.GONE);
return;
}
RequestOptions bgOptions = RequestOptions.centerCropTransform()
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE);
if (blur > 0) {
bgOptions = bgOptions.transform(new BlurTransformation(blur));
}
Glide.with(this)
.asDrawable()
.load(mUri)
.apply(bgOptions)
.into(new SimpleTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
resource.setAlpha(alpha);
Bitmap bitmap = ImageUtil.drawableToBitmap(resource);
findViewById(R.id.background).setBackgroundTintList(null);
findViewById(R.id.background).setBackground(new BitmapDrawable(getResources(), bitmap));
mPalette = Palette.from(bitmap).generate();
mAdapter.setPalette(mPalette);
mSelectColor.setVisibility(View.VISIBLE);
mProgress.setVisibility(View.GONE);
}
});
}
@Override
public void refreshStatusBarColor() {
ImmersionBar.with(this)
.transparentBar()
.init();
}
@SuppressLint({"ApplySharedPref", "ClickableViewAccessibility"})
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_translucent_theme);
TextView tip = (TextView) findViewById(R.id.tip);
Spanned spanned;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
spanned = Html.fromHtml(getString(R.string.tip_translucent_theme), Html.FROM_HTML_MODE_LEGACY);
} else {
spanned = Html.fromHtml(getString(R.string.tip_translucent_theme));
}
tip.setText(spanned);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setTitle(R.string.title_dialog_translucent_theme);
}
alpha = SharedPreferencesUtil.get(this, SharedPreferencesUtil.SP_SETTINGS).getInt("translucent_background_alpha", 255);
blur = SharedPreferencesUtil.get(this, SharedPreferencesUtil.SP_SETTINGS).getInt("translucent_background_blur", 0);
Button customColorBtn = (Button) findViewById(R.id.custom_color);
mSelectColor = findViewById(R.id.select_color);
Button selectPicBtn = (Button) findViewById(R.id.select_pic);
mProgress = findViewById(R.id.progress);
mProgress.setOnTouchListener((view, event) -> true);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.select_color_recycler_view);
mAdapter = new ThemeColorAdapter(this);
mAdapter.setOnItemClickListener((itemView, themeColor, position, viewType) -> {
SharedPreferencesUtil.get(this, SharedPreferencesUtil.SP_SETTINGS)
.edit()
.putString(SP_TRANSLUCENT_PRIMARY_COLOR, toString(themeColor))
.commit();
ThemeUtils.refreshUI(this);
});
recyclerView.setLayoutManager(new MyLinearLayoutManager(this, MyLinearLayoutManager.HORIZONTAL, false));
recyclerView.setAdapter(mAdapter);
SeekBar alphaSeekBar = (SeekBar) findViewById(R.id.alpha);
alphaSeekBar.setProgress(alpha);
SeekBar blueSeekBar = (SeekBar) findViewById(R.id.blur);
blueSeekBar.setProgress(blur);
alphaSeekBar.setOnSeekBarChangeListener(this);
blueSeekBar.setOnSeekBarChangeListener(this);
selectPicBtn.setOnClickListener(this);
customColorBtn.setOnClickListener(this);
findViewById(R.id.background).setBackgroundColor(Color.BLACK);
mProgress.setVisibility(View.GONE);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_translucent_theme_toolbar, menu);
return super.onCreateOptionsMenu(menu);
}
@SuppressLint("ApplySharedPref")
@Override
public void onColorSelected(int dialogId, int color) {
SharedPreferencesUtil.get(this, SharedPreferencesUtil.SP_SETTINGS)
.edit()
.putString(SP_TRANSLUCENT_PRIMARY_COLOR, toString(color))
.commit();
ThemeUtils.refreshUI(this);
}
@Override
public void onDialogDismissed(int dialogId) {
}
@SuppressLint("ApplySharedPref")
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_finish:
SharedPreferencesUtil.put(this, SharedPreferencesUtil.SP_SETTINGS, "translucent_background_alpha", alpha);
SharedPreferencesUtil.put(this, SharedPreferencesUtil.SP_SETTINGS, "translucent_background_blur", blur);
/*
saveOriginPic(file -> savePic(file1 -> {
ThemeUtil.getSharedPreferences(this)
.edit()
.putString(ThemeUtil.SP_THEME, THEME_TRANSLUCENT)
.putString(ThemeUtil.SP_OLD_THEME, THEME_TRANSLUCENT)
.commit();
Toast.makeText(TranslucentThemeActivity.this, R.string.toast_save_pic_success, Toast.LENGTH_SHORT).show();
mProgress.setVisibility(View.GONE);
finish();
}));
*/
savePic(file -> {
ThemeUtil.getSharedPreferences(this)
.edit()
.putString(ThemeUtil.SP_THEME, THEME_TRANSLUCENT)
.putString(ThemeUtil.SP_OLD_THEME, THEME_TRANSLUCENT)
.commit();
Toast.makeText(TranslucentThemeActivity.this, R.string.toast_save_pic_success, Toast.LENGTH_SHORT).show();
BaseApplication.setTranslucentBackground(null);
mProgress.setVisibility(View.GONE);
finish();
});
return true;
case R.id.select_color:
return true;
}
return super.onOptionsItemSelected(item);
}
private void savePic(SavePicCallback<File> callback) {
mProgress.setVisibility(View.VISIBLE);
RequestOptions bgOptions = RequestOptions.centerCropTransform()
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE);
if (blur > 0) {
bgOptions = bgOptions.transform(new BlurTransformation(blur));
}
Glide.with(this)
.asDrawable()
.load(mUri)
.apply(bgOptions)
.into(new SimpleTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
resource.setAlpha(alpha);
Bitmap bitmap = ImageUtil.drawableToBitmap(resource);
File file = ImageUtil.compressImage(bitmap, new File(getFilesDir(), "background.jpg"));
mPalette = Palette.from(bitmap).generate();
SharedPreferencesUtil.put(TranslucentThemeActivity.this,
SharedPreferencesUtil.SP_SETTINGS,
ThemeUtil.SP_TRANSLUCENT_THEME_BACKGROUND_PATH,
file.getAbsolutePath());
ThemeUtils.refreshUI(TranslucentThemeActivity.this, TranslucentThemeActivity.this);
callback.onSuccess(file);
}
});
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem finishItem = menu.findItem(R.id.menu_finish);
finishItem.setEnabled(mUri != null);
return super.onPrepareOptionsMenu(menu);
}
private void saveOriginPic(SavePicCallback<File> callback) {
mProgress.setVisibility(View.VISIBLE);
RequestOptions bgOptions = RequestOptions.centerCropTransform()
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE);
Glide.with(this)
.asFile()
.load(mUri)
.apply(bgOptions)
.into(new SimpleTarget<File>() {
@Override
public void onResourceReady(@NonNull File resource, @Nullable Transition<? super File> transition) {
File file = new File(getFilesDir(), "origin_background_file.jpg");
ImageUtil.copyFile(resource, file);
SharedPreferencesUtil.put(TranslucentThemeActivity.this,
SharedPreferencesUtil.SP_SETTINGS,
"translucent_background_origin_path",
file.getAbsolutePath());
callback.onSuccess(file);
}
});
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
switch (seekBar.getId()) {
case R.id.alpha:
alpha = seekBar.getProgress();
break;
case R.id.blur:
blur = seekBar.getProgress();
break;
}
refreshBackground();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.select_pic:
askPermission(data -> Matisse.from(this)
.choose(MimeType.ofImage())
.theme(ThemeUtil.isNightMode(this) ? R.style.Matisse_Dracula : R.style.Matisse_Zhihu)
.imageEngine(new MyImageEngine())
.forResult(REQUEST_CODE_CHOOSE));
break;
case R.id.custom_color:
ColorPickerDialog primaryColorPicker = ColorPickerDialog.newBuilder()
.setDialogTitle(R.string.title_color_picker_primary)
.setDialogType(ColorPickerDialog.TYPE_CUSTOM)
.setShowAlphaSlider(true)
.setDialogId(0)
.setAllowPresets(false)
.setColor(ThemeUtils.getColorById(this, R.color.default_color_primary))
.create();
primaryColorPicker.setColorPickerDialogListener(this);
primaryColorPicker.show(getFragmentManager(), "ColorPicker_TranslucentThemePrimaryColor");
break;
}
}
private void askPermission(Action<List<String>> granted) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
PermissionUtil.askPermission(this, granted, R.string.toast_no_permission_insert_photo,
new PermissionUtil.Permission(Permission.Group.STORAGE, getString(R.string.tip_permission_storage)));
} else {
PermissionUtil.askPermission(this, granted, R.string.toast_no_permission_insert_photo,
new PermissionUtil.Permission(Permission.READ_EXTERNAL_STORAGE, getString(R.string.tip_permission_storage)));
}
}
public interface SavePicCallback<T> {
void onSuccess(T t);
}
}

View File

@ -0,0 +1,344 @@
package com.huanchengfly.tieba.post.activities
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.MotionEvent
import android.view.View
import android.widget.Button
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.appcompat.widget.Toolbar
import androidx.core.text.HtmlCompat
import androidx.palette.graphics.Palette
import androidx.recyclerview.widget.RecyclerView
import butterknife.BindView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import com.gyf.immersionbar.ImmersionBar
import com.huanchengfly.tieba.post.BaseApplication
import com.huanchengfly.tieba.post.BaseApplication.Companion.translucentBackground
import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.adapters.ThemeColorAdapter
import com.huanchengfly.tieba.post.components.MyImageEngine
import com.huanchengfly.tieba.post.components.MyLinearLayoutManager
import com.huanchengfly.tieba.post.components.transformations.BlurTransformation
import com.huanchengfly.tieba.post.interfaces.OnItemClickListener
import com.huanchengfly.tieba.post.toastShort
import com.huanchengfly.tieba.post.ui.theme.utils.ThemeUtils
import com.huanchengfly.tieba.post.utils.ColorUtils
import com.huanchengfly.tieba.post.utils.ImageUtil
import com.huanchengfly.tieba.post.utils.PermissionUtil
import com.huanchengfly.tieba.post.utils.ThemeUtil
import com.jrummyapps.android.colorpicker.ColorPickerDialog
import com.jrummyapps.android.colorpicker.ColorPickerDialogListener
import com.yalantis.ucrop.UCrop
import com.yanzhenjie.permission.Action
import com.yanzhenjie.permission.runtime.Permission
import com.zhihu.matisse.Matisse
import com.zhihu.matisse.MimeType
import java.io.File
class TranslucentThemeActivity : BaseActivity(), View.OnClickListener, OnSeekBarChangeListener, ColorPickerDialogListener {
private var mUri: Uri? = null
private var alpha = 0
private var blur = 0
private var mPalette: Palette? = null
@BindView(R.id.select_color)
lateinit var mSelectColor: View
private var mAdapter: ThemeColorAdapter? = null
@BindView(R.id.progress)
lateinit var mProgress: View
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_CHOOSE && resultCode == Activity.RESULT_OK) {
val sourceUri = Matisse.obtainResult(data)[0]
Glide.with(this)
.asDrawable()
.load(sourceUri)
.into(object : CustomTarget<Drawable>() {
override fun onLoadCleared(placeholder: Drawable?) {}
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
val bitmap = ImageUtil.drawableToBitmap(resource)
val file = ImageUtil.bitmapToFile(bitmap, File(cacheDir, "origin_background.jpg"))
val sourceFileUri = Uri.fromFile(file)
val destUri = Uri.fromFile(File(cacheDir, "cropped_background.jpg"))
val height = BaseApplication.ScreenInfo.EXACT_SCREEN_HEIGHT.toFloat()
val width = BaseApplication.ScreenInfo.EXACT_SCREEN_WIDTH.toFloat()
val uCropOptions = UCrop.Options()
uCropOptions.setShowCropFrame(true)
uCropOptions.setShowCropGrid(true)
uCropOptions.setStatusBarColor(ColorUtils.getDarkerColor(ThemeUtils.getColorByAttr(this@TranslucentThemeActivity, R.attr.colorPrimary)))
uCropOptions.setToolbarColor(ThemeUtils.getColorByAttr(this@TranslucentThemeActivity, R.attr.colorPrimary))
uCropOptions.setToolbarWidgetColor(ThemeUtils.getColorByAttr(this@TranslucentThemeActivity, R.attr.colorTextOnPrimary))
uCropOptions.setActiveWidgetColor(ThemeUtils.getColorByAttr(this@TranslucentThemeActivity, R.attr.colorAccent))
uCropOptions.setActiveControlsWidgetColor(ThemeUtils.getColorByAttr(this@TranslucentThemeActivity, R.attr.colorAccent))
uCropOptions.setLogoColor(ThemeUtils.getColorByAttr(this@TranslucentThemeActivity, R.attr.colorPrimary))
uCropOptions.setCompressionFormat(Bitmap.CompressFormat.JPEG)
UCrop.of(sourceFileUri, destUri)
.withAspectRatio(width / height, 1f)
.withOptions(uCropOptions)
.start(this@TranslucentThemeActivity)
}
})
} else if (resultCode == Activity.RESULT_OK && requestCode == UCrop.REQUEST_CROP) {
mUri = UCrop.getOutput(data!!)
invalidateOptionsMenu()
refreshBackground()
} else if (resultCode == UCrop.RESULT_ERROR) {
val cropError = UCrop.getError(data!!)
cropError!!.printStackTrace()
}
}
private fun refreshBackground() {
mProgress.visibility = View.VISIBLE
if (mUri == null) {
findViewById(R.id.background).setBackgroundColor(Color.BLACK)
mProgress.visibility = View.GONE
return
}
var bgOptions = RequestOptions.centerCropTransform()
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
if (blur > 0) {
bgOptions = bgOptions.transform(BlurTransformation(blur))
}
Glide.with(this)
.asDrawable()
.load(mUri)
.apply(bgOptions)
.into(object : CustomTarget<Drawable>() {
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
resource.alpha = alpha
val bitmap = ImageUtil.drawableToBitmap(resource)
findViewById(R.id.background).backgroundTintList = null
findViewById(R.id.background).background = BitmapDrawable(resources, bitmap)
mPalette = Palette.from(bitmap).generate()
mAdapter!!.setPalette(mPalette)
mSelectColor.visibility = View.VISIBLE
mProgress.visibility = View.GONE
}
override fun onLoadCleared(placeholder: Drawable?) {}
})
}
override fun refreshStatusBarColor() {
ImmersionBar.with(this)
.transparentBar()
.init()
}
override fun getLayoutId(): Int {
return R.layout.activity_translucent_theme
}
@SuppressLint("ApplySharedPref", "ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setSupportActionBar(findViewById(R.id.toolbar) as Toolbar)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
supportActionBar!!.setTitle(R.string.title_dialog_translucent_theme)
(findViewById(R.id.tip) as TextView).apply {
text = HtmlCompat.fromHtml(getString(R.string.tip_translucent_theme), HtmlCompat.FROM_HTML_MODE_LEGACY)
}
(findViewById(R.id.custom_color) as Button).apply {
setOnClickListener(this@TranslucentThemeActivity)
}
(findViewById(R.id.select_pic) as Button).apply {
setOnClickListener(this@TranslucentThemeActivity)
}
mAdapter = ThemeColorAdapter(this)
mAdapter!!.onItemClickListener = OnItemClickListener { _: View?, themeColor: Int, _: Int, _: Int ->
appPreferences.translucentPrimaryColor = toString(themeColor)
ThemeUtils.refreshUI(this)
}
(findViewById(R.id.select_color_recycler_view) as RecyclerView).apply {
layoutManager = MyLinearLayoutManager(this@TranslucentThemeActivity, MyLinearLayoutManager.HORIZONTAL, false)
adapter = mAdapter
}
alpha = appPreferences.translucentBackgroundAlpha
blur = appPreferences.translucentBackgroundBlur
(findViewById(R.id.alpha) as SeekBar).apply {
progress = this@TranslucentThemeActivity.alpha
setOnSeekBarChangeListener(this@TranslucentThemeActivity)
}
(findViewById(R.id.blur) as SeekBar).apply {
progress = this@TranslucentThemeActivity.blur
setOnSeekBarChangeListener(this@TranslucentThemeActivity)
}
mProgress.setOnTouchListener { _: View?, _: MotionEvent? -> true }
mProgress.visibility = View.GONE
findViewById(R.id.background).setBackgroundColor(Color.BLACK)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_translucent_theme_toolbar, menu)
return super.onCreateOptionsMenu(menu)
}
@SuppressLint("ApplySharedPref")
override fun onColorSelected(dialogId: Int, color: Int) {
appPreferences.translucentPrimaryColor = toString(color)
ThemeUtils.refreshUI(this)
}
override fun onDialogDismissed(dialogId: Int) {}
@SuppressLint("ApplySharedPref")
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.menu_finish -> {
appPreferences.apply {
translucentBackgroundAlpha = alpha
translucentBackgroundBlur = blur
}
savePic(object : SavePicCallback<File> {
override fun onSuccess(t: File) {
ThemeUtil.getSharedPreferences(this@TranslucentThemeActivity)
.edit()
.putString(ThemeUtil.SP_THEME, ThemeUtil.THEME_TRANSLUCENT)
.putString(ThemeUtil.SP_OLD_THEME, ThemeUtil.THEME_TRANSLUCENT)
.commit()
toastShort(R.string.toast_save_pic_success)
translucentBackground = null
mProgress.visibility = View.GONE
finish()
}
})
return true
}
R.id.select_color -> return true
}
return super.onOptionsItemSelected(item)
}
private fun savePic(callback: SavePicCallback<File>) {
mProgress.visibility = View.VISIBLE
var bgOptions = RequestOptions.centerCropTransform()
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
if (blur > 0) {
bgOptions = bgOptions.transform(BlurTransformation(blur))
}
Glide.with(this)
.asDrawable()
.load(mUri)
.apply(bgOptions)
.into(object : CustomTarget<Drawable>() {
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
resource.alpha = alpha
val bitmap = ImageUtil.drawableToBitmap(resource)
val file = ImageUtil.compressImage(bitmap, File(filesDir, "background.jpg"))
mPalette = Palette.from(bitmap).generate()
appPreferences.translucentThemeBackgroundPath = file.absolutePath
ThemeUtils.refreshUI(this@TranslucentThemeActivity, this@TranslucentThemeActivity)
callback.onSuccess(file)
}
override fun onLoadCleared(placeholder: Drawable?) {}
})
}
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
val finishItem = menu.findItem(R.id.menu_finish)
finishItem.isEnabled = mUri != null
return super.onPrepareOptionsMenu(menu)
}
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {}
override fun onStartTrackingTouch(seekBar: SeekBar) {}
override fun onStopTrackingTouch(seekBar: SeekBar) {
when (seekBar.id) {
R.id.alpha -> alpha = seekBar.progress
R.id.blur -> blur = seekBar.progress
}
refreshBackground()
}
override fun onClick(v: View) {
when (v.id) {
R.id.select_pic -> askPermission(Action {
Matisse.from(this)
.choose(MimeType.ofImage())
.theme(if (ThemeUtil.isNightMode(this)) R.style.Matisse_Dracula else R.style.Matisse_Zhihu)
.imageEngine(MyImageEngine())
.forResult(REQUEST_CODE_CHOOSE)
})
R.id.custom_color -> {
val primaryColorPicker = ColorPickerDialog.newBuilder()
.setDialogTitle(R.string.title_color_picker_primary)
.setDialogType(ColorPickerDialog.TYPE_CUSTOM)
.setShowAlphaSlider(true)
.setDialogId(0)
.setAllowPresets(false)
.setColor(ThemeUtils.getColorById(this, R.color.default_color_primary))
.create()
primaryColorPicker.setColorPickerDialogListener(this)
primaryColorPicker.show(fragmentManager, "ColorPicker_TranslucentThemePrimaryColor")
}
}
}
private fun askPermission(granted: Action<List<String?>>) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
PermissionUtil.askPermission(this, granted, R.string.toast_no_permission_insert_photo,
PermissionUtil.Permission(Permission.Group.STORAGE, getString(R.string.tip_permission_storage)))
} else {
PermissionUtil.askPermission(this, granted, R.string.toast_no_permission_insert_photo,
PermissionUtil.Permission(Permission.READ_EXTERNAL_STORAGE, getString(R.string.tip_permission_storage)))
}
}
interface SavePicCallback<T> {
fun onSuccess(t: T)
}
companion object {
val TAG = TranslucentThemeActivity::class.java.simpleName
const val REQUEST_CODE_CHOOSE = 2
fun toString(alpha: Int, red: Int, green: Int, blue: Int): String {
val hr = Integer.toHexString(red)
val hg = Integer.toHexString(green)
val hb = Integer.toHexString(blue)
val ha = Integer.toHexString(alpha)
return "#" + fixHexString(ha) + fixHexString(hr) + fixHexString(hg) + fixHexString(hb)
}
private fun fixHexString(string: String): String {
var hexStr = string
if (hexStr.isEmpty()) {
hexStr = "00"
}
if (hexStr.length == 1) {
hexStr = "0$hexStr"
}
if (hexStr.length > 2) {
hexStr = hexStr.substring(0, 2)
}
return hexStr
}
fun toString(@ColorInt color: Int): String {
return toString(Color.alpha(color), Color.red(color), Color.green(color), Color.blue(color))
}
}
}

View File

@ -2,13 +2,14 @@ package com.huanchengfly.tieba.post.api
import android.annotation.SuppressLint
import android.content.Context
import com.huanchengfly.tieba.post.BaseApplication
import com.huanchengfly.tieba.post.api.interfaces.CommonAPICallback
import com.huanchengfly.tieba.post.api.models.ChangelogBean
import com.huanchengfly.tieba.post.api.models.NewUpdateBean
import com.huanchengfly.tieba.post.api.models.UpdateInfoBean
import com.huanchengfly.tieba.post.BaseApplication
import com.huanchengfly.tieba.post.utils.SharedPreferencesUtil
import com.huanchengfly.tieba.post.utils.VersionUtil
import com.huanchengfly.tieba.post.utils.appPreferences
import com.tsy.sdk.myokhttp.MyOkHttp
import com.tsy.sdk.myokhttp.response.GsonResponseHandler
import io.michaelrocks.paranoid.Obfuscate
@ -18,8 +19,8 @@ import java.lang.ref.WeakReference
class LiteApi private constructor(context: Context) {
private val myOkHttp: MyOkHttp = MyOkHttp()
private val contextWeakReference: WeakReference<Context> = WeakReference(context)
val context: Context?
get() = contextWeakReference.get()
val context: Context
get() = contextWeakReference.get()!!
fun changelog(apiCallback: CommonAPICallback<ChangelogBean?>) {
val builder = myOkHttp.get()
@ -44,7 +45,7 @@ class LiteApi private constructor(context: Context) {
}
fun newCheckUpdate(apiCallback: CommonAPICallback<NewUpdateBean?>) {
val beta = SharedPreferencesUtil.get(context, SharedPreferencesUtil.SP_SETTINGS).getBoolean("check_beta_update", false)
val beta = context.appPreferences.checkBetaUpdate
myOkHttp.get()
.url(Url.CHECK_UPDATE)
.addParam("version_code", VersionUtil.getVersionCode(context).toString())

View File

@ -1,154 +0,0 @@
package com.huanchengfly.tieba.post.components.dialogs;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import com.huanchengfly.tieba.post.ui.theme.utils.ThemeUtils;
import com.huanchengfly.tieba.post.R;
import com.huanchengfly.tieba.post.BaseApplication;
import com.huanchengfly.tieba.post.utils.SharedPreferencesUtil;
import com.jrummyapps.android.colorpicker.ColorPickerDialog;
import com.jrummyapps.android.colorpicker.ColorPickerDialogListener;
import java.util.Objects;
import static com.huanchengfly.tieba.post.utils.ThemeUtil.SP_CUSTOM_PRIMARY_COLOR;
import static com.huanchengfly.tieba.post.utils.ThemeUtil.SP_CUSTOM_STATUS_BAR_FONT_DARK;
import static com.huanchengfly.tieba.post.utils.ThemeUtil.SP_CUSTOM_TOOLBAR_PRIMARY_COLOR;
import static com.huanchengfly.tieba.post.utils.ThemeUtil.THEME_CUSTOM;
public class CustomThemeDialog extends AlertDialog implements View.OnClickListener, DialogInterface.OnClickListener, CompoundButton.OnCheckedChangeListener, ColorPickerDialogListener {
private LinearLayout primaryColorLayout;
private View primaryColorView;
private CheckBox statusBarFont;
private CheckBox toolbarPrimaryColor;
private int primaryColor;
private boolean statusBarFontDark;
private boolean toolbarPrimary;
public CustomThemeDialog(@NonNull Context context) {
super(context);
setButton(BUTTON_POSITIVE, context.getString(R.string.button_finish), this);
setCancelable(false);
setTitle(R.string.title_custom_theme);
initView();
initListener();
}
public static String toString(int alpha, int red, int green, int blue) {
String hr = Integer.toHexString(red);
String hg = Integer.toHexString(green);
String hb = Integer.toHexString(blue);
String ha = Integer.toHexString(alpha);
return "#" + fixHexString(ha) + fixHexString(hr) + fixHexString(hg) + fixHexString(hb);
}
public static String fixHexString(String hexString) {
if (hexString.length() < 1) {
hexString = "00";
}
if (hexString.length() == 1) {
hexString = "0" + hexString;
}
if (hexString.length() > 2) {
hexString = hexString.substring(0, 2);
}
return hexString;
}
public static String toString(@ColorInt int color) {
return toString(Color.alpha(color), Color.red(color), Color.green(color), Color.blue(color));
}
private void initListener() {
primaryColorLayout.setOnClickListener(this);
statusBarFont.setOnCheckedChangeListener(this);
toolbarPrimaryColor.setOnCheckedChangeListener(this);
}
private void initView() {
View contentView = View.inflate(getContext(), R.layout.dialog_custom_theme, null);
primaryColorLayout = contentView.findViewById(R.id.custom_theme_primary_holder);
primaryColorView = contentView.findViewById(R.id.custom_theme_primary);
statusBarFont = contentView.findViewById(R.id.custom_theme_status_bar_font);
toolbarPrimaryColor = contentView.findViewById(R.id.custom_theme_toolbar_primary_color);
setView(contentView);
primaryColor = BaseApplication.ThemeDelegate.INSTANCE.getColorByAttr(getContext(), R.attr.colorPrimary, THEME_CUSTOM);
statusBarFontDark = SharedPreferencesUtil.get(getContext(), SharedPreferencesUtil.SP_SETTINGS)
.getBoolean(SP_CUSTOM_STATUS_BAR_FONT_DARK, false);
toolbarPrimary = SharedPreferencesUtil.get(getContext(), SharedPreferencesUtil.SP_SETTINGS)
.getBoolean(SP_CUSTOM_TOOLBAR_PRIMARY_COLOR, true);
refreshView();
}
private void refreshView() {
primaryColorView.setBackgroundTintList(ColorStateList.valueOf(primaryColor));
statusBarFont.setChecked(statusBarFontDark);
toolbarPrimaryColor.setChecked(toolbarPrimary);
statusBarFont.setVisibility(toolbarPrimary ? View.VISIBLE : View.GONE);
ThemeUtils.refreshUI(getContext());
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.custom_theme_primary_holder) {
ColorPickerDialog primaryColorPicker = ColorPickerDialog.newBuilder()
.setDialogTitle(R.string.title_color_picker_primary)
.setDialogType(ColorPickerDialog.TYPE_PRESETS)
.setShowAlphaSlider(false)
.setDialogId(0)
.setAllowPresets(true)
.setColor(primaryColor)
.create();
primaryColorPicker.setColorPickerDialogListener(this);
primaryColorPicker.show(Objects.requireNonNull(ThemeUtils.getWrapperActivity(getContext())).getFragmentManager(), "ColorPicker_PrimaryColor");
}
refreshView();
}
@SuppressLint("ApplySharedPref")
@Override
public void onClick(DialogInterface dialog, int which) {
SharedPreferencesUtil.get(getContext(), SharedPreferencesUtil.SP_SETTINGS)
.edit()
.putString(SP_CUSTOM_PRIMARY_COLOR, toString(primaryColor))
.putBoolean(SP_CUSTOM_STATUS_BAR_FONT_DARK, statusBarFontDark || !toolbarPrimary)
.putBoolean(SP_CUSTOM_TOOLBAR_PRIMARY_COLOR, toolbarPrimary)
.commit();
dialog.dismiss();
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView.getId() == R.id.custom_theme_status_bar_font) {
statusBarFontDark = isChecked;
} else if (buttonView.getId() == R.id.custom_theme_toolbar_primary_color) {
toolbarPrimary = isChecked;
statusBarFontDark = !isChecked;
}
refreshView();
}
@Override
public void onColorSelected(int dialogId, int color) {
if (dialogId == 0) {
primaryColor = color;
refreshView();
}
}
@Override
public void onDialogDismissed(int dialogId) {
}
}

View File

@ -0,0 +1,139 @@
package com.huanchengfly.tieba.post.components.dialogs
import android.annotation.SuppressLint
import android.content.Context
import android.content.DialogInterface
import android.content.res.ColorStateList
import android.graphics.Color
import android.view.View
import android.widget.CheckBox
import android.widget.CompoundButton
import android.widget.LinearLayout
import androidx.annotation.ColorInt
import androidx.appcompat.app.AlertDialog
import com.huanchengfly.tieba.post.BaseApplication.ThemeDelegate.getColorByAttr
import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.ui.theme.utils.ThemeUtils
import com.huanchengfly.tieba.post.utils.ThemeUtil
import com.huanchengfly.tieba.post.utils.appPreferences
import com.jrummyapps.android.colorpicker.ColorPickerDialog
import com.jrummyapps.android.colorpicker.ColorPickerDialogListener
import java.util.*
class CustomThemeDialog(context: Context) : AlertDialog(context),
View.OnClickListener, DialogInterface.OnClickListener, CompoundButton.OnCheckedChangeListener, ColorPickerDialogListener {
private var primaryColorLayout: LinearLayout? = null
private var primaryColorView: View? = null
private var statusBarFont: CheckBox? = null
private var toolbarPrimaryColor: CheckBox? = null
private var primaryColor = 0
private var statusBarFontDark = false
private var toolbarPrimary = false
private fun initListener() {
primaryColorLayout!!.setOnClickListener(this)
statusBarFont!!.setOnCheckedChangeListener(this)
toolbarPrimaryColor!!.setOnCheckedChangeListener(this)
}
private fun initView() {
val contentView = View.inflate(context, R.layout.dialog_custom_theme, null)
primaryColorLayout = contentView.findViewById(R.id.custom_theme_primary_holder)
primaryColorView = contentView.findViewById(R.id.custom_theme_primary)
statusBarFont = contentView.findViewById(R.id.custom_theme_status_bar_font)
toolbarPrimaryColor = contentView.findViewById(R.id.custom_theme_toolbar_primary_color)
setView(contentView)
primaryColor = getColorByAttr(context, R.attr.colorPrimary, ThemeUtil.THEME_CUSTOM)
statusBarFontDark = context.appPreferences.customStatusBarFontDark
toolbarPrimary = context.appPreferences.customToolbarPrimaryColor
refreshView()
}
private fun refreshView() {
primaryColorView!!.backgroundTintList = ColorStateList.valueOf(primaryColor)
statusBarFont!!.isChecked = statusBarFontDark
toolbarPrimaryColor!!.isChecked = toolbarPrimary
statusBarFont!!.visibility = if (toolbarPrimary) View.VISIBLE else View.GONE
ThemeUtils.refreshUI(context)
}
override fun onClick(v: View) {
if (v.id == R.id.custom_theme_primary_holder) {
val primaryColorPicker = ColorPickerDialog.newBuilder()
.setDialogTitle(R.string.title_color_picker_primary)
.setDialogType(ColorPickerDialog.TYPE_PRESETS)
.setShowAlphaSlider(false)
.setDialogId(0)
.setAllowPresets(true)
.setColor(primaryColor)
.create()
primaryColorPicker.setColorPickerDialogListener(this)
primaryColorPicker.show(Objects.requireNonNull(ThemeUtils.getWrapperActivity(context)).fragmentManager, "ColorPicker_PrimaryColor")
}
refreshView()
}
@SuppressLint("ApplySharedPref")
override fun onClick(dialog: DialogInterface, which: Int) {
context.appPreferences.apply {
customPrimaryColor = toString(primaryColor)
customStatusBarFontDark = (statusBarFontDark || !toolbarPrimary)
customToolbarPrimaryColor = toolbarPrimary
}
dialog.dismiss()
}
override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
if (buttonView.id == R.id.custom_theme_status_bar_font) {
statusBarFontDark = isChecked
} else if (buttonView.id == R.id.custom_theme_toolbar_primary_color) {
toolbarPrimary = isChecked
statusBarFontDark = !isChecked
}
refreshView()
}
override fun onColorSelected(dialogId: Int, color: Int) {
if (dialogId == 0) {
primaryColor = color
refreshView()
}
}
override fun onDialogDismissed(dialogId: Int) {}
companion object {
fun toString(alpha: Int, red: Int, green: Int, blue: Int): String {
val hr = Integer.toHexString(red)
val hg = Integer.toHexString(green)
val hb = Integer.toHexString(blue)
val ha = Integer.toHexString(alpha)
return "#" + fixHexString(ha) + fixHexString(hr) + fixHexString(hg) + fixHexString(hb)
}
private fun fixHexString(hex: String): String {
var hexString = hex
if (hexString.isEmpty()) {
hexString = "00"
}
if (hexString.length == 1) {
hexString = "0$hexString"
}
if (hexString.length > 2) {
hexString = hexString.substring(0, 2)
}
return hexString
}
fun toString(@ColorInt color: Int): String {
return toString(Color.alpha(color), Color.red(color), Color.green(color), Color.blue(color))
}
}
init {
setButton(DialogInterface.BUTTON_POSITIVE, context.getString(R.string.button_finish), this)
setCancelable(false)
setTitle(R.string.title_custom_theme)
initView()
initListener()
}
}

View File

@ -26,12 +26,11 @@ import butterknife.ButterKnife;
import butterknife.Unbinder;
/**
* Created by dasu on 2016/9/27.
* <p>
* Fragment基类封装了懒加载的实现
* <p>
* 1Viewpager + Fragment情况下fragment的生命周期因Viewpager的缓存机制而失去了具体意义
* 该抽象类自定义新的回调方法fragment可见状态改变时会触发的回调方法 Fragment 第一次可见时会回调的方法
* ViewPager + Fragment 情况下Fragment 的生命周期因 ViewPager 的缓存机制而失去了具体意义
* 该抽象类自定义新的回调方法 Fragment 可见状态改变时会触发的回调方法 Fragment 第一次可见时会回调的方法
*
* @see #onFragmentVisibleChange(boolean)
* @see #onFragmentFirstVisible()
@ -171,18 +170,18 @@ public abstract class BaseFragment extends Fragment implements BackHandledInterf
/**
* 设置是否使用 view 的复用默认开启
* view 的复用是指ViewPager 在销毁和重建 MessageListFragment 时会不断调用 onCreateView() -> onDestroyView()
* 之间的生命函数这样可能会出现重复创建 view 的情况导致界面上显示多个相同的 MessageListFragment
* view 的复用是指ViewPager 在销毁和重建 Fragment 时会不断调用 onCreateView() -> onDestroyView()
* 之间的生命函数这样可能会出现重复创建 view 的情况导致界面上显示多个相同的 Fragment
* view 的复用其实就是指保存第一次创建的 view后面再 onCreateView() 时直接返回第一次创建的 view
*
* @param isReuse
* @param isReuse 是否使用 view 的复用
*/
protected void reuseView(boolean isReuse) {
isReuseView = isReuse;
}
/**
* 去除setUserVisibleHint()多余的回调场景保证只有当fragment可见状态发生变化时才回调
* 去除 setUserVisibleHint() 多余的回调场景保证只有当 Fragment 可见状态发生变化时才回调
* 回调时机在view创建完后所以支持ui操作解决在setUserVisibleHint()里进行ui操作有可能报null异常的问题
* <p>
* 可在该回调方法里进行一些ui显示与隐藏比如加载框的显示和隐藏
@ -194,7 +193,7 @@ public abstract class BaseFragment extends Fragment implements BackHandledInterf
}
/**
* fragment首次可见时回调可在这里进行加载数据保证只在第一次打开Fragment时才会加载数据
* Fragment 首次可见时回调可在这里进行加载数据保证只在第一次打开 Fragment 时才会加载数据
* 这样就可以防止每次进入都重复加载数据
* 该方法会在 onFragmentVisibleChange() 之前调用所以第一次打开时可以用一个全局变量表示数据下载状态
* 然后在该方法内将状态设置为下载状态接着去执行下载的任务

View File

@ -73,7 +73,7 @@ class FloorFragment : BaseBottomSheetDialogFragment() {
dataBean!!.post!!.id,
dataBean!!.post!!.floor,
dataBean!!.post!!.author.nameShow,
AccountUtil.getLoginInfo(attachContext).nameShow).setPn(pn.toString()).toString()))
AccountUtil.getLoginInfo(attachContext)!!.nameShow).setPn(pn.toString()).toString()))
}
override fun onStart() {

View File

@ -11,6 +11,10 @@ import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import butterknife.BindView
import com.huanchengfly.tieba.post.BaseApplication
import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.activities.ForumActivity
import com.huanchengfly.tieba.post.adapters.LikeForumListAdapter
import com.huanchengfly.tieba.post.api.Error
import com.huanchengfly.tieba.post.api.ForumSortType
import com.huanchengfly.tieba.post.api.TiebaApi
@ -18,10 +22,6 @@ import com.huanchengfly.tieba.post.api.models.CommonResponse
import com.huanchengfly.tieba.post.api.models.ForumRecommend
import com.huanchengfly.tieba.post.api.retrofit.exception.TiebaException
import com.huanchengfly.tieba.post.api.retrofit.exception.TiebaLocalException
import com.huanchengfly.tieba.post.activities.ForumActivity
import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.adapters.LikeForumListAdapter
import com.huanchengfly.tieba.post.BaseApplication
import com.huanchengfly.tieba.post.interfaces.OnItemClickListener
import com.huanchengfly.tieba.post.interfaces.OnItemLongClickListener
import com.huanchengfly.tieba.post.interfaces.Refreshable
@ -55,7 +55,7 @@ class ForumListFragment : BaseFragment(), Refreshable {
override fun onResume() {
super.onResume()
gridLayoutManager!!.spanCount = spanCount
likeForumListAdapter!!.isSingle = SharedPreferencesUtil.get(attachContext, SharedPreferencesUtil.SP_SETTINGS).getBoolean("listSingle", false)
likeForumListAdapter!!.isSingle = appPreferences.listSingle
}
override fun onAccountSwitch() {
@ -78,7 +78,7 @@ class ForumListFragment : BaseFragment(), Refreshable {
}
private val spanCount: Int
get() = if (SharedPreferencesUtil.get(attachContext, SharedPreferencesUtil.SP_SETTINGS).getBoolean("listSingle", false)) {
get() = if (appPreferences.listSingle) {
1
} else {
2
@ -96,8 +96,7 @@ class ForumListFragment : BaseFragment(), Refreshable {
}
private fun getSortType(forumName: String): ForumSortType {
val defaultSortType = SharedPreferencesUtil.get(attachContext, SharedPreferencesUtil.SP_SETTINGS)
.getString("default_sort_type", ForumSortType.REPLY_TIME.toString())!!.toInt()
val defaultSortType = appPreferences.defaultSortType!!.toInt()
return ForumSortType.valueOf(SharedPreferencesUtil.get(attachContext, SharedPreferencesUtil.SP_SETTINGS)
.getInt(forumName + "_sort_type", defaultSortType))
}
@ -127,20 +126,22 @@ class ForumListFragment : BaseFragment(), Refreshable {
topItem.setTitle(if (already) R.string.menu_top_del else R.string.menu_top)
popupMenu.setOnMenuItemClickListener { item: MenuItem ->
when (item.itemId) {
R.id.menu_top -> if (!SharedPreferencesUtil.get(attachContext, SharedPreferencesUtil.SP_SETTINGS).getBoolean("show_top_forum_in_normal_list", true)) {
DialogUtil.build(attachContext)
.setTitle(R.string.title_dialog_show_top_forum)
.setMessage(R.string.message_dialog_show_top_forum)
.setNegativeButton(R.string.button_no) { _, _ -> toggleTopForum(likeForum.forumId) }
.setPositiveButton(R.string.button_yes) { _, _ ->
SharedPreferencesUtil.get(attachContext, SharedPreferencesUtil.SP_SETTINGS).edit().putBoolean("show_top_forum_in_normal_list", true).commit()
toggleTopForum(likeForum.forumId)
}
.setNeutralButton(R.string.button_cancel, null)
.create()
.show()
} else {
toggleTopForum(likeForum.forumId)
R.id.menu_top -> {
if (!appPreferences.showTopForumInNormalList) {
DialogUtil.build(attachContext)
.setTitle(R.string.title_dialog_show_top_forum)
.setMessage(R.string.message_dialog_show_top_forum)
.setNegativeButton(R.string.button_no) { _, _ -> toggleTopForum(likeForum.forumId) }
.setPositiveButton(R.string.button_yes) { _, _ ->
SharedPreferencesUtil.get(attachContext, SharedPreferencesUtil.SP_SETTINGS).edit().putBoolean("show_top_forum_in_normal_list", true).commit()
toggleTopForum(likeForum.forumId)
}
.setNeutralButton(R.string.button_cancel, null)
.create()
.show()
} else {
toggleTopForum(likeForum.forumId)
}
}
R.id.menu_copy -> TiebaUtil.copyText(attachContext, likeForum.forumName)
R.id.menu_unfollow -> {

View File

@ -1,45 +0,0 @@
package com.huanchengfly.tieba.post.receivers;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.huanchengfly.tieba.post.utils.SharedPreferencesUtil;
import com.huanchengfly.tieba.post.utils.TiebaUtil;
import com.huanchengfly.tieba.post.utils.Util;
import java.util.Calendar;
import static android.content.Context.ALARM_SERVICE;
import static android.content.Context.MODE_PRIVATE;
public class BootCompleteSignReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
boolean autoSign = context.getSharedPreferences("settings", MODE_PRIVATE)
.getBoolean("auto_sign", false);
if (autoSign) {
String autoSignTimeStr = context.getSharedPreferences("settings", MODE_PRIVATE)
.getString("auto_sign_time", "09:00");
if (Util.getTimeInMillis(autoSignTimeStr) > System.currentTimeMillis()) {
TiebaUtil.initAutoSign(context);
} else {
int signDay = SharedPreferencesUtil.get(context, SharedPreferencesUtil.SP_SETTINGS).getInt(TiebaUtil.SP_SIGN_DAY, -1);
if (signDay != Calendar.getInstance().get(Calendar.DAY_OF_MONTH)) {
TiebaUtil.startSign(context);
}
AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
if (alarmManager != null) {
Calendar calendar = Util.time2Calendar(autoSignTimeStr);
calendar.add(Calendar.DAY_OF_MONTH, 1);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(context, AutoSignAlarm.class), 0);
alarmManager.setInexactRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
}
}
}
}
}
}

View File

@ -0,0 +1,36 @@
package com.huanchengfly.tieba.post.receivers
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.huanchengfly.tieba.post.utils.TiebaUtil
import com.huanchengfly.tieba.post.utils.Util
import com.huanchengfly.tieba.post.utils.appPreferences
import java.util.*
class BootCompleteSignReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (Intent.ACTION_BOOT_COMPLETED == intent.action) {
val autoSign = context.appPreferences.autoSign
if (autoSign) {
val autoSignTimeStr = context.appPreferences.autoSignTime
if (Util.getTimeInMillis(autoSignTimeStr) > System.currentTimeMillis()) {
TiebaUtil.initAutoSign(context)
} else {
val signDay = context.appPreferences.signDay
if (signDay != Calendar.getInstance()[Calendar.DAY_OF_MONTH]) {
TiebaUtil.startSign(context)
}
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val time = Util.time2Calendar(autoSignTimeStr).apply {
add(Calendar.DAY_OF_MONTH, 1)
}.timeInMillis
val pendingIntent = PendingIntent.getBroadcast(context, 0, Intent(context, AutoSignAlarm::class.java), 0)
alarmManager.setInexactRepeating(AlarmManager.RTC, time, AlarmManager.INTERVAL_DAY, pendingIntent)
}
}
}
}
}

View File

@ -8,15 +8,14 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.huanchengfly.tieba.post.R;
import com.huanchengfly.tieba.post.api.Error;
import com.huanchengfly.tieba.post.api.TiebaApi;
import com.huanchengfly.tieba.post.api.interfaces.CommonCallback;
import com.huanchengfly.tieba.post.api.retrofit.exception.TiebaException;
import com.huanchengfly.tieba.post.R;
import com.huanchengfly.tieba.post.models.MyInfoBean;
import com.huanchengfly.tieba.post.models.database.Account;
import org.jetbrains.annotations.NotNull;
import org.litepal.LitePal;
import java.util.List;
@ -29,8 +28,8 @@ public class AccountUtil {
public static final String TAG = "AccountUtil";
public static final String ACTION_SWITCH_ACCOUNT = "com.huanchengfly.tieba.post.action.SWITCH_ACCOUNT";
@Nullable
public static Account getLoginInfo(@NonNull Context context) {
if (context == null) return null;
int loginUser = context.getSharedPreferences("accountData", Context.MODE_PRIVATE).getInt("now", -1);
if (loginUser == -1) {
return null;
@ -54,11 +53,11 @@ public class AccountUtil {
return LitePal.where("bduss = ?", bduss).findFirst(Account.class);
}
public static boolean isLoggedIn(Context context) {
public static boolean isLoggedIn(@NonNull Context context) {
return (getLoginInfo(context) != null);
}
public static boolean newAccount(Context context, Account account, boolean needSwitch) {
public static boolean newAccount(@NonNull Context context, @NonNull Account account, boolean needSwitch) {
if (account.save()) {
if (needSwitch) {
return switchUser(context, account.getId());
@ -68,17 +67,12 @@ public class AccountUtil {
return false;
}
public static boolean switchUser(Context context, int id) {
context.sendBroadcast(new Intent()
.setAction(ACTION_SWITCH_ACCOUNT));
public static boolean switchUser(@NonNull Context context, int id) {
context.sendBroadcast(new Intent().setAction(ACTION_SWITCH_ACCOUNT));
return context.getSharedPreferences("accountData", Context.MODE_PRIVATE).edit().putInt("now", id).commit();
}
public static void updateUserInfo(Context context, CommonCallback<MyInfoBean> commonCallback) {
if (context == null) {
commonCallback.onFailure(Error.ERROR_UNKNOWN, "未知错误");
return;
}
public static void updateUserInfo(@NonNull Context context, CommonCallback<MyInfoBean> commonCallback) {
Account account = getLoginInfo(context);
if (account == null) {
commonCallback.onFailure(Error.ERROR_NOT_LOGGED_IN, "未登录");
@ -105,10 +99,9 @@ public class AccountUtil {
}
public static void updateUserInfoByBduss(@NonNull Context context, @NonNull String bduss, @Nullable CommonCallback<MyInfoBean> commonCallback) {
if (context == null) return;
TiebaApi.getInstance().myInfo(AccountUtil.getBdussCookie(bduss)).enqueue(new Callback<MyInfoBean>() {
@Override
public void onResponse(@NotNull Call<MyInfoBean> call, @NotNull Response<MyInfoBean> response) {
public void onResponse(@NonNull Call<MyInfoBean> call, @NonNull Response<MyInfoBean> response) {
MyInfoBean myInfoBean = response.body();
if (myInfoBean == null) {
if (commonCallback != null)
@ -149,7 +142,7 @@ public class AccountUtil {
}
@Override
public void onFailure(@NotNull Call<MyInfoBean> call, @NotNull Throwable t) {
public void onFailure(@NonNull Call<MyInfoBean> call, @NonNull Throwable t) {
if (commonCallback != null) {
if (t instanceof TiebaException) {
commonCallback.onFailure(((TiebaException) t).getCode(), t.getMessage());
@ -162,8 +155,7 @@ public class AccountUtil {
}
@SuppressWarnings("ApplySharedPref")
public static void exit(Context context) {
if (context == null) return;
public static void exit(@NonNull Context context) {
List<Account> accounts = getAllAccounts();
Account account = getLoginInfo(context);
if (account == null) return;

View File

@ -2,21 +2,78 @@ package com.huanchengfly.tieba.post.utils
import android.content.Context
import android.content.SharedPreferences
import io.michaelrocks.paranoid.Obfuscate
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
@Obfuscate
open class AppPreferencesUtils(context: Context) {
private val preferences: SharedPreferences =
context.getSharedPreferences("settings", Context.MODE_PRIVATE)
//PreferenceManager.getDefaultSharedPreferences(context)
var loadPictureWhenScroll by SharedPreferenceDelegates.boolean(true)
var autoSign by SharedPreferenceDelegates.boolean(defaultValue = false, key = "auto_sign")
var autoSignTime by SharedPreferenceDelegates.string(defaultValue = "09:00", key = "auto_sign_time")
var checkBetaUpdate by SharedPreferenceDelegates.boolean(defaultValue = false, key = "check_beta_update")
var collectThreadSeeLz by SharedPreferenceDelegates.boolean(defaultValue = true, key = "collect_thread_see_lz")
var customPrimaryColor by SharedPreferenceDelegates.string(key = "custom_primary_color")
var customStatusBarFontDark by SharedPreferenceDelegates.boolean(defaultValue = false, key = "custom_status_bar_font_dark")
var customToolbarPrimaryColor by SharedPreferenceDelegates.boolean(defaultValue = true, key = "custom_toolbar_primary_color")
var defaultSortType by SharedPreferenceDelegates.string(key = "default_sort_type", defaultValue = "0")
var darkTheme by SharedPreferenceDelegates.string(key = "dark_theme", defaultValue = "dark")
var followSystemNight by SharedPreferenceDelegates.boolean(defaultValue = true, key = "follow_system_night")
var hideExplore by SharedPreferenceDelegates.boolean(defaultValue = false)
var imageLoadType by SharedPreferenceDelegates.string(key = "image_load_type", defaultValue = "0")
var listSingle by SharedPreferenceDelegates.boolean(defaultValue = false)
var levelIconOldStyle by SharedPreferenceDelegates.boolean(defaultValue = false, key = "level_icon_old_style")
var littleTail by SharedPreferenceDelegates.string(key = "little_tail")
var loadPictureWhenScroll by SharedPreferenceDelegates.boolean(defaultValue = true)
var radius by SharedPreferenceDelegates.int(defaultValue = 8)
var signDay by SharedPreferenceDelegates.int(defaultValue = -1, key = "sign_day")
var showBothUsernameAndNickname by SharedPreferenceDelegates.boolean(defaultValue = false, key = "show_both_username_and_nickname")
var showShortcutInThread by SharedPreferenceDelegates.boolean(defaultValue = true)
var showTopForumInNormalList by SharedPreferenceDelegates.boolean(defaultValue = true, key = "show_top_forum_in_normal_list")
var statusBarDarker by SharedPreferenceDelegates.boolean(defaultValue = true, key = "status_bar_darker")
var translucentBackgroundAlpha by SharedPreferenceDelegates.int(defaultValue = 255, key = "translucent_background_alpha")
var translucentBackgroundBlur by SharedPreferenceDelegates.int(key = "translucent_background_blur")
var translucentThemeBackgroundPath by SharedPreferenceDelegates.string(key = "translucent_theme_background_path")
var translucentPrimaryColor by SharedPreferenceDelegates.string(key = "translucent_primary_color")
var useCustomTabs by SharedPreferenceDelegates.boolean(defaultValue = true, key = "use_custom_tabs")
var useWebView by SharedPreferenceDelegates.boolean(defaultValue = true, key = "use_webview")
private object SharedPreferenceDelegates {
fun int(defaultValue: Int = 0) = object : ReadWriteProperty<AppPreferencesUtils, Int> {
fun int(
defaultValue: Int = 0,
key: String? = null
) = object : ReadWriteProperty<AppPreferencesUtils, Int> {
override fun getValue(thisRef: AppPreferencesUtils, property: KProperty<*>): Int {
return thisRef.preferences.getInt(property.name, defaultValue)
return thisRef.preferences.getInt(key ?: property.name, defaultValue)
}
override fun setValue(
@ -24,7 +81,7 @@ open class AppPreferencesUtils(context: Context) {
property: KProperty<*>,
value: Int
) {
thisRef.preferences.edit().putInt(property.name, value).apply()
thisRef.preferences.edit().putInt(key ?: property.name, value).apply()
}
}
@ -46,13 +103,16 @@ open class AppPreferencesUtils(context: Context) {
}
}
fun boolean(defaultValue: Boolean = false) =
fun boolean(
defaultValue: Boolean = false,
key: String? = null
) =
object : ReadWriteProperty<AppPreferencesUtils, Boolean> {
override fun getValue(
thisRef: AppPreferencesUtils,
property: KProperty<*>
): Boolean {
return thisRef.preferences.getBoolean(property.name, defaultValue)
return thisRef.preferences.getBoolean(key ?: property.name, defaultValue)
}
override fun setValue(
@ -60,7 +120,7 @@ open class AppPreferencesUtils(context: Context) {
property: KProperty<*>,
value: Boolean
) {
thisRef.preferences.edit().putBoolean(property.name, value).apply()
thisRef.preferences.edit().putBoolean(key ?: property.name, value).apply()
}
}
@ -121,7 +181,7 @@ open class AppPreferencesUtils(context: Context) {
}
}
}
}
val Context.appPreferences: AppPreferencesUtils
get() = AppPreferencesUtils(this)
}
val Context.appPreferences: AppPreferencesUtils
get() = AppPreferencesUtils(this)

View File

@ -61,7 +61,6 @@ public class ThemeUtil {
public static final String THEME_GREY_DARK = "grey_dark";
public static final String THEME_AMOLED_DARK = "amoled_dark";
public static final String SP_CUSTOM_PRIMARY_COLOR = "custom_primary_color";
public static final String SP_TRANSLUCENT_PRIMARY_COLOR = "translucent_primary_color";
public static final String SP_CUSTOM_STATUS_BAR_FONT_DARK = "custom_status_bar_font_dark";
public static final String SP_CUSTOM_TOOLBAR_PRIMARY_COLOR = "custom_toolbar_primary_color";

View File

@ -1,133 +0,0 @@
package com.huanchengfly.tieba.post.utils;
import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.webkit.CookieManager;
import android.widget.Toast;
import com.huanchengfly.tieba.post.R;
import com.huanchengfly.tieba.post.models.database.Account;
import com.huanchengfly.tieba.post.receivers.AutoSignAlarm;
import com.huanchengfly.tieba.post.services.OKSignService;
import org.jetbrains.annotations.Nullable;
import java.util.Calendar;
import static android.content.Context.ALARM_SERVICE;
import static android.content.Context.MODE_PRIVATE;
public class TiebaUtil {
public static final String SP_SIGN_DAY = "sign_day";
public static void copyText(Context context, String text, String toast) {
ClipboardManager cm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
if (cm != null) {
ClipData clipData = ClipData.newPlainText("Tieba Lite", text);
cm.setPrimaryClip(clipData);
Toast.makeText(context, toast, Toast.LENGTH_SHORT).show();
}
}
public static void copyText(Context context, String text) {
copyText(context, text, context.getString(R.string.toast_copy_success));
}
public static void initAutoSign(Context context) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
boolean autoSign = context.getSharedPreferences("settings", MODE_PRIVATE)
.getBoolean("auto_sign", false);
if (alarmManager != null) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, new Intent(context, AutoSignAlarm.class), 0);
if (autoSign) {
String autoSignTimeStr = context.getSharedPreferences("settings", MODE_PRIVATE)
.getString("auto_sign_time", "09:00");
String[] time = autoSignTimeStr.split(":");
int hour = Integer.parseInt(time[0]);
int minute = Integer.parseInt(time[1]);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
if (calendar.getTimeInMillis() >= System.currentTimeMillis()) {
alarmManager.setInexactRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
}
} else {
alarmManager.cancel(pendingIntent);
}
}
}
public static void startSign(Context context) {
SharedPreferencesUtil.get(context, SharedPreferencesUtil.SP_SETTINGS)
.edit()
.putInt(SP_SIGN_DAY, Calendar.getInstance().get(Calendar.DAY_OF_MONTH))
.apply();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(new Intent(context, OKSignService.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setAction(OKSignService.ACTION_START_SIGN));
} else {
context.startService(new Intent(context, OKSignService.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setAction(OKSignService.ACTION_START_SIGN));
}
}
public static void shareText(Context context, String text) {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
String shareText = text + "\n「分享自Tieba Lite客户端」";
sendIntent.putExtra(Intent.EXTRA_TEXT, shareText);
sendIntent.setType("text/plain");
context.startActivity(sendIntent);
}
public static void shareText(Context context, String text, String title) {
if (title == null) {
shareText(context, text);
}
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
String shareText = "" + title + "\n" + text + "\n「分享自Tieba Lite客户端」";
sendIntent.putExtra(Intent.EXTRA_TEXT, shareText);
sendIntent.setType("text/plain");
context.startActivity(sendIntent);
}
@Deprecated
@Nullable
public static String getBduss(Context context) {
Account account = AccountUtil.getLoginInfo(context);
if (account != null) {
return account.getBduss();
}
return null;
}
@Deprecated
@Nullable
public static String getBdussCookie(Context context) {
String bduss = getBduss(context);
if (bduss != null) {
return "BDUSS=" + bduss + ";";
}
return null;
}
@SuppressLint("ApplySharedPref")
@Deprecated
public static void exit(Context context) {
SharedPreferences sp = context.getSharedPreferences("accountData", MODE_PRIVATE);
SharedPreferences.Editor edit = sp.edit();
edit.clear().commit();
CookieManager.getInstance().removeAllCookies(null);
Toast.makeText(context, "退出登录成功", Toast.LENGTH_SHORT).show();
}
}

View File

@ -0,0 +1,69 @@
package com.huanchengfly.tieba.post.utils
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.os.Build
import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.receivers.AutoSignAlarm
import com.huanchengfly.tieba.post.services.OKSignService
import com.huanchengfly.tieba.post.toastShort
import java.util.*
object TiebaUtil {
@JvmStatic
@JvmOverloads
fun copyText(context: Context, text: String?, toast: String = context.getString(R.string.toast_copy_success)) {
val cm = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clipData = ClipData.newPlainText("Tieba Lite", text)
cm.setPrimaryClip(clipData)
context.toastShort(toast)
}
fun initAutoSign(context: Context) {
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val autoSign = context.appPreferences.autoSign
val pendingIntent = PendingIntent.getBroadcast(context, 0, Intent(context, AutoSignAlarm::class.java), 0)
if (autoSign) {
val autoSignTimeStr = context.appPreferences.autoSignTime!!
val time = autoSignTimeStr.split(":".toRegex()).toTypedArray()
val hour = time[0].toInt()
val minute = time[1].toInt()
val calendar = Calendar.getInstance()
calendar[Calendar.HOUR_OF_DAY] = hour
calendar[Calendar.MINUTE] = minute
if (calendar.timeInMillis >= System.currentTimeMillis()) {
alarmManager.setInexactRepeating(AlarmManager.RTC, calendar.timeInMillis, AlarmManager.INTERVAL_DAY, pendingIntent)
}
} else {
alarmManager.cancel(pendingIntent)
}
}
@JvmStatic
fun startSign(context: Context) {
context.appPreferences.signDay = Calendar.getInstance()[Calendar.DAY_OF_MONTH]
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(Intent(context, OKSignService::class.java)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setAction(OKSignService.ACTION_START_SIGN))
} else {
context.startService(Intent(context, OKSignService::class.java)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setAction(OKSignService.ACTION_START_SIGN))
}
}
@JvmStatic
@JvmOverloads
fun shareText(context: Context, text: String, title: String? = null) {
context.startActivity(Intent().apply {
action = Intent.ACTION_SEND
type = "text/plain"
putExtra(Intent.EXTRA_TEXT, "${if (title != null) "「$title」\n" else ""}$text\n(分享自贴吧 Lite")
})
}
}

View File

@ -272,7 +272,7 @@
<string name="desc_hot_message_list">(每小时更新一次,以实时讨论量排序)</string>
<string name="toast_photo_saved">图片保存在 %1$s</string>
<string name="title_settings_default_sort_type">吧默认排序方式</string>
<string name="summary_default_sort_type">设置浏览吧贴子的默认排序方式</string>
<string name="summary_default_sort_type">设置浏览吧贴子的默认排序方式</string>
<string name="toast_load_failed">加载失败</string>
<string name="toast_deleted">已删除</string>
<string name="button_undo">撤销</string>

View File

@ -9,7 +9,10 @@
android:layout="@layout/layout_preference"
android:icon="@drawable/ic_round_format_paint_red"
android:title="@string/title_select_theme">
<intent android:targetPackage="com.huanchengfly.tieba.post" android:targetClass="com.huanchengfly.tieba.post.activities.ThemeActivity" android:action="android.intent.action.VIEW" />
<intent
android:targetPackage="com.huanchengfly.tieba.post"
android:targetClass="com.huanchengfly.tieba.post.activities.ThemeActivity"
android:action="android.intent.action.VIEW" />
</Preference>
<ListPreference
@ -46,17 +49,18 @@
android:title="@string/title_hide_explore" />
<SwitchPreference
android:icon="@drawable/ic_round_outlet"
android:defaultValue="false"
android:key="level_icon_old_style"
android:title="@string/title_level_old_style" />
<androidx.preference.SeekBarPreference
android:icon="@drawable/ic_round_rounded_corner"
app:min="0"
android:max="16"
app:showSeekBarValue="true"
android:defaultValue="8"
android:key="radius"
android:title="@string/title_preference_radius" />
</androidx.preference.PreferenceCategory>
</androidx.preference.PreferenceScreen>

View File

@ -4,9 +4,7 @@
xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.preference.PreferenceCategory
android:layout="@layout/layout_preference_category_no_title">
<androidx.preference.DropDownPreference
android:layout="@layout/layout_preference_dropdown"
<ListPreference
android:icon="@drawable/ic_round_photo_size_select_actual"
android:key="image_load_type"
android:entries="@array/image_load_type_entries"
@ -14,18 +12,16 @@
android:defaultValue="0"
android:title="@string/title_settings_image_load_type" />
<androidx.preference.DropDownPreference
android:layout="@layout/layout_preference_dropdown"
<ListPreference
android:entries="@array/sort_type_entries"
android:entryValues="@array/sort_type_entry_values"
android:title="@string/title_settings_default_sort_type"
android:summaryOff="@string/summary_default_sort_type"
android:defaultValue="0"
android:key="default_sort_type"
android:icon="@drawable/ic_round_calendar_view_day" />
<SwitchPreference
android:layout="@layout/layout_preference"
android:widgetLayout="@layout/layout_switch"
android:icon="@drawable/ic_quick_yellow"
android:defaultValue="true"
android:key="showShortcutInThread"
@ -34,8 +30,6 @@
android:summaryOn="@string/tip_show_shortcut_in_thread_on" />
<SwitchPreference
android:layout="@layout/layout_preference"
android:widgetLayout="@layout/layout_switch"
android:icon="@drawable/ic_round_star_yellow"
android:defaultValue="true"
android:key="collect_thread_see_lz"
@ -44,8 +38,6 @@
android:summaryOn="@string/tip_collect_thread_see_lz_on" />
<SwitchPreference
android:layout="@layout/layout_preference"
android:widgetLayout="@layout/layout_switch"
android:icon="@drawable/ic_arrow_dropup_circle"
android:defaultValue="true"
android:key="show_top_forum_in_normal_list"
@ -53,8 +45,15 @@
android:summary="@string/summary_show_top_forum_in_normal_list" />
<SwitchPreference
android:icon="@drawable/ic_round_verified"
android:defaultValue="false"
android:key="show_both_username_and_nickname"
android:title="@string/title_show_both_username_and_nickname" />
<SwitchPreference
android:icon="@drawable/ic_round_hourglass_full"
android:defaultValue="true"
android:key="loadPictureWhenScroll"
android:title="@string/title_load_picture_when_scroll" />
</androidx.preference.PreferenceCategory>
</androidx.preference.PreferenceScreen>

View File

@ -22,15 +22,5 @@
android:title="@string/title_use_webview"
android:summaryOn="@string/tip_use_webview_on"
android:summaryOff="@string/tip_use_webview"/>
<SwitchPreference
android:icon="@drawable/ic_today"
android:layout="@layout/layout_preference"
android:widgetLayout="@layout/layout_switch"
android:defaultValue="true"
android:key="use_custom_tabs"
android:title="@string/title_use_custom_tabs"
android:summaryOn="@string/tip_use_custom_tab_on"
android:summaryOff="@string/tip_use_custom_tab"/>
</androidx.preference.PreferenceCategory>
</androidx.preference.PreferenceScreen>

View File

@ -50,7 +50,6 @@
</androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory android:title="@string/title_settings_read_habit">
<ListPreference
android:icon="@drawable/ic_round_photo_size_select_actual"
android:key="image_load_type"