This commit is contained in:
xuhang-x 2024-07-22 10:45:47 +08:00
parent 992f46050b
commit 6668a35f02
9 changed files with 295 additions and 37 deletions

View File

@ -38,7 +38,7 @@ 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.ai.wallpaper.genie" applicationId = "com.live.fantasy.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.
minSdk = flutter.minSdkVersion minSdk = flutter.minSdkVersion

View File

@ -17,7 +17,7 @@
<application <application
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/launcher_icon" android:icon="@mipmap/launcher_icon"
android:label="Wallpaper Genie" android:label="Fantasy Wallpaper"
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
android:enableOnBackInvokedCallback="true" android:enableOnBackInvokedCallback="true"
tools:targetApi="tiramisu"> tools:targetApi="tiramisu">

View File

@ -488,18 +488,21 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 3; CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_TEAM = 34W9G5KLNH; DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 8B4CW938L2;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.ai.wallpaper.genie; PRODUCT_BUNDLE_IDENTIFIER = com.live.fantasy.wallpaper;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = Fantasy_Wallpaper_Release;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO; SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
@ -679,18 +682,21 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 3; CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_TEAM = 34W9G5KLNH; DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 8B4CW938L2;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.ai.wallpaper.genie; PRODUCT_BUNDLE_IDENTIFIER = com.live.fantasy.wallpaper;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = Fantasy_Wallpaper_Release;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO; SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
@ -710,18 +716,21 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 3; CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_TEAM = 34W9G5KLNH; DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 8B4CW938L2;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.ai.wallpaper.genie; PRODUCT_BUNDLE_IDENTIFIER = com.live.fantasy.wallpaper;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = Fantasy_Wallpaper_Release;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO; SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;

View File

@ -7,7 +7,7 @@
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
<string>Wallpaper Genie</string> <string>Fantasy Wallpaper</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
@ -15,7 +15,7 @@
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>wallpaper_genie</string> <string>fantasy_wallpaper</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>

View File

@ -0,0 +1,106 @@
library stacked_animated_list;
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:stacked_animated_list/models/stacked_item.dart';
import 'package:stacked_animated_list/utils/animated_stack_list_mixin.dart';
import 'package:wallpaperx/common/components/custom_transformed_list_item_widget.dart';
class StackedListWidget extends StatefulWidget {
final List<Widget> listItems;
final double listItemWidth;
final Duration animationDuration;
final BorderRadiusGeometry? borderRadius;
final double rotationAngle;
final double additionalTranslateOffsetBeyondScreen;
final List<BoxShadow>? focusedItemShadow;
final ValueChanged<int>? onIndexChanged;
const StackedListWidget({
required this.listItems,
required this.listItemWidth,
this.animationDuration = const Duration(milliseconds: 350),
this.borderRadius = const BorderRadius.all(Radius.circular(16)),
this.rotationAngle = 15,
this.additionalTranslateOffsetBeyondScreen = 0,
this.focusedItemShadow,
this.onIndexChanged,
super.key,
});
@override
State<StackedListWidget> createState() => _StackedListWidgetState();
}
class _StackedListWidgetState extends State<StackedListWidget>
with SingleTickerProviderStateMixin, AnimatedStackListMixin {
final List<StackedItem> _stackWidgets = [];
AnimationController? _animationCtr;
Animation? _increaseAnim;
@override
void initState() {
_animationCtr = AnimationController(
vsync: this,
duration: widget.animationDuration,
);
_increaseAnim = Tween<double>(
begin: 0,
end: 1,
).animate(CurvedAnimation(parent: _animationCtr!, curve: Curves.easeOut));
_stackWidgets.clear();
_stackWidgets.addAll(generateStackedItems(widget.listItems));
_animationCtr?.forward(from: 0);
super.initState();
}
@override
void dispose() {
_animationCtr?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Stack(
children: _stackWidgets
.mapIndexed(
(index, item) {
final isFirstItem = index == 0;
return Center(
child: TransformedListItemWidget(
stackedItem: item,
animation: _increaseAnim!,
widgetWidth: widget.listItemWidth,
focusedWidget: isFirstItem,
borderRadius: widget.borderRadius,
rotationAngle: widget.rotationAngle,
additionalTranslateOffsetBeyondScreen:
widget.additionalTranslateOffsetBeyondScreen,
focusedItemShadow: widget.focusedItemShadow,
onDragEnded: () {
final refreshList = refreshedStackedItems(_stackWidgets);
_stackWidgets.clear();
_stackWidgets.addAll(refreshList);
_animationCtr?.forward(from: 0);
setState(() {
final String keyValue =
_stackWidgets[0].widget.key is ValueKey<String>
? (_stackWidgets[0].widget.key as ValueKey<String>).value
: '0';
widget.onIndexChanged?.call(int.parse(keyValue));
});
},
),
);
},
)
.toList()
.reversed
.toList(),
);
}
}

View File

@ -0,0 +1,93 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:stacked_animated_list/models/stacked_item.dart';
import 'package:stacked_animated_list/ui/focused_transformed_item_widget.dart';
import 'package:stacked_animated_list/ui/unfocused_transformed_item_widget.dart';
import 'package:stacked_animated_list/utils/animated_stack_list_mixin.dart';
import 'package:wallpaperx/common/utils/log_print.dart';
import 'package:wallpaperx/page/discover/discover_controller.dart';
class TransformedListItemWidget extends StatelessWidget
with AnimatedStackListMixin {
final StackedItem stackedItem;
final double widgetWidth;
final bool focusedWidget;
final Function() onDragEnded;
final Animation animation;
final BorderRadiusGeometry? borderRadius;
final double rotationAngle;
final double additionalTranslateOffsetBeyondScreen;
final List<BoxShadow>? focusedItemShadow;
const TransformedListItemWidget({
super.key,
required this.stackedItem,
required this.widgetWidth,
required this.focusedWidget,
required this.onDragEnded,
required this.animation,
this.borderRadius = const BorderRadius.all(Radius.circular(16)),
this.rotationAngle = 15,
this.additionalTranslateOffsetBeyondScreen = 0,
this.focusedItemShadow,
});
@override
Widget build(BuildContext context) {
final horizontalOffset = getListItemHorizontalOffset(
context,
widgetWidth,
additionalTranslateOffsetBeyondScreen,
);
if (focusedWidget) {
final childWidget = Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
boxShadow: focusedItemShadow ?? defaultFocusedItemShadow(),
borderRadius: borderRadius,
),
child: stackedItem.widget,
);
final animatedFromPosType = stackedItem.positionTypeForNextItem.reverse;
return AnimatedBuilder(
animation: animation,
child: LongPressDraggable(
feedback: childWidget,
childWhenDragging: const SizedBox.shrink(),
delay: const Duration(milliseconds: 10),
child: childWidget,
onDragEnd: (details) {
if (isItemFlicked(details)) {
onDragEnded();
} else {
if (Get.isRegistered<DiscoverController>()) {
DiscoverController.to.onTapSwiperItem();
}
}
},
),
builder: (_, child) {
return FocusedTransformedItemWidget(
animation: animation,
rotationAngle: rotationAngle,
horizontalOffset: horizontalOffset,
positionType: animatedFromPosType,
child: child!,
);
},
);
}
return UnfocusedTransformedItemWidget(
stackedItem: stackedItem,
animation: animation,
rotationAngle: rotationAngle,
horizontalOffset: horizontalOffset,
borderRadius: borderRadius,
positionType: stackedItem.positionType,
);
}
}

View File

@ -9,12 +9,14 @@ import 'package:get/get_rx/get_rx.dart';
import 'package:wallpaperx/common/components/view_state_widget.dart'; import 'package:wallpaperx/common/components/view_state_widget.dart';
import 'package:wallpaperx/common/http/http_util.dart'; import 'package:wallpaperx/common/http/http_util.dart';
import 'package:wallpaperx/common/http/url.dart'; import 'package:wallpaperx/common/http/url.dart';
import 'package:wallpaperx/common/utils/log_print.dart';
import 'package:wallpaperx/common/utils/shared_util.dart'; import 'package:wallpaperx/common/utils/shared_util.dart';
import 'package:wallpaperx/entity/image_model.dart'; import 'package:wallpaperx/entity/image_model.dart';
import 'package:wallpaperx/page/home/home_controller.dart'; import 'package:wallpaperx/page/home/home_controller.dart';
import 'package:wallpaperx/routes/app_pages.dart'; import 'package:wallpaperx/routes/app_pages.dart';
class DiscoverController extends GetxController { class DiscoverController extends GetxController {
static DiscoverController get to => Get.find<DiscoverController>();
late final EasyRefreshController refreshController; late final EasyRefreshController refreshController;
late ScrollController scrollController; late ScrollController scrollController;
@ -66,7 +68,7 @@ class DiscoverController extends GetxController {
if (res["images"] != null) { if (res["images"] != null) {
List list = List.from(res["images"]); List list = List.from(res["images"]);
images.addAll(list.map((e) => ImageModel.fromJson(e)).toList()); images.addAll(list.map((e) => ImageModel.fromJson(e)).toList());
list = (list..shuffle()).take(10).toList(); list = (list..shuffle()).take(5).toList();
banners.addAll(list.map((e) => ImageModel.fromJson(e)).toList()); banners.addAll(list.map((e) => ImageModel.fromJson(e)).toList());
viewState = ViewState.normal.obs; viewState = ViewState.normal.obs;
update(["discover_background"]); update(["discover_background"]);
@ -75,7 +77,7 @@ class DiscoverController extends GetxController {
} }
_stopTimer(); _stopTimer();
} }
},errorCallback: (e) { }, errorCallback: (e) {
_timer ??= Timer.periodic(const Duration(seconds: 2), (Timer t) { _timer ??= Timer.periodic(const Duration(seconds: 2), (Timer t) {
getImages(); getImages();
}); });
@ -99,9 +101,9 @@ class DiscoverController extends GetxController {
} }
/// ///
void onTapSwiperItem(int index) { void onTapSwiperItem() {
Get.toNamed(AppPages.wallpaperDet, arguments: { Get.toNamed(AppPages.wallpaperDet, arguments: {
'position': index, 'position': index.value,
'wallpaperList': banners, 'wallpaperList': banners,
}); });
} }

View File

@ -7,10 +7,12 @@ import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter_swiper_view/flutter_swiper_view.dart'; import 'package:flutter_swiper_view/flutter_swiper_view.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:photo_view/photo_view.dart'; import 'package:photo_view/photo_view.dart';
import 'package:wallpaperx/common/components/custom_stacked_list_widget.dart';
import 'package:wallpaperx/common/components/image_network_widget.dart'; import 'package:wallpaperx/common/components/image_network_widget.dart';
import 'package:wallpaperx/common/components/navigation_bar/search_appbar.dart'; import 'package:wallpaperx/common/components/navigation_bar/search_appbar.dart';
import 'package:wallpaperx/common/components/refresh/base_easyrefresh.dart'; import 'package:wallpaperx/common/components/refresh/base_easyrefresh.dart';
import 'package:wallpaperx/common/components/view_state_widget.dart'; import 'package:wallpaperx/common/components/view_state_widget.dart';
import 'package:wallpaperx/common/utils/log_print.dart';
import 'package:wallpaperx/entity/image_model.dart'; import 'package:wallpaperx/entity/image_model.dart';
import 'package:wallpaperx/generated/assets.dart'; import 'package:wallpaperx/generated/assets.dart';
import 'package:wallpaperx/page/discover/discover_controller.dart'; import 'package:wallpaperx/page/discover/discover_controller.dart';
@ -86,27 +88,72 @@ class DiscoverView extends GetView<DiscoverController> {
onTapToCategory: controller.homeController.openDrawer, onTapToCategory: controller.homeController.openDrawer,
), ),
20.verticalSpace, 20.verticalSpace,
Obx(() { // Obx(() {
return Expanded( // return Expanded(
child: Swiper( // child: Swiper(
loop: true, // loop: true,
autoplay: true, // autoplay: true,
scale: .9, // scale: .9,
viewportFraction: .85, // viewportFraction: .85,
itemCount: controller.banners.length, // itemCount: controller.banners.length,
itemBuilder: (context, index) { // itemBuilder: (context, index) {
return GestureDetector( // return GestureDetector(
onTap: () => controller.onTapSwiperItem(index), // onTap: () => controller.onTapSwiperItem(index),
child: ImageNetworkWidget( // child: ImageNetworkWidget(
url: controller.banners[index].imageUrl, // url: controller.banners[index].imageUrl,
radius: 30.r, // radius: 30.r,
// ),
// );
// },
// onIndexChanged: controller.onIndexChanged,
// ),
// );
// }),
Obx(
() => controller.banners.isEmpty
? Container()
: GestureDetector(
onTap: () => LogPrint.d('onTapSwiperItem'),
child: StackedListWidget(
listItems: controller.banners
.asMap()
.entries
.map(
(e) => Container(
key: Key(e.key.toString()),
child: ImageNetworkWidget(
url: controller.banners[e.key].imageUrl,
radius: 30.r,
width: 300.w,
height: 500.w,
fit: BoxFit.fitHeight,
),
),
)
.toList(),
listItemWidth: 200.w,
animationDuration: const Duration(milliseconds: 350),
borderRadius: BorderRadius.circular(30.r),
rotationAngle: 4,
additionalTranslateOffsetBeyondScreen: -93,
onIndexChanged: controller.onIndexChanged,
focusedItemShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.26),
blurRadius: 28,
spreadRadius: 8,
offset: const Offset(8, 16),
),
BoxShadow(
color: Colors.black.withOpacity(0.26),
blurRadius: 28,
spreadRadius: 8,
offset: const Offset(-8, 2),
),
],
), ),
); ),
}, ),
onIndexChanged: controller.onIndexChanged,
),
);
}),
20.verticalSpace, 20.verticalSpace,
Image.asset( Image.asset(
width: 24.w, width: 24.w,

View File

@ -100,6 +100,7 @@ dependencies:
flip_card: ^0.7.0 flip_card: ^0.7.0
app_tracking_transparency: ^2.0.5 app_tracking_transparency: ^2.0.5
gradient_borders: ^1.0.1 gradient_borders: ^1.0.1
stacked_animated_list: ^1.0.1
# Firebase # Firebase
firebase_core: ^2.32.0 firebase_core: ^2.32.0