Browse Source

合并阿拉伯语开发分支

100Years 2 tháng trước cách đây
mục cha
commit
70d2776b34
54 tập tin đã thay đổi với 2555 bổ sung740 xóa
  1. 1 0
      Bridging-Header.h
  2. 1 1
      Podfile
  3. 1 1
      Podfile.lock
  4. 73 21
      TSLiveWallpaper.xcodeproj/project.pbxproj
  5. 13 4
      TSLiveWallpaper/AppDelegate.swift
  6. 22 0
      TSLiveWallpaper/Assets.xcassets/Mine/mine_cell_update.imageset/Contents.json
  7. BIN
      TSLiveWallpaper/Assets.xcassets/Mine/mine_cell_update.imageset/mine_cell_update@2x.png
  8. BIN
      TSLiveWallpaper/Assets.xcassets/Mine/mine_cell_update.imageset/mine_cell_update@3x.png
  9. 1 2
      TSLiveWallpaper/Business/BusinessView/TSAppBtnView.swift
  10. 25 12
      TSLiveWallpaper/Business/BusinessView/TSImageIPanComparisonView.swift
  11. 7 0
      TSLiveWallpaper/Business/BusinessView/TYCycleImageComparisonView.swift
  12. 3 3
      TSLiveWallpaper/Business/TSAIListVC/TSAIAgeImageHintVC/TSAIListHintBaseVC.swift
  13. 48 20
      TSLiveWallpaper/Business/TSAIListVC/TSAIListHistoryVC/TSAIListHistoryVC.swift
  14. 1 1
      TSLiveWallpaper/Business/TSAIListVC/TSAIListHistoryVC/View/TSGennerateCellView.swift
  15. 3 9
      TSLiveWallpaper/Business/TSAIListVC/TSAIListVC/TSAIListVC.swift
  16. 1 1
      TSLiveWallpaper/Business/TSAIListVC/TSAIListVC/View/TSAILIstCell.swift
  17. 66 0
      TSLiveWallpaper/Business/TSAIListVC/TSAIPhotoDetailsVC/TSAIPhotoDetailsBrowserCell.swift
  18. 168 0
      TSLiveWallpaper/Business/TSAIListVC/TSAIPhotoDetailsVC/TSAIPhotoDetailsBrowserVC.swift
  19. 13 4
      TSLiveWallpaper/Business/TSAIListVC/TSAIPhotoDetailsVC/TSAIPhotoDetailsVC.swift
  20. 1 2
      TSLiveWallpaper/Business/TSAIListVC/TSAIPhotoGeneratorVC/TSAIListPhotoGeneratorVC.swift
  21. 5 10
      TSLiveWallpaper/Business/TSBootVC/TSBootVC.swift
  22. 1 1
      TSLiveWallpaper/Business/TSBusinessWebVC/TSBusinessWebVC.swift
  23. 19 9
      TSLiveWallpaper/Business/TSMineVC/TSMineCell.swift
  24. 7 1
      TSLiveWallpaper/Business/TSMineVC/TSMineVC.swift
  25. 18 19
      TSLiveWallpaper/Business/TSMineVC/TSMineVM.swift
  26. 6 5
      TSLiveWallpaper/Business/TSMineVC/View/TSMineTopView.swift
  27. 31 30
      TSLiveWallpaper/Business/TSPurchaseMembershipVC/TSPurchaseVC.swift
  28. 75 20
      TSLiveWallpaper/Business/TSTabBarController/TSTabBarController.swift
  29. 1 1
      TSLiveWallpaper/Common/Ex/UICollectionView+Ex.swift
  30. 3 3
      TSLiveWallpaper/Common/Purchase/TSPurchaseEnum.swift
  31. 5 5
      TSLiveWallpaper/Common/Purchase/TSPurchaseManager.swift
  32. 2 2
      TSLiveWallpaper/Common/TSNetWork/TSNetWork+Business.swift
  33. 74 0
      TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYCyclePagerTransformLayout.h
  34. 319 0
      TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYCyclePagerTransformLayout.m
  35. 180 0
      TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYCyclePagerView.h
  36. 607 0
      TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYCyclePagerView.m
  37. 47 0
      TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYPageControl.h
  38. 285 0
      TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYPageControl.m
  39. 3 0
      TSLiveWallpaper/Common/Tool/TSCommonTool/TSCommonTool.swift
  40. 1 1
      TSLiveWallpaper/Data/OperationQueue/TSGenerateBaseOperation/TSGenerateBaseOperation.swift
  41. 2 2
      TSLiveWallpaper/Data/OperationQueue/TSGenerateBaseOperation/TSGenerateBasePhotoOperation.swift
  42. 44 0
      TSLiveWallpaper/Data/TSAppUpdateManager/TSAppUpdateManager.swift
  43. 8 0
      TSLiveWallpaper/ar.lproj/InfoPlist.strings
  44. 0 0
      TSLiveWallpaper/ar.lproj/LaunchScreen.strings
  45. 126 0
      TSLiveWallpaper/ar.lproj/Localizable.strings
  46. 0 115
      TSLiveWallpaper/de.lproj/Localizable.strings
  47. 8 0
      TSLiveWallpaper/en.lproj/InfoPlist.strings
  48. 109 101
      TSLiveWallpaper/en.lproj/Localizable.strings
  49. 8 0
      TSLiveWallpaper/es.lproj/InfoPlist.strings
  50. 113 103
      TSLiveWallpaper/es.lproj/Localizable.strings
  51. 0 1
      TSLiveWallpaper/fr.lproj/LaunchScreen.strings
  52. 0 115
      TSLiveWallpaper/fr.lproj/Localizable.strings
  53. 0 1
      TSLiveWallpaper/pt-PT.lproj/LaunchScreen.strings
  54. 0 114
      TSLiveWallpaper/pt-PT.lproj/Localizable.strings

+ 1 - 0
Bridging-Header.h

@@ -3,3 +3,4 @@
 //
 
 #import "LivePhotoUtil.h"
+#import "TYCyclePagerView.h"

+ 1 - 1
Podfile

@@ -27,7 +27,7 @@ target 'TSLiveWallpaper' do
   pod 'RealmSwift', '~>10'
   pod 'TSSmalCoacopods', :path => '../TSSmalCoacopods'
   pod "DynamicBlurView"
-  pod 'TYCyclePagerView'
+#  pod 'TYCyclePagerView'
 end
 
 

+ 1 - 1
Podfile.lock

@@ -128,6 +128,6 @@ SPEC CHECKSUMS:
   TYCyclePagerView: 2b051dade0615c70784aa34f40c646feeddb7344
   TZImagePickerController: d084a7b97c82d387e7669dd86dc9a9057500aacf
 
-PODFILE CHECKSUM: 5cbebc045aa8aafa7a1ab7df0b261de22231dead
+PODFILE CHECKSUM: 74c4f0b01b5d032891fb6b6ff41b26a5594adbda
 
 COCOAPODS: 1.16.2

+ 73 - 21
TSLiveWallpaper.xcodeproj/project.pbxproj

@@ -50,6 +50,7 @@
 		A81F5B5D2D1A906C00740085 /* TSHomeDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81F5B5C2D1A905800740085 /* TSHomeDataModel.swift */; };
 		A81F5B5F2D1A909300740085 /* TSRandomWallpaperModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81F5B5E2D1A907B00740085 /* TSRandomWallpaperModel.swift */; };
 		A81F5B622D1AB17E00740085 /* TSRandomWallpaperBrowseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A81F5B612D1AB17C00740085 /* TSRandomWallpaperBrowseVC.swift */; };
+		A828E9432E03AF4E00E6A9EA /* TSAppUpdateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A828E9422E03AF4D00E6A9EA /* TSAppUpdateManager.swift */; };
 		A83946212D1D61D600ABFF0D /* TSRateUsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83946202D1D61D400ABFF0D /* TSRateUsVC.swift */; };
 		A83946272D1D623800ABFF0D /* TSShareUsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83946262D1D623800ABFF0D /* TSShareUsVC.swift */; };
 		A839462F2D1D64BF00ABFF0D /* TSAboutUsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A839462E2D1D64B300ABFF0D /* TSAboutUsVC.swift */; };
@@ -100,7 +101,13 @@
 		A86857D72DF983620089D222 /* generat_loading.gif in Resources */ = {isa = PBXBuildFile; fileRef = A86857D62DF983620089D222 /* generat_loading.gif */; };
 		A86857DA2DF994600089D222 /* TSAIPhotoDetailsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86857D92DF9945F0089D222 /* TSAIPhotoDetailsVC.swift */; };
 		A86857DD2DF99C200089D222 /* TSImageIPanComparisonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86857DC2DF99C200089D222 /* TSImageIPanComparisonView.swift */; };
+		A87CF8522E0296B30063CB7E /* TSAIPhotoDetailsBrowserVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87CF8512E0296960063CB7E /* TSAIPhotoDetailsBrowserVC.swift */; };
+		A87CF8542E029B450063CB7E /* TSAIPhotoDetailsBrowserCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87CF8532E029B3F0063CB7E /* TSAIPhotoDetailsBrowserCell.swift */; };
+		A87CF85A2E02AF070063CB7E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A87CF8582E02AF070063CB7E /* InfoPlist.strings */; };
 		A895B5002E01370E004F9B85 /* TSTextToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A895B4FF2E01370E004F9B85 /* TSTextToastView.swift */; };
+		A895B5102E0287F2004F9B85 /* TYPageControl.m in Sources */ = {isa = PBXBuildFile; fileRef = A895B50E2E0287F2004F9B85 /* TYPageControl.m */; };
+		A895B5112E0287F2004F9B85 /* TYCyclePagerView.m in Sources */ = {isa = PBXBuildFile; fileRef = A895B50C2E0287F2004F9B85 /* TYCyclePagerView.m */; };
+		A895B5122E0287F2004F9B85 /* TYCyclePagerTransformLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = A895B50A2E0287F2004F9B85 /* TYCyclePagerTransformLayout.m */; };
 		A8C4C0982D242154003C46FC /* LivePhoto.swift in Sources */ = {isa = PBXBuildFile; fileRef = A858EE162D1CF49B004B680F /* LivePhoto.swift */; };
 		A8C4C0A42D24218A003C46FC /* metadata.mov in Resources */ = {isa = PBXBuildFile; fileRef = A8C4C09E2D24218A003C46FC /* metadata.mov */; };
 		A8C4C0A52D24218A003C46FC /* Converter4Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8C4C09B2D24218A003C46FC /* Converter4Video.swift */; };
@@ -154,14 +161,8 @@
 		60553FCD2D3B54A400BAAD7F /* GradientText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientText.swift; sourceTree = "<group>"; };
 		60553FCE2D3B54A400BAAD7F /* GradientBackgroundModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientBackgroundModifier.swift; sourceTree = "<group>"; };
 		60553FDC2D3B84E700BAAD7F /* UIScrollView+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+Ext.swift"; sourceTree = "<group>"; };
-		609B6E9F2D6F11D0007942D4 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/LaunchScreen.strings; sourceTree = "<group>"; };
-		609B6EA02D6F11D5007942D4 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/LaunchScreen.strings; sourceTree = "<group>"; };
 		609B6EA12D6F11E0007942D4 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/LaunchScreen.strings; sourceTree = "<group>"; };
-		609B6EA22D6F11E6007942D4 /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/LaunchScreen.strings"; sourceTree = "<group>"; };
 		609B6EA42D6F1221007942D4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
-		609B6EA62D6F1227007942D4 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
-		609B6EA72D6F1230007942D4 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
-		609B6EA82D6F1231007942D4 /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/Localizable.strings"; sourceTree = "<group>"; };
 		609B6EA92D6F1231007942D4 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
 		71E5F623537702A8306DF3C8 /* Pods-TSLiveWallpaper.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TSLiveWallpaper.release.xcconfig"; path = "Target Support Files/Pods-TSLiveWallpaper/Pods-TSLiveWallpaper.release.xcconfig"; sourceTree = "<group>"; };
 		A81CA4642D15685D00A3AAC8 /* TSLaunchVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSLaunchVC.swift; sourceTree = "<group>"; };
@@ -195,6 +196,7 @@
 		A81F5B5C2D1A905800740085 /* TSHomeDataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSHomeDataModel.swift; sourceTree = "<group>"; };
 		A81F5B5E2D1A907B00740085 /* TSRandomWallpaperModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSRandomWallpaperModel.swift; sourceTree = "<group>"; };
 		A81F5B612D1AB17C00740085 /* TSRandomWallpaperBrowseVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSRandomWallpaperBrowseVC.swift; sourceTree = "<group>"; };
+		A828E9422E03AF4D00E6A9EA /* TSAppUpdateManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAppUpdateManager.swift; sourceTree = "<group>"; };
 		A83946202D1D61D400ABFF0D /* TSRateUsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSRateUsVC.swift; sourceTree = "<group>"; };
 		A83946262D1D623800ABFF0D /* TSShareUsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSShareUsVC.swift; sourceTree = "<group>"; };
 		A839462E2D1D64B300ABFF0D /* TSAboutUsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAboutUsVC.swift; sourceTree = "<group>"; };
@@ -246,7 +248,20 @@
 		A86857D62DF983620089D222 /* generat_loading.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = generat_loading.gif; sourceTree = "<group>"; };
 		A86857D92DF9945F0089D222 /* TSAIPhotoDetailsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIPhotoDetailsVC.swift; sourceTree = "<group>"; };
 		A86857DC2DF99C200089D222 /* TSImageIPanComparisonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSImageIPanComparisonView.swift; sourceTree = "<group>"; };
+		A87CF8512E0296960063CB7E /* TSAIPhotoDetailsBrowserVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIPhotoDetailsBrowserVC.swift; sourceTree = "<group>"; };
+		A87CF8532E029B3F0063CB7E /* TSAIPhotoDetailsBrowserCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIPhotoDetailsBrowserCell.swift; sourceTree = "<group>"; };
+		A87CF8592E02AF070063CB7E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+		A87CF85C2E02AF150063CB7E /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+		A87CF85D2E02AF410063CB7E /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		A895B4FF2E01370E004F9B85 /* TSTextToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSTextToastView.swift; sourceTree = "<group>"; };
+		A895B5012E025020004F9B85 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/LaunchScreen.strings; sourceTree = "<group>"; };
+		A895B5022E025020004F9B85 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = "<group>"; };
+		A895B5092E0287F2004F9B85 /* TYCyclePagerTransformLayout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TYCyclePagerTransformLayout.h; sourceTree = "<group>"; };
+		A895B50A2E0287F2004F9B85 /* TYCyclePagerTransformLayout.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TYCyclePagerTransformLayout.m; sourceTree = "<group>"; };
+		A895B50B2E0287F2004F9B85 /* TYCyclePagerView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TYCyclePagerView.h; sourceTree = "<group>"; };
+		A895B50C2E0287F2004F9B85 /* TYCyclePagerView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TYCyclePagerView.m; sourceTree = "<group>"; };
+		A895B50D2E0287F2004F9B85 /* TYPageControl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TYPageControl.h; sourceTree = "<group>"; };
+		A895B50E2E0287F2004F9B85 /* TYPageControl.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TYPageControl.m; sourceTree = "<group>"; };
 		A8C4C0992D24218A003C46FC /* AVAssetExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVAssetExtension.swift; sourceTree = "<group>"; };
 		A8C4C09A2D24218A003C46FC /* Converter4Image.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Converter4Image.swift; sourceTree = "<group>"; };
 		A8C4C09B2D24218A003C46FC /* Converter4Video.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Converter4Video.swift; sourceTree = "<group>"; };
@@ -580,6 +595,14 @@
 			path = TSRandomWallpaperBrowseVC;
 			sourceTree = "<group>";
 		};
+		A828E9412E03AF3200E6A9EA /* TSAppUpdateManager */ = {
+			isa = PBXGroup;
+			children = (
+				A828E9422E03AF4D00E6A9EA /* TSAppUpdateManager.swift */,
+			);
+			path = TSAppUpdateManager;
+			sourceTree = "<group>";
+		};
 		A839461C2D1D61A900ABFF0D /* VC */ = {
 			isa = PBXGroup;
 			children = (
@@ -649,6 +672,7 @@
 		A858EE182D1CF635004B680F /* ThirdParty */ = {
 			isa = PBXGroup;
 			children = (
+				A895B50F2E0287F2004F9B85 /* TYCyclePagerView */,
 				A8C4C0E42D268D02003C46FC /* LivePhotoCreater.swift */,
 				A8C4C0E52D268D02003C46FC /* VideoRecorder.swift */,
 				A8C4C0A12D24218A003C46FC /* Util */,
@@ -678,6 +702,7 @@
 		A86857802DF81AC20089D222 /* Data */ = {
 			isa = PBXGroup;
 			children = (
+				A828E9412E03AF3200E6A9EA /* TSAppUpdateManager */,
 				A8EE92CC2DFFF2860077DFFD /* OperationQueue */,
 				A868578B2DF843F90089D222 /* TSRealmManager */,
 				A868577F2DF81AB90089D222 /* Model */,
@@ -818,6 +843,8 @@
 			children = (
 				A86857DB2DF99C170089D222 /* View */,
 				A86857D92DF9945F0089D222 /* TSAIPhotoDetailsVC.swift */,
+				A87CF8512E0296960063CB7E /* TSAIPhotoDetailsBrowserVC.swift */,
+				A87CF8532E029B3F0063CB7E /* TSAIPhotoDetailsBrowserCell.swift */,
 			);
 			path = TSAIPhotoDetailsVC;
 			sourceTree = "<group>";
@@ -829,6 +856,19 @@
 			path = View;
 			sourceTree = "<group>";
 		};
+		A895B50F2E0287F2004F9B85 /* TYCyclePagerView */ = {
+			isa = PBXGroup;
+			children = (
+				A895B5092E0287F2004F9B85 /* TYCyclePagerTransformLayout.h */,
+				A895B50A2E0287F2004F9B85 /* TYCyclePagerTransformLayout.m */,
+				A895B50B2E0287F2004F9B85 /* TYCyclePagerView.h */,
+				A895B50C2E0287F2004F9B85 /* TYCyclePagerView.m */,
+				A895B50D2E0287F2004F9B85 /* TYPageControl.h */,
+				A895B50E2E0287F2004F9B85 /* TYPageControl.m */,
+			);
+			path = TYCyclePagerView;
+			sourceTree = "<group>";
+		};
 		A8C4C0A12D24218A003C46FC /* Util */ = {
 			isa = PBXGroup;
 			children = (
@@ -875,6 +915,7 @@
 				A8E56BED2D1520EC003C54AF /* Assets.xcassets */,
 				A8FD8F462DFC3092008CAACF /* launch2.png */,
 				A8E56BEE2D1520EC003C54AF /* Info.plist */,
+				A87CF8582E02AF070063CB7E /* InfoPlist.strings */,
 				A8E56BF02D1520EC003C54AF /* LaunchScreen.storyboard */,
 				609B6EA32D6F1221007942D4 /* Localizable.strings */,
 			);
@@ -1024,10 +1065,8 @@
 			knownRegions = (
 				en,
 				Base,
-				de,
-				fr,
 				es,
-				"pt-PT",
+				ar,
 			);
 			mainGroup = A8E56BCB2D1520DD003C54AF;
 			minimizedProjectReferenceProxies = 1;
@@ -1049,6 +1088,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				603901222DF9770A0096551E /* Flash-old-Time.png in Resources */,
+				A87CF85A2E02AF070063CB7E /* InfoPlist.strings in Resources */,
 				A8C4C0A42D24218A003C46FC /* metadata.mov in Resources */,
 				A86857D72DF983620089D222 /* generat_loading.gif in Resources */,
 				A86857C62DF92BE70089D222 /* ZillaSlab-Bold.ttf in Resources */,
@@ -1115,6 +1155,7 @@
 			files = (
 				A81CA4992D1652C400A3AAC8 /* TSMineVC.swift in Sources */,
 				A8C4C0EF2D27BFF7003C46FC /* TSNetworkTool.swift in Sources */,
+				A828E9432E03AF4E00E6A9EA /* TSAppUpdateManager.swift in Sources */,
 				A81CA46E2D156C7000A3AAC8 /* GlobalImports.swift in Sources */,
 				A8FD8F382DFBD660008CAACF /* TSMineTopView.swift in Sources */,
 				A81CA4832D157F5C00A3AAC8 /* UIImageView+Ex.swift in Sources */,
@@ -1144,6 +1185,9 @@
 				60553FD72D3B54A400BAAD7F /* GradientText.swift in Sources */,
 				60553FD82D3B54A400BAAD7F /* LWBaseNavigationController.swift in Sources */,
 				60553FD92D3B54A400BAAD7F /* GradientBackgroundModifier.swift in Sources */,
+				A895B5102E0287F2004F9B85 /* TYPageControl.m in Sources */,
+				A895B5112E0287F2004F9B85 /* TYCyclePagerView.m in Sources */,
+				A895B5122E0287F2004F9B85 /* TYCyclePagerTransformLayout.m in Sources */,
 				A8FD8F432DFC1656008CAACF /* TSImageComparisonView.swift in Sources */,
 				A868579E2DF915E90089D222 /* TSPurchaseBusiness.swift in Sources */,
 				A81F5B5D2D1A906C00740085 /* TSHomeDataModel.swift in Sources */,
@@ -1157,6 +1201,7 @@
 				A81CA47F2D15789C00A3AAC8 /* TSConfig.swift in Sources */,
 				A81CA49F2D1655CE00A3AAC8 /* UICollectionView+Ex.swift in Sources */,
 				A81CA4BA2D16B6E300A3AAC8 /* TSHomeCell.swift in Sources */,
+				A87CF8542E029B450063CB7E /* TSAIPhotoDetailsBrowserCell.swift in Sources */,
 				A8F778B22D1BA07200BF55D5 /* TSRandomWallpaperBrowseSelectView.swift in Sources */,
 				A8477C9F2D22ABDA00DF0B93 /* TSEditLiveEidtCell.swift in Sources */,
 				A81CA4652D15685F00A3AAC8 /* TSLaunchVC.swift in Sources */,
@@ -1171,6 +1216,7 @@
 				A86857B72DF9258D0089D222 /* TSAIUploadPhotoVC.swift in Sources */,
 				A86857822DF81AD40089D222 /* TSActionInfoModel.swift in Sources */,
 				A86857B22DF921F90089D222 /* TSView.swift in Sources */,
+				A87CF8522E0296B30063CB7E /* TSAIPhotoDetailsBrowserVC.swift in Sources */,
 				A86857872DF81B660089D222 /* TSNetWork+Business.swift in Sources */,
 				A86857882DF81B660089D222 /* TSNetworkManager.swift in Sources */,
 				A86857892DF81B660089D222 /* TSNetworkManager+Loading.swift in Sources */,
@@ -1242,22 +1288,28 @@
 			isa = PBXVariantGroup;
 			children = (
 				609B6EA42D6F1221007942D4 /* en */,
-				609B6EA62D6F1227007942D4 /* fr */,
-				609B6EA72D6F1230007942D4 /* de */,
-				609B6EA82D6F1231007942D4 /* pt-PT */,
 				609B6EA92D6F1231007942D4 /* es */,
+				A895B5022E025020004F9B85 /* ar */,
 			);
 			name = Localizable.strings;
 			sourceTree = "<group>";
 		};
+		A87CF8582E02AF070063CB7E /* InfoPlist.strings */ = {
+			isa = PBXVariantGroup;
+			children = (
+				A87CF8592E02AF070063CB7E /* en */,
+				A87CF85C2E02AF150063CB7E /* es */,
+				A87CF85D2E02AF410063CB7E /* ar */,
+			);
+			name = InfoPlist.strings;
+			sourceTree = "<group>";
+		};
 		A8E56BF02D1520EC003C54AF /* LaunchScreen.storyboard */ = {
 			isa = PBXVariantGroup;
 			children = (
 				A8E56BEF2D1520EC003C54AF /* Base */,
-				609B6E9F2D6F11D0007942D4 /* de */,
-				609B6EA02D6F11D5007942D4 /* fr */,
 				609B6EA12D6F11E0007942D4 /* es */,
-				609B6EA22D6F11E6007942D4 /* pt-PT */,
+				A895B5012E025020004F9B85 /* ar */,
 			);
 			name = LaunchScreen.storyboard;
 			sourceTree = "<group>";
@@ -1273,13 +1325,13 @@
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 1;
+				CURRENT_PROJECT_VERSION = 2;
 				DEVELOPMENT_TEAM = 65UD255J84;
 				ENABLE_APP_SANDBOX = NO;
 				ENABLE_USER_SCRIPT_SANDBOXING = NO;
 				GENERATE_INFOPLIST_FILE = YES;
 				INFOPLIST_FILE = TSLiveWallpaper/Info.plist;
-				INFOPLIST_KEY_CFBundleDisplayName = "Old Photo\n";
+				INFOPLIST_KEY_CFBundleDisplayName = "Old Photo";
 				INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "This app needs to access your location information while you're using it to provide relevant location services and features. We promise to only obtain your location information when you're using the app and to use it solely for providing services and features.";
 				INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Allow us to access Photos in order to save wallpapers to your device.";
 				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
@@ -1290,7 +1342,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 3.6.3;
+				MARKETING_VERSION = 3.6.5;
 				PRODUCT_BUNDLE_IDENTIFIER = musicplayer.offline.com;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1313,13 +1365,13 @@
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 1;
+				CURRENT_PROJECT_VERSION = 2;
 				DEVELOPMENT_TEAM = 65UD255J84;
 				ENABLE_APP_SANDBOX = NO;
 				ENABLE_USER_SCRIPT_SANDBOXING = NO;
 				GENERATE_INFOPLIST_FILE = YES;
 				INFOPLIST_FILE = TSLiveWallpaper/Info.plist;
-				INFOPLIST_KEY_CFBundleDisplayName = "Old Photo\n";
+				INFOPLIST_KEY_CFBundleDisplayName = "Old Photo";
 				INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "This app needs to access your location information while you're using it to provide relevant location services and features. We promise to only obtain your location information when you're using the app and to use it solely for providing services and features.";
 				INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Allow us to access Photos in order to save wallpapers to your device.";
 				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
@@ -1330,7 +1382,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 3.6.3;
+				MARKETING_VERSION = 3.6.5;
 				PRODUCT_BUNDLE_IDENTIFIER = musicplayer.offline.com;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE_SPECIFIER = "";

+ 13 - 4
TSLiveWallpaper/AppDelegate.swift

@@ -62,7 +62,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
     }
 
     func applicationWillEnterForeground(_ application: UIApplication) {
-   
+        checkAppConfig()
     }
 }
 
@@ -73,14 +73,23 @@ extension AppDelegate {
     }
     
     func initPlatform() {
-        dePrint("TSRMShared.aiListDB.listModels.count=\(TSRMShared.aiListDB.listModels.count)")
-        TSColorConfigShared.naviMianTextColor = .white
-        _ = TSImageDataCenter.shared
+        TSRTLManage.setUpInit() //阿拉伯语适配
+        dePrint("TSRMShared.aiListDB.listModels.count=\(TSRMShared.aiListDB.listModels.count)")//提前预热数据库
+        TSColorConfigShared.themeColor = .themeColor
+        TSColorConfigShared.naviMianTextColor = .white//设置基类颜色
+//        _ = TSImageDataCenter.shared
         
+        //设置Kingfisher缓存规则
         let cache = ImageCache(name: "permanent_image_cache")
         cache.diskStorage.config.expiration = .never    // 永不过期
         cache.diskStorage.config.sizeLimit = 0          // 无大小限制
         KingfisherManager.shared.cache = cache
         
+        checkAppConfig()
+    }
+    
+    
+    func checkAppConfig() {
+        TSAppUpdateManager.checkAppConfig()
     }
 }

+ 22 - 0
TSLiveWallpaper/Assets.xcassets/Mine/mine_cell_update.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "mine_cell_update@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "mine_cell_update@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
TSLiveWallpaper/Assets.xcassets/Mine/mine_cell_update.imageset/mine_cell_update@2x.png


BIN
TSLiveWallpaper/Assets.xcassets/Mine/mine_cell_update.imageset/mine_cell_update@3x.png


+ 1 - 2
TSLiveWallpaper/Business/BusinessView/TSAppBtnView.swift

@@ -167,8 +167,7 @@ extension TSAppBtnView{
             make.width.equalTo(button.width)
             make.height.equalTo(button.height)
         }
-   
-        
+
         viewH = 48
     }
 }

+ 25 - 12
TSLiveWallpaper/Business/BusinessView/TSImageIPanComparisonView.swift

@@ -7,7 +7,7 @@
 
 import UIKit
 
-class TSImageIPanComparisonView: UIView {
+class TSImageIPanComparisonView: UIView , UIGestureRecognizerDelegate{
     // MARK: - 属性
     let oldImageView = UIImageView()
     let newImageView = UIImageView()
@@ -32,7 +32,11 @@ class TSImageIPanComparisonView: UIView {
         }
     }
     
-    
+    lazy var panGesture: UIPanGestureRecognizer = {
+        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
+        panGesture.delegate = self
+        return panGesture
+    }()
     // MARK: - 视图设置
     private func setupViews() {
         // 旧图片视图(初始显示)
@@ -56,24 +60,33 @@ class TSImageIPanComparisonView: UIView {
             make.center.equalTo(lineView.snp.center)
         }
 
-        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
         addGestureRecognizer(panGesture)
       
     }
     
+    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
+                          shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
+        
+        if gestureRecognizer == panGesture {
+            let velocity = panGesture.velocity(in: self)
+            return abs(velocity.x) < abs(velocity.y) // 只有垂直速度更快时才响应
+        }
+        return true // 允许同时识别
+    }
+    
     // 处理拖动手势
     @objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
-    
         // 获取手指在视图中的移动距离(相对起点)
         let translation = gesture.translation(in: self)
-        if translation.x > 0 {
-//            print("向右移动: \(translation.x) 像素")
-            lineX = min(lineX + translation.x, self.width-1)
-        } else if translation.x < 0 {
-            lineX = max(lineX + translation.x, 0)
-//            print("向左移动: \(translation.x) 像素")
-        }
-        gesture.setTranslation(.zero, in: self) // 重置位移
+        // 只处理水平移动
+         if abs(translation.x) > abs(translation.y) {
+             if translation.x > 0 {
+                 lineX = min(lineX + translation.x, self.width-1)
+             } else if translation.x < 0 {
+                 lineX = max(lineX + translation.x, 0)
+             }
+             gesture.setTranslation(.zero, in: self)
+         }
     }
 
 

+ 7 - 0
TSLiveWallpaper/Business/BusinessView/TYCycleImageComparisonView.swift

@@ -62,6 +62,13 @@ class TYCycleImageComparisonView: TSBaseView {
         pagerView.dataSource = self
         pagerView.layout.layoutType = TYCyclePagerTransformLayoutType.linear
         pagerView.register(TSCycleImageComparisonCell.classForCoder(), forCellWithReuseIdentifier: TSCycleImageComparisonCell.reuseIdentifier)
+        
+//        if let layout = pagerView.collectionView?.collectionViewLayout {
+////            if layout.responds(to: Selector(("setFlipsHorizontallyInOppositeLayoutDirection:"))) {
+//                layout.setValue(true, forKey: "flipsHorizontallyInOppositeLayoutDirection")
+////            }
+//        }
+        
         return pagerView
     }()
     

+ 3 - 3
TSLiveWallpaper/Business/TSAIListVC/TSAIAgeImageHintVC/TSAIListHintBaseVC.swift

@@ -181,8 +181,8 @@ class TSAIListHintBaseVC: TSBaseVC {
             make.leading.equalTo(0)
             make.top.equalTo(iconImageView.snp.bottom).offset(24)
         }
-        
-        let goodImageView = UIImageView.createImageView(imageName: config.goodImageNamed)
+    
+        let goodImageView = UIImageView.createImageView(imageName: config.goodImageNamed,autoMirrored: false)
         popupContentView.addSubview(goodImageView)
         goodImageView.snp.makeConstraints { make in
             make.top.equalTo(titleLabel.snp.bottom).offset(32)
@@ -207,7 +207,7 @@ class TSAIListHintBaseVC: TSBaseVC {
             make.trailing.equalTo(0)
         }
         
-        let badImageView = UIImageView.createImageView(imageName: config.badImageNamed)
+        let badImageView = UIImageView.createImageView(imageName: config.badImageNamed,autoMirrored: false)
         popupContentView.addSubview(badImageView)
         badImageView.snp.makeConstraints { make in
             make.top.equalTo(goodInfoLabel.snp.bottom).offset(20)

+ 48 - 20
TSLiveWallpaper/Business/TSAIListVC/TSAIListHistoryVC/TSAIListHistoryVC.swift

@@ -23,7 +23,7 @@ class TSAIListHistoryVC: TSBaseVC {
     lazy var navBarView: TSBaseNavContentBarView = {
         let navBarView = TSBaseNavContentBarView()
 
-        let label = UILabel.createLabel(text: "History",font: .font(name: .Pacifico, size: 24))
+        let label = UILabel.createLabel(text: "History".localized,font: .font(name: .Pacifico, size: 24))
         navBarView.barView.addSubview(label)
         label.snp.makeConstraints { make in
            make.center.equalToSuperview()
@@ -59,16 +59,10 @@ class TSAIListHistoryVC: TSBaseVC {
         layout.minimumLineSpacing = 16
         layout.sectionInset = UIEdgeInsets(top: 10, left: 16, bottom: k_Height_TabBar+20, right: 16)
         
-        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
+        let collectionView = TSBaseCollectionView(frame: .zero, collectionViewLayout: layout)
         collectionView.delegate = self
         collectionView.dataSource = self
-        collectionView.showsVerticalScrollIndicator = false
-        collectionView.showsHorizontalScrollIndicator = false
-        collectionView.backgroundColor = .clear
         collectionView.register(TSAIListHistoryCell.self, forCellWithReuseIdentifier: identifier)
-        if #available(iOS 11.0, *) {
-            collectionView.contentInsetAdjustmentBehavior = .never
-        }
         return collectionView
     }()
     
@@ -143,10 +137,18 @@ class TSAIListHistoryVC: TSBaseVC {
     }
     
     @objc func clickNavRight() {
-        showCustomAlert(message: "Are you sure to delete all histories?".localized, rightActionString: "Delete All".localized ,deleteHandler:  {
-            self.removeAllHistoryList()
-            self.updateDataView()
-        })
+        TSCustomAlertController.show(in: self, config: TSCustomAlertController.AlertConfig(
+            message: "Are you sure to delete all histories?".localized,
+            cancelTitle: "Delete All".localized,
+            cancelColor: .red,
+            confirmTitle: "Retain".localized,
+            confirmColor: .white,
+            cancelAction: { [weak self]  in
+                guard let self = self else { return }
+                self.removeAllHistoryList()
+                self.updateDataView()
+            }
+        ))
     }
     
 }
@@ -173,13 +175,32 @@ extension TSAIListHistoryVC: UICollectionViewDataSource ,UICollectionViewDelegat
     public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
 
         if let dbModel = listModelArray.safeObj(At:indexPath.row){
-            let vc = TSAIPhotoDetailsVC()
-            vc.infoModel = dbModel
-            vc.deleteBlock = { [weak self]  in
+            //单个浏览
+//            let vc = TSAIPhotoDetailsVC()
+//            vc.infoModel = dbModel
+//            vc.deleteBlock = { [weak self]  in
+//                guard let self = self else { return }
+//                removeDelete(index: indexPath.row)
+//            }
+//            kPresentModalVC(target: self, modelVC: vc)
+            
+            //多个浏览
+            var dataModelArray: [TSActionInfoModel] = []
+            for itemModel in listModelArray {
+                if itemModel.status == "success" || itemModel.modelType == .example {
+                    dataModelArray.append(itemModel)
+                }
+            }
+            
+            let vc = TSAIPhotoDetailsBrowserVC()
+            vc.currentIndex = dataModelArray.firstIndex(of: dbModel) ?? 0
+            vc.dataModelArray = dataModelArray
+            vc.deleteBlock = { [weak self]  index in
                 guard let self = self else { return }
-                removeDelete(index: indexPath.row)
+                removeDelete(index: index)
             }
             kPresentModalVC(target: self, modelVC: vc)
+            
         }
     }
 }
@@ -198,10 +219,17 @@ extension TSAIListHistoryVC{
                     updateDataView()
                 })
             }else if cmd == "delete" {
-                showCustomAlert(message: "Are you sure to delete?".localized, rightActionString: "Delete".localized ,deleteHandler:  { [weak self]  in
-                    guard let self = self else { return }
-                    removeDelete(index: indexPath.row)
-                })
+                TSCustomAlertController.show(in: self, config: TSCustomAlertController.AlertConfig(
+                    message: "Are you sure to delete?".localized,
+                    cancelTitle: "Delete".localized,
+                    cancelColor: .red,
+                    confirmTitle: "Retain".localized,
+                    confirmColor: .white,
+                    cancelAction: { [weak self]  in
+                        guard let self = self else { return }
+                        removeDelete(index: indexPath.row)
+                    }
+                ))
             }
         }
     }

+ 1 - 1
TSLiveWallpaper/Business/TSAIListVC/TSAIListHistoryVC/View/TSGennerateCellView.swift

@@ -88,7 +88,7 @@ class TSGennerateCellView: TSBaseView {
         isCanClick = false
         let progressInt = Int(progress*100)
 
-        infoLabel.text = "Processing you photo".localized + "..." + "\n\n\(progressInt)%"
+        infoLabel.text = "Processing you photo".localized + "..." + "\n\n" + kPercentlocalized(progressInt)
         infoLabel.textColor = .themeColor
 
         updateInfoLabelCenterY()

+ 3 - 9
TSLiveWallpaper/Business/TSAIListVC/TSAIListVC/TSAIListVC.swift

@@ -29,7 +29,7 @@ class TSAIListVC: TSBaseVC {
     lazy var navBarView: TSBaseNavContentBarView = {
         let navBarView = TSBaseNavContentBarView()
 
-        let label = UILabel.createLabel(text: "Home",font: .font(name: .Pacifico, size: 24))
+        let label = UILabel.createLabel(text: "Home".localized,font: .font(name: .Pacifico, size: 24))
         navBarView.barView.addSubview(label)
         label.snp.makeConstraints { make in
            make.center.equalToSuperview()
@@ -62,17 +62,11 @@ class TSAIListVC: TSBaseVC {
         layout.sectionInset = UIEdgeInsets(top: 10, left: 16, bottom: k_Height_TabBar+20, right: 16)
         return layout
     }()
-    lazy var collectionView: UICollectionView = {
-        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
+    lazy var collectionView:TSBaseCollectionView = {
+        let collectionView = TSBaseCollectionView(frame: .zero, collectionViewLayout: layout)
         collectionView.delegate = self
         collectionView.dataSource = self
-        collectionView.showsVerticalScrollIndicator = false
-        collectionView.showsHorizontalScrollIndicator = false
-        collectionView.backgroundColor = .clear
         collectionView.register(TSAILIstCell.self, forCellWithReuseIdentifier: TSAILIstCell.cellID)
-        if #available(iOS 11.0, *) {
-            collectionView.contentInsetAdjustmentBehavior = .never
-        }
         return collectionView
     }()
 

+ 1 - 1
TSLiveWallpaper/Business/TSAIListVC/TSAIListVC/View/TSAILIstCell.swift

@@ -13,7 +13,7 @@ class TSAILIstCell: TSBaseCollectionCell {
     var itemModel:TSBasicItemModel = TSBasicItemModel(){
         didSet{
             if let imageNamed = itemModel.leftImageName{
-                bgImageView.image = UIImage(named: imageNamed)
+                bgImageView.image = UIImage(named: imageNamed)?.mirrored
             }
             titleLab.text = itemModel.leftTitle
             infoLab.text = itemModel.leftSubTitle

+ 66 - 0
TSLiveWallpaper/Business/TSAIListVC/TSAIPhotoDetailsVC/TSAIPhotoDetailsBrowserCell.swift

@@ -0,0 +1,66 @@
+//
+//  TSAIPhotoDetailsBrowserCell.swift
+//  TSLiveWallpaper
+//
+//  Created by 100Years on 2025/6/17.
+//
+
+class TSAIPhotoDetailsBrowserCell: TSBaseCollectionCell {
+    var model:TSActionInfoModel = TSActionInfoModel(){
+        didSet{
+            dePrint("TSAIPhotoDetailsBrowserCell didSet model")
+            uploadPanComparisonView()
+        }
+    }
+    
+    
+    
+    lazy var panComparisonView : TSImageIPanComparisonView = {
+        let panComparisonView = TSImageIPanComparisonView()
+        return panComparisonView
+    }()
+    
+    
+    override func creatUI() {
+        contentView.addSubview(panComparisonView)
+        panComparisonView.snp.makeConstraints { make in
+            make.height.equalTo(k_ScreenHeight)
+            make.leading.trailing.equalTo(0)
+            make.centerY.equalToSuperview()
+        }
+    }
+    
+    
+    func uploadPanComparisonView(){
+        let infoModel = model
+        DispatchQueue.global(qos: .userInitiated).async {
+            var oldImage:UIImage?
+            var newImage:UIImage?
+            let grounp = DispatchGroup()
+            grounp.enter()
+            TSImageStoreTool.downloadImageWithProgress(urlString: infoModel.request.imageUrl) { image in
+                grounp.leave()
+                oldImage = image
+                
+            }
+            
+            grounp.enter()
+            TSImageStoreTool.downloadImageWithProgress(urlString: infoModel.response.resultUrl) { image in
+                grounp.leave()
+                newImage = image
+            }
+            
+            grounp.notify(queue: .main) {
+                if let oldImage = oldImage,let newImage = newImage {
+                    let size = oldImage.size.height > newImage.size.height ? oldImage.size : newImage.size
+                    self.panComparisonView.snp.updateConstraints { make in
+                        make.height.equalTo(kGetUIWdith(designSize: size, currentW: k_ScreenWidth))
+                    }
+                }
+                
+                self.panComparisonView.configure(oldImage: oldImage, newImage: newImage)
+            }
+        }
+    }
+    
+}

+ 168 - 0
TSLiveWallpaper/Business/TSAIListVC/TSAIPhotoDetailsVC/TSAIPhotoDetailsBrowserVC.swift

@@ -0,0 +1,168 @@
+//
+//  TSAIPhotoDetailsBrowserVC.swift
+//  TSLiveWallpaper
+//
+//  Created by 100Years on 2025/6/17.
+//
+private let cellId = "TSAIPhotoDetailsBrowserCell"
+class TSAIPhotoDetailsBrowserVC: TSBaseVC {
+    
+    var deleteBlock:((Int)->Void)?
+    var dataModelArray:[TSActionInfoModel] = []
+
+    var currentModel:TSActionInfoModel?{
+        if let model = dataModelArray.safeObj(At: currentIndex){
+            return model
+        }
+        return nil
+    }
+    
+    var currentIndex:Int = 0
+    
+    lazy var collectionView: UICollectionView = {
+
+        let layout = UICollectionViewFlowLayout()
+        layout.scrollDirection = .vertical
+        
+        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
+        collectionView.delegate = self
+        collectionView.dataSource = self
+        collectionView.showsVerticalScrollIndicator = false
+        collectionView.showsHorizontalScrollIndicator = false
+        collectionView.backgroundColor = .clear
+        if #available(iOS 11.0, *) {
+            collectionView.contentInsetAdjustmentBehavior = .never
+        }
+        collectionView.register(TSAIPhotoDetailsBrowserCell.self, forCellWithReuseIdentifier: cellId)
+        
+        collectionView.isPagingEnabled = true
+        collectionView.isHidden = true
+        if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
+            flowLayout.minimumInteritemSpacing = 0
+            flowLayout.minimumLineSpacing = 0
+            flowLayout.scrollDirection = .vertical
+            flowLayout.itemSize = CGSize(width: k_ScreenWidth, height: k_ScreenHeight)
+        }
+        return collectionView
+    }()
+
+
+    lazy var saveBtn: UIButton = {
+        let saveBtn = kCreateNormalSubmitBtn(title: "Save".localized) { [weak self]  in
+            guard let self = self else { return }
+            clickSaveBtn()
+        }
+        saveBtn.setTitleImageSpace(spacing: 0)
+        return saveBtn
+    }()
+    var navRightBtn:UIButton = UIButton()
+    
+    override func createView() {
+        super.createView()
+        
+        let imageView = UIImageView.createImageView(image: .navShadow,contentMode: .scaleToFill)
+        navBarContentView.addSubview(imageView)
+        imageView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+        addNormalNavBarView()
+        setPageTitle("Result".localized)
+        
+        navRightBtn = setNavigationItem("", imageName: "ai_delete", direction: .right, action: #selector(clickNavRight))
+        contentView.snp.updateConstraints { make in
+            make.top.equalTo(0)
+        }
+        
+        contentView.addSubview(collectionView)
+        collectionView.snp.makeConstraints { make in
+            make.edges.equalTo(0)
+        }
+        
+        contentView.addSubview(saveBtn)
+        saveBtn.snp.makeConstraints { make in
+            make.centerX.equalToSuperview()
+            make.width.equalTo(250*kDesignScale)
+            make.height.equalTo(48)
+            make.bottom.equalTo(-12-k_Height_safeAreaInsetsBottom())
+        }
+        
+
+        DispatchQueue.main.async {
+            self.collectionView.isHidden = false
+            self.collectionView.reloadData()
+            self.collectionView.setContentOffset(CGPoint(x:0 , y:CGFloat(self.currentIndex) * self.collectionView.frame.size.height), animated: false)
+
+            if let flowLayout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
+                flowLayout.itemSize = self.collectionView.bounds.size
+            }
+        }
+    }
+    
+    //保存功能
+    @objc func clickSaveBtn(){
+        guard let infoModel = currentModel else { return }
+        TSImageStoreTool.downloadImageWithProgress(urlString: infoModel.response.resultUrl) { image in
+            if let image = image {
+                PhotoManagerShared.saveImageToAlbum(image) { [weak self] success, error in
+                    guard let self = self else { return }
+                    if success {
+                        kSaveSuccesswShared.show(atView:self.view)
+                    }else{
+                        debugPrint(error)
+                    }
+                }
+            }
+        }
+    }
+    
+    @objc func clickNavRight() {
+
+        TSCustomAlertController.show(in: self, config: TSCustomAlertController.AlertConfig(
+            message: "Are you sure to delete?".localized,
+            cancelTitle: "Delete".localized,
+            cancelColor: .red,
+            confirmTitle: "Retain".localized,
+            confirmColor: .white,
+            cancelAction: { [weak self]  in
+                guard let self = self else { return }
+                dataModelArray.remove(at: currentIndex)
+                collectionView.deleteItems(at: [IndexPath(item: currentIndex, section: 0)])
+                self.deleteBlock?(currentIndex)
+                if dataModelArray.count <= 0 {
+                    self.navBarClickLeftAction()
+                }
+            }
+        ))
+    }
+}
+
+//MARK: UICollectionViewDataSource
+extension TSAIPhotoDetailsBrowserVC:UICollectionViewDataSource,UICollectionViewDelegate {
+    
+    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
+        resetIndexWithOffset(scrollView)
+    }
+
+    func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
+        resetIndexWithOffset(scrollView)
+    }
+
+    private func resetIndexWithOffset(_ scrollView: UIScrollView) {
+        let item = Int((scrollView.contentOffset.y / scrollView.bounds.height).rounded())
+        currentIndex = item
+    }
+    
+    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+        return dataModelArray.count
+    }
+    
+    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! TSAIPhotoDetailsBrowserCell
+        if let model = dataModelArray.safeObj(At: indexPath.item){
+            cell.model = model
+        }
+        return cell
+    }
+    
+}

+ 13 - 4
TSLiveWallpaper/Business/TSAIListVC/TSAIPhotoDetailsVC/TSAIPhotoDetailsVC.swift

@@ -167,10 +167,19 @@ class TSAIPhotoDetailsVC: TSBaseVC {
     }
     
     @objc func clickNavRight() {
-        showCustomAlert(message: "Are you sure to delete?".localized, rightActionString: "Delete".localized ,deleteHandler:  {
-            self.deleteBlock?()
-            self.navBarClickLeftAction()
-        })
+
+        TSCustomAlertController.show(in: self, config: TSCustomAlertController.AlertConfig(
+            message: "Are you sure to delete?".localized,
+            cancelTitle: "Delete".localized,
+            cancelColor: .red,
+            confirmTitle: "Retain".localized,
+            confirmColor: .white,
+            cancelAction: { [weak self]  in
+                guard let self = self else { return }
+                self.deleteBlock?()
+                self.navBarClickLeftAction()
+            }
+        ))
     }
 }
 

+ 1 - 2
TSLiveWallpaper/Business/TSAIListVC/TSAIPhotoGeneratorVC/TSAIListPhotoGeneratorVC.swift

@@ -278,8 +278,7 @@ extension TSAIListPhotoGeneratorVC {
     }
     
     func showLoading(){
-        generateInView.updateShowLoading(text: "Processing".localized + " 0%")
-
+        generateInView.updateShowLoading(text: "Processing".localized + " " + kPercentlocalized(0))
     }
     
     func showError(text:String,code:Int = 0){

+ 5 - 10
TSLiveWallpaper/Business/TSBootVC/TSBootVC.swift

@@ -62,8 +62,8 @@ class TSBootVC: TSBaseVC {
         }
     }
     
-    lazy var layout: UICollectionViewFlowLayout = {
-        let layout = UICollectionViewFlowLayout()
+    lazy var layout: TSBaseCollectionViewFlowLayout = {
+        let layout = TSBaseCollectionViewFlowLayout()
         layout.scrollDirection = .horizontal
         layout.itemSize = CGSize(width: k_ScreenWidth, height: k_ScreenHeight)
         layout.minimumInteritemSpacing = 0.0
@@ -73,19 +73,14 @@ class TSBootVC: TSBaseVC {
     }()
     
     lazy var collectionView: UICollectionView = {
-        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
+        let collectionView = TSBaseCollectionView(frame: .zero, collectionViewLayout: layout)
         collectionView.delegate = self
         collectionView.dataSource = self
         collectionView.isScrollEnabled = false
         collectionView.isPagingEnabled = true
-        collectionView.showsVerticalScrollIndicator = false
-        collectionView.showsHorizontalScrollIndicator = false
-        collectionView.backgroundColor = .clear
         collectionView.register(TSBootCell.self, forCellWithReuseIdentifier: "TSBootCell")
         collectionView.register(TSBootBaseCell.self, forCellWithReuseIdentifier: "TSBootBaseCell")
-        if #available(iOS 11.0, *) {
-            collectionView.contentInsetAdjustmentBehavior = .never
-        }
+//        collectionView.transform = kIsRTL ? CGAffineTransform(scaleX: -1, y: 1) : .identity
         return collectionView
     }()
 
@@ -99,7 +94,7 @@ class TSBootVC: TSBaseVC {
     }
     
     override func dealThings() {
-
+        currentIndex = 0
     }
 }
 

+ 1 - 1
TSLiveWallpaper/Business/TSBusinessWebVC/TSBusinessWebVC.swift

@@ -18,7 +18,7 @@ class TSBusinessWebVC: TSBaseVC , WKNavigationDelegate {
             case .privacy:
                 return "Privacy Policy".localized
             case .terms:
-                return "Terms of Service".localized
+                return "User Agreement".localized
             }
         }
     }

+ 19 - 9
TSLiveWallpaper/Business/TSMineVC/TSMineCell.swift

@@ -23,19 +23,21 @@ class TSMineCell: TSSimpleTableViewCell {
         return UIImageView.createRightArrow()
     }()
     
+    
+    lazy var dotView: UIView = {
+        let view = UIView()
+        view.backgroundColor = "#FF2B2B".uiColor
+        view.cornerRadius = 2
+        view.isHidden = true
+        return view
+    }()
+    
     override var itemModel:TSBasicItemModel{
         didSet{
             leftImageView.image = itemModel.leftImage
             leftLab.text = itemModel.leftTitle
             rightLab.text = itemModel.rightString
-            
-            if itemModel.rightIsHave {
-                rightImageView.isHidden = false
-                rightLab.isHidden = true
-            }else{
-                rightImageView.isHidden = true
-                rightLab.isHidden = false
-            }
+            dotView.isHidden = !itemModel.isWhether
         }
     }
     
@@ -45,6 +47,7 @@ class TSMineCell: TSSimpleTableViewCell {
         bgContentView.addSubview(leftLab)
         bgContentView.addSubview(rightLab)
         bgContentView.addSubview(rightImageView)
+        bgContentView.addSubview(dotView)
         
         leftImageView.snp.makeConstraints { make in
             make.leading.equalTo(16)
@@ -58,7 +61,7 @@ class TSMineCell: TSSimpleTableViewCell {
         }
         
         rightLab.snp.makeConstraints { make in
-            make.trailing.equalTo(-16)
+            make.trailing.equalTo(rightImageView.snp.leading).offset(-4)
             make.centerY.equalToSuperview()
         }
         
@@ -67,6 +70,13 @@ class TSMineCell: TSSimpleTableViewCell {
             make.centerY.equalToSuperview()
             make.width.height.equalTo(16)
         }
+        
+        dotView.snp.makeConstraints { make in
+            make.trailing.equalTo(rightLab.snp.leading).offset(-4)
+            make.centerY.equalToSuperview()
+            make.width.height.equalTo(4)
+        }
+        
     }
 
 }

+ 7 - 1
TSLiveWallpaper/Business/TSMineVC/TSMineVC.swift

@@ -43,9 +43,10 @@ class TSMineVC: TSBaseVC {
     }
 
     override func dealThings() {
+        NotificationCenter.default.addObserver(self, selector: #selector(refreshView), name: .kAppUpdateNotification, object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(updateVipView), name: .kPurchaseDidChanged, object: nil)
         updateVipView()
-        
+        refreshView()
     }
     
     @objc func updateVipView() {
@@ -54,4 +55,9 @@ class TSMineVC: TSBaseVC {
             self.simpleTableView.tableView.reloadData()
         }
     }
+    
+    @objc func refreshView() {
+        self.viewModel.updateItem.isWhether = TSAppUpdateManager.isNeedUpdate
+        self.simpleTableView.tableView.reloadData()
+    }
 }

+ 18 - 19
TSLiveWallpaper/Business/TSMineVC/TSMineVM.swift

@@ -103,26 +103,25 @@ class TSMineVM {
                     self.target.navigationController?.pushViewController(vc, animated: true)
                 }))
 
-
-
-        sectionModel.addSubItemModel(
-            createItemModel(
-                leftImage: .mineCellAbout,
-                leftTitle: "About us".localized,
-                rightString: appVersion(),
-                rightIsHave: false,
-                tapBlock: { [weak self] _, _, _ in
-                    guard let self = self else { return }
-                    #if DEBUG
-                        let vc = TSPurchaseVC()
-                        vc.hidesBottomBarWhenPushed = true
-                    kPresentModalVC(target: self.target, modelVC: vc)
-                    #endif
-
-                }))
-
+        sectionModel.addSubItemModel(updateItem)
         return dataArray
-
+    }()
+    
+    
+    lazy var updateItem: TSBasicItemModel = {
+        let itemModel = createItemModel(
+            leftImage: .mineCellUpdate,
+            leftTitle: "Update".localized,
+            rightString: appVersion(),
+            rightIsHave: true,
+            tapBlock: { [weak self] _, _, _ in
+                guard let self = self else { return }
+                if let url = URL(string: "https://apps.apple.com/app/id\(appid)"),
+                    UIApplication.shared.canOpenURL(url) {
+                    UIApplication.shared.open(url)
+                }
+            })
+        return itemModel
     }()
 }
 

+ 6 - 5
TSLiveWallpaper/Business/TSMineVC/View/TSMineTopView.swift

@@ -17,12 +17,12 @@ class TSMineTopView: TSBaseView {
     
  
     lazy var titleLabel: UILabel = {
-        let titleLabel = UILabel.createLabel(text: "Update to PRO", font: .font(name: .ZillaSlabBoldItalic,size: 24,weight: .bold), textColor: .mainText)
+        let titleLabel = UILabel.createLabel(text: "Update to PRO".localized, font: .font(name: .ZillaSlabBoldItalic,size: 24,weight: .bold), textColor: .mainText)
         return titleLabel
     }()
     
     lazy var timeLabel: UILabel = {
-        let timeLabel = UILabel.createLabel(text: "Limited Time Discount", font: .font(name: .ZillaSlab,size: 14), textColor: .lesserText)
+        let timeLabel = UILabel.createLabel(text: "Limited Time Discount".localized, font: .font(name: .ZillaSlab,size: 14), textColor: .lesserText)
         return timeLabel
     }()
 
@@ -31,6 +31,7 @@ class TSMineTopView: TSBaseView {
             guard let self = self else { return }
             clickView()
         }
+        upgradeBtn.setTitleImageSpace(spacing: 0)
         return upgradeBtn
     }()
     
@@ -89,7 +90,7 @@ class TSMineTopView: TSBaseView {
     }()
     
     lazy var vipTimeLabel: UILabel = {
-        let timeLabel = UILabel.createLabel(text: "Limited Time Discount", font: .font(size: 14), textColor: .lesserText)
+        let timeLabel = UILabel.createLabel(text: "Limited Time Discount".localized, font: .font(size: 14), textColor: .lesserText)
         return timeLabel
     }()
     
@@ -154,12 +155,12 @@ class TSMineTopView: TSBaseView {
             self.height = 120 + 16
             noVipView.isHidden = true
             vipView.isHidden = false
-            vipTimeLabel.text = "Due Date: \(PurchaseManager.default.expiredDateString)"
+            vipTimeLabel.text = "Due Date:".localized + "\(PurchaseManager.default.expiredDateString)"
         } else {
             self.height = 134 + 16
             noVipView.isHidden = false
             vipView.isHidden = true
-            saveView.setTitle("Save" + " " + PurchaseManager.default.vipType.saveString, for: .normal)
+            saveView.setTitle("Save-Vip".localized + " " + PurchaseManager.default.vipType.saveString, for: .normal)
         }
     }
 }

+ 31 - 30
TSLiveWallpaper/Business/TSPurchaseMembershipVC/TSPurchaseVC.swift

@@ -245,28 +245,28 @@ struct PurchaseView :View {
             }
             
             Spacer().frame(height: 20)
- 
+            
             
             VStack(spacing: 16) {
                 
                 //                if vipType == .none {
-                                    ZStack(alignment: .topTrailing) {
-                //                    //增加月付费
-                //                        PurchaseItemView(title: "One Month".localized, type: .month, selectedType: $viewModel.selectedType).onTapGesture {
-                //                            viewModel.selectedType = .month
-                                        PurchaseItemView(title: "YEARLY".localized, type: .year, selectedType: $viewModel.selectedType).onTapGesture {
-                                            viewModel.selectedType = .year
-                                            viewModel.buyPublisher.send(true)
-                                        }
-                                        TSVipRecView(save: vipType.saveString)
-                                            .offset(x:-30,y:-14)
-                                    }
-                                    
-                                PurchaseItemView(title: "WEEKLY".localized, type: .week, selectedType: $viewModel.selectedType).onTapGesture {
-                                    viewModel.selectedType = .week
-                                        viewModel.buyPublisher.send(true)
-                                    }
-                                    
+                ZStack(alignment: .topTrailing) {
+                    //                    //增加月付费
+                    //                        PurchaseItemView(title: "One Month".localized, type: .month, selectedType: $viewModel.selectedType).onTapGesture {
+                    //                            viewModel.selectedType = .month
+                    PurchaseItemView(title: "Yearly".localized, type: .year, selectedType: $viewModel.selectedType).onTapGesture {
+                        viewModel.selectedType = .year
+                        viewModel.buyPublisher.send(true)
+                    }
+                    TSVipRecView(save: vipType.saveString)
+                        .offset(x:-30,y:-14)
+                }
+                
+                PurchaseItemView(title: "Weekly".localized, type: .week, selectedType: $viewModel.selectedType).onTapGesture {
+                    viewModel.selectedType = .week
+                    viewModel.buyPublisher.send(true)
+                }
+                
                 //                }else{
                 //                    PurchaseItemTypeOneView(title: "One Year".localized, type: .year, selectedType: $viewModel.selectedType).onTapGesture {
                 //                        viewModel.selectedType = .year
@@ -284,37 +284,38 @@ struct PurchaseView :View {
                 } label: {
                     ZStack {
                         Image("submit_btn_bg").resizable().aspectRatio(contentMode: .fill)
-                        Text("Continue")
+                        Text("Continue".localized)
                             .font(.system(size: 16))
                             .foregroundColor(.hex("#111111"))
-                            
+                        
                     }.frame(maxWidth: .infinity ,maxHeight: 48.0)
                         .cornerRadius(0.0)
                 }
-            
+                
                 HStack {
-                    Text("Recurring billing, cancel anytime")
+                    Text("Recurring billing,cancel anytime.".localized)
                         .foregroundColor(UIColor.themeColor.color) +
-                        Text(", Payment will be charged to your iTunes account at confirmation of purchase. Subscriptions automatically renew for the same applicable term and price, unless auto-renew is turned off at least 24 hours before the end of the current period.")
+                    Text("Payment will be charged to your iTunes account at confirmation of purchase. Subscriptions automatically renew for the same applicable term and price, unless auto-renew is turned off at least 24 hours before the end of the current period.".localized)
                         .foregroundColor(UIColor.lesserText.color)
                 }
-                .multilineTextAlignment(.center).font(.font(size: 8))
+                .multilineTextAlignment(.center)
+                .font(.font(size: 8))
                 .onTapGesture {
                     viewModel.privacyPublisher.send(true)
                 }
-
+                
                 HStack(spacing: 8) {
-                    Text("Term of us")
+                    Text("Terms of us".localized)
                         .onTapGesture {
                             viewModel.termPublisher.send(true)
                         }
                     Text("|")
-                    Text("Privacy Policy")
+                    Text("Privacy Policy".localized)
                         .onTapGesture {
                             viewModel.privacyPublisher.send(true)
                         }
                     Text("|")
-                    Text("Restore")
+                    Text("Restore".localized)
                         .onTapGesture {
                             viewModel.restorePublisher.send(true)
                         }
@@ -322,7 +323,7 @@ struct PurchaseView :View {
             }.padding(.horizontal)
             
             Spacer().frame(height:9+k_Height_safeAreaInsetsBottom())
-        }
+        }.environment(\.layoutDirection, kIsRTL ? .rightToLeft : .leftToRight)
     }
 }
 
@@ -358,7 +359,7 @@ struct PurchaseItemView: View {
                 //右边每周的💰
                 VStack(alignment: .trailing, spacing: 2) {
                     Text("\(PurchaseManager.default.averageWeekly(for:type) ?? "--")")
-                    Text("Per week".localized)
+                    Text("per week".localized)
 
                 }.font(.font(size: 16,weight: .regular)).foregroundColor(Color.white.opacity(0.6))
 

+ 75 - 20
TSLiveWallpaper/Business/TSTabBarController/TSTabBarController.swift

@@ -32,9 +32,21 @@ class TSTabBarController: UITabBarController {
         delegate = self
         setUpData()
         createUI()
-      
+        monitorEvent()
     }
 
+    let dotSize:CGFloat = 6.0
+    lazy var appUpdateDotView: UIView = {
+        let bgView = UIView(frame: CGRect(x: 0, y: 0, width: dotSize, height: dotSize))
+        let view = UIView()
+        let backgroundColor = "#FF2B2B".uiColor
+        view.backgroundColor = backgroundColor
+        view.cornerRadius = dotSize/2.0
+        view.addShadow(shadowColor: backgroundColor.cgColor, shadowOffset: CGSizeMake(0, 0), shadowRadius: 4, shadowOpacity: 0.4)
+        bgView.addSubview(view)
+        return view
+    }()
+    
     @objc private func setUpData() {
         viewControllerArray = [
             "TSAIListVC",
@@ -89,12 +101,20 @@ class TSTabBarController: UITabBarController {
         tabBar.addSubview(markView)
         markView.snp.makeConstraints { make in
             make.bottom.equalTo(-k_Height_safeAreaInsetsBottom())
-            make.left.equalTo(0)
+            make.leading.equalTo(0)
             make.width.equalTo(markWidth)
             make.height.equalTo(2)
         }
     }
-
+    
+    func monitorEvent(){
+        refreshView()
+        NotificationCenter.default.addObserver(self, selector: #selector(refreshView), name: .kAppUpdateNotification, object: nil)
+    }
+    
+    @objc func refreshView() {
+        showRedDotOnLastItem(show: TSAppUpdateManager.tabbarDotShow == 1)
+    }
     deinit {
         debugPrint("TSTabBarController deinit")
         NotificationCenter.default.removeObserver(self)
@@ -102,36 +122,71 @@ class TSTabBarController: UITabBarController {
 
 }
 extension TSTabBarController {
-    
-    func changeSelectedIndex(index:Int){
-        self.selectedIndex = index
-        updateMarkViewFrame()
-    }
-    
-    func updateMarkViewFrame() {
-        markView.snp.updateConstraints { make in
-            make.left.equalTo(CGFloat(selectedIndex) * markWidth)
-        }
-    }
-    
-    
     private func tabBarItem(title: String, image: UIImage?, selectedImage: UIImage?, tag: Int) -> UITabBarItem {
         let tabBarItem = UITabBarItem()
-        tabBarItem.image = image?.withRenderingMode(.alwaysOriginal)
-        tabBarItem.selectedImage = selectedImage?.withRenderingMode(.alwaysOriginal)
+        tabBarItem.image = image?.withRenderingMode(.alwaysOriginal).mirrored
+        tabBarItem.selectedImage = selectedImage?.withRenderingMode(.alwaysOriginal).mirrored
         tabBarItem.imageInsets = UIEdgeInsets(top: 0, left: 0, bottom: -8, right: 0) // 向下移动图标
         return tabBarItem
     }
-
 }
 extension TSTabBarController: UITabBarControllerDelegate {
     func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
         updateMarkViewFrame()
+        
+        if let viewControllers = viewControllers {
+            if selectedIndex == viewControllers.count-1 {
+                TSAppUpdateManager.tabbarDotShow = 2
+                showRedDotOnLastItem(show: false)
+            }
+        }
     }
 }
 
+extension TSTabBarController {
+    func showRedDotOnLastItem(show: Bool) {
+        guard let items = tabBar.items, !items.isEmpty else { return }
+        if show {
+            addRedDotToLastTab()
+        } else {
+            appUpdateDotView.isHidden = true
+        }
+    }
+    
+    func addRedDotToLastTab() {
+        guard let items = tabBar.items,
+              !items.isEmpty else { return }
+        
+        if appUpdateDotView.superview != nil {
+            appUpdateDotView.isHidden = false
+            return
+        }
+        
+        let lastItemIndex = items.count - 1
+        let itemWidth = tabBar.frame.width / CGFloat(items.count)
+        let xPosition = itemWidth * CGFloat(lastItemIndex) + itemWidth/2 + (dotSize * 2) + 2
+        let yPosition: CGFloat = 10
+        tabBar.addSubview(appUpdateDotView)
+        appUpdateDotView.snp.makeConstraints { make in
+            make.width.height.equalTo(dotSize)
+            make.leading.equalTo(xPosition)
+            make.top.equalTo(yPosition)
+        }
+    }
+    
+    func changeSelectedIndex(index:Int){
+        self.selectedIndex = index
+        updateMarkViewFrame()
+    }
+    
+    func updateMarkViewFrame() {
+        markView.snp.updateConstraints { make in
+            make.leading.equalTo(CGFloat(selectedIndex) * markWidth)
+        }
+    }
+    
+}
 
-// MARK: 进到首页后需要做的处理
 
 extension TSTabBarController {
     /// 暂时没用,后续迭代

+ 1 - 1
TSLiveWallpaper/Common/Ex/UICollectionView+Ex.swift

@@ -21,7 +21,7 @@ extension UICollectionView {
         let layout = UICollectionViewFlowLayout()
         layout.scrollDirection = .vertical
         
-        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
+        let collectionView = TSBaseCollectionView(frame: .zero, collectionViewLayout: layout)
         collectionView.delegate = delegate
         collectionView.dataSource = delegate
         collectionView.showsVerticalScrollIndicator = false

+ 3 - 3
TSLiveWallpaper/Common/Purchase/TSPurchaseEnum.swift

@@ -28,13 +28,13 @@ public enum PremiumPeriod: String, CaseIterable {
             return 30
         }
     }
-
+    
     var saveString: String {
         switch self {
         case .none:
-            return "60%"
+            return kPercentlocalized(90)
         default:
-            return "60%"
+            return kPercentlocalized(90)
         }
     }
     

+ 5 - 5
TSLiveWallpaper/Common/Purchase/TSPurchaseManager.swift

@@ -75,9 +75,9 @@ public class PurchaseManager: NSObject {
     }
 
     @objc public var isVip: Bool {
-//        #if DEBUG
-//        return true
-//        #endif
+        #if DEBUG
+        return true
+        #endif
         guard let expiresDate = expiredDate else {
             return false
         }
@@ -329,10 +329,10 @@ extension PurchaseManager: SKPaymentTransactionObserver {
                     }
                 }
                 
-                var message = "Payment Failed"
+                var message = "Payment Failed".localized
                 if let error = transaction.error as? SKError{
                     if error.code == SKError.paymentCancelled {
-                        message = "The subscription was canceled"
+                        message = "The subscription was canceled".localized
                     }
                 }
                 purchase(self, didChaged: .payFail, object: message)

+ 2 - 2
TSLiveWallpaper/Common/TSNetWork/TSNetWork+Business.swift

@@ -20,8 +20,8 @@ enum TSNeURLType:String {
 //    case imageToImageStyle = "/api/ops/aichat-img2img-config"     //图生图 风格列表
 //    case chatV2 = "/api/text/chat/v2"             //AI 对话接口V2,扩展了 DeepSeek 深度思考
 //    
-//    case config = "/api/ops/aichat-config"       //App配置
-//    
+    case config = "/api/ops/old-photo-config"       //App配置
+//
 //    case changeAge = "/api/image/change-age"       //换年龄
 //    case subscriptionApple = "/api/subscription/apple"       //苹果订阅
 //    case changeEmotion = "/api/image/change-emotion"       //更换表情

+ 74 - 0
TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYCyclePagerTransformLayout.h

@@ -0,0 +1,74 @@
+//
+//  TYCyclePagerViewLayout.h
+//  TYCyclePagerViewDemo
+//
+//  Created by tany on 2017/6/19.
+//  Copyright © 2017年 tany. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef NS_ENUM(NSUInteger, TYCyclePagerTransformLayoutType) {
+    TYCyclePagerTransformLayoutNormal,
+    TYCyclePagerTransformLayoutLinear,
+    TYCyclePagerTransformLayoutCoverflow,
+};
+
+@class TYCyclePagerTransformLayout;
+@protocol TYCyclePagerTransformLayoutDelegate <NSObject>
+
+// initialize layout attributes
+- (void)pagerViewTransformLayout:(TYCyclePagerTransformLayout *)pagerViewTransformLayout initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes;
+
+// apply layout attributes
+- (void)pagerViewTransformLayout:(TYCyclePagerTransformLayout *)pagerViewTransformLayout applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes;
+
+@end
+
+
+@interface TYCyclePagerViewLayout : NSObject
+
+@property (nonatomic, assign) CGSize itemSize;
+@property (nonatomic, assign) CGFloat itemSpacing;
+@property (nonatomic, assign) UIEdgeInsets sectionInset;
+
+@property (nonatomic, assign) TYCyclePagerTransformLayoutType layoutType;
+
+@property (nonatomic, assign) CGFloat minimumScale; // sacle default 0.8
+@property (nonatomic, assign) CGFloat minimumAlpha; // alpha default 1.0
+@property (nonatomic, assign) CGFloat maximumAngle; // angle is % default 0.2
+
+@property (nonatomic, assign) BOOL isInfiniteLoop;  // infinte scroll
+@property (nonatomic, assign) CGFloat rateOfChange; // scale and angle change rate
+@property (nonatomic, assign) BOOL adjustSpacingWhenScroling; 
+
+/**
+ pageView cell item vertical centering
+ */
+@property (nonatomic, assign) BOOL itemVerticalCenter;
+
+/**
+ first and last item horizontalc enter, when isInfiniteLoop is NO
+ */
+@property (nonatomic, assign) BOOL itemHorizontalCenter;
+
+// sectionInset
+@property (nonatomic, assign, readonly) UIEdgeInsets onlyOneSectionInset;
+@property (nonatomic, assign, readonly) UIEdgeInsets firstSectionInset;
+@property (nonatomic, assign, readonly) UIEdgeInsets lastSectionInset;
+@property (nonatomic, assign, readonly) UIEdgeInsets middleSectionInset;
+
+@end
+
+
+@interface TYCyclePagerTransformLayout : UICollectionViewFlowLayout
+
+@property (nonatomic, strong) TYCyclePagerViewLayout *layout;
+
+@property (nonatomic, weak, nullable) id<TYCyclePagerTransformLayoutDelegate> delegate;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 319 - 0
TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYCyclePagerTransformLayout.m

@@ -0,0 +1,319 @@
+//
+//  TYCyclePagerViewLayout.m
+//  TYCyclePagerViewDemo
+//
+//  Created by tany on 2017/6/19.
+//  Copyright © 2017年 tany. All rights reserved.
+//
+
+#import "TYCyclePagerTransformLayout.h"
+#import "TSLiveWallpaper-Swift.h"
+typedef NS_ENUM(NSUInteger, TYTransformLayoutItemDirection) {
+    TYTransformLayoutItemLeft,
+    TYTransformLayoutItemCenter,
+    TYTransformLayoutItemRight,
+};
+
+
+@interface TYCyclePagerTransformLayout () {
+    struct {
+        unsigned int applyTransformToAttributes   :1;
+        unsigned int initializeTransformAttributes   :1;
+    }_delegateFlags;
+}
+
+@property (nonatomic, assign) BOOL applyTransformToAttributesDelegate;
+
+@end
+
+
+@interface TYCyclePagerViewLayout ()
+
+@property (nonatomic, weak) UIView *pageView;
+
+@end
+
+
+@implementation TYCyclePagerTransformLayout
+
+
++ (NSString *)appLanguage {
+    id systemLanguages = [[NSUserDefaults standardUserDefaults] valueForKey:@"AppleLanguages"];
+    NSString *currentLanguage = nil;
+    
+    if ([systemLanguages isKindOfClass:[NSArray class]]) {
+        currentLanguage = [systemLanguages firstObject];
+    }
+    else if ([systemLanguages isKindOfClass:[NSString class]]) {
+        currentLanguage = systemLanguages;
+    }
+    
+    return currentLanguage ?: @"";
+}
+
+- (BOOL)flipsHorizontallyInOppositeLayoutDirection {
+    return [[TYCyclePagerTransformLayout appLanguage] compare:@"ar"];
+}
+
+- (instancetype)init {
+    if (self = [super init]) {
+        self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
+    }
+    return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder {
+    if (self = [super initWithCoder:aDecoder]) {
+        self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
+    }
+    return self;
+}
+
+#pragma mark - getter setter
+
+- (void)setDelegate:(id<TYCyclePagerTransformLayoutDelegate>)delegate {
+    _delegate = delegate;
+    _delegateFlags.initializeTransformAttributes = [delegate respondsToSelector:@selector(pagerViewTransformLayout:initializeTransformAttributes:)];
+    _delegateFlags.applyTransformToAttributes = [delegate respondsToSelector:@selector(pagerViewTransformLayout:applyTransformToAttributes:)];
+}
+
+- (void)setLayout:(TYCyclePagerViewLayout *)layout {
+    _layout = layout;
+    _layout.pageView = self.collectionView;
+    self.itemSize = _layout.itemSize;
+    self.minimumInteritemSpacing = _layout.itemSpacing;
+    self.minimumLineSpacing = _layout.itemSpacing;
+}
+
+- (CGSize)itemSize {
+    if (!_layout) {
+        return [super itemSize];
+    }
+    return _layout.itemSize;
+}
+
+- (CGFloat)minimumLineSpacing {
+    if (!_layout) {
+        return [super minimumLineSpacing];
+    }
+    return _layout.itemSpacing;
+}
+
+- (CGFloat)minimumInteritemSpacing {
+    if (!_layout) {
+        return [super minimumInteritemSpacing];
+    }
+    return _layout.itemSpacing;
+}
+
+- (TYTransformLayoutItemDirection)directionWithCenterX:(CGFloat)centerX {
+    TYTransformLayoutItemDirection direction= TYTransformLayoutItemRight;
+    CGFloat contentCenterX = self.collectionView.contentOffset.x + CGRectGetWidth(self.collectionView.frame)/2;
+    if (ABS(centerX - contentCenterX) < 0.5) {
+        direction = TYTransformLayoutItemCenter;
+    }else if (centerX - contentCenterX < 0) {
+        direction = TYTransformLayoutItemLeft;
+    }
+    return direction;
+}
+
+#pragma mark - layout
+
+-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
+{
+    return _layout.layoutType == TYCyclePagerTransformLayoutNormal ? [super shouldInvalidateLayoutForBoundsChange:newBounds] : YES;
+}
+
+- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
+    if (_delegateFlags.applyTransformToAttributes || _layout.layoutType != TYCyclePagerTransformLayoutNormal) {
+        NSArray *attributesArray = [[NSArray alloc] initWithArray:[super layoutAttributesForElementsInRect:rect] copyItems:YES];
+        CGRect visibleRect = {self.collectionView.contentOffset,self.collectionView.bounds.size};
+        for (UICollectionViewLayoutAttributes *attributes in attributesArray) {
+            if (!CGRectIntersectsRect(visibleRect, attributes.frame)) {
+                continue;
+            }
+            if (_delegateFlags.applyTransformToAttributes) {
+                [_delegate pagerViewTransformLayout:self applyTransformToAttributes:attributes];
+            }else {
+                [self applyTransformToAttributes:attributes layoutType:_layout.layoutType];
+            }
+        }
+        return attributesArray;
+    }
+    return [super layoutAttributesForElementsInRect:rect];
+}
+
+- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
+    UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForItemAtIndexPath:indexPath];
+    if (_delegateFlags.initializeTransformAttributes) {
+        [_delegate pagerViewTransformLayout:self initializeTransformAttributes:attributes];
+    }else if(_layout.layoutType != TYCyclePagerTransformLayoutNormal){
+        [self initializeTransformAttributes:attributes layoutType:_layout.layoutType];
+    }
+    return attributes;
+}
+
+#pragma mark - transform
+
+- (void)initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes layoutType:(TYCyclePagerTransformLayoutType)layoutType {
+    switch (layoutType) {
+        case TYCyclePagerTransformLayoutLinear:
+            [self applyLinearTransformToAttributes:attributes scale:_layout.minimumScale alpha:_layout.minimumAlpha];
+            break;
+        case TYCyclePagerTransformLayoutCoverflow:
+        {
+            [self applyCoverflowTransformToAttributes:attributes angle:_layout.maximumAngle alpha:_layout.minimumAlpha];
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+- (void)applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes layoutType:(TYCyclePagerTransformLayoutType)layoutType {
+    switch (layoutType) {
+        case TYCyclePagerTransformLayoutLinear:
+            [self applyLinearTransformToAttributes:attributes];
+            break;
+        case TYCyclePagerTransformLayoutCoverflow:
+            [self applyCoverflowTransformToAttributes:attributes];
+            break;
+        default:
+            break;
+    }
+}
+
+#pragma mark - LinearTransform
+
+- (void)applyLinearTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes {
+    CGFloat collectionViewWidth = self.collectionView.frame.size.width;
+    if (collectionViewWidth <= 0) {
+        return;
+    }
+    CGFloat centetX = self.collectionView.contentOffset.x + collectionViewWidth/2;
+    CGFloat delta = ABS(attributes.center.x - centetX);
+    CGFloat scale = MAX(1 - delta/collectionViewWidth*_layout.rateOfChange, _layout.minimumScale);
+    CGFloat alpha = MAX(1 - delta/collectionViewWidth, _layout.minimumAlpha);
+    [self applyLinearTransformToAttributes:attributes scale:scale alpha:alpha];
+}
+
+- (void)applyLinearTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes scale:(CGFloat)scale alpha:(CGFloat)alpha {
+    CGAffineTransform transform = CGAffineTransformMakeScale(scale, scale);
+    if (_layout.adjustSpacingWhenScroling) {
+        TYTransformLayoutItemDirection direction = [self directionWithCenterX:attributes.center.x];
+        CGFloat translate = 0;
+        switch (direction) {
+            case TYTransformLayoutItemLeft:
+                translate = 1.15 * attributes.size.width*(1-scale)/2;
+                break;
+            case TYTransformLayoutItemRight:
+                translate = -1.15 * attributes.size.width*(1-scale)/2;
+                break;
+            default:
+                // center
+                scale = 1.0;
+                alpha = 1.0;
+                break;
+        }
+        transform = CGAffineTransformTranslate(transform,translate, 0);
+    }
+    attributes.transform = transform;
+    attributes.alpha = alpha;
+}
+
+#pragma mark - CoverflowTransform
+
+- (void)applyCoverflowTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes{
+    CGFloat collectionViewWidth = self.collectionView.frame.size.width;
+    if (collectionViewWidth <= 0) {
+        return;
+    }
+    CGFloat centetX = self.collectionView.contentOffset.x + collectionViewWidth/2;
+    CGFloat delta = ABS(attributes.center.x - centetX);
+    CGFloat angle = MIN(delta/collectionViewWidth*(1-_layout.rateOfChange), _layout.maximumAngle);
+    CGFloat alpha = MAX(1 - delta/collectionViewWidth, _layout.minimumAlpha);
+    [self applyCoverflowTransformToAttributes:attributes angle:angle alpha:alpha];
+}
+
+- (void)applyCoverflowTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes angle:(CGFloat)angle alpha:(CGFloat)alpha {
+    TYTransformLayoutItemDirection direction = [self directionWithCenterX:attributes.center.x];
+    CATransform3D transform3D = CATransform3DIdentity;
+    transform3D.m34 = -0.002;
+    CGFloat translate = 0;
+    switch (direction) {
+        case TYTransformLayoutItemLeft:
+            translate = (1-cos(angle*1.2*M_PI))*attributes.size.width;
+            break;
+        case TYTransformLayoutItemRight:
+            translate = -(1-cos(angle*1.2*M_PI))*attributes.size.width;
+            angle = -angle;
+            break;
+        default:
+            // center
+            angle = 0;
+            alpha = 1;
+            break;
+    }
+
+    transform3D = CATransform3DRotate(transform3D, M_PI*angle, 0, 1, 0);
+    if (_layout.adjustSpacingWhenScroling) {
+        transform3D = CATransform3DTranslate(transform3D, translate, 0, 0);
+    }
+    attributes.transform3D = transform3D;
+    attributes.alpha = alpha;
+
+}
+@end
+
+
+@implementation TYCyclePagerViewLayout
+
+- (instancetype)init {
+    if (self = [super init]) {
+        _itemVerticalCenter = YES;
+        _minimumScale = 0.8;
+        _minimumAlpha = 1.0;
+        _maximumAngle = 0.2;
+        _rateOfChange = 0.4;
+        _adjustSpacingWhenScroling = YES;
+    }
+    return self;
+}
+
+#pragma mark - getter
+
+- (UIEdgeInsets)onlyOneSectionInset {
+    CGFloat leftSpace = _pageView && !_isInfiniteLoop && _itemHorizontalCenter ? (CGRectGetWidth(_pageView.frame) - _itemSize.width)/2 : _sectionInset.left;
+    CGFloat rightSpace = _pageView && !_isInfiniteLoop && _itemHorizontalCenter ? (CGRectGetWidth(_pageView.frame) - _itemSize.width)/2 : _sectionInset.right;
+    if (_itemVerticalCenter) {
+        CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2;
+        return UIEdgeInsetsMake(verticalSpace, leftSpace, verticalSpace, rightSpace);
+    }
+    return UIEdgeInsetsMake(_sectionInset.top, leftSpace, _sectionInset.bottom, rightSpace);
+}
+
+- (UIEdgeInsets)firstSectionInset {
+    if (_itemVerticalCenter) {
+        CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2;
+        return UIEdgeInsetsMake(verticalSpace, _sectionInset.left, verticalSpace, _itemSpacing);
+    }
+    return UIEdgeInsetsMake(_sectionInset.top, _sectionInset.left, _sectionInset.bottom, _itemSpacing);
+}
+
+- (UIEdgeInsets)lastSectionInset {
+    if (_itemVerticalCenter) {
+        CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2;
+        return UIEdgeInsetsMake(verticalSpace, 0, verticalSpace, _sectionInset.right);
+    }
+    return UIEdgeInsetsMake(_sectionInset.top, 0, _sectionInset.bottom, _sectionInset.right);
+}
+
+- (UIEdgeInsets)middleSectionInset {
+    if (_itemVerticalCenter) {
+        CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2;
+        return UIEdgeInsetsMake(verticalSpace, 0, verticalSpace, _itemSpacing);
+    }
+    return _sectionInset;
+}
+
+@end

+ 180 - 0
TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYCyclePagerView.h

@@ -0,0 +1,180 @@
+//
+//  TYCyclePagerView.h
+//  TYCyclePagerViewDemo
+//
+//  Created by tany on 2017/6/14.
+//  Copyright © 2017年 tany. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "TYCyclePagerTransformLayout.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef struct {
+    NSInteger index;
+    NSInteger section;
+}TYIndexSection;
+
+// pagerView scrolling direction
+typedef NS_ENUM(NSUInteger, TYPagerScrollDirection) {
+    TYPagerScrollDirectionLeft,
+    TYPagerScrollDirectionRight,
+};
+
+@class TYCyclePagerView;
+@protocol TYCyclePagerViewDataSource <NSObject>
+
+- (NSInteger)numberOfItemsInPagerView:(TYCyclePagerView *)pageView;
+
+- (__kindof UICollectionViewCell *)pagerView:(TYCyclePagerView *)pagerView cellForItemAtIndex:(NSInteger)index;
+
+/**
+ return pagerView layout,and cache layout
+ */
+- (TYCyclePagerViewLayout *)layoutForPagerView:(TYCyclePagerView *)pageView;
+
+@end
+
+@protocol TYCyclePagerViewDelegate <NSObject>
+
+@optional
+
+/**
+ pagerView did scroll to new index page
+ */
+- (void)pagerView:(TYCyclePagerView *)pageView didScrollFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex;
+
+/**
+ pagerView did selected item cell
+ */
+- (void)pagerView:(TYCyclePagerView *)pageView didSelectedItemCell:(__kindof UICollectionViewCell *)cell atIndex:(NSInteger)index;
+- (void)pagerView:(TYCyclePagerView *)pageView didSelectedItemCell:(__kindof UICollectionViewCell *)cell atIndexSection:(TYIndexSection)indexSection;
+
+// custom layout
+- (void)pagerView:(TYCyclePagerView *)pageView initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes;
+
+- (void)pagerView:(TYCyclePagerView *)pageView applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes;
+
+
+// scrollViewDelegate
+
+- (void)pagerViewDidScroll:(TYCyclePagerView *)pageView;
+
+- (void)pagerViewWillBeginDragging:(TYCyclePagerView *)pageView;
+
+- (void)pagerViewDidEndDragging:(TYCyclePagerView *)pageView willDecelerate:(BOOL)decelerate;
+
+- (void)pagerViewWillBeginDecelerating:(TYCyclePagerView *)pageView;
+
+- (void)pagerViewDidEndDecelerating:(TYCyclePagerView *)pageView;
+
+- (void)pagerViewWillBeginScrollingAnimation:(TYCyclePagerView *)pageView;
+
+- (void)pagerViewDidEndScrollingAnimation:(TYCyclePagerView *)pageView;
+
+@end
+
+
+@interface TYCyclePagerView : UIView
+
+// will be automatically resized to track the size of the pagerView
+@property (nonatomic, strong, nullable) UIView *backgroundView; 
+
+@property (nonatomic, weak, nullable) id<TYCyclePagerViewDataSource> dataSource;
+@property (nonatomic, weak, nullable) id<TYCyclePagerViewDelegate> delegate;
+
+// pager view, don't set dataSource and delegate
+@property (nonatomic, weak, readonly) UICollectionView *collectionView;
+// pager view layout
+@property (nonatomic, strong, readonly) TYCyclePagerViewLayout *layout;
+
+/**
+ is infinite cycle pageview
+ */
+@property (nonatomic, assign) BOOL isInfiniteLoop;
+
+/**
+ pagerView automatic scroll time interval, default 0,disable automatic
+ */
+@property (nonatomic, assign) CGFloat autoScrollInterval;
+
+@property (nonatomic, assign) BOOL reloadDataNeedResetIndex;
+
+/**
+ current page index
+ */
+@property (nonatomic, assign, readonly) NSInteger curIndex;
+@property (nonatomic, assign, readonly) TYIndexSection indexSection;
+
+// scrollView property
+@property (nonatomic, assign, readonly) CGPoint contentOffset;
+@property (nonatomic, assign, readonly) BOOL tracking;
+@property (nonatomic, assign, readonly) BOOL dragging;
+@property (nonatomic, assign, readonly) BOOL decelerating;
+
+
+/**
+ reload data, !!important!!: will clear layout and call delegate layoutForPagerView
+ */
+- (void)reloadData;
+
+/**
+ update data is reload data, but not clear layuot
+ */
+- (void)updateData;
+
+/**
+ if you only want update layout
+ */
+- (void)setNeedUpdateLayout;
+
+/**
+ will set layout nil and call delegate->layoutForPagerView
+ */
+- (void)setNeedClearLayout;
+
+/**
+ current index cell in pagerView
+ */
+- (__kindof UICollectionViewCell * _Nullable)curIndexCell;
+
+/**
+ visible cells in pageView
+ */
+- (NSArray<__kindof UICollectionViewCell *> *_Nullable)visibleCells;
+
+
+/**
+ visible pageView indexs, maybe repeat index
+ */
+- (NSArray *)visibleIndexs;
+
+/**
+ scroll to item at index
+ */
+- (void)scrollToItemAtIndex:(NSInteger)index animate:(BOOL)animate;
+- (void)scrollToItemAtIndexSection:(TYIndexSection)indexSection animate:(BOOL)animate;
+/**
+ scroll to next or pre item
+ */
+- (void)scrollToNearlyIndexAtDirection:(TYPagerScrollDirection)direction animate:(BOOL)animate;
+
+/**
+ register pager view cell with class
+ */
+- (void)registerClass:(Class)Class forCellWithReuseIdentifier:(NSString *)identifier;
+
+/**
+ register pager view cell with nib
+ */
+- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier;
+
+/**
+ dequeue reusable cell for pagerView
+ */
+- (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 607 - 0
TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYCyclePagerView.m

@@ -0,0 +1,607 @@
+//
+//  TYCyclePagerView.m
+//  TYCyclePagerViewDemo
+//
+//  Created by tany on 2017/6/14.
+//  Copyright © 2017年 tany. All rights reserved.
+//
+
+#import "TYCyclePagerView.h"
+
+NS_INLINE BOOL TYEqualIndexSection(TYIndexSection indexSection1,TYIndexSection indexSection2) {
+    return indexSection1.index == indexSection2.index && indexSection1.section == indexSection2.section;
+}
+
+NS_INLINE TYIndexSection TYMakeIndexSection(NSInteger index, NSInteger section) {
+    TYIndexSection indexSection;
+    indexSection.index = index;
+    indexSection.section = section;
+    return indexSection;
+}
+
+@interface TYCyclePagerView () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, TYCyclePagerTransformLayoutDelegate> {
+    struct {
+        unsigned int pagerViewDidScroll   :1;
+        unsigned int didScrollFromIndexToNewIndex   :1;
+        unsigned int initializeTransformAttributes   :1;
+        unsigned int applyTransformToAttributes   :1;
+    }_delegateFlags;
+    struct {
+        unsigned int cellForItemAtIndex   :1;
+        unsigned int layoutForPagerView   :1;
+    }_dataSourceFlags;
+}
+
+// UI
+@property (nonatomic, weak) UICollectionView *collectionView;
+@property (nonatomic, strong) TYCyclePagerViewLayout *layout;
+@property (nonatomic, strong) NSTimer *timer;
+
+// Data
+@property (nonatomic, assign) NSInteger numberOfItems;
+
+@property (nonatomic, assign) NSInteger dequeueSection;
+@property (nonatomic, assign) TYIndexSection beginDragIndexSection;
+@property (nonatomic, assign) NSInteger firstScrollIndex;
+
+@property (nonatomic, assign) BOOL needClearLayout;
+@property (nonatomic, assign) BOOL didReloadData;
+@property (nonatomic, assign) BOOL didLayout;
+@property (nonatomic, assign) BOOL needResetIndex;
+
+@end
+
+#define kPagerViewMaxSectionCount 200
+#define kPagerViewMinSectionCount 18
+
+@implementation TYCyclePagerView
+
+#pragma mark - life Cycle
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    if (self = [super initWithFrame:frame]) {
+        [self configureProperty];
+        
+        [self addCollectionView];
+    }
+    return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder {
+    if (self = [super initWithCoder:aDecoder]) {
+        [self configureProperty];
+        
+        [self addCollectionView];
+    }
+    return self;
+}
+
+- (void)configureProperty {
+    _needResetIndex = NO;
+    _didReloadData = NO;
+    _didLayout = NO;
+    _autoScrollInterval = 0;
+    _isInfiniteLoop = YES;
+    _beginDragIndexSection.index = 0;
+    _beginDragIndexSection.section = 0;
+    _indexSection.index = -1;
+    _indexSection.section = -1;
+    _firstScrollIndex = -1;
+}
+
+- (void)addCollectionView {
+    TYCyclePagerTransformLayout *layout = [[TYCyclePagerTransformLayout alloc]init];
+    UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:layout];
+    layout.delegate = _delegateFlags.applyTransformToAttributes ? self : nil;;
+    collectionView.backgroundColor = [UIColor clearColor];
+    collectionView.dataSource = self;
+    collectionView.delegate = self;
+    collectionView.pagingEnabled = NO;
+    collectionView.decelerationRate = 1-0.0076;
+    if ([collectionView respondsToSelector:@selector(setPrefetchingEnabled:)]) {
+        collectionView.prefetchingEnabled = NO;
+    }
+    collectionView.showsHorizontalScrollIndicator = NO;
+    collectionView.showsVerticalScrollIndicator = NO;
+    [self addSubview:collectionView];
+    _collectionView = collectionView;
+}
+
+- (void)willMoveToSuperview:(UIView *)newSuperview {
+    if (!newSuperview) {
+        [self removeTimer];
+    }else {
+        [self removeTimer];
+        if (_autoScrollInterval > 0) {
+            [self addTimer];
+        }
+    }
+}
+
+
+#pragma mark - timer
+
+- (void)addTimer {
+    if (_timer || _autoScrollInterval <= 0) {
+        return;
+    }
+    _timer = [NSTimer timerWithTimeInterval:_autoScrollInterval target:self selector:@selector(timerFired:) userInfo:nil repeats:YES];
+    [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
+}
+
+- (void)removeTimer {
+    if (!_timer) {
+        return;
+    }
+    [_timer invalidate];
+    _timer = nil;
+}
+
+- (void)timerFired:(NSTimer *)timer {
+    if (!self.superview || !self.window || _numberOfItems == 0 || self.tracking) {
+        return;
+    }
+    
+    [self scrollToNearlyIndexAtDirection:TYPagerScrollDirectionRight animate:YES];
+}
+
+#pragma mark - getter
+
+- (TYCyclePagerViewLayout *)layout {
+    if (!_layout) {
+        if (_dataSourceFlags.layoutForPagerView) {
+            _layout = [_dataSource layoutForPagerView:self];
+            _layout.isInfiniteLoop = _isInfiniteLoop;
+        }
+        if (_layout.itemSize.width <= 0 || _layout.itemSize.height <= 0) {
+            _layout = nil;
+        }
+    }
+    return _layout;
+}
+
+- (NSInteger)curIndex {
+    return _indexSection.index;
+}
+
+- (CGPoint)contentOffset {
+    return _collectionView.contentOffset;
+}
+
+- (BOOL)tracking {
+    return _collectionView.tracking;
+}
+
+- (BOOL)dragging {
+    return _collectionView.dragging;
+}
+
+- (BOOL)decelerating {
+    return _collectionView.decelerating;
+}
+
+- (UIView *)backgroundView {
+    return _collectionView.backgroundView;
+}
+
+- (__kindof UICollectionViewCell *)curIndexCell {
+    return [_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:_indexSection.index inSection:_indexSection.section]];
+}
+
+- (NSArray<__kindof UICollectionViewCell *> *)visibleCells {
+    return _collectionView.visibleCells;
+}
+
+- (NSArray *)visibleIndexs {
+    NSMutableArray *indexs = [NSMutableArray array];
+    for (NSIndexPath *indexPath in _collectionView.indexPathsForVisibleItems) {
+        [indexs addObject:@(indexPath.item)];
+    }
+    return [indexs copy];
+}
+
+#pragma mark - setter
+
+- (void)setBackgroundView:(UIView *)backgroundView {
+    [_collectionView setBackgroundView:backgroundView];
+}
+
+- (void)setAutoScrollInterval:(CGFloat)autoScrollInterval {
+    _autoScrollInterval = autoScrollInterval;
+    [self removeTimer];
+    if (autoScrollInterval > 0 && self.superview) {
+        [self addTimer];
+    }
+}
+
+- (void)setDelegate:(id<TYCyclePagerViewDelegate>)delegate {
+    _delegate = delegate;
+    _delegateFlags.pagerViewDidScroll = [delegate respondsToSelector:@selector(pagerViewDidScroll:)];
+    _delegateFlags.didScrollFromIndexToNewIndex = [delegate respondsToSelector:@selector(pagerView:didScrollFromIndex:toIndex:)];
+    _delegateFlags.initializeTransformAttributes = [delegate respondsToSelector:@selector(pagerView:initializeTransformAttributes:)];
+    _delegateFlags.applyTransformToAttributes = [delegate respondsToSelector:@selector(pagerView:applyTransformToAttributes:)];
+    if (self.collectionView && self.collectionView.collectionViewLayout) {
+        ((TYCyclePagerTransformLayout *)self.collectionView.collectionViewLayout).delegate = _delegateFlags.applyTransformToAttributes ? self : nil;
+    }
+}
+
+- (void)setDataSource:(id<TYCyclePagerViewDataSource>)dataSource {
+    _dataSource = dataSource;
+    _dataSourceFlags.cellForItemAtIndex = [dataSource respondsToSelector:@selector(pagerView:cellForItemAtIndex:)];
+    _dataSourceFlags.layoutForPagerView = [dataSource respondsToSelector:@selector(layoutForPagerView:)];
+}
+
+#pragma mark - public
+
+- (void)reloadData {
+    _didReloadData = YES;
+    _needResetIndex = YES;
+    [self setNeedClearLayout];
+    [self clearLayout];
+    [self updateData];
+}
+
+// not clear layout
+- (void)updateData {
+    [self updateLayout];
+    _numberOfItems = [_dataSource numberOfItemsInPagerView:self];
+    [_collectionView reloadData];
+    if (!_didLayout && !CGRectIsEmpty(self.collectionView.frame) && _indexSection.index < 0) {
+        _didLayout = YES;
+    }
+    BOOL needResetIndex = _needResetIndex && _reloadDataNeedResetIndex;
+    _needResetIndex = NO;
+    if (needResetIndex) {
+        [self removeTimer];
+    }
+    [self resetPagerViewAtIndex:(_indexSection.index < 0 && !CGRectIsEmpty(self.collectionView.frame)) || needResetIndex ? 0 :_indexSection.index];
+    if (needResetIndex) {
+        [self addTimer];
+    }
+}
+
+- (void)scrollToNearlyIndexAtDirection:(TYPagerScrollDirection)direction animate:(BOOL)animate {
+    TYIndexSection indexSection = [self nearlyIndexPathAtDirection:direction];
+    [self scrollToItemAtIndexSection:indexSection animate:animate];
+}
+
+- (void)scrollToItemAtIndex:(NSInteger)index animate:(BOOL)animate {
+    if (!_didLayout && _didReloadData) {
+        _firstScrollIndex = index;
+    }else {
+        _firstScrollIndex = -1;
+    }
+    if (!_isInfiniteLoop) {
+        [self scrollToItemAtIndexSection:TYMakeIndexSection(index, 0) animate:animate];
+        return;
+    }
+
+    [self scrollToItemAtIndexSection:TYMakeIndexSection(index, index >= self.curIndex ? _indexSection.section : _indexSection.section+1) animate:animate];
+}
+
+- (void)scrollToItemAtIndexSection:(TYIndexSection)indexSection animate:(BOOL)animate {
+    if (_numberOfItems <= 0 || ![self isValidIndexSection:indexSection]) {
+        //NSLog(@"scrollToItemAtIndex: item indexSection is invalid!");
+        return;
+    }
+    
+    if (animate && [_delegate respondsToSelector:@selector(pagerViewWillBeginScrollingAnimation:)]) {
+        [_delegate pagerViewWillBeginScrollingAnimation:self];
+    }
+    CGFloat offset = [self caculateOffsetXAtIndexSection:indexSection];
+    [_collectionView setContentOffset:CGPointMake(offset, _collectionView.contentOffset.y) animated:animate];
+}
+
+- (void)registerClass:(Class)Class forCellWithReuseIdentifier:(NSString *)identifier {
+    [_collectionView registerClass:Class forCellWithReuseIdentifier:identifier];
+}
+
+- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier {
+    [_collectionView registerNib:nib forCellWithReuseIdentifier:identifier];
+}
+
+- (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index {
+    UICollectionViewCell *cell = [_collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:[NSIndexPath indexPathForItem:index inSection:_dequeueSection]];
+    return cell;
+}
+
+#pragma mark - configure layout
+
+- (void)updateLayout {
+    if (!self.layout) {
+        return;
+    }
+    self.layout.isInfiniteLoop = _isInfiniteLoop;
+    ((TYCyclePagerTransformLayout *)_collectionView.collectionViewLayout).layout = self.layout;
+}
+
+- (void)clearLayout {
+    if (_needClearLayout) {
+        _layout = nil;
+        _needClearLayout = NO;
+    }
+}
+
+- (void)setNeedClearLayout {
+    _needClearLayout = YES;
+}
+
+- (void)setNeedUpdateLayout {
+    if (!self.layout) {
+        return;
+    }
+    [self clearLayout];
+    [self updateLayout];
+    [_collectionView.collectionViewLayout invalidateLayout];
+    [self resetPagerViewAtIndex:_indexSection.index < 0 ? 0 :_indexSection.index];
+}
+
+#pragma mark - pager index
+
+- (BOOL)isValidIndexSection:(TYIndexSection)indexSection {
+    return indexSection.index >= 0 && indexSection.index < _numberOfItems && indexSection.section >= 0 && indexSection.section < kPagerViewMaxSectionCount;
+}
+
+- (TYIndexSection)nearlyIndexPathAtDirection:(TYPagerScrollDirection)direction{
+    return [self nearlyIndexPathForIndexSection:_indexSection direction:direction];
+}
+
+- (TYIndexSection)nearlyIndexPathForIndexSection:(TYIndexSection)indexSection direction:(TYPagerScrollDirection)direction {
+    if (indexSection.index < 0 || indexSection.index >= _numberOfItems) {
+        return indexSection;
+    }
+    
+    if (!_isInfiniteLoop) {
+        if (direction == TYPagerScrollDirectionRight && indexSection.index == _numberOfItems - 1) {
+            return _autoScrollInterval > 0 ? TYMakeIndexSection(0, 0) : indexSection;
+        } else if (direction == TYPagerScrollDirectionRight) {
+            return TYMakeIndexSection(indexSection.index+1, 0);
+        }
+        
+        if (indexSection.index == 0) {
+            return _autoScrollInterval > 0 ? TYMakeIndexSection(_numberOfItems - 1, 0) : indexSection;
+        }
+        return TYMakeIndexSection(indexSection.index-1, 0);
+    }
+    
+    if (direction == TYPagerScrollDirectionRight) {
+        if (indexSection.index < _numberOfItems-1) {
+            return TYMakeIndexSection(indexSection.index+1, indexSection.section);
+        }
+        if (indexSection.section >= kPagerViewMaxSectionCount-1) {
+            return TYMakeIndexSection(indexSection.index, kPagerViewMaxSectionCount-1);
+        }
+        return TYMakeIndexSection(0, indexSection.section+1);
+    }
+    
+    if (indexSection.index > 0) {
+        return TYMakeIndexSection(indexSection.index-1, indexSection.section);
+    }
+    if (indexSection.section <= 0) {
+        return TYMakeIndexSection(indexSection.index, 0);
+    }
+    return TYMakeIndexSection(_numberOfItems-1, indexSection.section-1);
+}
+
+- (TYIndexSection)caculateIndexSectionWithOffsetX:(CGFloat)offsetX {
+    if (_numberOfItems <= 0) {
+        return TYMakeIndexSection(0, 0);
+    }
+     UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)_collectionView.collectionViewLayout;
+    CGFloat leftEdge = _isInfiniteLoop ? _layout.sectionInset.left : _layout.onlyOneSectionInset.left;
+    CGFloat width = CGRectGetWidth(_collectionView.frame);
+    CGFloat middleOffset = offsetX + width/2;
+    CGFloat itemWidth = layout.itemSize.width + layout.minimumInteritemSpacing;
+    NSInteger curIndex = 0;
+    NSInteger curSection = 0;
+    if (middleOffset - leftEdge >= 0) {
+        NSInteger itemIndex = (middleOffset - leftEdge+layout.minimumInteritemSpacing/2)/itemWidth;
+        if (itemIndex < 0) {
+            itemIndex = 0;
+        }else if (itemIndex >= _numberOfItems*kPagerViewMaxSectionCount) {
+            itemIndex = _numberOfItems*kPagerViewMaxSectionCount-1;
+        }
+        curIndex = itemIndex%_numberOfItems;
+        curSection = itemIndex/_numberOfItems;
+    }
+    return TYMakeIndexSection(curIndex, curSection);
+}
+
+- (CGFloat)caculateOffsetXAtIndexSection:(TYIndexSection)indexSection{
+    if (_numberOfItems == 0) {
+        return 0;
+    }
+    UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)_collectionView.collectionViewLayout;
+    UIEdgeInsets edge = _isInfiniteLoop ? _layout.sectionInset : _layout.onlyOneSectionInset;
+    CGFloat leftEdge = edge.left;
+    CGFloat rightEdge = edge.right;
+    CGFloat width = CGRectGetWidth(_collectionView.frame);
+    CGFloat itemWidth = layout.itemSize.width + layout.minimumInteritemSpacing;
+    CGFloat offsetX = 0;
+    if (!_isInfiniteLoop && !_layout.itemHorizontalCenter && indexSection.index == _numberOfItems - 1) {
+        offsetX = leftEdge + itemWidth*(indexSection.index + indexSection.section*_numberOfItems) - (width - itemWidth) -  layout.minimumInteritemSpacing + rightEdge;
+    }else {
+        offsetX = leftEdge + itemWidth*(indexSection.index + indexSection.section*_numberOfItems) - layout.minimumInteritemSpacing/2 - (width - itemWidth)/2;
+    }
+    return MAX(offsetX, 0);
+}
+
+- (void)resetPagerViewAtIndex:(NSInteger)index {
+    if (_didLayout && _firstScrollIndex >= 0) {
+        index = _firstScrollIndex;
+        _firstScrollIndex = -1;
+    }
+    if (index < 0) {
+        return;
+    }
+    if (index >= _numberOfItems) {
+        index = 0;
+    }
+    [self scrollToItemAtIndexSection:TYMakeIndexSection(index, _isInfiniteLoop ? kPagerViewMaxSectionCount/3 : 0) animate:NO];
+    if (!_isInfiniteLoop && _indexSection.index < 0) {
+        [self scrollViewDidScroll:_collectionView];
+    }
+}
+
+- (void)recyclePagerViewIfNeed {
+    if (!_isInfiniteLoop) {
+        return;
+    }
+    if (_indexSection.section > kPagerViewMaxSectionCount - kPagerViewMinSectionCount || _indexSection.section < kPagerViewMinSectionCount) {
+        [self resetPagerViewAtIndex:_indexSection.index];
+    }
+}
+
+#pragma mark - UICollectionViewDataSource
+
+- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
+    return _isInfiniteLoop ? kPagerViewMaxSectionCount : 1;
+}
+
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
+    _numberOfItems = [_dataSource numberOfItemsInPagerView:self];
+    return _numberOfItems;
+}
+
+- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
+    _dequeueSection = indexPath.section;
+    if (_dataSourceFlags.cellForItemAtIndex) {
+       return [_dataSource pagerView:self cellForItemAtIndex:indexPath.row];
+    }
+    NSAssert(NO, @"pagerView cellForItemAtIndex: is nil!");
+    return nil;
+}
+
+#pragma mark - UICollectionViewDelegateFlowLayout
+
+- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
+    if (!_isInfiniteLoop) {
+        return _layout.onlyOneSectionInset;
+    }
+    if (section == 0 ) {
+        return _layout.firstSectionInset;
+    }else if (section == kPagerViewMaxSectionCount -1) {
+        return _layout.lastSectionInset;
+    }
+    return _layout.middleSectionInset;
+}
+
+- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
+    UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
+    if ([_delegate respondsToSelector:@selector(pagerView:didSelectedItemCell:atIndex:)]) {
+        [_delegate pagerView:self didSelectedItemCell:cell atIndex:indexPath.item];
+    }
+    if ([_delegate respondsToSelector:@selector(pagerView:didSelectedItemCell:atIndexSection:)]) {
+        [_delegate pagerView:self didSelectedItemCell:cell atIndexSection:TYMakeIndexSection(indexPath.item, indexPath.section)];
+    }
+}
+
+#pragma mark - UIScrollViewDelegate
+
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
+    if (!_didLayout) {
+        return;
+    }
+    TYIndexSection newIndexSection =  [self caculateIndexSectionWithOffsetX:scrollView.contentOffset.x];
+    if (_numberOfItems <= 0 || ![self isValidIndexSection:newIndexSection]) {
+        NSLog(@"inVlaidIndexSection:(%ld,%ld)!",(long)newIndexSection.index,(long)newIndexSection.section);
+        return;
+    }
+    TYIndexSection indexSection = _indexSection;
+    _indexSection = newIndexSection;
+    
+    if (_delegateFlags.pagerViewDidScroll) {
+        [_delegate pagerViewDidScroll:self];
+    }
+    
+    if (_delegateFlags.didScrollFromIndexToNewIndex && !TYEqualIndexSection(_indexSection, indexSection)) {
+        //NSLog(@"curIndex %ld",(long)_indexSection.index);
+        [_delegate pagerView:self didScrollFromIndex:MAX(indexSection.index, 0) toIndex:_indexSection.index];
+    }
+}
+
+- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
+    if (_autoScrollInterval > 0) {
+        [self removeTimer];
+    }
+    _beginDragIndexSection = [self caculateIndexSectionWithOffsetX:scrollView.contentOffset.x];
+    if ([_delegate respondsToSelector:@selector(pagerViewWillBeginDragging:)]) {
+        [_delegate pagerViewWillBeginDragging:self];
+    }
+}
+
+- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
+    if (fabs(velocity.x) < 0.35 || !TYEqualIndexSection(_beginDragIndexSection, _indexSection)) {
+        targetContentOffset->x = [self caculateOffsetXAtIndexSection:_indexSection];
+        return;
+    }
+    TYPagerScrollDirection direction = TYPagerScrollDirectionRight;
+    if ((scrollView.contentOffset.x < 0 && targetContentOffset->x <= 0) || (targetContentOffset->x < scrollView.contentOffset.x && scrollView.contentOffset.x < scrollView.contentSize.width - scrollView.frame.size.width)) {
+        direction = TYPagerScrollDirectionLeft;
+    }
+    TYIndexSection indexSection = [self nearlyIndexPathForIndexSection:_indexSection direction:direction];
+    targetContentOffset->x = [self caculateOffsetXAtIndexSection:indexSection];
+}
+
+- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
+    if (_autoScrollInterval > 0) {
+        [self addTimer];
+    }
+    if ([_delegate respondsToSelector:@selector(pagerViewDidEndDragging:willDecelerate:)]) {
+        [_delegate pagerViewDidEndDragging:self willDecelerate:decelerate];
+    }
+}
+
+- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
+    if ([_delegate respondsToSelector:@selector(pagerViewWillBeginDecelerating:)]) {
+        [_delegate pagerViewWillBeginDecelerating:self];
+    }
+}
+
+- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
+    [self recyclePagerViewIfNeed];
+    if ([_delegate respondsToSelector:@selector(pagerViewDidEndDecelerating:)]) {
+        [_delegate pagerViewDidEndDecelerating:self];
+    }
+}
+
+- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
+    [self recyclePagerViewIfNeed];
+    if ([_delegate respondsToSelector:@selector(pagerViewDidEndScrollingAnimation:)]) {
+        [_delegate pagerViewDidEndScrollingAnimation:self];
+    }
+}
+
+#pragma mark - TYCyclePagerTransformLayoutDelegate
+
+- (void)pagerViewTransformLayout:(TYCyclePagerTransformLayout *)pagerViewTransformLayout initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes {
+    if (_delegateFlags.initializeTransformAttributes) {
+        [_delegate pagerView:self initializeTransformAttributes:attributes];
+    }
+}
+
+- (void)pagerViewTransformLayout:(TYCyclePagerTransformLayout *)pagerViewTransformLayout applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes {
+    if (_delegateFlags.applyTransformToAttributes) {
+        [_delegate pagerView:self applyTransformToAttributes:attributes];
+    }
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    BOOL needUpdateLayout = !CGRectEqualToRect(_collectionView.frame, self.bounds);
+    _collectionView.frame = self.bounds;
+    if ((_indexSection.section < 0 || needUpdateLayout) && (_numberOfItems > 0 || _didReloadData)) {
+        _didLayout = YES;
+        [self setNeedUpdateLayout];
+    }
+}
+
+- (void)dealloc {
+    ((TYCyclePagerTransformLayout *)_collectionView.collectionViewLayout).delegate = nil;
+    _collectionView.delegate = nil;
+    _collectionView.dataSource = nil;
+}
+
+@end
+
+

+ 47 - 0
TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYPageControl.h

@@ -0,0 +1,47 @@
+//
+//  TYPageControl.h
+//  TYCyclePagerViewDemo
+//
+//  Created by tany on 2017/6/20.
+//  Copyright © 2017年 tany. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface TYPageControl : UIControl
+
+@property (nonatomic, assign) NSInteger numberOfPages;          // default is 0
+@property (nonatomic, assign) NSInteger currentPage;            // default is 0. value pinned to 0..numberOfPages-1
+
+@property (nonatomic, assign) BOOL hidesForSinglePage;          // hide the the indicator if there is only one page. default is NO
+
+@property (nonatomic, assign) CGFloat pageIndicatorSpaing;
+@property (nonatomic, assign) UIEdgeInsets contentInset; // center will ignore this
+@property (nonatomic, assign ,readonly) CGSize contentSize; // real content size
+
+// override super 
+//@property (nonatomic, assign) UIControlContentVerticalAlignment contentVerticalAlignment;     // how to position content vertically inside control. default is center
+//@property (nonatomic, assign) UIControlContentHorizontalAlignment contentHorizontalAlignment; // how to position content hozontally inside control. default is center
+
+// indicatorTint color
+@property (nullable, nonatomic,strong) UIColor *pageIndicatorTintColor;
+@property (nullable, nonatomic,strong) UIColor *currentPageIndicatorTintColor;
+
+// indicator image
+@property (nullable, nonatomic,strong) UIImage *pageIndicatorImage;
+@property (nullable, nonatomic,strong) UIImage *currentPageIndicatorImage;
+
+@property (nonatomic, assign) UIViewContentMode indicatorImageContentMode; // default is UIViewContentModeCenter
+
+@property (nonatomic, assign) CGSize pageIndicatorSize; // indicator size
+@property (nonatomic, assign) CGSize currentPageIndicatorSize; // default pageIndicatorSize
+
+@property (nonatomic, assign) CGFloat animateDuring; // default 0.3
+
+- (void)setCurrentPage:(NSInteger)currentPage animate:(BOOL)animate;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 285 - 0
TSLiveWallpaper/Common/ThirdParty/TYCyclePagerView/TYPageControl.m

@@ -0,0 +1,285 @@
+//
+//  TYPageControl.m
+//  TYCyclePagerViewDemo
+//
+//  Created by tany on 2017/6/20.
+//  Copyright © 2017年 tany. All rights reserved.
+//
+
+#import "TYPageControl.h"
+
+@interface TYPageControl ()
+// UI
+@property (nonatomic, strong) NSArray<UIImageView *> *indicatorViews;
+
+// Data
+@property (nonatomic, assign) BOOL forceUpdate;
+
+@end
+
+@implementation TYPageControl
+
+#pragma mark - life cycle
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    if (self = [super initWithFrame:frame]) {
+        [self configurePropertys];
+    }
+    return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder {
+    if (self = [super initWithCoder:aDecoder]) {
+        [self configurePropertys];
+    }
+    return self;
+}
+
+- (void)configurePropertys {
+    self.userInteractionEnabled = NO;
+    _forceUpdate = NO;
+    _animateDuring = 0.3;
+    _pageIndicatorSpaing = 10;
+    _indicatorImageContentMode = UIViewContentModeCenter;
+    _pageIndicatorSize = CGSizeMake(6,6);
+    _currentPageIndicatorSize = _pageIndicatorSize;
+    _pageIndicatorTintColor = [UIColor colorWithRed:128/255. green:128/255. blue:128/255. alpha:1];
+    _currentPageIndicatorTintColor = [UIColor whiteColor];
+}
+
+- (void)willMoveToSuperview:(UIView *)newSuperview {
+    [super willMoveToSuperview:newSuperview];
+    if (newSuperview) {
+        _forceUpdate = YES;
+        [self updateIndicatorViews];
+        _forceUpdate = NO;
+    }
+}
+
+#pragma mark - getter setter
+
+- (CGSize)contentSize {
+    CGFloat width = (_indicatorViews.count - 1) * (_pageIndicatorSize.width + _pageIndicatorSpaing) + _pageIndicatorSize.width + _contentInset.left +_contentInset.right;
+    CGFloat height = _currentPageIndicatorSize.height + _contentInset.top + _contentInset.bottom;
+    return CGSizeMake(width, height);
+}
+
+- (void)setNumberOfPages:(NSInteger)numberOfPages {
+    if (numberOfPages == _numberOfPages) {
+        return;
+    }
+    _numberOfPages = numberOfPages;
+    if (_currentPage >= numberOfPages) {
+        _currentPage = 0;
+    }
+    [self updateIndicatorViews];
+    if (_indicatorViews.count > 0) {
+        [self setNeedsLayout];
+    }
+}
+
+- (void)setCurrentPage:(NSInteger)currentPage {
+    if (_currentPage == currentPage || _indicatorViews.count <= currentPage) {
+        return;
+    }
+    _currentPage = currentPage;
+    if (!CGSizeEqualToSize(_currentPageIndicatorSize, _pageIndicatorSize)) {
+        [self setNeedsLayout];
+    }
+    [self updateIndicatorViewsBehavior];
+    if (self.userInteractionEnabled) {
+        [self sendActionsForControlEvents:UIControlEventValueChanged];
+    }
+}
+
+- (void)setCurrentPage:(NSInteger)currentPage animate:(BOOL)animate {
+    if (animate) {
+        [UIView animateWithDuration:_animateDuring animations:^{
+            [self setCurrentPage:currentPage];
+        }];
+    }else {
+        [self setCurrentPage:currentPage];
+    }
+}
+
+- (void)setPageIndicatorImage:(UIImage *)pageIndicatorImage {
+    _pageIndicatorImage = pageIndicatorImage;
+    [self updateIndicatorViewsBehavior];
+}
+
+- (void)setCurrentPageIndicatorImage:(UIImage *)currentPageIndicatorImage {
+    _currentPageIndicatorImage = currentPageIndicatorImage;
+    [self updateIndicatorViewsBehavior];
+}
+
+- (void)setPageIndicatorTintColor:(UIColor *)pageIndicatorTintColor {
+    _pageIndicatorTintColor = pageIndicatorTintColor;
+    [self updateIndicatorViewsBehavior];
+}
+
+- (void)setCurrentPageIndicatorTintColor:(UIColor *)currentPageIndicatorTintColor {
+    _currentPageIndicatorTintColor = currentPageIndicatorTintColor;
+    [self updateIndicatorViewsBehavior];
+}
+
+- (void)setPageIndicatorSize:(CGSize)pageIndicatorSize {
+    if (CGSizeEqualToSize(_pageIndicatorSize, pageIndicatorSize)) {
+        return;
+    }
+    _pageIndicatorSize = pageIndicatorSize;
+    if (CGSizeEqualToSize(_currentPageIndicatorSize, CGSizeZero) || (_currentPageIndicatorSize.width < pageIndicatorSize.width && _currentPageIndicatorSize.height < pageIndicatorSize.height)) {
+        _currentPageIndicatorSize = pageIndicatorSize;
+    }
+    if (_indicatorViews.count > 0) {
+        [self setNeedsLayout];
+    }
+}
+
+- (void)setPageIndicatorSpaing:(CGFloat)pageIndicatorSpaing {
+    _pageIndicatorSpaing = pageIndicatorSpaing;
+    if (_indicatorViews.count > 0) {
+        [self setNeedsLayout];
+    }
+}
+
+- (void)setCurrentPageIndicatorSize:(CGSize)currentPageIndicatorSize {
+    if (CGSizeEqualToSize(_currentPageIndicatorSize, currentPageIndicatorSize)) {
+        return;
+    }
+    _currentPageIndicatorSize = currentPageIndicatorSize;
+    if (_indicatorViews.count > 0) {
+        [self setNeedsLayout];
+    }
+}
+
+- (void)setContentHorizontalAlignment:(UIControlContentHorizontalAlignment)contentHorizontalAlignment {
+    [super setContentHorizontalAlignment:contentHorizontalAlignment];
+    if (_indicatorViews.count > 0) {
+        [self setNeedsLayout];
+    }
+}
+
+- (void)setContentVerticalAlignment:(UIControlContentVerticalAlignment)contentVerticalAlignment {
+    [super setContentVerticalAlignment:contentVerticalAlignment];
+    if (_indicatorViews.count > 0) {
+        [self setNeedsLayout];
+    }
+}
+
+#pragma mark - update indicator
+
+- (void)updateIndicatorViews {
+    if (!self.superview && !_forceUpdate) {
+        return;
+    }
+    if (_indicatorViews.count == _numberOfPages) {
+        [self updateIndicatorViewsBehavior];
+        return;
+    }
+    NSMutableArray *indicatorViews = _indicatorViews ? [_indicatorViews mutableCopy] :[NSMutableArray array];
+    if (indicatorViews.count < _numberOfPages) {
+        for (NSInteger idx = indicatorViews.count; idx < _numberOfPages; ++idx) {
+            UIImageView *indicatorView = [[UIImageView alloc]init];
+            indicatorView.contentMode = _indicatorImageContentMode;
+            [self addSubview:indicatorView];
+            [indicatorViews addObject:indicatorView];
+        }
+    }else if (indicatorViews.count > _numberOfPages) {
+        for (NSInteger idx = indicatorViews.count - 1; idx >= _numberOfPages; --idx) {
+            UIImageView *indicatorView = indicatorViews[idx];
+            [indicatorView removeFromSuperview];
+            [indicatorViews removeObjectAtIndex:idx];
+        }
+    }
+    _indicatorViews = [indicatorViews copy];
+    [self updateIndicatorViewsBehavior];
+}
+
+- (void)updateIndicatorViewsBehavior {
+    if (_indicatorViews.count == 0 || (!self.superview && !_forceUpdate)) {
+        return;
+    }
+    if (_hidesForSinglePage && _indicatorViews.count == 1) {
+        UIImageView *indicatorView = _indicatorViews.lastObject;
+        indicatorView.hidden = YES;
+        return;
+    }
+    NSInteger index = 0;
+    for (UIImageView *indicatorView in _indicatorViews) {
+        if (_pageIndicatorImage) {
+            indicatorView.contentMode = _indicatorImageContentMode;
+            indicatorView.image = _currentPage == index ? _currentPageIndicatorImage : _pageIndicatorImage;
+        }else {
+            indicatorView.image = nil;
+            indicatorView.backgroundColor = _currentPage == index ? _currentPageIndicatorTintColor : _pageIndicatorTintColor;
+        }
+        indicatorView.hidden = NO;
+        ++index;
+    }
+}
+
+#pragma mark - layout
+
+- (void)layoutIndicatorViews {
+    if (_indicatorViews.count == 0) {
+        return;
+    }
+    CGFloat orignX = 0;
+    CGFloat centerY = 0;
+    CGFloat pageIndicatorSpaing = _pageIndicatorSpaing;
+    switch (self.contentHorizontalAlignment) {
+        case UIControlContentHorizontalAlignmentCenter:
+            // ignore contentInset
+            orignX = (CGRectGetWidth(self.frame) - (_indicatorViews.count - 1) * (_pageIndicatorSize.width + _pageIndicatorSpaing) - _currentPageIndicatorSize.width)/2;
+            break;
+        case UIControlContentHorizontalAlignmentLeft:
+            orignX = _contentInset.left;
+            break;
+        case UIControlContentHorizontalAlignmentRight:
+            orignX = CGRectGetWidth(self.frame) - ((_indicatorViews.count - 1) * (_pageIndicatorSize.width + _pageIndicatorSpaing) + _currentPageIndicatorSize.width) - _contentInset.right;
+            break;
+        case UIControlContentHorizontalAlignmentFill:
+            orignX = _contentInset.left;
+            if (_indicatorViews.count > 1) {
+                pageIndicatorSpaing = (CGRectGetWidth(self.frame) - _contentInset.left - _contentInset.right - _pageIndicatorSize.width - (_indicatorViews.count - 1) * _pageIndicatorSize.width)/(_indicatorViews.count - 1);
+            }
+            break;
+        default:
+            break;
+    }
+    switch (self.contentVerticalAlignment) {
+        case UIControlContentVerticalAlignmentCenter:
+            centerY = CGRectGetHeight(self.frame)/2;
+            break;
+        case UIControlContentVerticalAlignmentTop:
+            centerY = _contentInset.top + _currentPageIndicatorSize.height/2;
+            break;
+        case UIControlContentVerticalAlignmentBottom:
+            centerY = CGRectGetHeight(self.frame) - _currentPageIndicatorSize.height/2 - _contentInset.bottom;
+            break;
+        case UIControlContentVerticalAlignmentFill:
+            centerY = (CGRectGetHeight(self.frame) - _contentInset.top - _contentInset.bottom)/2 + _contentInset.top;
+            break;
+        default:
+            break;
+    }
+    NSInteger index = 0;
+    for (UIImageView *indicatorView in _indicatorViews) {
+        if (_pageIndicatorImage) {
+            indicatorView.layer.cornerRadius = 0;
+        }else {
+            indicatorView.layer.cornerRadius = _currentPage == index ? _currentPageIndicatorSize.height/2 : _pageIndicatorSize.height/2;
+        }
+        CGSize size = index == _currentPage ? _currentPageIndicatorSize : _pageIndicatorSize;
+        indicatorView.frame = CGRectMake(orignX, centerY - size.height/2, size.width, size.height);
+        orignX += size.width + pageIndicatorSpaing;
+        ++index;
+    }
+}
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    [self layoutIndicatorViews];
+}
+
+@end

+ 3 - 0
TSLiveWallpaper/Common/Tool/TSCommonTool/TSCommonTool.swift

@@ -216,6 +216,9 @@ func kMainAsync(_ block: @escaping () -> Void) {
     }
 }
 
+func kPercentlocalized(_ num:Int)-> String{
+    return String(format: "%d%".localized, num)
+}
 
 func kPresentModalVC(target:UIViewController,modelVC:UIViewController,style:UIModalPresentationStyle = .overFullScreen){
     let navi = TSBaseNavigationC(rootViewController: modelVC)

+ 1 - 1
TSLiveWallpaper/Data/OperationQueue/TSGenerateBaseOperation/TSGenerateBaseOperation.swift

@@ -208,7 +208,7 @@ class TSGenerateBaseOperation: TSBaseOperation , @unchecked Sendable{
             guard let self = self else { return }
     
             let progressInt = Int(progress*10.0)
-            let progressString = "Processing".localized + " \(90 + progressInt)%"
+            let progressString = "Processing".localized + " " + kPercentlocalized(90 + progressInt)
             stateDatauPblished = (.progressString(progressString),currentActionInfoModel)
             dePrint("生成后图片下载进度: \(progress)")
         } completion: { image in

+ 2 - 2
TSLiveWallpaper/Data/OperationQueue/TSGenerateBaseOperation/TSGenerateBasePhotoOperation.swift

@@ -247,7 +247,7 @@ class TSGenerateBasePhotoOperation: TSGenerateBaseOperation , @unchecked Sendabl
         }
         
         generatingProgress = progressInt
-        return "Processing".localized + " \(progressInt)%"
+        return "Processing".localized + " " + kPercentlocalized(progressInt)
     }
 
     var imageMaxKb:Int{
@@ -260,7 +260,7 @@ class TSGenerateBasePhotoOperation: TSGenerateBaseOperation , @unchecked Sendabl
         if progressInt > 99 {
             progressInt = 99
         }
-        return "Uploading Photo".localized + " \(progressInt)%"
+        return "Uploading Photo".localized + " " + kPercentlocalized(progressInt)
     }
     
     

+ 44 - 0
TSLiveWallpaper/Data/TSAppUpdateManager/TSAppUpdateManager.swift

@@ -0,0 +1,44 @@
+//
+//  TSAppUpdateManager.swift
+//  TSLiveWallpaper
+//
+//  Created by 100Years on 2025/6/18.
+//
+
+
+public extension Notification.Name {
+    static let kAppUpdateNotification = Notification.Name("kAppUpdateNotification")
+}
+
+class TSAppUpdateManager {
+
+    static var newVerison:String = ""
+    static var isNeedUpdate:Bool = false
+    
+    static var tabbarDotShow:Int = 0 //0,无需显示,1 需要显示,2 显示后隐藏
+    
+    
+    static func checkAppConfig() {
+        _ = TSNetworkShared.get(urlType: .config) { data, _ in
+            if let result = kNetWorkResultSuccess(data: data) {
+                newVerison = result.safeString(forKey: "version")
+                dePrint("checkAppConfig 刷新版本号refreshView = \(newVerison),appShortVersion=\(appShortVersion())")
+                if UIApplication.compareAppVersions(newVersion1: newVerison, oldVersion: appShortVersion()) == .newer {
+                    isNeedUpdate = true
+                }else{
+                    isNeedUpdate = false
+                }
+                
+                if isNeedUpdate,tabbarDotShow != 2 {
+                    tabbarDotShow = 1
+                }
+            }
+            kMainAsync{
+                NotificationCenter.default.post(name: .kAppUpdateNotification, object: nil)
+            }
+            
+        }
+    }
+    
+    
+}

+ 8 - 0
TSLiveWallpaper/ar.lproj/InfoPlist.strings

@@ -0,0 +1,8 @@
+/* 
+  InfoPlist.strings
+  TSLiveWallpaper
+
+  Created by 100Years on 2025/6/18.
+  
+*/
+NSPhotoLibraryUsageDescription = "اسمح لنا بالوصول إلى الصور التي تم تحميلها لمعالجتها وحفظها على جهازك.";

+ 0 - 0
TSLiveWallpaper/de.lproj/LaunchScreen.strings → TSLiveWallpaper/ar.lproj/LaunchScreen.strings


+ 126 - 0
TSLiveWallpaper/ar.lproj/Localizable.strings

@@ -0,0 +1,126 @@
+/* 
+  Localizable.strings
+  TSLiveWallpaper
+
+  Created by nkl on 2025/2/26.
+  
+*/
+
+"Allow us to access to upload photos to process and save processed photos to your device." = "اسمح لنا بالوصول إلى الصور التي تم تحميلها لمعالجتها وحفظها على جهازك.";
+"Add Color to Memories" = "أضف اللون إلى الذكريات";
+"Your photo is now vibrantly colorized, bringing memories to life" = "أصبحت صورتك الآن ملونة بشكل نابض بالحياة، مما يجعل الذكريات تنبض بالحياة";
+"Erase Scratches" = "مسح الخدوش";
+"Scratches and blemishes have vanished" = "لقد اختفت الخدوش والبقع";
+"Make photos clearer" = "جعل الصور أكثر وضوحا";
+"Your photo has become clearer,and the details are more noticeable" = "أصبحت صورتك أكثر وضوحًا، والتفاصيل أكثر وضوحًا";
+"Continue" = "يكمل";
+"Colorize Photo" = "تلوين الصورة";
+"Remove Scratches" = "إزالة الخدوش";
+"Enhance Photo" = "تحسين الصورة";
+"Get PRO Access" = "احصل على وصول احترافي";
+"Unlimited Process" = "عملية غير محدودة";
+"Unlock All Features" = "فتح جميع الميزات";
+"High Speed & Quality" = "سرعة وجودة عالية";
+"100%\nNo Ads" = "100% \nلا إعلانات";
+"Yearly" = "سنويا";
+"Weekly" = "أسبوعياً";
+"Just" = "فقط";
+"Per Year" = "كل سنة";
+"Per Week" = "للأسبوع";
+"Save-Vip" = "يحفظ";
+"per week" = "لمدة اسبوع";
+"Continue" = "يكمل";
+"Recurring billing,cancel anytime." = "الفواتير المتكررة، يمكن إلغاؤها في أي وقت.";
+"Payment will be charged to your iTunes account at confirmation of purchase. Subscriptions automatically renew for the same applicable term and price, unless auto-renew is turned off at least 24 hours before the end of the current period." = "سيتم خصم المبلغ من حساب iTunes الخاص بك عند تأكيد الشراء. تُجدد الاشتراكات تلقائيًا لنفس المدة والسعر المطبقين، ما لم يتم إيقاف التجديد التلقائي قبل 24 ساعة على الأقل من نهاية الفترة الحالية.";
+"Terms of us" = "شروطنا";
+"Privacy Policy" = "سياسة الخصوصية";
+"Restore" = "يعيد";
+"Enhance" = "يحسن";
+"Remove blur, sharpen, add details" = "إزالة الضبابية، وزيادة الوضوح، وإضافة التفاصيل";
+"Try" = "يحاول";
+"Colorize" = "تلوين";
+"Add colors to black-and-white photos" = "إضافة الألوان إلى الصور بالأبيض والأسود";
+"Descratch" = "ديسكراتش";
+"Remove scratches and dirt" = "إزالة الخدوش والأوساخ";
+"Enhance Tips" = "نصائح التحسين";
+"Suitable" = "مناسب";
+"Portraits, Low-resolution and photos, faces should be visible" = "الصور الشخصية والصور منخفضة الدقة والصور التي يجب أن تكون الوجوه مرئية";
+"Unsuitable" = "غير مناسب";
+"High resulotion, Severaly damaged and Difficult to recognize the face" = "نتائج عالية، تالفة للغاية ويصعب التعرف على الوجه";
+"Colorize Tips" = "نصائح التلوين";
+"Clear outline black-and-white photos" = "صور واضحة بالأبيض والأسود";
+"Colorful or Severely damaged photos" = "الصور الملونة أو التالفة بشدة";
+"Descratch Tips" = "نصائح ديسكراتش";
+"Scratched and Damaged photos
+" = "الصور المخدوشة والمتضررة";
+"High-resolution, Not damaged, and Clear photos" = "صور عالية الدقة، غير تالفة، وواضحة";
+"Upload Photo" = "تحميل الصورة";
+"Enhance Photo" = "تحسين الصورة";
+"Colorize Photo" = "تلوين الصورة";
+"Descratch Photo" = "ديسكراتش فوتو";
+"Enlighten Photo" = "إنليتن فوتو";
+"Recreate Photo" = "إعادة إنشاء الصورة";
+"You haven't saved the photo yet. Are you sure to quit?" = "لم تحفظ الصورة بعد. هل أنت متأكد من إغلاقها؟";
+"Quit" = "يترك";
+"Save" = "يحفظ";
+"As you leave, your task will be interrupted and no result." = "عندما تغادر، سوف يتم مقاطعة مهمتك ولن تحصل على أي نتيجة.";
+"Leave" = "يترك";
+"Wait" = "انتظر";
+"Processing" = "يعالج";
+"Uploading Photo" = "تحميل الصورة";
+"Process successfully" = "تمت العملية بنجاح";
+"Save Successfully" = "تم الحفظ بنجاح";
+"1 task is processing" = "1 مهمة قيد المعالجة";
+"~ %d mins" = "~ %d دقيقة";
+"Lots of people are processing images right now, so this might take a bit." = "هناك الكثير من الأشخاص الذين يقومون بمعالجة الصور في الوقت الحالي، لذا قد يستغرق هذا الأمر بعض الوقت.";
+"Home" = "بيت";
+"Result" = "نتيجة";
+"Are you sure to delete?" = "هل أنت متأكد من الحذف؟";
+"Retain" = "يحتفظ";
+"Delete" = "يمسح";
+"Delete this error history?" = "حذف سجل هذا الخطأ؟";
+"Due Date:" = "تاريخين:";
+"Share us" = "شاركنا";
+"Rate us" = "قيمنا";
+"User Agreement" = "اتفاقية المستخدم";
+"Privacy Policy" = "سياسة الخصوصية";
+"About us" = "معلومات عنا";
+"Lifetime" = "حياة";
+"Congratulation you have become VIP" = "مبروك لقد أصبحت VIP";
+"Finish" = "ينهي";
+"Restoring now" = "استعادة الآن";
+"Couldn't Restore Subscription" = "تعذر استعادة الاشتراك";
+"Getting price" = "الحصول على السعر";
+"Failed to get the price, will automatically retry in 5 seconds" = "فشل في الحصول على السعر، سيتم إعادة المحاولة تلقائيًا في غضون 5 ثوانٍ";
+"Failed to restore subscribe, please try again" = "فشل في استعادة الاشتراك، يرجى المحاولة مرة أخرى";
+"Verifying receipt..." = "جاري التحقق من الإيصال...";
+"Failed to validate receipt" = "فشل التحقق من صحة الإيصال";
+"Verify receipt failed" = "فشل التحقق من الإيصال";
+"Purchasing now" = "الشراء الآن";
+"Got it" = "فهمتها";
+"Reselect photos" = "إعادة تحديد الصور";
+"Sorry there was a slight problem with the image processing, please try again later." = "نأسف لوجود مشكلة بسيطة في معالجة الصورة، يرجى المحاولة مرة أخرى لاحقًا.";
+"No network, please check your network and try again." = "لا يوجد شبكة، يرجى التحقق من شبكتك ومحاولة مرة أخرى.";
+"Your photo may contain nudity, gore or violence that does not comply with the health policy, please replace the photo and try again." = "قد تحتوي صورتك على مشاهد عُري أو دماء أو عنف لا تتوافق مع سياسة الصحة، يرجى استبدال الصورة والمحاولة مرة أخرى.";
+"Process in the background" = "عملية في الخلفية";
+"History" = "تاريخ";
+"Upgrade" = "يرقي";
+"Well-exposed or severely damaged photos" = "الصور المعرضة جيدًا أو التالفة بشدة";
+"Over-dark or over-light, overexposed, or underexposed photos" = "الصور شديدة الظلام أو شديدة الإضاءة، أو شديدة التعرض، أو قليلة التعرض";
+"Recreate Tips" = "نصائح إعادة الإنشاء";
+"Recreate" = "إعادة إنشاء";
+"Bring new life to old photos" = "إضفاء حياة جديدة على الصور القديمة";
+"Enlighten" = "تنوير";
+"Easily fix lighting issues on photos" = "إصلاح مشاكل الإضاءة في الصور بسهولة";
+"View" = "منظر";
+"Example" = "مثال";
+"Limited Time Discount" = "خصم لفترة محدودة";
+"This task has expired" = "انتهت صلاحية هذه المهمة";
+"Processing you photo" = "معالجة صورتك";
+"Enlighten Tips" = "نصائح التنوير";
+"Payment Failed" = "فشل الدفع";
+"The subscription was canceled" = "تم إلغاء الاشتراك";
+"%d%" = "%%%d";
+"Your photo may contain copyright infringement, nudity, gore or violence that does not comply with the Health Policy, please replace the photo and try again." = "قد تحتوي صورتك على انتهاك لحقوق الطبع والنشر أو عُري أو دم أو عنف لا يتوافق مع سياسة الصحة، يرجى استبدال الصورة والمحاولة مرة أخرى.";
+"There's nothing here yet" = "لا يوجد شيء هنا حتى الآن";
+"Try Again" = "حاول ثانية";

+ 0 - 115
TSLiveWallpaper/de.lproj/Localizable.strings

@@ -1,115 +0,0 @@
-/* 
-  Localizable.strings
-  TSLiveWallpaper
-
-  Created by nkl on 2025/2/26.
-  
-*/
-
-/* Unlock Message */
-"It will be unlocked after an ad." = "Es wird nach einer Werbung freigeschaltet.";
-
-/* Unlocking */
-"Unlocking..." = "Wird freigeschaltet...";
-
-/* Loading */
-"Loading Failed" = "Laden fehlgeschlagen";
-
-/* Search */
-"Search" = "Suchen";
-
-/* Music */
-"No Music" = "Keine Musik";
-
-/* Network */
-"Network error, please check." = "Netzwerkfehler, bitte überprüfen.";
-
-/* Data */
-"No Data" = "Keine Daten";
-
-/* Reload */
-"Reload" = "Neu laden";
-
-/* Rename */
-"Rename" = "Umbenennen";
-
-/* Playlist */
-"Delete Playlist" = "Playlist löschen";
-"Create Playlist" = "Playlist erstellen";
-"Playlist Name" = "Playlist-Name";
-"input name" = "Name eingeben";
-"Playlist" = "Playlist";
-"Shuffle All" = "Alle mischen";
-
-/* Confirmation */
-"Are you sure to delete" = "Möchten Sie dies wirklich löschen?";
-
-/* Actions */
-"Like" = "Gefällt mir";
-"Delete" = "Löschen";
-"Add to Playlist" = "Zur Playlist";
-"Remove from playlist" = "Aus Playlist entfernen";
-"Created Successfully" = "Erfolgreich erstellt";
-"OK" = "OK";
-"Recently" = "Kürzlich";
-"Already Exists" = "Existiert bereits";
-"Up Next" = "Als Nächstes";
-"UnKnown" = "Unbekannt";
-"Select All" = "Alle auswählen";
-"Play All" = "Alle abspielen";
-"Done" = "Fertig";
-"Find your favorite songs" = "Finden Sie Ihre Lieblingssongs";
-"Sort By" = "Sortieren nach";
-"Ascending order by time" = "Aufsteigend nach Zeit";
-"Descending order by time" = "Absteigend nach Zeit";
-"Ascending order by name" = "Aufsteigend nach Name";
-"Descending order by name" = "Absteigend nach Name";
-"Add to like" = "Zu Favoriten hinzufügen";
-"Remove from like" = "Aus Favoriten entfernen";
-"Removed Successfully" = "Erfolgreich entfernt";
-"Added Successfully" = "Erfolgreich hinzugefügt";
-"Delete Successfully" = "Erfolgreich gelöscht";
-"Search Music" = "Musik suchen";
-"History" = "Verlauf";
-"Delete all" = "Alle löschen";
-"Sleep Mode" = "Schlafmodus";
-"Turn Off" = "Ausschalten";
-"Downloading" = "Wird heruntergeladen";
-"Retry" = "Erneut versuchen";
-"From Photo" = "Aus Foto";
-"From Files" = "Aus Dateien";
-"Go to Add" = "Zum Hinzufügen gehen";
-"Getting price" = "Preis wird abgerufen";
-"Get price failure, Will automatically retry in 5 seconds" = "Preisabruf fehlgeschlagen, automatischer Versuch in 5 Sekunden";
-"Purchasing now" = "Kauf wird durchgeführt";
-"Congratulation you have become VIP" = "Herzlichen Glückwunsch, Sie sind jetzt VIP";
-"Finish" = "Fertig";
-"Restoring now" = "Wird wiederhergestellt";
-"Couldn't Restore Subscription" = "Abonnement konnte nicht wiederhergestellt werden";
-"Failed to restore subscribe, please try again" = "Wiederherstellung des Abonnements fehlgeschlagen, bitte versuchen Sie es erneut";
-"Verify receipt failed" = "Überprüfung des Belegs fehlgeschlagen";
-"Continue" = "Fortsetzen";
-
-"Save Successfully" = "Erfolgreich gespeichert";
-"View" = "Anzeigen";
-"Create Live Wallpaper" = "Live-Hintergrund erstellen";
-"DIY Live Wallpaper" = "DIY Live-Hintergrund";
-"DIY Successfully" = "DIY erfolgreich";
-"Upload Video" = "Video hochladen";
-"How to set shuffle packs" = "Wie man Shuffle-Packs einstellt";
-"Save All" = "Alle speichern";
-"Upgrade" = "Upgrade";
-"Update" = "Aktualisieren";
-"Rate us" = "Bewerte uns";
-"Share us" = "Teile uns";
-"Privacy Policy" = "Datenschutzrichtlinie";
-"Terms of Service" = "Nutzungsbedingungen";
-"About us" = "Über uns";
-"Save" = "Speichern";
-"Save Fail" = "Speichern fehlgeschlagen";
-"ScreenRecorder unAvailable" = "Bildschirmrecorder nicht verfügbar";
-
-"All Premium Wallpapers" = "Alle Premium-Hintergründe";
-"Unlimited Video to Live" = "Unbegrenztes Video to Live";
-"100% No Ads" = "100 % keine Werbung";
-"Share" = "Aktie";

+ 8 - 0
TSLiveWallpaper/en.lproj/InfoPlist.strings

@@ -0,0 +1,8 @@
+/* 
+  InfoPlist.strings
+  TSLiveWallpaper
+
+  Created by 100Years on 2025/6/18.
+  
+*/
+NSPhotoLibraryUsageDescription = "Allow us to access to upload photos to process and save processed photos to your device.";

+ 109 - 101
TSLiveWallpaper/en.lproj/Localizable.strings

@@ -5,112 +5,120 @@
   Created by nkl on 2025/2/26.
   
 */
-
-/* Unlock Message */
-"It will be unlocked after an ad." = "It will be unlocked after an ad.";
-
-/* Unlocking */
-"Unlocking..." = "Unlocking...";
-
-/* Loading */
-"Loading Failed" = "Loading Failed";
-
-/* Search */
-"Search" = "Search";
-
-/* Music */
-"No Music" = "No Music";
-
-/* Network */
-"Network error, please check." = "Network error, please check.";
-
-/* Data */
-"No Data" = "No Data";
-
-/* Reload */
-"Reload" = "Reload";
-
-/* Rename */
-"Rename" = "Rename";
-
-/* Playlist */
-"Delete Playlist" = "Delete Playlist";
-"Create Playlist" = "Create Playlist";
-"Playlist Name" = "Playlist Name";
-"input name" = "input name";
-"Playlist" = "Playlist";
-"Shuffle All" = "Shuffle All";
-
-/* Confirmation */
-"Are you sure to delete" = "Are you sure to delete";
-
-/* Actions */
-"Like" = "Like";
+"Allow us to access to upload photos to process and save processed photos to your device." = "Allow us to access to upload photos to process and save processed photos to your device.";
+"Add Color to Memories" = "Add Color to Memories";
+"Your photo is now vibrantly colorized, bringing memories to life" = "Your photo is now vibrantly colorized, bringing memories to life";
+"Erase Scratches" = "Erase Scratches";
+"Scratches and blemishes have vanished" = "Scratches and blemishes have vanished";
+"Make photos clearer" = "Make photos clearer";
+"Your photo has become clearer,and the details are more noticeable" = "Your photo has become clearer,and the details are more noticeable";
+"Continue" = "Continue";
+"Colorize Photo" = "Colorize Photo";
+"Remove Scratches" = "Remove Scratches";
+"Enhance Photo" = "Enhance Photo";
+"Get PRO Access" = "Get PRO Access";
+"Unlimited Process" = "Unlimited Process";
+"Unlock All Features" = "Unlock All Features";
+"High Speed & Quality" = "High Speed & Quality";
+"100%\nNo Ads" = "100%\nNo Ads";
+"Yearly" = "Yearly";
+"Weekly" = "Weekly";
+"Just" = "Just";
+"Per Year" = "Per Year";
+"Per Week" = "Per Week";
+"Save-Vip" = "Save";
+"per week" = "per week";
+"Continue" = "Continue";
+"Recurring billing,cancel anytime." = "Recurring billing,cancel anytime.";
+"Payment will be charged to your iTunes account at confirmation of purchase. Subscriptions automatically renew for the same applicable term and price, unless auto-renew is turned off at least 24 hours before the end of the current period." = "Payment will be charged to your iTunes account at confirmation of purchase. Subscriptions automatically renew for the same applicable term and price, unless auto-renew is turned off at least 24 hours before the end of the current period.";
+"Terms of us" = "Terms of us";
+"Privacy Policy" = "Privacy Policy";
+"Restore" = "Restore";
+"Enhance" = "Enhance";
+"Remove blur, sharpen, add details" = "Remove blur, sharpen, add details";
+"Try" = "Try";
+"Colorize" = "Colorize";
+"Add colors to black-and-white photos" = "Add colors to black-and-white photos";
+"Descratch" = "Descratch";
+"Remove scratches and dirt" = "Remove scratches and dirt";
+"Enhance Tips" = "Enhance Tips";
+"Suitable" = "Suitable";
+"Portraits, Low-resolution and photos, faces should be visible" = "Portraits, Low-resolution and photos, faces should be visible";
+"Unsuitable" = "Unsuitable";
+"High resulotion, Severaly damaged and Difficult to recognize the face" = "High resulotion, Severaly damaged and Difficult to recognize the face";
+"Colorize Tips" = "Colorize Tips";
+"Clear outline black-and-white photos" = "Clear outline black-and-white photos";
+"Colorful or Severely damaged photos" = "Colorful or Severely damaged photos";
+"Descratch Tips" = "Descratch Tips";
+"Scratched and Damaged photos" = "Scratched and Damaged photos";
+"High-resolution, Not damaged, and Clear photos" = "High-resolution, Not damaged, and Clear photos";
+"Upload Photo" = "Upload Photo";
+"Enhance Photo" = "Enhance Photo";
+"Colorize Photo" = "Colorize Photo";
+"Descratch Photo" = "Descratch Photo";
+"Enlighten Photo" = "Enlighten Photo";
+"Recreate Photo" = "Recreate Photo";
+"You haven't saved the photo yet. Are you sure to quit?" = "You haven't saved the photo yet. Are you sure to quit?";
+"Quit" = "Quit";
+"Save" = "Save";
+"As you leave, your task will be interrupted and no result." = "As you leave, your task will be interrupted and no result.";
+"Leave" = "Leave";
+"Wait" = "Wait";
+"Processing" = "Processing";
+"Uploading Photo" = "Uploading Photo";
+"Process successfully" = "Process successfully";
+"Save Successfully" = "Save Successfully";
+"1 task is processing" = "1 task is processing";
+"~ %d mins" = "~ %d mins";
+"Lots of people are processing images right now, so this might take a bit." = "Lots of people are processing images right now, so this might take a bit.";
+"Home" = "Home";
+"Result" = "Result";
+"Are you sure to delete?" = "Are you sure to delete?";
+"Retain" = "Retain";
 "Delete" = "Delete";
-"Add to Playlist" = "Add to Playlist";
-"Remove from playlist" = "Remove from playlist";
-"Created Successfully" = "Created Successfully";
-"OK" = "OK";
-"Recently" = "Recently";
-"Already Exists" = "Already Exists";
-"Up Next" = "Up Next";
-"UnKnown" = "UnKnown";
-"Select All" = "Select All";
-"Play All" = "Play All";
-"Done" = "Done";
-"Find your favorite songs" = "Find your favorite songs";
-"Sort By" = "Sort By";
-"Ascending order by time" = "Ascending order by time";
-"Descending order by time" = "Descending order by time";
-"Ascending order by name" = "Ascending order by name";
-"Descending order by name" = "Descending order by name";
-"Add to like" = "Add to like";
-"Remove from like" = "Remove from like";
-"Removed Successfully" = "Removed Successfully";
-"Added Successfully" = "Added Successfully";
-"Delete Successfully" = "Delete Successfully";
-"Search Music" = "Search Music";
-"History" = "History";
-"Delete all" = "Delete all";
-"Sleep Mode" = "Sleep Mode";
-"Turn Off" = "Turn Off";
-"Downloading" = "Downloading";
-"Retry" = "Retry";
-"From Photo" = "From Photo";
-"From Files" = "From Files";
-"Go to Add" = "Go to Add";
-"Getting price" = "Getting price";
-"Get price failure, Will automatically retry in 5 seconds" = "Get price failure, Will automatically retry in 5 seconds";
-"Purchasing now" = "Purchasing now";
+"Delete this error history?" = "Delete this error history?";
+"Due Date:" = "Due Date:";
+"Share us" = "Share us";
+"Rate us" = "Rate us";
+"User Agreement" = "User Agreement";
+"Privacy Policy" = "Privacy Policy";
+"About us" = "About us";
+"Lifetime" = "Lifetime";
 "Congratulation you have become VIP" = "Congratulation you have become VIP";
 "Finish" = "Finish";
 "Restoring now" = "Restoring now";
 "Couldn't Restore Subscription" = "Couldn't Restore Subscription";
+"Getting price" = "Getting price";
+"Failed to get the price, will automatically retry in 5 seconds" = "Failed to get the price, will automatically retry in 5 seconds";
 "Failed to restore subscribe, please try again" = "Failed to restore subscribe, please try again";
+"Verifying receipt..." = "Verifying receipt...";
+"Failed to validate receipt" = "Failed to validate receipt";
 "Verify receipt failed" = "Verify receipt failed";
-"Continue" = "Continue";
-
-
-"Save Successfully" = "Save Successfully";
-"View" = "View";
-"Create Live Wallpaper" = "Create Live Wallpaper";
-"DIY Live Wallpaper" = "DIY Live Wallpaper";
-"DIY Successfully" = "DIY Successfully";
-"Upload Video" = "Upload Video";
-"How to set shuffle packs" = "How to set shuffle packs";
-"Save All" = "Save All";
+"Purchasing now" = "Purchasing now";
+"Got it" = "Got it";
+"Reselect photos" = "Reselect photos";
+"Sorry there was a slight problem with the image processing, please try again later." = "Sorry there was a slight problem with the image processing, please try again later.";
+"No network, please check your network and try again." = "No network, please check your network and try again.";
+"Your photo may contain nudity, gore or violence that does not comply with the health policy, please replace the photo and try again." = "Your photo may contain nudity, gore or violence that does not comply with the health policy, please replace the photo and try again.";
+"Process in the background" = "Process in the background";
+"History" = "History";
 "Upgrade" = "Upgrade";
-"Update" = "Update";
-"Rate us" = "Rate us";
-"Share us" = "Share us";
-"Privacy Policy" = "Privacy Policy";
-"Terms of Service" = "Terms of Service";
-"About us" = "About us";
-"Save" = "Save";
-"Save Fail" = "Save Fail";
-"ScreenRecorder unAvailable" = "ScreenRecorder unAvailable";
-
-"All Premium Wallpapers" = "All Premium Wallpapers";
-"Unlimited Video to Live" = "Unlimited Video to Live";
-"100% No Ads" = "100% No Ads";
-"Share" = "Share";
+"Well-exposed or severely damaged photos" = "Well-exposed or severely damaged photos";
+"Over-dark or over-light, overexposed, or underexposed photos" = "Over-dark or over-light, overexposed, or underexposed photos";
+"Recreate Tips" = "Recreate Tips";
+"Recreate" = "Recreate";
+"Bring new life to old photos" = "Bring new life to old photos";
+"Enlighten" = "Enlighten";
+"Easily fix lighting issues on photos" = "Easily fix lighting issues on photos";
+"View" = "View";
+"Example" = "Example";
+"Limited Time Discount" = "Limited Time Discount";
+"This task has expired" = "This task has expired";
+"Processing you photo" = "Processing you photo";
+"Enlighten Tips" = "Enlighten Tips";
+"Payment Failed" = "Payment Failed";
+"The subscription was canceled" = "The subscription was canceled";
+"%d%" = "%d%%";
+"Your photo may contain copyright infringement, nudity, gore or violence that does not comply with the Health Policy, please replace the photo and try again." = "Your photo may contain copyright infringement, nudity, gore or violence that does not comply with the Health Policy, please replace the photo and try again.";
+"There's nothing here yet" = "There's nothing here yet";
+"Try Again" = "Try Again";

+ 8 - 0
TSLiveWallpaper/es.lproj/InfoPlist.strings

@@ -0,0 +1,8 @@
+/* 
+  InfoPlist.strings
+  TSLiveWallpaper
+
+  Created by 100Years on 2025/6/18.
+  
+*/
+NSPhotoLibraryUsageDescription = "Permítanos acceder para cargar fotos para procesarlas y guardar las fotos procesadas en su dispositivo.";

+ 113 - 103
TSLiveWallpaper/es.lproj/Localizable.strings

@@ -5,111 +5,121 @@
   Created by nkl on 2025/2/26.
   
 */
-/* Unlock Message */
-"It will be unlocked after an ad." = "Se desbloqueará después de un anuncio.";
 
-/* Unlocking */
-"Unlocking..." = "Desbloqueando...";
-
-/* Loading */
-"Loading Failed" = "Error al cargar";
-
-/* Search */
-"Search" = "Buscar";
-
-/* Music */
-"No Music" = "No hay música";
-
-/* Network */
-"Network error, please check." = "Error de red, por favor verifique.";
-
-/* Data */
-"No Data" = "No hay datos";
-
-/* Reload */
-"Reload" = "Recargar";
-
-/* Rename */
-"Rename" = "Renombrar";
-
-/* Playlist */
-"Delete Playlist" = "Eliminar lista de reproducción";
-"Create Playlist" = "Crear lista de reproducción";
-"Playlist Name" = "Nombre de la lista de reproducción";
-"input name" = "ingrese un nombre";
-"Playlist" = "Lista de reproducción";
-"Shuffle All" = "Mezclar todo";
-
-/* Confirmation */
-"Are you sure to delete" = "¿Estás seguro de eliminar?";
-
-/* Actions */
-"Like" = "Me gusta";
+"Allow us to access to upload photos to process and save processed photos to your device." = "Permítanos acceder para cargar fotos para procesarlas y guardar las fotos procesadas en su dispositivo.";
+"Add Color to Memories" = "Añade color a los recuerdos";
+"Your photo is now vibrantly colorized, bringing memories to life" = "Tu foto ahora tiene colores vibrantes, dando vida a los recuerdos.";
+"Erase Scratches" = "Borrar arañazos";
+"Scratches and blemishes have vanished" = "Los arañazos y las imperfecciones han desaparecido.";
+"Make photos clearer" = "Hacer fotos más claras";
+"Your photo has become clearer,and the details are more noticeable" = "Tu foto se ha vuelto más clara y los detalles son más visibles.";
+"Continue" = "Continuar";
+"Colorize Photo" = "Colorear foto";
+"Remove Scratches" = "Eliminar arañazos";
+"Enhance Photo" = "Mejorar foto";
+"Get PRO Access" = "Obtenga acceso PRO";
+"Unlimited Process" = "Proceso ilimitado";
+"Unlock All Features" = "Desbloquear todo";
+"High Speed & Quality" = "Alta velocidad y calidad";
+"100%\nNo Ads" = "100% \nSin anuncios";
+"Yearly" = "Anual";
+"Weekly" = "Semanal";
+"Just" = "Justo";
+"Per Year" = "Por año";
+"Per Week" = "Por semana";
+"Save-Vip" = "Ahorrar";
+"per week" = "por semana";
+"Continue" = "Continuar";
+"Recurring billing,cancel anytime." = "Facturación recurrente, cancele en cualquier momento.";
+"Payment will be charged to your iTunes account at confirmation of purchase. Subscriptions automatically renew for the same applicable term and price, unless auto-renew is turned off at least 24 hours before the end of the current period." = "El pago se cargará a su cuenta de iTunes al confirmar la compra. Las suscripciones se renuevan automáticamente por el mismo plazo y precio, a menos que la renovación automática se desactive al menos 24 horas antes del final del periodo actual.";
+"Terms of us" = "Términos de uso";
+"Privacy Policy" = "política de privacidad";
+"Restore" = "Restaurar";
+"Enhance" = "Mejorar";
+"Remove blur, sharpen, add details" = "Eliminar desenfoque, enfocar, agregar detalles";
+"Try" = "Intentar";
+"Colorize" = "Colorear";
+"Add colors to black-and-white photos" = "Añadir colores a fotos en blanco y negro";
+"Descratch" = "Descratch";
+"Remove scratches and dirt" = "Eliminar arañazos y suciedad";
+"Enhance Tips" = "Consejos para mejorar";
+"Suitable" = "Adecuado";
+"Portraits, Low-resolution and photos, faces should be visible" = "Retratos, fotografías de baja resolución y en las que los rostros deben ser visibles.";
+"Unsuitable" = "Inadecuado";
+"High resulotion, Severaly damaged and Difficult to recognize the face" = "Alta resolución, muy dañado y difícil de reconocer la cara.";
+"Colorize Tips" = "Consejos para colorear";
+"Clear outline black-and-white photos" = "Fotografías en blanco y negro con contornos claros";
+"Colorful or Severely damaged photos" = "Fotos coloridas o muy dañadas";
+"Descratch Tips" = "Consejos para descratch";
+"Scratched and Damaged photos" = "Fotos rayadas y dañadas";
+"High-resolution, Not damaged, and Clear photos" = "Fotos de alta resolución, sin daños y claras.";
+"Upload Photo" = "Subir foto";
+"Enhance Photo" = "Mejorar foto";
+"Colorize Photo" = "Colorear foto";
+"Descratch Photo" = "Descratch Photo";
+"Enlighten Photo" = "Iluminar la foto";
+"Recreate Photo" = "Recrear foto";
+"You haven't saved the photo yet. Are you sure to quit?" = "Aún no has guardado la foto. ¿Estás seguro de que quieres salir?";
+"Quit" = "Abandonar";
+"Save" = "Ahorrar";
+"As you leave, your task will be interrupted and no result." = "Al salir, su tarea se verá interrumpida y no habrá resultado.";
+"Leave" = "Dejar";
+"Wait" = "Esperar";
+"Processing" = "Tratamiento";
+"Uploading Photo" = "Subiendo foto";
+"Process successfully" = "Procesar exitosamente";
+"Save Successfully" = "Guardar exitosamente";
+"1 task is processing" = "1 tarea está procesando";
+"~ %d mins" = "~ %d minutos";
+"Lots of people are processing images right now, so this might take a bit." = "Mucha gente está procesando imágenes en estos momentos, por lo que esto podría demorar un poco.";
+"Home" = "Hogar";
+"Result" = "Resultado";
+"Are you sure to delete?" = "¿Estás seguro de eliminarlo?";
+"Retain" = "Retener";
 "Delete" = "Borrar";
-"Add to Playlist" = "Añadir a la playlist";
-"Remove from playlist" = "Eliminar de la lista de reproducción";
-"Created Successfully" = "Creado exitosamente";
-"OK" = "OK";
-"Recently" = "Recientemente";
-"Already Exists" = "Ya existe";
-"Up Next" = "A continuación";
-"UnKnown" = "Desconocido";
-"Select All" = "Seleccionar todo";
-"Play All" = "Reproducir todo";
-"Done" = "Hecho";
-"Find your favorite songs" = "Encuentra tus canciones favoritas";
-"Sort By" = "Ordenar por";
-"Ascending order by time" = "Orden ascendente por tiempo";
-"Descending order by time" = "Orden descendente por tiempo";
-"Ascending order by name" = "Orden ascendente por nombre";
-"Descending order by name" = "Orden descendente por nombre";
-"Add to like" = "Añadir a favoritos";
-"Remove from like" = "Eliminar de favoritos";
-"Removed Successfully" = "Eliminado exitosamente";
-"Added Successfully" = "Añadido exitosamente";
-"Delete Successfully" = "Eliminado exitosamente";
-"Search Music" = "Buscar música";
-"History" = "Historial";
-"Delete all" = "Eliminar todo";
-"Sleep Mode" = "Modo de suspensión";
-"Turn Off" = "Apagar";
-"Downloading" = "Descargando";
-"Retry" = "Reintentar";
-"From Photo" = "Desde la foto";
-"From Files" = "Desde archivos";
-"Go to Add" = "Ir a añadir";
-"Getting price" = "Obteniendo precio";
-"Get price failure, Will automatically retry in 5 seconds" = "Error al obtener el precio, se reintentará automáticamente en 5 segundos";
-"Purchasing now" = "Comprando ahora";
-"Congratulation you have become VIP" = "Felicidades, te has convertido en VIP";
+"Delete this error history?" = "¿Borrar este historial de errores?";
+"Due Date:" = "Dos fechas:";
+"Share us" = "Compartenos";
+"Rate us" = "Calificanos";
+"User Agreement" = "Acuerdo de usuario";
+"Privacy Policy" = "política de privacidad";
+"About us" = "Sobre nosotros";
+"Lifetime" = "Vida";
+"Congratulation you have become VIP" = "¡Enhorabuena! ¡Te has convertido en VIP!";
 "Finish" = "Finalizar";
 "Restoring now" = "Restaurando ahora";
 "Couldn't Restore Subscription" = "No se pudo restaurar la suscripción";
-"Failed to restore subscribe, please try again" = "Error al restaurar la suscripción, por favor inténtalo de nuevo";
-"Verify receipt failed" = "Error al verificar el recibo";
-"Continue" = "Continuar";
-
-
-"Save Successfully" = "Guardado exitosamente";
-"View" = "Ver";
-"Create Live Wallpaper" = "Crear fondo de pantalla en vivo";
-"DIY Live Wallpaper" = "Fondo de pantalla en vivo DIY";
-"DIY Successfully" = "DIY exitoso";
-"Upload Video" = "Subir video";
-"How to set shuffle packs" = "Cómo configurar paquetes aleatorios";
-"Save All" = "Guardar todo";
-"Upgrade" = "Actualizar";
-"Update" = "Actualización";
-"Rate us" = "Califícanos";
-"Share us" = "Compártenos";
-"Privacy Policy" = "Política de Privacidad";
-"Terms of Service" = "Términos de Servicio";
-"About us" = "Sobre nosotros";
-"Save" = "Guardar";
-"Save Fail" = "Error al guardar";
-"ScreenRecorder unAvailable" = "Grabador de pantalla no disponible";
-
-"All Premium Wallpapers" = "Todos los fondos de pantalla premium";
-"Unlimited Video to Live" = "Vídeo ilimitado para vivir";
-"100% No Ads" = "100% sin publicidad";
-"Share" = "Compartir";
+"Getting price" = "Obtener precio";
+"Failed to get the price, will automatically retry in 5 seconds" = "No se pudo obtener el precio, se volverá a intentar automáticamente en 5 segundos.";
+"Failed to restore subscribe, please try again" = "No se pudo restaurar la suscripción, inténtelo nuevamente";
+"Verifying receipt..." = "Verificando recibo...";
+"Failed to validate receipt" = "No se pudo validar el recibo";
+"Verify receipt failed" = "Verificación de recibo fallida";
+"Purchasing now" = "Comprando ahora";
+"Got it" = "Entiendo";
+"Reselect photos" = "Volver a seleccionar fotos";
+"Sorry there was a slight problem with the image processing, please try again later." = "Lamentamos que haya habido un pequeño problema con el procesamiento de la imagen, inténtelo nuevamente más tarde.";
+"No network, please check your network and try again." = "No hay red, por favor verifique su red y vuelva a intentarlo.";
+"Your photo may contain nudity, gore or violence that does not comply with the health policy, please replace the photo and try again." = "Su foto puede contener desnudez, sangre o violencia que no cumple con la política de salud; reemplace la foto y vuelva a intentarlo.";
+"Process in the background" = "Proceso en segundo plano";
+"History" = "Historia";
+"Upgrade" = "Mejora";
+"Well-exposed or severely damaged photos" = "Fotos bien expuestas o muy dañadas";
+"Over-dark or over-light, overexposed, or underexposed photos" = "Fotos demasiado oscuras o demasiado claras, sobreexpuestas o subexpuestas";
+"Recreate Tips" = "Consejos para recrear";
+"Recreate" = "Recrear";
+"Bring new life to old photos" = "Dale nueva vida a fotos antiguas";
+"Enlighten" = "Iluminar";
+"Easily fix lighting issues on photos" = "Solucione fácilmente los problemas de iluminación en las fotografías";
+"View" = "Vista";
+"Example" = "Ejemplo";
+"Limited Time Discount" = "Oferta por Tiempo Limitado";
+"This task has expired" = "Esta tarea ha expirado";
+"Processing you photo" = "Procesando tu foto";
+"Enlighten Tips" = "Consejos para iluminar";
+"Payment Failed" = "Pago fallido";
+"The subscription was canceled" = "La suscripción fue cancelada";
+"%d%" = "%d%%";
+"Your photo may contain copyright infringement, nudity, gore or violence that does not comply with the Health Policy, please replace the photo and try again." = "Su foto puede contener violaciones de derechos de autor, desnudez, sangre o violencia que no cumple con la Política de salud; reemplace la foto y vuelva a intentarlo.";
+"There's nothing here yet" = "No hay nada aquí todavía";
+"Try Again" = "Intentar otra vez";

+ 0 - 1
TSLiveWallpaper/fr.lproj/LaunchScreen.strings

@@ -1 +0,0 @@
-

+ 0 - 115
TSLiveWallpaper/fr.lproj/Localizable.strings

@@ -1,115 +0,0 @@
-/* 
-  Localizable.strings
-  TSLiveWallpaper
-
-  Created by nkl on 2025/2/26.
-  
-*/
-
-/* Unlock Message */
-"It will be unlocked after an ad." = "Il sera débloqué après une publicité.";
-
-/* Unlocking */
-"Unlocking..." = "Déverrouillage...";
-
-/* Loading */
-"Loading Failed" = "Échec du chargement";
-
-/* Search */
-"Search" = "Rechercher";
-
-/* Music */
-"No Music" = "Aucune musique";
-
-/* Network */
-"Network error, please check." = "Erreur réseau, veuillez vérifier.";
-
-/* Data */
-"No Data" = "Aucune donnée";
-
-/* Reload */
-"Reload" = "Recharger";
-
-/* Rename */
-"Rename" = "Renommer";
-
-/* Playlist */
-"Delete Playlist" = "Supprimer la playlist";
-"Create Playlist" = "Créer une playlist";
-"Playlist Name" = "Nom de la playlist";
-"input name" = "saisir un nom";
-"Playlist" = "Playlist";
-"Shuffle All" = "Mélanger tout";
-
-/* Confirmation */
-"Are you sure to delete" = "Êtes-vous sûr de vouloir supprimer ?";
-
-/* Actions */
-"Like" = "J'aime";
-"Delete" = "Supprimer";
-"Add to Playlist" = "Ajouter à la playlist";
-"Remove from playlist" = "Retirer de la playlist";
-"Created Successfully" = "Créé avec succès";
-"OK" = "OK";
-"Recently" = "Récemment";
-"Already Exists" = "Existe déjà";
-"Up Next" = "À suivre";
-"UnKnown" = "Inconnu";
-"Select All" = "Tout sélectionner";
-"Play All" = "Tout lire";
-"Done" = "Terminé";
-"Find your favorite songs" = "Trouvez vos chansons préférées";
-"Sort By" = "Trier par";
-"Ascending order by time" = "Ordre croissant par temps";
-"Descending order by time" = "Ordre décroissant par temps";
-"Ascending order by name" = "Ordre croissant par nom";
-"Descending order by name" = "Ordre décroissant par nom";
-"Add to like" = "Ajouter aux favoris";
-"Remove from like" = "Retirer des favoris";
-"Removed Successfully" = "Retiré avec succès";
-"Added Successfully" = "Ajouté avec succès";
-"Delete Successfully" = "Supprimé avec succès";
-"Search Music" = "Rechercher de la musique";
-"History" = "Historique";
-"Delete all" = "Tout supprimer";
-"Sleep Mode" = "Mode veille";
-"Turn Off" = "Éteindre";
-"Downloading" = "Téléchargement en cours";
-"Retry" = "Réessayer";
-"From Photo" = "Depuis la photo";
-"From Files" = "Depuis les fichiers";
-"Go to Add" = "Aller à Ajouter";
-"Getting price" = "Obtention du prix";
-"Get price failure, Will automatically retry in 5 seconds" = "Échec de l'obtention du prix, nouvelle tentative automatique dans 5 secondes";
-"Purchasing now" = "Achat en cours";
-"Congratulation you have become VIP" = "Félicitations, vous êtes devenu VIP";
-"Finish" = "Terminer";
-"Restoring now" = "Restauration en cours";
-"Couldn't Restore Subscription" = "Impossible de restaurer l'abonnement";
-"Failed to restore subscribe, please try again" = "Échec de la restauration de l'abonnement, veuillez réessayer";
-"Verify receipt failed" = "Échec de la vérification du reçu";
-"Continue" = "Continuer";
-
-"Save Successfully" = "Enregistré avec succès";
-"View" = "Voir";
-"Create Live Wallpaper" = "Créer un fond d'écran animé";
-"DIY Live Wallpaper" = "Fond d'écran animé DIY";
-"DIY Successfully" = "DIY réussi";
-"Upload Video" = "Télécharger une vidéo";
-"How to set shuffle packs" = "Comment configurer les packs aléatoires";
-"Save All" = "Tout enregistrer";
-"Upgrade" = "Améliorer";
-"Update" = "Mettre à jour";
-"Rate us" = "Évaluez-nous";
-"Share us" = "Partagez-nous";
-"Privacy Policy" = "Politique de confidentialité";
-"Terms of Service" = "Conditions d'utilisation";
-"About us" = "À propos de nous";
-"Save" = "Enregistrer";
-"Save Fail" = "Échec de l'enregistrement";
-"ScreenRecorder unAvailable" = "Enregistreur d'écran non disponible";
-
-"All Premium Wallpapers" = "Tous les fonds d'écran premium";
-"Unlimited Video to Live" = "Vidéo illimitée en direct";
-"100% No Ads" = "100 % sans publicité";
-"Share" = "Partager";

+ 0 - 1
TSLiveWallpaper/pt-PT.lproj/LaunchScreen.strings

@@ -1 +0,0 @@
-

+ 0 - 114
TSLiveWallpaper/pt-PT.lproj/Localizable.strings

@@ -1,114 +0,0 @@
-/* 
-  Localizable.strings
-  TSLiveWallpaper
-
-  Created by nkl on 2025/2/26.
-  
-*/
-/* Unlock Message */
-"It will be unlocked after an ad." = "Será desbloqueado após um anúncio.";
-
-/* Unlocking */
-"Unlocking..." = "Desbloqueando...";
-
-/* Loading */
-"Loading Failed" = "Falha ao carregar";
-
-/* Search */
-"Search" = "Pesquisar";
-
-/* Music */
-"No Music" = "Nenhuma música";
-
-/* Network */
-"Network error, please check." = "Erro de rede, por favor verifique.";
-
-/* Data */
-"No Data" = "Nenhum dado";
-
-/* Reload */
-"Reload" = "Recarregar";
-
-/* Rename */
-"Rename" = "Renomear";
-
-/* Playlist */
-"Delete Playlist" = "Excluir playlist";
-"Create Playlist" = "Criar playlist";
-"Playlist Name" = "Nome da playlist";
-"input name" = "insira o nome";
-"Playlist" = "Playlist";
-"Shuffle All" = "Embaralhar tudo";
-
-/* Confirmation */
-"Are you sure to delete" = "Tem certeza que deseja excluir?";
-
-/* Actions */
-"Like" = "Curtir";
-"Delete" = "Excluir";
-"Add to Playlist" = "Adicionar à playlist";
-"Remove from playlist" = "Remover da playlist";
-"Created Successfully" = "Criado com sucesso";
-"OK" = "OK";
-"Recently" = "Recentemente";
-"Already Exists" = "Já existe";
-"Up Next" = "A seguir";
-"UnKnown" = "Desconhecido";
-"Select All" = "Selecionar tudo";
-"Play All" = "Reproduzir tudo";
-"Done" = "Concluído";
-"Find your favorite songs" = "Encontre suas músicas favoritas";
-"Sort By" = "Ordenar por";
-"Ascending order by time" = "Ordem crescente por tempo";
-"Descending order by time" = "Ordem decrescente por tempo";
-"Ascending order by name" = "Ordem crescente por nome";
-"Descending order by name" = "Ordem decrescente por nome";
-"Add to like" = "Adicionar aos favoritos";
-"Remove from like" = "Remover dos favoritos";
-"Removed Successfully" = "Removido com sucesso";
-"Added Successfully" = "Adicionado com sucesso";
-"Delete Successfully" = "Excluído com sucesso";
-"Search Music" = "Pesquisar música";
-"History" = "Histórico";
-"Delete all" = "Excluir tudo";
-"Sleep Mode" = "Modo de espera";
-"Turn Off" = "Desligar";
-"Downloading" = "Baixando";
-"Retry" = "Tentar novamente";
-"From Photo" = "Da foto";
-"From Files" = "Dos arquivos";
-"Go to Add" = "Ir para adicionar";
-"Getting price" = "Obtendo preço";
-"Get price failure, Will automatically retry in 5 seconds" = "Falha ao obter preço, tentativa automática em 5 segundos";
-"Purchasing now" = "Comprando agora";
-"Congratulation you have become VIP" = "Parabéns, você se tornou VIP";
-"Finish" = "Concluir";
-"Restoring now" = "Restaurando agora";
-"Couldn't Restore Subscription" = "Não foi possível restaurar a assinatura";
-"Failed to restore subscribe, please try again" = "Falha ao restaurar a assinatura, por favor tente novamente";
-"Verify receipt failed" = "Falha ao verificar o recibo";
-"Continue" = "Continuar";
-
-"Save Successfully" = "Salvo com sucesso";
-"View" = "Ver";
-"Create Live Wallpaper" = "Criar papel de parede ao vivo";
-"DIY Live Wallpaper" = "Papel de parede ao vivo DIY";
-"DIY Successfully" = "DIY concluído com sucesso";
-"Upload Video" = "Carregar vídeo";
-"How to set shuffle packs" = "Como configurar pacotes aleatórios";
-"Save All" = "Salvar tudo";
-"Upgrade" = "Atualizar";
-"Update" = "Atualização";
-"Rate us" = "Avalie-nos";
-"Share us" = "Compartilhe-nos";
-"Privacy Policy" = "Política de Privacidade";
-"Terms of Service" = "Termos de Serviço";
-"About us" = "Sobre nós";
-"Save" = "Salvar";
-"Save Fail" = "Falha ao salvar";
-"ScreenRecorder unAvailable" = "Gravador de tela indisponível";
-
-"All Premium Wallpapers" = "Todos os papéis de parede premium";
-"Unlimited Video to Live" = "Vídeo ilimitado para viver";
-"100% No Ads" = "100% sem anúncios";
-"Share" = "Compartilhar";