diff --git a/i18n/it/docusaurus-plugin-content-docs/current/advanced/anisette.mdx b/i18n/it/docusaurus-plugin-content-docs/current/advanced/anisette.mdx index 4c005139..8a8d7dd7 100644 --- a/i18n/it/docusaurus-plugin-content-docs/current/advanced/anisette.mdx +++ b/i18n/it/docusaurus-plugin-content-docs/current/advanced/anisette.mdx @@ -13,7 +13,7 @@ I dati Anisette sono info utilizzate dal processo di firma dell'app e necessitan Quando tante persone usano lo stesso server Anisette (specialmente un server v1), Apple attiva un processo di sicurezza e blocca gli account che usano quel "Mac". Ecco perché consigliamo di usare un Apple ID usa e getta al posto del principale. -Il nosto team ha lavorato a migliori approcci per evitare account bloccati (con gli _anisette-v3_). Comunque, se stai usando una vecchia versione di SideStore, hostare il tuo server anisette è una buona idea per evitare il blocco dell'account. Tutto ciò è reso estremamente semplice grazie al fatto che il nostro server è open source e pronto per Docker. Ciò significa che possiamo deployare un server semplicemente con un link GitHub. +Il nostro team ha lavorato a migliori approcci per evitare account bloccati (con gli _anisette-v3_). Comunque, se stai usando una vecchia versione di SideStore, hostare il tuo server anisette è una buona idea per evitare il blocco dell'account. Tutto ciò è reso estremamente semplice grazie al fatto che il nostro server è open source e pronto per Docker. Ciò significa che possiamo deployare un server semplicemente con un link GitHub. ## Deploy su Render @@ -65,7 +65,7 @@ Dalla release 0.5.8, SideStore usa una lista di server anisette cosicché i serv Se vuoi mantenere l'opzione di utilizzare i server inclusi, segui i seguenti step: 1. Vai [qui](https://servers.sidestore.io/servers.json) per ottenere la lista attuale dei server. 2. Vai su un hosting di fiducia per pubblicare il file online. Consigliamo l'utilizzo di GitHub Pages perché è facilita un'eventuale modifica in futuro, sarà quindi il servizio di esempio per questa guida. Se hai un altro modo, adatta gli step al tuo setup. -3. Se hai già un sito GitHub Pages, salta al sesto sotto-step. Altimenti, continua con gli step seguenti: +3. Se hai già un sito GitHub Pages, salta al sesto sotto-step. Altrimenti, continua con gli step seguenti: * Crea una nuova repo GitHub o con l'icona del più (+) in alto a destra su desktop, o icona del profilo > Crea nuovo su mobile, o tramite [questa pagina](https://github.com/new). * Dagli il nome [il tuo username GitHub].github.io, attiva il README e metti le altre impostazioni come preferisci * Una volta creata, vai nel tab Impostazioni e vai nella sezione Pages sotto a Code and automation. @@ -100,7 +100,7 @@ e procedi normalmente. Per usare il tuo server appena creato nell'app di SideStore, procedi in questa maniera: 1. Apri la tab Impostazioni di SideStore. -2. Sorri fino a 'Server Anisette' +2. Scorri fino a 'Server Anisette' 3. Tocca sull'url della lista e cambialo con l'URL della tua lista dei server 4. Premi 'Aggiorna Server' e seleziona il tuo server dalla lista aggiornata. diff --git a/i18n/it/docusaurus-plugin-content-docs/current/advanced/app-sources.mdx b/i18n/it/docusaurus-plugin-content-docs/current/advanced/app-sources.mdx index 62ce384e..0a1aa38a 100644 --- a/i18n/it/docusaurus-plugin-content-docs/current/advanced/app-sources.mdx +++ b/i18n/it/docusaurus-plugin-content-docs/current/advanced/app-sources.mdx @@ -21,4 +21,4 @@ Per più info, vedi [URL Schema](/docs/advanced/url-schema). Spesso è utile cre ## Finito! -Ecco alcune AltSource consigliate che puoi aggiungere a SideStore: La [SideStore Community Source](https://github.com/SideStore/Community-Source), the [official AltStore Source](https://apps.altstore.io), la [LiveContainer Source](https://raw.githubusercontent.com/LiveContainer/LiveContainer/refs/heads/main/apps.json) e la [DolphiniOS Source](https://altstore.oatmealdome.me). +Ecco alcune AltSource consigliate che puoi aggiungere a SideStore: La [SideStore Community Source](https://github.com/SideStore/Community-Source), la [Source ufficiale di AltStore](https://apps.altstore.io), la [LiveContainer Source](https://raw.githubusercontent.com/LiveContainer/LiveContainer/refs/heads/main/apps.json) e la [DolphiniOS Source](https://altstore.oatmealdome.me). diff --git a/i18n/it/docusaurus-plugin-content-docs/current/advanced/jit.mdx b/i18n/it/docusaurus-plugin-content-docs/current/advanced/jit.mdx index 534a9501..0888d84c 100644 --- a/i18n/it/docusaurus-plugin-content-docs/current/advanced/jit.mdx +++ b/i18n/it/docusaurus-plugin-content-docs/current/advanced/jit.mdx @@ -4,11 +4,17 @@ description: Tutorial su come abilitare la compilazione Just-In-Time (JIT) per a --- :::note -iOS 26 ha rotto di nuovo JIT. Un fix sarà rilasciato in StikDebug dopo il rilascio dell'iPhone 17. +iOS 26 ha rotto di nuovo JIT. È stato rilasciato un fix in StikDebug, ma il supporto è **molto** limitato. Ad oggi (16 sett), le uniche app supportate sono: +* UTM +* Amethyst +* MeloNX +* maciOS (non rilasciata completamente) Ci sono diversi metodi per abilitare JIT, come AltJIT, SideJITServer e altri. Questo tutorial copre l'uso di StikDebug (prima StikJIT), in quanto è il metodo raccomandato. Per più info, vedi la [guida ufficiale per il pairing StikDebug](https://github.com/StephenDev0/StikDebug-Guide/blob/main/pairing_file.md). -Come alternativa, SideStore 0.6.2 include aggiornamente a minimuxeer, permettendo la funzionalità JIT built-in, in modo simile a StikDebug. Per usarlo, assicurati di essere connesso a StosVPN con il Wi-Fi connesso o la Modalità Aereo attiva, poi naviga in "Le mie app", tieni premuto l'app in cui vuoi abilitare JIT e tocca "abilita JIT". +Come alternativa, SideStore 0.6.2 include aggiornamenti a minimuxer, permettendo la funzionalità JIT built-in, in modo simile a StikDebug. Per usarlo, assicurati di essere connesso a StosVPN con il Wi-Fi connesso o la Modalità Aereo attiva, poi naviga in "Le mie app", tieni premuto l'app in cui vuoi abilitare JIT e tocca "abilita JIT". + +Tieni d'occhio il nostro canale di annunci nel server Discord e sul [server di idevice](https://discord.gg/mACqxMxP3X) per ulteriori aggiornamenti. ::: ## Prerequisiti @@ -17,8 +23,9 @@ Come alternativa, SideStore 0.6.2 include aggiornamente a minimuxeer, permettend ## Installazione di StikDebug nell'App Store di Apple 1. **Installa StikDebug** - Install StikDebug dall'[App Store](https://apps.apple.com/us/app/stikdebug/id6744045754). -:::note Punto a favore- la VPN di StikDebug è simile a quella di SideStore, puoi dunque usarla per installare e refreshare le app in SideStore, in modo simile a StosVPN. + Installa StikDebug dall'[App Store](https://apps.apple.com/us/app/stikdebug/id6744045754). +:::note +Punto a favore- la VPN di StikDebug è simile a quella di SideStore, puoi dunque usarla per installare e refreshare le app in SideStore, in modo simile a StosVPN. ::: 2. **Procedura di installazione:** diff --git a/i18n/it/docusaurus-plugin-content-docs/current/advanced/sparserestore.mdx b/i18n/it/docusaurus-plugin-content-docs/current/advanced/sparserestore.mdx index 4e763f4b..8a6fcf52 100644 --- a/i18n/it/docusaurus-plugin-content-docs/current/advanced/sparserestore.mdx +++ b/i18n/it/docusaurus-plugin-content-docs/current/advanced/sparserestore.mdx @@ -33,7 +33,7 @@ L'exploit bypass del limite delle 3 app di SparseRestore **funziona solo sulle v 4. Riapri SideStore e scorri in basso nelle impostazioni. Premi "cancella cache", in questo modo SideStore vedrà l'exploit. -5. Verifica che l'exploit funzioni (potresti dover installare più di un'app, in base a quanti slot liberi hai). Se mostra un errore riguardante il limite, riapri SideStore o riesegui l'exploit. Se installa l'app, congratulazion! Puoi avere più di 3 app installate nello stesso momento. +5. Verifica che l'exploit funzioni (potresti dover installare più di un'app, in base a quanti slot liberi hai). Se mostra un errore riguardante il limite, riapri SideStore o riesegui l'exploit. Se installa l'app, congratulazioni! Puoi avere più di 3 app installate nello stesso momento. ## Note A causa di alcune limitazioni, l'exploit deve essere eseguito ogni volta che installi altre 3 app. diff --git a/i18n/it/docusaurus-plugin-content-docs/current/contributing/advanced-formatting.mdx b/i18n/it/docusaurus-plugin-content-docs/current/contributing/advanced-formatting.mdx new file mode 100644 index 00000000..5ce4c35e --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/contributing/advanced-formatting.mdx @@ -0,0 +1,794 @@ +--- +sidebar_position: 3 +--- + +# Linee guida avanzate per la formattazione + +Esamineremo situazioni di formattazione avanzata, modelli architetturali e funzionalità complesse di Swift/Objective-C per SideStore. + +## Pattern Swift Avanzati + +### Programmazione Protocol-Oriented + +#### Definizione dei Protocolli +- Mantieni i protocolli mirati e coerenti +- Utilizza tipi associati per i protocolli generici +- Fornisci implementazioni predefinite nelle estensioni quando opportuno + +```swift +// ✅ Giusto +protocol AppInstalling { + associatedtype AppType: App + + func install(_ app: AppType) async throws + func uninstall(_ app: AppType) async throws +} + +extension AppInstalling { + func validateApp(_ app: AppType) -> Bool { + return !app.identifier.isEmpty && app.version.isValid + } +} + +// ❌ Sbagliato +protocol AppManager { + func install(_ app: Any) -> Bool + func uninstall(_ app: Any) -> Bool + func update(_ app: Any) -> Bool + func backup(_ app: Any) -> Bool + func restore(_ app: Any) -> Bool + // Troppe responsabilità +} +``` + +#### Composizione del Protocollo +- Usa la composizione del protocollo per requisiti complessi +- Mantieni i protocolli individuali piccoli e mirati + +```swift +// ✅ Giusto +protocol Downloadable { + var downloadURL: URL { get } + func download() async throws -> Data +} + +protocol Installable { + var installationRequirements: InstallationRequirements { get } + func install() async throws +} + +typealias DeployableApp = App & Downloadable & Installable + +class AppDeployer { + func deploy(_ app: T) async throws { + let data = try await app.download() + try await app.install() + } +} +``` + +### Generici e vincoli di tipo + +#### Definizioni di Tipo Generico +- Usa nomi significativi per i vincoli +- Preferisci vincoli di protocollo anziché vincoli di classe +- Usa le clausole `where` per vincoli complessi + +```swift +// ✅ Giusto +struct Repository { + private var entities: [Entity.ID: Entity] = [:] + + func save(_ entity: T) where T == Entity { + entities[entity.id] = entity + } + + func find(byId id: ID) -> Entity? where ID == Entity.ID { + return entities[id] + } +} + +// ❌ Sbagliato +struct Repository { + private var items: [String: T] = [:] + // Nessuna sicurezza dei tipi +} +``` + +#### Vincoli Generici Avanzati +- Utilizzare la conformità condizionale in modo appropriato +- Sfrutta i tipi fantasma quando necessario + +```swift +// ✅ Giusto +extension Array: AppCollection where Element: App { + var installedApps: [Element] { + return filter { $0.isInstalled } + } + + func sortedByInstallDate() -> [Element] { + return sorted { $0.installDate < $1.installDate } + } +} + +// Tipi fantasma per la sicurezza dei tipi +struct AppState { + let app: App +} + +enum Downloaded {} +enum Installed {} + +typealias DownloadedApp = AppState +typealias InstalledApp = AppState +``` + +### Pattern Async/Await + +#### Design Funzione Async +- Utilizza async/await in modo coerente +- Struttura le operazioni simultanee in modo chiaro +- Gestisci le cancellazioni in modo appropriato + +```swift +// ✅ Giusto +actor AppInstallationManager { + private var activeInstallations: [String: Task] = [:] + + func installApp(_ app: App) async throws { + // Previene installazioni duplicate + if activeInstallations[app.identifier] != nil { + throw InstallationError.alreadyInstalling + } + + let task = Task { + try await performInstallation(app) + } + + activeInstallations[app.identifier] = task + + defer { + activeInstallations.removeValue(forKey: app.identifier) + } + + try await task.value + } + + private func performInstallation(_ app: App) async throws { + // Controlla cancellazioni durante i punti chiave + try Task.checkCancellation() + + let data = try await downloadApp(app) + + try Task.checkCancellation() + + try await installData(data, for: app) + } +} + +// ❌ Sbagliato +func installApp(_ app: App, completion: @escaping (Error?) -> Void) { + DispatchQueue.global().async { + // Mischia il vecchio completion handler style con il nuovo codice async + let result = await self.downloadApp(app) + DispatchQueue.main.async { + completion(nil) + } + } +} +``` + +#### Concorrenza Strutturata +- Usa i task group per operazioni concorrenti correlate +- Prediligi la concorrenza strutturata alle task non strutturate + +```swift +// ✅ Giusto +func installMultipleApps(_ apps: [App]) async throws { + try await withThrowingTaskGroup(of: Void.self) { group in + for app in apps { + group.addTask { + try await self.installApp(app) + } + } + + // Attende che tutte le installazioni siano completate + try await group.waitForAll() + } +} + +// Per risultati indipendenti +func downloadMultipleApps(_ apps: [App]) async throws -> [App: Data] { + try await withThrowingTaskGroup(of: (App, Data).self) { group in + for app in apps { + group.addTask { + let data = try await self.downloadApp(app) + return (app, data) + } + } + + var results: [App: Data] = [:] + for try await (app, data) in group { + results[app] = data + } + return results + } +} +``` + +### Result Builder e DSL + +#### Result Builder Personalizzati +- Crea result builder mirati e mono-funzione +- Usa una sintassi chiara per operazioni domain-specific + +```swift +// ✅ Giusto +@resultBuilder +struct AppConfigurationBuilder { + static func buildBlock(_ components: AppConfigurationComponent...) -> AppConfiguration { + return AppConfiguration(components: components) + } + + static func buildOptional(_ component: AppConfigurationComponent?) -> AppConfigurationComponent? { + return component + } + + static func buildEither(first component: AppConfigurationComponent) -> AppConfigurationComponent { + return component + } + + static func buildEither(second component: AppConfigurationComponent) -> AppConfigurationComponent { + return component + } +} + +// Utilizzo +func configureApp(@AppConfigurationBuilder builder: () -> AppConfiguration) -> App { + let config = builder() + return App(configuration: config) +} + +let app = configureApp { + AppName("SideStore") + AppVersion("1.0.0") + if debugMode { + DebugSettings() + } + Permissions { + NetworkAccess() + FileSystemAccess() + } +} +``` + +## Pattern Objective-C Avanzati + +### Organizzazione di Categorie +- Usa le categorie per organizzare funzionalità correlate +- Mantieni i nomi delle categorie descrittivi e specifici + +```objc +// ✅ Giusto +@interface NSString (SSValidation) +- (BOOL)ss_isValidAppIdentifier; +- (BOOL)ss_isValidVersion; +@end + +@interface UIViewController (SSAppInstallation) +- (void)ss_presentAppInstallationViewController:(SSApp *)app; +- (void)ss_showInstallationProgress:(SSInstallationProgress *)progress; +@end + +// ❌ Sbagliato +@interface NSString (Helpers) +- (BOOL)isValid; // Troppo generico +- (NSString *)cleanup; // Utilità non chiara +@end +``` + +### Gestione Avanzata della Memoria +- Usa modelli adeguati per le relazioni dei delegati +- Gestisci correttamente i grafi complessi degli oggetti + +```objc +// ✅ Giusto +@interface SSAppInstaller : NSObject +@property (nonatomic, weak) id delegate; +@property (nonatomic, strong) NSOperationQueue *installationQueue; +@end + +@implementation SSAppInstaller + +- (instancetype)init { + self = [super init]; + if (self) { + _installationQueue = [[NSOperationQueue alloc] init]; + _installationQueue.maxConcurrentOperationCount = 3; + _installationQueue.name = @"com.sidestore.installation"; + } + return self; +} + +- (void)installApp:(SSApp *)app completion:(void (^)(NSError *))completion { + __weak typeof(self) weakSelf = self; + NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ + __strong typeof(weakSelf) strongSelf = weakSelf; + if (!strongSelf) return; + + NSError *error = nil; + [strongSelf performInstallationForApp:app error:&error]; + + dispatch_async(dispatch_get_main_queue(), ^{ + completion(error); + }); + }]; + + [self.installationQueue addOperation:operation]; +} + +@end +``` + +### Utilizzo Pattern Block +- Usa pattern block appropriati per operazioni asincrone +- Gestisci correttamente la gestione della memoria nei blocchi + +```objc +// ✅ Giusto +typedef void (^SSInstallationProgressBlock)(float progress); +typedef void (^SSInstallationCompletionBlock)(SSApp *app, NSError *error); + +@interface SSAppDownloader : NSObject +- (NSURLSessionTask *)downloadApp:(SSApp *)app + progress:(SSInstallationProgressBlock)progressBlock + completion:(SSInstallationCompletionBlock)completion; +@end + +@implementation SSAppDownloader + +- (NSURLSessionTask *)downloadApp:(SSApp *)app + progress:(SSInstallationProgressBlock)progressBlock + completion:(SSInstallationCompletionBlock)completion { + + NSURLRequest *request = [NSURLRequest requestWithURL:app.downloadURL]; + + __weak typeof(self) weakSelf = self; + NSURLSessionDownloadTask *task = [[NSURLSession sharedSession] + downloadTaskWithRequest:request + completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { + __strong typeof(weakSelf) strongSelf = weakSelf; + if (!strongSelf) return; + + if (error) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(nil, error); + }); + return; + } + + // Processa il file scaricato + [strongSelf processDownloadedFile:location + forApp:app + completion:completion]; + }]; + + [task resume]; + return task; +} + +@end +``` + +## Pattern Architetturali + +### Implementazione MVVM +- Separa chiaramente tra Model, View e ViewModel +- Utilizza pattern appropriati di data binding + +```swift +// ✅ Giusto +// Model +struct App { + let identifier: String + let name: String + let version: String + let isInstalled: Bool +} + +// ViewModel +@MainActor +class AppListViewModel: ObservableObject { + @Published var apps: [App] = [] + @Published var isLoading = false + @Published var errorMessage: String? + + private let appService: AppService + + init(appService: AppService) { + self.appService = appService + } + + func loadApps() async { + isLoading = true + errorMessage = nil + + do { + apps = try await appService.fetchAvailableApps() + } catch { + errorMessage = error.localizedDescription + } + + isLoading = false + } + + func installApp(_ app: App) async { + do { + try await appService.installApp(app) + await loadApps() // Aggiorna la lista + } catch { + errorMessage = "Failed to install \(app.name): \(error.localizedDescription)" + } + } +} + +// View +struct AppListView: View { + @StateObject private var viewModel: AppListViewModel + + init(appService: AppService) { + _viewModel = StateObject(wrappedValue: AppListViewModel(appService: appService)) + } + + var body: some View { + NavigationView { + List(viewModel.apps, id: \.identifier) { app in + AppRowView(app: app) { + Task { + await viewModel.installApp(app) + } + } + } + .navigationTitle("Available Apps") + .overlay { + if viewModel.isLoading { + ProgressView() + } + } + .alert("Error", isPresented: .constant(viewModel.errorMessage != nil)) { + Button("OK") { + viewModel.errorMessage = nil + } + } message: { + Text(viewModel.errorMessage ?? "") + } + } + .task { + await viewModel.loadApps() + } + } +} +``` + +### Dependency Injection +- Usa il dependency injection per la provabilità e la flessibilità +- Prendi in considerazione l'utilizzo di un container DI per applicazioni complesse + +```swift +// ✅ Giusto +protocol AppService { + func fetchAvailableApps() async throws -> [App] + func installApp(_ app: App) async throws +} + +protocol NetworkService { + func downloadData(from url: URL) async throws -> Data +} + +class DefaultAppService: AppService { + private let networkService: NetworkService + private let deviceService: DeviceService + + init(networkService: NetworkService, deviceService: DeviceService) { + self.networkService = networkService + self.deviceService = deviceService + } + + func fetchAvailableApps() async throws -> [App] { + let data = try await networkService.downloadData(from: appsURL) + return try JSONDecoder().decode([App].self, from: data) + } + + func installApp(_ app: App) async throws { + guard deviceService.hasSpace(for: app) else { + throw InstallationError.insufficientStorage + } + + let appData = try await networkService.downloadData(from: app.downloadURL) + try await deviceService.installApp(data: appData) + } +} + +// Container DI +class ServiceContainer { + static let shared = ServiceContainer() + + private init() {} + + lazy var networkService: NetworkService = DefaultNetworkService() + lazy var deviceService: DeviceService = DefaultDeviceService() + lazy var appService: AppService = DefaultAppService( + networkService: networkService, + deviceService: deviceService + ) +} +``` + +### Architettura di Gestione degli Errori +- Crea strategie globali di gestione degli errori +- Usa errori tipo per una migliore gestione degli errori + +```swift +// ✅ Giusto +enum SideStoreError: Error { + case network(NetworkError) + case installation(InstallationError) + case device(DeviceError) + case validation(ValidationError) +} + +enum NetworkError: Error { + case noConnection + case timeout + case serverError(Int) + case invalidResponse +} + +enum InstallationError: Error { + case insufficientStorage + case incompatibleDevice + case corruptedFile + case alreadyInstalled +} + +extension SideStoreError: LocalizedError { + var errorDescription: String? { + switch self { + case .network(let networkError): + return "Network error: \(networkError.localizedDescription)" + case .installation(let installError): + return "Installation error: \(installError.localizedDescription)" + case .device(let deviceError): + return "Device error: \(deviceError.localizedDescription)" + case .validation(let validationError): + return "Validation error: \(validationError.localizedDescription)" + } + } +} + +// Gestione degli errori nei servizi +class AppService { + func installApp(_ app: App) async throws { + do { + try validateApp(app) + } catch { + throw SideStoreError.validation(error as! ValidationError) + } + + do { + try await performInstallation(app) + } catch let error as NetworkError { + throw SideStoreError.network(error) + } catch let error as InstallationError { + throw SideStoreError.installation(error) + } + } +} +``` + +## Considerazioni di Performance + +### Ottimizzazione della Memoria +- Usa il lazy loading per risorse costose +- Implementa strategie di caching adatte + +```swift +// ✅ Giusto +class AppImageCache { + private let cache = NSCache() + private let downloadQueue = DispatchQueue(label: "image-download", qos: .utility) + + init() { + cache.countLimit = 50 + cache.totalCostLimit = 50 * 1024 * 1024 // 50MB + } + + func image(for app: App) async -> UIImage? { + let key = app.identifier as NSString + + // Prima controllo la cache + if let cachedImage = cache.object(forKey: key) { + return cachedImage + } + + // Scarico se non è nella cache + return await withCheckedContinuation { continuation in + downloadQueue.async { [weak self] in + guard let self = self else { + continuation.resume(returning: nil) + return + } + + do { + let data = try Data(contentsOf: app.iconURL) + let image = UIImage(data: data) + + if let image = image { + self.cache.setObject(image, forKey: key) + } + + continuation.resume(returning: image) + } catch { + continuation.resume(returning: nil) + } + } + } + } +} +``` + +### Threading Best Practices +- Utilizza priorità appropriate della coda +- Minimizza il context switching + +```swift +// ✅ Giusto +actor BackgroundProcessor { + private let processingQueue = DispatchQueue( + label: "background-processing", + qos: .utility, + attributes: .concurrent + ) + + func processLargeDataSet(_ data: [LargeDataItem]) async -> [ProcessedItem] { + return await withTaskGroup(of: ProcessedItem?.self, returning: [ProcessedItem].self) { group in + let chunkSize = max(data.count / ProcessInfo.processInfo.activeProcessorCount, 1) + + for chunk in data.chunked(into: chunkSize) { + group.addTask { + return await self.processChunk(chunk) + } + } + + var results: [ProcessedItem] = [] + for await result in group { + if let processed = result { + results.append(processed) + } + } + + return results + } + } + + private func processChunk(_ chunk: [LargeDataItem]) async -> ProcessedItem? { + // Calcolo CPU-intensive + return await withCheckedContinuation { continuation in + processingQueue.async { + let result = chunk.map { self.expensiveOperation($0) } + continuation.resume(returning: ProcessedItem(results: result)) + } + } + } +} +``` + +## Pattern di Testing + +### Testing Protocol-Based +- Usa i protocolli per la dependency injection nei test +- Crea test double mirati + +```swift +// ✅ Giusto +class MockAppService: AppService { + var shouldFailInstallation = false + var installedApps: [App] = [] + + func fetchAvailableApps() async throws -> [App] { + return [ + App(identifier: "test.app1", name: "Test App 1", version: "1.0.0"), + App(identifier: "test.app2", name: "Test App 2", version: "2.0.0") + ] + } + + func installApp(_ app: App) async throws { + if shouldFailInstallation { + throw InstallationError.insufficientStorage + } + installedApps.append(app) + } +} + +class AppListViewModelTests: XCTestCase { + private var mockAppService: MockAppService! + private var viewModel: AppListViewModel! + + override func setUp() { + super.setUp() + mockAppService = MockAppService() + viewModel = AppListViewModel(appService: mockAppService) + } + + @MainActor + func testLoadAppsSuccess() async { + await viewModel.loadApps() + + XCTAssertEqual(viewModel.apps.count, 2) + XCTAssertFalse(viewModel.isLoading) + XCTAssertNil(viewModel.errorMessage) + } + + @MainActor + func testInstallAppFailure() async { + mockAppService.shouldFailInstallation = true + + let testApp = App(identifier: "test", name: "Test", version: "1.0") + await viewModel.installApp(testApp) + + XCTAssertNotNil(viewModel.errorMessage) + XCTAssertTrue(viewModel.errorMessage!.contains("insufficient storage")) + } +} +``` + +## Standard della Documentazione + +### Documentazione API Complessa +- Documenta comportamenti complessi e gli edge case +- Fornisci esempi di utilizzo per API non-trivial + +```swift +/** + * Un gestore thread-safe per la gestione delle installazioni delle app con logica di riprova automatica. + * + * Questa classe gestisce il processo di installazione delle applicazioni iOS, occupandosi dei + * download di rete, della verifica delle firme e della comunicazione con i dispositivi. + * Fornisce una funzionalità di riprova automatica per gli errori transitori e una + * reportistica completa degli errori. + * + * ## Esempio di utilizzo + * ```swift + * let installer = AppInstallationManager() + * + * do { + * let result = try await installer.installApp( + * from: app.sourceURL, + * identifier: app.bundleID, + * maxRetries: 3 + * ) + * print(“Installazione completata: \(result.installedPath)”) + * } catch InstallationError.insufficientStorage { + * // Gestisci errore di archiviazione + * } catch { + * // Gestisci altri errori + * } + * ``` + * + * ## Sicurezza dei thread + * Questa classe è thread-safe e può essere richiamata da qualsiasi coda. Tutti i gestori di + * completamento vengono richiamati sulla coda principale, salvo diversamente specificato. + * + * ## Gestione degli errori + * Gli errori di installazione sono classificati in errori recuperabili e non recuperabili. + * Gli errori recuperabili (timeout di rete, problemi temporanei del dispositivo) + * verranno riprovati automaticamente fino al limite specificato. Gli errori non recuperabili + * (firme non valide, dispositivi incompatibili) causeranno un errore immediato. + */ +@MainActor +class AppInstallationManager { + // Implementazione +} +``` + +Ricorda: questi modelli avanzati devono essere utilizzati con giudizio. Dai sempre la priorità alla chiarezza e alla manutenibilità del codice rispetto a implementazioni ingegnose. In caso di dubbio, scegli l'approccio più semplice che soddisfi comunque i requisiti. \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/current/contributing/contributing.mdx b/i18n/it/docusaurus-plugin-content-docs/current/contributing/contributing.mdx new file mode 100644 index 00000000..a286a637 --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/contributing/contributing.mdx @@ -0,0 +1,240 @@ +--- +sidebar_position: 1 +--- + +# Contribuire a SideStore + +Ti ringraziamo per l'interesse nel contribuire a SideStore! SideStore è un progetto guidato dalla community ed è reso possibile grazie a gente come te. + +Contribuendo a questo progetto (SideStore) accetti il Developer Certificate of Origin che puoi trovare in [CERTIFICATE-OF-ORIGIN.md](https://github.com/SideStore/SideStore/blob/develop/CERTIFICATE-OF-ORIGIN.md). Qualsiasi contributo a questo progetto dopo l'aggiunta del Developer Certificate of Origin è soggetto alla sua politica. + +Ci sono diversi modi per contribuire a SideStore, quindi se non sei uno sviluppatore ci sono comunque vari medi per aiutare: + +- [Scrivere la documentazione](https://github.com/SideStore/SideStore-Docs) +- [Inviare bug report dettagliati e consigliare nuove funzionalità](https://github.com/SideStore/SideStore/issues/new/choose) +- Aiutarci col supporto: + - [Discord](https://discord.gg/sidestore-949183273383395328) + - [GitHub Discussions](https://github.com/SideStore/SideStore/discussions) + +In ogni caso, questa guida si concentrerà sulla parte dello sviluppo. Per ora qui troverai solo le info per il setup, ma puoi [unirti al nostro Discord](https://discord.gg/sidestore-949183273383395328) se hai bisogno di più aiuto. + +## Requisiti + +Questa guida assume che tu: + +- abbia un Mac +- abbia Xcode installato +- abbia una conoscenza base del terminale (come eseguire comandi, fare cd in una directory) +- abbia una conoscenza base di Git ([GitHub Desktop](https://desktop.github.com/) è un ottimo tool per beginner e semplifica molto il lavorare con Git) +- abbia una conoscenza base di Swift e sviluppo iOS + +## Setup + +1. **Forka la repo SideStore su GitHub**. + +2. **Clona il fork**: + ```bash + git clone https://github.com//SideStore.git --recurse + cd SideStore + ``` + + Se stai usando GitHub Desktop, guarda [questa guida](https://docs.github.com/en/desktop/contributing-and-collaborating-using-github-desktop/adding-and-cloning-repositories/cloning-and-forking-repositories-from-github-desktop). + +3. **Copia `CodeSigning.xcconfig.sample` in `CodeSigning.xcconfig`** e inserisci i valori. + +4. **(Solo sviluppo)** Cambia il valore di `ALTDeviceID` nell'Info.plist con l'UDID del tuo dispositivo. Di solito SideServer lo fa in automatico durante l'installazione. Quando utilizzi Xcode devi settarlo manualmente altrimenti SideStore non ri-firmerà (né installerà) correttamente le app. + +5. **Infine, apri `AltStore.xcworkspace` in Xcode**. + +Successivamente fai e prova le tue modifiche. Poi fai il commit e pusha i cambiamenti con git e apri una pull request. + + +## Info sui binari precompilati + +minimuxer ed em_proxy utilizzano binari precompilati con librerie statiche creati da GitHub Actions per velocizzare le compilazioni ed eliminare la necessità di installare Rust quando si lavora su SideStore. [`SideStore/fetch-prebuilt.sh`](https://github.com/SideStore/SideStore/blob/develop/SideStore/fetch-prebuilt.sh) verrà eseguito prima di ogni compilazione da Xcode e verificherà una volta ogni 6 ore se i binari scaricati sono aggiornati. Se si desidera forzare la verifica della presenza di nuovi binari, esegui `bash ./SideStore/fetch-prebuilt.sh force`. + +## Compilare con Xcode + +Se necessario installa cocoapods con: `brew install cocoapods` +Ora dal terminale nella root della repository, esegui un Pod-Install con il comando `pod install` per installare le dipendenze di cocoapod. +Dopodiché potrai compilare con Xcode normalmente. + +## Compilare un IPA per la Distribuzione + +Se necessario installa cocoapods con: `brew install cocoapods` +Ora dal terminale nella root della repository, esegui un Pod-Install con il comando `pod install` per installare le dipendenze di cocoapod. + +Puoi ora usare il comando Makefile `make build fakesign ipa` nella root directory. +La configurazione di default per la compilazione è `Release` +Per le build di debug: `export BUILD_CONFIG=Debug;make build fakesign ipa` nella root directory. +Per le build alpha/beta: `export IS_ALPHA=1;` o `export IS_BETA=1;` prima di invocare il comando per la build. +Questo creerà il file SideStore.ipa. + +```sh +Esempi: + + # cocoapods + brew install cocoapods + # esegui l'installazione dei pods + pod install + + # build alpha release + export IS_ALPHA=1;make build fakesign ipa + # build alpha debug + export IS_ALPHA=1;export BUILD_CONFIG=Debug;make build fakesign ipa + + # build beta release + export IS_BETA=1;make build fakesign ipa + # build beta debug + export IS_BETA=1;export BUILD_CONFIG=Debug;make build fakesign ipa + + # build release stabile + make build fakesign ipa + # build debug stabile + export BUILD_CONFIG=Debug;make build fakesign ipa +``` + +Di default SideStore verrà compilato con il suo bundleIdentifier di default `com.SideStore.SideStore`, se hai bisogno di impostarne uno personalizzato puoi farlo esportando la variabile `BUNDLE_ID_SUFFIX`: + +```sh + # build release stabile + export BUNDLE_ID_SUFFIX=XYZ0123456;make build fakesign ipa + # build debug stabile + export BUNDLE_ID_SUFFIX=XYZ0123456;export BUILD_CONFIG=Debug;make build fakesign ipa +``` + +**NOTA**: Quando si compila da XCode, `BUNDLE_ID_SUFFIX` è impostato di default al valore di `DEVELOPMENT_TEAM` + +Questo comportamento può essere modificato impostando/rimuovendo BUNDLE_ID_SUFFIX sovrascrivendo CodeSigning.xcconfig creato da CodeSigning.xcconfig.sample + +:::warning +Il binario creato conterrà i percorsi dei DerivedData di Xcode e, se hai compilato minimuxer sulla tua macchina, i percorsi di $HOME/.cargo. Questi includono il tuo username. Se vuoi mantenere primato il tuo username, puoi far compilare l'IPA da GitHub Actions. +::: + +## Sviluppare minimuxer affianco a SideStore + +Leggi il [README di minimuxer](https://github.com/SideStore/minimuxer) per istruzioni sullo sviluppo. + +## Procedura per una Pull Request + +### Prima di presentarla + +1. **Segui gli standard della programmazione**: Assicurati che il tuo codice segua le nostre [linee guida sulla formattazione](./formatting.mdx). + +2. **Testa i cambiamenti**: + - Testa su diverse versioni iOS quando possibile + - Assicurati che le funzioni esistenti non siano rotte + - Aggiungi test per le nuove funzioni quando possibile + +3. **Aggiorna la documentazione**: Aggiorna la documentazione se le modifiche apportate influiscono su funzionalità visibili all'utente. + +### Presentare la tua PR + +1. **Crea una feature branch**: + ```bash + git checkout -b feature/nome-della-feature + ``` + +2. **Applica i cambiamenti**: Segui le linee guida e le best-practice. + +3. **Committa i cambiamenti firmandoli**: + ```bash. + git add . + git commit -s -m "Aggiungi un messaggio descrittivo" + ``` + + **Importante**: Tutti i commit devono essere firmati con il Developer Certificate of Origin (DCO). Il flag `-s` aggiunge automaticamente la linea `Signed-off-by` al tuo messaggio del commit. + +4. **Pusha nel tuo fork**: + ```bash + git push origin feature/nome-della-feature + ``` + +5. **Crea una Pull Request**: Vai nella repo di SideStore e crea una pull request dal tuo branch. + +:::caution +**Non** accettiamo pull request che sono palesemente generate da AI o "vibe-coded" (es: troppi commenti ovvi, codice generico, mancanza di comprensione del progetto o codice non pensato appositamente per SideStore). Assicurati che i tuoi contributi siano originali e dimostrino chiara comprensione del codice e dei suoi obiettivi. +::: + +### PR Guidelines + +- **Clear title**: Use a descriptive title that summarizes the change +- **Detailed description**: Explain what changes you made and why +- **Link related issues**: Reference any related GitHub issues +- **Screenshots**: Include screenshots for UI changes +- **Testing notes**: Describe how you tested your changes + +## Developer Certificate of Origin (DCO) + +SideStore richiede che tutti i collaboratori firmino i commit utilizzando il Developer Certificate of Origin (DCO). Questo funge da Codice di Condotta dei collaboratori ed è un modo semplice per certificare che hai scritto e hai diritto di inviare il codice che stai pushando. + +### Cos'è il DCO? + +Firmando i tuoi commit, certifichi che: + +- **(a)** La contribuzione è stata creata interamente o in parte da te e hai il diritto di inviarla sotto la licenza open source indicata nel file; oppure +- **(b)** La contribuzione è basata su lavori esistenti che, secondo la tua conoscenza, sono coperti da una licenza open source appropriata e hai il diritto, in base a tale licenza, di presentare il lavoro con quelle modifiche; oppure +- **(c)** La contribuzione ti è stata direttamente fornita da qualche altra persona che ha certificato (a) o (b) e non hai apportato modifiche. +- **(d)** Comprendi e accetti che questo progetto e il contributo sono pubblici e che la registrazione del contributo è conservata per un tempo indeterminato. + +### Come firmare + +Per firmare i tuoi commit, aggiungi semplicemente il flag `-s` quando fai un commit: + +```bash +git commit -s -m "Messaggio del commit" +``` + +Questo aggiungerà automaticamente la riga `Signed-off-by` al tuo messaggio del commit: + +``` +Messaggio del commit + +Signed-off-by: SternXD +``` + +### Note importanti + +- **Tutti i commit devono essere firmati** - Di solito preferiamo che tu firmi i tuoi commit. +- **Usa l'indirizzo email corretto** - L'indirizzo email deve corrispondere al tuo account GitHub +- **Firma retroattiva** - Se dimentichi di firmare, puoi modificare il tuo ultimo commit con `git commit --amend -s` + +Per maggiori dettagli, vedi il documento completo del [Certificato di Origine](https://github.com/SideStore/SideStore/blob/develop/CERTIFICATE-OF-ORIGIN.md). + +## Processo di revisione del codice + +1. **Revisione iniziale**: un responsabile della manutenzione esaminerà la tua PR entro pochi giorni +2. **Feedback**: rispondi a eventuali richieste di modifiche o domande +3. **Approvazione finale**: una volta approvata, un responsabile della manutenzione mergerà la tua PR + +## Linee guida per contributi di qualità + +### Qualità del codice +- Scrivi un codice pulito e leggibile +- Segui le best-practice di Swift e Objective-C +- Usa nomi di funzioni e variabili sensati +- Aggiungi commenti dove il codice è complesso + +### Testing +- Testa su device fisico quando possibile +- Testa gli edge case e i possibili errori +- Verifica la retro-compatibilità + +### Documentazione +- Aggiorna i commenti sul codice +- Aggiorna la documentazione destinata agli utenti +- Includei documentazione inline per le API pubbliche + +## Ottenere Aiuto + +Se hai bisogno di aiuto o hai domande: + +- **GitHub Discussions**: Usa GitHub Discussions per domande generiche +- **GitHub Issues**: Crea un'issue per bug o una feature request +- **Discord**: Unisciti alla community di SideStore su Discord + +## Riconoscimenti + +I collaboratori che contribuiscono in modo importante saranno inseriti nei crediti e nel changelog del progetto. + +Grazie per contribuire a SideStore! \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/current/contributing/formatting.mdx b/i18n/it/docusaurus-plugin-content-docs/current/contributing/formatting.mdx new file mode 100644 index 00000000..043674ac --- /dev/null +++ b/i18n/it/docusaurus-plugin-content-docs/current/contributing/formatting.mdx @@ -0,0 +1,492 @@ +--- +sidebar_position: 2 +--- + +# Linee guida sulla formattazione del codice + +Questo documento schematizza gli standard della formattazione di Swift e Objective-C per SideStore. Una formattazione coerente rende il codice più leggibile e manutenibile. + +## Principi Generali + +- **Consistenza**: Segui lo stile già esistente nel progetto +- **Leggibilità**: Il codice deve essere semplice da leggere e da capire +- **Semplicità**: Preferisci soluzioni semplici e chiare a quelle furbe +- **Convenzioni di Apple**: Segui le convenzioni di Apple per Swift e Objective-C quando possibile + +## Formattazione Swift + +### Convenzione sui Nomi + +#### Variabili e Funzioni +- Usa il **camelCase** per variabili, funzioni e metodi +- Usa nomi descrittivi che indichino chiaramente lo scopo + +```swift +// ✅ Giusto +let downloadProgress: Float +func validateUserCredentials() -> Bool +var isAppInstalling: Bool + +// ❌ Sbagliato +let dp: Float +func validate() -> Bool +var installing: Bool +``` + +#### Classi, Struct, Enums, e Protocolli +- Usa il **PascalCase** per i tipi +- Usa nomi descrittivi + +```swift +// ✅ Giusto +class AppInstaller +struct InstallationProgress +enum AppState +protocol AppManaging + +// ❌ Sbagliato +class installer +struct progress +enum state +protocol managing +``` + +#### Costanti +- Usa il **camelCase** per le costanti +- Considera l'utilizzo del **SCREAMING_SNAKE_CASE** per costanti globali + +```swift +// ✅ Giusto +let maxRetryAttempts = 3 +private let defaultTimeout: TimeInterval = 30.0 + +// Global constants +let MAX_CONCURRENT_DOWNLOADS = 5 + +// ❌ Sbagliato +let MaxRetryAttempts = 3 +let max_retry_attempts = 3 +``` + +### Indentazione e spaziatura + +#### Indentazione +- Usa **4 spazi** per l'indentazione (non tab) +- Allinea le righe successive con il delimitatore aperto + +```swift +// ✅ Giusto +func installApp(withIdentifier identifier: String, + sourceURL: URL, + completion: @escaping (Result) -> Void) { + // Implementazione +} + +// ❌ Sbagliato +func installApp(withIdentifier identifier: String, +sourceURL: URL, +completion: @escaping (Result) -> Void) { +// Implementazione +} +``` + +#### Lunghezza delle righe +- Tieni le righe sotto i **120 caratteri** quando possibile +- Spezza le righe lunghe in punti logici + +```swift +// ✅ Giusto +let longVariableName = SomeClass.createInstanceWithVeryLongMethodName( + parameter1: value1, + parameter2: value2 +) + +// ❌ Sbagliato +let longVariableName = SomeClass.createInstanceWithVeryLongMethodName(parameter1: value1, parameter2: value2, parameter3: value3) +``` + +#### Spaziatura +- Usa spazi singoli intorno agli operatori +- Nessuno spazio bianco finale +- Una sola riga vuota tra le funzioni e le sezioni principali del codice + +```swift +// ✅ Giusto +let result = value1 + value2 +if condition && anotherCondition { + // Codice +} + +func firstFunction() { + // Implementazione +} + +func secondFunction() { + // Implementazione +} + +// ❌ Sbagliato +let result=value1+value2 +if condition&&anotherCondition{ + // Codice +} +func firstFunction(){ + // Implementazione +} +func secondFunction(){ + // Implementazione +} +``` + +### Parentesi e Control Flow + +#### Stile delle parentesi +- Apri la parentesi nella stessa riga dello statement +- Chiudi la parentesi in una riga tutta sua, allineata con lo statement di apertura + +```swift +// ✅ Giusto +if condition { + doSomething() +} else { + doSomethingElse() +} + +class MyClass { + func myMethod() { + // Implementazione + } +} + +// ❌ Sbagliato +if condition +{ + doSomething() +} +else +{ + doSomethingElse() +} +``` + +#### Guard Statement +- Usa i guard statement per return anticipati +- Mantieni le condizioni del guard semplici e leggibili + +```swift +// ✅ Giusto +guard let url = URL(string: urlString) else { + completion(.failure(ValidationError.invalidURL)) + return +} + +guard !apps.isEmpty else { + return +} + +// ❌ Sbagliato +if let url = URL(string: urlString) { + // Blocco di codice lungo e annidato +} else { + completion(.failure(ValidationError.invalidURL)) + return +} +``` + +### Type Annotation e Inference + +#### Quando usare le Type Annotation +- Usa le type annotation quando il tipo non è ovvio +- Ometti le type annotation quando Swift può chiaramente capire il tipo + +```swift +// ✅ Giusto +let name = "SideStore" // Il tipo è ovvio +let timeout: TimeInterval = 30 // Il tipo chiarisce l'intento +var apps: [App] = [] // L'array vuoto necessita del tipo + +// ❌ Sbagliato +let name: String = "SideStore" // Tipo superfluo +let timeout = 30 // Non è chiaro se è Int o TimeInterval +``` + +### Dichiarare le Funzioni + +#### Etichette dei parametri +- Usa etichette descrittive +- Ometti la prima etichetta quando si legge naturalmente + +```swift +// ✅ Giusto +func install(_ app: App, to device: Device) +func download(from url: URL, completion: @escaping (Data?) -> Void) + +// ❌ Sbagliato +func install(app: App, device: Device) +func download(url: URL, completion: @escaping (Data?) -> Void) +``` + +#### Return Type +- Tieni i return type sulla stessa riga quando possibile +- Mettili su una nuova riga se diventa troppo lunga + +```swift +// ✅ Giusto +func processData() -> Result + +func complexFunction(withManyParameters param1: String, + param2: Int, + param3: Bool) + -> Result { + // Implementazione +} +``` + +## Formattazione Objective-C + +### Convenzione dei nomi + +#### Metodi +- Usa nomi dei metodi descrittivi con etichette dei parametri chiare +- Inizia con la lettera minuscola +- Usa il camelCase + +```objc +// ✅ Giusto +- (void)installAppWithIdentifier:(NSString *)identifier + sourceURL:(NSURL *)sourceURL + completion:(void (^)(NSError *error))completion; + +// ❌ Sbagliato +- (void)install:(NSString *)id url:(NSURL *)url completion:(void (^)(NSError *))completion; +``` + +#### Variabili e Proprietà +- Usa il camelCase +- Usa nomi descrittivi +- Metti un underscore davanti alle instance variable + +```objc +// ✅ Giusto +@interface AppManager : NSObject +@property (nonatomic, strong) NSArray *installedApps; +@property (nonatomic, assign) BOOL isInstalling; +@end + +@implementation AppManager { + NSURLSession *_networkSession; + dispatch_queue_t _processingQueue; +} +``` + +#### Classi e Protocolli +- Usa il PascalCase +- Considera l'utilizzo di prefissi per classi pubbliche (es: SS per SideStore) + +```objc +// ✅ Giusto +@interface SSAppInstaller : NSObject +@protocol SSAppManaging + +// ❌ Sbagliato +@interface appInstaller : NSObject +@protocol appManaging +``` + +### Spaziatura e Formattazione + +#### Dichiarazione dei metodi +- Allinea i parametri verticalmente +- Usa una spaziatura uniforme + +```objc +// ✅ Giusto +- (instancetype)initWithIdentifier:(NSString *)identifier + title:(NSString *)title + version:(NSString *)version; + +// ❌ Sbagliato +- (instancetype)initWithIdentifier:(NSString *)identifier title:(NSString *)title version:(NSString *)version; +``` + +#### Parentesi +- La parentesi si apre nella stessa riga +- La parentesi si chiude in una riga sua + +```objc +// ✅ Giusto +if (condition) { + [self doSomething]; +} else { + [self doSomethingElse]; +} + +// ❌ Sbagliato +if (condition) +{ + [self doSomething]; +} +else +{ + [self doSomethingElse]; +} +``` + +## Commenti e Documentazione + +### Documentazione Swift +- Usa `///` per commenti di documentazione +- Includi le descrizioni dei parametri e dei valori per API pubbliche + +```swift +/// Downloads and installs an app from the specified URL +/// - Parameters: +/// - identifier: The unique identifier for the app +/// - sourceURL: The URL to download the app from +/// - completion: Called when installation completes or fails +/// - Returns: A cancellable operation +func installApp(withIdentifier identifier: String, + sourceURL: URL, + completion: @escaping (Result) -> Void) -> Operation { + // Implementazione +} +``` + +### Documentazione Objective-C +- Usa `/** */` per commenti sulla documentazione +- Segui le convenzioni HeaderDoc o Doxygen + +```objc +/** + * Downloads and installs an app from the specified URL + * @param identifier The unique identifier for the app + * @param sourceURL The URL to download the app from + * @param completion Block called when installation completes or fails + */ +- (void)installAppWithIdentifier:(NSString *)identifier + sourceURL:(NSURL *)sourceURL + completion:(void (^)(NSError *error))completion; +``` + +### Commenti inline +- Usa `//` per commenti in una sola riga +- Mantieni i commenti concisi e rilevanti +- Spiega **perché**, non **cosa** + +```swift +// ✅ Giusto +// Retry failed downloads up to 3 times to handle temporary network issues +let maxRetryAttempts = 3 + +// ❌ Sbagliato +// Set maxRetryAttempts to 3 +let maxRetryAttempts = 3 +``` + +## Gestione degli Errori + +### Gestione degli Errori di Swift +- Usa la gestione degli errori nativa di Swift con `throws` e `Result` +- Crea tipi significativi per gli errori + +```swift +enum InstallationError: Error { + case invalidURL + case networkFailure(Error) + case insufficientStorage + case deviceNotSupported +} + +func installApp() throws -> App { + guard let url = URL(string: urlString) else { + throw InstallationError.invalidURL + } + // Implementazione +} +``` + +### Gestione degli Errori per Objective-C +- Utilizza il modello di parametro `NSError **` +- Controlla sempre che il parametro di errore sia non-nullo + +```objc +- (BOOL)installAppWithError:(NSError **)error { + if (someCondition) { + if (error) { + *error = [NSError errorWithDomain:SSErrorDomain + code:SSErrorCodeInvalidInput + userInfo:nil]; + } + return NO; + } + return YES; +} +``` + +## Best Practice + +### Gestione della Memoria +- Utilizza ARC correttamente sia in Swift che in Objective-C +- Fai attenzione ai cicli retain; utilizza i riferimenti `weak` e `unowned` in modo appropriato + +```swift +// ✅ Giusto +class AppInstaller { + weak var delegate: AppInstallerDelegate? + + private lazy var networkManager: NetworkManager = { + let manager = NetworkManager() + manager.delegate = self // Self è un riferimento forte, ma il gestore non conserva self + return manager + }() +} +``` + +### Threading +- Aggiorna sempre l'UI sulla coda principale +- Usa code appropriate per task in background + +```swift +// ✅ Giusto +DispatchQueue.global(qos: .userInitiated).async { + let result = self.processData() + DispatchQueue.main.async { + self.updateUI(with: result) + } +} +``` + +### Gestione facoltativa +- Usa tecniche sicure di unwrapping +- Prediligi le istruzioni guard per i return anticipati + +```swift +// ✅ Giusto +guard let data = response.data, + let apps = try? JSONDecoder().decode([App].self, from: data) else { + completion(.failure(ParsingError.invalidResponse)) + return +} +``` + +## Strumenti e Automazioni + +### SwiftLint +Considera l'utilizzo di SwiftLint per applicare automaticamente queste regole di formattazione: + +```yaml +# .swiftlint.yml +line_length: 120 +function_body_length: 60 +file_length: 400 +type_body_length: 300 + +disabled_rules: + - trailing_whitespace + +opt_in_rules: + - empty_count + - force_unwrapping +``` + +Ricorda: Queste linee guida dovrebbero migliorare la leggibilità e la manutenibilità del codice. Se sei in dubbio, prediligi la chiarezza e l'omogeneità col codice già scritto. \ No newline at end of file diff --git a/i18n/it/docusaurus-plugin-content-docs/current/faq.mdx b/i18n/it/docusaurus-plugin-content-docs/current/faq.mdx index 06de25c8..eb0f945e 100644 --- a/i18n/it/docusaurus-plugin-content-docs/current/faq.mdx +++ b/i18n/it/docusaurus-plugin-content-docs/current/faq.mdx @@ -18,7 +18,7 @@ L'obbiettivo di SideStore è quello di fornire un'esperienza di sideload untethe ### Posso attivare JIT? -Gli utenti che utilizzano iOS/iPadOS 16 o inferiori possono attivare JIT direttamente dalla pagina 'Le mie app' di Sidestore tenendo premuto l'app e selezionando 'Abilita JIT'. +Gli utenti che utilizzano iOS/iPadOS 16 o inferiori possono attivare JIT direttamente dalla pagina 'Le mie app' di SideStore tenendo premuto l'app e selezionando 'Abilita JIT'. Gli utenti su iOS o iPadOS 17.4 o superiori possono utilizzare SideStore 0.6.2 o StikDebug (prima StikJIT). Per più info seguire il tutorial nella sezione [Avanzate](advanced/jit). @@ -52,7 +52,7 @@ Normalmente no, in quanto è una limitazione di iOS e dell'account sviluppatore. Per rimuovere questa restrizione (e avere una scadenza di 365 giorni), puoi pagare €99/anno per un account Apple Sviluppatore. -In alternativa, sulle versioni di iOS 18 db5/18.0.1 e inferiori, puoi utlizzare l'exploit di SparseRestore per bypassare il limite di 3 app. +In alternativa, sulle versioni di iOS 18 db5/18.0.1 e inferiori, puoi utilizzare l'exploit di SparseRestore per bypassare il limite di 3 app. Puoi trovare la guida [qui](advanced/sparserestore). @@ -92,7 +92,7 @@ Certo che la abbiamo! ### Ho visto un iMac o un MacBook Pro aggiunto al mio account. È sicuro? È un vero Mac? -Questi Mac non sono veri, sono generati automaticamente dal server Anisett per semplificare il login. Nessun dato privato è inviato al server Anisette, dato che i dati del server sono utlizzati solo da SideStore. +Questi Mac non sono veri, sono generati automaticamente dal server Anisette per semplificare il login. Nessun dato privato è inviato al server Anisette, dato che i dati del server sono utilizzati solo da SideStore. ### Perché il mio account viene bloccato quando uso SideStore? @@ -108,7 +108,7 @@ Sì, semplicemente non cancellare l'app dal tuo dispositivo. Vai su SideStore e ### Perché devo refreshare SideStore subito dopo il login? -Perché AltServer o altri programmi eseguono il sideload di SideStore con il loro groupID, mentre noi usiamo il nostro. Refreshare Sidestore lo cambia con il nostro, il che farebbe sparire le altre app con un diverso groupID. È meglio non sideloadare niente prima del primo refresh di SideStore. +Perché AltServer o altri programmi eseguono il sideload di SideStore con il loro groupID, mentre noi usiamo il nostro. Refreshare SideStore lo cambia con il nostro, il che farebbe sparire le altre app con un diverso groupID. È meglio non sideloadare niente prima del primo refresh di SideStore. ### SideStore supporta gli aggiornamenti OTA? @@ -124,7 +124,7 @@ Non andare nel panico! Ri-esegui il sideload delle app senza rimuoverle dal disp ### Non riesco a selezionare il pairing file con qualsiasi estensione -Assicurati che l'estensione del file di pairing sia `.mobiledevicepairing` o `.plist`. Se non dovesse essere così, controlla se hai zippato il pairing file prima di averlo mandato sul tuo dispositivo. Altrimenti potrebbe essere che venga corrotto durante il trasferimento. Inoltre quando firmi SideStore con un certificato, non sarai in grado di selezionare il file di pairing dall'app. Puoi provare a spostare il file di pairing nella cartalla di SideStore nell'app File e cambiare il nome in `ALTPairingFile.mobiledevicepairing`. Se non vedi la cartella SideStore nell'app File, connetti il dispositivo al computer e trascina il file di pairing nei file dell'app SideStore. Assicurati di cambiare il nome come scritto sopra. Nota che è case sensitive. +Assicurati che l'estensione del file di pairing sia `.mobiledevicepairing` o `.plist`. Se non dovesse essere così, controlla se hai zippato il pairing file prima di averlo mandato sul tuo dispositivo. Altrimenti potrebbe essere che venga corrotto durante il trasferimento. Inoltre quando firmi SideStore con un certificato, non sarai in grado di selezionare il file di pairing dall'app. Puoi provare a spostare il file di pairing nella cartella di SideStore nell'app File e cambiare il nome in `ALTPairingFile.mobiledevicepairing`. Se non vedi la cartella SideStore nell'app File, connetti il dispositivo al computer e trascina il file di pairing nei file dell'app SideStore. Assicurati di cambiare il nome come scritto sopra. Nota che è case sensitive. ### Impossibile eseguire DebugServer diff --git a/i18n/it/docusaurus-plugin-content-docs/current/installation/prerequisites.mdx b/i18n/it/docusaurus-plugin-content-docs/current/installation/prerequisites.mdx index faba5011..976baaa6 100644 --- a/i18n/it/docusaurus-plugin-content-docs/current/installation/prerequisites.mdx +++ b/i18n/it/docusaurus-plugin-content-docs/current/installation/prerequisites.mdx @@ -19,7 +19,7 @@ Per installare SideStore ti serviranno: ## StosVPN -SideStore utilizza una VPN on-device che permette a sidestore di comunicare con dei servizi interni +SideStore utilizza una VPN on-device che permette a SideStore di comunicare con dei servizi interni 1. Scarica StosVPN dall'[Apple App Store](https://apps.apple.com/us/app/stosvpn/id6744003051). 2. Attiva la VPN. diff --git a/i18n/it/docusaurus-plugin-content-docs/current/release-notes.mdx b/i18n/it/docusaurus-plugin-content-docs/current/release-notes.mdx index 2cf60374..6c7d5e40 100644 --- a/i18n/it/docusaurus-plugin-content-docs/current/release-notes.mdx +++ b/i18n/it/docusaurus-plugin-content-docs/current/release-notes.mdx @@ -15,7 +15,7 @@ sidebar_position: 6 - Added support for importing/exporting your Apple ID's certificate for use with multiple devices, instructions to utilize this [here](https://github.com/SideStore/SideStore/pull/1008#issue-3138680291) - Adds url scheme/allow exporting certificate (to LiveContainer) - Fix issue where installing apps would get stuck around 75% -- Add option to resuse the main App ID profile for extensions instead of removing/registering them (only one app id/app) +- Add option to reuse the main App ID profile for extensions instead of removing/registering them (only one app id/app) - General type fixes and visual updates ### What's Changed: diff --git a/i18n/it/docusaurus-plugin-content-docs/current/troubleshooting/error-codes.mdx b/i18n/it/docusaurus-plugin-content-docs/current/troubleshooting/error-codes.mdx index c3ed4873..9ec60103 100644 --- a/i18n/it/docusaurus-plugin-content-docs/current/troubleshooting/error-codes.mdx +++ b/i18n/it/docusaurus-plugin-content-docs/current/troubleshooting/error-codes.mdx @@ -133,7 +133,7 @@ Questo errore può presentarsi per varie ragioni, sotto puoi trovarne alcune (no "vector too long" -Significa che Windwos Defender sta bloccando la tua richiesta. Potresti dover disattivare la Protezione in tempo reale su Windows per installare SideStore correttamente. +Significa che Windows Defender sta bloccando la tua richiesta. Potresti dover disattivare la Protezione in tempo reale su Windows per installare SideStore correttamente. #### (1999) Underlying Error @@ -206,7 +206,7 @@ Significa che iOS ha rifiutato l'app che stavi provando ad installare. Assicurat `AltServer.ServerError` -Significa che hai raggiunto il massimo numero di app sideloaded che puoi installare con un Account Sviluppatore Gratuito. Apple limita il numero di app in sideload che puoi avere con un account gratuito, per rimuovere questo limite devi acquistare un Account Sviluppatore a Pagamento su [developer.apple.com](https://developer.apple.com). +Significa che hai raggiunto il massimo numero di app in sideload che puoi installare con un Account Sviluppatore Gratuito. Apple limita il numero di app in sideload che puoi avere con un account gratuito, per rimuovere questo limite devi acquistare un Account Sviluppatore a Pagamento su [developer.apple.com](https://developer.apple.com). #### (2010) Your device must be running iOS 12.2 or later to install AltStore.