1.按照UI图修改

2.完善其他功能
This commit is contained in:
fengshengxiong 2024-05-17 17:02:22 +08:00
parent 1a271ba9b0
commit 9caadfb09a
128 changed files with 1875 additions and 13213 deletions

View File

@ -27,7 +27,7 @@ def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
android { android {
namespace "com.lux.wallpaper" namespace "com.now.wallpaper"
compileSdk flutter.compileSdkVersion compileSdk flutter.compileSdkVersion
ndkVersion flutter.ndkVersion ndkVersion flutter.ndkVersion
@ -46,10 +46,11 @@ android {
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.lux.wallpaper" applicationId "com.now.wallpaper"
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion // minSdkVersion flutter.minSdkVersion
minSdkVersion 24
targetSdkVersion flutter.targetSdkVersion targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName

View File

@ -5,14 +5,18 @@
<uses-permission <uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" android:maxSdkVersion="32"
tools:ignore="ScopedStorage" /> tools:ignore="ScopedStorage"
/>
<uses-permission <uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE" android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" /> android:maxSdkVersion="32"
/>
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<application <application
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/launcher_icon"
android:label="@string/app_name" android:label="@string/app_name"
android:requestLegacyExternalStorage="true"> android:requestLegacyExternalStorage="true">
<activity <activity
@ -40,6 +44,18 @@
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />
<!-- Provider -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application> </application>
<!-- Required to query activities that can process text, see: <!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility?hl=en and https://developer.android.com/training/package-visibility?hl=en and

View File

@ -1,5 +0,0 @@
package com.lux.wallpaper
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity()

View File

@ -0,0 +1,20 @@
package com.now.wallpaper
import io.flutter.Log
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity : FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
try {
flutterEngine.plugins.add(SetWallpaperPlugin())
GeneratedPluginRegistrant.registerWith(flutterEngine)
} catch (e: Exception) {
Log.e(
"GeneratedPluginRegistrant",
"Error registering plugin set_wallpaper, com.now.wallpaper.SetWallpaperPlugin",
)
}
}
}

View File

@ -0,0 +1,59 @@
package com.now.wallpaper
import android.app.WallpaperManager
import android.content.Context
import android.graphics.BitmapFactory
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.Result
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class SetWallpaperPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
private lateinit var context: Context
private lateinit var channel: MethodChannel
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "set_wallpaper")
context = flutterPluginBinding.applicationContext
channel.setMethodCallHandler(this)
}
@OptIn(DelicateCoroutinesApi::class)
override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method == "setWallpaper") {
val path = call.argument<String>("path")
val wallpaperType = call.argument<Int>("wallpaperType") // 0 for home screen, 1 for lock screen, 2 for both
GlobalScope.launch(Dispatchers.IO) {
val bitmap = BitmapFactory.decodeFile(path)
withContext(Dispatchers.Main) {
try {
val wallpaperManager = WallpaperManager.getInstance(context)
when (wallpaperType) {
0 -> wallpaperManager.setBitmap(bitmap, null, true, WallpaperManager.FLAG_SYSTEM)
1 -> wallpaperManager.setBitmap(bitmap, null, true, WallpaperManager.FLAG_LOCK)
2 -> {
wallpaperManager.setBitmap(bitmap, null, true, WallpaperManager.FLAG_SYSTEM)
wallpaperManager.setBitmap(bitmap, null, true, WallpaperManager.FLAG_LOCK)
}
}
result.success("Wallpaper applied successfully")
} catch (e: Exception) {
result.error("ERROR", "Failed to set wallpaper: ${e.message}", null)
}
}
}
} else {
result.notImplemented()
}
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
}

View File

@ -1,12 +1,11 @@
<?xml version="1.0" encoding="utf-8"?><!-- Modify this file to customize your launch splash screen --> <?xml version="1.0" encoding="utf-8"?><!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!--<item android:drawable="?android:colorBackground" />--> <item android:drawable="?android:colorBackground" />
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here --> <!-- You can insert your own image assets here -->
<item> <item>
<bitmap <bitmap
android:gravity="center" android:gravity="center"
android:src="@mipmap/ic_launcher" /> android:src="@mipmap/launcher_icon" />
</item> </item>
</layer-list> </layer-list>

View File

@ -6,6 +6,6 @@
<item>¬ <item>¬
<bitmap <bitmap
android:gravity="center" android:gravity="center"
android:src="@mipmap/ic_launcher" /> android:src="@mipmap/launcher_icon" />
</item> </item>
</layer-list> </layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@ -5,6 +5,10 @@
<!-- Show a splash screen on the activity. Automatically removed when <!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame --> the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item> <item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
</style> </style>
<!-- Theme applied to the Android Window as soon as the process has started. <!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your This theme determines the color of the Android Window while your

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name">Wallpaper</string> <string name="app_name">Now wallpaper</string>
</resources> </resources>

View File

@ -5,6 +5,10 @@
<!-- Show a splash screen on the activity. Automatically removed when <!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame --> the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item> <item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
</style> </style>
<!-- Theme applied to the Android Window as soon as the process has started. <!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your This theme determines the color of the Android Window while your

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path name="files" path="." />
<cache-path name="cache" path="." />
<external-files-path name="external-files" path="." />
<external-cache-path name="external-cache" path="." />
<external-media-path name="external-media" path="." />
</paths>

View File

@ -20,7 +20,7 @@ pluginManagement {
plugins { plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.3.0" apply false id "com.android.application" version "7.3.0" apply false
id "org.jetbrains.kotlin.android" version "1.7.10" apply false id "org.jetbrains.kotlin.android" version "1.8.22" apply false
} }
include ":app" include ":app"

BIN
assets/icon/icon_app.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 913 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

BIN
assets/images/ic_back.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 B

BIN
assets/images/ic_download.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 B

BIN
assets/images/ic_favorite.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 B

BIN
assets/images/ic_filtered.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 663 B

BIN
assets/images/ic_preview.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

BIN
assets/images/ic_settings.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 654 B

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

File diff suppressed because one or more lines are too long

View File

@ -496,7 +496,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.lux.wallpaper; PRODUCT_BUNDLE_IDENTIFIER = com.now.wallpaper;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
@ -558,7 +558,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
@ -616,7 +616,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
@ -681,7 +681,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.lux.wallpaper; PRODUCT_BUNDLE_IDENTIFIER = com.now.wallpaper;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@ -704,7 +704,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.lux.wallpaper; PRODUCT_BUNDLE_IDENTIFIER = com.now.wallpaper;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

@ -2,10 +2,12 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
<string>Wallpaper</string> <string>Now wallpaper</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
@ -24,6 +26,12 @@
<string>$(FLUTTER_BUILD_NUMBER)</string> <string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>To save wallpapers to gallery, we need this permission</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>To save wallpapers to gallery, we need this permission</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>LaunchScreen</string> <string>LaunchScreen</string>
<key>UIMainStoryboardFile</key> <key>UIMainStoryboardFile</key>
@ -41,11 +49,5 @@
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Please allow the APP to save photos to the album</string>
</dict> </dict>
</plist> </plist>

View File

@ -1,70 +0,0 @@
// Author: fengshengxiong
// Date: 2024/5/7
// Description: BaseAppBar
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
class BaseAppBar extends StatelessWidget implements PreferredSizeWidget {
const BaseAppBar(
this.titleStr, {
super.key,
this.height,
this.backgroundColor,
this.titleStyle,
this.title,
this.iconColor,
this.showLeading = true,
this.leading,
this.leadingOnPressed,
this.actions,
this.systemOverlayStyle,
this.bottom,
});
final double? height;
final Color? backgroundColor;
final String titleStr;
final TextStyle? titleStyle;
final Widget? title;
final Color? iconColor;
final bool showLeading;
final Widget? leading;
final Function()? leadingOnPressed;
final List<Widget>? actions;
final SystemUiOverlayStyle? systemOverlayStyle;
final PreferredSizeWidget? bottom;
@override
Widget build(BuildContext context) {
Widget titleWidget = title ??
Text(
titleStr,
style: titleStyle,
maxLines: 1,
overflow: TextOverflow.ellipsis,
);
Widget? leadingWidget = showLeading
? (leading ??
IconButton(
icon: Icon(
Icons.arrow_back_ios_rounded,
color: iconColor,
),
onPressed: leadingOnPressed ?? Get.back,
))
: null;
return AppBar(
title: titleWidget,
backgroundColor: backgroundColor,
systemOverlayStyle: systemOverlayStyle,
leading: leadingWidget,
actions: actions,
bottom: bottom,
);
}
@override
Size get preferredSize => Size.fromHeight(height ?? kToolbarHeight);
}

View File

@ -1,56 +0,0 @@
// Author: fengshengxiong
// Date: 2024/5/11
// Description:
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:wallpaper/common/components/image_widget.dart';
import 'package:wallpaper/common/components/view_state_widget.dart';
import 'package:wallpaper/common/models/wallpaper_model.dart';
class BaseMasonryGridView extends StatelessWidget {
const BaseMasonryGridView({
super.key,
this.viewState = ViewState.normal,
required this.wallpaperList,
required this.itemOnTap,
this.onLongPress,
});
final List<WallpaperData> wallpaperList;
final Function(int index) itemOnTap;
final Function(int index)? onLongPress;
final ViewState? viewState;
@override
Widget build(BuildContext context) {
return ViewStateWidget(
state: viewState!,
child: MasonryGridView.count(
itemCount: wallpaperList.length,
crossAxisCount: 2,
mainAxisSpacing: 8.w,
crossAxisSpacing: 8.w,
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.symmetric(horizontal: 8).w,
itemBuilder: (context, index) {
return _wallpaperItem(wallpaperList[index], index);
},
),
);
}
Widget _wallpaperItem(WallpaperData item, index) {
return InkWell(
onTap: () => itemOnTap(index),
borderRadius: BorderRadius.circular(8).r,
onLongPress: onLongPress != null ? () => onLongPress!(index) : null,
child: ImageWidget(
url: item.previewThumb,
fit: BoxFit.contain,
radius: 8.r,
),
);
}
}

View File

@ -0,0 +1,60 @@
// Author: fengshengxiong
// Date: 2024/5/7
// Description: BaseTextButton
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:now_wallpaper/res/themes/app_styles.dart';
class BaseTextButton extends StatelessWidget {
final double? width;
final double? height;
final ButtonStyle? buttonStyle;
final Color? bgColor;
final double? radius;
final String? label;
final TextStyle? textStyle;
final Widget? child;
final Function()? onTap;
const BaseTextButton({
super.key,
this.label,
this.width,
this.height,
this.buttonStyle,
this.bgColor,
this.radius,
this.textStyle,
this.child,
this.onTap,
});
@override
Widget build(BuildContext context) {
return SizedBox(
width: width,
height: height,
child: TextButton(
onPressed: onTap,
style: buttonStyle ??
baseTextButtonStyle(
bgColor: bgColor,
radius: radius,
),
child: child ??
Text(
label ?? '',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: textStyle ??
TextStyle(
color: const Color(0xFF333333),
fontSize: 16.sp,
fontWeight: FontWeight.w600,
),
),
),
);
}
}

View File

@ -0,0 +1,53 @@
// Author: fengshengxiong
// Date: 2024/5/16
// Description: BottomSheetDialog
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:now_wallpaper/common/components/button/base_textbutton.dart';
import 'package:now_wallpaper/common/components/divider_widget.dart';
class BottomSheetDialog {
static void show(void Function(int location) function) {
Get.bottomSheet(
Container(
color: Colors.white,
height: 150.h,
child: Column(
children: [
Expanded(
child: BaseTextButton(
label: 'Home Screen',
onTap: () {
Get.back();
function(0);
},
),
),
const DividerWidget(),
Expanded(
child: BaseTextButton(
label: 'Lock Screen',
onTap: () {
Get.back();
function(1);
},
),
),
const DividerWidget(),
Expanded(
child: BaseTextButton(
label: 'Both Screen',
onTap: () {
Get.back();
function(2);
},
),
),
],
),
),
);
}
}

View File

@ -4,8 +4,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:wallpaper/common/components/view_state_widget.dart'; import 'package:now_wallpaper/common/components/view_state_widget.dart';
import 'package:wallpaper/common/utils/obj_util.dart'; import 'package:now_wallpaper/common/utils/obj_util.dart';
class ProcessDialog extends StatelessWidget { class ProcessDialog extends StatelessWidget {
final double process; final double process;

View File

@ -5,10 +5,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:wallpaper/common/components/divider_widget.dart'; import 'package:now_wallpaper/common/components/divider_widget.dart';
class HintDialog extends StatelessWidget { class RemindDialog extends StatelessWidget {
const HintDialog({ const RemindDialog({
super.key, super.key,
this.title, this.title,
this.content, this.content,
@ -55,7 +55,7 @@ class HintDialog extends StatelessWidget {
content ?? '', content ?? '',
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
color: Colors.black54, color: const Color(0xFF333333),
fontSize: 15.sp, fontSize: 15.sp,
), ),
), ),
@ -103,7 +103,7 @@ class HintDialog extends StatelessWidget {
label, label,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
color: isConfirm ? Colors.black : Colors.black45, color: isConfirm ? Colors.black : const Color(0xFF666666),
fontSize: 16.sp, fontSize: 16.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),

View File

@ -4,7 +4,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:wallpaper/common/utils/obj_util.dart';
/// EasyLoading配置 /// EasyLoading配置
void configLoading() { void configLoading() {
@ -34,7 +33,7 @@ void configLoading() {
// , 4.0, [EasyLoadingIndicatorType.ring, EasyLoadingIndicatorType.dualRing]. // , 4.0, [EasyLoadingIndicatorType.ring, EasyLoadingIndicatorType.dualRing].
..lineWidth = 2.0 ..lineWidth = 2.0
// [showSuccess] [showError] [showInfo], 2000ms. // [showSuccess] [showError] [showInfo], 2000ms.
..displayDuration = const Duration(milliseconds: 2000) ..displayDuration = const Duration(milliseconds: 1000)
// , 200ms. // , 200ms.
..animationDuration = const Duration(milliseconds: 200) ..animationDuration = const Duration(milliseconds: 200)
// , [EasyLoadingStyle.custom]. // , [EasyLoadingStyle.custom].
@ -54,8 +53,8 @@ void configLoading() {
} }
void toast(String? value, {bool show = true}) { void toast(String? value, {bool show = true}) {
if (show && ObjUtil.isNotEmptyStr(value)) { if (show && value != null) {
EasyLoading.showToast('$value'); EasyLoading.showToast(value);
} }
} }

View File

@ -0,0 +1,57 @@
// Author: fengshengxiong
// Date: 2024/5/9
// Description:
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:now_wallpaper/generated/assets.dart';
class ImageNetworkWidget extends StatelessWidget {
const ImageNetworkWidget({
super.key,
this.width,
this.height,
this.radius = 0.0,
required this.url,
this.fit = BoxFit.cover,
this.placeholder,
this.errorWidget,
});
final double? width;
final double? height;
final double radius;
final String? url;
final BoxFit fit;
final Widget? placeholder;
final Widget? errorWidget;
@override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(radius),
child: CachedNetworkImage(
width: width,
height: height,
imageUrl: '$url',
fit: fit,
placeholder: (context, url) {
return placeholder ?? _placeholderWidget(Assets.imagesImgPlaceholder);
},
errorWidget: (context, url, error) {
return errorWidget ?? _placeholderWidget(Assets.imagesImgError);
},
),
);
}
Widget _placeholderWidget(String imgName) {
return Container(
color: Colors.white10,
child: Image.asset(
imgName,
color: Colors.white12,
),
);
}
}

View File

@ -1,71 +0,0 @@
// Author: fengshengxiong
// Date: 2024/5/9
// Description:
import 'dart:io';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:wallpaper/generated/assets.dart';
class ImageWidget extends StatelessWidget {
const ImageWidget({
super.key,
this.width,
this.height,
this.radius = 0.0,
this.url,
this.filePath,
this.isLocal = false,
this.fit = BoxFit.cover,
this.placeholder,
this.errorWidget,
});
final double? width, height;
final double radius;
final String? url;
final String? filePath;
final bool isLocal;
final BoxFit fit;
final Widget? placeholder;
final Widget? errorWidget;
@override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(radius),
child: Visibility(
visible: !isLocal,
replacement: Image.file(
File('$filePath'),
fit: fit,
width: width,
height: height,
),
child: CachedNetworkImage(
width: width,
height: height,
imageUrl: '$url',
fit: fit,
placeholder: (context, url) {
return placeholder ?? _placeErrWidget(Assets.imagesPlaceholder);
},
errorWidget: (context, url, error) {
return errorWidget ?? _placeErrWidget(Assets.imagesError);
},
),
),
);
}
Widget _placeErrWidget(String imgName) {
return Container(
color: Colors.white10,
child: Image.asset(
imgName,
color: Colors.white10,
),
);
}
}

View File

@ -0,0 +1,70 @@
// Author: fengshengxiong
// Date: 2024/5/7
// Description: BaseAppBar
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:now_wallpaper/generated/assets.dart';
import 'package:now_wallpaper/res/themes/app_colors.dart';
class BaseAppBar extends StatelessWidget implements PreferredSizeWidget {
const BaseAppBar(
this.title, {
super.key,
this.backgroundColor,
this.backWidget,
this.titleStyle,
});
final Color? backgroundColor;
final Widget? backWidget;
final String title;
final TextStyle? titleStyle;
@override
Widget build(BuildContext context) {
return Container(
height: preferredSize.height,
padding: EdgeInsets.fromLTRB(10, ScreenUtil().statusBarHeight, 20, 0).w,
color: backgroundColor ?? seedColor,
child: Row(
children: [
backWidget ??
ClipOval(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: Get.back,
child: Padding(
padding: const EdgeInsets.all(10).w,
child: Image.asset(
Assets.imagesIcBack,
width: 13.w,
height: 13.w,
),
),
),
),
),
Flexible(
child: Text(
title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: titleStyle ??
TextStyle(
color: Colors.white,
fontSize: 20.sp,
fontWeight: FontWeight.w500,
),
),
),
],
),
);
}
@override
Size get preferredSize => Size.fromHeight(ScreenUtil().statusBarHeight + kToolbarHeight);
}

View File

@ -0,0 +1,62 @@
// Author: fengshengxiong
// Date: 2024/5/11
// Description:
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:now_wallpaper/generated/assets.dart';
import 'package:now_wallpaper/res/themes/app_sizes.dart';
class TitleBarWidget extends StatelessWidget {
const TitleBarWidget(
this.title, {
super.key,
this.showSettingsBtn = true,
this.settingsOnTap,
});
final String title;
final bool? showSettingsBtn;
final Function()? settingsOnTap;
@override
Widget build(BuildContext context) {
return SizedBox(
height: titleBarHeight,
child: Row(
children: [
SizedBox(width: 20.w),
Expanded(
child: Text(
title,
style: TextStyle(
color: Colors.white,
fontSize: 32.sp,
fontWeight: FontWeight.w600,
),
),
),
if (showSettingsBtn!) ...[
ClipOval(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: settingsOnTap,
child: Padding(
padding: const EdgeInsets.all(10).w,
child: Image.asset(
Assets.imagesIcSettings,
width: 20.w,
height: 20.w,
),
),
),
),
),
SizedBox(width: 10.w),
],
],
),
);
}
}

View File

@ -0,0 +1,58 @@
// Author: fengshengxiong
// Date: 2024/5/7
// Description:
import 'dart:async';
import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:now_wallpaper/common/components/view_state_widget.dart';
class BaseEasyRefresh extends StatelessWidget {
const BaseEasyRefresh({
super.key,
required this.controller,
this.header,
this.footer,
this.onRefresh,
this.onLoad,
this.refreshOnStart = false,
required this.viewState,
required this.child,
this.width,
this.height,
});
final EasyRefreshController controller;
final Header? header;
final Footer? footer;
final FutureOr Function()? onRefresh;
final FutureOr Function()? onLoad;
final bool refreshOnStart;
final ViewState viewState;
final Widget child;
final double? width;
final double? height;
@override
Widget build(BuildContext context) {
return EasyRefresh(
controller: controller,
header: header ?? const ClassicHeader(),
footer: footer ?? const ClassicFooter(),
onRefresh: onRefresh,
onLoad: onLoad,
refreshOnStart: refreshOnStart,
child: viewState == ViewState.normal ? child : SingleChildScrollView(
child: SizedBox(
width: width ?? 1.sw,
height: height ?? 300.h,
child: ViewStateWidget(
viewState: viewState,
child: child,
),
),
),
);
}
}

View File

@ -1,69 +0,0 @@
// Author: fengshengxiong
// Date: 2024/5/11
// Description:
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:wallpaper/res/themes/app_sizes.dart';
class TitleBarWidget extends StatelessWidget {
const TitleBarWidget({
super.key,
required this.title,
this.showMenuBtn = false,
this.deleteOnTap,
});
final String title;
final bool? showMenuBtn;
final Function()? deleteOnTap;
@override
Widget build(BuildContext context) {
return Container(
height: kTextTabBarHeight,
alignment: Alignment.centerLeft,
child: Row(
children: [
SizedBox(width: 16.w),
Expanded(
child: Text(
title,
style: TextStyle(
color: Colors.white,
fontSize: 22.sp,
fontWeight: FontWeight.bold,
),
),
),
if (showMenuBtn!) ...[
IconButton(
onPressed: () {
_showPopMenu(context);
},
icon: const Icon(Icons.menu, color: Colors.white),
),
],
],
),
);
}
void _showPopMenu(context) {
showMenu(
context: context,
surfaceTintColor: Colors.white,
position: RelativeRect.fromLTRB(double.infinity, statusToolBarHeight, 0.0, 0.0),
items: [
PopupMenuItem<String>(
value: 'delete',
onTap: deleteOnTap,
child: const ListTile(
leading: Icon(Icons.delete),
title: Text('Delete All'),
),
),
],
);
}
}

View File

@ -9,22 +9,26 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
enum ViewState { normal, error, loading, empty } enum ViewState { normal, error, loading, empty }
class ViewStateWidget extends StatelessWidget { class ViewStateWidget extends StatelessWidget {
const ViewStateWidget({super.key, required this.state, required this.child}); const ViewStateWidget({
super.key,
required this.viewState,
required this.child,
});
final ViewState state; final ViewState viewState;
final Widget child; final Widget child;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
switch (state) { switch (viewState) {
case ViewState.normal: case ViewState.normal:
return child; return child;
case ViewState.loading: case ViewState.loading:
return loadingView(); return loadingView();
case ViewState.error:
return errorView;
case ViewState.empty: case ViewState.empty:
return emptyView; return emptyView;
case ViewState.error:
return errorView;
} }
} }
} }
@ -53,7 +57,7 @@ Widget get emptyView {
'No data available', 'No data available',
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
color: Colors.white, color: const Color(0xFF666666),
fontSize: 14.sp, fontSize: 14.sp,
), ),
), ),
@ -67,7 +71,7 @@ Widget get errorView {
'An error occurred, please try again later', 'An error occurred, please try again later',
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
color: Colors.white, color: const Color(0xFF666666),
fontSize: 14.sp, fontSize: 14.sp,
), ),
), ),

View File

@ -1,80 +0,0 @@
// Author: fengshengxiong
// Date: 2024/5/11
// Description: /
import 'package:async_wallpaper/async_wallpaper.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:wallpaper/common/components/divider_widget.dart';
import 'package:wallpaper/common/components/easy_loading.dart';
import 'package:wallpaper/res/themes/app_colors.dart';
class WallpaperPicker {
static void picker(String imgPath) {
Get.bottomSheet(
Container(
color: Colors.white,
child: IntrinsicHeight(
child: Column(
children: [
_bottomSheetItem('Lock Screen', () {
Get.back();
setWallpaper(imgPath, AsyncWallpaper.LOCK_SCREEN);
}),
const DividerWidget(),
_bottomSheetItem('Home Screen', () {
Get.back();
setWallpaper(imgPath, AsyncWallpaper.HOME_SCREEN);
}),
const DividerWidget(),
_bottomSheetItem('Both Screen', () {
Get.back();
setWallpaper(imgPath, AsyncWallpaper.BOTH_SCREENS);
}),
const DividerWidget(),
_bottomSheetItem('Cancel', Get.back),
],
),
),
),
);
}
static Widget _bottomSheetItem(String label, Function() onTap) {
return SizedBox(
width: 1.sw,
child: TextButton(
onPressed: onTap,
child: Text(
label,
style: TextStyle(
color: seedColor,
fontSize: 18.sp,
fontWeight: FontWeight.w500,
),
),
),
);
}
static Future setWallpaper(String imgPath, int wallpaperLocation) async {
loading();
String result;
try {
result = await AsyncWallpaper.setWallpaperFromFile(
filePath: imgPath,
wallpaperLocation: AsyncWallpaper.LOCK_SCREEN,
// toastDetails: ToastDetails.success(),
// errorToastDetails: ToastDetails.error(),
)
? 'Wallpaper applied successfully'
: 'Failed to get wallpaper';
} on PlatformException {
result = 'Failed to get wallpaper';
}
dismiss();
toast(result);
}
}

View File

@ -4,12 +4,12 @@
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart'; import 'package:pretty_dio_logger/pretty_dio_logger.dart';
import 'package:wallpaper/common/components/easy_loading.dart'; import 'package:now_wallpaper/common/components/easy_loading.dart';
import 'package:wallpaper/common/models/base_resp_model.dart'; import 'package:now_wallpaper/common/network/base_error.dart';
import 'package:wallpaper/common/network/base_error.dart'; import 'package:now_wallpaper/common/network/dio_interceptor.dart';
import 'package:wallpaper/common/network/dio_interceptor.dart'; import 'package:now_wallpaper/common/utils/log_print.dart';
import 'package:wallpaper/common/utils/log_print.dart'; import 'package:now_wallpaper/generated/json/base/json_convert_content.dart';
import 'package:wallpaper/generated/json/base/json_convert_content.dart'; import 'package:now_wallpaper/models/base_resp_model.dart';
class DioClient { class DioClient {
static final DioClient _instance = DioClient._internal(); static final DioClient _instance = DioClient._internal();
@ -71,10 +71,11 @@ class DioClient {
} }
} on DioException catch (e) { } on DioException catch (e) {
BaseError error = getError(e); BaseError error = getError(e);
toast(error.message, show: showToast);
if (fail != null) fail(error); if (fail != null) fail(error);
toast(error.message, show: showToast);
} catch (e) { } catch (e) {
LogPrint.e(e.toString()); LogPrint.e(e.toString());
toast(e.toString(), show: showToast);
} }
} }

View File

@ -5,7 +5,7 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:wallpaper/common/models/base_resp_model.dart'; import 'package:now_wallpaper/models/base_resp_model.dart';
class DioInterceptor extends Interceptor { class DioInterceptor extends Interceptor {
@override @override

View File

@ -0,0 +1,23 @@
// Author: fengshengxiong
// Date: 2024/5/17
// Description:
import 'package:flutter/services.dart';
class SetWallpaper {
static const MethodChannel _channel = MethodChannel('set_wallpaper');
static Future<String> setWallpaper(String path, int wallpaperType) async {
try {
final String result = await _channel.invokeMethod('setWallpaper', {
"path": path,
"wallpaperType": wallpaperType // 0 for home screen, 1 for lock screen, 2 for both
});
print(result);
return result;
} on PlatformException catch (e) {
print('Failed to set wallpaper: ${e.message}.');
return 'Failed to set wallpaper: ${e.message}.';
}
}
}

View File

@ -2,9 +2,8 @@
// Date: 2024/5/8 // Date: 2024/5/8
// Description: // Description:
import 'package:wallpaper/common/models/wallpaper_model.dart'; import 'package:now_wallpaper/common/storage/hive_storage.dart';
import 'package:now_wallpaper/models/wallpaper_model.dart';
import 'hive_storage.dart';
class FavoriteData { class FavoriteData {
/// ///
@ -28,17 +27,19 @@ class FavoriteData {
} }
/// ///
void setWallpaperData(WallpaperData wallpaperData) { Future<int> setWallpaperData(WallpaperData wallpaperData) async {
_box.add(wallpaperData); return await _box.add(wallpaperData);
} }
/// ///
void delete(index) { Future<void> delete(index) async {
_box.deleteAt(index); await _box.deleteAt(index);
await _box.flush();
} }
/// ///
void clear() { Future<void> clear() async {
_box.clear(); await _box.clear();
await _box.flush();
} }
} }

View File

@ -3,7 +3,7 @@
// Description: // Description:
import 'package:hive_flutter/hive_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart';
import 'package:wallpaper/common/models/wallpaper_model.dart'; import 'package:now_wallpaper/models/wallpaper_model.dart';
const favoriteBox = 'favoriteBox'; const favoriteBox = 'favoriteBox';

View File

@ -5,11 +5,17 @@
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
class DeviceInfoUtil { class DeviceInfoUtil {
/// sdk版本 /// Android设备的系统版本
static Future<int> getSDKVersion() async { static Future<int> getAndroidSystemVersion() async {
DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin(); DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
AndroidDeviceInfo androidInfo = await deviceInfoPlugin.androidInfo; AndroidDeviceInfo androidDeviceInfo = await deviceInfoPlugin.androidInfo;
int sdkVersion = androidInfo.version.sdkInt; return androidDeviceInfo.version.sdkInt;
return sdkVersion;
} }
}
/// iOS设备的系统版本
static Future<String> getIOSSystemVersion() async {
DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
IosDeviceInfo iosDeviceInfo = await deviceInfoPlugin.iosInfo;
return iosDeviceInfo.systemVersion;
}
}

View File

@ -3,31 +3,30 @@
// Description: // Description:
import 'dart:io'; import 'dart:io';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:wallpaper/common/components/view_state_widget.dart'; import 'package:now_wallpaper/common/components/view_state_widget.dart';
import 'package:wallpaper/common/network/dio_client.dart'; import 'package:now_wallpaper/common/network/dio_client.dart';
import 'package:wallpaper/common/utils/filesize_util.dart'; import 'package:now_wallpaper/common/utils/filesize_util.dart';
import 'package:wallpaper/common/utils/local_path_util.dart'; import 'package:now_wallpaper/common/utils/local_path_util.dart';
import 'package:wallpaper/common/utils/log_print.dart'; import 'package:now_wallpaper/common/utils/log_print.dart';
import 'package:wallpaper/common/utils/num_util.dart'; import 'package:now_wallpaper/common/utils/num_util.dart';
class DownloadUtil { class DownloadUtil {
/// ///
static Future downloadWallpaper(String imageUrl, Function(String savePath) callBack) async { static Future downloadFile(String imageUrl, Function(String savePath) callBack) async {
var process = 0.0.obs; var process = 0.0.obs;
var processStr = ''.obs; var processStr = ''.obs;
var cancelToken = CancelToken(); var cancelToken = CancelToken();
Get.showSnackbar(GetSnackBar( Get.showSnackbar(GetSnackBar(
borderRadius: 8.r, borderRadius: 8.r,
margin: const EdgeInsets.symmetric(horizontal: 16).w, margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 16).w,
snackPosition: SnackPosition.TOP, snackPosition: SnackPosition.TOP,
backgroundColor: Colors.white, backgroundColor: Colors.white,
titleText: const Text( titleText: const Text(
'Loading...', 'downloading...',
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500), style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
), ),
messageText: Obx(() { messageText: Obx(() {
@ -53,15 +52,13 @@ class DownloadUtil {
); );
}), }),
)); ));
Directory dir = Directory(await LocalPathUtil.getTemporaryPath()); Directory dir = await LocalPathUtil.getTemporaryPath();
bool exist = await dir.exists(); bool exist = await dir.exists();
if (!exist) { if (!exist) {
// //
await dir.create(); await dir.create();
} }
// 使uri来解析url String savePath = '${dir.path}/${DateTime.now().millisecondsSinceEpoch}.jpg';
Uri uri = Uri.parse(imageUrl);
String savePath = '${dir.path}/${uri.pathSegments.last}';
LogPrint.d('壁纸保存位置:$savePath'); LogPrint.d('壁纸保存位置:$savePath');
await DioClient().download(imageUrl, savePath, cancelToken: cancelToken, onReceiveProgress: (int count, int total) { await DioClient().download(imageUrl, savePath, cancelToken: cancelToken, onReceiveProgress: (int count, int total) {
if (total != -1) { if (total != -1) {

View File

@ -2,27 +2,28 @@
// Date: 2024/5/10 // Date: 2024/5/10
// Description: // Description:
import 'dart:io';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
class LocalPathUtil { class LocalPathUtil {
/// (IOS和Android通用) ///
/// Android: /data/user/0//cache /// `NSCachesDirectory` on iOS and macOS
static Future<String> getTemporaryPath() async { /// `Context.getCacheDir` on Android.
final dir = await getTemporaryDirectory(); static Future<Directory> getTemporaryPath() async {
return dir.path; return await getTemporaryDirectory();
} }
/// (IOS和Android通用) ///
/// Android: /data/user/0//files /// `NSApplicationSupportDirectory` on iOS and macOS.
static Future<String> getSupportPath() async { /// The Flutter engine's `PathUtils.getFilesDir` API on Android.
final dir = await getApplicationSupportDirectory(); static Future<Directory> getSupportPath() async {
return dir.path; return await getApplicationSupportDirectory();
} }
/// (IOS和Android通用) ///
/// Android: /data/user/0//app_flutter /// `NSDocumentDirectory` on iOS and macOS.
static Future<String> getDocumentsPath() async { /// The Flutter engine's `PathUtils.getDataDirectory` API on Android.
final dir = await getApplicationDocumentsDirectory(); static Future<Directory> getDocumentsPath() async {
return dir.path; return await getApplicationDocumentsDirectory();
} }
} }

View File

@ -3,7 +3,6 @@
// Description: // Description:
import 'package:logger/logger.dart'; import 'package:logger/logger.dart';
import 'package:wallpaper/res/values/strings.dart';
final _logger = Logger( final _logger = Logger(
printer: PrettyPrinter( printer: PrettyPrinter(
@ -23,7 +22,7 @@ final _logger = Logger(
); );
class LogPrint { class LogPrint {
static const String _tag = '$appName Log'; static const String _tag = 'LogPrint';
LogPrint.t(dynamic msg, {String tag = _tag}) { LogPrint.t(dynamic msg, {String tag = _tag}) {
_logger.t('[$tag]: $msg'); _logger.t('[$tag]: $msg');

View File

@ -4,15 +4,19 @@
class ObjUtil { class ObjUtil {
static bool isNotEmptyStr(String? str) { static bool isNotEmptyStr(String? str) {
return str == null || str.trim().isNotEmpty; return str != null && str.trim().isNotEmpty;
}
static String getStr(String? str) {
return isNotEmptyStr(str) ? str! : '';
} }
static bool isNotEmptyList(Iterable? list) { static bool isNotEmptyList(Iterable? list) {
return list == null || list.isNotEmpty; return list != null && list.isNotEmpty;
} }
static bool isNotEmptyMap(Map? map) { static bool isNotEmptyMap(Map? map) {
return map == null || map.isNotEmpty; return map != null && map.isNotEmpty;
} }
static bool isEmpty(Object? object) { static bool isEmpty(Object? object) {
@ -44,18 +48,4 @@ class ObjUtil {
} }
return true; return true;
} }
/// get length.
static int getLength(Object? value) {
if (value == null) return 0;
if (value is String) {
return value.length;
} else if (value is Iterable) {
return value.length;
} else if (value is Map) {
return value.length;
} else {
return 0;
}
}
} }

View File

@ -4,7 +4,7 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:wallpaper/common/components/dialog/hint_dialog.dart'; import 'package:now_wallpaper/common/components/dialog/remind_dialog.dart';
class PermissionUtil { class PermissionUtil {
/// ///
@ -108,7 +108,7 @@ class PermissionUtil {
static _showFailedDialog(List<Permission> permissionList, {bool isPermanentlyDenied = false}) async { static _showFailedDialog(List<Permission> permissionList, {bool isPermanentlyDenied = false}) async {
Get.dialog( Get.dialog(
barrierDismissible: false, barrierDismissible: false,
HintDialog( RemindDialog(
content: await _getInstructions(permissionList), content: await _getInstructions(permissionList),
confirmText: isPermanentlyDenied ? 'Go Settings' : 'Confirm', confirmText: isPermanentlyDenied ? 'Go Settings' : 'Confirm',
confirmOnTap: () { confirmOnTap: () {
@ -138,7 +138,7 @@ class PermissionUtil {
} }
String explain = ''; String explain = '';
if (failedPermission == Permission.storage) { if (failedPermission == Permission.storage) {
explain = 'Please allow the APP to save photos to the album'; explain = 'To save wallpapers to gallery, we need this permission';
} }
return explain; return explain;
} }

View File

@ -0,0 +1,15 @@
// Author: fengshengxiong
// Date: 2024/5/11
// Description: /
import 'package:now_wallpaper/common/components/easy_loading.dart';
import 'package:now_wallpaper/common/plugin/set_wallpaper.dart';
class WallpaperManage {
static Future setWallpaper(String imgPath, int location) async {
loading();
String result = await SetWallpaper.setWallpaper(imgPath, location);
dismiss();
toast(result);
}
}

View File

@ -2,8 +2,22 @@
class Assets { class Assets {
Assets._(); Assets._();
static const String imagesError = 'assets/images/error.png'; static const String iconIconApp = 'assets/icon/icon_app.jpeg';
static const String imagesPlaceholder = 'assets/images/placeholder.png'; static const String imagesCatalogSelected = 'assets/images/catalog_selected.png';
static const String imagesCatalogUnchecked = 'assets/images/catalog_unchecked.png';
static const String imagesDiscoverSelected = 'assets/images/discover_selected.png';
static const String imagesDiscoverUnchecked = 'assets/images/discover_unchecked.png';
static const String imagesFavoriteSelected = 'assets/images/favorite_selected.png';
static const String imagesFavoriteUnchecked = 'assets/images/favorite_unchecked.png';
static const String imagesIcBack = 'assets/images/ic_back.png';
static const String imagesIcDownload = 'assets/images/ic_download.png';
static const String imagesIcFavorite = 'assets/images/ic_favorite.png';
static const String imagesIcFiltered = 'assets/images/ic_filtered.png';
static const String imagesIcPreview = 'assets/images/ic_preview.png';
static const String imagesIcSettingArrow = 'assets/images/ic_setting_arrow.png';
static const String imagesIcSettings = 'assets/images/ic_settings.png';
static const String imagesImgError = 'assets/images/img_error.png';
static const String imagesImgPlaceholder = 'assets/images/img_placeholder.png';
static const String jsonWallpaper = 'assets/json/wallpaper.json'; static const String jsonWallpaper = 'assets/json/wallpaper.json';
} }

View File

@ -4,8 +4,8 @@
// This file is automatically generated. DO NOT EDIT, all your changes would be lost. // This file is automatically generated. DO NOT EDIT, all your changes would be lost.
import 'package:flutter/material.dart' show debugPrint; import 'package:flutter/material.dart' show debugPrint;
import 'package:wallpaper/common/models/base_resp_model.dart'; import 'package:now_wallpaper/models/base_resp_model.dart';
import 'package:wallpaper/common/models/wallpaper_model.dart'; import 'package:now_wallpaper/models/wallpaper_model.dart';
JsonConvert jsonConvert = JsonConvert(); JsonConvert jsonConvert = JsonConvert();

View File

@ -1,5 +1,5 @@
import 'package:wallpaper/generated/json/base/json_convert_content.dart'; import 'package:now_wallpaper/generated/json/base/json_convert_content.dart';
import 'package:wallpaper/common/models/base_resp_model.dart'; import 'package:now_wallpaper/models/base_resp_model.dart';
BaseRespModel $BaseRespModelFromJson(Map<String, dynamic> json) { BaseRespModel $BaseRespModelFromJson(Map<String, dynamic> json) {
final BaseRespModel baseRespModel = BaseRespModel(); final BaseRespModel baseRespModel = BaseRespModel();

View File

@ -1,13 +1,10 @@
import 'package:wallpaper/generated/json/base/json_convert_content.dart'; import 'package:now_wallpaper/generated/json/base/json_convert_content.dart';
import 'package:wallpaper/common/models/wallpaper_model.dart'; import 'package:now_wallpaper/models/wallpaper_model.dart';
import 'package:hive/hive.dart';
WallpaperModel $WallpaperModelFromJson(Map<String, dynamic> json) { WallpaperModel $WallpaperModelFromJson(Map<String, dynamic> json) {
final WallpaperModel wallpaperModel = WallpaperModel(); final WallpaperModel wallpaperModel = WallpaperModel();
final List<WallpaperData>? data = (json['data'] as List<dynamic>?) final List<WallpaperData>? data = (json['data'] as List<dynamic>?)
?.map( ?.map((e) => jsonConvert.convert<WallpaperData>(e) as WallpaperData)
(e) => jsonConvert.convert<WallpaperData>(e) as WallpaperData)
.toList(); .toList();
if (data != null) { if (data != null) {
wallpaperModel.data = data; wallpaperModel.data = data;
@ -47,8 +44,8 @@ WallpaperData $WallpaperDataFromJson(Map<String, dynamic> json) {
if (original != null) { if (original != null) {
wallpaperData.original = original; wallpaperData.original = original;
} }
final String? previewThumb = jsonConvert.convert<String>( final String? previewThumb =
json['previewThumb']); jsonConvert.convert<String>(json['previewThumb']);
if (previewThumb != null) { if (previewThumb != null) {
wallpaperData.previewThumb = previewThumb; wallpaperData.previewThumb = previewThumb;
} }
@ -81,4 +78,4 @@ extension WallpaperDataExtension on WallpaperData {
..previewThumb = previewThumb ?? this.previewThumb ..previewThumb = previewThumb ?? this.previewThumb
..source = source ?? this.source; ..source = source ?? this.source;
} }
} }

View File

@ -4,11 +4,11 @@ import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:wallpaper/common/components/easy_loading.dart'; import 'package:now_wallpaper/common/components/easy_loading.dart';
import 'package:wallpaper/common/storage/hive_storage.dart'; import 'package:now_wallpaper/common/storage/hive_storage.dart';
import 'package:wallpaper/res/themes/app_themes.dart'; import 'package:now_wallpaper/res/themes/app_themes.dart';
import 'package:wallpaper/res/values/strings.dart'; import 'package:now_wallpaper/res/values/strings.dart';
import 'package:wallpaper/routes/app_pages.dart'; import 'package:now_wallpaper/routes/app_pages.dart';
void main() async { void main() async {
// Hive // Hive
@ -41,6 +41,7 @@ class MyApp extends StatelessWidget {
builder: (context, child) { builder: (context, child) {
return GetMaterialApp( return GetMaterialApp(
title: appName, title: appName,
debugShowCheckedModeBanner: false,
theme: darkTheme, theme: darkTheme,
darkTheme: darkTheme, darkTheme: darkTheme,
themeMode: ThemeMode.dark, themeMode: ThemeMode.dark,

View File

@ -1,7 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:now_wallpaper/generated/json/base/json_field.dart';
import 'package:wallpaper/generated/json/base/json_field.dart'; import 'package:now_wallpaper/generated/json/base_resp_model.g.dart';
import 'package:wallpaper/generated/json/base_resp_model.g.dart';
@JsonSerializable() @JsonSerializable()
class BaseRespModel { class BaseRespModel {

View File

@ -1,7 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:wallpaper/generated/json/base/json_field.dart'; import 'package:now_wallpaper/generated/json/base/json_field.dart';
import 'package:wallpaper/generated/json/wallpaper_model.g.dart'; import 'package:now_wallpaper/generated/json/wallpaper_model.g.dart';
part 'wallpaper_model.g.dart'; part 'wallpaper_model.g.dart';

View File

@ -1,6 +1,6 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
import 'package:wallpaper/res/values/strings.dart'; import 'package:now_wallpaper/res/values/strings.dart';
class AboutController extends GetxController { class AboutController extends GetxController {
var versionName = ''.obs; var versionName = ''.obs;
@ -14,6 +14,6 @@ class AboutController extends GetxController {
/// ///
void _getVersion() async { void _getVersion() async {
final packageInfo = await PackageInfo.fromPlatform(); final packageInfo = await PackageInfo.fromPlatform();
versionName.value = '$appName\nversion${packageInfo.version}'; versionName.value = 'App Version${packageInfo.version}';
} }
} }

View File

@ -1,9 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:wallpaper/common/components/base_appbar.dart'; import 'package:now_wallpaper/common/components/navigation_bar/base_appbar.dart';
import 'package:now_wallpaper/generated/assets.dart';
import 'about_controller.dart'; import 'package:now_wallpaper/modules/about/about_controller.dart';
import 'package:now_wallpaper/res/values/strings.dart';
class AboutView extends GetView<AboutController> { class AboutView extends GetView<AboutController> {
const AboutView({super.key}); const AboutView({super.key});
@ -12,23 +13,44 @@ class AboutView extends GetView<AboutController> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: const BaseAppBar('About'), appBar: const BaseAppBar('About'),
body: Column( body: Container(
children: [ alignment: Alignment.topCenter,
SizedBox(height: 100.h), child: Column(
Obx(() { children: [
return Align( SizedBox(height: 60.h),
alignment: Alignment.center, Image.asset(
child: Text( Assets.iconIconApp,
controller.versionName.value, width: 110.w,
height: 110.w,
),
SizedBox(height: 20.h),
Obx(() {
return RichText(
maxLines: 2,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( text: TextSpan(
color: Colors.white, text: appName,
fontSize: 14.sp, style: TextStyle(
color: Colors.white,
fontSize: 22.sp,
fontWeight: FontWeight.w600,
),
children: [
TextSpan(
text: '\n${controller.versionName.value}',
style: TextStyle(
color: Colors.white,
fontSize: 12.sp,
fontWeight: FontWeight.w600,
),
),
],
), ),
), );
); }),
}), ],
], ),
), ),
); );
} }

View File

@ -0,0 +1,43 @@
import 'package:get/get.dart';
import 'package:now_wallpaper/common/components/view_state_widget.dart';
import 'package:now_wallpaper/models/wallpaper_model.dart';
import 'package:now_wallpaper/modules/root/root_controller.dart';
import 'package:now_wallpaper/routes/app_pages.dart';
class CatalogController extends GetxController {
static CatalogController get to => Get.find<CatalogController>();
late ViewState viewState;
late List<WallpaperModel> wallpaperModelList;
@override
void onInit() {
super.onInit();
getData();
}
void getData() {
wallpaperModelList = RootController.to.wallpaperModelList;
viewState = wallpaperModelList.isNotEmpty ? ViewState.normal : ViewState.empty;
refresh();
}
/// 5
List<WallpaperData> getRandomFiveList(WallpaperModel item) {
if (item.data != null && item.data!.length >= 5) {
var flatList = item.data!.map((e) => e).toList();
return (flatList..shuffle()).take(5).toList();
} else {
return item.data == null ? <WallpaperData>[] : item.data!;
}
}
void onTapSingleCls(WallpaperModel wallpaperModel) {
//
Get.toNamed(AppPages.singleCls, arguments: wallpaperModel);
}
///
void onTapItem(List<WallpaperData> wallpaperList, int index) {
Get.toNamed(AppPages.wallpaperDet, arguments: {'position': index, 'wallpaperList': wallpaperList});
}
}

View File

@ -0,0 +1,109 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:now_wallpaper/common/components/image_network_widget.dart';
import 'package:now_wallpaper/models/wallpaper_model.dart';
import 'package:now_wallpaper/modules/catalog/catalog_controller.dart';
class CatalogView extends GetView<CatalogController> {
const CatalogView({super.key});
@override
Widget build(BuildContext context) {
Get.lazyPut(() => CatalogController());
return GetBuilder<CatalogController>(
builder: (logic) {
return ListView.separated(
physics: const BouncingScrollPhysics(),
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 7.h),
itemCount: controller.wallpaperModelList.length,
itemBuilder: (context, index) {
return _buildCatalogItem(controller.wallpaperModelList[index]);
},
separatorBuilder: (context, index) {
return SizedBox(height: 24.h);
},
);
},
);
}
Widget _buildCatalogItem(WallpaperModel item) {
final wallpaperList = controller.getRandomFiveList(item);
return Column(
children: [
Row(
children: [
Expanded(
child: Text(
'${item.name}',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Colors.white,
fontSize: 24.sp,
fontWeight: FontWeight.w600,
),
),
),
if (item.data != null && item.data!.isNotEmpty) ...[
SizedBox(width: 10.w),
GestureDetector(
onTap: () => controller.onTapSingleCls(item),
child: Row(
children: [
Text(
'${item.data!.length} More',
style: TextStyle(
color: Colors.white,
fontSize: 14.sp,
fontWeight: FontWeight.w500,
),
),
Icon(Icons.keyboard_arrow_right, size: 18.w),
],
),
),
],
],
),
SizedBox(height: 7.h),
SizedBox(
height: 233.h,
child: ShaderMask(
shaderCallback: (Rect bounds) {
return const LinearGradient(
colors: [Colors.transparent, Color(0xFF0C0C15), Color(0xFF0C0C15), Colors.transparent],
stops: [0.0, 0.1, 0.9, 1],
).createShader(bounds);
},
blendMode: BlendMode.dstIn,
child: ListView.separated(
scrollDirection: Axis.horizontal,
physics: const BouncingScrollPhysics(),
itemCount: wallpaperList.length,
itemBuilder: (context, index) {
return _buildWallpaperItem(wallpaperList, wallpaperList[index], index);
},
separatorBuilder: (context, index) {
return SizedBox(width: 8.w);
},
),
),
),
],
);
}
Widget _buildWallpaperItem(List<WallpaperData> wallpaperList, WallpaperData item, int index) {
return GestureDetector(
onTap: () => controller.onTapItem(wallpaperList, index),
child: ImageNetworkWidget(
url: item.previewThumb,
width: 136.w,
height: double.infinity,
radius: 8.r,
),
);
}
}

View File

@ -0,0 +1,75 @@
import 'package:easy_refresh/easy_refresh.dart';
import 'package:get/get.dart';
import 'package:now_wallpaper/common/components/view_state_widget.dart';
import 'package:now_wallpaper/common/utils/obj_util.dart';
import 'package:now_wallpaper/models/wallpaper_model.dart';
import 'package:now_wallpaper/modules/root/root_controller.dart';
import 'package:now_wallpaper/routes/app_pages.dart';
class DiscoverController extends GetxController {
static DiscoverController get to => Get.find<DiscoverController>();
late final EasyRefreshController refreshController;
late ViewState viewState;
var allWallpaper = <WallpaperData>[];
var wallpaperDataList = <WallpaperData>[];
var todayNewestList = <WallpaperData>[];
WallpaperModel? todayNewestData;
///
var clsName = '';
///
int pageNum = 1;
int pageSize = 10;
@override
void onInit() {
super.onInit();
refreshController = EasyRefreshController(controlFinishLoad: true);
getData();
}
void getData() {
todayNewestData = RootController.to.getRandomCls();
if (todayNewestData != null && todayNewestData!.data != null && todayNewestData!.data!.length >= 3) {
clsName = ObjUtil.getStr(todayNewestData!.name);
var flatList = todayNewestData!.data!.map((e) => e).toList();
// 3
todayNewestList = (flatList..shuffle()).take(3).toList();
}
viewState = RootController.to.viewState;
allWallpaper = RootController.to.wallpaperModelList.expand((element) => element.data ?? <WallpaperData>[]).toList();
_getDataToShow();
}
void _getDataToShow() {
if (allWallpaper.isNotEmpty) {
//
int startIndex = (pageNum - 1) * pageSize;
//
int endIndex = startIndex + pageSize;
wallpaperDataList.addAll(allWallpaper.sublist(startIndex, endIndex));
refreshController.finishLoad();
}
refresh();
}
///
void onLoad() {
if (pageNum == (allWallpaper.length / pageSize).ceil()) {
refreshController.finishLoad(IndicatorResult.noMore);
} else {
pageNum++;
_getDataToShow();
}
}
///
void onTapTodayNewest() {
//
Get.toNamed(AppPages.singleCls, arguments: todayNewestData);
}
///
void onTapItem(int index) {
Get.toNamed(AppPages.wallpaperDet, arguments: {'position': index, 'wallpaperList': wallpaperDataList});
}
}

View File

@ -0,0 +1,124 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:get/get.dart';
import 'package:now_wallpaper/common/components/image_network_widget.dart';
import 'package:now_wallpaper/common/components/refresh/base_easyrefresh.dart';
import 'package:now_wallpaper/models/wallpaper_model.dart';
import 'package:now_wallpaper/modules/discover/discover_controller.dart';
import 'package:now_wallpaper/res/themes/app_sizes.dart';
class DiscoverView extends GetView<DiscoverController> {
const DiscoverView({super.key});
@override
Widget build(BuildContext context) {
Get.lazyPut(() => DiscoverController());
return GetBuilder<DiscoverController>(
builder: (controller) {
return Column(
children: [
SizedBox(height: 7.h),
if (controller.todayNewestList.isNotEmpty) ...[
_buildTodayNewest(),
SizedBox(height: 7.h),
],
Expanded(
child: BaseEasyRefresh(
controller: controller.refreshController,
onLoad: controller.onLoad,
viewState: controller.viewState,
height: discoverListHeight,
child: MasonryGridView.count(
itemCount: controller.wallpaperDataList.length,
crossAxisCount: 2,
mainAxisSpacing: 10.w,
crossAxisSpacing: 10.w,
padding: EdgeInsets.fromLTRB(20.w, 0, 20.w, 7.h),
itemBuilder: (context, index) {
return _buildDiscoverItem(controller.wallpaperDataList[index], index);
},
),
),
),
],
);
},
);
}
Widget _buildDiscoverItem(WallpaperData item, index) {
return GestureDetector(
onTap: () => controller.onTapItem(index),
child: ImageNetworkWidget(
url: item.previewThumb,
radius: 8.r,
),
);
}
///
Widget _buildTodayNewest() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20).w,
child: ClipRRect(
borderRadius: BorderRadius.circular(12).r,
child: Material(
color: Colors.white,
child: InkWell(
onTap: controller.onTapTodayNewest,
child: Container(
height: todayNewestHeight,
padding: const EdgeInsets.symmetric(horizontal: 16).w,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: RichText(
maxLines: 2,
overflow: TextOverflow.ellipsis,
text: TextSpan(
text: 'Today',
style: TextStyle(
color: const Color(0xFF666666),
fontSize: 12.sp,
fontWeight: FontWeight.w600,
),
children: [
TextSpan(
text: '\n${controller.clsName}',
style: TextStyle(
color: const Color(0xFF333333),
fontSize: 16.sp,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
...List.generate(controller.todayNewestList.length, (index) {
final item = controller.todayNewestList[index];
return Row(
children: [
ImageNetworkWidget(
url: item.previewThumb,
width: 42.w,
height: 42.w,
radius: 4.r,
),
if (index != controller.todayNewestList.length - 1) ...[
SizedBox(width: 8.w),
],
],
);
}),
],
),
),
),
),
),
);
}
}

View File

@ -1,38 +1,50 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:wallpaper/common/components/dialog/hint_dialog.dart'; import 'package:now_wallpaper/common/components/dialog/remind_dialog.dart';
import 'package:wallpaper/common/components/view_state_widget.dart'; import 'package:now_wallpaper/common/components/view_state_widget.dart';
import 'package:wallpaper/common/models/wallpaper_model.dart'; import 'package:now_wallpaper/common/storage/favorite_data.dart';
import 'package:wallpaper/common/storage/favorite_data.dart'; import 'package:now_wallpaper/models/wallpaper_model.dart';
import 'package:wallpaper/routes/app_pages.dart'; import 'package:now_wallpaper/modules/root/root_controller.dart';
import 'package:now_wallpaper/routes/app_pages.dart';
class FavoriteController extends GetxController { class FavoriteController extends GetxController {
static FavoriteController get to => Get.find<FavoriteController>(); static FavoriteController get to => Get.find<FavoriteController>();
var viewState = ViewState.loading; late ViewState viewState;
late List<WallpaperData> wallpaperList; late List<WallpaperData> favoriteList;
var todayHottestList = <WallpaperData>[];
WallpaperModel? todayHottestData;
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
_getData(); getData();
getTodayHottestList();
} }
/// void getData() {
void _getData() { favoriteList = FavoriteData().getWallpaperData().reversed.toList();
wallpaperList = FavoriteData().getWallpaperData().reversed.toList(); _refreshList();
_changeViewState();
} }
/// void _refreshList() {
void _changeViewState() { viewState = favoriteList.isNotEmpty ? ViewState.normal : ViewState.empty;
viewState = wallpaperList.isNotEmpty ? ViewState.normal : ViewState.empty; refresh();
}
///
void getTodayHottestList() {
// 3
todayHottestData = RootController.to.getRandomCls();
if (todayHottestData != null && todayHottestData!.data != null && todayHottestData!.data!.length >= 3) {
var flatList = todayHottestData!.data!.map((e) => e).toList();
todayHottestList = (flatList..shuffle()).take(3).toList();
}
} }
/// ///
void itemOnTap(int index) async { void onTapItem(int index, bool isFavorite) {
Get.toNamed(AppPages.wallpaperDet, arguments: { Get.toNamed(AppPages.wallpaperDet, arguments: {
'isFavorite': true,
'position': index, 'position': index,
'wallpaperList': wallpaperList 'wallpaperList': isFavorite ? favoriteList : todayHottestList,
}); });
} }
@ -40,11 +52,14 @@ class FavoriteController extends GetxController {
void onLongPress(int index) { void onLongPress(int index) {
Get.dialog( Get.dialog(
barrierDismissible: false, barrierDismissible: false,
HintDialog( RemindDialog(
content: 'Are you sure you want to delete the wallpaper?', content: 'Are you sure you want to delete the wallpaper?',
confirmOnTap: () { confirmOnTap: () {
FavoriteData().delete(index); //
refreshList(); int indexToRemoveFromDb = FavoriteData().getWallpaperData().length - 1 - index;
FavoriteData().delete(indexToRemoveFromDb);
favoriteList.removeAt(index);
_refreshList();
}, },
), ),
); );
@ -54,21 +69,19 @@ class FavoriteController extends GetxController {
void deleteAll() { void deleteAll() {
Get.dialog( Get.dialog(
barrierDismissible: false, barrierDismissible: false,
HintDialog( RemindDialog(
content: 'Are you sure to delete all wallpapers?', content: 'Are you sure to delete all wallpapers?',
confirmOnTap: () { confirmOnTap: () async {
FavoriteData().clear(); FavoriteData().clear();
wallpaperList.clear(); favoriteList.clear();
_changeViewState(); _refreshList();
refresh();
}, },
), ),
); );
} }
/// void onTapViewMore() {
void refreshList() { //
_getData(); Get.toNamed(AppPages.singleCls, arguments: todayHottestData);
refresh();
} }
} }

Some files were not shown because too many files have changed in this diff Show More