V1.0.1(2)修改bug,添加进度条,优化界面

This commit is contained in:
lihongwei 2025-03-19 15:55:40 +08:00
parent f4b54c5e52
commit abd022ee8b
15 changed files with 254 additions and 81 deletions

View File

@ -13,8 +13,8 @@ android {
applicationId = "com.live.flowlivewallpaper"
minSdk = 23
targetSdk = 34
versionCode = 1
versionName = "1.0.0"
versionCode = 2
versionName = "1.0.1"
setProperty(
"archivesBaseName",
"Flow Live Wallpaper_V" + versionName + "(${versionCode})_$timestamp"

View File

@ -1,8 +1,13 @@
package com.live.flowlivewallpaper;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import androidx.annotation.NonNull;
import com.live.flowlivewallpaper.data.dao.FlowEntityDao;
import com.live.flowlivewallpaper.data.database.AppDatabase;
@ -26,6 +31,8 @@ public class MyApplication extends Application {
application = this;
lockScreenOrientation();
SharedPreferences sharedPreferences = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
boolean isDatabaseInitialized = sharedPreferences.getBoolean(KEY_INIT, false);
@ -35,6 +42,45 @@ public class MyApplication extends Application {
}
}
private void lockScreenOrientation(){
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
@Override
public void onActivityStarted(@NonNull Activity activity) {
}
@Override
public void onActivityResumed(@NonNull Activity activity) {
}
@Override
public void onActivityPaused(@NonNull Activity activity) {
}
@Override
public void onActivityStopped(@NonNull Activity activity) {
}
@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
}
@Override
public void onActivityDestroyed(@NonNull Activity activity) {
}
});
}
public static Context getContext() {
return application.getApplicationContext();
}

View File

@ -0,0 +1,9 @@
package com.live.flowlivewallpaper.callback;
import java.io.File;
public interface OnDownloadProgressListener {
void onSuccess(File file);
void onFailure(Exception e);
void onProgress(int progress);
}

View File

@ -31,7 +31,7 @@ public class LiveService extends WallpaperService {
private void initExoPlayer() {
exoPlayer = new ExoPlayer.Builder(LiveService.this).build();
exoPlayer.setRepeatMode(ExoPlayer.REPEAT_MODE_ALL);
exoPlayer.setRepeatMode(ExoPlayer.REPEAT_MODE_ONE);
update();
}

View File

@ -1,5 +1,6 @@
package com.live.flowlivewallpaper.ui.activity;
import android.animation.ObjectAnimator;
import android.app.WallpaperManager;
import android.content.ComponentName;
import android.content.Intent;
@ -7,6 +8,7 @@ import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
@ -16,6 +18,7 @@ import androidx.core.view.WindowInsetsCompat;
import androidx.lifecycle.ViewModelProvider;
import com.live.flowlivewallpaper.R;
import com.live.flowlivewallpaper.callback.OnDownloadProgressListener;
import com.live.flowlivewallpaper.data.entity.FlowEntity;
import com.live.flowlivewallpaper.databinding.ActivityLiveBinding;
import com.live.flowlivewallpaper.service.LiveService;
@ -29,8 +32,7 @@ public class LiveActivity extends AppCompatActivity {
private ActivityLiveBinding binding;
private FlowEntity flowEntity;
private FlowViewModel flowViewModel;
private int flowId;
private String image;
private WallpaperDownloader downloader;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -40,38 +42,38 @@ public class LiveActivity extends AppCompatActivity {
setContentView(binding.getRoot());
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
// v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
downloader = new WallpaperDownloader();
initData();
initEvent();
}
private void initData() {
flowEntity = (FlowEntity) getIntent().getSerializableExtra("flowEntity");
int flowId;
String image;
if (flowEntity != null) {
flowId = flowEntity.getFlowId();
image = flowEntity.getImage();
} else {
finish();
return;
}
showProgress();
flowViewModel = new ViewModelProvider(this).get(FlowViewModel.class);
String quality;
if (flowEntity.getWallpaperType() == 2) {
quality = "ViewShiftLive";
} else {
quality = "ViewLive";
}
String quality = flowEntity.getWallpaperType() == 2 ? "ViewShiftLive" : "ViewLive";
if (Objects.equals(flowEntity.getWallpaperPath(), "")) {
WallpaperDownloader.downloadMp4FileAsync(this, flowId, image, quality, new WallpaperDownloader.OnDownloadCompleteListener() {
downloader.downloadMp4FileAsync(this, flowId, image, quality, new OnDownloadProgressListener() {
@Override
public void onSuccess(File file) {
if (binding == null) return;
flowEntity.setWallpaperPath(file.getAbsolutePath());
flowViewModel.update(flowEntity);
loadVideoSuccess();
@ -80,18 +82,26 @@ public class LiveActivity extends AppCompatActivity {
@Override
public void onFailure(Exception e) {
Log.d("onFailure", e.getMessage());
Log.d("onFailure", flowId + " " + image);
if (binding == null) return;
hideProgress();
Toast.makeText(LiveActivity.this, "Download failed", Toast.LENGTH_SHORT).show();
Log.e("LiveActivity", "Download failed", e);
}
@Override
public void onProgress(int progress) {
if (!isFinishing() && !isDestroyed() && binding != null && progress >= 0 && progress <= 100) {
binding.downloadProgressBar.setProgress(progress);
binding.progressText.setText(progress + "%");
}
}
});
} else {
loadVideoSuccess();
hideProgress();
}
loadFavorite();
loadLike();
}
private void initEvent() {
@ -111,9 +121,10 @@ public class LiveActivity extends AppCompatActivity {
File videoFile = new File(flowEntity.getWallpaperPath());
if (videoFile.exists()) {
binding.videoView.setVideoPath(flowEntity.getWallpaperPath());
Log.d("VideoPath", flowEntity.getWallpaperPath());
binding.videoView.start();
binding.videoView.setOnPreparedListener(mp -> mp.setLooping(true));
} else {
Log.e("LiveActivity", "Video file missing: " + flowEntity.getWallpaperPath());
}
}
}
@ -122,6 +133,12 @@ public class LiveActivity extends AppCompatActivity {
SharedPreferences prefs = getSharedPreferences("WallpaperPrefs", MODE_PRIVATE);
prefs.edit().putString("video_path", flowEntity.getWallpaperPath()).apply();
WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
try {
wallpaperManager.clear();
} catch (Exception ignored) {
}
Intent intent = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
new ComponentName(this, LiveService.class));
@ -129,24 +146,34 @@ public class LiveActivity extends AppCompatActivity {
finish();
}
private void loadFavorite() {
private void loadLike() {
flowViewModel.getLike(flowEntity.getWallpaperType(), flowEntity.getFlowId()).observe(this, wallpaper -> setLike());
}
private void setLike() {
binding.like.setImageResource(
flowEntity.isFavorite() ? R.drawable.like : R.drawable.dislike
);
}
private void hideProgress() {
binding.progressBar.setVisibility(View.GONE);
binding.view.setVisibility(View.GONE);
if (binding != null) {
binding.like.setImageResource(flowEntity.isFavorite() ? R.drawable.like : R.drawable.dislike);
}
}
private void showProgress() {
binding.progressBar.setVisibility(View.VISIBLE);
binding.view.setVisibility(View.VISIBLE);
if (binding != null) {
binding.downloadProgressBar.setVisibility(View.VISIBLE);
binding.progressTip.setVisibility(View.VISIBLE);
binding.progressText.setVisibility(View.VISIBLE);
binding.loadingSpinner.setVisibility(View.VISIBLE);
binding.view.setVisibility(View.VISIBLE);
}
}
private void hideProgress() {
if (!isFinishing() && !isDestroyed() && binding != null) {
binding.downloadProgressBar.setVisibility(View.GONE);
binding.progressTip.setVisibility(View.GONE);
binding.progressText.setVisibility(View.GONE);
binding.loadingSpinner.setVisibility(View.GONE);
binding.view.setVisibility(View.GONE);
}
}
@Override
@ -160,6 +187,7 @@ public class LiveActivity extends AppCompatActivity {
@Override
protected void onDestroy() {
super.onDestroy();
downloader.cancelDownload();
binding = null;
}
}

View File

@ -14,6 +14,7 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.live.flowlivewallpaper.R;
import com.live.flowlivewallpaper.data.entity.FlowEntity;
@ -51,10 +52,6 @@ public class FlowAdapter extends RecyclerView.Adapter<FlowAdapter.ViewHolder> {
public void onBindViewHolder(ViewHolder holder, int position) {
FlowEntity flowEntity = flowEntities.get(position);
holder.bind(flowEntity);
int randomHeight = (position % 2 == 0) ? 800 : 1000;
ViewGroup.LayoutParams params = holder.itemView.getLayoutParams();
params.height = randomHeight;
holder.itemView.setLayoutParams(params);
}
@Override
@ -83,7 +80,7 @@ public class FlowAdapter extends RecyclerView.Adapter<FlowAdapter.ViewHolder> {
private void loadImage(String imagePath) {
Glide.with(context)
.load(imagePath)
.transform(new RoundedCorners(32))
.transform(new CenterCrop(),new RoundedCorners(32))
.error(R.mipmap.placeholder)
.placeholder(R.mipmap.placeholder)
.into(imageView);

View File

@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import android.view.LayoutInflater;
@ -38,7 +39,7 @@ public class ExploreFragment extends Fragment {
private void initData() {
flowViewModel = new ViewModelProvider(this).get(FlowViewModel.class);
binding.recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
binding.recyclerView.setLayoutManager(new GridLayoutManager(requireContext(),2));
adapter = new FlowAdapter(flowViewModel, requireContext(), new ArrayList<>(), requireActivity());
binding.recyclerView.setAdapter(adapter);

View File

@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import android.view.LayoutInflater;
@ -38,7 +39,7 @@ public class FavoriteFragment extends Fragment {
private void initData() {
flowViewModel = new ViewModelProvider(this).get(FlowViewModel.class);
binding.recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
binding.recyclerView.setLayoutManager(new GridLayoutManager(requireContext(),2));
adapter = new FlowAdapter(flowViewModel, requireContext(), new ArrayList<>(), requireActivity());
binding.recyclerView.setAdapter(adapter);

View File

@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import android.view.LayoutInflater;
@ -38,7 +39,7 @@ public class ShiftFragment extends Fragment {
private void initData() {
flowViewModel = new ViewModelProvider(this).get(FlowViewModel.class);
binding.recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
binding.recyclerView.setLayoutManager(new GridLayoutManager(requireContext(),2));
adapter = new FlowAdapter(flowViewModel, requireContext(), new ArrayList<>(), requireActivity());
binding.recyclerView.setAdapter(adapter);

View File

@ -6,6 +6,7 @@ import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import android.view.LayoutInflater;
@ -39,7 +40,7 @@ public class TrendingFragment extends Fragment {
private void initData() {
flowViewModel = new ViewModelProvider(this).get(FlowViewModel.class);
binding.recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
binding.recyclerView.setLayoutManager(new GridLayoutManager(requireContext(),2));
adapter = new FlowAdapter(flowViewModel, requireContext(), new ArrayList<>(), requireActivity());
binding.recyclerView.setAdapter(adapter);

View File

@ -1,36 +1,19 @@
package com.live.flowlivewallpaper.util;
import android.content.Context;
import android.os.Environment;
import androidx.annotation.NonNull;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;
import android.content.Context;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import androidx.annotation.NonNull;
import com.live.flowlivewallpaper.callback.OnDownloadProgressListener;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
@ -44,17 +27,23 @@ import okhttp3.Response;
public class WallpaperDownloader {
private static final String SERVER_URL = "https://neutrolabgames.com/LiveLoop/AppData/jmywall.php";
private static final OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.build();
private static final Handler mainHandler = new Handler(Looper.getMainLooper());
public static void downloadMp4FileAsync(Context context, int pi, String image,String quality, OnDownloadCompleteListener listener) {
private Call currentCall;
public WallpaperDownloader() {
this.currentCall = null;
}
public void downloadMp4FileAsync(Context context, int pi, String image, String quality, OnDownloadProgressListener listener) {
RequestBody requestBody = new FormBody.Builder()
.add("pi", String.valueOf(pi))
.add("medium", "5eV6snEwfY7Yv6Ub")
.add("alpha", image)
.add("alpha", image != null ? image : "")
.add("version", "DL8")
.add("quality", quality)
.build();
@ -64,27 +53,59 @@ public class WallpaperDownloader {
.post(requestBody)
.build();
client.newCall(request).enqueue(new Callback() {
WeakReference<Context> weakContext = new WeakReference<>(context);
currentCall = client.newCall(request);
currentCall.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
mainHandler.post(() -> listener.onFailure(e));
mainHandler.post(() -> {
if (listener != null) {
listener.onFailure(e);
}
});
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if (!response.isSuccessful()) {
mainHandler.post(() -> listener.onFailure(new IOException("Download failure: " + response.code())));
mainHandler.post(() -> {
if (listener != null) {
listener.onFailure(new IOException("Download failure: " + response.code()));
}
});
return;
}
if (response.body() == null) {
mainHandler.post(() -> listener.onFailure(new IOException("The response body is empty")));
mainHandler.post(() -> {
if (listener != null) {
listener.onFailure(new IOException("The response body is empty"));
}
});
return;
}
String fileName = "wallpaper_" + System.currentTimeMillis() + pi + image + ".mp4";
File dir = context.getExternalFilesDir(Environment.DIRECTORY_MOVIES);
String fileLengthStr = response.header("File-Length");
long totalBytes = -1;
if (fileLengthStr != null) {
try {
totalBytes = Long.parseLong(fileLengthStr);
} catch (NumberFormatException ignored) {
}
}
if (totalBytes <= 0) {
totalBytes = response.body().contentLength();
}
Context ctx = weakContext.get();
if (ctx == null) {
return;
}
String fileName = "wallpaper_" + System.currentTimeMillis() + pi + (image != null ? image : "") + ".mp4";
File dir = ctx.getExternalFilesDir(Environment.DIRECTORY_MOVIES);
File file = new File(dir, fileName);
long downloadedBytes = 0;
try (InputStream inputStream = response.body().byteStream();
FileOutputStream outputStream = new FileOutputStream(file)) {
@ -92,19 +113,43 @@ public class WallpaperDownloader {
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
if (call.isCanceled()) {
file.delete();
return;
}
outputStream.write(buffer, 0, bytesRead);
downloadedBytes += bytesRead;
if (totalBytes > 0) {
int progress = (int) (downloadedBytes * 100 / totalBytes);
mainHandler.post(() -> {
if (listener != null) {
listener.onProgress(progress);
}
});
}
}
mainHandler.post(() -> listener.onSuccess(file));
mainHandler.post(() -> {
if (listener != null) {
listener.onSuccess(file);
}
});
} catch (IOException e) {
mainHandler.post(() -> listener.onFailure(e));
mainHandler.post(() -> {
if (listener != null) {
listener.onFailure(e);
}
});
}
}
});
}
public interface OnDownloadCompleteListener {
void onSuccess(File file);
void onFailure(Exception e);
public void cancelDownload() {
if (currentCall != null && !currentCall.isCanceled()) {
currentCall.cancel();
currentCall = null;
}
mainHandler.removeCallbacksAndMessages(null);
}
}

View File

@ -3,7 +3,7 @@
<item android:id="@android:id/background">
<shape>
<corners android:radius="5dp" />
<solid android:color="#D3D3D3" /> <!-- 背景颜色 -->
<solid android:color="#D3D3D3" />
</shape>
</item>
@ -11,7 +11,7 @@
<clip>
<shape>
<corners android:radius="5dp" />
<solid android:color="#FFD700" /> <!-- 次级进度颜色 -->
<solid android:color="#FFD700" />
</shape>
</clip>
</item>

View File

@ -68,10 +68,55 @@
android:focusable="true"
android:visibility="gone" />
<ProgressBar
android:id="@+id/progress_bar"
<TextView
android:id="@+id/progress_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginBottom="32dp"
android:padding="4dp"
android:text="Please wait, downloading"
android:textColor="#FFFFFF"
android:textSize="16sp"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/downloadProgressBar"
app:layout_constraintStart_toStartOf="@id/downloadProgressBar" />
<TextView
android:id="@+id/progressText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:padding="4dp"
android:text="0%"
android:textColor="#FFFFFF"
android:textSize="16sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/progress_tip"
app:layout_constraintStart_toEndOf="@+id/progress_tip"
app:layout_constraintTop_toTopOf="@id/progress_tip" />
<ProgressBar
android:id="@+id/loadingSpinner"
style="?android:attr/progressBarStyle"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="16dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/progress_tip"
app:layout_constraintStart_toEndOf="@id/progressText"
app:layout_constraintTop_toTopOf="@id/progress_tip" />
<ProgressBar
android:id="@+id/downloadProgressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="12dp"
android:layout_margin="48dp"
android:elevation="4dp"
android:max="100"
android:progress="0"
android:progressDrawable="@drawable/progress_bar_color"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"

View File

@ -40,7 +40,7 @@
android:layout_marginBottom="80dp"
android:max="100"
android:progress="0"
android:progressDrawable="@drawable/seek_bar_color"
android:progressDrawable="@drawable/progress_bar_color"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

View File

@ -6,8 +6,7 @@
<ImageView
android:id="@+id/item_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
android:layout_height="match_parent" />
<ImageView
android:id="@+id/item_like"