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))
android {
namespace "com.lux.wallpaper"
namespace "com.now.wallpaper"
compileSdk flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
@ -46,10 +46,11 @@ android {
defaultConfig {
// 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.
// 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
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName

View File

@ -5,14 +5,18 @@
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32"
tools:ignore="ScopedStorage" />
tools:ignore="ScopedStorage"
/>
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
android:maxSdkVersion="32"
/>
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<application
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:icon="@mipmap/launcher_icon"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true">
<activity
@ -40,6 +44,18 @@
<meta-data
android:name="flutterEmbedding"
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>
<!-- Required to query activities that can process text, see:
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 -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!--<item android:drawable="?android:colorBackground" />-->
<item android:drawable="@android:color/white" />
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<item>
<bitmap
android:gravity="center"
android:src="@mipmap/ic_launcher" />
android:src="@mipmap/launcher_icon" />
</item>
</layer-list>

View File

@ -6,6 +6,6 @@
<item>¬
<bitmap
android:gravity="center"
android:src="@mipmap/ic_launcher" />
android:src="@mipmap/launcher_icon" />
</item>
</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
the Flutter engine draws its first frame -->
<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>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your

View File

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

View File

@ -5,6 +5,10 @@
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<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>
<!-- Theme applied to the Android Window as soon as the process has started.
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 {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
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"

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)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.lux.wallpaper;
PRODUCT_BUNDLE_IDENTIFIER = com.now.wallpaper;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@ -558,7 +558,7 @@
isa = XCBuildConfiguration;
buildSettings = {
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_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
@ -616,7 +616,7 @@
isa = XCBuildConfiguration;
buildSettings = {
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_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
@ -681,7 +681,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.lux.wallpaper;
PRODUCT_BUNDLE_IDENTIFIER = com.now.wallpaper;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@ -704,7 +704,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.lux.wallpaper;
PRODUCT_BUNDLE_IDENTIFIER = com.now.wallpaper;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
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">
<plist version="1.0">
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Wallpaper</string>
<string>Now wallpaper</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@ -24,6 +26,12 @@
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<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>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
@ -41,11 +49,5 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</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>
</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_screenutil/flutter_screenutil.dart';
import 'package:wallpaper/common/components/view_state_widget.dart';
import 'package:wallpaper/common/utils/obj_util.dart';
import 'package:now_wallpaper/common/components/view_state_widget.dart';
import 'package:now_wallpaper/common/utils/obj_util.dart';
class ProcessDialog extends StatelessWidget {
final double process;

View File

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

View File

@ -4,7 +4,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:wallpaper/common/utils/obj_util.dart';
/// EasyLoading配置
void configLoading() {
@ -34,7 +33,7 @@ void configLoading() {
// , 4.0, [EasyLoadingIndicatorType.ring, EasyLoadingIndicatorType.dualRing].
..lineWidth = 2.0
// [showSuccess] [showError] [showInfo], 2000ms.
..displayDuration = const Duration(milliseconds: 2000)
..displayDuration = const Duration(milliseconds: 1000)
// , 200ms.
..animationDuration = const Duration(milliseconds: 200)
// , [EasyLoadingStyle.custom].
@ -54,8 +53,8 @@ void configLoading() {
}
void toast(String? value, {bool show = true}) {
if (show && ObjUtil.isNotEmptyStr(value)) {
EasyLoading.showToast('$value');
if (show && value != null) {
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 }
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;
@override
Widget build(BuildContext context) {
switch (state) {
switch (viewState) {
case ViewState.normal:
return child;
case ViewState.loading:
return loadingView();
case ViewState.error:
return errorView;
case ViewState.empty:
return emptyView;
case ViewState.error:
return errorView;
}
}
}
@ -53,7 +57,7 @@ Widget get emptyView {
'No data available',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
color: const Color(0xFF666666),
fontSize: 14.sp,
),
),
@ -67,7 +71,7 @@ Widget get errorView {
'An error occurred, please try again later',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
color: const Color(0xFF666666),
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:pretty_dio_logger/pretty_dio_logger.dart';
import 'package:wallpaper/common/components/easy_loading.dart';
import 'package:wallpaper/common/models/base_resp_model.dart';
import 'package:wallpaper/common/network/base_error.dart';
import 'package:wallpaper/common/network/dio_interceptor.dart';
import 'package:wallpaper/common/utils/log_print.dart';
import 'package:wallpaper/generated/json/base/json_convert_content.dart';
import 'package:now_wallpaper/common/components/easy_loading.dart';
import 'package:now_wallpaper/common/network/base_error.dart';
import 'package:now_wallpaper/common/network/dio_interceptor.dart';
import 'package:now_wallpaper/common/utils/log_print.dart';
import 'package:now_wallpaper/generated/json/base/json_convert_content.dart';
import 'package:now_wallpaper/models/base_resp_model.dart';
class DioClient {
static final DioClient _instance = DioClient._internal();
@ -71,10 +71,11 @@ class DioClient {
}
} on DioException catch (e) {
BaseError error = getError(e);
toast(error.message, show: showToast);
if (fail != null) fail(error);
toast(error.message, show: showToast);
} catch (e) {
LogPrint.e(e.toString());
toast(e.toString(), show: showToast);
}
}

View File

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

View File

@ -3,7 +3,7 @@
// Description:
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';

View File

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

View File

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

View File

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

View File

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

View File

@ -4,15 +4,19 @@
class ObjUtil {
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) {
return list == null || list.isNotEmpty;
return list != null && list.isNotEmpty;
}
static bool isNotEmptyMap(Map? map) {
return map == null || map.isNotEmpty;
return map != null && map.isNotEmpty;
}
static bool isEmpty(Object? object) {
@ -44,18 +48,4 @@ class ObjUtil {
}
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: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 {
///
@ -108,7 +108,7 @@ class PermissionUtil {
static _showFailedDialog(List<Permission> permissionList, {bool isPermanentlyDenied = false}) async {
Get.dialog(
barrierDismissible: false,
HintDialog(
RemindDialog(
content: await _getInstructions(permissionList),
confirmText: isPermanentlyDenied ? 'Go Settings' : 'Confirm',
confirmOnTap: () {
@ -138,7 +138,7 @@ class PermissionUtil {
}
String explain = '';
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;
}

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 {
Assets._();
static const String imagesError = 'assets/images/error.png';
static const String imagesPlaceholder = 'assets/images/placeholder.png';
static const String iconIconApp = 'assets/icon/icon_app.jpeg';
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';
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
import 'package:get/get.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 {
var versionName = ''.obs;
@ -14,6 +14,6 @@ class AboutController extends GetxController {
///
void _getVersion() async {
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_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:wallpaper/common/components/base_appbar.dart';
import 'about_controller.dart';
import 'package:now_wallpaper/common/components/navigation_bar/base_appbar.dart';
import 'package:now_wallpaper/generated/assets.dart';
import 'package:now_wallpaper/modules/about/about_controller.dart';
import 'package:now_wallpaper/res/values/strings.dart';
class AboutView extends GetView<AboutController> {
const AboutView({super.key});
@ -12,23 +13,44 @@ class AboutView extends GetView<AboutController> {
Widget build(BuildContext context) {
return Scaffold(
appBar: const BaseAppBar('About'),
body: Column(
children: [
SizedBox(height: 100.h),
Obx(() {
return Align(
alignment: Alignment.center,
child: Text(
controller.versionName.value,
body: Container(
alignment: Alignment.topCenter,
child: Column(
children: [
SizedBox(height: 60.h),
Image.asset(
Assets.iconIconApp,
width: 110.w,
height: 110.w,
),
SizedBox(height: 20.h),
Obx(() {
return RichText(
maxLines: 2,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 14.sp,
text: TextSpan(
text: appName,
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:wallpaper/common/components/dialog/hint_dialog.dart';
import 'package:wallpaper/common/components/view_state_widget.dart';
import 'package:wallpaper/common/models/wallpaper_model.dart';
import 'package:wallpaper/common/storage/favorite_data.dart';
import 'package:wallpaper/routes/app_pages.dart';
import 'package:now_wallpaper/common/components/dialog/remind_dialog.dart';
import 'package:now_wallpaper/common/components/view_state_widget.dart';
import 'package:now_wallpaper/common/storage/favorite_data.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 FavoriteController extends GetxController {
static FavoriteController get to => Get.find<FavoriteController>();
var viewState = ViewState.loading;
late List<WallpaperData> wallpaperList;
late ViewState viewState;
late List<WallpaperData> favoriteList;
var todayHottestList = <WallpaperData>[];
WallpaperModel? todayHottestData;
@override
void onInit() {
super.onInit();
_getData();
getData();
getTodayHottestList();
}
///
void _getData() {
wallpaperList = FavoriteData().getWallpaperData().reversed.toList();
_changeViewState();
void getData() {
favoriteList = FavoriteData().getWallpaperData().reversed.toList();
_refreshList();
}
///
void _changeViewState() {
viewState = wallpaperList.isNotEmpty ? ViewState.normal : ViewState.empty;
void _refreshList() {
viewState = favoriteList.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: {
'isFavorite': true,
'position': index,
'wallpaperList': wallpaperList
'wallpaperList': isFavorite ? favoriteList : todayHottestList,
});
}
@ -40,11 +52,14 @@ class FavoriteController extends GetxController {
void onLongPress(int index) {
Get.dialog(
barrierDismissible: false,
HintDialog(
RemindDialog(
content: 'Are you sure you want to delete the wallpaper?',
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() {
Get.dialog(
barrierDismissible: false,
HintDialog(
RemindDialog(
content: 'Are you sure to delete all wallpapers?',
confirmOnTap: () {
confirmOnTap: () async {
FavoriteData().clear();
wallpaperList.clear();
_changeViewState();
refresh();
favoriteList.clear();
_refreshList();
},
),
);
}
///
void refreshList() {
_getData();
refresh();
void onTapViewMore() {
//
Get.toNamed(AppPages.singleCls, arguments: todayHottestData);
}
}

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