- 清除vip、隐藏开关

This commit is contained in:
linshujie 2026-09-15 15:30:29 +08:00
parent 536e735f3b
commit 43b6e1f73c
98 changed files with 84 additions and 6151 deletions

View File

@ -101,8 +101,6 @@
305A76E02FCA8C7000227D26 /* GroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305A76232FCA8C7000227D26 /* GroupView.swift */; }; 305A76E02FCA8C7000227D26 /* GroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305A76232FCA8C7000227D26 /* GroupView.swift */; };
305A76E12FCA8C7000227D26 /* GroupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305A76242FCA8C7000227D26 /* GroupViewController.swift */; }; 305A76E12FCA8C7000227D26 /* GroupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305A76242FCA8C7000227D26 /* GroupViewController.swift */; };
305A76E22FCA8C7000227D26 /* GroupViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305A76252FCA8C7000227D26 /* GroupViewModel.swift */; }; 305A76E22FCA8C7000227D26 /* GroupViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305A76252FCA8C7000227D26 /* GroupViewModel.swift */; };
305A76E32FCA8C7000227D26 /* GroupMemberView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305A76272FCA8C7000227D26 /* GroupMemberView.swift */; };
305A76E42FCA8C7000227D26 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305A76282FCA8C7000227D26 /* HomeView.swift */; };
305A76E52FCA8C7000227D26 /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305A76292FCA8C7000227D26 /* HomeViewController.swift */; }; 305A76E52FCA8C7000227D26 /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305A76292FCA8C7000227D26 /* HomeViewController.swift */; };
305A76E62FCA8C7000227D26 /* LaunchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305A762B2FCA8C7000227D26 /* LaunchViewController.swift */; }; 305A76E62FCA8C7000227D26 /* LaunchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305A762B2FCA8C7000227D26 /* LaunchViewController.swift */; };
305A76E72FCA8C7000227D26 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305A762D2FCA8C7000227D26 /* LoginView.swift */; }; 305A76E72FCA8C7000227D26 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 305A762D2FCA8C7000227D26 /* LoginView.swift */; };
@ -167,7 +165,6 @@
3062E8BE2FCEBD0E00CEF511 /* GroupIconListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3062E8BD2FCEBD0E00CEF511 /* GroupIconListVC.swift */; }; 3062E8BE2FCEBD0E00CEF511 /* GroupIconListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3062E8BD2FCEBD0E00CEF511 /* GroupIconListVC.swift */; };
3062E8C02FCED7BB00CEF511 /* GroupIconListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3062E8BF2FCED7BB00CEF511 /* GroupIconListView.swift */; }; 3062E8C02FCED7BB00CEF511 /* GroupIconListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3062E8BF2FCED7BB00CEF511 /* GroupIconListView.swift */; };
3062E8C22FCFB86800CEF511 /* CreateGroupViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3062E8C12FCFB86800CEF511 /* CreateGroupViewModel.swift */; }; 3062E8C22FCFB86800CEF511 /* CreateGroupViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3062E8C12FCFB86800CEF511 /* CreateGroupViewModel.swift */; };
3062E8C42FCFC90F00CEF511 /* CreateGroupVipPopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3062E8C32FCFC90F00CEF511 /* CreateGroupVipPopView.swift */; };
307073E12FD15F50004C37CC /* GroupIMService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 307073E02FD15F50004C37CC /* GroupIMService.swift */; }; 307073E12FD15F50004C37CC /* GroupIMService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 307073E02FD15F50004C37CC /* GroupIMService.swift */; };
307073E52FD18A20004C37CC /* GroupChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 307073E32FD18A20004C37CC /* GroupChatView.swift */; }; 307073E52FD18A20004C37CC /* GroupChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 307073E32FD18A20004C37CC /* GroupChatView.swift */; };
307073E62FD18A20004C37CC /* GroupChatVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 307073E22FD18A20004C37CC /* GroupChatVC.swift */; }; 307073E62FD18A20004C37CC /* GroupChatVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 307073E22FD18A20004C37CC /* GroupChatVC.swift */; };
@ -188,13 +185,10 @@
30A87A622FEE724D0095E7C6 /* CreateBubbleTiemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A87A612FEE724D0095E7C6 /* CreateBubbleTiemView.swift */; }; 30A87A622FEE724D0095E7C6 /* CreateBubbleTiemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A87A612FEE724D0095E7C6 /* CreateBubbleTiemView.swift */; };
30A87A642FEE75520095E7C6 /* CreateBubbleTipsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A87A632FEE75520095E7C6 /* CreateBubbleTipsView.swift */; }; 30A87A642FEE75520095E7C6 /* CreateBubbleTipsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A87A632FEE75520095E7C6 /* CreateBubbleTipsView.swift */; };
30A87A662FEE843E0095E7C6 /* CreateBubbleDoneView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A87A652FEE843E0095E7C6 /* CreateBubbleDoneView.swift */; }; 30A87A662FEE843E0095E7C6 /* CreateBubbleDoneView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A87A652FEE843E0095E7C6 /* CreateBubbleDoneView.swift */; };
30A87A682FEE86560095E7C6 /* CreateBubblePopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A87A672FEE86560095E7C6 /* CreateBubblePopView.swift */; };
30A87A6B2FEF5B950095E7C6 /* SearchLocationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A87A6A2FEF5B950095E7C6 /* SearchLocationView.swift */; }; 30A87A6B2FEF5B950095E7C6 /* SearchLocationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A87A6A2FEF5B950095E7C6 /* SearchLocationView.swift */; };
30A87A6D2FEF5BA10095E7C6 /* SearchLocationVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A87A6C2FEF5BA10095E7C6 /* SearchLocationVC.swift */; }; 30A87A6D2FEF5BA10095E7C6 /* SearchLocationVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A87A6C2FEF5BA10095E7C6 /* SearchLocationVC.swift */; };
30A87A6F2FEF7BE40095E7C6 /* SearchLocationResultVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A87A6E2FEF7BE40095E7C6 /* SearchLocationResultVC.swift */; }; 30A87A6F2FEF7BE40095E7C6 /* SearchLocationResultVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A87A6E2FEF7BE40095E7C6 /* SearchLocationResultVC.swift */; };
30A87A712FEF7BED0095E7C6 /* SearchLocationResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A87A702FEF7BED0095E7C6 /* SearchLocationResultView.swift */; }; 30A87A712FEF7BED0095E7C6 /* SearchLocationResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30A87A702FEF7BED0095E7C6 /* SearchLocationResultView.swift */; };
30ACD54C2FF6336000174861 /* PopupWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30ACD54B2FF6336000174861 /* PopupWindow.swift */; };
30ACD67B2FF7B36A00174861 /* PopupQueueManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30ACD67A2FF7B36A00174861 /* PopupQueueManager.swift */; };
30B2D0B12FEB111100CA0001 /* PhotoPickerStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30B2D0B02FEB111100CA0001 /* PhotoPickerStore.swift */; }; 30B2D0B12FEB111100CA0001 /* PhotoPickerStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30B2D0B02FEB111100CA0001 /* PhotoPickerStore.swift */; };
30B2D0B32FEB111100CA0001 /* PhotoPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30B2D0B22FEB111100CA0001 /* PhotoPickerView.swift */; }; 30B2D0B32FEB111100CA0001 /* PhotoPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30B2D0B22FEB111100CA0001 /* PhotoPickerView.swift */; };
30B2D0B52FEB111100CA0001 /* PhotoPickerAlbumView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30B2D0B42FEB111100CA0001 /* PhotoPickerAlbumView.swift */; }; 30B2D0B52FEB111100CA0001 /* PhotoPickerAlbumView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30B2D0B42FEB111100CA0001 /* PhotoPickerAlbumView.swift */; };
@ -227,9 +221,7 @@
30C4C01D2FDBF557009215C1 /* RemoveMemberViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C4C01C2FDBF557009215C1 /* RemoveMemberViewModel.swift */; }; 30C4C01D2FDBF557009215C1 /* RemoveMemberViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C4C01C2FDBF557009215C1 /* RemoveMemberViewModel.swift */; };
30C4C0202FDC0EC5009215C1 /* GroupInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C4C01F2FDC0EC5009215C1 /* GroupInfoView.swift */; }; 30C4C0202FDC0EC5009215C1 /* GroupInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C4C01F2FDC0EC5009215C1 /* GroupInfoView.swift */; };
30C4C0222FDC0ED3009215C1 /* GroupInfoVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C4C0212FDC0ED3009215C1 /* GroupInfoVC.swift */; }; 30C4C0222FDC0ED3009215C1 /* GroupInfoVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C4C0212FDC0ED3009215C1 /* GroupInfoVC.swift */; };
30C6666C2FFB7C4000E62B25 /* IAPManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C6666B2FFB7C4000E62B25 /* IAPManager.swift */; };
30C6679E2FFB7FEF00E62B25 /* SharePopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C6679C2FFB7FEF00E62B25 /* SharePopView.swift */; }; 30C6679E2FFB7FEF00E62B25 /* SharePopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C6679C2FFB7FEF00E62B25 /* SharePopView.swift */; };
30CCDE4E2FE26CEA00F5214A /* PayResultPopVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCDE4D2FE26CEA00F5214A /* PayResultPopVC.swift */; };
30CCDE512FE2785D00F5214A /* SignInVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCDE502FE2785D00F5214A /* SignInVC.swift */; }; 30CCDE512FE2785D00F5214A /* SignInVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCDE502FE2785D00F5214A /* SignInVC.swift */; };
30CCDE532FE2786600F5214A /* SignInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCDE522FE2786600F5214A /* SignInView.swift */; }; 30CCDE532FE2786600F5214A /* SignInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCDE522FE2786600F5214A /* SignInView.swift */; };
30CCDE552FE2903100F5214A /* SignInModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCDE542FE2903100F5214A /* SignInModel.swift */; }; 30CCDE552FE2903100F5214A /* SignInModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCDE542FE2903100F5214A /* SignInModel.swift */; };
@ -237,9 +229,6 @@
30CCDE5A2FE39F9D00F5214A /* SOSViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCDE592FE39F9D00F5214A /* SOSViewController.swift */; }; 30CCDE5A2FE39F9D00F5214A /* SOSViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCDE592FE39F9D00F5214A /* SOSViewController.swift */; };
30CCDE5C2FE3A1A800F5214A /* SOSPracticeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCDE5B2FE3A1A800F5214A /* SOSPracticeView.swift */; }; 30CCDE5C2FE3A1A800F5214A /* SOSPracticeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCDE5B2FE3A1A800F5214A /* SOSPracticeView.swift */; };
30D74AAB2FE8C7700050EB2C /* GPSSignalHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AAA2FE8C7700050EB2C /* GPSSignalHelper.swift */; }; 30D74AAB2FE8C7700050EB2C /* GPSSignalHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AAA2FE8C7700050EB2C /* GPSSignalHelper.swift */; };
30D74AAE2FEA13E00050EB2C /* ScheduleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AAD2FEA13E00050EB2C /* ScheduleView.swift */; };
30D74AB02FEA13ED0050EB2C /* ScheduleVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AAF2FEA13ED0050EB2C /* ScheduleVC.swift */; };
30D74AB22FEA1D5D0050EB2C /* ScheduleViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AB12FEA1D5D0050EB2C /* ScheduleViewModel.swift */; };
30D74AB42FEA25B90050EB2C /* ViewedModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AB32FEA25B90050EB2C /* ViewedModel.swift */; }; 30D74AB42FEA25B90050EB2C /* ViewedModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AB32FEA25B90050EB2C /* ViewedModel.swift */; };
30D74AB62FEA34FF0050EB2C /* ItineraryAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AB52FEA34FF0050EB2C /* ItineraryAPI.swift */; }; 30D74AB62FEA34FF0050EB2C /* ItineraryAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AB52FEA34FF0050EB2C /* ItineraryAPI.swift */; };
30D74AB82FEA36A50050EB2C /* ItineraryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AB72FEA36A50050EB2C /* ItineraryService.swift */; }; 30D74AB82FEA36A50050EB2C /* ItineraryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AB72FEA36A50050EB2C /* ItineraryService.swift */; };
@ -249,13 +238,9 @@
30D74AC12FEA6EEF0050EB2C /* CreateSchedulePopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AC02FEA6EEF0050EB2C /* CreateSchedulePopView.swift */; }; 30D74AC12FEA6EEF0050EB2C /* CreateSchedulePopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AC02FEA6EEF0050EB2C /* CreateSchedulePopView.swift */; };
30D74D1F2FEBB09B0050EB2C /* CreateScheduleVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74D1E2FEBB09B0050EB2C /* CreateScheduleVM.swift */; }; 30D74D1F2FEBB09B0050EB2C /* CreateScheduleVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74D1E2FEBB09B0050EB2C /* CreateScheduleVM.swift */; };
30D87CDB2FDFA9EE00E958FD /* MQTTService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D87CDA2FDFA9EE00E958FD /* MQTTService.swift */; }; 30D87CDB2FDFA9EE00E958FD /* MQTTService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D87CDA2FDFA9EE00E958FD /* MQTTService.swift */; };
30D87CDD2FDFF07500E958FD /* InteractionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D87CDC2FDFF07500E958FD /* InteractionView.swift */; };
30D87CDF2FDFF1A100E958FD /* QuickMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D87CDE2FDFF1A100E958FD /* QuickMessageView.swift */; }; 30D87CDF2FDFF1A100E958FD /* QuickMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D87CDE2FDFF1A100E958FD /* QuickMessageView.swift */; };
30D87D042FE1336300E958FD /* NavigationVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D87D012FE1336300E958FD /* NavigationVC.swift */; }; 30D87D042FE1336300E958FD /* NavigationVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D87D012FE1336300E958FD /* NavigationVC.swift */; };
30D87D052FE1336300E958FD /* NavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D87D022FE1336300E958FD /* NavigationView.swift */; }; 30D87D052FE1336300E958FD /* NavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D87D022FE1336300E958FD /* NavigationView.swift */; };
30D891F52FE22E0600E958FD /* OrderAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D891F42FE22E0600E958FD /* OrderAPI.swift */; };
30D891F72FE22E6E00E958FD /* OrderService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D891F62FE22E6E00E958FD /* OrderService.swift */; };
30DA36BD2FECC5AB008D5A2C /* CreateScheduleVipPopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30DA36BC2FECC5AB008D5A2C /* CreateScheduleVipPopView.swift */; };
30DC185A2FD11E7A0041DCD1 /* WebOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30DC18562FD11E7A0041DCD1 /* WebOperations.swift */; }; 30DC185A2FD11E7A0041DCD1 /* WebOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30DC18562FD11E7A0041DCD1 /* WebOperations.swift */; };
30DC185B2FD11E7A0041DCD1 /* NavigationTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30DC18552FD11E7A0041DCD1 /* NavigationTitleView.swift */; }; 30DC185B2FD11E7A0041DCD1 /* NavigationTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30DC18552FD11E7A0041DCD1 /* NavigationTitleView.swift */; };
30DC185C2FD11E7A0041DCD1 /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30DC18572FD11E7A0041DCD1 /* WebViewController.swift */; }; 30DC185C2FD11E7A0041DCD1 /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30DC18572FD11E7A0041DCD1 /* WebViewController.swift */; };
@ -366,11 +351,13 @@
55B26001304B000100786601 /* VersionUpgradePopVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55B26000304B000100786600 /* VersionUpgradePopVC.swift */; }; 55B26001304B000100786601 /* VersionUpgradePopVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55B26000304B000100786600 /* VersionUpgradePopVC.swift */; };
55B261010000000100786601 /* PrivacySettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55B261000000000100786600 /* PrivacySettingsViewController.swift */; }; 55B261010000000100786601 /* PrivacySettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55B261000000000100786600 /* PrivacySettingsViewController.swift */; };
55BF752D2FFE53F70055DA57 /* LocationPermissionPopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55BF752C2FFE53F70055DA57 /* LocationPermissionPopView.swift */; }; 55BF752D2FFE53F70055DA57 /* LocationPermissionPopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55BF752C2FFE53F70055DA57 /* LocationPermissionPopView.swift */; };
55BF75352FFF91690055DA57 /* InteractionEmojiCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55BF75342FFF91690055DA57 /* InteractionEmojiCell.swift */; };
55C1A0113034101000786011 /* PhoneStatusCollector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55C1A0103034101000786010 /* PhoneStatusCollector.swift */; }; 55C1A0113034101000786011 /* PhoneStatusCollector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55C1A0103034101000786010 /* PhoneStatusCollector.swift */; };
55C1A0213034102000786021 /* PrivilegeDeniedOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55C1A0203034102000786020 /* PrivilegeDeniedOverlay.swift */; }; 55C1A0213034102000786021 /* PrivilegeDeniedOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55C1A0203034102000786020 /* PrivilegeDeniedOverlay.swift */; };
55C219C13024C00100784731 /* SearchLocationHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55C219C13024C00100784730 /* SearchLocationHeaderView.swift */; }; 55C219C13024C00100784731 /* SearchLocationHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55C219C13024C00100784730 /* SearchLocationHeaderView.swift */; };
55C4C0242FDB91C8009215C2 /* CheckPermissionGuideVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55C4C0232FDB91C8009215C2 /* CheckPermissionGuideVC.swift */; }; 55C4C0242FDB91C8009215C2 /* CheckPermissionGuideVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55C4C0232FDB91C8009215C2 /* CheckPermissionGuideVC.swift */; };
55CA150E3058E55E000F1189 /* ScheduleViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55CA150B3058E55E000F1189 /* ScheduleViewModel.swift */; };
55CA15103058EBE5000F1189 /* InteractionEmojiCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55CA150F3058EBE5000F1189 /* InteractionEmojiCell.swift */; };
55CA15123058EC23000F1189 /* InteractionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55CA15113058EC23000F1189 /* InteractionView.swift */; };
60BEE25E61F3DE24976A7A47 /* ManagedSettingsUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FE44DF1C46BDA7B98BC7859 /* ManagedSettingsUI.framework */; }; 60BEE25E61F3DE24976A7A47 /* ManagedSettingsUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FE44DF1C46BDA7B98BC7859 /* ManagedSettingsUI.framework */; };
68F0D48EB76039050533197C /* AppRestrictShared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB29D0618C4BE76F2CA5261 /* AppRestrictShared.swift */; }; 68F0D48EB76039050533197C /* AppRestrictShared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB29D0618C4BE76F2CA5261 /* AppRestrictShared.swift */; };
6D90E8FFE4D597E888E6A224 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E326B06736FE04DD7A5E96D /* UIKit.framework */; }; 6D90E8FFE4D597E888E6A224 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E326B06736FE04DD7A5E96D /* UIKit.framework */; };
@ -539,8 +526,6 @@
305A76232FCA8C7000227D26 /* GroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupView.swift; sourceTree = "<group>"; }; 305A76232FCA8C7000227D26 /* GroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupView.swift; sourceTree = "<group>"; };
305A76242FCA8C7000227D26 /* GroupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupViewController.swift; sourceTree = "<group>"; }; 305A76242FCA8C7000227D26 /* GroupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupViewController.swift; sourceTree = "<group>"; };
305A76252FCA8C7000227D26 /* GroupViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupViewModel.swift; sourceTree = "<group>"; }; 305A76252FCA8C7000227D26 /* GroupViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupViewModel.swift; sourceTree = "<group>"; };
305A76272FCA8C7000227D26 /* GroupMemberView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMemberView.swift; sourceTree = "<group>"; };
305A76282FCA8C7000227D26 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = "<group>"; };
305A76292FCA8C7000227D26 /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = "<group>"; }; 305A76292FCA8C7000227D26 /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = "<group>"; };
305A762B2FCA8C7000227D26 /* LaunchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchViewController.swift; sourceTree = "<group>"; }; 305A762B2FCA8C7000227D26 /* LaunchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchViewController.swift; sourceTree = "<group>"; };
305A762D2FCA8C7000227D26 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; }; 305A762D2FCA8C7000227D26 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
@ -609,7 +594,6 @@
3062E8BD2FCEBD0E00CEF511 /* GroupIconListVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupIconListVC.swift; sourceTree = "<group>"; }; 3062E8BD2FCEBD0E00CEF511 /* GroupIconListVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupIconListVC.swift; sourceTree = "<group>"; };
3062E8BF2FCED7BB00CEF511 /* GroupIconListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupIconListView.swift; sourceTree = "<group>"; }; 3062E8BF2FCED7BB00CEF511 /* GroupIconListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupIconListView.swift; sourceTree = "<group>"; };
3062E8C12FCFB86800CEF511 /* CreateGroupViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateGroupViewModel.swift; sourceTree = "<group>"; }; 3062E8C12FCFB86800CEF511 /* CreateGroupViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateGroupViewModel.swift; sourceTree = "<group>"; };
3062E8C32FCFC90F00CEF511 /* CreateGroupVipPopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateGroupVipPopView.swift; sourceTree = "<group>"; };
307073E02FD15F50004C37CC /* GroupIMService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupIMService.swift; sourceTree = "<group>"; }; 307073E02FD15F50004C37CC /* GroupIMService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupIMService.swift; sourceTree = "<group>"; };
307073E22FD18A20004C37CC /* GroupChatVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupChatVC.swift; sourceTree = "<group>"; }; 307073E22FD18A20004C37CC /* GroupChatVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupChatVC.swift; sourceTree = "<group>"; };
307073E32FD18A20004C37CC /* GroupChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupChatView.swift; sourceTree = "<group>"; }; 307073E32FD18A20004C37CC /* GroupChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupChatView.swift; sourceTree = "<group>"; };
@ -630,13 +614,10 @@
30A87A612FEE724D0095E7C6 /* CreateBubbleTiemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateBubbleTiemView.swift; sourceTree = "<group>"; }; 30A87A612FEE724D0095E7C6 /* CreateBubbleTiemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateBubbleTiemView.swift; sourceTree = "<group>"; };
30A87A632FEE75520095E7C6 /* CreateBubbleTipsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateBubbleTipsView.swift; sourceTree = "<group>"; }; 30A87A632FEE75520095E7C6 /* CreateBubbleTipsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateBubbleTipsView.swift; sourceTree = "<group>"; };
30A87A652FEE843E0095E7C6 /* CreateBubbleDoneView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateBubbleDoneView.swift; sourceTree = "<group>"; }; 30A87A652FEE843E0095E7C6 /* CreateBubbleDoneView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateBubbleDoneView.swift; sourceTree = "<group>"; };
30A87A672FEE86560095E7C6 /* CreateBubblePopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateBubblePopView.swift; sourceTree = "<group>"; };
30A87A6A2FEF5B950095E7C6 /* SearchLocationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchLocationView.swift; sourceTree = "<group>"; }; 30A87A6A2FEF5B950095E7C6 /* SearchLocationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchLocationView.swift; sourceTree = "<group>"; };
30A87A6C2FEF5BA10095E7C6 /* SearchLocationVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchLocationVC.swift; sourceTree = "<group>"; }; 30A87A6C2FEF5BA10095E7C6 /* SearchLocationVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchLocationVC.swift; sourceTree = "<group>"; };
30A87A6E2FEF7BE40095E7C6 /* SearchLocationResultVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchLocationResultVC.swift; sourceTree = "<group>"; }; 30A87A6E2FEF7BE40095E7C6 /* SearchLocationResultVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchLocationResultVC.swift; sourceTree = "<group>"; };
30A87A702FEF7BED0095E7C6 /* SearchLocationResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchLocationResultView.swift; sourceTree = "<group>"; }; 30A87A702FEF7BED0095E7C6 /* SearchLocationResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchLocationResultView.swift; sourceTree = "<group>"; };
30ACD54B2FF6336000174861 /* PopupWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopupWindow.swift; sourceTree = "<group>"; };
30ACD67A2FF7B36A00174861 /* PopupQueueManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopupQueueManager.swift; sourceTree = "<group>"; };
30B2D0B02FEB111100CA0001 /* PhotoPickerStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPickerStore.swift; sourceTree = "<group>"; }; 30B2D0B02FEB111100CA0001 /* PhotoPickerStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPickerStore.swift; sourceTree = "<group>"; };
30B2D0B22FEB111100CA0001 /* PhotoPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPickerView.swift; sourceTree = "<group>"; }; 30B2D0B22FEB111100CA0001 /* PhotoPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPickerView.swift; sourceTree = "<group>"; };
30B2D0B42FEB111100CA0001 /* PhotoPickerAlbumView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPickerAlbumView.swift; sourceTree = "<group>"; }; 30B2D0B42FEB111100CA0001 /* PhotoPickerAlbumView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPickerAlbumView.swift; sourceTree = "<group>"; };
@ -670,9 +651,7 @@
30C4C01C2FDBF557009215C1 /* RemoveMemberViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveMemberViewModel.swift; sourceTree = "<group>"; }; 30C4C01C2FDBF557009215C1 /* RemoveMemberViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveMemberViewModel.swift; sourceTree = "<group>"; };
30C4C01F2FDC0EC5009215C1 /* GroupInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupInfoView.swift; sourceTree = "<group>"; }; 30C4C01F2FDC0EC5009215C1 /* GroupInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupInfoView.swift; sourceTree = "<group>"; };
30C4C0212FDC0ED3009215C1 /* GroupInfoVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupInfoVC.swift; sourceTree = "<group>"; }; 30C4C0212FDC0ED3009215C1 /* GroupInfoVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupInfoVC.swift; sourceTree = "<group>"; };
30C6666B2FFB7C4000E62B25 /* IAPManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IAPManager.swift; sourceTree = "<group>"; };
30C6679C2FFB7FEF00E62B25 /* SharePopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharePopView.swift; sourceTree = "<group>"; }; 30C6679C2FFB7FEF00E62B25 /* SharePopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharePopView.swift; sourceTree = "<group>"; };
30CCDE4D2FE26CEA00F5214A /* PayResultPopVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayResultPopVC.swift; sourceTree = "<group>"; };
30CCDE502FE2785D00F5214A /* SignInVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInVC.swift; sourceTree = "<group>"; }; 30CCDE502FE2785D00F5214A /* SignInVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInVC.swift; sourceTree = "<group>"; };
30CCDE522FE2786600F5214A /* SignInView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInView.swift; sourceTree = "<group>"; }; 30CCDE522FE2786600F5214A /* SignInView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInView.swift; sourceTree = "<group>"; };
30CCDE542FE2903100F5214A /* SignInModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInModel.swift; sourceTree = "<group>"; }; 30CCDE542FE2903100F5214A /* SignInModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInModel.swift; sourceTree = "<group>"; };
@ -680,9 +659,6 @@
30CCDE592FE39F9D00F5214A /* SOSViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SOSViewController.swift; sourceTree = "<group>"; }; 30CCDE592FE39F9D00F5214A /* SOSViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SOSViewController.swift; sourceTree = "<group>"; };
30CCDE5B2FE3A1A800F5214A /* SOSPracticeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SOSPracticeView.swift; sourceTree = "<group>"; }; 30CCDE5B2FE3A1A800F5214A /* SOSPracticeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SOSPracticeView.swift; sourceTree = "<group>"; };
30D74AAA2FE8C7700050EB2C /* GPSSignalHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GPSSignalHelper.swift; sourceTree = "<group>"; }; 30D74AAA2FE8C7700050EB2C /* GPSSignalHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GPSSignalHelper.swift; sourceTree = "<group>"; };
30D74AAD2FEA13E00050EB2C /* ScheduleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleView.swift; sourceTree = "<group>"; };
30D74AAF2FEA13ED0050EB2C /* ScheduleVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleVC.swift; sourceTree = "<group>"; };
30D74AB12FEA1D5D0050EB2C /* ScheduleViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleViewModel.swift; sourceTree = "<group>"; };
30D74AB32FEA25B90050EB2C /* ViewedModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewedModel.swift; sourceTree = "<group>"; }; 30D74AB32FEA25B90050EB2C /* ViewedModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewedModel.swift; sourceTree = "<group>"; };
30D74AB52FEA34FF0050EB2C /* ItineraryAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItineraryAPI.swift; sourceTree = "<group>"; }; 30D74AB52FEA34FF0050EB2C /* ItineraryAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItineraryAPI.swift; sourceTree = "<group>"; };
30D74AB72FEA36A50050EB2C /* ItineraryService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItineraryService.swift; sourceTree = "<group>"; }; 30D74AB72FEA36A50050EB2C /* ItineraryService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItineraryService.swift; sourceTree = "<group>"; };
@ -692,13 +668,9 @@
30D74AC02FEA6EEF0050EB2C /* CreateSchedulePopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateSchedulePopView.swift; sourceTree = "<group>"; }; 30D74AC02FEA6EEF0050EB2C /* CreateSchedulePopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateSchedulePopView.swift; sourceTree = "<group>"; };
30D74D1E2FEBB09B0050EB2C /* CreateScheduleVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateScheduleVM.swift; sourceTree = "<group>"; }; 30D74D1E2FEBB09B0050EB2C /* CreateScheduleVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateScheduleVM.swift; sourceTree = "<group>"; };
30D87CDA2FDFA9EE00E958FD /* MQTTService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MQTTService.swift; sourceTree = "<group>"; }; 30D87CDA2FDFA9EE00E958FD /* MQTTService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MQTTService.swift; sourceTree = "<group>"; };
30D87CDC2FDFF07500E958FD /* InteractionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractionView.swift; sourceTree = "<group>"; };
30D87CDE2FDFF1A100E958FD /* QuickMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickMessageView.swift; sourceTree = "<group>"; }; 30D87CDE2FDFF1A100E958FD /* QuickMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickMessageView.swift; sourceTree = "<group>"; };
30D87D012FE1336300E958FD /* NavigationVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationVC.swift; sourceTree = "<group>"; }; 30D87D012FE1336300E958FD /* NavigationVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationVC.swift; sourceTree = "<group>"; };
30D87D022FE1336300E958FD /* NavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationView.swift; sourceTree = "<group>"; }; 30D87D022FE1336300E958FD /* NavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationView.swift; sourceTree = "<group>"; };
30D891F42FE22E0600E958FD /* OrderAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderAPI.swift; sourceTree = "<group>"; };
30D891F62FE22E6E00E958FD /* OrderService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderService.swift; sourceTree = "<group>"; };
30DA36BC2FECC5AB008D5A2C /* CreateScheduleVipPopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateScheduleVipPopView.swift; sourceTree = "<group>"; };
30DC18552FD11E7A0041DCD1 /* NavigationTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationTitleView.swift; sourceTree = "<group>"; }; 30DC18552FD11E7A0041DCD1 /* NavigationTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationTitleView.swift; sourceTree = "<group>"; };
30DC18562FD11E7A0041DCD1 /* WebOperations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebOperations.swift; sourceTree = "<group>"; }; 30DC18562FD11E7A0041DCD1 /* WebOperations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebOperations.swift; sourceTree = "<group>"; };
30DC18572FD11E7A0041DCD1 /* WebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = "<group>"; }; 30DC18572FD11E7A0041DCD1 /* WebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = "<group>"; };
@ -813,11 +785,13 @@
55B26000304B000100786600 /* VersionUpgradePopVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionUpgradePopVC.swift; sourceTree = "<group>"; }; 55B26000304B000100786600 /* VersionUpgradePopVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionUpgradePopVC.swift; sourceTree = "<group>"; };
55B261000000000100786600 /* PrivacySettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySettingsViewController.swift; sourceTree = "<group>"; }; 55B261000000000100786600 /* PrivacySettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySettingsViewController.swift; sourceTree = "<group>"; };
55BF752C2FFE53F70055DA57 /* LocationPermissionPopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPermissionPopView.swift; sourceTree = "<group>"; }; 55BF752C2FFE53F70055DA57 /* LocationPermissionPopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPermissionPopView.swift; sourceTree = "<group>"; };
55BF75342FFF91690055DA57 /* InteractionEmojiCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractionEmojiCell.swift; sourceTree = "<group>"; };
55C1A0103034101000786010 /* PhoneStatusCollector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneStatusCollector.swift; sourceTree = "<group>"; }; 55C1A0103034101000786010 /* PhoneStatusCollector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhoneStatusCollector.swift; sourceTree = "<group>"; };
55C1A0203034102000786020 /* PrivilegeDeniedOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivilegeDeniedOverlay.swift; sourceTree = "<group>"; }; 55C1A0203034102000786020 /* PrivilegeDeniedOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivilegeDeniedOverlay.swift; sourceTree = "<group>"; };
55C219C13024C00100784730 /* SearchLocationHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchLocationHeaderView.swift; sourceTree = "<group>"; }; 55C219C13024C00100784730 /* SearchLocationHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchLocationHeaderView.swift; sourceTree = "<group>"; };
55C4C0232FDB91C8009215C2 /* CheckPermissionGuideVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckPermissionGuideVC.swift; sourceTree = "<group>"; }; 55C4C0232FDB91C8009215C2 /* CheckPermissionGuideVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckPermissionGuideVC.swift; sourceTree = "<group>"; };
55CA150B3058E55E000F1189 /* ScheduleViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleViewModel.swift; sourceTree = "<group>"; };
55CA150F3058EBE5000F1189 /* InteractionEmojiCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractionEmojiCell.swift; sourceTree = "<group>"; };
55CA15113058EC23000F1189 /* InteractionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractionView.swift; sourceTree = "<group>"; };
5E5F5DC8694A001BF0C47147 /* PairGuideStepsView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PairGuideStepsView.swift; path = AppRestrict/PairGuideStepsView.swift; sourceTree = "<group>"; }; 5E5F5DC8694A001BF0C47147 /* PairGuideStepsView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PairGuideStepsView.swift; path = AppRestrict/PairGuideStepsView.swift; sourceTree = "<group>"; };
6BAE595D39202A2958737BD3 /* SelectActivityVC.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SelectActivityVC.swift; path = AppRestrict/SelectActivityVC.swift; sourceTree = "<group>"; }; 6BAE595D39202A2958737BD3 /* SelectActivityVC.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SelectActivityVC.swift; path = AppRestrict/SelectActivityVC.swift; sourceTree = "<group>"; };
787F87DD1CEBED1A4E1E9FC7 /* AppRestrictView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AppRestrictView.swift; path = AppRestrict/AppRestrictView.swift; sourceTree = "<group>"; }; 787F87DD1CEBED1A4E1E9FC7 /* AppRestrictView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AppRestrictView.swift; path = AppRestrict/AppRestrictView.swift; sourceTree = "<group>"; };
@ -949,7 +923,6 @@
305A74CF2FCA8C7000227D26 /* UserAPI.swift */, 305A74CF2FCA8C7000227D26 /* UserAPI.swift */,
55B230023032000100785003 /* PigeonAPI.swift */, 55B230023032000100785003 /* PigeonAPI.swift */,
30BAB8502FCD331C00C33B5C /* GroupAPI.swift */, 30BAB8502FCD331C00C33B5C /* GroupAPI.swift */,
30D891F42FE22E0600E958FD /* OrderAPI.swift */,
30D74AB52FEA34FF0050EB2C /* ItineraryAPI.swift */, 30D74AB52FEA34FF0050EB2C /* ItineraryAPI.swift */,
30B74B4A2FF390EF00F6744D /* DrivingAPI.swift */, 30B74B4A2FF390EF00F6744D /* DrivingAPI.swift */,
); );
@ -1210,7 +1183,6 @@
55B217D23022F0A000784728 /* Unlock */, 55B217D23022F0A000784728 /* Unlock */,
305A752C2FCA8C7000227D26 /* URL */, 305A752C2FCA8C7000227D26 /* URL */,
30D87CD52FDF9F1900E958FD /* MQTT */, 30D87CD52FDF9F1900E958FD /* MQTT */,
30C6666A2FFB7C3000E62B25 /* IAPManager */,
2F518AB6587CC227CC515D8C /* AppRestrict */, 2F518AB6587CC227CC515D8C /* AppRestrict */,
); );
path = Manager; path = Manager;
@ -1300,10 +1272,10 @@
305A762A2FCA8C7000227D26 /* Home */ = { 305A762A2FCA8C7000227D26 /* Home */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
55CA15113058EC23000F1189 /* InteractionView.swift */,
55CA150F3058EBE5000F1189 /* InteractionEmojiCell.swift */,
305A76292FCA8C7000227D26 /* HomeViewController.swift */, 305A76292FCA8C7000227D26 /* HomeViewController.swift */,
305A798B2FCAB99300227D26 /* HomeViewModel.swift */, 305A798B2FCAB99300227D26 /* HomeViewModel.swift */,
305A76282FCA8C7000227D26 /* HomeView.swift */,
305A76272FCA8C7000227D26 /* GroupMemberView.swift */,
55B2179030217D6600784774 /* HomeView2.swift */, 55B2179030217D6600784774 /* HomeView2.swift */,
55B2179230218CE100784774 /* GroupMemberView2.swift */, 55B2179230218CE100784774 /* GroupMemberView2.swift */,
55B222000000000100784830 /* AddEmojiPopView.swift */, 55B222000000000100784830 /* AddEmojiPopView.swift */,
@ -1319,8 +1291,6 @@
55B240063040000100784906 /* AppUsageReport */, 55B240063040000100784906 /* AppUsageReport */,
30A7A9102FCAEE3D00105780 /* GroupListPopView.swift */, 30A7A9102FCAEE3D00105780 /* GroupListPopView.swift */,
30D87CDE2FDFF1A100E958FD /* QuickMessageView.swift */, 30D87CDE2FDFF1A100E958FD /* QuickMessageView.swift */,
30D87CDC2FDFF07500E958FD /* InteractionView.swift */,
55BF75342FFF91690055DA57 /* InteractionEmojiCell.swift */,
55BF752C2FFE53F70055DA57 /* LocationPermissionPopView.swift */, 55BF752C2FFE53F70055DA57 /* LocationPermissionPopView.swift */,
30A87A692FEF59E60095E7C6 /* SearchLocation */, 30A87A692FEF59E60095E7C6 /* SearchLocation */,
30A87A5C2FEE711C0095E7C6 /* Bubble */, 30A87A5C2FEE711C0095E7C6 /* Bubble */,
@ -1398,7 +1368,6 @@
305A762C2FCA8C7000227D26 /* Launch */, 305A762C2FCA8C7000227D26 /* Launch */,
3062E8B32FCE6BA400CEF511 /* Scan */, 3062E8B32FCE6BA400CEF511 /* Scan */,
30DC18592FD11E7A0041DCD1 /* Web */, 30DC18592FD11E7A0041DCD1 /* Web */,
30ACD54A2FF6332200174861 /* PopupWindow */,
30EFF3AD2FD7FF1400EB35D4 /* TextInput */, 30EFF3AD2FD7FF1400EB35D4 /* TextInput */,
30C6679D2FFB7FEF00E62B25 /* Share */, 30C6679D2FFB7FEF00E62B25 /* Share */,
F49062649CA8E5F9FA2F22A5 /* AppRestrict */, F49062649CA8E5F9FA2F22A5 /* AppRestrict */,
@ -1415,7 +1384,6 @@
55B230003032000100785001 /* UploadService.swift */, 55B230003032000100785001 /* UploadService.swift */,
55B230043032000100785005 /* PigeonService.swift */, 55B230043032000100785005 /* PigeonService.swift */,
30BAB8522FCD337C00C33B5C /* GroupService.swift */, 30BAB8522FCD337C00C33B5C /* GroupService.swift */,
30D891F62FE22E6E00E958FD /* OrderService.swift */,
30D74AB72FEA36A50050EB2C /* ItineraryService.swift */, 30D74AB72FEA36A50050EB2C /* ItineraryService.swift */,
30B74B4C2FF391FF00F6744D /* DrivingService.swift */, 30B74B4C2FF391FF00F6744D /* DrivingService.swift */,
); );
@ -1515,7 +1483,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
55B26000304B000100786600 /* VersionUpgradePopVC.swift */, 55B26000304B000100786600 /* VersionUpgradePopVC.swift */,
30CCDE4D2FE26CEA00F5214A /* PayResultPopVC.swift */,
30EFF3BA2FD90D7600EB35D4 /* ConfirmPopVC.swift */, 30EFF3BA2FD90D7600EB35D4 /* ConfirmPopVC.swift */,
305A76642FCA8C7000227D26 /* DLAlertPopVC.swift */, 305A76642FCA8C7000227D26 /* DLAlertPopVC.swift */,
305A76652FCA8C7000227D26 /* DLCustomPopVC.swift */, 305A76652FCA8C7000227D26 /* DLCustomPopVC.swift */,
@ -1599,7 +1566,6 @@
3062E8C12FCFB86800CEF511 /* CreateGroupViewModel.swift */, 3062E8C12FCFB86800CEF511 /* CreateGroupViewModel.swift */,
3062E8BD2FCEBD0E00CEF511 /* GroupIconListVC.swift */, 3062E8BD2FCEBD0E00CEF511 /* GroupIconListVC.swift */,
3062E8BF2FCED7BB00CEF511 /* GroupIconListView.swift */, 3062E8BF2FCED7BB00CEF511 /* GroupIconListView.swift */,
3062E8C32FCFC90F00CEF511 /* CreateGroupVipPopView.swift */,
); );
path = CreateGroup; path = CreateGroup;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1666,7 +1632,6 @@
30A87A612FEE724D0095E7C6 /* CreateBubbleTiemView.swift */, 30A87A612FEE724D0095E7C6 /* CreateBubbleTiemView.swift */,
30A87A632FEE75520095E7C6 /* CreateBubbleTipsView.swift */, 30A87A632FEE75520095E7C6 /* CreateBubbleTipsView.swift */,
30A87A652FEE843E0095E7C6 /* CreateBubbleDoneView.swift */, 30A87A652FEE843E0095E7C6 /* CreateBubbleDoneView.swift */,
30A87A672FEE86560095E7C6 /* CreateBubblePopView.swift */,
); );
path = Bubble; path = Bubble;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1684,15 +1649,6 @@
path = SearchLocation; path = SearchLocation;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
30ACD54A2FF6332200174861 /* PopupWindow */ = {
isa = PBXGroup;
children = (
30ACD67A2FF7B36A00174861 /* PopupQueueManager.swift */,
30ACD54B2FF6336000174861 /* PopupWindow.swift */,
);
path = PopupWindow;
sourceTree = "<group>";
};
30B2D0BA2FEB111100CA0001 /* PhotoPicker */ = { 30B2D0BA2FEB111100CA0001 /* PhotoPicker */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -1784,14 +1740,6 @@
path = GroupInfo; path = GroupInfo;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
30C6666A2FFB7C3000E62B25 /* IAPManager */ = {
isa = PBXGroup;
children = (
30C6666B2FFB7C4000E62B25 /* IAPManager.swift */,
);
path = IAPManager;
sourceTree = "<group>";
};
30C6679D2FFB7FEF00E62B25 /* Share */ = { 30C6679D2FFB7FEF00E62B25 /* Share */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -1827,9 +1775,7 @@
30D74AAC2FEA13BD0050EB2C /* Schedule */ = { 30D74AAC2FEA13BD0050EB2C /* Schedule */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
30D74AAF2FEA13ED0050EB2C /* ScheduleVC.swift */, 55CA150B3058E55E000F1189 /* ScheduleViewModel.swift */,
30D74AB12FEA1D5D0050EB2C /* ScheduleViewModel.swift */,
30D74AAD2FEA13E00050EB2C /* ScheduleView.swift */,
30D74AB32FEA25B90050EB2C /* ViewedModel.swift */, 30D74AB32FEA25B90050EB2C /* ViewedModel.swift */,
30D74AB92FEA37AD0050EB2C /* ScheduleModel.swift */, 30D74AB92FEA37AD0050EB2C /* ScheduleModel.swift */,
30D74ABB2FEA67CE0050EB2C /* CreateSchedule */, 30D74ABB2FEA67CE0050EB2C /* CreateSchedule */,
@ -1848,7 +1794,6 @@
30D74D1E2FEBB09B0050EB2C /* CreateScheduleVM.swift */, 30D74D1E2FEBB09B0050EB2C /* CreateScheduleVM.swift */,
30D74ABE2FEA67F30050EB2C /* CreateScheduleView.swift */, 30D74ABE2FEA67F30050EB2C /* CreateScheduleView.swift */,
30D74AC02FEA6EEF0050EB2C /* CreateSchedulePopView.swift */, 30D74AC02FEA6EEF0050EB2C /* CreateSchedulePopView.swift */,
30DA36BC2FECC5AB008D5A2C /* CreateScheduleVipPopView.swift */,
); );
path = CreateSchedule; path = CreateSchedule;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2432,7 +2377,6 @@
305A76922FCA8C7000227D26 /* LogUtils.swift in Sources */, 305A76922FCA8C7000227D26 /* LogUtils.swift in Sources */,
305A76932FCA8C7000227D26 /* AddImageCell.swift in Sources */, 305A76932FCA8C7000227D26 /* AddImageCell.swift in Sources */,
30EFF3D82FDA8F1000EB35D4 /* EmergencyContactVC.swift in Sources */, 30EFF3D82FDA8F1000EB35D4 /* EmergencyContactVC.swift in Sources */,
30A87A682FEE86560095E7C6 /* CreateBubblePopView.swift in Sources */,
55B219C13024C00100784722 /* BubbleHeroView.swift in Sources */, 55B219C13024C00100784722 /* BubbleHeroView.swift in Sources */,
55B219C13024C00100784724 /* CreateBubbleSetupView.swift in Sources */, 55B219C13024C00100784724 /* CreateBubbleSetupView.swift in Sources */,
55B219C13024C00100784726 /* BubbleKnowledgeView.swift in Sources */, 55B219C13024C00100784726 /* BubbleKnowledgeView.swift in Sources */,
@ -2455,27 +2399,24 @@
30EFF3DA2FDA935D00EB35D4 /* EmergencyContactFooterView.swift in Sources */, 30EFF3DA2FDA935D00EB35D4 /* EmergencyContactFooterView.swift in Sources */,
3062E8C22FCFB86800CEF511 /* CreateGroupViewModel.swift in Sources */, 3062E8C22FCFB86800CEF511 /* CreateGroupViewModel.swift in Sources */,
30A87A662FEE843E0095E7C6 /* CreateBubbleDoneView.swift in Sources */, 30A87A662FEE843E0095E7C6 /* CreateBubbleDoneView.swift in Sources */,
55BF75352FFF91690055DA57 /* InteractionEmojiCell.swift in Sources */,
305A769B2FCA8C7000227D26 /* PopupAnimators.swift in Sources */, 305A769B2FCA8C7000227D26 /* PopupAnimators.swift in Sources */,
30A87A4D2FEE1DB40095E7C6 /* ItineraryDetailView.swift in Sources */, 30A87A4D2FEE1DB40095E7C6 /* ItineraryDetailView.swift in Sources */,
305A769C2FCA8C7000227D26 /* PopupViewController.swift in Sources */, 305A769C2FCA8C7000227D26 /* PopupViewController.swift in Sources */,
305A769D2FCA8C7000227D26 /* PopupViewController+Extension.swift in Sources */, 305A769D2FCA8C7000227D26 /* PopupViewController+Extension.swift in Sources */,
30EFF3C42FDA431D00EB35D4 /* ChangePhoneVC.swift in Sources */, 30EFF3C42FDA431D00EB35D4 /* ChangePhoneVC.swift in Sources */,
30C6666C2FFB7C4000E62B25 /* IAPManager.swift in Sources */,
305A769E2FCA8C7000227D26 /* TextArrowCell.swift in Sources */, 305A769E2FCA8C7000227D26 /* TextArrowCell.swift in Sources */,
305A769F2FCA8C7000227D26 /* TextContentArrowCell.swift in Sources */, 305A769F2FCA8C7000227D26 /* TextContentArrowCell.swift in Sources */,
30D87D042FE1336300E958FD /* NavigationVC.swift in Sources */, 30D87D042FE1336300E958FD /* NavigationVC.swift in Sources */,
30D87D052FE1336300E958FD /* NavigationView.swift in Sources */, 30D87D052FE1336300E958FD /* NavigationView.swift in Sources */,
30B819F42FF3CE4900FAB693 /* ItineraryTraceVC.swift in Sources */, 30B819F42FF3CE4900FAB693 /* ItineraryTraceVC.swift in Sources */,
305A76A02FCA8C7000227D26 /* TextTableViewCell.swift in Sources */, 305A76A02FCA8C7000227D26 /* TextTableViewCell.swift in Sources */,
30ACD67B2FF7B36A00174861 /* PopupQueueManager.swift in Sources */,
305A76A12FCA8C7000227D26 /* UIButton+RTL.m in Sources */, 305A76A12FCA8C7000227D26 /* UIButton+RTL.m in Sources */,
30EFF3A62FD7C5AF00EB35D4 /* GroupSettingVC.swift in Sources */, 30EFF3A62FD7C5AF00EB35D4 /* GroupSettingVC.swift in Sources */,
55CA15103058EBE5000F1189 /* InteractionEmojiCell.swift in Sources */,
305A76A22FCA8C7000227D26 /* Array+Extension.swift in Sources */, 305A76A22FCA8C7000227D26 /* Array+Extension.swift in Sources */,
305A76A32FCA8C7000227D26 /* ControlEvents+Block.swift in Sources */, 305A76A32FCA8C7000227D26 /* ControlEvents+Block.swift in Sources */,
3062E8B72FCE6BFE00CEF511 /* ScanView.swift in Sources */, 3062E8B72FCE6BFE00CEF511 /* ScanView.swift in Sources */,
305A76A42FCA8C7000227D26 /* Date+Extension.swift in Sources */, 305A76A42FCA8C7000227D26 /* Date+Extension.swift in Sources */,
30D74AAE2FEA13E00050EB2C /* ScheduleView.swift in Sources */,
305A76A52FCA8C7000227D26 /* Dictionay+Extension.swift in Sources */, 305A76A52FCA8C7000227D26 /* Dictionay+Extension.swift in Sources */,
30A87A522FEE4E5D0095E7C6 /* ScheduleHistoryVC.swift in Sources */, 30A87A522FEE4E5D0095E7C6 /* ScheduleHistoryVC.swift in Sources */,
305A76A62FCA8C7000227D26 /* Int+Extension.swift in Sources */, 305A76A62FCA8C7000227D26 /* Int+Extension.swift in Sources */,
@ -2566,9 +2507,11 @@
55B234013036000100785051 /* RelationSelectPopVC.swift in Sources */, 55B234013036000100785051 /* RelationSelectPopVC.swift in Sources */,
55B234033036000100785053 /* RelationStore.swift in Sources */, 55B234033036000100785053 /* RelationStore.swift in Sources */,
55B220013031000100784801 /* FeedbackVC.swift in Sources */, 55B220013031000100784801 /* FeedbackVC.swift in Sources */,
55CA15123058EC23000F1189 /* InteractionView.swift in Sources */,
55B220033031000100784803 /* FeedbackView.swift in Sources */, 55B220033031000100784803 /* FeedbackView.swift in Sources */,
55B220053031000100784805 /* FeedbackSuccessView.swift in Sources */, 55B220053031000100784805 /* FeedbackSuccessView.swift in Sources */,
55B221210000000100784821 /* MoodStatusVC.swift in Sources */, 55B221210000000100784821 /* MoodStatusVC.swift in Sources */,
55CA150E3058E55E000F1189 /* ScheduleViewModel.swift in Sources */,
55B221230000000100784823 /* MoodStatusView.swift in Sources */, 55B221230000000100784823 /* MoodStatusView.swift in Sources */,
55B222010000000100784831 /* AddEmojiPopView.swift in Sources */, 55B222010000000100784831 /* AddEmojiPopView.swift in Sources */,
55B222030000000100784833 /* AddMessagePopView.swift in Sources */, 55B222030000000100784833 /* AddMessagePopView.swift in Sources */,
@ -2588,7 +2531,6 @@
305A76C72FCA8C7000227D26 /* UserConfigModel.swift in Sources */, 305A76C72FCA8C7000227D26 /* UserConfigModel.swift in Sources */,
30B74B472FF3608600F6744D /* ScheduleRecordModel.swift in Sources */, 30B74B472FF3608600F6744D /* ScheduleRecordModel.swift in Sources */,
305A76C82FCA8C7000227D26 /* UserConfigResponse.swift in Sources */, 305A76C82FCA8C7000227D26 /* UserConfigResponse.swift in Sources */,
30ACD54C2FF6336000174861 /* PopupWindow.swift in Sources */,
305A76C92FCA8C7000227D26 /* ApiManager.swift in Sources */, 305A76C92FCA8C7000227D26 /* ApiManager.swift in Sources */,
305A76CA2FCA8C7000227D26 /* AppSettings.swift in Sources */, 305A76CA2FCA8C7000227D26 /* AppSettings.swift in Sources */,
305A76CB2FCA8C7000227D26 /* Authorize.swift in Sources */, 305A76CB2FCA8C7000227D26 /* Authorize.swift in Sources */,
@ -2596,7 +2538,6 @@
30C6679E2FFB7FEF00E62B25 /* SharePopView.swift in Sources */, 30C6679E2FFB7FEF00E62B25 /* SharePopView.swift in Sources */,
305A76CC2FCA8C7000227D26 /* FileTools.swift in Sources */, 305A76CC2FCA8C7000227D26 /* FileTools.swift in Sources */,
305A76CD2FCA8C7000227D26 /* Permission.swift in Sources */, 305A76CD2FCA8C7000227D26 /* Permission.swift in Sources */,
30D74AB02FEA13ED0050EB2C /* ScheduleVC.swift in Sources */,
55B218B13024B00100784722 /* FeatureIntroVC.swift in Sources */, 55B218B13024B00100784722 /* FeatureIntroVC.swift in Sources */,
55B218B13024B00100784724 /* FeatureIntroView.swift in Sources */, 55B218B13024B00100784724 /* FeatureIntroView.swift in Sources */,
305A76CE2FCA8C7000227D26 /* RouterManager.swift in Sources */, 305A76CE2FCA8C7000227D26 /* RouterManager.swift in Sources */,
@ -2641,7 +2582,6 @@
55B250043038000100786504 /* MailboxView.swift in Sources */, 55B250043038000100786504 /* MailboxView.swift in Sources */,
55B250063038000100786506 /* MailboxViewController.swift in Sources */, 55B250063038000100786506 /* MailboxViewController.swift in Sources */,
55B250083038000100786508 /* MailboxDetailViewController.swift in Sources */, 55B250083038000100786508 /* MailboxDetailViewController.swift in Sources */,
30D74AB22FEA1D5D0050EB2C /* ScheduleViewModel.swift in Sources */,
30EFF3B52FD8F1D000EB35D4 /* ReviewMemberListVC.swift in Sources */, 30EFF3B52FD8F1D000EB35D4 /* ReviewMemberListVC.swift in Sources */,
30BAB84D2FCD2FDE00C33B5C /* InviteJoinView.swift in Sources */, 30BAB84D2FCD2FDE00C33B5C /* InviteJoinView.swift in Sources */,
30A87A592FEE5A4C0095E7C6 /* ScheduleViewedView.swift in Sources */, 30A87A592FEE5A4C0095E7C6 /* ScheduleViewedView.swift in Sources */,
@ -2649,10 +2589,7 @@
30CCDE5C2FE3A1A800F5214A /* SOSPracticeView.swift in Sources */, 30CCDE5C2FE3A1A800F5214A /* SOSPracticeView.swift in Sources */,
30EFF3E52FDAA93400EB35D4 /* PrivacyPolicyVC.swift in Sources */, 30EFF3E52FDAA93400EB35D4 /* PrivacyPolicyVC.swift in Sources */,
305A76E22FCA8C7000227D26 /* GroupViewModel.swift in Sources */, 305A76E22FCA8C7000227D26 /* GroupViewModel.swift in Sources */,
30CCDE4E2FE26CEA00F5214A /* PayResultPopVC.swift in Sources */,
305A76E32FCA8C7000227D26 /* GroupMemberView.swift in Sources */,
30BAB84F2FCD2FED00C33B5C /* InviteJoinVC.swift in Sources */, 30BAB84F2FCD2FED00C33B5C /* InviteJoinVC.swift in Sources */,
305A76E42FCA8C7000227D26 /* HomeView.swift in Sources */,
305A76E52FCA8C7000227D26 /* HomeViewController.swift in Sources */, 305A76E52FCA8C7000227D26 /* HomeViewController.swift in Sources */,
305A76E62FCA8C7000227D26 /* LaunchViewController.swift in Sources */, 305A76E62FCA8C7000227D26 /* LaunchViewController.swift in Sources */,
3062E8B52FCE6BBA00CEF511 /* ScanVC.swift in Sources */, 3062E8B52FCE6BBA00CEF511 /* ScanVC.swift in Sources */,
@ -2722,16 +2659,13 @@
305A77032FCA8C7000227D26 /* ProgressHUD.swift in Sources */, 305A77032FCA8C7000227D26 /* ProgressHUD.swift in Sources */,
305A77042FCA8C7000227D26 /* MXParallaxHeader.m in Sources */, 305A77042FCA8C7000227D26 /* MXParallaxHeader.m in Sources */,
305A77052FCA8C7000227D26 /* MXScrollView.m in Sources */, 305A77052FCA8C7000227D26 /* MXScrollView.m in Sources */,
30D87CDD2FDFF07500E958FD /* InteractionView.swift in Sources */,
30BAB8652FCD718A00C33B5C /* JoinGroupView.swift in Sources */, 30BAB8652FCD718A00C33B5C /* JoinGroupView.swift in Sources */,
305A77062FCA8C7000227D26 /* MXScrollViewController.m in Sources */, 305A77062FCA8C7000227D26 /* MXScrollViewController.m in Sources */,
30B74B432FF2438800F6744D /* GroupMemberListView.swift in Sources */, 30B74B432FF2438800F6744D /* GroupMemberListView.swift in Sources */,
305A77072FCA8C7000227D26 /* Helper.swift in Sources */, 305A77072FCA8C7000227D26 /* Helper.swift in Sources */,
30BF30102FED0C8E00D9CB52 /* ScheduleDetailVM.swift in Sources */, 30BF30102FED0C8E00D9CB52 /* ScheduleDetailVM.swift in Sources */,
30DA36BD2FECC5AB008D5A2C /* CreateScheduleVipPopView.swift in Sources */,
305A77082FCA8C7000227D26 /* PageCollectionViewFlowLayout.swift in Sources */, 305A77082FCA8C7000227D26 /* PageCollectionViewFlowLayout.swift in Sources */,
55BF752D2FFE53F70055DA57 /* LocationPermissionPopView.swift in Sources */, 55BF752D2FFE53F70055DA57 /* LocationPermissionPopView.swift in Sources */,
3062E8C42FCFC90F00CEF511 /* CreateGroupVipPopView.swift in Sources */,
30D74ABA2FEA37AD0050EB2C /* ScheduleModel.swift in Sources */, 30D74ABA2FEA37AD0050EB2C /* ScheduleModel.swift in Sources */,
30CCDE512FE2785D00F5214A /* SignInVC.swift in Sources */, 30CCDE512FE2785D00F5214A /* SignInVC.swift in Sources */,
305A77092FCA8C7000227D26 /* PageContentView.swift in Sources */, 305A77092FCA8C7000227D26 /* PageContentView.swift in Sources */,
@ -2739,7 +2673,6 @@
305A770B2FCA8C7000227D26 /* PageTitleView.swift in Sources */, 305A770B2FCA8C7000227D26 /* PageTitleView.swift in Sources */,
305A770C2FCA8C7000227D26 /* PageView.swift in Sources */, 305A770C2FCA8C7000227D26 /* PageView.swift in Sources */,
305A770D2FCA8C7000227D26 /* PageViewManager.swift in Sources */, 305A770D2FCA8C7000227D26 /* PageViewManager.swift in Sources */,
30D891F52FE22E0600E958FD /* OrderAPI.swift in Sources */,
307073EA2FD2715A004C37CC /* GroupChatViewModel.swift in Sources */, 307073EA2FD2715A004C37CC /* GroupChatViewModel.swift in Sources */,
305A770E2FCA8C7000227D26 /* DLAlertPopVC.swift in Sources */, 305A770E2FCA8C7000227D26 /* DLAlertPopVC.swift in Sources */,
305A770F2FCA8C7000227D26 /* DLCustomPopVC.swift in Sources */, 305A770F2FCA8C7000227D26 /* DLCustomPopVC.swift in Sources */,
@ -2751,7 +2684,6 @@
30EFF3B72FD8F86200EB35D4 /* ReviewMemberListVM.swift in Sources */, 30EFF3B72FD8F86200EB35D4 /* ReviewMemberListVM.swift in Sources */,
305A77112FCA8C7000227D26 /* DLViewTransition.m in Sources */, 305A77112FCA8C7000227D26 /* DLViewTransition.m in Sources */,
3062E8BA2FCEAC6500CEF511 /* CreateGroupView.swift in Sources */, 3062E8BA2FCEAC6500CEF511 /* CreateGroupView.swift in Sources */,
30D891F72FE22E6E00E958FD /* OrderService.swift in Sources */,
305A77192FCA8C7000227D26 /* CollectionHFlowLayout.swift in Sources */, 305A77192FCA8C7000227D26 /* CollectionHFlowLayout.swift in Sources */,
30D74AC12FEA6EEF0050EB2C /* CreateSchedulePopView.swift in Sources */, 30D74AC12FEA6EEF0050EB2C /* CreateSchedulePopView.swift in Sources */,
305A771A2FCA8C7000227D26 /* JJPageControl.swift in Sources */, 305A771A2FCA8C7000227D26 /* JJPageControl.swift in Sources */,
@ -2897,7 +2829,7 @@
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2; CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = LRDLWZ2Y83; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = LRDLWZ2Y83;
ENABLE_USER_SCRIPT_SANDBOXING = "$(inherited)"; ENABLE_USER_SCRIPT_SANDBOXING = "$(inherited)";
@ -2952,7 +2884,7 @@
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2; CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = LRDLWZ2Y83; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = LRDLWZ2Y83;
ENABLE_USER_SCRIPT_SANDBOXING = "$(inherited)"; ENABLE_USER_SCRIPT_SANDBOXING = "$(inherited)";
@ -3185,7 +3117,7 @@
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual; CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2; CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = LRDLWZ2Y83; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = LRDLWZ2Y83;
ENABLE_USER_SCRIPT_SANDBOXING = "$(inherited)"; ENABLE_USER_SCRIPT_SANDBOXING = "$(inherited)";

View File

@ -151,12 +151,6 @@ enum GatewayStatusCode: Int {
// //
case review = 201 case review = 201
/** ============== ============== */
// vip
case needVip = 20000
//
case groupLimit = 20009
/** ============== ============== */ /** ============== ============== */
case unknownError = -9999 case unknownError = -9999
} }

View File

@ -1,77 +0,0 @@
//
// OrderAPI.swift
// QuickLocation
//
// Created by on 2026/6/17.
//
import Moya
import SwiftyUserDefaults
internal import Alamofire
/// API
enum OrderAPI {
///
/// - Parameters:
/// - type: member
case rechargeInfo(type: String)
///
/// - Parameters:
/// - goodsId: ID
/// - payType: alipayweixin
/// - source: center
/// - extra:
case orderPayParams(goodsId: String, payType: String, source: String, extra: [String:Any]=[:])
/// Apple
case appleNotify(receipt: String, productId: String, transactionId: String)
}
extension OrderAPI: MultiTargetProtocol {
var path: String {
switch self {
case .rechargeInfo:
return "api/order/goods"
case .orderPayParams:
return "api/order"
case .appleNotify:
return "api/order/notify/apple"
}
}
var method: Moya.Method {
switch self {
case .rechargeInfo:
return .get
default:
return .post
}
}
var task: Moya.Task {
switch self {
case let .rechargeInfo(type):
var params = Parameters()
params["type"] = type
return .requestParameters(parameters: params, encoding: URLEncoding())
case let .orderPayParams(goodsId, payType, source, extra):
var params = Parameters()
params["goods_id"] = goodsId
params["pay_type"] = payType
params["source"] = source
params["pay_source"] = "app"
params["extra"] = extra
return .requestParameters(parameters: params, encoding: JSONEncoding())
case let .appleNotify(receipt, productId, transactionId):
var params = Parameters()
params["receipt_data"] = receipt
params["product_id"] = productId
params["transaction_id"] = transactionId
return .requestParameters(parameters: params, encoding: JSONEncoding())
}
}
}

View File

@ -38,8 +38,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
SwiftDate.defaultRegion = Region(zone: TimeZone.current, locale: Locale.current) SwiftDate.defaultRegion = Region(zone: TimeZone.current, locale: Locale.current)
IAPManager.shared.startObserving()
IQKeyboardManager.shared.isEnabled = true IQKeyboardManager.shared.isEnabled = true
IQKeyboardManager.shared.enableAutoToolbar = false IQKeyboardManager.shared.enableAutoToolbar = false
IQKeyboardManager.shared.resignOnTouchOutside = true IQKeyboardManager.shared.resignOnTouchOutside = true
@ -91,25 +89,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
return true return true
} }
} }
return WXApi.handleOpen(url, delegate: self)
// host SDK
if url.scheme?.hasPrefix("Alipay") == true || url.host == "safepay" {
AlipaySDK.defaultService().processOrder(withPaymentResult: url) { resultDic in
print("📱 Alipay callback: \(resultDic ?? [:])")
guard let result = resultDic,
let resultStatus = result["resultStatus"] as? String,
resultStatus != "6001" else { return }
if resultStatus == "9000" {
NotificationCenter.default.post(name: .RequestOrderPayStatusNotification, object: nil)
}
}
return true
}
// else if url.host == "pay" {
return WXApi.handleOpen(url, delegate: self)
// }
//
// return true
} }
func application(_ application: UIApplication, func application(_ application: UIApplication,
@ -197,22 +177,5 @@ extension AppDelegate: WXApiDelegate {
handleWechatLoginCode(code) handleWechatLoginCode(code)
return return
} }
if resp.isKind(of: SendAuthResp.self) {
NotificationCenter.default.post(name: .resumePopupQueue, object: nil)
}
if resp.isKind(of: PayResp.self),
let response: PayResp = resp as? PayResp {
print("===================== WxPay =====================")
print(response.errStr)
if response.errCode == 0 { //
DispatchQueue.global().async {
DispatchQueue.main.async {
}
}
}
}
} }
} }

View File

@ -1,20 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -1,20 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -1,20 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -1,20 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -1,20 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 284 KiB

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 KiB

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 KiB

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 KiB

View File

@ -1,20 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -1,9 +0,0 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"provides-namespace" : true
}
}

View File

@ -1,20 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -1,20 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

View File

@ -1,20 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

View File

@ -1,20 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -1,20 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -1,9 +0,0 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"provides-namespace" : true
}
}

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 681 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,20 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -1,20 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,20 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

View File

@ -62,14 +62,7 @@ class AppContextManager: NSObject {
var sex: Int { var sex: Int {
account?.sex ?? -1 account?.sex ?? -1
} }
/// 1 2 3
var vip: Int {
guard AppContextManager.shared.systemConfig?.isIntercept == false else {
return 2
}
return account?.vip ?? 1
}
/// 0 1SOS 2 /// 0 1SOS 2
var status: Int { var status: Int {
account?.status ?? 0 account?.status ?? 0

View File

@ -32,12 +32,6 @@ struct UserConfigModel: Mappable {
/// ID /// ID
var uid: String? var uid: String?
/// 1 2 3
var vip: Int = 1
///
var vip_name: String = ""
///
var vip_expire_time: String = ""
/// 0 1SOS 2 /// 0 1SOS 2
var status: Int = 0 var status: Int = 0
/// 0 1 2 /// 0 1 2
@ -59,9 +53,6 @@ struct UserConfigModel: Mappable {
sex <- map["sex"] sex <- map["sex"]
head_pic <- (map["head_pic"], kFlexString) head_pic <- (map["head_pic"], kFlexString)
config <- map["config"] config <- map["config"]
vip <- map["vip"]
vip_name <- map["vip_name"]
vip_expire_time <- map["vip_expire_time"]
status <- map["status"] status <- map["status"]
mood <- map["mood"] mood <- map["mood"]
} }
@ -70,9 +61,9 @@ struct UserConfigModel: Mappable {
struct SystemConfigModel: Mappable { struct SystemConfigModel: Mappable {
/// ///
var popupConfig: PopupWindowConfigModel? // var popupConfig: PopupWindowConfigModel?
/// ///
var timeConfig: PopupWindowTimeModel? // var timeConfig: PopupWindowTimeModel?
/// ///
var shareConfig: WxShareConfigModel? var shareConfig: WxShareConfigModel?
/// ///
@ -89,17 +80,6 @@ struct SystemConfigModel: Mappable {
/// banner /// banner
var groupBannerList: [String] = [] var groupBannerList: [String] = []
///
var guideDisplay: Bool = true
///
var globalDisplay: Bool = true
///
var isIntercept: Bool {
return globalDisplay == false || !WXApi.isWXAppInstalled() //
}
init?(map: Map) { init?(map: Map) {
} }
@ -107,63 +87,14 @@ struct SystemConfigModel: Mappable {
mutating func mapping(map: Map) { mutating func mapping(map: Map) {
chatWarning <- map["client.chatwarning", nested: false] chatWarning <- map["client.chatwarning", nested: false]
groupBannerList <- map["client.team.ad", nested: false] groupBannerList <- map["client.team.ad", nested: false]
popupConfig <- map["client.popup.display", nested: false] // timeConfig <- map["client.time.setting", nested: false]
timeConfig <- map["client.time.setting", nested: false]
pigeonConfig <- map["client.time.setting.pigeon", nested: false] pigeonConfig <- map["client.time.setting.pigeon", nested: false]
shareConfig <- map["client.weixin.share", nested: false] shareConfig <- map["client.weixin.share", nested: false]
guideDisplay <- map["client.guide_display", nested: false]
globalDisplay <- map["client.global_display", nested: false]
versionUpgradeModel <- map["client.version.upgrade", nested: false] versionUpgradeModel <- map["client.version.upgrade", nested: false]
bannerList <- map["client.banner.explore", nested: false] bannerList <- map["client.banner.explore", nested: false]
} }
} }
struct PopupWindowConfigModel: Mappable {
/// vip
var pay_pop: Bool = true
///
var search_phone: Bool = true
init?(map: Map) {
}
mutating func mapping(map: Map) {
pay_pop <- map["pay_pop"]
search_phone <- map["search_phone"]
}
}
struct PopupWindowTimeModel: Mappable {
/// push
var buy_vip_tip: Int = 0
///
var search_phone: Int = 0
///
var signup_tip: Int = 0
/// vip
var pay_pop_time: Int = 0
/// vip
var min_discount: Double = 0
/// 1 2
var pay_pop_type: Int = 0
init?(map: Map) {
}
mutating func mapping(map: Map) {
buy_vip_tip <- map["buy_vip_tip"]
search_phone <- map["search_phone"]
signup_tip <- map["signup_tip"]
pay_pop_time <- map["pay_pop_time"]
min_discount <- map["min_discount"]
pay_pop_type <- map["pay_pop_type"]
}
}
struct PigeonTimeSettingModel: Mappable { struct PigeonTimeSettingModel: Mappable {
/// ///
var nums: Int = 0 var nums: Int = 0
@ -237,7 +168,7 @@ struct VersionUpgradeModel: Mappable {
struct BannerConfigModel: Mappable { struct BannerConfigModel: Mappable {
/// ///
var img: String = "" var img: String = ""
/// url:member url: /// url:membercz url:
var url: String = "" var url: String = ""
/// app: web: /// app: web:
var type: String = "" var type: String = ""

View File

@ -114,8 +114,6 @@ extension ApiManager {
handleTokenExpired(msg: message) handleTokenExpired(msg: message)
case GatewayStatusCode.failure.rawValue, GatewayStatusCode.noAuthority.rawValue: // 退 case GatewayStatusCode.failure.rawValue, GatewayStatusCode.noAuthority.rawValue: // 退
handlePopView(message, handle) handlePopView(message, handle)
case GatewayStatusCode.needVip.rawValue:
handleNeedVip(message)
default: default:
// codesuccess // codesuccess
if success != nil { if success != nil {
@ -136,7 +134,6 @@ extension ApiManager {
return .failure(handleError(with: code, return .failure(handleError(with: code,
domain: "Data Error", domain: "Data Error",
message: message, message: message,
isShowTip: code != GatewayStatusCode.needVip.rawValue,
data: response)) data: response))
case let .failure(error): case let .failure(error):
let message = error.gatewayMessage ?? "请检查网络连接" let message = error.gatewayMessage ?? "请检查网络连接"
@ -197,14 +194,6 @@ extension ApiManager {
} }
} }
// MARK: - VIP
private func handleNeedVip(_ msg: String) {
MainAsync {
UIViewController.showConfirmPop(title: "温馨提示", message: msg, confirmText: "去开通", confirmBlock: {
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
}, cancelText: "取消")
}
}
} }
extension ApiManager { extension ApiManager {

View File

@ -1,81 +0,0 @@
//
// IAPManager.swift
// QuickLocation
//
// Created by on 2026/7/3.
//
import StoreKit
import RxSwift
class IAPManager: NSObject {
static let shared = IAPManager()
private let disposeBag = DisposeBag()
private var currentGoodsId: String = ""
private var purchaseCompletion: ((Bool, String?) -> Void)?
func startObserving() {
SKPaymentQueue.default().add(self)
}
func purchase(goodsId: String, completion: @escaping (Bool, String?) -> Void) {
currentGoodsId = goodsId
purchaseCompletion = completion
let request = SKProductsRequest(productIdentifiers: [goodsId])
request.delegate = self
request.start()
}
}
// MARK: - SKProductsRequestDelegate
extension IAPManager: SKProductsRequestDelegate {
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
guard let product = response.products.first else {
purchaseCompletion?(false, "商品不可用")
return
}
SKPaymentQueue.default().add(SKPayment(product: product))
}
}
// MARK: - SKPaymentTransactionObserver
extension IAPManager: SKPaymentTransactionObserver {
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for tx in transactions {
switch tx.transactionState {
case .purchased:
verifyReceipt(transaction: tx)
case .failed:
queue.finishTransaction(tx)
let msg = tx.error?.localizedDescription ?? "支付失败"
purchaseCompletion?(false, msg)
default:
break
}
}
}
private func verifyReceipt(transaction: SKPaymentTransaction) {
guard let receiptURL = Bundle.main.appStoreReceiptURL,
let receiptData = try? Data(contentsOf: receiptURL) else {
SKPaymentQueue.default().finishTransaction(transaction)
purchaseCompletion?(false, "获取凭证失败")
return
}
let receipt = receiptData.base64EncodedString()
let txId = transaction.transactionIdentifier ?? ""
OrderService.appleNotify(
receipt: receipt,
productId: currentGoodsId,
transactionId: txId
).subscribe(onNext: { [weak self] _ in
SKPaymentQueue.default().finishTransaction(transaction)
self?.purchaseCompletion?(true, nil)
}, onError: { [weak self] error in
SKPaymentQueue.default().finishTransaction(transaction)
self?.purchaseCompletion?(false, error.localizedDescription)
}).disposed(by: disposeBag)
}
}

View File

@ -92,7 +92,6 @@ struct GroupUsersResponse: BaseModelProtocol {
var message: String? var message: String?
var model: GroupInfoModel? var model: GroupInfoModel?
var list: [GroupMemberModel] = [] var list: [GroupMemberModel] = []
var vip = GroupMemberVip()
var reviewCount: Int = 0 var reviewCount: Int = 0
init?(map: Map) {} init?(map: Map) {}
@ -102,7 +101,6 @@ struct GroupUsersResponse: BaseModelProtocol {
message <- map["message"] message <- map["message"]
model <- map["data.group"] model <- map["data.group"]
list <- map["data.mates"] list <- map["data.mates"]
vip <- map["data.vip"]
reviewCount <- (map["data.reviewCount"], kStrTransformInt) reviewCount <- (map["data.reviewCount"], kStrTransformInt)
if reviewCount == 0 { if reviewCount == 0 {
reviewCount <- (map["data.review_count"], kStrTransformInt) reviewCount <- (map["data.review_count"], kStrTransformInt)
@ -231,7 +229,7 @@ struct GroupInfoModel: Mappable, Equatable {
var people_no: Int = 0 var people_no: Int = 0
/// ///
var description: String = "" var description: String = ""
/// ///
var level: String = "" var level: String = ""
/// ///
var share_code: String = "" var share_code: String = ""
@ -288,27 +286,6 @@ struct GroupPrivilege: Mappable, Equatable {
} }
} }
struct GroupMemberVip: Mappable, Equatable {
var app_usage_record: Bool?
var phone_report: Bool?
var trip_analysis_others: Bool?
var app_lock: Bool?
var pigeon_mail: Bool?
var view_phone: Bool?
init() {}
init?(map: Map) {}
mutating func mapping(map: Map) {
app_usage_record <- (map["app_usage_record"], kOptionalFlexibleBool)
phone_report <- (map["phone_report"], kOptionalFlexibleBool)
trip_analysis_others <- (map["trip_analysis_others"], kOptionalFlexibleBool)
app_lock <- (map["app_lock"], kOptionalFlexibleBool)
pigeon_mail <- (map["pigeon_mail"], kOptionalFlexibleBool)
view_phone <- (map["view_phone"], kOptionalFlexibleBool)
}
}
private let kFlexibleBool = TransformOf<Bool, Any>(fromJSON: { value in private let kFlexibleBool = TransformOf<Bool, Any>(fromJSON: { value in
switch value { switch value {
case let value as Bool: case let value as Bool:
@ -327,31 +304,6 @@ private let kFlexibleBool = TransformOf<Bool, Any>(fromJSON: { value in
value value
}) })
private let kOptionalFlexibleBool = TransformOf<Bool, Any>(fromJSON: { value in
switch value {
case let value as Bool:
return value
case let value as NSNumber:
return value.boolValue
case let value as Int:
return value != 0
case let value as String:
let text = value.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
switch text {
case "1", "true", "yes":
return true
case "0", "false", "no":
return false
default:
return nil
}
default:
return nil
}
}, toJSON: { value in
value
})
extension UIImageView { extension UIImageView {
@MainActor @MainActor
func setGroupIcon(_ model: GroupInfoModel) { func setGroupIcon(_ model: GroupInfoModel) {
@ -470,11 +422,6 @@ struct GroupMemberModel: Mappable, Equatable {
remark.isEmpty ? nick_name : remark remark.isEmpty ? nick_name : remark
} }
/// 1 2 3 4
var level: Int = 1
var shouldShowVipAvatarFrame: Bool {
AppContextManager.shared.systemConfig?.isIntercept != true && level != 1
}
/// 0 1SOS 2 /// 0 1SOS 2
var status: Int = 0 var status: Int = 0
/// ///
@ -530,7 +477,6 @@ struct GroupMemberModel: Mappable, Equatable {
if avater.isEmpty { if avater.isEmpty {
avater <- (map["avatar"], kFlexString) avater <- (map["avatar"], kFlexString)
} }
level <- (map["level"], kStrTransformInt)
nick_name <- map["nick_name"] nick_name <- map["nick_name"]
remark <- map["remark"] remark <- map["remark"]
battery <- map["battery"] battery <- map["battery"]

View File

@ -1 +0,0 @@
{"v":"5.12.1","fr":25,"ip":0,"op":110,"w":375,"h":375,"nm":"合成 1","ddd":0,"assets":[{"id":"image_0","w":480,"h":480,"u":"images/","p":"dialog_buy_vip3_img_0.png","e":0},{"id":"image_1","w":192,"h":160,"u":"images/","p":"dialog_buy_vip3_img_1.png","e":0}],"layers":[{"ddd":0,"ind":1,"ty":2,"nm":"image 112.png","cl":"png","refId":"image_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[306,117.5,0],"to":[0,0,0],"ti":[117,4,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18.462,"s":[226,248,0],"to":[-117,-4,0],"ti":[-39.5,36,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":36.923,"s":[125,136,0],"to":[6.063,-5.526,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":55.385,"s":[232.5,144,0],"to":[0,0,0],"ti":[140.5,-22,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":73.846,"s":[167.5,284,0],"to":[-140.5,22,0],"ti":[-39.436,13.632,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":92.308,"s":[73.5,227,0],"to":[40.5,-14,0],"ti":[-22,-19,0]},{"t":110.76953125,"s":[212.5,285.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[243.995,243.45,0],"ix":1,"l":2},"s":{"a":0,"k":[11.792,11.792,100],"ix":6,"l":2}},"ao":1,"ip":0,"op":126,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":2,"nm":"图层 30 1.png","cl":"png","refId":"image_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[195,210.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18.445,"s":[195,181.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":22,"s":[195,197.089,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":36.892,"s":[195,210.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":55.337,"s":[195,181.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":73.783,"s":[195,210.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":92.229,"s":[195,181.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":110.673828125,"s":[195,210.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[96,80,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":126,"st":0,"bm":0}],"markers":[],"props":{}}

View File

@ -35,8 +35,7 @@ final class FeatureIntroVC: BaseViewController {
super.viewDidAppear(animated) super.viewDidAppear(animated)
rootView.reloadFeatureItems() rootView.reloadFeatureItems()
guard AppContextManager.shared.systemConfig?.isIntercept == false, guard let config = AppContextManager.shared.systemConfig else { return }
let config = AppContextManager.shared.systemConfig else { return }
bannerList = config.bannerList bannerList = config.bannerList
rootView.cycleScrollView.isHidden = config.bannerList.filter { $0.enable == true }.count == 0 rootView.cycleScrollView.isHidden = config.bannerList.filter { $0.enable == true }.count == 0
rootView.cycleScrollView.imageURLStringsGroup = config.bannerList.filter { $0.enable == true }.map { $0.img } rootView.cycleScrollView.imageURLStringsGroup = config.bannerList.filter { $0.enable == true }.map { $0.img }
@ -58,7 +57,6 @@ final class FeatureIntroVC: BaseViewController {
case .pigeonMessage: case .pigeonMessage:
AppRouter.push(Route.pigeonMessage) AppRouter.push(Route.pigeonMessage)
case .searchLocation: case .searchLocation:
guard AppContextManager.shared.systemConfig?.isIntercept != true else { return }
AppRouter.push(Route.searchLocation) AppRouter.push(Route.searchLocation)
case .sos: case .sos:
AppRouter.push(Route.sos) AppRouter.push(Route.sos)

View File

@ -154,8 +154,7 @@ final class FeatureIntroView: UIView {
} }
func reloadFeatureItems() { func reloadFeatureItems() {
let hideSearch = AppContextManager.shared.systemConfig?.isIntercept == true displayedItems = Self.allItems
displayedItems = Self.allItems.filter { !hideSearch || $0.action != .searchLocation }
rebuildGrid() rebuildGrid()
} }

View File

@ -128,15 +128,7 @@ class CreateGroupViewModel {
"labels": selectedTagList]).subscribe(onNext: { [weak self] _ in "labels": selectedTagList]).subscribe(onNext: { [weak self] _ in
self?.createSucceeded.accept(()) self?.createSucceeded.accept(())
}, onError: { (error) in }, onError: { (error) in
guard let code = error.underlyingError?.code else { return } DLToast.show(error)
guard let systemConfig = AppContextManager.shared.systemConfig, systemConfig.isIntercept == false else { return }
if code == 20009 { // ""
CreateGroupVipPopView.show()
}
else {
DLToast.show(error)
}
}).disposed(by: disposeBag) }).disposed(by: disposeBag)
} }

View File

@ -1,120 +0,0 @@
//
// CreateGroupVipPopView.swift
// QuickLocation
//
// Created by on 2026/6/3.
//
import UIKit
import RxSwift
import RxCocoa
class CreateGroupVipPopView: UIView {
private static let shared = CreateGroupVipPopView(frame: CGRect(origin: .zero, size: kScreenSize))
var disposeBag = DisposeBag()
static func show() {
guard let superView = kKeyWindow else {
return
}
if CreateGroupVipPopView.shared.superview != nil {
CreateGroupVipPopView.shared.removeFromSuperview()
CreateGroupVipPopView.shared.bgView.frame = .zero
}
CreateGroupVipPopView.shared.bgView.alpha = 1
CreateGroupVipPopView.shared.bgView.frame = CGRect(x: 0, y: 0, width: kScreenWidth, height: kScreenHeight)
superView.addSubview(CreateGroupVipPopView.shared)
superView.bringSubviewToFront(CreateGroupVipPopView.shared)
UIView.animate(withDuration: 0.25) {
CreateGroupVipPopView.shared.bgView.alpha = 1
}
}
///
static func dismiss() {
guard CreateGroupVipPopView.shared.superview != nil else { return }
UIView.animate(withDuration: 0.25, delay: 0, options: [.curveEaseIn]) {
CreateGroupVipPopView.shared.bgView.alpha = 0
} completion: { _ in
CreateGroupVipPopView.shared.removeFromSuperview()
}
}
private func setupRx() {
upgradedBtn.rx.tap.subscribe(onNext: { _ in
CreateGroupVipPopView.dismiss()
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
}).disposed(by: disposeBag)
closeBtn.rx.tap.subscribe(onNext: { _ in
CreateGroupVipPopView.dismiss()
}).disposed(by: disposeBag)
}
private lazy var bgView: UIView = {
let view = UIView()
view.backgroundColor = .black.withAlphaComponent(0.5)
return view
}()
lazy var vipImgView: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "Group/vip_pop")
view.contentMode = .scaleAspectFill
return view
}()
lazy var upgradedBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.backgroundColor = .clear
btn.setBackgroundImage(UIImage(named: "Group/upgrade_bg"), for: .normal)
return btn
}()
lazy var closeBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.backgroundColor = .clear
btn.setBackgroundImage(UIImage(named: "Group/close"), for: .normal)
btn.extendEdgeInsets = UIEdgeInsets(top: 10, left: 100, bottom: 100, right: 100)
return btn
}()
// MARK: - Init
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .clear
addSubview(bgView)
bgView.addSubview(vipImgView)
bgView.addSubview(upgradedBtn)
bgView.addSubview(closeBtn)
vipImgView.layoutChain
.centerY()
.edgesHorzontal(25)
.heightToWidth(814/648)
upgradedBtn.layoutChain
.topToBottomOfView(vipImgView, offset: -20)
.centerX()
.width(240)
.height(60)
closeBtn.layoutChain
.topToBottomOfView(upgradedBtn, offset: 15)
.centerX()
.width(22)
.height(22)
setupRx()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@ -96,7 +96,6 @@ final class GroupChatVC: BaseViewController {
setupKeyboard() setupKeyboard()
IQKeyboardManager.shared.isEnabled = false IQKeyboardManager.shared.isEnabled = false
IQKeyboardManager.shared.resignOnTouchOutside = false IQKeyboardManager.shared.resignOnTouchOutside = false
rootView.updateVipMediaAccess(isUnlocked: isVipUnlocked)
} }
override func viewWillDisappear(_ animated: Bool) { override func viewWillDisappear(_ animated: Bool) {
@ -292,7 +291,6 @@ final class GroupChatVC: BaseViewController {
rootView.bringSubviewToFront(rootView.mentionPickerView) rootView.bringSubviewToFront(rootView.mentionPickerView)
rootView.bringSubviewToFront(rootView.quoteBar) rootView.bringSubviewToFront(rootView.quoteBar)
rootView.bringSubviewToFront(rootView.bottomBar) rootView.bringSubviewToFront(rootView.bottomBar)
rootView.bringSubviewToFront(rootView.disableIMView)
rootView.bringSubviewToFront(rootView.voiceRecordView) rootView.bringSubviewToFront(rootView.voiceRecordView)
} }
@ -580,18 +578,6 @@ final class GroupChatVC: BaseViewController {
} }
// MARK: - Actions // MARK: - Actions
private var isVipUnlocked: Bool {
return AppContextManager.shared.vip > 1
}
private func requireVipForMedia() -> Bool {
guard isVipUnlocked else {
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
return false
}
return true
}
private func reactiveAction() { private func reactiveAction() {
rootView.backBtn.rx.tap rootView.backBtn.rx.tap
.subscribe(onNext: { _ in .subscribe(onNext: { _ in
@ -641,7 +627,7 @@ final class GroupChatVC: BaseViewController {
rootView.galleryBtn.rx.tap rootView.galleryBtn.rx.tap
.subscribe(onNext: { [weak self] in .subscribe(onNext: { [weak self] in
guard let self, self.requireVipForMedia() else { return } guard let self else { return }
self.rootView.dismissAllPanels() self.rootView.dismissAllPanels()
self.showAlbum() self.showAlbum()
}) })
@ -649,7 +635,7 @@ final class GroupChatVC: BaseViewController {
rootView.cameraBtn.rx.tap rootView.cameraBtn.rx.tap
.subscribe(onNext: { [weak self] in .subscribe(onNext: { [weak self] in
guard let self, self.requireVipForMedia() else { return } guard let self else { return }
self.rootView.dismissAllPanels() self.rootView.dismissAllPanels()
self.showCamera() self.showCamera()
}) })
@ -714,10 +700,9 @@ final class GroupChatVC: BaseViewController {
// MARK: - // MARK: -
private func showAlbum() { private func showAlbum() {
guard requireVipForMedia() else { return }
let picker = PhotoPickerVC(maxCount: 9) let picker = PhotoPickerVC(maxCount: 9)
picker.onConfirm = { [weak self] images in picker.onConfirm = { [weak self] images in
guard let self, self.requireVipForMedia() else { return } guard let self else { return }
for image in images { for image in images {
self.sendImageMessage(image) self.sendImageMessage(image)
} }
@ -726,7 +711,6 @@ final class GroupChatVC: BaseViewController {
} }
private func showCamera() { private func showCamera() {
guard requireVipForMedia() else { return }
guard UIImagePickerController.isSourceTypeAvailable(.camera) else { guard UIImagePickerController.isSourceTypeAvailable(.camera) else {
DLToast.showError(text: "当前设备不支持拍照") DLToast.showError(text: "当前设备不支持拍照")
return return
@ -769,11 +753,6 @@ final class GroupChatVC: BaseViewController {
private var currentVoiceHover: VoiceRecordView.HoverTarget = .none private var currentVoiceHover: VoiceRecordView.HoverTarget = .none
private func enterVoiceInputMode() { private func enterVoiceInputMode() {
guard isVipUnlocked else {
rootView.dismissAllPanels()
rootView.setVoiceInputMode(true)
return
}
let status = AVCaptureDevice.authorizationStatus(for: .audio) let status = AVCaptureDevice.authorizationStatus(for: .audio)
switch status { switch status {
case .authorized: case .authorized:
@ -857,7 +836,6 @@ final class GroupChatVC: BaseViewController {
} }
private func startVoiceRecording() { private func startVoiceRecording() {
guard requireVipForMedia() else { return }
guard !isVoiceRecording else { return } guard !isVoiceRecording else { return }
AudioServicesPlaySystemSound(1519) AudioServicesPlaySystemSound(1519)
currentVoiceHover = .none currentVoiceHover = .none
@ -972,11 +950,6 @@ final class GroupChatVC: BaseViewController {
} }
private func sendVoiceMessage(url: URL, durationMs: Int) { private func sendVoiceMessage(url: URL, durationMs: Int) {
guard requireVipForMedia() else {
deleteRecordFile()
rootView.voiceRecordView.reset()
return
}
GroupIMService.shared.sendGroupMessage(groupId: viewModel.groupId, GroupIMService.shared.sendGroupMessage(groupId: viewModel.groupId,
makeMessage: { makeMessage: {
OIMMessageInfo.createSoundMessage(fromFullPath: url.path, duration: durationMs) OIMMessageInfo.createSoundMessage(fromFullPath: url.path, duration: durationMs)
@ -1235,7 +1208,6 @@ private class MessageListenerProxy: NSObject, OIMAdvancedMsgListener {
extension GroupChatVC { extension GroupChatVC {
private func sendImageMessage(_ image: UIImage) { private func sendImageMessage(_ image: UIImage) {
guard requireVipForMedia() else { return }
let sendImage = image.cgImage != nil ? image.fixOrientation() : image let sendImage = image.cgImage != nil ? image.fixOrientation() : image
guard let data = sendImage.jpegData(compressionQuality: 0.8) else { return } guard let data = sendImage.jpegData(compressionQuality: 0.8) else { return }
let dir = NSTemporaryDirectory() let dir = NSTemporaryDirectory()

View File

@ -217,7 +217,6 @@ class GroupChatView: UIView {
/// ///
private var isVoiceInputMode = false private var isVoiceInputMode = false
private var isVipMediaUnlocked = true
func setVoiceInputMode(_ enabled: Bool) { func setVoiceInputMode(_ enabled: Bool) {
isVoiceInputMode = enabled isVoiceInputMode = enabled
@ -228,18 +227,6 @@ class GroupChatView: UIView {
refreshComposer() refreshComposer()
} }
func updateVipMediaAccess(isUnlocked: Bool) {
isVipMediaUnlocked = isUnlocked
let lockedBackground = isUnlocked ? nil : UIImage(named: "VipFeature/media_locked_bg")
galleryBtn.setBackgroundImage(lockedBackground, for: .normal)
cameraBtn.setBackgroundImage(lockedBackground, for: .normal)
galleryBtn.backgroundColor = isUnlocked ? .white : .clear
cameraBtn.backgroundColor = isUnlocked ? .white : .clear
voiceBtn.setImage(UIImage(named: "IM/voice_input"), for: .normal)
textField.placeholder = "发消息或者按住说话"
refreshComposer()
}
func refreshComposer() { func refreshComposer() {
let hasText = !(textField.text ?? "").trimmingCharacters(in: .whitespacesAndNewlines).isEmpty let hasText = !(textField.text ?? "").trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
textField.updatePlaceholderVisibility() textField.updatePlaceholderVisibility()
@ -292,9 +279,7 @@ class GroupChatView: UIView {
private func updateHoldSpeakAppearance() { private func updateHoldSpeakAppearance() {
var configuration = UIButton.Configuration.plain() var configuration = UIButton.Configuration.plain()
configuration.title = "按住 说话" configuration.title = "按住 说话"
configuration.image = isVipMediaUnlocked ? nil : UIImage(named: "VipFeature/crown")
configuration.imagePlacement = .leading configuration.imagePlacement = .leading
configuration.imagePadding = isVipMediaUnlocked ? 0 : 10
configuration.contentInsets = .zero configuration.contentInsets = .zero
configuration.baseForegroundColor = UIColor(hexStr: "#293445") configuration.baseForegroundColor = UIColor(hexStr: "#293445")
configuration.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { attributes in configuration.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { attributes in
@ -389,7 +374,6 @@ class GroupChatView: UIView {
addSubview(mentionPickerView) addSubview(mentionPickerView)
addSubview(quickActionBar) addSubview(quickActionBar)
addSubview(bottomBar) addSubview(bottomBar)
addSubview(disableIMView)
bottomBar.addSubview(bottomBarCornerView) bottomBar.addSubview(bottomBarCornerView)
addSubview(voiceRecordView) addSubview(voiceRecordView)
addSubview(emojiPanelView) addSubview(emojiPanelView)
@ -522,11 +506,6 @@ class GroupChatView: UIView {
bottomBarHeightConstraint = bottomBar.heightAnchor.constraint(equalToConstant: minimumBottomBarHeight) bottomBarHeightConstraint = bottomBar.heightAnchor.constraint(equalToConstant: minimumBottomBarHeight)
bottomBarHeightConstraint?.isActive = true bottomBarHeightConstraint?.isActive = true
disableIMView.layoutChain
.edgesHorzontal(15)
.height(50)
.bottom(kSafeBottomMargin)
bottomBarBottomConstraint = bottomBar.jh_constraint(.bottom, toAttribute: .bottom, otherView: bottomBar.superview, relation: .equal) bottomBarBottomConstraint = bottomBar.jh_constraint(.bottom, toAttribute: .bottom, otherView: bottomBar.superview, relation: .equal)
bottomBarCornerView.layoutChain.edges() bottomBarCornerView.layoutChain.edges()
@ -883,32 +862,6 @@ class GroupChatView: UIView {
return btn return btn
}() }()
/// IM
lazy var disableIMView: UIView = {
let view = UIView()
view.backgroundColor = .clear
view.layer.shadowColor = UIColor(hexStr: "#0F2846", alpha: 0.1).cgColor
view.layer.shadowOffset = CGSize(width: 0, height: 0)
view.layer.shadowOpacity = 1
view.layer.shadowRadius = 9
view.isHidden = true
let v = UIView()
v.backgroundColor = .white
v.cornerRadius = 25
view.addSubview(v)
v.layoutChain.edges()
let label = UILabel()
label.text = "开通VIP后可发送消息"
label.textColor = ThemeManager.shared.color.titleAuxColor
label.font = .systemFont(ofSize: 15, weight: .medium)
view.addSubview(label)
label.layoutChain.centerX().centerY()
return view
}()
/// ///
lazy var voiceRecordView: VoiceRecordView = { lazy var voiceRecordView: VoiceRecordView = {
let v = VoiceRecordView() let v = VoiceRecordView()

View File

@ -264,7 +264,6 @@ final class GroupMemberListCell: UICollectionViewCell {
nameLabel.text = model.showName nameLabel.text = model.showName
nameLabel.textColor = UIColor(hexStr: isCurrentUser ? "#16B3FF" : "#0F2846") nameLabel.textColor = UIColor(hexStr: isCurrentUser ? "#16B3FF" : "#0F2846")
selectionImageView.isHidden = !isSelected selectionImageView.isHidden = !isSelected
vipBackgroundView.isHidden = !model.shouldShowVipAvatarFrame
let isSOS = model.status == 1 let isSOS = model.status == 1
updateSOSBlink(isSOS) updateSOSBlink(isSOS)
@ -291,10 +290,9 @@ final class GroupMemberListCell: UICollectionViewCell {
contentView.addSubview(avatarImageView) contentView.addSubview(avatarImageView)
contentView.addSubview(bubbleImageView) contentView.addSubview(bubbleImageView)
contentView.addSubview(sosImageView) contentView.addSubview(sosImageView)
contentView.addSubview(vipBackgroundView)
contentView.addSubview(nameLabel) contentView.addSubview(nameLabel)
[selectionImageView, avatarImageView, bubbleImageView, sosImageView, vipBackgroundView, nameLabel].forEach { [selectionImageView, avatarImageView, bubbleImageView, sosImageView, nameLabel].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false $0.translatesAutoresizingMaskIntoConstraints = false
} }
@ -319,9 +317,6 @@ final class GroupMemberListCell: UICollectionViewCell {
sosImageView.trailingAnchor.constraint(equalTo: avatarImageView.trailingAnchor), sosImageView.trailingAnchor.constraint(equalTo: avatarImageView.trailingAnchor),
sosImageView.bottomAnchor.constraint(equalTo: avatarImageView.bottomAnchor), sosImageView.bottomAnchor.constraint(equalTo: avatarImageView.bottomAnchor),
vipBackgroundView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 7),
vipBackgroundView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
nameLabel.topAnchor.constraint(equalTo: avatarImageView.bottomAnchor, constant: 7), nameLabel.topAnchor.constraint(equalTo: avatarImageView.bottomAnchor, constant: 7),
nameLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), nameLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
nameLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor) nameLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
@ -360,12 +355,6 @@ final class GroupMemberListCell: UICollectionViewCell {
return view return view
}() }()
private lazy var vipBackgroundView: UIImageView = {
let view = UIImageView(image: UIImage(named: "GroupMemberList/vip"))
view.isHidden = true
return view
}()
private lazy var nameLabel: UILabel = { private lazy var nameLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.font = .systemFont(ofSize: 12, weight: .medium) label.font = .systemFont(ofSize: 12, weight: .medium)

View File

@ -1,120 +0,0 @@
//
// CreateBubblePopView.swift
// QuickLocation
//
// Created by on 2026/6/26.
//
import UIKit
import RxSwift
import RxCocoa
class CreateBubblePopView: UIView {
private static let shared = CreateBubblePopView(frame: CGRect(origin: .zero, size: kScreenSize))
var disposeBag = DisposeBag()
static func show() {
guard let superView = kKeyWindow else {
return
}
if CreateBubblePopView.shared.superview != nil {
CreateBubblePopView.shared.removeFromSuperview()
CreateBubblePopView.shared.bgView.frame = .zero
}
CreateBubblePopView.shared.bgView.alpha = 1
CreateBubblePopView.shared.bgView.frame = CGRect(x: 0, y: 0, width: kScreenWidth, height: kScreenHeight)
superView.addSubview(CreateBubblePopView.shared)
superView.bringSubviewToFront(CreateBubblePopView.shared)
UIView.animate(withDuration: 0.25) {
CreateBubblePopView.shared.bgView.alpha = 1
}
}
///
static func dismiss() {
guard CreateBubblePopView.shared.superview != nil else { return }
UIView.animate(withDuration: 0.25, delay: 0, options: [.curveEaseIn]) {
CreateBubblePopView.shared.bgView.alpha = 0
} completion: { _ in
CreateBubblePopView.shared.removeFromSuperview()
}
}
private func setupRx() {
upgradedBtn.rx.tap.subscribe(onNext: { _ in
CreateBubblePopView.dismiss()
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
}).disposed(by: disposeBag)
closeBtn.rx.tap.subscribe(onNext: { _ in
CreateBubblePopView.dismiss()
}).disposed(by: disposeBag)
}
private lazy var bgView: UIView = {
let view = UIView()
view.backgroundColor = .black.withAlphaComponent(0.5)
return view
}()
lazy var vipImgView: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "Bubble/vip_pop")
view.contentMode = .scaleAspectFill
return view
}()
lazy var upgradedBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.backgroundColor = .clear
btn.setBackgroundImage(UIImage(named: "Bubble/upgrade_bg"), for: .normal)
return btn
}()
lazy var closeBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.backgroundColor = .clear
btn.setBackgroundImage(UIImage(named: "Group/close"), for: .normal)
btn.extendEdgeInsets = UIEdgeInsets(top: 10, left: 100, bottom: 100, right: 100)
return btn
}()
// MARK: - Init
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .clear
addSubview(bgView)
bgView.addSubview(vipImgView)
bgView.addSubview(upgradedBtn)
bgView.addSubview(closeBtn)
vipImgView.layoutChain
.centerY()
.edgesHorzontal(25)
.heightToWidth(814/648)
upgradedBtn.layoutChain
.topToBottomOfView(vipImgView, offset: -20)
.centerX()
.width(240)
.height(60)
closeBtn.layoutChain
.topToBottomOfView(upgradedBtn, offset: 15)
.centerX()
.width(22)
.height(22)
setupRx()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@ -25,7 +25,6 @@ final class CreateBubbleSetupView: UIView {
private let subtitleLab = UILabel() private let subtitleLab = UILabel()
private let titleLab = UILabel() private let titleLab = UILabel()
private let hourPicker = BubbleHourPickerView() private let hourPicker = BubbleHourPickerView()
private let vipOfferImageView = UIImageView(image: UIImage(named: "VipFeature/limited_offer"))
private let sheetOverlay = UIView() private let sheetOverlay = UIView()
private let sheetPanel = UIView() private let sheetPanel = UIView()
@ -84,7 +83,6 @@ final class CreateBubbleSetupView: UIView {
addSubview(subtitleLab) addSubview(subtitleLab)
addSubview(hourPicker) addSubview(hourPicker)
addSubview(confirmBtn) addSubview(confirmBtn)
addSubview(vipOfferImageView)
heroView.showsOuterDecorBubbles = false heroView.showsOuterDecorBubbles = false
heroView.layoutChain heroView.layoutChain
@ -115,25 +113,6 @@ final class CreateBubbleSetupView: UIView {
confirmBtn.setBackgroundImage(UIImage(named: "Common/button_bg_2"), for: .normal) confirmBtn.setBackgroundImage(UIImage(named: "Common/button_bg_2"), for: .normal)
confirmBtn.cornerRadius = 20 confirmBtn.cornerRadius = 20
confirmBtn.layoutChain.left(30).right(30).bottom(34).height(56) confirmBtn.layoutChain.left(30).right(30).bottom(34).height(56)
vipOfferImageView.contentMode = .scaleAspectFit
vipOfferImageView.isHidden = true
vipOfferImageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
vipOfferImageView.trailingAnchor.constraint(equalTo: confirmBtn.trailingAnchor, constant: -6),
vipOfferImageView.bottomAnchor.constraint(equalTo: confirmBtn.topAnchor, constant: 10),
vipOfferImageView.widthAnchor.constraint(equalToConstant: 94),
vipOfferImageView.heightAnchor.constraint(equalToConstant: 32)
])
}
func updateVipAccess(isUnlocked: Bool) {
confirmBtn.setTitle(isUnlocked ? "确定" : "开通会员 解锁功能", for: .normal)
confirmBtn.setBackgroundImage(
UIImage(named: isUnlocked ? "Common/button_bg_2" : "VipFeature/wide_button_bg"),
for: .normal
)
vipOfferImageView.isHidden = isUnlocked
} }
private func setupSheet() { private func setupSheet() {

View File

@ -26,7 +26,6 @@ class CreateBubbleVC: BaseViewController {
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
rootView.updateVipAccess(isUnlocked: isVipUnlocked)
requestUserStatus() requestUserStatus()
} }
@ -49,10 +48,6 @@ class CreateBubbleVC: BaseViewController {
rootView.setupView.confirmBtn.rx.tap rootView.setupView.confirmBtn.rx.tap
.subscribe(onNext: { [weak self] in .subscribe(onNext: { [weak self] in
guard let self else { return } guard let self else { return }
guard self.isVipUnlocked else {
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
return
}
let hours = self.rootView.setupView.selectedHour.value let hours = self.rootView.setupView.selectedHour.value
let message = self.rootView.setupView.buildMessage(for: hours) let message = self.rootView.setupView.buildMessage(for: hours)
self.rootView.setupView.showNotifySheet(message: message) self.rootView.setupView.showNotifySheet(message: message)
@ -85,19 +80,10 @@ class CreateBubbleVC: BaseViewController {
} }
private func submitCreate() { private func submitCreate() {
guard isVipUnlocked else {
rootView.setupView.dismissNotifySheet()
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
return
}
let hours = rootView.setupView.selectedHour.value let hours = rootView.setupView.selectedHour.value
requestSetBubble(enable: true, keep_time: hours) requestSetBubble(enable: true, keep_time: hours)
} }
private var isVipUnlocked: Bool {
return AppContextManager.shared.vip > 1
}
private func restoreCachedBubbleIfNeeded() { private func restoreCachedBubbleIfNeeded() {
guard AppContextManager.shared.status == 2, guard AppContextManager.shared.status == 2,
let endDate = Defaults[\.bubbleKeepTimes], let endDate = Defaults[\.bubbleKeepTimes],

View File

@ -90,8 +90,4 @@ class CreateBubbleView: UIView {
func updateNavTitleForSheet(_ visible: Bool) { func updateNavTitleForSheet(_ visible: Bool) {
navView.titleLabel.text = visible ? "通知您的圈子" : "设置气泡时间" navView.titleLabel.text = visible ? "通知您的圈子" : "设置气泡时间"
} }
func updateVipAccess(isUnlocked: Bool) {
setupView.updateVipAccess(isUnlocked: isUnlocked)
}
} }

View File

@ -1,478 +0,0 @@
//
// GroupMemberView.swift
// QuickLocation
//
// Created by on 2026/5/29.
//
import UIKit
import RxSwift
import RxCocoa
import Lottie
class GroupMemberView: UIView {
func setupCountData(_ memberCount: Int, _ memberOnlineCount: Int) {
groupContentLab.text = "\(memberCount)成员/\(memberOnlineCount)在线"
}
private func setupRx() {
}
private func setupUI() {
addSubview(headerBgView)
addSubview(bgView)
addSubview(groupIcon)
addSubview(titleIcon)
addSubview(groupContentLab)
addSubview(refreshBtn)
addSubview(inviteJoinBtn)
addSubview(tableView)
headerBgView.layoutChain
.edges(excludingEdge: .bottom)
.heightToWidth(136/375)
bgView.layoutChain
.topToBottomOfView(headerBgView)
.edges(excludingEdge: .top)
groupIcon.layoutChain
.top()
.left()
.width(52)
.height(52)
titleIcon.layoutChain
.top(5)
.leftToRightOfView(groupIcon)
.width(110)
.height(26)
groupContentLab.layoutChain
.topToBottomOfView(titleIcon, offset: 8)
.leftToView(titleIcon)
inviteJoinBtn.layoutChain
.top(23)
.right(15)
.height(20)
refreshBtn.layoutChain
.topToView(inviteJoinBtn)
.rightToLeftOfView(inviteJoinBtn, offset: -20)
.height(20)
inviteJoinBtn.sizeToFit()
refreshBtn.sizeToFit()
tableView.layoutChain
.topToBottomOfView(groupContentLab, offset: 8)
.edges(excludingEdge: .top)
}
lazy var headerBgView: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "Home/group_member_bg")
view.backgroundColor = .clear
view.contentMode = .scaleAspectFill
return view
}()
lazy var bgView: UIView = {
let view = UIView()
view.backgroundColor = .white
return view
}()
lazy var groupIcon: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "Home/group_icon")
view.backgroundColor = .clear
view.contentMode = .scaleAspectFill
return view
}()
lazy var titleIcon: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "Home/title_icon")
view.backgroundColor = .clear
view.contentMode = .scaleAspectFill
return view
}()
lazy var groupContentLab: UILabel = {
let label = UILabel()
label.text = "共0成员/0在线"
label.font = .systemFont(ofSize: 12, weight: .medium)
label.textColor = UIColor(hexStr: "#0F2846")
return label
}()
lazy var refreshBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setTitle(" 刷新列表", for: .normal)
btn.setTitleColor(UIColor(hexStr: "#1A1A1A"), for: .normal)
btn.titleLabel?.font = .systemFont(ofSize: 12, weight: .regular)
btn.setImage(UIImage(named: "Home/refresh"), for: .normal)
return btn
}()
lazy var inviteJoinBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setTitle(" 邀请加入", for: .normal)
btn.setTitleColor(UIColor(hexStr: "#1A1A1A"), for: .normal)
btn.titleLabel?.font = .systemFont(ofSize: 12, weight: .regular)
btn.setImage(UIImage(named: "Home/member"), for: .normal)
return btn
}()
lazy var tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .plain)
tableView.backgroundColor = .clear
tableView.separatorStyle = .none
tableView.estimatedRowHeight = 76
tableView.showsVerticalScrollIndicator = false
tableView.register(GroupMemberCell.self)
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 97 + kSafeBottomMargin, right: 0)
return tableView
}()
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .clear
setupUI()
setupRx()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// MARK: - GroupMemberCell
class GroupMemberCell: UITableViewCell {
func configure(model: GroupMemberModel, isCurrentUser: Bool, isOwn: Bool) {
ownView.isHidden = !isOwn
avaterImgView.setHeadPic(model.displayHeadPic)
nameLab.text = model.showName
//
locationLab.text = "" + model.lastLocation
nameLab.textColor = UIColor(hexStr: isCurrentUser ? "#16B3FF" : "#0F2846")
//
batteryInfoView.isHidden = true
if AppContextManager.shared.vip > 1, model.is_online {
batteryInfoView.isHidden = model.battery.int == 0
// 16
let batteryPercent = min(CGFloat(model.battery.int), 100)
batteryView.layoutChain.width(CGFloat(16 - 1) * batteryPercent / 100.0)
batteryLab.text = "\(model.battery)%"
}
// 线
if model.is_online {
onlineDotView.isHidden = false
onlineStatusLab.text = "在线"
onlineStatusLab.textColor = ThemeManager.shared.color.titleAuxColor
} else {
onlineDotView.isHidden = true
onlineStatusLab.text = model.lastUpdateText
onlineStatusLab.textColor = UIColor(hexStr: "#999999")
}
// sos
sosLottieView.isHidden = model.status != 1
model.status == 1 ? sosLottieView.play() : sosLottieView.stop()
//
shieldIconView.isHidden = model.status != 2
}
private func setupSubviews() {
contentView.addSubview(selectedBgView)
contentView.addSubview(avaterImgView)
contentView.addSubview(batteryInfoView)
batteryInfoView.addSubview(cornerView)
cornerView.addSubview(batteryView)
cornerView.addSubview(batteryIcon)
cornerView.addSubview(batteryLab)
contentView.addSubview(nameLab)
contentView.addSubview(locationIcon)
contentView.addSubview(locationLab)
contentView.addSubview(tagView)
contentView.addSubview(onlineView)
setupLayout()
}
private func setupLayout() {
selectedBgView.layoutChain
.edgesHorzontal(15)
.edgesVertical()
avaterImgView.layoutChain
.edgesVertical(13)
.left(28)
.width(50)
.height(50)
batteryInfoView.layoutChain
.leftToView(avaterImgView)
.rightToView(avaterImgView)
.bottomToView(avaterImgView)
.height(12)
cornerView.layoutChain.edges()
batteryIcon.layoutChain
.left(7)
.centerY()
.width(16)
.height(8)
batteryView.layoutChain
.topToView(batteryIcon)
.leftToView(batteryIcon, offset: -1)
.bottomToView(batteryIcon)
batteryLab.layoutChain
.leftToRightOfView(batteryIcon, offset: 4)
.right(5)
.centerY()
nameLab.layoutChain
.topToView(avaterImgView, offset: 6)
.leftToRightOfView(avaterImgView, offset: 8)
locationLab.layoutChain
.bottomToView(avaterImgView, offset: -6)
.leftToView(nameLab)
locationIcon.layoutChain
.leftToRightOfView(locationLab, offset: 4)
.centerY(locationLab)
.width(10)
.height(10)
.right(80, relation: .greaterThanOrEqual)
tagView.layoutChain
.leftToRightOfView(nameLab, offset: 4)
.centerY(nameLab)
.height(30)
ownView.layoutChain.height(15)
offlineView.layoutChain.height(15)
onlineView.layoutChain
.right(26)
.bottom(18)
}
lazy var selectedBgView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hexStr: "#EAFBFF")
view.cornerRadius = 10
view.isHidden = true
return view
}()
lazy var avaterImgView: UIImageView = {
let view = UIImageView()
view.backgroundColor = .lightGray
view.contentMode = .scaleAspectFill
view.cornerRadius = 25
return view
}()
lazy var batteryInfoView: UIView = {
let view = UIView()
view.backgroundColor = .clear
view.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.1).cgColor
view.layer.shadowOffset = CGSize(width: 0, height: 2)
view.layer.shadowOpacity = 1
view.layer.shadowRadius = 6
view.isHidden = true
return view
}()
lazy var cornerView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.cornerRadius = 6
return view
}()
lazy var batteryView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hexStr: "#75E582")
return view
}()
lazy var batteryIcon: UIImageView = {
let view = UIImageView()
view.backgroundColor = .clear
view.image = UIImage(named: "Home/battery")
return view
}()
lazy var batteryLab: UILabel = {
let label = UILabel()
label.textColor = UIColor(hexStr: "#D4D4D4")
label.font = .systemFont(ofSize: 6, weight: .medium)
return label
}()
lazy var nameLab: UILabel = {
let label = UILabel()
label.textColor = UIColor(hexStr: "#0F2846")
label.font = .systemFont(ofSize: 14, weight: .semibold)
return label
}()
lazy var locationIcon: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "Home/member_location")
return view
}()
lazy var locationLab: UILabel = {
let label = UILabel()
label.textColor = UIColor(hexStr: "#8D8D8D")
label.font = .systemFont(ofSize: 10, weight: .regular)
return label
}()
lazy var tagView: UIStackView = {
let view = UIStackView(arrangedSubviews: [ownView, offlineView, sosLottieView, shieldIconView])
view.axis = .horizontal
view.alignment = .center
view.spacing = 5
view.backgroundColor = .clear
return view
}()
//
lazy var ownView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hexStr: "#9FD9FF")
view.cornerRadius = 2
let label = UILabel()
label.textColor = UIColor(hexStr: "#194045")
label.font = .systemFont(ofSize: 8, weight: .medium)
label.text = "圈主"
view.addSubview(label)
label.layoutChain
.edgesVertical(2)
.edgesHorzontal(8)
return view
}()
// 线
lazy var offlineView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hexStr: "#EDEDED")
view.cornerRadius = 2
let label = UILabel()
label.textColor = ThemeManager.shared.color.contentColor
label.font = .systemFont(ofSize: 8, weight: .medium)
label.text = "离线"
view.addSubview(label)
label.layoutChain
.edgesVertical(2)
.edgesHorzontal(8)
view.isHidden = true
return view
}()
// sos
lazy var sosLottieView: LottieAnimationView = {
let view = LottieAnimationView(name: "siren")
view.loopMode = .loop
view.isHidden = true
view.layoutChain.width(26).height(26)
return view
}()
//
lazy var shieldIconView: UIImageView = {
let view = UIImageView(image: UIImage(named: "Home/shield"))
view.contentMode = .scaleAspectFill
view.isHidden = true
view.layoutChain.width(20).height(20)
return view
}()
// 线
lazy var onlineView: UIView = {
let view = UIView()
view.backgroundColor = .clear
view.addSubview(onlineDotView)
view.addSubview(onlineStatusLab)
onlineDotView.layoutChain
.left()
.centerY()
.height(8)
.width(8)
onlineStatusLab.layoutChain
.edgesVertical()
.leftToRightOfView(onlineDotView, offset: 3)
.right()
return view
}()
lazy var onlineDotView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hexStr: "#67EA76")
view.cornerRadius = 4
return view
}()
lazy var onlineStatusLab: UILabel = {
let label = UILabel()
label.textColor = ThemeManager.shared.color.titleAuxColor
label.font = .systemFont(ofSize: 10, weight: .medium)
label.text = "在线"
return label
}()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override init(style: CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
selectionStyle = .none
backgroundColor = .clear
setupSubviews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
selectedBgView.isHidden = !selected
}
}

View File

@ -12,7 +12,6 @@ import SwiftyUserDefaults
enum MemberFeatureAccessState: Equatable { enum MemberFeatureAccessState: Equatable {
case available case available
case vipRequired
case privilegeDenied case privilegeDenied
} }
@ -28,7 +27,6 @@ class GroupMemberView2: UIView {
private var appUsageBottomConstraint: NSLayoutConstraint? private var appUsageBottomConstraint: NSLayoutConstraint?
private var isAppUsageVisible = false private var isAppUsageVisible = false
private var currentMemberModel: GroupMemberModel? private var currentMemberModel: GroupMemberModel?
private var currentGroupVip = GroupMemberVip()
private var emojiEchoByUserId: [String: String] = [:] private var emojiEchoByUserId: [String: String] = [:]
private var messageEchoByUserId: [String: String] = [:] private var messageEchoByUserId: [String: String] = [:]
private var phoneStatusObserver: NSObjectProtocol? private var phoneStatusObserver: NSObjectProtocol?
@ -37,7 +35,6 @@ class GroupMemberView2: UIView {
private var localWeatherSnapshotKey: String? private var localWeatherSnapshotKey: String?
private var localWeatherUpdatedAt: Date? private var localWeatherUpdatedAt: Date?
private var pendingWeatherLocationKey: String? private var pendingWeatherLocationKey: String?
private(set) var isTodayTrackVipRequired = false
var onCoupleMemberTap: ((GroupMemberModel) -> Void)? var onCoupleMemberTap: ((GroupMemberModel) -> Void)?
private static let weatherRefreshInterval: TimeInterval = 15 * 60 private static let weatherRefreshInterval: TimeInterval = 15 * 60
@ -55,11 +52,9 @@ class GroupMemberView2: UIView {
func setupMemberInfo( func setupMemberInfo(
_ model: GroupMemberModel, _ model: GroupMemberModel,
isOwner: Bool, isOwner: Bool,
phoneUsage: PhoneUsageTodayModel?, phoneUsage: PhoneUsageTodayModel?
groupVip: GroupMemberVip
) { ) {
currentMemberModel = model currentMemberModel = model
currentGroupVip = groupVip
memberNameLab.text = model.showName memberNameLab.text = model.showName
ownView.isHidden = !isOwner ownView.isHidden = !isOwner
relationIconView.configure(relationIdx: model.extra.relation_idx) relationIconView.configure(relationIdx: model.extra.relation_idx)
@ -78,7 +73,7 @@ class GroupMemberView2: UIView {
} }
applyPhoneUsage(phoneUsage) applyPhoneUsage(phoneUsage)
if isCurrentUser, !isPhoneDeviceVipRequired { if isCurrentUser {
requestLocalWeather() requestLocalWeather()
} }
updateRealtimeInteractionVisibility(isCurrentUser: isCurrentUser) updateRealtimeInteractionVisibility(isCurrentUser: isCurrentUser)
@ -87,7 +82,6 @@ class GroupMemberView2: UIView {
func clearMemberInfo() { func clearMemberInfo() {
currentMemberModel = nil currentMemberModel = nil
currentGroupVip = GroupMemberVip()
memberNameLab.text = "" memberNameLab.text = ""
ownView.isHidden = true ownView.isHidden = true
relationIconView.configure(relationIdx: "") relationIconView.configure(relationIdx: "")
@ -105,20 +99,18 @@ class GroupMemberView2: UIView {
func updatePhoneUsage(_ phoneUsage: PhoneUsageTodayModel?, for userId: String) { func updatePhoneUsage(_ phoneUsage: PhoneUsageTodayModel?, for userId: String) {
guard currentMemberModel?.user_id == userId else { return } guard currentMemberModel?.user_id == userId else { return }
applyPhoneUsage(phoneUsage) applyPhoneUsage(phoneUsage)
if Self.isCurrentUser(userId), !isPhoneDeviceVipRequired { if Self.isCurrentUser(userId) {
applyLocalDeviceInfo() applyLocalDeviceInfo()
} }
} }
func refreshLocalDeviceInfoIfNeeded() { func refreshLocalDeviceInfoIfNeeded() {
guard isShowingCurrentUser, !isPhoneDeviceVipRequired else { return } guard isShowingCurrentUser else { return }
applyLocalDeviceInfo() applyLocalDeviceInfo()
} }
func refreshInterceptState() { func refreshInterceptState() {
memberCV.reloadData() memberCV.reloadData()
coupleLeftSlot.refreshVipVisibility()
coupleRightSlot.refreshVipVisibility()
updateFeatureVisibilityLayout() updateFeatureVisibilityLayout()
} }
@ -206,9 +198,7 @@ class GroupMemberView2: UIView {
} }
private func applyPhoneUsage(_ usage: PhoneUsageTodayModel?) { private func applyPhoneUsage(_ usage: PhoneUsageTodayModel?) {
if isPhoneDeviceVipRequired { if isShowingCurrentUser {
stopLocalPhoneStatusObserving()
} else if isShowingCurrentUser {
applyLocalDeviceInfo() applyLocalDeviceInfo()
startLocalPhoneStatusObserving() startLocalPhoneStatusObserving()
} else { } else {
@ -219,7 +209,6 @@ class GroupMemberView2: UIView {
applyDeviceInfo(usage?.phoneInfo) applyDeviceInfo(usage?.phoneInfo)
} }
} }
applyPhoneDeviceAccessState()
if isShowingOfflineOther { if isShowingOfflineOther {
phoneReportView.configure(with: nil) phoneReportView.configure(with: nil)
appUsageView.configure(with: nil) appUsageView.configure(with: nil)
@ -236,15 +225,11 @@ class GroupMemberView2: UIView {
var isPhoneReportDenied: Bool { phoneReportView.isDenied } var isPhoneReportDenied: Bool { phoneReportView.isDenied }
var isAppUsageDenied: Bool { appUsageView.isDenied } var isAppUsageDenied: Bool { appUsageView.isDenied }
var isPhoneReportVipRequired: Bool { phoneReportView.isVipRequired }
var isAppUsageVipRequired: Bool { appUsageView.isVipRequired }
var onPhoneReportRemind: (() -> Void)? var onPhoneReportRemind: (() -> Void)?
var onAppUsageRemind: (() -> Void)? var onAppUsageRemind: (() -> Void)?
private func applyFeatureAccessStates(appUsagePreview: MemberAppUsagePreview?) { private func applyFeatureAccessStates(appUsagePreview: MemberAppUsagePreview?) {
guard currentMemberModel != nil else { guard currentMemberModel != nil else {
isTodayTrackVipRequired = false
todayTrackVipView.isHidden = true
phoneReportView.setAccessState(.available) phoneReportView.setAccessState(.available)
appUsageView.setAccessState(.available) appUsageView.setAccessState(.available)
updateAppUsageVisibility(appUsagePreview != nil) updateAppUsageVisibility(appUsagePreview != nil)
@ -253,16 +238,12 @@ class GroupMemberView2: UIView {
let isSelf = isShowingCurrentUser let isSelf = isShowingCurrentUser
let memberPrivilege = currentMemberModel?.extra.privilege ?? GroupPrivilege() let memberPrivilege = currentMemberModel?.extra.privilege ?? GroupPrivilege()
let phoneState = Self.accessState( let phoneState = Self.accessState(
vipAllowed: currentGroupVip.phone_report,
privilegeAllowed: isSelf || memberPrivilege.phone_report privilegeAllowed: isSelf || memberPrivilege.phone_report
) )
let appUsageState = Self.accessState( let appUsageState = Self.accessState(
vipAllowed: currentGroupVip.app_usage_record,
privilegeAllowed: isSelf || memberPrivilege.app_usage_record privilegeAllowed: isSelf || memberPrivilege.app_usage_record
) )
isTodayTrackVipRequired = !isSelf && currentGroupVip.trip_analysis_others == false
todayTrackVipView.isHidden = !isTodayTrackVipRequired
phoneReportView.setAccessState(phoneState) phoneReportView.setAccessState(phoneState)
phoneReportView.onDeniedAction = { [weak self] in self?.onPhoneReportRemind?() } phoneReportView.onDeniedAction = { [weak self] in self?.onPhoneReportRemind?() }
appUsageView.setAccessState(appUsageState) appUsageView.setAccessState(appUsageState)
@ -274,13 +255,7 @@ class GroupMemberView2: UIView {
updateAppUsageVisibility(showUsage) updateAppUsageVisibility(showUsage)
} }
private static func accessState( private static func accessState(privilegeAllowed: Bool) -> MemberFeatureAccessState {
vipAllowed: Bool?,
privilegeAllowed: Bool
) -> MemberFeatureAccessState {
if vipAllowed == false {
return .vipRequired
}
if !privilegeAllowed { if !privilegeAllowed {
return .privilegeDenied return .privilegeDenied
} }
@ -291,23 +266,6 @@ class GroupMemberView2: UIView {
Self.isCurrentUser(currentMemberModel?.user_id) Self.isCurrentUser(currentMemberModel?.user_id)
} }
private var isPhoneDeviceVipRequired: Bool {
currentMemberModel != nil && !isShowingCurrentUser && currentGroupVip.view_phone == false
}
private func applyPhoneDeviceAccessState() {
let requiresVip = isPhoneDeviceVipRequired
phoneModelView.isHidden = requiresVip
batteryView.isHidden = requiresVip
networkView.isHidden = requiresVip
weatherView.isHidden = requiresVip
phoneDeviceVipButton.isHidden = !requiresVip
}
@objc private func handlePhoneDeviceVipTap() {
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
}
private static func isCurrentUser(_ userId: String?) -> Bool { private static func isCurrentUser(_ userId: String?) -> Bool {
let memberId = userId?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" let memberId = userId?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
let selfId = AppContextManager.shared.userId.trimmingCharacters(in: .whitespacesAndNewlines) let selfId = AppContextManager.shared.userId.trimmingCharacters(in: .whitespacesAndNewlines)
@ -346,7 +304,7 @@ class GroupMemberView2: UIView {
object: nil, object: nil,
queue: .main queue: .main
) { [weak self] _ in ) { [weak self] _ in
guard let self, self.isShowingCurrentUser, !self.isPhoneDeviceVipRequired else { return } guard let self, self.isShowingCurrentUser else { return }
self.applyLocalDeviceInfo() self.applyLocalDeviceInfo()
} }
} }
@ -375,7 +333,6 @@ class GroupMemberView2: UIView {
} }
private func requestLocalWeather() { private func requestLocalWeather() {
guard !isPhoneDeviceVipRequired else { return }
guard let latitude = Defaults[\.currentLatitude], guard let latitude = Defaults[\.currentLatitude],
let longitude = Defaults[\.currentLongitude] else { let longitude = Defaults[\.currentLongitude] else {
if localWeatherSnapshot == nil { if localWeatherSnapshot == nil {
@ -409,7 +366,7 @@ class GroupMemberView2: UIView {
MemberWeatherService.shared.weather(for: location) { [weak self] result in MemberWeatherService.shared.weather(for: location) { [weak self] result in
guard let self, self.weatherRequestID == requestID else { return } guard let self, self.weatherRequestID == requestID else { return }
self.pendingWeatherLocationKey = nil self.pendingWeatherLocationKey = nil
guard self.isShowingCurrentUser, !self.isPhoneDeviceVipRequired else { return } guard self.isShowingCurrentUser else { return }
switch result { switch result {
case .success(let snapshot): case .success(let snapshot):
self.localWeatherSnapshot = snapshot self.localWeatherSnapshot = snapshot
@ -442,15 +399,16 @@ class GroupMemberView2: UIView {
} }
private func updateFeatureVisibilityLayout() { private func updateFeatureVisibilityLayout() {
let hidesPhoneReport = AppContextManager.shared.systemConfig?.isIntercept == true let hidesPhoneReport = false
let showsAppUsage = !hidesPhoneReport && isAppUsageVisible
phoneReportView.isHidden = hidesPhoneReport phoneReportView.isHidden = hidesPhoneReport
appUsageView.isHidden = hidesPhoneReport appUsageView.isHidden = !showsAppUsage
appUsageTopToPhoneReportConstraint?.isActive = !hidesPhoneReport appUsageTopToPhoneReportConstraint?.isActive = !hidesPhoneReport
appUsageTopToTodayTrackConstraint?.isActive = hidesPhoneReport appUsageTopToTodayTrackConstraint?.isActive = hidesPhoneReport
phoneReportBottomConstraint?.isActive = !hidesPhoneReport && !isAppUsageVisible phoneReportBottomConstraint?.isActive = !hidesPhoneReport && !isAppUsageVisible
appUsageBottomConstraint?.isActive = isAppUsageVisible appUsageBottomConstraint?.isActive = showsAppUsage
todayTrackBottomConstraint?.isActive = hidesPhoneReport && !isAppUsageVisible todayTrackBottomConstraint?.isActive = hidesPhoneReport
setNeedsLayout() setNeedsLayout()
} }
@ -950,7 +908,6 @@ class GroupMemberView2: UIView {
view.addSubview(batteryView) view.addSubview(batteryView)
view.addSubview(networkView) view.addSubview(networkView)
view.addSubview(weatherView) view.addSubview(weatherView)
view.addSubview(phoneDeviceVipButton)
phoneModelView.layoutChain phoneModelView.layoutChain
.topToBottomOfView(locationLab, offset: 20) .topToBottomOfView(locationLab, offset: 20)
@ -971,12 +928,6 @@ class GroupMemberView2: UIView {
.leftToRightOfView(networkView) .leftToRightOfView(networkView)
.right() .right()
.widthToView(phoneModelView) .widthToView(phoneModelView)
phoneDeviceVipButton.layoutChain
.centerX()
.centerY(phoneModelView)
.width(174)
.height(34)
return view return view
}() }()
@ -1239,17 +1190,6 @@ class GroupMemberView2: UIView {
label.font = .systemFont(ofSize: 12, weight: .medium) label.font = .systemFont(ofSize: 12, weight: .medium)
return label return label
}() }()
private lazy var phoneDeviceVipButton: UIButton = {
let button = UIButton(type: .custom)
button.setTitle("开通会员 解锁功能", for: .normal)
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = FontManager.boboBold(14)
button.setBackgroundImage(UIImage(named: "VipFeature/narrow_button_bg"), for: .normal)
button.isHidden = true
button.addTarget(self, action: #selector(handlePhoneDeviceVipTap), for: .touchUpInside)
return button
}()
// MARK: - / APP使 // MARK: - / APP使
lazy var phoneReportView = MemberPhoneReportView() lazy var phoneReportView = MemberPhoneReportView()
@ -1463,28 +1403,9 @@ class GroupMemberView2: UIView {
stayNodataView.layoutChain stayNodataView.layoutChain
.topToBottomOfView(stayTxtLab, offset: 14) .topToBottomOfView(stayTxtLab, offset: 14)
.leftToView(stayTxtLab) .leftToView(stayTxtLab)
view.addSubview(todayTrackVipView)
todayTrackVipView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
todayTrackVipView.topAnchor.constraint(equalTo: infoView.topAnchor),
todayTrackVipView.leadingAnchor.constraint(equalTo: infoView.leadingAnchor),
todayTrackVipView.trailingAnchor.constraint(equalTo: infoView.trailingAnchor),
todayTrackVipView.bottomAnchor.constraint(equalTo: infoView.bottomAnchor)
])
return view return view
}() }()
private lazy var todayTrackVipView: UIImageView = {
let view = UIImageView(image: UIImage(named: "MemberVipRequired/today_track"))
view.contentMode = .scaleAspectFill
view.clipsToBounds = true
view.cornerRadius = 16
view.isHidden = true
view.isUserInteractionEnabled = false
return view
}()
lazy var stayNumLab: UILabel = { lazy var stayNumLab: UILabel = {
let label = UILabel() let label = UILabel()
@ -1630,20 +1551,13 @@ private final class CoupleMemberSlot: UIControl {
avatarImageView.setHeadPic(model?.displayHeadPic) avatarImageView.setHeadPic(model?.displayHeadPic)
avatarImageView.layer.borderColor = UIColor(hexStr: isSelected ? "#FFD43B" : "#FFFFFF").cgColor avatarImageView.layer.borderColor = UIColor(hexStr: isSelected ? "#FFD43B" : "#FFFFFF").cgColor
nameLabel.text = model?.showName nameLabel.text = model?.showName
refreshVipVisibility()
}
func refreshVipVisibility() {
vipImageView.isHidden = member?.shouldShowVipAvatarFrame != true
} }
private func setupUI() { private func setupUI() {
addSubview(avatarImageView) addSubview(avatarImageView)
addSubview(vipImageView)
addSubview(nameLabel) addSubview(nameLabel)
avatarImageView.translatesAutoresizingMaskIntoConstraints = false avatarImageView.translatesAutoresizingMaskIntoConstraints = false
vipImageView.translatesAutoresizingMaskIntoConstraints = false
nameLabel.translatesAutoresizingMaskIntoConstraints = false nameLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
@ -1652,9 +1566,6 @@ private final class CoupleMemberSlot: UIControl {
avatarImageView.widthAnchor.constraint(equalToConstant: 50), avatarImageView.widthAnchor.constraint(equalToConstant: 50),
avatarImageView.heightAnchor.constraint(equalToConstant: 50), avatarImageView.heightAnchor.constraint(equalToConstant: 50),
vipImageView.topAnchor.constraint(equalTo: avatarImageView.topAnchor, constant: -2),
vipImageView.centerXAnchor.constraint(equalTo: avatarImageView.centerXAnchor),
nameLabel.topAnchor.constraint(equalTo: avatarImageView.bottomAnchor, constant: 9), nameLabel.topAnchor.constraint(equalTo: avatarImageView.bottomAnchor, constant: 9),
nameLabel.leadingAnchor.constraint(equalTo: leadingAnchor), nameLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
nameLabel.trailingAnchor.constraint(equalTo: trailingAnchor) nameLabel.trailingAnchor.constraint(equalTo: trailingAnchor)
@ -1671,13 +1582,6 @@ private final class CoupleMemberSlot: UIControl {
return view return view
}() }()
private let vipImageView: UIImageView = {
let view = UIImageView(image: UIImage(named: "GroupMemberList/vip"))
view.contentMode = .scaleAspectFit
view.isHidden = true
return view
}()
private let nameLabel: UILabel = { private let nameLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.font = .systemFont(ofSize: 12, weight: .medium) label.font = .systemFont(ofSize: 12, weight: .medium)

View File

@ -1,913 +0,0 @@
//
// HomeView.swift
// QuickLocation
//
// Created by on 2026/5/27.
//
import UIKit
import RxSwift
import RxCocoa
import Lottie
#if !targetEnvironment(simulator)
import AMapNaviKit
import MarqueeLabel
#endif
class HomeView: UIView {
var disposeBag = DisposeBag()
let groupMemberView = GroupMemberView(frame: .zero)
let quickMessageView = QuickMessageView(frame: CGRectMake(0, kScreenHeight, kScreenWidth, 93))
let interactionView = InteractionView(frame: CGRectMake(0, kScreenHeight, kScreenWidth, 384))
var gpsSignalViewList: [UIView] = []
///
func updateGPSSignal(bars: Int) {
let filled = max(0, min(bars, gpsSignalViewList.count))
for (i, view) in gpsSignalViewList.enumerated() {
view.backgroundColor = i < filled ? UIColor(hexStr: "#4ED178") : UIColor(hexStr: "#E0E0E0")
}
}
// MARK: - groupMemberView
private var groupMemberTopConstraint: NSLayoutConstraint?
private var groupMemberUpLimit: CGFloat = 0
private var groupMemberDownLimit: CGFloat = 0
private var isGroupMemberLimitsSet = false
private var panStartTop: CGFloat = 0
/// tableView
private var isSubCanScroll = false
private var groupMemberTableTopOffset: CGFloat {
-groupMemberView.tableView.adjustedContentInset.top
}
// MARK: - Map
#if !targetEnvironment(simulator)
lazy var mapView: MAMapView! = {
let mv = MAMapView()
mv.zoomLevel = 16
mv.showsUserLocation = true
mv.userTrackingMode = .none
mv.showsCompass = false
mv.showsScale = false
mv.isRotateEnabled = false
mv.isRotateCameraEnabled = false
DispatchQueue.main.async { mv.logoCenter = CGPoint(x: kScreenWidth - 50, y: kScreenHeight / 2 + 65) }
return mv
}()
#else
lazy var mapPlaceholderView: UIView = {
let v = UIView()
v.backgroundColor = UIColor(hexStr: "#EDEDED")
let label = UILabel()
label.text = "Map requires a real device"
label.font = UIFont.systemFont(ofSize: 14)
label.textColor = UIColor(hexStr: "#999999")
label.textAlignment = .center
v.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: v.centerXAnchor),
label.centerYAnchor.constraint(equalTo: v.centerYAnchor)
])
return v
}()
#endif
///
var onDismissPanel: (() -> Void)?
// MARK: - Setup
private func setupRx() {
quickMessageView.closeBtn.rx.tap
.subscribe(onNext: { [weak self] _ in
self?.dismissMemberPanel()
self?.onDismissPanel?()
})
.disposed(by: disposeBag)
groupMemberView.tableView.rx.setDelegate(self)
.disposed(by: disposeBag)
//
searchLottieView.rx.tapGesture.subscribe { _ in
AppRouter.push(Route.searchLocation)
}.disposed(by: disposeBag)
//
warningIconView.rx.tapGesture.subscribe { _ in
LocationPermissionPopView.show()
}.disposed(by: disposeBag)
}
private func setupUI() {
#if !targetEnvironment(simulator)
addSubview(mapView)
#else
addSubview(mapPlaceholderView)
#endif
addSubview(navBarBg)
addSubview(avatarImgView)
addSubview(groupView)
groupView.addSubview(groupIconView)
groupView.addSubview(groupNameLab)
groupView.addSubview(groupArrowIconView)
addSubview(messageView)
addSubview(messageStackView)
addSubview(toolsView)
addSubview(warningIconView)
addSubview(searchLottieView)
addSubview(locationView)
locationView.addSubview(locationIconView)
addSubview(emojiPopView)
addSubview(sosPopView)
#if !targetEnvironment(simulator)
mapView.layoutChain
.top()
.edges(excludingEdge: .top)
sendSubviewToBack(mapView)
#else
mapPlaceholderView.layoutChain
.topToBottomOfView(navBarBg)
.left(0).right(0).bottom(0)
#endif
navBarBg.layoutChain
.edges(excludingEdge: .bottom)
.heightToWidth(160/375)
avatarImgView.layoutChain
.top(59)
.left(15)
.width(36)
.heightToWidth(1)
groupView.layoutChain
.centerY(avatarImgView)
.height(36)
.centerX()
.width(185, relation: .greaterThanOrEqual)
groupIconView.layoutChain
.left(11)
.centerY()
.width(30)
.height(30)
groupArrowIconView.layoutChain
.right(15)
.centerY()
.width(15)
.height(8.5)
groupNameLab.layoutChain
.edgesVertical()
.leftToRightOfView(groupIconView)
.rightToLeftOfView(groupArrowIconView)
messageView.layoutChain
.right(15)
.centerY(groupView)
.width(36)
.height(36)
messageStackView.layoutChain
.topToBottomOfView(messageView, offset: 23)
.edgesHorzontal(15)
toolsView.layoutChain
.left(15)
.width(40)
.centerY(self, offset: -50)
warningIconView.layoutChain
.bottomToTopOfView(toolsView, offset: -10)
.centerX(toolsView)
.width(28)
.heightToWidth(1)
searchLottieView.layoutChain
.centerY(toolsView)
.right()
.width(100)
.height(100)
locationView.layoutChain
.right(15)
.bottomToView(toolsView, offset: -10)
.width(40)
.height(40)
locationIconView.layoutChain
.centerX()
.centerY()
emojiPopView.layoutChain
.centerX().centerY()
.width(180).height(180)
sosPopView.layoutChain
.bottomToView(toolsView)
.leftToRightOfView(toolsView)
.height(57).width(57)
// View
addSubview(groupMemberView)
groupMemberView.layoutChain
.topToBottomOfView(toolsView, offset: 10)
.edgesHorzontal()
.bottom()
groupMemberTopConstraint = groupMemberView.jh_constraint(
.top, toAttribute: .bottom, otherView: toolsView, relation: .equal
)
let pan = UIPanGestureRecognizer(target: self, action: #selector(handleGroupMemberPan(_:)))
pan.delegate = self
groupMemberView.addGestureRecognizer(pan)
groupMemberView.tableView.isScrollEnabled = false
// quickMessageView interactionView
addSubview(interactionView)
addSubview(quickMessageView)
}
// MARK: -
func showMemberPanel(member: CircleMember) {
interactionView.configure(member: member)
quickMessageView.isHidden = false
interactionView.isHidden = false
toolsView.isHidden = true
searchLottieView.isHidden = true
quickMessageView.frame.origin.y = kScreenHeight - 384 - 93
interactionView.frame.origin.y = kScreenHeight - 384
}
func dismissMemberPanel() {
quickMessageView.frame.origin.y = kScreenHeight
interactionView.frame.origin.y = kScreenHeight
quickMessageView.isHidden = true
interactionView.isHidden = true
toolsView.isHidden = false
searchLottieView.isHidden = AppContextManager.shared.systemConfig?.isIntercept == true
onDismissPanel?()
}
override init(frame: CGRect) {
super.init(frame: .zero)
backgroundColor = .white
setupUI()
setupRx()
searchLottieView.play()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Layout
override func layoutSubviews() {
super.layoutSubviews()
noticeView.layoutIfNeeded()
noticeInfoView.setGradientLayer(frame: noticeInfoView.bounds,
startPoint: CGPoint(x: 0, y: 0.5),
endPoint: CGPoint(x: 1, y: 0.5),
colors: [UIColor(hexStr: "#FFFFFF", alpha: 0), UIColor(hexStr: "#FFFFFF"), UIColor(hexStr: "#FFFFFF", alpha: 0)],
locations: [0, 0.5, 1])
if !isGroupMemberLimitsSet {
isGroupMemberLimitsSet = true
groupMemberDownLimit = groupMemberView.frame.minY
groupMemberUpLimit = groupView.frame.maxY + 20
}
}
// MARK: - Pan Gesture
@objc private func handleGroupMemberPan(_ pan: UIPanGestureRecognizer) {
guard isGroupMemberLimitsSet, let topConstraint = groupMemberTopConstraint else { return }
switch pan.state {
case .began:
layoutIfNeeded()
panStartTop = groupMemberView.frame.minY
case .changed:
let newTop = panStartTop + pan.translation(in: self).y
let scrollOffset = groupMemberView.tableView.contentOffset.y
// tableView
// tableView view
if isSubCanScroll {
if scrollOffset > groupMemberTableTopOffset + 0.5 {
// GroupMemberView
return
}
if pan.velocity(in: self).y > 0 || groupMemberView.frame.minY > groupMemberUpLimit + 1 {
//
isSubCanScroll = false
panStartTop = groupMemberView.frame.minY
}
} else {
// GroupMemberView
if groupMemberView.frame.minY <= groupMemberUpLimit && newTop <= groupMemberUpLimit {
isSubCanScroll = true
panStartTop = groupMemberView.frame.minY
topConstraint.constant = groupMemberUpLimit - groupMemberDownLimit + 10
return
}
}
let clamped = max(groupMemberUpLimit, min(groupMemberDownLimit, newTop))
topConstraint.constant = clamped - groupMemberDownLimit + 10
case .ended, .cancelled:
let velocity = pan.velocity(in: self)
let isNearUp = abs(groupMemberView.frame.minY - groupMemberUpLimit) < abs(groupMemberView.frame.minY - groupMemberDownLimit)
let target: CGFloat
if groupMemberView.frame.minY <= groupMemberUpLimit + 5 {
// tableView
target = isNearUp ? groupMemberUpLimit : groupMemberDownLimit
} else if abs(velocity.y) > 200 {
target = velocity.y < 0 ? groupMemberUpLimit : groupMemberDownLimit
} else {
target = isNearUp ? groupMemberUpLimit : groupMemberDownLimit
}
topConstraint.constant = target - groupMemberDownLimit + 10
let atTop = target == self.groupMemberUpLimit
if !atTop {
isSubCanScroll = false
groupMemberView.tableView.isScrollEnabled = false
groupMemberView.tableView.setContentOffset(CGPoint(x: 0, y: groupMemberTableTopOffset), animated: false)
}
isSubCanScroll = atTop
UIView.animate(withDuration: 0.25, delay: 0,
options: [.curveEaseOut, .allowUserInteraction]) {
self.layoutIfNeeded()
} completion: { _ in
self.groupMemberView.tableView.isScrollEnabled = atTop
}
default:
break
}
}
/// GroupMemberView
func dismissGroupMemberView() {
guard isGroupMemberLimitsSet, let topConstraint = groupMemberTopConstraint else { return }
isSubCanScroll = false
groupMemberView.tableView.isScrollEnabled = false
topConstraint.constant = groupMemberDownLimit - groupMemberDownLimit + 10
groupMemberView.tableView.setContentOffset(CGPoint(x: 0, y: groupMemberTableTopOffset), animated: false)
UIView.animate(withDuration: 0.25, delay: 0, options: .curveEaseOut) {
self.layoutIfNeeded()
}
}
// MARK: - UI Components
lazy var navBarBg: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "Home/navBar_bg")
view.contentMode = .scaleAspectFill
return view
}()
lazy var avatarImgView: UIImageView = {
let view = UIImageView()
view.backgroundColor = .lightGray
view.contentMode = .scaleAspectFill
view.cornerRadius = 18
return view
}()
//
lazy var groupView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.cornerRadius = 18
return view
}()
lazy var groupIconView: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "Home/group")
view.backgroundColor = .clear
view.contentMode = .scaleAspectFill
return view
}()
lazy var groupNameLab: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 16, weight: .medium)
label.textColor = UIColor(hexStr: "#0F2846")
label.textAlignment = .center
return label
}()
lazy var groupArrowIconView: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "Home/arrow_down")
view.backgroundColor = .clear
view.contentMode = .scaleAspectFill
return view
}()
///
lazy var messageView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.cornerRadius = 18
view.clipsToBounds = false
view.isHidden = true
view.addSubview(messageIcon)
view.addSubview(messageDotView)
messageIcon.layoutChain
.centerX().centerY()
messageDotView.layoutChain
.top()
.right()
.width(10)
.height(10)
return view
}()
lazy var messageIcon: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "Home/message")
view.backgroundColor = .clear
view.contentMode = .scaleAspectFill
return view
}()
lazy var messageDotView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hexStr: "#FD5E61")
view.cornerRadius = 5
return view
}()
lazy var messageStackView: UIStackView = {
let view = UIStackView(arrangedSubviews: [tipsView, messageBubbleView])
view.axis = .vertical
view.alignment = .leading
view.spacing = 5
view.backgroundColor = .clear
return view
}()
lazy var tipsView: UIView = {
let view = UIView()
view.backgroundColor = .clear
view.layoutChain.height(22)
view.addSubview(gpsSignalView)
gpsSignalView.layoutChain
.left()
.centerY()
view.addSubview(noticeView)
noticeView.layoutChain
.leftToRightOfView(gpsSignalView, offset: 0)
.right(15)
.edgesVertical()
return view
}()
// MARK: -
lazy var gpsSignalView: UIView = {
let view = UIView()
view.cornerRadius = 5
view.backgroundColor = .black.withAlphaComponent(0.4)
let signalView1 = UIView()
signalView1.backgroundColor = UIColor(hexStr: "#E6E6E6")
view.addSubview(signalView1)
signalView1.layoutChain
.left(7)
.bottom(5)
.width(3)
.height(4)
let signalView2 = UIView()
signalView2.backgroundColor = UIColor(hexStr: "#E6E6E6")
view.addSubview(signalView2)
signalView2.layoutChain
.leftToRightOfView(signalView1, offset: 2)
.bottomToView(signalView1)
.width(3)
.height(6)
let signalView3 = UIView()
signalView3.backgroundColor = UIColor(hexStr: "#E6E6E6")
view.addSubview(signalView3)
signalView3.layoutChain
.leftToRightOfView(signalView2, offset: 2)
.bottomToView(signalView1)
.width(3)
.height(8)
let signalView4 = UIView()
signalView4.backgroundColor = UIColor(hexStr: "#E6E6E6")
view.addSubview(signalView4)
signalView4.layoutChain
.leftToRightOfView(signalView3, offset: 2)
.bottomToView(signalView1)
.width(3)
.height(10)
let label = UILabel()
label.text = "卫星信号"
label.font = .systemFont(ofSize: 10, weight: .medium)
label.textColor = .white
view.addSubview(label)
label.layoutChain
.leftToRightOfView(signalView4, offset: 2)
.edgesVertical(4)
.right(7)
gpsSignalViewList = [signalView1, signalView2, signalView3, signalView4]
return view
}()
// MARK: -
lazy var noticeView: UIView = {
let view = UIView()
view.backgroundColor = .clear
view.addSubview(noticeInfoView)
noticeInfoView.layoutChain
.left()
.right()
.edgesVertical()
view.addSubview(noticeCloseBtn)
noticeCloseBtn.layoutChain
.right()
.width(16)
.height(16)
.centerY()
return view
}()
lazy var noticeInfoView: UIView = {
let view = UIView()
view.backgroundColor = .clear
// let titleLab = UILabel()
// titleLab.text = ""
// titleLab.font = .systemFont(ofSize: 10, weight: .medium)
// titleLab.textColor = UIColor(hexStr: "#0F2948")
// view.addSubview(titleLab)
// titleLab.layoutChain
// .left(16)
// .centerY()
// .width(40)
view.addSubview(noticeLab)
noticeLab.layoutChain
.left(16)
.centerY()
.right(24)
return view
}()
lazy var noticeLab: CallbackMarqueeLabel = {
let label = CallbackMarqueeLabel()
label.font = .systemFont(ofSize: 10, weight: .medium)
label.textColor = UIColor(hexStr: "#0F2948")
return label
}()
lazy var noticeCloseBtn: UIButton = {
let btn = UIButton()
btn.setImage(UIImage(named: "Common/x_black"), for: .normal)
btn.backgroundColor = .white
btn.cornerRadius = 8
btn.extendEdgeInsets = UIEdgeInsets(top: 15, left: 15, bottom: 15, right: 15)
btn.rx.tap.subscribe(onNext: { [weak self] _ in
self?.noticeView.isHidden = true
}).disposed(by: disposeBag)
return btn
}()
// MARK: -
lazy var messageBubbleView: UIView = {
let view = UIView()
view.backgroundColor = .white.withAlphaComponent(0.8)
view.cornerRadius = 10
view.isHidden = true
view.addSubview(messageLab)
messageLab.layoutChain
.edges(all: 12)
return view
}()
lazy var messageLab: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 12, weight: .medium)
label.textColor = UIColor(hexStr: "#0F2846")
return label
}()
// MARK: - SOS
lazy var sosPopView: LottieAnimationView = {
let view = LottieAnimationView(name: "siren")
view.loopMode = .loop
view.isHidden = true
return view
}()
// MARK: -
lazy var emojiPopView: LottieAnimationView = {
let view = LottieAnimationView()
view.loopMode = .playOnce
view.isHidden = true
return view
}()
// MARK: - warning
lazy var warningIconView: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "Home/warning")
view.contentMode = .scaleAspectFill
view.isHidden = true
return view
}()
// MARK: -
lazy var toolsView: UIStackView = {
let view = UIStackView(arrangedSubviews: [bubbleView, signInView, sosView, scheduleView])
view.axis = .vertical
view.distribution = .fill
view.alignment = .fill
view.backgroundColor = .black.withAlphaComponent(0.5)
view.cornerRadius = 20
return view
}()
//
lazy var bubbleView: UIView = {
let view = UIView()
view.backgroundColor = .clear
view.addSubview(bubbleIcon)
bubbleIcon.layoutChain
.top(10)
.centerX()
.width(28)
.height(28)
view.addSubview(bubbleLab)
bubbleLab.layoutChain
.topToBottomOfView(bubbleIcon, offset: 4)
.edgesHorzontal()
let lineView = UIView()
lineView.backgroundColor = .white
view.addSubview(lineView)
lineView.layoutChain
.width(12)
.height(2)
.centerX()
.bottom(7)
lineView.layoutChain.topToBottomOfView(bubbleLab, offset: 4)
return view
}()
lazy var bubbleIcon: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "Home/bubble")
view.backgroundColor = .clear
view.contentMode = .scaleAspectFill
return view
}()
lazy var bubbleLab: UILabel = {
let label = UILabel()
label.text = "气泡"
label.font = .systemFont(ofSize: 10, weight: .medium)
label.textColor = .white
label.textAlignment = .center
return label
}()
//
lazy var signInView: UIView = {
let view = UIView()
view.backgroundColor = .clear
view.addSubview(signInIcon)
signInIcon.layoutChain
.top()
.centerX()
.width(28)
.height(28)
view.addSubview(signInLab)
signInLab.layoutChain
.topToBottomOfView(signInIcon, offset: 4)
.edgesHorzontal()
let lineView = UIView()
lineView.backgroundColor = .white
view.addSubview(lineView)
lineView.layoutChain
.width(12)
.height(2)
.centerX()
.bottom(7)
lineView.layoutChain.topToBottomOfView(signInLab, offset: 4)
return view
}()
lazy var signInIcon: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "Home/signIn")
view.backgroundColor = .clear
view.contentMode = .scaleAspectFill
return view
}()
lazy var signInLab: UILabel = {
let label = UILabel()
label.text = "签到"
label.font = .systemFont(ofSize: 10, weight: .medium)
label.textColor = .white
label.textAlignment = .center
return label
}()
// SOS
lazy var sosView: UIView = {
let view = UIView()
view.backgroundColor = .clear
view.addSubview(sosIcon)
view.addSubview(sosLab)
sosIcon.layoutChain
.top()
.centerX()
.width(28)
.height(28)
sosLab.layoutChain
.topToBottomOfView(sosIcon, offset: 4)
.edgesHorzontal()
let lineView = UIView()
lineView.backgroundColor = .white
view.addSubview(lineView)
lineView.layoutChain
.width(12)
.height(2)
.centerX()
.bottom(7)
lineView.layoutChain.topToBottomOfView(sosLab, offset: 4)
return view
}()
lazy var sosIcon: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "Home/sos")
view.backgroundColor = .clear
view.contentMode = .scaleAspectFill
return view
}()
lazy var sosLab: UILabel = {
let label = UILabel()
label.text = "SOS"
label.font = .systemFont(ofSize: 10, weight: .medium)
label.textColor = .white
label.textAlignment = .center
return label
}()
//
lazy var scheduleView: UIView = {
let view = UIView()
view.backgroundColor = .clear
let icon = UIImageView(image: UIImage(named: "Home/schedule"))
icon.contentMode = .scaleAspectFill
view.addSubview(icon)
icon.layoutChain
.top()
.centerX()
.width(28)
.height(28)
let label = UILabel()
label.text = "行程"
label.font = .systemFont(ofSize: 10, weight: .medium)
label.textColor = .white
label.textAlignment = .center
view.addSubview(label)
label.layoutChain
.topToBottomOfView(icon, offset: 4)
.edgesHorzontal()
label.layoutChain.bottom(10)
return view
}()
// MARK: -
lazy var searchLottieView: LottieAnimationView = {
let view = LottieAnimationView(name: "home_search")
view.loopMode = .loop
return view
}()
// MARK: -
lazy var locationView: UIView = {
let view = UIView()
view.backgroundColor = .black.withAlphaComponent(0.4)
view.cornerRadius = 20
return view
}()
lazy var locationIconView: UIImageView = {
let view = UIImageView()
view.backgroundColor = .clear
view.image = UIImage(named: "Home/location")
return view
}()
}
// MARK: - UIScrollViewDelegate
extension HomeView: UIScrollViewDelegate {
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
guard scrollView == groupMemberView.tableView else { return }
if scrollView.contentOffset.y > groupMemberTableTopOffset {
isSubCanScroll = true
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard scrollView == groupMemberView.tableView else { return }
if isSubCanScroll {
if scrollView.contentOffset.y <= groupMemberTableTopOffset {
isSubCanScroll = false
scrollView.contentOffset = CGPoint(x: 0, y: groupMemberTableTopOffset)
}
} else {
scrollView.contentOffset = CGPoint(x: 0, y: groupMemberTableTopOffset)
}
}
}
// MARK: - UIGestureRecognizerDelegate
extension HomeView: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWith other: UIGestureRecognizer) -> Bool {
// GroupMemberView pan tableView pan
// isSubCanScroll + contentOffset
return true
}
}
// MARK: - CallbackMarqueeLabel
class CallbackMarqueeLabel: MarqueeLabel {
//
var onScrollLoopComplete: (() -> Void)?
var onScrollStart: (() -> Void)?
//
override func labelWillBeginScroll() {
super.labelWillBeginScroll()
onScrollStart?()
}
//
override func labelReturnedToHome(_ finished: Bool) {
super.labelReturnedToHome(finished)
//
guard finished else { return }
onScrollLoopComplete?()
}
}

View File

@ -72,7 +72,6 @@ class HomeViewController: BaseViewController {
private var lastUpdateTimes: [String: Date] = [:] private var lastUpdateTimes: [String: Date] = [:]
/// 线 /// 线
private var offlineCheckTimer: Timer? private var offlineCheckTimer: Timer?
private var popupQueue: PopupQueueManager?
private static var sosPlayerKey: UInt8 = 0 private static var sosPlayerKey: UInt8 = 0
private var groupRefreshWorkItem: DispatchWorkItem? private var groupRefreshWorkItem: DispatchWorkItem?
private var groupDataRetryWorkItem: DispatchWorkItem? private var groupDataRetryWorkItem: DispatchWorkItem?
@ -330,12 +329,7 @@ class HomeViewController: BaseViewController {
// //
rootView.groupMemberView.todayTrackView.rx.tapGesture.subscribe(onNext: { [weak self] _ in rootView.groupMemberView.todayTrackView.rx.tapGesture.subscribe(onNext: { [weak self] _ in
guard let self else { return } self?.openTodayTrackDetail()
if self.rootView.groupMemberView.isTodayTrackVipRequired {
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
} else {
self.openTodayTrackDetail()
}
}).disposed(by: disposeBag) }).disposed(by: disposeBag)
// //
@ -350,10 +344,6 @@ class HomeViewController: BaseViewController {
// //
rootView.groupMemberView.phoneReportView.rx.tapGesture.subscribe(onNext: { [weak self] _ in rootView.groupMemberView.phoneReportView.rx.tapGesture.subscribe(onNext: { [weak self] _ in
guard let self else { return } guard let self else { return }
if self.rootView.groupMemberView.isPhoneReportVipRequired {
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
return
}
guard !self.rootView.groupMemberView.isPhoneReportDenied else { return } guard !self.rootView.groupMemberView.isPhoneReportDenied else { return }
self.openPhoneReportDetail() self.openPhoneReportDetail()
}).disposed(by: disposeBag) }).disposed(by: disposeBag)
@ -361,10 +351,6 @@ class HomeViewController: BaseViewController {
// APP // APP
rootView.groupMemberView.appUsageView.rx.tapGesture.subscribe(onNext: { [weak self] _ in rootView.groupMemberView.appUsageView.rx.tapGesture.subscribe(onNext: { [weak self] _ in
guard let self else { return } guard let self else { return }
if self.rootView.groupMemberView.isAppUsageVipRequired {
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
return
}
guard !self.rootView.groupMemberView.isAppUsageDenied else { return } guard !self.rootView.groupMemberView.isAppUsageDenied else { return }
self.openAppUsageReport() self.openAppUsageReport()
}).disposed(by: disposeBag) }).disposed(by: disposeBag)
@ -384,9 +370,6 @@ class HomeViewController: BaseViewController {
// User Config // User Config
NotificationCenter.default.rx.notification(.RefreshUserConfigNotification, object: nil) NotificationCenter.default.rx.notification(.RefreshUserConfigNotification, object: nil)
.startWith(Notification(name: .RefreshUserConfigNotification)) .startWith(Notification(name: .RefreshUserConfigNotification))
.do(onNext: { [weak self] _ in
self?.popupQueue = nil
})
.flatMapLatest { _ in .flatMapLatest { _ in
SystemService.userConfig() SystemService.userConfig()
} }
@ -395,15 +378,11 @@ class HomeViewController: BaseViewController {
Defaults[\.loginToken] = model.token Defaults[\.loginToken] = model.token
AppContextManager.shared.systemConfig = model.config AppContextManager.shared.systemConfig = model.config
self.rootView.groupMemberView.refreshInterceptState() self.rootView.groupMemberView.refreshInterceptState()
// rootView.searchLottieView.isHidden = model.config?.isIntercept == true
self.requestUserInfo { [weak self] in self.requestUserInfo { [weak self] in
self?.requestGroupInfo() self?.requestGroupInfo()
} }
self.requestNotice() self.requestNotice()
self.refreshPigeonInbox() self.refreshPigeonInbox()
self.popupQueue = nil
self.popupQueue = PopupQueueManager()
// self.popupQueue?.start(from: self)
}).disposed(by: disposeBag) }).disposed(by: disposeBag)
// //
@ -849,7 +828,7 @@ class HomeViewController: BaseViewController {
return return
} }
self.viewModel.updateGroupUsers(response.list, vip: response.vip) self.viewModel.updateGroupUsers(response.list)
// status=0 // status=0
self.syncMemberAnnotations(self.viewModel.memberList) self.syncMemberAnnotations(self.viewModel.memberList)
self.refreshMQTTSubscriptions(self.viewModel.memberList) self.refreshMQTTSubscriptions(self.viewModel.memberList)
@ -1184,8 +1163,7 @@ class HomeViewController: BaseViewController {
rootView.groupMemberView.setupMemberInfo( rootView.groupMemberView.setupMemberInfo(
model, model,
isOwner: viewModel.isGroupOwn(id: model.user_id), isOwner: viewModel.isGroupOwn(id: model.user_id),
phoneUsage: usage, phoneUsage: usage
groupVip: viewModel.groupVip
) )
} }

View File

@ -87,7 +87,6 @@ class HomeViewModel {
} }
private(set) var memberList: [GroupMemberModel] = [] private(set) var memberList: [GroupMemberModel] = []
private(set) var groupVip = GroupMemberVip()
func markMemberInBubble(userId: String) { func markMemberInBubble(userId: String) {
updateMemberStatus(userId: userId, status: 2) updateMemberStatus(userId: userId, status: 2)
@ -113,13 +112,11 @@ class HomeViewModel {
sectionedItems.onNext(memberList.mapSection()) sectionedItems.onNext(memberList.mapSection())
} }
func updateGroupUsers(_ list: [GroupMemberModel], vip: GroupMemberVip) { func updateGroupUsers(_ list: [GroupMemberModel]) {
groupVip = vip
updateMembers(list) updateMembers(list)
} }
func clearMembers() { func clearMembers() {
groupVip = GroupMemberVip()
updateMembers([]) updateMembers([])
} }

View File

@ -76,8 +76,5 @@ final class InteractionEmojiCell: UICollectionViewCell {
let path = Bundle.main.path(forResource: "\(pngName)", ofType: "png") { let path = Bundle.main.path(forResource: "\(pngName)", ofType: "png") {
imageView.image = UIImage(contentsOfFile: path) imageView.image = UIImage(contentsOfFile: path)
} }
guard AppContextManager.shared.systemConfig?.isIntercept == false else { return }
lockView.isHidden = name.hasPrefix("normal_") || AppContextManager.shared.vip > 1
} }
} }

View File

@ -25,22 +25,15 @@ class InteractionView: UIView {
nameLab.text = member.name nameLab.text = member.name
locationLab.text = member.address locationLab.text = member.address
// batteryInfoView.isHidden = member.battery.int == 0
if AppContextManager.shared.vip > 1 { //
batteryInfoView.isHidden = member.battery.int == 0 let batteryInt = Int(member.battery) ?? 0
// let batteryPercent = min(CGFloat(batteryInt), 100)
let batteryInt = Int(member.battery) ?? 0 batteryView.layoutChain.width(CGFloat(16 - 1) * batteryPercent / 100.0)
let batteryPercent = min(CGFloat(batteryInt), 100) batteryLab.text = "\(member.battery)%"
batteryView.layoutChain.width(CGFloat(16 - 1) * batteryPercent / 100.0)
batteryLab.text = "\(member.battery)%"
// //
lockView.isHidden = true lockView.isHidden = true
}
else {
batteryInfoView.isHidden = true
lockView.isHidden = false
}
} }
/// normal / fun /// normal / fun
@ -84,7 +77,7 @@ class InteractionView: UIView {
emojiCollectionView.rx.modelSelected(String.self) emojiCollectionView.rx.modelSelected(String.self)
.subscribe(onNext: { [weak self] name in .subscribe(onNext: { [weak self] name in
guard let self = self else { return } guard let self = self else { return }
if name.hasPrefix("fun_"), AppContextManager.shared.vip <= 1 { return } if name.hasPrefix("fun_") { return }
// index: normal_5 15, fun_2 22 // index: normal_5 15, fun_2 22
let prefix: String let prefix: String
let numStr: String let numStr: String
@ -612,7 +605,7 @@ final class EmojiPanelCell: UICollectionViewCell {
self.lottieView.play() self.lottieView.play()
} }
lockView.isHidden = true//AppContextManager.shared.vip > 1 lockView.isHidden = true
} }
func playAnimation() { func playAnimation() {

View File

@ -74,10 +74,8 @@ final class MemberAppUsageView: UIView {
private let usageTitleLab = UILabel() private let usageTitleLab = UILabel()
private let topTitleLab = UILabel() private let topTitleLab = UILabel()
private let topStack = UIStackView() private let topStack = UIStackView()
private let vipRequiredView = UIImageView()
private let deniedOverlay = PrivilegeDeniedOverlay() private let deniedOverlay = PrivilegeDeniedOverlay()
private(set) var isDenied = false private(set) var isDenied = false
private(set) var isVipRequired = false
var onDeniedAction: (() -> Void)? var onDeniedAction: (() -> Void)?
override init(frame: CGRect) { override init(frame: CGRect) {
@ -92,7 +90,6 @@ final class MemberAppUsageView: UIView {
func setAccessState(_ state: MemberFeatureAccessState) { func setAccessState(_ state: MemberFeatureAccessState) {
isDenied = state == .privilegeDenied isDenied = state == .privilegeDenied
isVipRequired = state == .vipRequired
deniedOverlay.configure( deniedOverlay.configure(
title: "TA未开启设置", title: "TA未开启设置",
message: "无法查看app使用记录", message: "无法查看app使用记录",
@ -102,9 +99,8 @@ final class MemberAppUsageView: UIView {
deniedOverlay.onAction = { [weak self] in self?.onDeniedAction?() } deniedOverlay.onAction = { [weak self] in self?.onDeniedAction?() }
deniedOverlay.setVisible(isDenied) deniedOverlay.setVisible(isDenied)
deniedOverlay.layer.cornerRadius = cardView.layer.cornerRadius deniedOverlay.layer.cornerRadius = cardView.layer.cornerRadius
vipRequiredView.isHidden = !isVipRequired
[usageTitleLab, topTitleLab, donutView, totalTimeLab, totalHintLab, topStack].forEach { [usageTitleLab, topTitleLab, donutView, totalTimeLab, totalHintLab, topStack].forEach {
$0.isHidden = isVipRequired $0.isHidden = false
} }
gestureRecognizers?.forEach { $0.isEnabled = !isDenied } gestureRecognizers?.forEach { $0.isEnabled = !isDenied }
} }
@ -207,14 +203,6 @@ final class MemberAppUsageView: UIView {
.left(160) .left(160)
.right(14) .right(14)
vipRequiredView.image = UIImage(named: "MemberVipRequired/app_usage")
vipRequiredView.contentMode = .scaleAspectFill
vipRequiredView.clipsToBounds = true
vipRequiredView.isHidden = true
vipRequiredView.isUserInteractionEnabled = false
cardView.addSubview(vipRequiredView)
vipRequiredView.layoutChain.edges()
cardView.bringSubviewToFront(deniedOverlay) cardView.bringSubviewToFront(deniedOverlay)
} }

View File

@ -52,10 +52,8 @@ final class MemberPhoneReportView: UIView {
private let unlockIcon = UIImageView() private let unlockIcon = UIImageView()
private let unlockTitleLab = UILabel() private let unlockTitleLab = UILabel()
private let unlockValueLab = UILabel() private let unlockValueLab = UILabel()
private let vipRequiredView = UIImageView()
private let deniedOverlay = PrivilegeDeniedOverlay() private let deniedOverlay = PrivilegeDeniedOverlay()
private(set) var isDenied = false private(set) var isDenied = false
private(set) var isVipRequired = false
var onDeniedAction: (() -> Void)? var onDeniedAction: (() -> Void)?
override init(frame: CGRect) { override init(frame: CGRect) {
@ -70,7 +68,6 @@ final class MemberPhoneReportView: UIView {
func setAccessState(_ state: MemberFeatureAccessState) { func setAccessState(_ state: MemberFeatureAccessState) {
isDenied = state == .privilegeDenied isDenied = state == .privilegeDenied
isVipRequired = state == .vipRequired
deniedOverlay.configure( deniedOverlay.configure(
title: "TA未开启设置", title: "TA未开启设置",
message: "无法查看手机报告", message: "无法查看手机报告",
@ -80,9 +77,8 @@ final class MemberPhoneReportView: UIView {
deniedOverlay.onAction = { [weak self] in self?.onDeniedAction?() } deniedOverlay.onAction = { [weak self] in self?.onDeniedAction?() }
deniedOverlay.setVisible(isDenied) deniedOverlay.setVisible(isDenied)
deniedOverlay.layer.cornerRadius = cardView.layer.cornerRadius deniedOverlay.layer.cornerRadius = cardView.layer.cornerRadius
vipRequiredView.isHidden = !isVipRequired leftPanel.isHidden = false
leftPanel.isHidden = isVipRequired rightPanel.isHidden = false
rightPanel.isHidden = isVipRequired
gestureRecognizers?.forEach { $0.isEnabled = !isDenied } gestureRecognizers?.forEach { $0.isEnabled = !isDenied }
} }
@ -265,14 +261,6 @@ final class MemberPhoneReportView: UIView {
.leftToRightOfView(unlockValueLab, offset: 3) .leftToRightOfView(unlockValueLab, offset: 3)
.bottomToView(unlockValueLab, offset: -4) .bottomToView(unlockValueLab, offset: -4)
vipRequiredView.image = UIImage(named: "MemberVipRequired/phone_report")
vipRequiredView.contentMode = .scaleAspectFill
vipRequiredView.clipsToBounds = true
vipRequiredView.isHidden = true
vipRequiredView.isUserInteractionEnabled = false
cardView.addSubview(vipRequiredView)
vipRequiredView.layoutChain.edges()
cardView.bringSubviewToFront(deniedOverlay) cardView.bringSubviewToFront(deniedOverlay)
} }
} }

View File

@ -36,32 +36,13 @@ class SearchLocationResultVC: BaseViewController {
applyResultPresentation() applyResultPresentation()
} }
private func isVipUnlocked() -> Bool {
AppContextManager.shared.vip > 1
}
private func applyResultPresentation() { private func applyResultPresentation() {
handleCode() handleCode()
let isVip = isVipUnlocked() rootView.updateSubViews()
rootView.updateVipAccess(isUnlocked: isVip)
if !isVip {
rootView.actionBtn.setTitle("开通会员 解锁功能", for: .normal)
rootView.actionBtn.isHidden = false
}
} }
private func reactiveAction() { private func reactiveAction() {
rootView.vipMaskView.rx.tap
.subscribe(onNext: {
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
})
.disposed(by: disposeBag)
rootView.actionBtn.rx.tap.subscribe(onNext: { _ in rootView.actionBtn.rx.tap.subscribe(onNext: { _ in
guard self.isVipUnlocked() else {
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
return
}
switch self.code { switch self.code {
case 0: case 0:
NotificationCenter.default.post(name: .ShowMemberLocationNotification, NotificationCenter.default.post(name: .ShowMemberLocationNotification,

View File

@ -9,7 +9,6 @@ import Lottie
class SearchLocationResultView: UIView { class SearchLocationResultView: UIView {
let headerView = SearchLocationHeaderView() let headerView = SearchLocationHeaderView()
private var vipResultHeightConstraint: NSLayoutConstraint?
private func setupUI() { private func setupUI() {
addSubview(navBgView) addSubview(navBgView)
@ -45,15 +44,8 @@ class SearchLocationResultView: UIView {
.height(showInviteRow ? 72 : 0) .height(showInviteRow ? 72 : 0)
} }
func updateVipAccess(isUnlocked: Bool) { func updateSubViews() {
normalResultContentView.isHidden = !isUnlocked normalResultContentView.isHidden = false
vipMaskView.isHidden = isUnlocked
vipOfferImageView.isHidden = isUnlocked
vipResultHeightConstraint?.isActive = !isUnlocked
actionBtn.setBackgroundImage(
UIImage(named: isUnlocked ? "Common/button_bg_2" : "VipFeature/wide_button_bg"),
for: .normal
)
} }
lazy var navBgView: UIImageView = { lazy var navBgView: UIImageView = {
@ -85,7 +77,6 @@ class SearchLocationResultView: UIView {
resultCard.layoutChain resultCard.layoutChain
.topToBottomOfView(headerView, offset: 20) .topToBottomOfView(headerView, offset: 20)
.edgesHorzontal(15) .edgesHorzontal(15)
vipResultHeightConstraint = resultCard.heightAnchor.constraint(equalToConstant: 158)
contentView.addSubview(actionBtn) contentView.addSubview(actionBtn)
actionBtn.layoutChain actionBtn.layoutChain
@ -94,15 +85,6 @@ class SearchLocationResultView: UIView {
.height(56) .height(56)
.bottom(kSafeBottomMargin + 30) .bottom(kSafeBottomMargin + 30)
contentView.addSubview(vipOfferImageView)
vipOfferImageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
vipOfferImageView.trailingAnchor.constraint(equalTo: actionBtn.trailingAnchor, constant: -6),
vipOfferImageView.bottomAnchor.constraint(equalTo: actionBtn.topAnchor, constant: 10),
vipOfferImageView.widthAnchor.constraint(equalToConstant: 94),
vipOfferImageView.heightAnchor.constraint(equalToConstant: 32)
])
return view return view
}() }()
@ -115,8 +97,6 @@ class SearchLocationResultView: UIView {
resultStackView.layoutChain.edges() resultStackView.layoutChain.edges()
resultStackView.addArrangedSubview(normalResultContentView) resultStackView.addArrangedSubview(normalResultContentView)
card.addSubview(vipMaskView)
vipMaskView.layoutChain.edges()
return card return card
}() }()
@ -233,13 +213,6 @@ class SearchLocationResultView: UIView {
return btn return btn
}() }()
private lazy var vipOfferImageView: UIImageView = {
let view = UIImageView(image: UIImage(named: "VipFeature/limited_offer"))
view.contentMode = .scaleAspectFit
view.isHidden = true
return view
}()
var inviteBtn: UIButton { actionBtn } var inviteBtn: UIButton { actionBtn }
lazy var inviteView: UIView = { lazy var inviteView: UIView = {
@ -282,13 +255,6 @@ class SearchLocationResultView: UIView {
btn.cornerRadius = 18 btn.cornerRadius = 18
return btn return btn
}() }()
lazy var vipMaskView: UIButton = {
let view = UIButton(type: .custom)
view.setBackgroundImage(UIImage(named: "VipFeature/realtime_location"), for: .normal)
view.isHidden = true
return view
}()
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: .zero) super.init(frame: .zero)

View File

@ -130,12 +130,6 @@ final class TodayTrackDetailVC: BaseViewController {
}) })
.disposed(by: disposeBag) .disposed(by: disposeBag)
rootView.vipRequiredBtn.rx.tap
.subscribe(onNext: {
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
})
.disposed(by: disposeBag)
viewModel.displayedTrips viewModel.displayedTrips
.observe(on: MainScheduler.instance) .observe(on: MainScheduler.instance)
.subscribe(onNext: { [weak self] trips in .subscribe(onNext: { [weak self] trips in
@ -146,22 +140,7 @@ final class TodayTrackDetailVC: BaseViewController {
viewModel.isEmpty viewModel.isEmpty
.observe(on: MainScheduler.instance) .observe(on: MainScheduler.instance)
.subscribe(onNext: { [weak self] empty in .subscribe(onNext: { [weak self] empty in
guard let self, !self.viewModel.isVipRequired.value else { return } self?.rootView.emptyLab.isHidden = !empty
self.rootView.emptyLab.isHidden = !empty
})
.disposed(by: disposeBag)
viewModel.isVipRequired
.observe(on: MainScheduler.instance)
.distinctUntilChanged()
.subscribe(onNext: { [weak self] required in
guard let self else { return }
self.stopPlayback(resetProgress: true)
self.rootView.setVipRequired(required)
self.updateSheetHeight(isVipRequired: required)
if !required {
self.rootView.emptyLab.isHidden = !self.viewModel.isEmpty.value
}
}) })
.disposed(by: disposeBag) .disposed(by: disposeBag)
@ -202,14 +181,6 @@ final class TodayTrackDetailVC: BaseViewController {
} }
private func updateSheetHeight(isVipRequired: Bool) {
guard let constraint = rootView.sheetHeightConstraint else { return }
let minHeight: CGFloat = 200 + kSafeBottomMargin
let maxHeight: CGFloat = UIScreen.main.bounds.height * 0.7
let vipHeight: CGFloat = UIScreen.main.bounds.height * 0.47
constraint.constant = isVipRequired ? min(maxHeight, max(minHeight, vipHeight)) : minHeight
}
private func bindSheetPan() { private func bindSheetPan() {
let pan = UIPanGestureRecognizer() let pan = UIPanGestureRecognizer()
rootView.sheetView.addGestureRecognizer(pan) rootView.sheetView.addGestureRecognizer(pan)

View File

@ -150,14 +150,6 @@ final class TodayTrackDetailView: UIView {
return lab return lab
}() }()
let vipRequiredBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "Home/HistoryTrack/vip_required"), for: .normal)
btn.imageView?.contentMode = .scaleAspectFit
btn.isHidden = true
return btn
}()
private(set) var sheetHeightConstraint: NSLayoutConstraint? private(set) var sheetHeightConstraint: NSLayoutConstraint?
override init(frame: CGRect) { override init(frame: CGRect) {
@ -272,19 +264,6 @@ final class TodayTrackDetailView: UIView {
.centerX() .centerX()
.topToBottomOfView(dateBar, offset: 40) .topToBottomOfView(dateBar, offset: 40)
sheetView.addSubview(vipRequiredBtn)
vipRequiredBtn.layoutChain
.topToBottomOfView(dateBar, offset: 28)
.centerX()
.width(303)
.height(139)
}
func setVipRequired(_ required: Bool) {
vipRequiredBtn.isHidden = !required
timelineTV.isHidden = required
emptyLab.isHidden = true
playbackBar.isHidden = required
} }
func cleanupMap() { func cleanupMap() {

View File

@ -23,7 +23,6 @@ final class TodayTrackDetailViewModel {
let selectedTripId = BehaviorRelay<String?>(value: nil) let selectedTripId = BehaviorRelay<String?>(value: nil)
let displayedTrips = BehaviorRelay<[ScheduleRecordModel]>(value: []) let displayedTrips = BehaviorRelay<[ScheduleRecordModel]>(value: [])
let isEmpty = BehaviorRelay<Bool>(value: true) let isEmpty = BehaviorRelay<Bool>(value: true)
let isVipRequired = BehaviorRelay<Bool>(value: false)
let loading = BehaviorRelay<Bool>(value: false) let loading = BehaviorRelay<Bool>(value: false)
private let disposeBag = DisposeBag() private let disposeBag = DisposeBag()
@ -76,7 +75,6 @@ final class TodayTrackDetailViewModel {
selectedTripId.accept(nil) selectedTripId.accept(nil)
trips.accept([]) trips.accept([])
displayedTrips.accept([]) displayedTrips.accept([])
isVipRequired.accept(false)
isEmpty.accept(false) isEmpty.accept(false)
loadTrips(userId: userId, dateKey: dateKey) loadTrips(userId: userId, dateKey: dateKey)
} }
@ -95,19 +93,14 @@ final class TodayTrackDetailViewModel {
.subscribe(onNext: { [weak self] response in .subscribe(onNext: { [weak self] response in
guard let self, self.requestToken == token else { return } guard let self, self.requestToken == token else { return }
self.applyTrips(response.trips) self.applyTrips(response.trips)
}, onError: { [weak self] error in }, onError: { [weak self] _ in
guard let self, self.requestToken == token else { return } guard let self, self.requestToken == token else { return }
if error.gatewayStatusCode == 22000 {
self.applyVipRequired()
return
}
self.applyTrips([]) self.applyTrips([])
}) })
.disposed(by: disposeBag) .disposed(by: disposeBag)
} }
private func applyTrips(_ list: [ScheduleRecordModel]) { private func applyTrips(_ list: [ScheduleRecordModel]) {
isVipRequired.accept(false)
let sorted = list.sorted { $0.start_time < $1.start_time } let sorted = list.sorted { $0.start_time < $1.start_time }
trips.accept(sorted) trips.accept(sorted)
if selectedTripId.value == nil || !sorted.contains(where: { $0.id == selectedTripId.value }) { if selectedTripId.value == nil || !sorted.contains(where: { $0.id == selectedTripId.value }) {
@ -117,15 +110,6 @@ final class TodayTrackDetailViewModel {
loading.accept(false) loading.accept(false)
} }
private func applyVipRequired() {
selectedTripId.accept(nil)
trips.accept([])
displayedTrips.accept([])
isEmpty.accept(false)
isVipRequired.accept(true)
loading.accept(false)
}
private func applyDisplayedTrips() { private func applyDisplayedTrips() {
let all = trips.value let all = trips.value
if let id = selectedTripId.value, let one = all.first(where: { $0.id == id }) { if let id = selectedTripId.value, let one = all.first(where: { $0.id == id }) {

View File

@ -12,14 +12,6 @@ import RxCocoa
class LaunchViewController: BaseViewController { class LaunchViewController: BaseViewController {
private let guideImgList: [String] = [
"guide_1",
"guide_2",
"guide_3",
"guide_4",
"guide_5"
]
private let showVersion = 1 private let showVersion = 1
override func viewDidLoad() { override func viewDidLoad() {
@ -28,31 +20,9 @@ class LaunchViewController: BaseViewController {
// Do any additional setup after loading the view. // Do any additional setup after loading the view.
view.backgroundColor = .white view.backgroundColor = .white
setupLayout() setupLayout()
experienceBtn.rx.tap.subscribe(onNext: { _ in
Defaults[\.isShowGuide] = false
AppDelegate.shared.showMainViewController()
}).disposed(by: disposeBag)
getUserConfig() getUserConfig()
} }
private func navigateAfterDelay() {
Observable.just(())
.delay(.milliseconds(2500), scheduler: MainScheduler.instance)
.subscribe(onNext: { [weak self] in
guard let systemConfig = AppContextManager.shared.systemConfig else { return }
if systemConfig.guideDisplay, Defaults[\.isShowGuide] {
self?.collectionView.isHidden = false
self?.pageControl.isHidden = false
self?.experienceBtn.isHidden = false
} else {
AppDelegate.shared.showMainViewController()
}
})
.disposed(by: disposeBag)
}
/// ///
func getUserConfig() { func getUserConfig() {
SystemService.userConfig().subscribe(onNext: { response in SystemService.userConfig().subscribe(onNext: { response in
@ -122,7 +92,7 @@ class LaunchViewController: BaseViewController {
} }
private func continueAfterConfig(model: UserConfigModel) { private func continueAfterConfig(model: UserConfigModel) {
self.navigateAfterDelay() AppDelegate.shared.showMainViewController()
} }
private func showVersionUpgrade(_ upgrade: VersionUpgradeModel, model: UserConfigModel) { private func showVersionUpgrade(_ upgrade: VersionUpgradeModel, model: UserConfigModel) {
@ -155,62 +125,12 @@ class LaunchViewController: BaseViewController {
view.contentMode = .scaleAspectFill view.contentMode = .scaleAspectFill
return view return view
}() }()
///
lazy var collectionView: UICollectionView = {
let viewFlowLayout = UICollectionViewFlowLayout()
viewFlowLayout.scrollDirection = .horizontal
viewFlowLayout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
viewFlowLayout.minimumLineSpacing = 0
viewFlowLayout.minimumInteritemSpacing = 0
viewFlowLayout.itemSize = CGSizeMake(kScreenWidth, kScreenHeight)
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: viewFlowLayout)
collectionView.backgroundColor = .white
collectionView.dataSource = self
collectionView.delegate = self
collectionView.showsVerticalScrollIndicator = false
collectionView.showsHorizontalScrollIndicator = false
collectionView.isPagingEnabled = true
collectionView.bounces = false
collectionView.register(GuideCell.self)
collectionView.isHidden = true
return collectionView
}()
lazy var experienceBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setTitle("立即体验", for: .normal)
btn.setTitleColor(UIColor(hexStr: "#0F2846"), for: .normal)
btn.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
btn.setBackgroundImage(UIImage(named: "Guide/experience"), for: .normal)
btn.isHidden = true
return btn
}()
lazy var pageControl: JJPageControl = {
let pageControl = JJPageControl(frame: CGRectMake(0, 0, kScreenWidth, 10))
pageControl.currentColor = ThemeManager.shared.color.mainColor
pageControl.currentPointSize = CGSize(width: 20, height: 6)
pageControl.otherColor = ThemeManager.shared.color.mainColor.withAlphaComponent(0.5)
pageControl.otherPointSize = CGSize(width: 6, height: 6)
pageControl.pointCornerRadius = 3
pageControl.controlSpacing = 18
pageControl.pageAliment = .Center
pageControl.backgroundColor = .clear
pageControl.numberOfPages = guideImgList.count
pageControl.isHidden = true
return pageControl
}()
} }
extension LaunchViewController { extension LaunchViewController {
private func setupLayout() { private func setupLayout() {
view.addSubview(launchLogoView) view.addSubview(launchLogoView)
view.addSubview(tipsImgView) view.addSubview(tipsImgView)
view.addSubview(collectionView)
view.addSubview(experienceBtn)
view.addSubview(pageControl)
launchLogoView.layoutChain launchLogoView.layoutChain
.centerX() .centerX()
@ -219,74 +139,5 @@ extension LaunchViewController {
tipsImgView.layoutChain tipsImgView.layoutChain
.centerX() .centerX()
.bottom(kSafeBottomMargin + 50) .bottom(kSafeBottomMargin + 50)
collectionView.layoutChain.edges()
experienceBtn.layoutChain
.bottom(kSafeBottomMargin + 23)
.width(245)
.height(50)
.centerX()
pageControl.layoutChain
.bottomToTopOfView(experienceBtn, offset: -25)
.edgesHorzontal(10)
.centerX()
.height(10)
}
}
// MARK: - UICollectionViewDataSource
extension LaunchViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
guideImgList.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: GuideCell = collectionView.dequeueReusableCell(for: indexPath)
cell.configure(imageName: guideImgList[indexPath.row])
return cell
}
}
// MARK: - UICollectionViewDelegate
extension LaunchViewController: UICollectionViewDelegate {
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
if scrollView == collectionView {
let page = Int(scrollView.contentOffset.x / scrollView.dl.width)
pageControl.currentPage = page
}
}
}
class GuideCell: UICollectionViewCell {
func configure(imageName: String) {
imgView.image = UIImage(named: "Guide/" + imageName)
}
private func setupSubViews() {
addSubview(imgView)
setupLayout()
}
private func setupLayout() {
imgView.layoutChain.edges()
}
lazy var imgView: UIImageView = {
let icon = UIImageView()
icon.contentMode = .scaleAspectFill
return icon
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.backgroundColor = .clear
setupSubViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
} }
} }

View File

@ -13,12 +13,10 @@ final class LockDistractVC: BaseViewController {
private var groupModel: GroupModel? private var groupModel: GroupModel?
private var ownedGroups: [GroupInfoModel] = [] private var ownedGroups: [GroupInfoModel] = []
private var activeGroupKey: String = "" private var activeGroupKey: String = ""
private var groupVip = GroupMemberVip()
private var members: [GroupMemberModel] = [] private var members: [GroupMemberModel] = []
private var selectedIndex = 0 private var selectedIndex = 0
private var lockAppsDisposable: Disposable? private var lockAppsDisposable: Disposable?
private let lockStateSubscriptionOwner = UUID() private let lockStateSubscriptionOwner = UUID()
private var hasAppeared = false
override var isNavigationBarHidden: Bool { true } override var isNavigationBarHidden: Bool { true }
@ -31,18 +29,9 @@ final class LockDistractVC: BaseViewController {
super.viewDidLoad() super.viewDidLoad()
view.backgroundColor = UIColor(hexStr: "#FAFAFA") view.backgroundColor = UIColor(hexStr: "#FAFAFA")
bind() bind()
applyGroupVip(groupVip)
loadGroupMembers() loadGroupMembers()
} }
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if hasAppeared {
refreshGroupVip()
}
hasAppeared = true
}
@MainActor deinit { @MainActor deinit {
MQTTService.shared.updateLockStateSubscriptions( MQTTService.shared.updateLockStateSubscriptions(
owner: lockStateSubscriptionOwner, owner: lockStateSubscriptionOwner,
@ -156,7 +145,6 @@ final class LockDistractVC: BaseViewController {
private func loadUsers(for groupKey: String) { private func loadUsers(for groupKey: String) {
guard !groupKey.isEmpty else { guard !groupKey.isEmpty else {
applyGroupVip(GroupMemberVip())
applyMembers([]) applyMembers([])
return return
} }
@ -167,7 +155,6 @@ final class LockDistractVC: BaseViewController {
return return
} }
guard let self, self.activeGroupKey == groupKey else { return } guard let self, self.activeGroupKey == groupKey else { return }
self.applyGroupVip(response.vip)
self.applyMembers(response.list) self.applyMembers(response.list)
}, onError: { error in }, onError: { error in
DLToast.showError(error) DLToast.showError(error)
@ -187,28 +174,6 @@ final class LockDistractVC: BaseViewController {
loadLockableApps() loadLockableApps()
} }
private var isAppLockVipUnlocked: Bool {
groupVip.app_lock == true
}
private func applyGroupVip(_ vip: GroupMemberVip) {
groupVip = vip
rootView.updateVipAccess(isUnlocked: isAppLockVipUnlocked)
}
private func refreshGroupVip() {
let groupKey = activeGroupKey
guard !groupKey.isEmpty else { return }
GroupService.groupUsers(groupKey: groupKey)
.subscribe(onNext: { [weak self] response in
guard let self,
self.activeGroupKey == groupKey,
response.isValid(for: groupKey) else { return }
self.applyGroupVip(response.vip)
}, onError: { _ in })
.disposed(by: disposeBag)
}
private func stepMember(_ delta: Int) { private func stepMember(_ delta: Int) {
guard !members.isEmpty else { return } guard !members.isEmpty else { return }
let count = members.count let count = members.count
@ -326,9 +291,8 @@ final class LockDistractVC: BaseViewController {
} }
DLToast.showLoading() DLToast.showLoading()
UserService.requestPhoneUnlock(os: os, groupKey: activeGroupKey, tokens: tokens) UserService.requestPhoneUnlock(os: os, groupKey: activeGroupKey, tokens: tokens)
.subscribe(onNext: { [weak self] _ in .subscribe(onNext: { _ in
DLToast.show(text: "已向圈主发送解锁请求") DLToast.show(text: "已向圈主发送解锁请求")
self?.refreshGroupVip()
}, onError: { error in }, onError: { error in
DLToast.show(error, fallbackText: "发送失败") DLToast.show(error, fallbackText: "发送失败")
}) })
@ -359,7 +323,6 @@ final class LockDistractVC: BaseViewController {
self?.rootView.lockBtn.isEnabled = true self?.rootView.lockBtn.isEnabled = true
DLToast.show(text: "已解锁") DLToast.show(text: "已解锁")
self?.loadLockableApps() self?.loadLockableApps()
self?.refreshGroupVip()
}, onError: { [weak self] error in }, onError: { [weak self] error in
self?.rootView.lockBtn.isEnabled = true self?.rootView.lockBtn.isEnabled = true
DLToast.show(error, fallbackText: "解锁失败") DLToast.show(error, fallbackText: "解锁失败")
@ -368,10 +331,6 @@ final class LockDistractVC: BaseViewController {
} }
private func performPrimaryAction() { private func performPrimaryAction() {
if rootView.primaryAction == .lock, !isAppLockVipUnlocked {
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
return
}
switch rootView.primaryAction { switch rootView.primaryAction {
case .requestUnlock: case .requestUnlock:
requestUnlockForLockedApps() requestUnlockForLockedApps()
@ -385,10 +344,6 @@ final class LockDistractVC: BaseViewController {
} }
private func lockSelectedApps() { private func lockSelectedApps() {
guard isAppLockVipUnlocked else {
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
return
}
guard let member = selectedMember, !activeGroupKey.isEmpty else { guard let member = selectedMember, !activeGroupKey.isEmpty else {
DLToast.show(text: "请选择要锁定的成员") DLToast.show(text: "请选择要锁定的成员")
return return
@ -414,7 +369,6 @@ final class LockDistractVC: BaseViewController {
self?.rootView.lockBtn.isEnabled = true self?.rootView.lockBtn.isEnabled = true
DLToast.show(text: "锁定成功") DLToast.show(text: "锁定成功")
self?.loadLockableApps() self?.loadLockableApps()
self?.refreshGroupVip()
}, onError: { [weak self] error in }, onError: { [weak self] error in
self?.rootView.lockBtn.isEnabled = true self?.rootView.lockBtn.isEnabled = true
DLToast.show(error, fallbackText: "锁定失败") DLToast.show(error, fallbackText: "锁定失败")

View File

@ -35,7 +35,6 @@ final class LockDistractView: UIView {
private(set) var isLocked = false private(set) var isLocked = false
private(set) var isCurrentUser = false private(set) var isCurrentUser = false
private(set) var primaryAction: LockDistractPrimaryAction = .lock private(set) var primaryAction: LockDistractPrimaryAction = .lock
private(set) var isVipUnlocked = true
private let copyMaxLength = 20 private let copyMaxLength = 20
private var lockBtnHeightConstraint: NSLayoutConstraint? private var lockBtnHeightConstraint: NSLayoutConstraint?
private var bottomStackToAppsConstraint: NSLayoutConstraint? private var bottomStackToAppsConstraint: NSLayoutConstraint?
@ -111,11 +110,6 @@ final class LockDistractView: UIView {
appCollectionView.reloadData() appCollectionView.reloadData()
} }
func updateVipAccess(isUnlocked: Bool) {
isVipUnlocked = isUnlocked
applyLockedState()
}
var selectedLockApps: [PhoneLockAppItem] { var selectedLockApps: [PhoneLockAppItem] {
lockableApps.enumerated().compactMap { index, app in lockableApps.enumerated().compactMap { index, app in
selectedAppIndexes.contains(index) ? app : nil selectedAppIndexes.contains(index) ? app : nil
@ -173,13 +167,12 @@ final class LockDistractView: UIView {
appCollectionView.reloadData() appCollectionView.reloadData()
lockBtn.isHidden = lockedByOthers lockBtn.isHidden = lockedByOthers
lockBtnHeightConstraint?.constant = lockedByOthers ? 0 : 56 lockBtnHeightConstraint?.constant = lockedByOthers ? 0 : 56
vipOfferImageView.isHidden = lockedByOthers || primaryAction != .lock || isVipUnlocked
switch primaryAction { switch primaryAction {
case .lock: case .lock:
tipLab.text = "锁定功能需要在对方开启权限情况下才能使用哟~" tipLab.text = "锁定功能需要在对方开启权限情况下才能使用哟~"
lockBtn.setTitle(isVipUnlocked ? "锁定" : "开通会员 解锁功能", for: .normal) lockBtn.setTitle("锁定", for: .normal)
lockBtn.setBackgroundImage( lockBtn.setBackgroundImage(
UIImage(named: isVipUnlocked ? "Common/button_bg_2" : "VipFeature/wide_button_bg"), UIImage(named: "Common/button_bg_2"),
for: .normal for: .normal
) )
case .requestUnlock: case .requestUnlock:
@ -208,7 +201,6 @@ final class LockDistractView: UIView {
addSubview(footerBar) addSubview(footerBar)
footerBar.addSubview(tipRow) footerBar.addSubview(tipRow)
footerBar.addSubview(lockBtn) footerBar.addSubview(lockBtn)
footerBar.addSubview(vipOfferImageView)
contentView.addSubview(navBgView) contentView.addSubview(navBgView)
contentView.addSubview(statsRow) contentView.addSubview(statsRow)
@ -244,14 +236,6 @@ final class LockDistractView: UIView {
.bottomToTopOfView(lockBtn, offset: -8) .bottomToTopOfView(lockBtn, offset: -8)
.top(10) .top(10)
vipOfferImageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
vipOfferImageView.trailingAnchor.constraint(equalTo: lockBtn.trailingAnchor, constant: -6),
vipOfferImageView.bottomAnchor.constraint(equalTo: lockBtn.topAnchor, constant: 10),
vipOfferImageView.widthAnchor.constraint(equalToConstant: 94),
vipOfferImageView.heightAnchor.constraint(equalToConstant: 32)
])
scrollView.layoutChain scrollView.layoutChain
.top() .top()
.edgesHorzontal() .edgesHorzontal()
@ -727,13 +711,6 @@ final class LockDistractView: UIView {
return btn return btn
}() }()
lazy var vipOfferImageView: UIImageView = {
let view = UIImageView(image: UIImage(named: "VipFeature/limited_offer"))
view.contentMode = .scaleAspectFit
view.isHidden = true
return view
}()
private func makeSectionTitle(_ text: String) -> UIView { private func makeSectionTitle(_ text: String) -> UIView {
let row = UIView() let row = UIView()
let star = UIImageView(image: UIImage(named: "LockDistract/section_star")) let star = UIImageView(image: UIImage(named: "LockDistract/section_star"))

View File

@ -63,6 +63,7 @@ final class AboutVC: BaseViewController {
} }
@objc private func handleLogoTap() { @objc private func handleLogoTap() {
#if DEBUG || AdHoc
logoTapResetWork?.cancel() logoTapResetWork?.cancel()
logoTapCount += 1 logoTapCount += 1
if logoTapCount >= 5 { if logoTapCount >= 5 {
@ -75,6 +76,7 @@ final class AboutVC: BaseViewController {
} }
logoTapResetWork = work logoTapResetWork = work
DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: work) DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: work)
#endif
} }
private func showServerSwitchAlert() { private func showServerSwitchAlert() {

View File

@ -73,10 +73,9 @@ final class CancelAccountView: UIView {
.bottom(20) .bottom(20)
let specs: [(String, String)] = [ let specs: [(String, String)] = [
("1. 放弃当前的VIP权益", "当前充值的VIP我们不会退款请解除你的自动续费如果有同意请打勾"), ("1. 当前账号没有违规及其他的法律纠纷", "同意请打勾"),
("2. 当前账号没有违规及其他的法律纠纷", "同意请打勾"), ("2. 确认是账号本人进行注销操作,自愿承担后果", "同意请打勾"),
("3. 确认是账号本人进行注销操作,自愿承担后果", "同意请打勾"), ("3. 账号注销后账号不可登录,不可恢复", "同意请打勾")
("4. 账号注销后账号不可登录,不可恢复", "同意请打勾")
] ]
var previous: UIView? var previous: UIView?
for spec in specs { for spec in specs {
@ -96,7 +95,7 @@ final class CancelAccountView: UIView {
agreementBtn.titleLabel?.font = .systemFont(ofSize: 13, weight: .medium) agreementBtn.titleLabel?.font = .systemFont(ofSize: 13, weight: .medium)
agreementBtn.contentHorizontalAlignment = .left agreementBtn.contentHorizontalAlignment = .left
let agreementItem = CancelCheckItemView( let agreementItem = CancelCheckItemView(
title: "5. 账号注销协议", title: "4. 账号注销协议",
actionButton: agreementBtn actionButton: agreementBtn
) )
checkItems.append(agreementItem) checkItems.append(agreementItem)
@ -104,7 +103,7 @@ final class CancelAccountView: UIView {
agreementItem.layoutChain.topToBottomOfView(previous!).edgesHorzontal(14) agreementItem.layoutChain.topToBottomOfView(previous!).edgesHorzontal(14)
let tip6 = UILabel() let tip6 = UILabel()
tip6.text = "6. 请在输入框中输入以下文字" tip6.text = "5. 请在输入框中输入以下文字"
tip6.font = .systemFont(ofSize: 16, weight: .medium) tip6.font = .systemFont(ofSize: 16, weight: .medium)
tip6.textColor = UIColor(hexStr: "#293445") tip6.textColor = UIColor(hexStr: "#293445")
card.addSubview(tip6) card.addSubview(tip6)

View File

@ -13,30 +13,13 @@ final class MineView: UIView {
var disposeBag = DisposeBag() var disposeBag = DisposeBag()
private let vipCardHeight: CGFloat = 90
private let settingsRowHeight: CGFloat = 52 private let settingsRowHeight: CGFloat = 52
private let quickItemTitles = ["权限检测", "隐私设置", "状态设置", "账户设置"] private let quickItemTitles = ["权限检测", "隐私设置", "状态设置", "账户设置"]
var onQuickTap: ((String) -> Void)? var onQuickTap: ((String) -> Void)?
func setupData(_ model: UserConfigModel) { func setupData(_ model: UserConfigModel) {
guard AppContextManager.shared.systemConfig?.isIntercept == false else {
maskBgView.isHidden = false
return
}
maskBgView.isHidden = true
guard model.vip > 1 else {
vipTitleLab.text = "开通会员"
vipContentLab.text = "会员尊享10+VIP特权"
vipActivateButton.isHidden = false
vipActivateButton.setTitle("立即开通", for: .normal)
return
}
vipTitleLab.text = model.vip_name
vipContentLab.text = model.vip == 3 ? "会员终身有效"
: "会员到期:\(self.getDateInterval2String(date: model.vip_expire_time, dateFormat: "yyyy.MM.dd"))"
vipActivateButton.setTitle("点击续费", for: .normal)
vipActivateButton.isHidden = model.vip == 3
} }
// MARK: - Components // MARK: - Components
@ -72,55 +55,20 @@ final class MineView: UIView {
MinePhotoWallView() MinePhotoWallView()
}() }()
lazy var vipCardView: UIView = { lazy var cardView: UIView = {
let view = UIView() let view = UIView()
view.layer.cornerRadius = 16 view.layer.cornerRadius = 16
view.clipsToBounds = true view.clipsToBounds = true
return view return view
}() }()
lazy var vipCardBgImageView: UIImageView = {
let iv = UIImageView()
iv.image = UIImage(named: "Mine/vip_card")
iv.contentMode = .scaleToFill
return iv
}()
lazy var maskBgView: UIImageView = { lazy var maskBgView: UIImageView = {
let iv = UIImageView() let iv = UIImageView()
iv.image = UIImage(named: "Mine/mask_bg") iv.image = UIImage(named: "Mine/mask_bg")
iv.contentMode = .scaleToFill iv.contentMode = .scaleToFill
iv.isHidden = true
return iv return iv
}() }()
lazy var vipTitleLab: UILabel = {
let label = UILabel()
label.font = FontManager.boboBold(18)
label.textColor = .white
label.text = " "
return label
}()
lazy var vipContentLab: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 12, weight: .medium)
label.textColor = .white
label.text = " "
return label
}()
lazy var vipActivateButton: UIButton = {
let btn = UIButton(type: .custom)
btn.backgroundColor = UIColor(hexStr: "#C0FF54")
btn.setTitle("立即开通", for: .normal)
btn.setTitleColor(UIColor(hexStr: "#00343B"), for: .normal)
btn.titleLabel?.font = FontManager.boboBold(14)
btn.cornerRadius = 9
btn.isHidden = true
return btn
}()
private lazy var quickCardView: UIView = { private lazy var quickCardView: UIView = {
let v = UIView() let v = UIView()
v.backgroundColor = .white v.backgroundColor = .white
@ -190,12 +138,8 @@ final class MineView: UIView {
addSubview(navBgView) addSubview(navBgView)
addSubview(photoWall) addSubview(photoWall)
contentView.addSubview(vipCardView) contentView.addSubview(cardView)
vipCardView.addSubview(vipCardBgImageView) cardView.addSubview(maskBgView)
vipCardView.addSubview(vipActivateButton)
vipCardView.addSubview(vipTitleLab)
vipCardView.addSubview(vipContentLab)
vipCardView.addSubview(maskBgView)
contentView.addSubview(quickCardView) contentView.addSubview(quickCardView)
quickCardView.addSubview(quickStack) quickCardView.addSubview(quickStack)
@ -230,29 +174,15 @@ final class MineView: UIView {
.edges() .edges()
.widthToView(scrollView) .widthToView(scrollView)
vipCardView.layoutChain cardView.layoutChain
.top(12) .top(12)
.left(16).right(16) .left(16).right(16)
.height(vipCardHeight) .height(90)
vipCardBgImageView.layoutChain.edges()
vipTitleLab.layoutChain
.top(22)
.left(77)
vipContentLab.layoutChain
.topToBottomOfView(vipTitleLab, offset: 6)
.leftToView(vipTitleLab)
vipActivateButton.layoutChain
.right(19).centerY()
.width(70).height(28)
maskBgView.layoutChain.edges() maskBgView.layoutChain.edges()
quickCardView.layoutChain quickCardView.layoutChain
.topToBottomOfView(vipCardView, offset: 20) .topToBottomOfView(cardView, offset: 20)
.left(16).right(16) .left(16).right(16)
.height(90) .height(90)

View File

@ -56,12 +56,6 @@ final class MineViewController: BaseViewController {
} }
private func reactiveAction() { private func reactiveAction() {
rootView.vipActivateButton.rx.tap
.subscribe(onNext: { _ in
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
})
.disposed(by: disposeBag)
rootView.photoWall.onTapMember = { [weak self] member in rootView.photoWall.onTapMember = { [weak self] member in
self?.openMemberInfo(selectedUserId: member.user_id) self?.openMemberInfo(selectedUserId: member.user_id)
} }

View File

@ -13,7 +13,6 @@ final class PigeonMessageVC: BaseViewController {
private var rootView: PigeonMessageView! private var rootView: PigeonMessageView!
private var groupModel: GroupModel? private var groupModel: GroupModel?
private var activeGroupKey: String = "" private var activeGroupKey: String = ""
private var groupVip = GroupMemberVip()
private var members: [GroupMemberModel] = [] private var members: [GroupMemberModel] = []
private var selectedMembers: [GroupMemberModel] = [] private var selectedMembers: [GroupMemberModel] = []
private var selectedImage: UIImage? private var selectedImage: UIImage?
@ -27,7 +26,6 @@ final class PigeonMessageVC: BaseViewController {
private var playbackTimer: Timer? private var playbackTimer: Timer?
private var recordedDuration: TimeInterval = 0 private var recordedDuration: TimeInterval = 0
private var isPressingRecord = false private var isPressingRecord = false
private var hasAppeared = false
override func loadView() { override func loadView() {
rootView = PigeonMessageView(frame: UIScreen.main.bounds) rootView = PigeonMessageView(frame: UIScreen.main.bounds)
@ -38,18 +36,9 @@ final class PigeonMessageVC: BaseViewController {
super.viewDidLoad() super.viewDidLoad()
bindActions() bindActions()
setupRecordingGesture() setupRecordingGesture()
applyGroupVip(groupVip)
loadMembers() loadMembers()
} }
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if hasAppeared {
refreshGroupVip()
}
hasAppeared = true
}
override func viewWillDisappear(_ animated: Bool) { override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated) super.viewWillDisappear(animated)
guard isMovingFromParent || navigationController?.isBeingDismissed == true else { return } guard isMovingFromParent || navigationController?.isBeingDismissed == true else { return }
@ -120,7 +109,6 @@ final class PigeonMessageVC: BaseViewController {
private func loadUsers(for groupKey: String, showLoading: Bool) { private func loadUsers(for groupKey: String, showLoading: Bool) {
guard !groupKey.isEmpty else { guard !groupKey.isEmpty else {
DLToast.dismiss() DLToast.dismiss()
applyGroupVip(GroupMemberVip())
applyMembers([]) applyMembers([])
return return
} }
@ -133,7 +121,6 @@ final class PigeonMessageVC: BaseViewController {
return return
} }
guard let self, self.activeGroupKey == groupKey else { return } guard let self, self.activeGroupKey == groupKey else { return }
self.applyGroupVip(response.vip)
self.applyMembers(response.list) self.applyMembers(response.list)
}, onError: { error in }, onError: { error in
DLToast.dismiss() DLToast.dismiss()
@ -148,28 +135,6 @@ final class PigeonMessageVC: BaseViewController {
rootView.configureMembers(members, selectedIds: []) rootView.configureMembers(members, selectedIds: [])
} }
private var isPigeonVipUnlocked: Bool {
groupVip.pigeon_mail == true
}
private func applyGroupVip(_ vip: GroupMemberVip) {
groupVip = vip
rootView.updateVipAccess(isUnlocked: isPigeonVipUnlocked)
}
private func refreshGroupVip() {
let groupKey = activeGroupKey
guard !groupKey.isEmpty else { return }
GroupService.groupUsers(groupKey: groupKey)
.subscribe(onNext: { [weak self] response in
guard let self,
self.activeGroupKey == groupKey,
response.isValid(for: groupKey) else { return }
self.applyGroupVip(response.vip)
}, onError: { _ in })
.disposed(by: disposeBag)
}
private func updateCurrentGroupDisplay() { private func updateCurrentGroupDisplay() {
let groupName = groupModel?.groups.first { let groupName = groupModel?.groups.first {
$0.group_key == activeGroupKey $0.group_key == activeGroupKey
@ -516,10 +481,6 @@ final class PigeonMessageVC: BaseViewController {
} }
@objc private func sendMessage() { @objc private func sendMessage() {
guard isPigeonVipUnlocked else {
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
return
}
if let wait = pigeonSendWaitSeconds() { if let wait = pigeonSendWaitSeconds() {
DLToast.show(text: "发送过于频繁,请\(Self.formatWaitDuration(wait))后再试") DLToast.show(text: "发送过于频繁,请\(Self.formatWaitDuration(wait))后再试")
return return
@ -619,9 +580,7 @@ final class PigeonMessageVC: BaseViewController {
self.cleanupAudio(deleteFile: true) self.cleanupAudio(deleteFile: true)
self.rootView.clearVoiceDraft() self.rootView.clearVoiceDraft()
self.recordPigeonSendSuccess() self.recordPigeonSendSuccess()
DLToast.show(text: "发送成功") { DLToast.show(text: "发送成功")
self.refreshGroupVip()
}
}, onError: { error in }, onError: { error in
DLToast.dismiss() DLToast.dismiss()
DLToast.show(error) DLToast.show(error)

View File

@ -82,7 +82,6 @@ final class PigeonMessageView: UIView, UITextFieldDelegate {
private let recordingHintLabel = UILabel() private let recordingHintLabel = UILabel()
private let voiceTimeLabel = UILabel() private let voiceTimeLabel = UILabel()
private let waveformView = PigeonWaveformView() private let waveformView = PigeonWaveformView()
private let vipOfferImageView = UIImageView(image: UIImage(named: "VipFeature/limited_offer"))
private var selectedImageHeightConstraint: NSLayoutConstraint? private var selectedImageHeightConstraint: NSLayoutConstraint?
private var isRecording = false private var isRecording = false
@ -253,15 +252,6 @@ final class PigeonMessageView: UIView, UITextFieldDelegate {
updateMode() updateMode()
} }
func updateVipAccess(isUnlocked: Bool) {
sendButton.setTitle(isUnlocked ? "发送" : "开通会员 解锁功能", for: .normal)
sendButton.setBackgroundImage(
UIImage(named: isUnlocked ? "Common/button_bg_2" : "VipFeature/wide_button_bg"),
for: .normal
)
vipOfferImageView.isHidden = isUnlocked
}
private func setupUI() { private func setupUI() {
let headerView = PigeonHeaderGradientView() let headerView = PigeonHeaderGradientView()
addSubview(headerView) addSubview(headerView)
@ -394,17 +384,6 @@ final class PigeonMessageView: UIView, UITextFieldDelegate {
.topToBottomOfView(modeContainer, offset: 12) .topToBottomOfView(modeContainer, offset: 12)
.edgesHorzontal(15) .edgesHorzontal(15)
.bottom(16) .bottom(16)
vipOfferImageView.contentMode = .scaleAspectFit
vipOfferImageView.isHidden = true
addSubview(vipOfferImageView)
vipOfferImageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
vipOfferImageView.trailingAnchor.constraint(equalTo: sendButton.trailingAnchor, constant: -6),
vipOfferImageView.bottomAnchor.constraint(equalTo: sendButton.topAnchor, constant: 10),
vipOfferImageView.widthAnchor.constraint(equalToConstant: 94),
vipOfferImageView.heightAnchor.constraint(equalToConstant: 32)
])
} }
private func setupRecipientCard(_ card: UIView) { private func setupRecipientCard(_ card: UIView) {

View File

@ -1,195 +0,0 @@
//
// PopupQueueManager.swift
// QuickLocation
//
// Created by on 2026/7/3.
//
import UIKit
class PopupQueueManager {
private weak var sourceVC: UIViewController?
private var currentStep = 0
private var stepGeneration = 0
private var countdownTimer: Timer?
private var isPaused = false
init() {
NotificationCenter.default.addObserver(self,
selector: #selector(handlePause),
name: .pausePopupQueue,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(handleResume),
name: .resumePopupQueue,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(handleInvalidate),
name: .invalidatePopupQueue,
object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
func start(from vc: UIViewController) {
sourceVC = vc
currentStep = 0
executeNextStep()
}
@objc private func handlePause() {
countdownTimer?.invalidate()
countdownTimer = nil
isPaused = true
}
@objc private func handleResume() {
guard isPaused else { return }
isPaused = false
executeNextStep()
}
@objc private func handleInvalidate() {
countdownTimer?.invalidate()
countdownTimer = nil
isPaused = true
currentStep = 3
}
private func executeNextStep() {
guard AppContextManager.shared.systemConfig?.isIntercept == false else { return }
switch currentStep {
case 0:
tryStartPromotionalActivities()
case 1:
tryStartSearchPopup()
case 2:
tryStartRegisterOrVipPopup()
default:
break
}
}
// MARK: - Step 0: PromotionalActivities
private func tryStartPromotionalActivities() {
guard let config = AppContextManager.shared.systemConfig else {
skipToNext()
return
}
guard config.popupConfig?.pay_pop == true,
AppContextManager.shared.vip == 1,
let timeConfig = config.timeConfig else {
skipToNext()
return
}
let gen = stepGeneration
startCountdown(seconds: timeConfig.pay_pop_time) { [weak self] in
guard let self = self, self.currentStep == 0, self.stepGeneration == gen else { return }
/// TODO
}
}
// MARK: - Step 1: Search PopupWindow
private func tryStartSearchPopup() {
guard let config = AppContextManager.shared.systemConfig else {
skipToNext()
return
}
guard config.popupConfig?.search_phone == true,
let timeConfig = config.timeConfig else {
skipToNext()
return
}
let gen = stepGeneration
startCountdown(seconds: timeConfig.search_phone) {
guard self.currentStep == 1, self.stepGeneration == gen else { return }
PopupWindow.show(popupType: .search) {
self.skipToNext()
}
}
}
// MARK: - Step 2: Register or VIP PopupWindow (mutually exclusive)
private func tryStartRegisterOrVipPopup() {
guard let config = AppContextManager.shared.systemConfig,
let timeConfig = config.timeConfig else {
return
}
if AppContextManager.shared.isGuest {
let gen = stepGeneration
startCountdown(seconds: timeConfig.signup_tip) {
guard self.currentStep == 2, self.stepGeneration == gen else { return }
PopupWindow.show(popupType: .register) {
// done
}
}
} else if AppContextManager.shared.vip == 1 {
let gen = stepGeneration
startCountdown(seconds: timeConfig.buy_vip_tip) {
guard self.currentStep == 2, self.stepGeneration == gen else { return }
PopupWindow.show(popupType: .vip) {
// done
}
}
}
}
// MARK: - Helpers
private func skipToNext() {
stepGeneration += 1
currentStep += 1
executeNextStep()
}
private func startCountdown(seconds: Int, onExpired: @escaping () -> Void) {
guard seconds > 0 else {
onExpired()
return
}
countdownTimer?.invalidate()
var remaining = seconds
countdownTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in
remaining -= 1
if remaining <= 0 {
timer.invalidate()
self?.countdownTimer = nil
onExpired()
}
}
}
private func push(_ vc: UIViewController) {
let topVC = topViewController()
guard let nav = topVC?.navigationController else { return }
if nav.viewControllers.contains(where: { type(of: $0) == type(of: vc) }) {
return
}
nav.pushViewController(vc, animated: true)
}
private func topViewController() -> UIViewController? {
guard let rootVC = kKeyWindow?.rootViewController else { return nil }
return topViewController(from: rootVC)
}
private func topViewController(from root: UIViewController) -> UIViewController {
if let presented = root.presentedViewController {
return topViewController(from: presented)
}
if let nav = root as? UINavigationController, let visible = nav.visibleViewController {
return topViewController(from: visible)
}
if let tab = root as? UITabBarController, let selected = tab.selectedViewController {
return topViewController(from: selected)
}
return root
}
}

File diff suppressed because it is too large Load Diff

View File

@ -110,16 +110,7 @@ class CreateScheduleVC: BaseViewController, MAMapViewDelegate {
AppRouter.shared.popOrDismiss() AppRouter.shared.popOrDismiss()
} }
}, onError: { error in }, onError: { error in
guard let code = error.underlyingError?.code else { return } self.dl.show(error)
guard let systemConfig = AppContextManager.shared.systemConfig, systemConfig.isIntercept == false else { return }
if code == 20010 { // ""
CreateScheduleVipPopView.show()
}
else {
self.dl.show(error)
}
}).disposed(by: disposeBag) }).disposed(by: disposeBag)
} }

View File

@ -1,120 +0,0 @@
//
// CreateScheduleVipPopView.swift
// QuickLocation
//
// Created by on 2026/6/25.
//
import UIKit
import RxSwift
import RxCocoa
class CreateScheduleVipPopView: UIView {
private static let shared = CreateScheduleVipPopView(frame: CGRect(origin: .zero, size: kScreenSize))
var disposeBag = DisposeBag()
static func show() {
guard let superView = kKeyWindow else {
return
}
if CreateScheduleVipPopView.shared.superview != nil {
CreateScheduleVipPopView.shared.removeFromSuperview()
CreateScheduleVipPopView.shared.bgView.frame = .zero
}
CreateScheduleVipPopView.shared.bgView.alpha = 1
CreateScheduleVipPopView.shared.bgView.frame = CGRect(x: 0, y: 0, width: kScreenWidth, height: kScreenHeight)
superView.addSubview(CreateScheduleVipPopView.shared)
superView.bringSubviewToFront(CreateScheduleVipPopView.shared)
UIView.animate(withDuration: 0.25) {
CreateScheduleVipPopView.shared.bgView.alpha = 1
}
}
///
static func dismiss() {
guard CreateScheduleVipPopView.shared.superview != nil else { return }
UIView.animate(withDuration: 0.25, delay: 0, options: [.curveEaseIn]) {
CreateScheduleVipPopView.shared.bgView.alpha = 0
} completion: { _ in
CreateScheduleVipPopView.shared.removeFromSuperview()
}
}
private func setupRx() {
upgradedBtn.rx.tap.subscribe(onNext: { _ in
CreateScheduleVipPopView.dismiss()
AppRouter.push(Route.web, userInfo: ["url": URLManager.shared.homeUrl])
}).disposed(by: disposeBag)
closeBtn.rx.tap.subscribe(onNext: { _ in
CreateScheduleVipPopView.dismiss()
}).disposed(by: disposeBag)
}
private lazy var bgView: UIView = {
let view = UIView()
view.backgroundColor = .black.withAlphaComponent(0.5)
return view
}()
lazy var vipImgView: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "Schedule/vip_pop")
view.contentMode = .scaleAspectFill
return view
}()
lazy var upgradedBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.backgroundColor = .clear
btn.setBackgroundImage(UIImage(named: "Schedule/upgrade_bg"), for: .normal)
return btn
}()
lazy var closeBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.backgroundColor = .clear
btn.setBackgroundImage(UIImage(named: "Group/close"), for: .normal)
btn.extendEdgeInsets = UIEdgeInsets(top: 10, left: 100, bottom: 100, right: 100)
return btn
}()
// MARK: - Init
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .clear
addSubview(bgView)
bgView.addSubview(vipImgView)
bgView.addSubview(upgradedBtn)
bgView.addSubview(closeBtn)
vipImgView.layoutChain
.centerY()
.edgesHorzontal(25)
.heightToWidth(814/648)
upgradedBtn.layoutChain
.topToBottomOfView(vipImgView, offset: -20)
.centerX()
.width(240)
.height(60)
closeBtn.layoutChain
.topToBottomOfView(upgradedBtn, offset: 15)
.centerX()
.width(22)
.height(22)
setupRx()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@ -1,179 +0,0 @@
//
// ScheduleVC.swift
// QuickLocation
//
// Created by on 2026/6/23.
//
import UIKit
import RxSwift
import RxCocoa
import RxDataSources
import MJRefresh
import ObjectMapper
class ScheduleVC: BaseViewController {
fileprivate var rootView: ScheduleView!
override func loadView() {
rootView = ScheduleView(frame: UIScreen.main.bounds)
view = rootView
}
private var viewModel = ScheduleViewModel()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
rootView.allCheckBtn.isSelected = true
setupTableViewHeaderFooter()
bindViewModel()
reactiveAction()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
requestFollowList()
requestData()
}
private func bindViewModel() {
viewModel.output.sectionedItems
.bind(to: rootView.collectionView.rx.items(dataSource: dataSource))
.disposed(by: disposeBag)
viewModel.output.scheduleSectionedItems
.bind(to: rootView.tableView.rx.items(dataSource: tableViewDataSource))
.disposed(by: disposeBag)
viewModel.output.refreshResult.subscribe(onNext: { [weak self] (status, isEmpty) in
guard let self = self else { return }
self.dl.dismiss()
self.rootView.tableView.refresh(status: status, isEmpty: isEmpty)
}).disposed(by: disposeBag)
viewModel.output.sectionedItems
.map { !($0.first?.items.isEmpty ?? true) }
.bind(to: rootView.emptyVisitorsLabel.rx.isHidden)
.disposed(by: disposeBag)
viewModel.output.scheduleSectionedItems
.map { !($0.first?.items.isEmpty ?? true) }
.bind(to: rootView.emptyScheduleLabel.rx.isHidden)
.disposed(by: disposeBag)
rootView.collectionView.rx.modelSelected(ViewedModel.self)
.subscribe(viewModel.viewedCellAction.inputs)
.disposed(by: disposeBag)
rootView.tableView.rx.modelSelected(ScheduleModel.self)
.subscribe(viewModel.cellAction.inputs)
.disposed(by: disposeBag)
}
private func reactiveAction() {
//
rootView.allCheckBtn.rx.tap.subscribe(onNext: { [weak self] _ in
guard let self = self, !self.rootView.allCheckBtn.isSelected else { return }
self.rootView.allCheckBtn.isSelected = true
self.rootView.followedCheckBtn.isSelected = false
self.rootView.mineCheckBtn.isSelected = false
self.changeCondition(follow: false, own: false)
}).disposed(by: disposeBag)
//
rootView.followedCheckBtn.rx.tap.subscribe(onNext: { [weak self] _ in
guard let self = self, !self.rootView.followedCheckBtn.isSelected else { return }
self.rootView.allCheckBtn.isSelected = false
self.rootView.followedCheckBtn.isSelected = true
self.rootView.mineCheckBtn.isSelected = false
self.changeCondition(follow: true, own: false)
}).disposed(by: disposeBag)
//
rootView.mineCheckBtn.rx.tap.subscribe(onNext: { [weak self] _ in
guard let self = self, !self.rootView.mineCheckBtn.isSelected else { return }
self.rootView.allCheckBtn.isSelected = false
self.rootView.followedCheckBtn.isSelected = false
self.rootView.mineCheckBtn.isSelected = true
self.changeCondition(follow: false, own: true)
}).disposed(by: disposeBag)
}
private func setupTableViewHeaderFooter() {
// header/footer
let header = MJRefreshNormalHeader(refreshingBlock: { [weak self] in
self?.viewModel.refresh()
})
header.addFeedbackGenerator()
header.stateLabel?.isHidden = true
rootView.tableView.mj_header = header
let footer = MJRefreshAutoNormalFooter(refreshingBlock: viewModel.loadMore)
footer.isHidden = true
rootView.tableView.mj_footer = footer
}
// MARK: - API
private func requestFollowList() {
DLToast.showLoading()
UserService.followList().subscribe(onNext: { response in
DLToast.dismiss()
self.viewModel.loadViewedData(response.list)
}).disposed(by: disposeBag)
}
private func requestSetFollow(id: String, op: Bool) {
DLToast.showLoading()
ItineraryService.follow(id: id, op: op ? 2 : 1).subscribe(onNext: { response in
DLToast.dismiss()
DLToast.show(text: op ? "已取消" : "已关注此行程, \n行程路线将自动添加到您的行程列表。")
self.requestData()
}).disposed(by: disposeBag)
}
// MARK: - API
private func requestData() {
viewModel.refresh()
}
//
private func changeCondition(follow: Bool, own: Bool) {
viewModel.changeCondition(follow: follow, own: own)
requestData()
}
// MARK: - dataSource
private lazy var dataSource: RxCollectionViewSectionedReloadDataSource<ViewedListSectionModel> = {
RxCollectionViewSectionedReloadDataSource<ViewedListSectionModel> { datasource, collectionView, indexPath, model in
let cell: ViewedCell = collectionView.dequeueReusableCell(for: indexPath)
cell.configure(model)
return cell
}
}()
// MARK: - UITableViewDataSource
lazy private var tableViewDataSource: RxTableViewSectionedReloadDataSource<ScheduleListSectionModel> = {
return RxTableViewSectionedReloadDataSource<ScheduleListSectionModel>(
configureCell: { (_, tableView, indexPath, model) in
let cell: ScheduleListPopCell = tableView.dequeueReusableCell(for: indexPath)
cell.configure(model)
//
cell.editBtn.rx.tap.subscribe(onNext: { _ in
AppRouter.push(Route.createSchedule, userInfo: ["scheduleJson": model.toJSON()])
}).disposed(by: cell.disposeBag)
//
cell.followBtn.rx.tap.subscribe(onNext: { _ in
self.requestSetFollow(id: model.id, op: cell.followBtn.isSelected)
}).disposed(by: cell.disposeBag)
return cell
}
)
}()
}

View File

@ -1,508 +0,0 @@
//
// ScheduleView.swift
// QuickLocation
//
// Created by on 2026/6/23.
//
import UIKit
import RxSwift
import RxCocoa
import TagListView
class ScheduleView: UIView {
var disposeBag = DisposeBag()
private func setupRx() {
createBtn.rx.tap.subscribe(onNext: { _ in
AppRouter.push(Route.createSchedule)
}).disposed(by: disposeBag)
}
private func setupUI() {
addSubview(navBgView)
addSubview(navView)
addSubview(headerView)
addSubview(travelRouteView)
addSubview(tableView)
addSubview(createBtn)
navBgView.layoutChain
.edges(excludingEdge: .bottom)
.height(kNaviHeight)
navView.layoutChain
.edges(excludingEdge: .bottom)
.height(kNaviHeight)
headerView.layoutChain
.topToBottomOfView(navView)
.edgesHorzontal()
// .height(147)
travelRouteView.layoutChain
.topToBottomOfView(headerView)
.edgesHorzontal()
tableView.layoutChain
.topToBottomOfView(travelRouteView)
.edges(excludingEdge: .top)
createBtn.layoutChain
.bottom(kSafeBottomMargin + 102)
.right(10)
.width(60)
.heightToWidth(1)
}
lazy var navBgView: UIImageView = {
let iv = UIImageView()
iv.image = UIImage(named: "Common/navBar_bg_1")
iv.contentMode = .scaleAspectFill
return iv
}()
lazy var navView: BaseNavigationView = {
let nav = BaseNavigationView(title: "行程")
nav.backBtn.isHidden = true
return nav
}()
///
lazy var headerView: UIView = {
let view = UIView()
view.backgroundColor = .clear
let titleLab = UILabel()
titleLab.text = "谁看过我"
titleLab.font = .systemFont(ofSize: 16, weight: .medium)
titleLab.textColor = ThemeManager.shared.color.titleAuxColor
view.addSubview(titleLab)
titleLab.layoutChain
.top(15)
let dotView = UIView()
dotView.backgroundColor = UIColor(hexStr: "#16B3FF")
dotView.cornerRadius = 2
view.addSubview(dotView)
dotView.layoutChain
.left(15)
.centerY(titleLab)
.width(4)
.height(11)
titleLab.layoutChain.leftToRightOfView(dotView, offset: 5)
let historyBtn = UIButton()
historyBtn.setTitle("历史行程", for: .normal)
historyBtn.setTitleColor(ThemeManager.shared.color.titleAuxColor, for: .normal)
historyBtn.titleLabel?.font = .systemFont(ofSize: 12, weight: .medium)
historyBtn.rx.tap.subscribe(onNext: { _ in
AppRouter.push(Route.scheduleHistory)
}).disposed(by: disposeBag)
view.addSubview(historyBtn)
historyBtn.layoutChain
.right(15)
.centerY(titleLab)
historyBtn.sizeToFit()
view.addSubview(collectionView)
collectionView.layoutChain
.topToBottomOfView(titleLab, offset: 15)
.edgesHorzontal()
.height(80)
.bottom(15)
// 访
view.addSubview(emptyVisitorsLabel)
emptyVisitorsLabel.layoutChain
.centerY(collectionView)
.centerX()
return view
}()
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.itemSize = CGSize(width: 80, height: 80)
layout.minimumLineSpacing = 15
layout.sectionInset = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 15)
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .clear
cv.showsHorizontalScrollIndicator = false
cv.register(ViewedCell.self)
return cv
}()
lazy var emptyVisitorsLabel: UILabel = {
let label = UILabel()
label.text = "暂无访客"
label.font = .systemFont(ofSize: 14)
label.textColor = UIColor(hexStr: "#999999")
label.textAlignment = .center
label.isHidden = true
return label
}()
/// 线
lazy var travelRouteView: UIView = {
let view = UIView()
view.backgroundColor = .clear
let titleLab = UILabel()
titleLab.text = "行程路线"
titleLab.font = .systemFont(ofSize: 16, weight: .medium)
titleLab.textColor = ThemeManager.shared.color.titleAuxColor
view.addSubview(titleLab)
titleLab.layoutChain
.top(15)
.edgesVertical(5)
let dotView = UIView()
dotView.backgroundColor = UIColor(hexStr: "#16B3FF")
dotView.cornerRadius = 2
view.addSubview(dotView)
dotView.layoutChain
.left(15)
.centerY(titleLab)
.width(4)
.height(11)
titleLab.layoutChain.leftToRightOfView(dotView, offset: 5)
// checkbox
view.addSubview(allCheckBtn)
view.addSubview(followedCheckBtn)
view.addSubview(mineCheckBtn)
allCheckBtn.layoutChain
.right(15)
.centerY(titleLab)
followedCheckBtn.layoutChain
.rightToLeftOfView(allCheckBtn, offset: -20)
.centerY(titleLab)
mineCheckBtn.layoutChain
.rightToLeftOfView(followedCheckBtn, offset: -20)
.centerY(titleLab)
return view
}()
lazy var allCheckBtn: UIButton = makeCheckButton(title: "全部")
lazy var followedCheckBtn: UIButton = makeCheckButton(title: "我关注的")
lazy var mineCheckBtn: UIButton = makeCheckButton(title: "我的")
private func makeCheckButton(title: String) -> UIButton {
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "Schedule/checkbox"), for: .normal)
btn.setImage(UIImage(named: "Schedule/checkbox_selected"), for: .selected)
btn.setTitle(" \(title)", for: .normal)
btn.setTitleColor(UIColor(hexStr: "#333333"), for: .normal)
btn.titleLabel?.font = .systemFont(ofSize: 13, weight: .medium)
btn.sizeToFit()
return btn
}
lazy var tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .plain)
tableView.backgroundColor = .clear
tableView.separatorStyle = .none
tableView.estimatedRowHeight = 80
tableView.rowHeight = UITableView.automaticDimension
tableView.showsVerticalScrollIndicator = false
tableView.register(ScheduleListPopCell.self)
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 97 + kSafeBottomMargin, right: 0)
tableView.backgroundView = emptyScheduleLabel
return tableView
}()
lazy var emptyScheduleLabel: UILabel = {
let label = UILabel()
label.text = "暂无行程"
label.font = .systemFont(ofSize: 14)
label.textColor = UIColor(hexStr: "#999999")
label.textAlignment = .center
label.isHidden = true
return label
}()
lazy var createBtn: UIButton = {
let btn = UIButton()
btn.setImage(UIImage(named: "Schedule/create"), for: .normal)
return btn
}()
override init(frame: CGRect) {
super.init(frame: .zero)
backgroundColor = .white
setupUI()
setupRx()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// MARK: - ViewedCell
final class ViewedCell: UICollectionViewCell {
func configure(_ model: ViewedModel) {
iconView.setHeadPic(model.displayHeadPic)
//
blurView.isHidden = AppContextManager.shared.vip > 1
lockView.isHidden = AppContextManager.shared.vip > 1
viewedCountLab.text = "看了\(model.count)"
}
lazy var iconView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFill
iv.cornerRadius = 40
iv.clipsToBounds = true
iv.backgroundColor = .clear
iv.addSubview(blurView)
blurView.layoutChain.edges()
return iv
}()
lazy var blurView: UIVisualEffectView = {
let blurEffect = UIBlurEffect(style: .systemUltraThinMaterial)
let view = UIVisualEffectView(effect: blurEffect)
return view
}()
lazy var lockView: UIView = {
let view = UIView()
view.backgroundColor = .clear
let lockIcon = UIImageView(image: UIImage(named: "Common/lock_white"))
lockIcon.contentMode = .scaleAspectFill
view.addSubview(lockIcon)
lockIcon.layoutChain
.top(17)
.centerX()
view.addSubview(viewedCountLab)
viewedCountLab.layoutChain
.bottom(17)
.edgesHorzontal()
return view
}()
lazy var viewedCountLab: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 12, weight: .medium)
label.textColor = .white
label.textAlignment = .center
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(iconView)
contentView.addSubview(lockView)
iconView.layoutChain
.edges()
lockView.layoutChain
.edges()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// MARK: - ScheduleListPopCell
class ScheduleListPopCell: UITableViewCell {
var disposeBag = DisposeBag()
func configure(_ model: ScheduleModel) {
nameLab.text = model.nick_name + " 的行程路线"
monthLab.text = getDateInterval2String(date: "\(model.timestamp/1000)", dateFormat: "MM月")
editBtn.isHidden = !model.is_own
followBtn.isHidden = model.is_own
followBtn.isSelected = model.is_follow ? true : false
let groupNames = model.groups.map { $0.group_name }
// addTags frame.width
if !groupNames.isEmpty {
let w = contentView.frame.width > 0 ? contentView.frame.width : UIScreen.main.bounds.width
tagListView.frame.size.width = w - 170
}
tagListView.removeAllTags()
tagListView.addTags(groupNames)
tagListView.tagViews.forEach {
$0.layer.cornerRadius = 2
}
tagListView.invalidateIntrinsicContentSize()
guard let pointModel = model.points.last else { return }
dateLab.text = getDateInterval2String(date: "\(pointModel.expected_timestamp/1000)", dateFormat: "MM.dd")
}
override init(style: CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
selectionStyle = .none
backgroundColor = .clear
setupSubviews()
}
private func setupSubviews() {
contentView.addSubview(bgView)
bgView.addSubview(cornerView)
cornerView.addSubview(nameLab)
cornerView.addSubview(monthLab)
cornerView.addSubview(dateLab)
cornerView.addSubview(tagListView)
cornerView.addSubview(editBtn)
cornerView.addSubview(followBtn)
bgView.layoutChain
.top(15).bottom(15)
.edgesHorzontal(15)
cornerView.layoutChain.edges()
monthLab.layoutChain
.top(15)
.left(11)
.width(35)
dateLab.layoutChain
.topToBottomOfView(monthLab, offset: 4)
.leftToView(monthLab)
.width(35)
editBtn.layoutChain
.top(15)
.right(10)
.width(70)
.height(28)
nameLab.layoutChain
.top(15)
.leftToRightOfView(monthLab, offset: 15)
tagListView.layoutChain
.leftToRightOfView(dateLab, offset: 15)
.bottom(15)
.rightToLeftOfView(editBtn, offset: -10)
nameLab.layoutChain.bottomToTopOfView(tagListView, offset:-5)
followBtn.layoutChain
.topToView(editBtn)
.rightToView(editBtn)
.width(70)
.height(28)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func prepareForReuse() {
super.prepareForReuse()
disposeBag = DisposeBag()
}
lazy var bgView: UIView = {
let view = UIView()
view.backgroundColor = .clear
view.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.05).cgColor
view.layer.shadowOffset = CGSize(width: 0, height: 0)
view.layer.shadowOpacity = 1
view.layer.shadowRadius = 8
return view
}()
lazy var cornerView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.cornerRadius = 10
return view
}()
lazy var monthLab: UILabel = {
let label = UILabel()
label.textColor = ThemeManager.shared.color.titleAuxColor
label.font = .systemFont(ofSize: 14, weight: .medium)
return label
}()
lazy var dateLab: UILabel = {
let label = UILabel()
label.textColor = ThemeManager.shared.color.subTitleColor
label.font = .systemFont(ofSize: 12, weight: .regular)
return label
}()
lazy var nameLab: UILabel = {
let label = UILabel()
label.textColor = ThemeManager.shared.color.titleAuxColor
label.font = .systemFont(ofSize: 14, weight: .medium)
return label
}()
lazy var editBtn: UIButton = {
let btn = UIButton()
btn.isHidden = true
btn.setTitle("编辑", for: .normal)
btn.titleLabel?.font = .systemFont(ofSize: 12, weight: .medium)
btn.setTitleColor(UIColor(hexStr: "#0F2846"), for: .normal)
btn.backgroundColor = UIColor(hexStr: "#EEFAFF")
btn.borderWidth = 0.5
btn.borderColor = UIColor(hexStr: "#16B3FF")
btn.cornerRadius = 14
return btn
}()
lazy var followBtn: UIButton = {
let btn = UIButton()
btn.isHidden = true
btn.setTitle("关注", for: .normal)
btn.setTitle("取消关注", for: .selected)
btn.titleLabel?.font = .systemFont(ofSize: 12, weight: .medium)
btn.setTitleColor(UIColor(hexStr: "#16B3FF"), for: .normal)
btn.backgroundColor = .white
btn.borderWidth = 0.5
btn.borderColor = UIColor(hexStr: "#16B3FF")
btn.cornerRadius = 14
return btn
}()
lazy var tagListView: TagListView = {
let view = TagListView()
view.textFont = UIFont.systemFont(ofSize: 8, weight: .regular)
view.textColor = UIColor(hexStr: "#B78C56")
view.tagBackgroundColor = UIColor(hexStr: "#FFF3E4")
view.paddingX = 6 //
view.paddingY = 6 //
view.alignment = .left //
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
}

View File

@ -1,44 +0,0 @@
//
// OrderService.swift
// QuickLocation
//
// Created by on 2026/6/17.
//
import RxSwift
import Moya
struct OrderService {
static let disposeBag = DisposeBag()
// ///
// /// - Parameters:
// /// - type: member
// static func rechargeInfo(type: String) -> Observable<VipExpenseResponse> {
// let api = OrderAPI.rechargeInfo(type: type).multiTarget
// return APIProvider.request(token: api)
// .map(VipExpenseResponse.self)
// .asObservable()
// }
///
/// - Parameters:
/// - goodsId: ID
/// - payType: alipayweixin
/// - source: center
/// - extra:
static func orderPayParams(goodsId: String, payType: String, source: String="center", extra: [String:Any]=[:]) -> Observable<ResponseModel> {
let api = OrderAPI.orderPayParams(goodsId: goodsId, payType: payType, source: source, extra: extra).multiTarget
return APIProvider.request(token: api)
.map(ResponseModel.self)
.asObservable()
}
/// Apple
static func appleNotify(receipt: String, productId: String, transactionId: String) -> Observable<Void> {
let api = OrderAPI.appleNotify(receipt: receipt, productId: productId, transactionId: transactionId).multiTarget
return APIProvider.request(token: api)
.map { _ in () }
.asObservable()
}
}

View File

@ -1,281 +0,0 @@
//
// PayResultPopVC.swift
// QuickLocation
//
// Created by on 2026/6/17.
//
import UIKit
import RxSwift
import RxCocoa
import URLNavigator
class PayResultPopVC: DLCustomPopVC {
var disposeBag = DisposeBag()
// MARK: - Accessor
public var confirmBlock: (() -> Void)?
public var cancelBlock: (() -> Void)?
public var status: Bool? {
didSet {
guard let status = status else { return }
logoImgView.image = UIImage(named: status ? "Popup/success" : "Popup/failure")
}
}
public var titleText: String? {
didSet {
titleLab.text = titleText
}
}
public var contentText: String? {
didSet {
contentLab.text = contentText
}
}
public var cancelText: String? {
didSet {
closeBtn.setTitle(cancelText, for: .normal)
}
}
public var confirmText: String? {
didSet {
confirmBtn.setTitle(confirmText, for: .normal)
}
}
private func setupSubviews() {
contentBgView.addSubview(logoImgView)
contentView.addSubview(headerBgImg)
if titleText != nil,
titleText?.isEmpty == false {
contentView.addSubview(titleLab)
}
if contentText != nil,
contentText?.isEmpty == false {
contentView.addSubview(contentLab)
}
if cancelText?.isEmpty == false || confirmText?.isEmpty == false {
contentView.addSubview(stackView)
}
closeBtn.isHidden = !(cancelText?.isEmpty == false)
confirmBtn.isHidden = !(confirmText?.isEmpty == false)
}
private func setupLayout() {
logoImgView.layoutChain
.centerX()
.top(-44)
.width(88)
.height(88)
headerBgImg.layoutChain
.edges(excludingEdge: .bottom)
.heightToWidth(100/315)
var tempView: UIView?
if titleText != nil,
titleText?.isEmpty == false {
titleLab.layoutChain
.top(69)
.edgesHorzontal(20)
tempView = titleLab
}
if contentText != nil,
contentText?.isEmpty == false {
if let tempView = tempView {
contentLab.layoutChain
.edgesHorzontal(20)
.topToBottomOfView(tempView, offset: 20)
} else {
contentLab.layoutChain
.top(53)
.edgesHorzontal(20)
}
tempView = contentLab
}
guard let tempView = tempView else { return }
if cancelText?.isEmpty == false || confirmText?.isEmpty == false {
stackView.layoutChain
.topToBottomOfView(tempView, offset: 30)
.left(20)
.right(20)
.bottom(15)
confirmBtn.layoutChain
.height(50)
closeBtn.layoutChain
.height(50)
}
}
// MARK: - UI
private lazy var bgView: UIView = {
let view = UIView()
view.backgroundColor = .black.withAlphaComponent(0.5)
return view
}()
lazy var popView: UIView = {
let view = UIView()
view.backgroundColor = .clear
return view
}()
lazy var popBgView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.cornerRadius = 30
return view
}()
lazy var logoImgView: UIImageView = {
let view = UIImageView()
view.backgroundColor = .clear
return view
}()
lazy var headerBgImg: UIImageView = {
let view = UIImageView(image: UIImage(named: "Popup/header_bg"))
view.contentMode = .scaleAspectFill
return view
}()
lazy var titleLab: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 20, weight: .bold)
label.textColor = UIColor(hexStr: "#1A1A1A")
label.textAlignment = .center
label.numberOfLines = 0
return label
}()
lazy var contentLab: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 14, weight: .medium)
label.textColor = UIColor(hexStr: "#767676")
label.textAlignment = .center
label.numberOfLines = 0
return label
}()
lazy var stackView: UIStackView = {
let view = UIStackView(arrangedSubviews: [confirmBtn, closeBtn])
view.spacing = 10
view.axis = .vertical
view.alignment = .fill
view.distribution = .fill
return view
}()
lazy var confirmBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setTitle("", for: .normal)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
btn.setBackgroundImage(UIImage(named: "Common/button_bg_2"), for: .normal)
btn.cornerRadius = 25
btn.addTouchBlock { [weak self] _ in
self?.dismiss(animated: true, completion: {
self?.confirmBlock?()
})
}
return btn
}()
lazy var closeBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setTitle("", for: .normal)
btn.setTitleColor(UIColor(hexStr: "#16B3FF"), for: .normal)
btn.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
btn.backgroundColor = .clear
btn.addTouchBlock { [weak self] _ in
self?.dismiss(animated: true, completion: {
self?.cancelBlock?()
})
}
return btn
}()
// MARK: - Lifecycle
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
popStyle = .center
centerCornerRadius = 30
}
public required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public override func viewDidLoad() {
super.viewDidLoad()
setupSubviews()
setupLayout()
}
}
public extension UIViewController {
///
/// - Parameters:
/// - status: true false
/// - title:
/// - message:
/// - confirmText:
/// - confirmBlock:
/// - cancelText:
/// - cancelBlock:
func showPayResultPop(showCloseBtn: Bool = true,
status: Bool,
title: String?=nil,
message: String?=nil,
confirmText: String?=nil,
confirmBlock: (() -> Void)?=nil,
cancelText: String?=nil,
cancelBlock: (() -> Void)?=nil) {
if title == nil && message == nil { return }
let vc = PayResultPopVC()
vc.titleText = title
vc.status = status
vc.contentText = message
vc.confirmText = confirmText
vc.confirmBlock = confirmBlock
vc.cancelText = cancelText
vc.cancelBlock = cancelBlock
vc.closeBtn.isHidden = !showCloseBtn
vc.dimmingClick = showCloseBtn
present(vc, animated: true)
}
static func showPayResultPop(showCloseBtn: Bool = true,
status: Bool,
title: String?=nil,
message: String?=nil,
confirmText: String?=nil,
confirmBlock: (() -> Void)?=nil,
cancelText: String?=nil,
cancelBlock: (() -> Void)?=nil) {
if title == nil && message == nil { return }
let vc = PayResultPopVC()
vc.titleText = title
vc.status = status
vc.contentText = message
vc.confirmText = confirmText
vc.confirmBlock = confirmBlock
vc.cancelText = cancelText
vc.cancelBlock = cancelBlock
vc.closeBtn.isHidden = !showCloseBtn
vc.dimmingClick = showCloseBtn
UIViewController.topMost?.present(vc, animated: true)
}
}