|
841 | 841 | stackTraceTextView.translatesAutoresizingMaskIntoConstraints = NO; |
842 | 842 | [stackTraceContainer addSubview:stackTraceTextView]; |
843 | 843 |
|
| 844 | + // TODO: Investigate why the copy action doesn't copy to clipboard |
844 | 845 | // Copy button for stack trace |
845 | | - UIButton* copyButton = [UIButton buttonWithType:UIButtonTypeSystem]; |
846 | | - [copyButton setTitle:@"📋 Copy Stack Trace" forState:UIControlStateNormal]; |
847 | | - [copyButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; |
848 | | - copyButton.backgroundColor = [UIColor colorWithRed:0.3 green:0.3 blue:0.3 alpha:1.0]; |
849 | | - copyButton.titleLabel.font = [UIFont systemFontOfSize:16]; |
850 | | - copyButton.layer.cornerRadius = 8; |
851 | | - copyButton.translatesAutoresizingMaskIntoConstraints = NO; |
852 | | - [contentView addSubview:copyButton]; |
| 846 | + // UIButton* copyButton = [UIButton buttonWithType:UIButtonTypeSystem]; |
| 847 | + // [copyButton setTitle:@"📋 Copy Stack Trace" forState:UIControlStateNormal]; |
| 848 | + // [copyButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; |
| 849 | + // copyButton.backgroundColor = [UIColor colorWithRed:0.3 green:0.3 blue:0.3 alpha:1.0]; |
| 850 | + // copyButton.titleLabel.font = [UIFont systemFontOfSize:16]; |
| 851 | + // copyButton.layer.cornerRadius = 8; |
| 852 | + // copyButton.translatesAutoresizingMaskIntoConstraints = NO; |
| 853 | + // [contentView addSubview:copyButton]; |
853 | 854 |
|
854 | 855 | // Configure copy button action |
855 | | - void (^copyAction)(void) = ^{ |
856 | | - UIPasteboard* pasteboard = [UIPasteboard generalPasteboard]; |
857 | | - NSString* stackTraceText = [NSString stringWithUTF8String:stackTrace.c_str()]; |
858 | | - BOOL wrote = NO; |
859 | | - |
860 | | - // Prefer modern UTType on iOS 14+, but avoid hard link to UTTypePlainText (use reflection) |
861 | | - if (@available(iOS 14.0, *)) { |
862 | | - Class UTTypeClass = NSClassFromString(@"UTType"); |
863 | | - if (UTTypeClass) { |
864 | | - SEL plainSel = NSSelectorFromString(@"plainText"); |
865 | | - if ([UTTypeClass respondsToSelector:plainSel]) { |
866 | | - id plain = ((id(*)(id, SEL))objc_msgSend)(UTTypeClass, plainSel); |
867 | | - if (plain) { |
868 | | - SEL idSel = NSSelectorFromString(@"identifier"); |
869 | | - if ([plain respondsToSelector:idSel]) { |
870 | | - NSString* utiIdentifier = ((id(*)(id, SEL))objc_msgSend)(plain, idSel); |
871 | | - if (utiIdentifier.length > 0) { |
872 | | - [pasteboard setValue:stackTraceText forPasteboardType:utiIdentifier]; |
873 | | - wrote = YES; |
874 | | - } |
875 | | - } |
876 | | - } |
877 | | - } |
878 | | - } |
879 | | - } |
880 | | - |
881 | | - // Fallback to kUTTypePlainText (MobileCoreServices) |
882 | | - if (!wrote) { |
883 | | - [pasteboard setValue:stackTraceText forPasteboardType:(NSString*)kUTTypePlainText]; |
884 | | - wrote = YES; |
885 | | - } |
886 | | - |
887 | | - // Quick verification; if pasteboard appears empty, try string fallback |
888 | | - if (wrote) { |
889 | | - BOOL hasString = NO; |
890 | | - if ([pasteboard respondsToSelector:@selector(hasStrings)]) { |
891 | | - hasString = pasteboard.hasStrings; |
892 | | - } else { |
893 | | - hasString = (pasteboard.string.length > 0); |
894 | | - } |
895 | | - if (!hasString) { |
896 | | - wrote = NO; |
897 | | - } |
898 | | - } |
899 | | - |
900 | | - // Last resort: set .string |
901 | | - if (!wrote || pasteboard.string.length == 0) { |
902 | | - pasteboard.string = stackTraceText; |
903 | | - } |
904 | | - |
905 | | - // Show temporary feedback |
906 | | - [copyButton setTitle:@"✅ Copied!" forState:UIControlStateNormal]; |
907 | | - copyButton.backgroundColor = [UIColor colorWithRed:0.2 green:0.7 blue:0.2 alpha:1.0]; |
| 856 | + // void (^copyAction)(void) = ^{ |
| 857 | + // UIPasteboard* pasteboard = [UIPasteboard generalPasteboard]; |
| 858 | + // NSString* stackTraceText = [NSString stringWithUTF8String:stackTrace.c_str()]; |
| 859 | + // BOOL wrote = NO; |
| 860 | + |
| 861 | + // // Prefer modern UTType on iOS 14+, but avoid hard link to UTTypePlainText (use reflection) |
| 862 | + // if (@available(iOS 14.0, *)) { |
| 863 | + // Class UTTypeClass = NSClassFromString(@"UTType"); |
| 864 | + // if (UTTypeClass) { |
| 865 | + // SEL plainSel = NSSelectorFromString(@"plainText"); |
| 866 | + // if ([UTTypeClass respondsToSelector:plainSel]) { |
| 867 | + // id plain = ((id(*)(id, SEL))objc_msgSend)(UTTypeClass, plainSel); |
| 868 | + // if (plain) { |
| 869 | + // SEL idSel = NSSelectorFromString(@"identifier"); |
| 870 | + // if ([plain respondsToSelector:idSel]) { |
| 871 | + // NSString* utiIdentifier = ((id(*)(id, SEL))objc_msgSend)(plain, idSel); |
| 872 | + // if (utiIdentifier.length > 0) { |
| 873 | + // [pasteboard setValue:stackTraceText forPasteboardType:utiIdentifier]; |
| 874 | + // wrote = YES; |
| 875 | + // } |
| 876 | + // } |
| 877 | + // } |
| 878 | + // } |
| 879 | + // } |
| 880 | + // } |
| 881 | + |
| 882 | + // // Fallback to kUTTypePlainText (MobileCoreServices) |
| 883 | + // if (!wrote) { |
| 884 | + // [pasteboard setValue:stackTraceText forPasteboardType:(NSString*)kUTTypePlainText]; |
| 885 | + // wrote = YES; |
| 886 | + // } |
| 887 | + |
| 888 | + // // Quick verification; if pasteboard appears empty, try string fallback |
| 889 | + // if (wrote) { |
| 890 | + // BOOL hasString = NO; |
| 891 | + // if ([pasteboard respondsToSelector:@selector(hasStrings)]) { |
| 892 | + // hasString = pasteboard.hasStrings; |
| 893 | + // } else { |
| 894 | + // hasString = (pasteboard.string.length > 0); |
| 895 | + // } |
| 896 | + // if (!hasString) { |
| 897 | + // wrote = NO; |
| 898 | + // } |
| 899 | + // } |
| 900 | + |
| 901 | + // // Last resort: set .string |
| 902 | + // if (!wrote || pasteboard.string.length == 0) { |
| 903 | + // pasteboard.string = stackTraceText; |
| 904 | + // } |
| 905 | + |
| 906 | + // // Show temporary feedback |
| 907 | + // [copyButton setTitle:@"✅ Copied!" forState:UIControlStateNormal]; |
| 908 | + // copyButton.backgroundColor = [UIColor colorWithRed:0.2 green:0.7 blue:0.2 alpha:1.0]; |
| 909 | + |
| 910 | + // dispatch_after( |
| 911 | + // dispatch_time(DISPATCH_TIME_NOW, 1.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ |
| 912 | + // [copyButton setTitle:@"📋 Copy Stack Trace" forState:UIControlStateNormal]; |
| 913 | + // copyButton.backgroundColor = [UIColor colorWithRed:0.3 green:0.3 blue:0.3 alpha:1.0]; |
| 914 | + // }); |
| 915 | + // }; |
908 | 916 |
|
909 | | - dispatch_after( |
910 | | - dispatch_time(DISPATCH_TIME_NOW, 1.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ |
911 | | - [copyButton setTitle:@"📋 Copy Stack Trace" forState:UIControlStateNormal]; |
912 | | - copyButton.backgroundColor = [UIColor colorWithRed:0.3 green:0.3 blue:0.3 alpha:1.0]; |
913 | | - }); |
914 | | - }; |
915 | | - |
916 | | - if (@available(iOS 14.0, *)) { |
917 | | - UIAction* action = [UIAction actionWithTitle:@"" |
918 | | - image:nil |
919 | | - identifier:nil |
920 | | - handler:^(UIAction* action) { |
921 | | - copyAction(); |
922 | | - }]; |
923 | | - [copyButton addAction:action forControlEvents:UIControlEventTouchUpInside]; |
924 | | - } else { |
925 | | - // For older iOS versions, use target-action pattern |
926 | | - NSObject* target = [[NSObject alloc] init]; |
927 | | - objc_setAssociatedObject(target, "copyBlock", copyAction, OBJC_ASSOCIATION_COPY_NONATOMIC); |
928 | | - |
929 | | - IMP copyImp = imp_implementationWithBlock(^(id self) { |
930 | | - void (^block)(void) = objc_getAssociatedObject(self, "copyBlock"); |
931 | | - if (block) { |
932 | | - block(); |
933 | | - } |
934 | | - }); |
| 917 | + // if (@available(iOS 14.0, *)) { |
| 918 | + // UIAction* action = [UIAction actionWithTitle:@"" |
| 919 | + // image:nil |
| 920 | + // identifier:nil |
| 921 | + // handler:^(UIAction* action) { |
| 922 | + // copyAction(); |
| 923 | + // }]; |
| 924 | + // [copyButton addAction:action forControlEvents:UIControlEventTouchUpInside]; |
| 925 | + // } else { |
| 926 | + // // For older iOS versions, use target-action pattern |
| 927 | + // NSObject* target = [[NSObject alloc] init]; |
| 928 | + // objc_setAssociatedObject(target, "copyBlock", copyAction, OBJC_ASSOCIATION_COPY_NONATOMIC); |
| 929 | + |
| 930 | + // IMP copyImp = imp_implementationWithBlock(^(id self) { |
| 931 | + // void (^block)(void) = objc_getAssociatedObject(self, "copyBlock"); |
| 932 | + // if (block) { |
| 933 | + // block(); |
| 934 | + // } |
| 935 | + // }); |
935 | 936 |
|
936 | | - class_addMethod([target class], NSSelectorFromString(@"copyStackTrace"), copyImp, "v@:"); |
937 | | - [copyButton addTarget:target |
938 | | - action:NSSelectorFromString(@"copyStackTrace") |
939 | | - forControlEvents:UIControlEventTouchUpInside]; |
940 | | - } |
| 937 | + // class_addMethod([target class], NSSelectorFromString(@"copyStackTrace"), copyImp, "v@:"); |
| 938 | + // [copyButton addTarget:target |
| 939 | + // action:NSSelectorFromString(@"copyStackTrace") |
| 940 | + // forControlEvents:UIControlEventTouchUpInside]; |
| 941 | + // } |
941 | 942 |
|
942 | 943 | // Hot-reload indicator |
943 | 944 | UILabel* hotReloadLabel = [[UILabel alloc] init]; |
|
1051 | 1052 | [stackTraceTextView.bottomAnchor constraintEqualToAnchor:stackTraceContainer.bottomAnchor], |
1052 | 1053 |
|
1053 | 1054 | // Copy button below stack trace |
1054 | | - [copyButton.topAnchor constraintEqualToAnchor:stackTraceContainer.bottomAnchor constant:10], |
1055 | | - [copyButton.centerXAnchor constraintEqualToAnchor:contentView.centerXAnchor], |
1056 | | - [copyButton.widthAnchor constraintEqualToConstant:200], |
1057 | | - [copyButton.heightAnchor constraintEqualToConstant:40], |
| 1055 | + // [copyButton.topAnchor constraintEqualToAnchor:stackTraceContainer.bottomAnchor constant:10], |
| 1056 | + // [copyButton.centerXAnchor constraintEqualToAnchor:contentView.centerXAnchor], |
| 1057 | + // [copyButton.widthAnchor constraintEqualToConstant:200], |
| 1058 | + // [copyButton.heightAnchor constraintEqualToConstant:40], |
1058 | 1059 |
|
1059 | 1060 | // Hot-reload indicator below copy button - this will push stack trace up to fill space |
1060 | | - [hotReloadLabel.topAnchor constraintEqualToAnchor:copyButton.bottomAnchor constant:15], |
| 1061 | + // [hotReloadLabel.topAnchor constraintEqualToAnchor:copyButton.bottomAnchor constant:15], |
| 1062 | + // [hotReloadLabel.leadingAnchor constraintEqualToAnchor:contentView.leadingAnchor constant:20], |
| 1063 | + // [hotReloadLabel.trailingAnchor constraintEqualToAnchor:contentView.trailingAnchor constant:-20], |
| 1064 | + // [hotReloadLabel.bottomAnchor constraintEqualToAnchor:contentView.bottomAnchor constant:-30], |
| 1065 | + [hotReloadLabel.topAnchor constraintEqualToAnchor:stackTraceContainer.bottomAnchor constant:15], |
1061 | 1066 | [hotReloadLabel.leadingAnchor constraintEqualToAnchor:contentView.leadingAnchor constant:20], |
1062 | 1067 | [hotReloadLabel.trailingAnchor constraintEqualToAnchor:contentView.trailingAnchor constant:-20], |
1063 | 1068 | [hotReloadLabel.bottomAnchor constraintEqualToAnchor:contentView.bottomAnchor constant:-30], |
|
0 commit comments