mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 16:05:19 +00:00
* refactor: remove dead code and consolidate system messages - Delete 3 unused functions in ShareViewController (36 lines) - Extract addSystemMessage() helper to eliminate duplication (120+ lines) - Remove 22 'let _ =' wasteful computations across multiple files - Net reduction of 215 lines of dead/duplicate code - Improves maintainability and reduces technical debt * fix: remove remaining unused variables to eliminate compiler warnings - Remove unused senderNoiseKey in ChatViewModel - Remove unused lastSuccess variable in BluetoothMeshService - Eliminates all compiler warnings related to unused values * refactor: remove all dead legacy and migration code - Remove unused migrateSession() functions (never called in production) - NoiseSession.migrateSession() - 13 lines - NoiseEncryptionService.migratePeerSession() - 18 lines - Test for migration functionality - 17 lines - Remove unnecessary keychain cleanup code (no legacy data existed) - cleanupLegacyKeychainItems() - 62 lines - aggressiveCleanupLegacyItems() - 72 lines - resetCleanupFlag() - 4 lines - Simplified panic mode to just use deleteAllKeychainData() Total removed: 194 lines of dead/unnecessary code Analysis revealed: - KeychainManager introduced July 5, 2025 - Cleanup code added July 15, 2025 (10 days later) - Legacy service names were never used in production - Migration functions were incomplete implementation never called - Peer ID rotation remains active (not legacy) * Remove dead code and simplify codebase - Remove unused BinaryEncodable protocol and BinaryMessageType enum - Delete MockNoiseSession.swift (never used in tests) - Remove all relay detection code (hardcoded to false) - Removed isRelayConnected property from BitchatPeer - Removed relayConnected case from ConnectionState enum - Cleaned up relay-related UI indicators in ContentView - Removed relay status checks from ChatViewModel - Simplified peer connection logic by removing relay layer Total: 169 lines removed across 5 files --------- Co-authored-by: jack <jackjackbits@users.noreply.github.com>
166 lines
6.4 KiB
Swift
166 lines
6.4 KiB
Swift
//
|
|
// ShareViewController.swift
|
|
// bitchatShareExtension
|
|
//
|
|
// This is free and unencumbered software released into the public domain.
|
|
// For more information, see <https://unlicense.org>
|
|
//
|
|
|
|
import UIKit
|
|
import Social
|
|
import UniformTypeIdentifiers
|
|
|
|
class ShareViewController: SLComposeServiceViewController {
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
// Set placeholder text
|
|
placeholder = "Share to bitchat..."
|
|
// Set character limit (optional)
|
|
charactersRemaining = 500
|
|
}
|
|
|
|
override func isContentValid() -> Bool {
|
|
// Validate that we have text content or attachments
|
|
if let text = contentText, !text.isEmpty {
|
|
return true
|
|
}
|
|
// Check if we have attachments
|
|
if let item = extensionContext?.inputItems.first as? NSExtensionItem,
|
|
let attachments = item.attachments,
|
|
!attachments.isEmpty {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
override func didSelectPost() {
|
|
guard let extensionItem = extensionContext?.inputItems.first as? NSExtensionItem else {
|
|
self.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
|
|
return
|
|
}
|
|
|
|
|
|
// Get the page title from the compose view or extension item
|
|
let pageTitle = self.contentText ?? extensionItem.attributedContentText?.string ?? extensionItem.attributedTitle?.string
|
|
|
|
var foundURL: URL? = nil
|
|
let group = DispatchGroup()
|
|
|
|
// IMPORTANT: Check if the NSExtensionItem itself has a URL
|
|
// Safari often provides the URL as an attributedString with a link
|
|
if let attributedText = extensionItem.attributedContentText {
|
|
let text = attributedText.string
|
|
let detector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
|
|
let matches = detector?.matches(in: text, options: [], range: NSRange(location: 0, length: text.utf16.count))
|
|
if let firstMatch = matches?.first, let url = firstMatch.url {
|
|
foundURL = url
|
|
}
|
|
}
|
|
|
|
// Only check attachments if we haven't found a URL yet
|
|
if foundURL == nil {
|
|
for (_, itemProvider) in (extensionItem.attachments ?? []).enumerated() {
|
|
|
|
// Try multiple URL type identifiers that Safari might use
|
|
let urlTypes = [
|
|
UTType.url.identifier,
|
|
"public.url",
|
|
"public.file-url"
|
|
]
|
|
|
|
for urlType in urlTypes {
|
|
if itemProvider.hasItemConformingToTypeIdentifier(urlType) {
|
|
group.enter()
|
|
itemProvider.loadItem(forTypeIdentifier: urlType, options: nil) { (item, error) in
|
|
defer { group.leave() }
|
|
|
|
if let url = item as? URL {
|
|
foundURL = url
|
|
} else if let data = item as? Data,
|
|
let urlString = String(data: data, encoding: .utf8),
|
|
let url = URL(string: urlString) {
|
|
foundURL = url
|
|
} else if let string = item as? String,
|
|
let url = URL(string: string) {
|
|
foundURL = url
|
|
}
|
|
}
|
|
break // Found a URL type, no need to check other types
|
|
}
|
|
}
|
|
|
|
// Also check for plain text that might be a URL
|
|
if foundURL == nil && itemProvider.hasItemConformingToTypeIdentifier(UTType.plainText.identifier) {
|
|
group.enter()
|
|
itemProvider.loadItem(forTypeIdentifier: UTType.plainText.identifier, options: nil) { (item, error) in
|
|
defer { group.leave() }
|
|
|
|
if let text = item as? String {
|
|
// Check if the text is actually a URL
|
|
if let url = URL(string: text),
|
|
(url.scheme == "http" || url.scheme == "https") {
|
|
foundURL = url
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} // End of if foundURL == nil
|
|
|
|
// Process after all checks complete
|
|
group.notify(queue: .main) { [weak self] in
|
|
if let url = foundURL {
|
|
// We have a URL! Create the JSON data
|
|
let urlData: [String: String] = [
|
|
"url": url.absoluteString,
|
|
"title": pageTitle ?? url.host ?? "Shared Link"
|
|
]
|
|
|
|
|
|
if let jsonData = try? JSONSerialization.data(withJSONObject: urlData),
|
|
let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
self?.saveToSharedDefaults(content: jsonString, type: "url")
|
|
}
|
|
} else if let title = pageTitle, !title.isEmpty {
|
|
// No URL found, just share the text
|
|
self?.saveToSharedDefaults(content: title, type: "text")
|
|
}
|
|
|
|
self?.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
|
|
}
|
|
}
|
|
|
|
override func configurationItems() -> [Any]! {
|
|
// No configuration items needed
|
|
return []
|
|
}
|
|
|
|
// MARK: - Helper Methods
|
|
|
|
private func saveToSharedDefaults(content: String, type: String) {
|
|
// Use app groups to share data between extension and main app
|
|
guard let userDefaults = UserDefaults(suiteName: "group.chat.bitchat") else {
|
|
return
|
|
}
|
|
|
|
userDefaults.set(content, forKey: "sharedContent")
|
|
userDefaults.set(type, forKey: "sharedContentType")
|
|
userDefaults.set(Date(), forKey: "sharedContentDate")
|
|
userDefaults.synchronize()
|
|
|
|
|
|
// Force open the main app
|
|
self.openMainApp()
|
|
}
|
|
|
|
private func openMainApp() {
|
|
// Share extensions cannot directly open the containing app
|
|
// The app will check for shared content when it becomes active
|
|
// Show success feedback to user
|
|
DispatchQueue.main.async {
|
|
self.textView.text = "✓ Shared to bitchat"
|
|
self.textView.isEditable = false
|
|
}
|
|
}
|
|
} |