Merge pull request #106 from VernissageApp/merge/2.0.4
Merge version 2.0.4 into main
This commit is contained in:
commit
8d546096f8
|
@ -13,7 +13,7 @@ extension Client {
|
|||
sinceId: String? = nil,
|
||||
minId: String? = nil,
|
||||
limit: Int = 40,
|
||||
includeReblogs: Bool? = nil) async throws -> [Status] {
|
||||
includeReblogs: Bool? = nil) async throws -> Linkable<[Status]> {
|
||||
return try await pixelfedClient.getHomeTimeline(maxId: maxId, sinceId: sinceId, minId: minId, limit: limit, includeReblogs: includeReblogs)
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ extension Client {
|
|||
maxId: String? = nil,
|
||||
sinceId: String? = nil,
|
||||
minId: String? = nil,
|
||||
limit: Int = 40) async throws -> [Status] {
|
||||
limit: Int = 40) async throws -> Linkable<[Status]> {
|
||||
return try await pixelfedClient.getPublicTimeline(local: local,
|
||||
remote: remote,
|
||||
onlyMedia: true,
|
||||
|
@ -38,7 +38,7 @@ extension Client {
|
|||
maxId: String? = nil,
|
||||
sinceId: String? = nil,
|
||||
minId: String? = nil,
|
||||
limit: Int = 40) async throws -> [Status] {
|
||||
limit: Int = 40) async throws -> Linkable<[Status]> {
|
||||
return try await pixelfedClient.getTagTimeline(tag: tag,
|
||||
local: local,
|
||||
remote: remote,
|
||||
|
|
|
@ -64,7 +64,7 @@ class AccountDataHandler {
|
|||
}
|
||||
}
|
||||
|
||||
func update(lastSeenStatusId: String?, lastLoadedStatusId: String?, statuses: [Status]? = nil, applicationState: ApplicationState, modelContext: ModelContext) throws {
|
||||
func update(lastSeenStatusId: String?, lastLoadedStatusId: String?, statuses: Linkable<[Status]>? = nil, applicationState: ApplicationState, modelContext: ModelContext) throws {
|
||||
guard let accountId = applicationState.account?.id else {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -44,13 +44,13 @@ class ViewedStatusHandler {
|
|||
let statusId = status.id
|
||||
|
||||
var fetchDescriptor = FetchDescriptor<ViewedStatus>(
|
||||
// Here we are finding status which is other then checked status AND orginal status has been visible OR same reblogged by different user status has been visible.
|
||||
predicate: #Predicate { $0.pixelfedAccount?.id == accountId && $0.id != statusId && ($0.id == reblogId || $0.reblogId == reblogId) }
|
||||
// Here we are finding status which is older then checked status AND orginal status has been visible OR same reblogged by different user status has been visible.
|
||||
predicate: #Predicate { $0.pixelfedAccount?.id == accountId && $0.id < statusId && ($0.id == reblogId || $0.reblogId == reblogId) }
|
||||
)
|
||||
fetchDescriptor.fetchLimit = 1
|
||||
fetchDescriptor.includePendingChanges = true
|
||||
|
||||
guard let first = try modelContext.fetch(fetchDescriptor).first else {
|
||||
guard try modelContext.fetch(fetchDescriptor).first != nil else {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,371 +0,0 @@
|
|||
// MARK: Common strings.
|
||||
"global.title.contentWarning" = "Contenido sensible";
|
||||
"global.title.seePost" = "Ver publicación";
|
||||
"global.title.refresh" = "Actualizar";
|
||||
"global.title.momentsAgo" = "hace uno momento";
|
||||
"global.title.success" = "Éxito";
|
||||
"global.title.photoSaved" = "La foto se ha guardado.";
|
||||
"global.title.ok" = "Aceptar";
|
||||
"global.title.showMore" = "Mostrar más";
|
||||
"global.title.showLess" = "Mostrar menos";
|
||||
"global.title.close" = "Cerrar";
|
||||
"global.error.refreshingCredentialsTitle" = "Error al actualizar las credenciales.";
|
||||
"global.error.refreshingCredentialsSubtitle" = "Por favor, vuelve a iniciar sesión en Pixelfed.";
|
||||
|
||||
// MARK: Global errors.
|
||||
"global.error.unexpected" = "Error inesperado.";
|
||||
"global.error.statusesNotRetrieved" = "No se pudieron obtener los estados.";
|
||||
"global.error.errorDuringDownloadStatuses" = "Error durante la descarga de estados del servidor.";
|
||||
"global.error.errorDuringDownloadHashtag" = "Error durante la descarga de etiquetas del servidor.";
|
||||
"global.error.hashtagNotExists" = "La etiqueta no existe.";
|
||||
"global.error.errorDuringImageDownload" = "No se puede descargar la imagen.";
|
||||
"global.error.canceledImageDownload" = "La descarga de la imagen ha sido cancelada.";
|
||||
"global.error.errorDuringDataLoad" = "Error al cargar los datos.";
|
||||
"global.error.errorDuringUserRead" = "No se puede recuperar la cuenta de usuario.";
|
||||
"global.error.badUrlServer" = "URL incorrecta del servidor.";
|
||||
"global.error.accessTokenNotFound" = "Token de acceso no encontrado.";
|
||||
"global.error.errorDuringDownloadStatus" = "Error durante la descarga del estado del servidor.";
|
||||
"global.error.errorDuringPurchaseVerification" = "Fallo en la verificación de la compra.";
|
||||
|
||||
// MARK: Main view (main navigation bar).
|
||||
"mainview.tab.homeTimeline" = "Inicio";
|
||||
"mainview.tab.localTimeline" = "Local";
|
||||
"mainview.tab.federatedTimeline" = "Federado";
|
||||
"mainview.tab.trendingPhotos" = "Fotos";
|
||||
"mainview.tab.trendingTags" = "Etiquetas";
|
||||
"mainview.tab.trendingAccounts" = "Cuentas";
|
||||
"mainview.tab.userProfile" = "Perfil";
|
||||
"mainview.tab.notifications" = "Notificaciones";
|
||||
"mainview.tab.search" = "Buscar";
|
||||
"mainview.tab.trending" = "Tendencias";
|
||||
|
||||
// MARK: Main view (leading navigation bar).
|
||||
"mainview.menu.settings" = "Ajustes";
|
||||
|
||||
// MARK: Main view (error notifications).
|
||||
"mainview.error.switchAccounts" = "No se pueden cambiar las cuentas.";
|
||||
|
||||
// MARK: Home timeline.
|
||||
"home.title.allCaughtUp" = "Estás al día";
|
||||
"home.title.noPhotos" = "Desafortunadamente, no hay fotos aquí.";
|
||||
|
||||
// MARK: Statuses timeline (local/federated/favourite/bookmarks etc.).
|
||||
"statuses.navigationBar.localTimeline" = "Local";
|
||||
"statuses.navigationBar.federatedTimeline" = "Federado";
|
||||
"statuses.navigationBar.favourites" = "Favoritos";
|
||||
"statuses.navigationBar.bookmarks" = "Marcadores";
|
||||
"statuses.title.noPhotos" = "Desafortunadamente, no hay fotos aquí.";
|
||||
"statuses.title.tagFollowed" = "Estás siguiendo la etiqueta.";
|
||||
"statuses.title.tagUnfollowed" = "Se ha dejado de seguir la etiqueta.";
|
||||
"statuses.error.loadingStatusesFailed" = "Error al cargar los estados.";
|
||||
"statuses.error.tagFollowFailed" = "Error al seguir la etiqueta.";
|
||||
"statuses.error.tagUnfollowFailed" = "Error al dejar de seguir la etiqueta.";
|
||||
|
||||
// Mark: Search view.
|
||||
"search.navigationBar.title" = "Buscar";
|
||||
"search.title.placeholder" = "Buscar...";
|
||||
"search.title.usersWith" = "Usuarios con %@";
|
||||
"search.title.goToUser" = "Ir al usuario %@";
|
||||
"search.title.hashtagWith" = "Etiquetas con %@";
|
||||
"search.title.goToHashtag" = "Ir a la etiqueta %@";
|
||||
|
||||
// Mark: Trending statuses.
|
||||
"trendingStatuses.navigationBar.title" = "Fotos";
|
||||
"trendingStatuses.title.daily" = "Diario";
|
||||
"trendingStatuses.title.monthly" = "Mensual";
|
||||
"trendingStatuses.title.yearly" = "Anual";
|
||||
"trendingStatuses.error.loadingStatusesFailed" = "Error al cargar los estados.";
|
||||
"trendingStatuses.title.noPhotos" = "Desafortunadamente, no hay fotos aquí.";
|
||||
|
||||
// Mark: Trending tags.
|
||||
"trendingTags.navigationBar.title" = "Etiquetas";
|
||||
"trendingTags.title.noTags" = "Desafortunadamente, no hay etiquetas aquí.";
|
||||
"trendingTags.title.amountOfPosts" = "%d publicaciones";
|
||||
"trendingTags.error.loadingTagsFailed" = "Error al cargar las etiquetas.";
|
||||
|
||||
// Mark: Trending accounts.
|
||||
"trendingAccounts.navigationBar.title" = "Cuentas";
|
||||
"trendingAccounts.title.noAccounts" = "Desafortunadamente, aquí no hay nadie.";
|
||||
"trendingAccounts.error.loadingAccountsFailed" = "Error al cargar las cuentas.";
|
||||
|
||||
// Mark: User profile view.
|
||||
"userProfile.title.openInBrowser" = "Abrir en el navegador";
|
||||
"userProfile.title.share" = "Compartir";
|
||||
"userProfile.title.unmute" = "Quitar silencio";
|
||||
"userProfile.title.mute" = "Silenciar";
|
||||
"userProfile.title.unblock" = "Desbloquear";
|
||||
"userProfile.title.block" = "Bloquear";
|
||||
"userProfile.title.favourites" = "Favoritos";
|
||||
"userProfile.title.bookmarks" = "Marcadores";
|
||||
"userProfile.title.posts" = "Publicaciones";
|
||||
"userProfile.title.followers" = "Seguidores";
|
||||
"userProfile.title.following" = "Siguiendo";
|
||||
"userProfile.title.joined" = "Unido a %@";
|
||||
"userProfile.title.unfollow" = "Dejar de seguir";
|
||||
"userProfile.title.follow" = "Seguir";
|
||||
"userProfile.title.instance" = "Información de la instancia";
|
||||
"userProfile.title.blocks" = "Cuentas bloqueadas";
|
||||
"userProfile.title.mutes" = "Cuentas silenciadas";
|
||||
"userProfile.title.muted" = "Cuenta silenciada";
|
||||
"userProfile.title.unmuted" = "Cuenta sin silencio";
|
||||
"userProfile.title.blocked" = "Cuenta bloqueada";
|
||||
"userProfile.title.unblocked" = "Cuenta desbloqueada";
|
||||
"userProfile.title.report" = "Informar";
|
||||
"userProfile.title.followsYou" = "Te sigue";
|
||||
"userProfile.title.requestFollow" = "Solicitar seguir";
|
||||
"userProfile.title.cancelRequestFollow" = "Cancelar solicitud";
|
||||
"userProfile.title.followRequests" = "Solicitudes de seguimiento";
|
||||
"userProfile.title.privateProfileTitle" = "Este perfil es privado.";
|
||||
"userProfile.title.privateProfileSubtitle" = "Solo los seguidores aprobados pueden ver las fotos.";
|
||||
"userProfile.error.notExists" = "La cuenta no existe.";
|
||||
"userProfile.error.loadingAccountFailed" = "Error al descargar la cuenta del servidor.";
|
||||
"userProfile.error.muting" = "Error al silenciar/quitar silencio.";
|
||||
"userProfile.error.block" = "Error al bloquear/desbloquear.";
|
||||
"userProfile.error.relationship" = "Error en la acción de relación.";
|
||||
"userProfile.title.edit" = "Editar";
|
||||
"userProfile.title.muted" = "Silenciado";
|
||||
"userProfile.title.blocked" = "Bloqueado";
|
||||
|
||||
// Mark: Notifications view.
|
||||
"notifications.navigationBar.title" = "Notificaciones";
|
||||
"notifications.title.noNotifications" = "Desafortunadamente, aquí no hay nada.";
|
||||
"notifications.title.followedYou" = "te ha seguido";
|
||||
"notifications.title.mentionedYou" = "te ha mencionado";
|
||||
"notifications.title.boosted" = "ha compartido";
|
||||
"notifications.title.favourited" = "le ha gustado";
|
||||
"notifications.title.postedStatus" = "ha publicado un estado";
|
||||
"notifications.title.followRequest" = "solicitud de seguimiento";
|
||||
"notifications.title.poll" = "encuesta";
|
||||
"notifications.title.updatedStatus" = "estado actualizado";
|
||||
"notifications.title.signedUp" = "se ha registrado";
|
||||
"notifications.title.newReport" = "nuevo informe";
|
||||
"notifications.error.loadingNotificationsFailed" = "Error al cargar las notificaciones.";
|
||||
|
||||
// Mark: Compose view.
|
||||
"compose.navigationBar.title" = "Componer";
|
||||
"compose.title.everyone" = "Todos";
|
||||
"compose.title.unlisted" = "No listado";
|
||||
"compose.title.followers" = "Seguidores";
|
||||
"compose.title.attachPhotoFull" = "Adjunta una foto y escribe lo que piensas";
|
||||
"compose.title.attachPhotoMini" = "Escribe lo que piensas";
|
||||
"compose.title.publish" = "Publicar";
|
||||
"compose.title.cancel" = "Cancelar";
|
||||
"compose.title.writeContentWarning" = "Escribir aviso de contenido";
|
||||
"compose.title.commentsWillBeDisabled" = "Los comentarios estarán desactivados";
|
||||
"compose.title.statusPublished" = "Estado publicado";
|
||||
"compose.title.tryToUpload" = "Intentar subir";
|
||||
"compose.title.delete" = "Eliminar";
|
||||
"compose.title.edit" = "Editar";
|
||||
"compose.title.photos" = "Fototeca";
|
||||
"compose.title.camera" = "Hacer una foto";
|
||||
"compose.title.files" = "Explorar archivos";
|
||||
"compose.title.missingAltTexts" = "Textos ALT faltantes";
|
||||
"compose.title.missingAltTextsWarning" = "No todas las imágenes han sido descritas para personas con discapacidad visual. ¿Te gustaría enviar las fotos de todos modos?";
|
||||
"compose.error.loadingPhotosFailed" = "No se puede recuperar la imagen de la biblioteca.";
|
||||
"compose.error.postingPhotoFailed" = "Error al publicar la foto.";
|
||||
"compose.error.postingStatusFailed" = "Error al publicar el estado.";
|
||||
|
||||
// Mark: Photo editor view.
|
||||
"photoEdit.navigationBar.title" = "Detalles de la foto";
|
||||
"photoEdit.title.photo" = "Foto";
|
||||
"photoEdit.title.accessibility" = "Accesibilidad";
|
||||
"photoEdit.title.accessibilityDescription" = "Descripción para personas con discapacidad visual";
|
||||
"photoEdit.title.save" = "Guardar";
|
||||
"photoEdit.title.cancel" = "Cancelar";
|
||||
"photoEdit.error.updatePhotoFailed" = "Error al actualizar la foto.";
|
||||
|
||||
// Mark: Place selector view.
|
||||
"placeSelector.navigationBar.title" = "Lugares";
|
||||
"placeSelector.title.search" = "Buscar...";
|
||||
"placeSelector.title.buttonSearch" = "Buscar";
|
||||
"placeSelector.title.cancel" = "Cancelar";
|
||||
"placeSelector.error.loadingPlacesFailed" = "Error al cargar las notificaciones.";
|
||||
|
||||
// Mark: Settings view.
|
||||
"settings.navigationBar.title" = "Ajustes";
|
||||
"settings.title.close" = "Cerrar";
|
||||
"settings.title.version" = "Versión";
|
||||
"settings.title.accounts" = "Cuentas";
|
||||
"settings.title.newAccount" = "Nueva cuenta";
|
||||
"settings.title.accent" = "Acento";
|
||||
"settings.title.theme" = "Tema";
|
||||
"settings.title.system" = "Sistema";
|
||||
"settings.title.light" = "Claro";
|
||||
"settings.title.dark" = "Oscuro";
|
||||
"settings.title.avatar" = "Avatar";
|
||||
"settings.title.circle" = "Círculo";
|
||||
"settings.title.rounderRectangle" = "Rectángulo redondeado";
|
||||
"settings.title.other" = "Otros";
|
||||
"settings.title.thirdParty" = "Terceros";
|
||||
"settings.title.reportBug" = "Informar de un error";
|
||||
"settings.title.githubIssues" = "Problemas en Github";
|
||||
"settings.title.follow" = "Sígueme";
|
||||
"settings.title.support" = "Soporte";
|
||||
"settings.title.thankYouTitle" = "Gracias 💕";
|
||||
"settings.title.thankYouMessage" = "Gracias por tu compra. Tanto las compras grandes como las pequeñas nos ayudan a mantener nuestro sueño de proporcionar productos de la mejor calidad a nuestros clientes. Esperamos que estés disfrutando de Vernissage.";
|
||||
"settings.title.thankYouClose" = "Cerrar";
|
||||
"settings.title.haptics" = "Respuesta háptica";
|
||||
"settings.title.hapticsTabSelection" = "Selección de pestaña";
|
||||
"settings.title.hapticsButtonPress" = "Pulsación de botón";
|
||||
"settings.title.hapticsListRefresh" = "Actualizar lista";
|
||||
"settings.title.hapticsAnimationFinished" = "Animación finalizada";
|
||||
"settings.title.mediaSettings" = "Ajustes multimedia";
|
||||
"settings.title.alwaysShowSensitiveTitle" = "Mostrar siempre NSFW";
|
||||
"settings.title.alwaysShowSensitiveDescription" = "Mostrar siempre todos los medios NSFW (sensibles) sin advertencias";
|
||||
"settings.title.alwaysShowAltTitle" = "Mostrar texto alternativo";
|
||||
"settings.title.alwaysShowAltDescription" = "Mostrar el texto alternativo si está presente en la pantalla de detalles del estado";
|
||||
"settings.title.general" = "General";
|
||||
"settings.title.applicationIcon" = "Icono de la aplicación";
|
||||
"settings.title.followVernissage" = "Sígueme en Vernissage";
|
||||
"settings.title.mastodonAccount" = "Cuenta de Mastodon";
|
||||
"settings.title.pixelfedAccount" = "Cuenta de Pixelfed";
|
||||
"settings.title.openPage" = "Abrir";
|
||||
"settings.title.privacyPolicy" = "Política de privacidad";
|
||||
"settings.title.terms" = "Términos y condiciones";
|
||||
"settings.title.sourceCode" = "Código fuente";
|
||||
"settings.title.rate" = "Puntúa Vernissage";
|
||||
"settings.title.socials" = "Redes sociales";
|
||||
"settings.title.menuPosition" = "Posición del menú";
|
||||
"settings.title.topMenu" = "Barra de navegación";
|
||||
"settings.title.bottomRightMenu" = "Abajo a la derecha";
|
||||
"settings.title.bottomLeftMenu" = "Abajo a la izquierda";
|
||||
"settings.title.showAvatars" = "Mostrar avatares";
|
||||
"settings.title.showAvatarsOnTimeline" = "Los avatares se mostrarán en las cronologías";
|
||||
"settings.title.showFavourite" = "Mostrar favoritos";
|
||||
"settings.title.showFavouriteOnTimeline" = "Los favoritos se mostrarán en las cronologías";
|
||||
"settings.title.showAltText" = "Mostrar icono ALT";
|
||||
"settings.title.showAltTextOnTimeline" = "El icono ALT se mostrará en las cronologíasS";
|
||||
"settings.title.warnAboutMissingAltTitle" = "Advertir sobre el texto ALT faltante";
|
||||
"settings.title.warnAboutMissingAltDescription" = "Se mostrará una advertencia sobre los textos ALT faltantes antes de publicar una nueva entrada.";
|
||||
|
||||
// Mark: Signin view.
|
||||
"signin.navigationBar.title" = "Iniciar sesión en Pixelfed";
|
||||
"signin.title.serverAddress" = "Dirección del servidor";
|
||||
"signin.title.signIn" = "Iniciar sesión";
|
||||
"signin.title.enterServerAddress" = "Introducir la dirección del servidor";
|
||||
"signin.title.howToJoinLink" = "Cómo unirse a Pixelfed";
|
||||
"signin.title.chooseServer" = "O elige un servidor Pixelfed";
|
||||
"signin.title.amountOfUsers" = "%d usuarios";
|
||||
"signin.title.amountOStatuses" = "%d estados";
|
||||
"signin.error.communicationFailed" = "Error de comunicación con el servidor.";
|
||||
|
||||
// Mark: Status view.
|
||||
"status.navigationBar.title" = "Detalles";
|
||||
"status.title.uploaded" = "Subido";
|
||||
"status.title.via" = "a través de %@";
|
||||
"status.title.reboostedBy" = "Compartido por";
|
||||
"status.title.favouritedBy" = "Le ha gustado a";
|
||||
"status.title.openInBrowser" = "Abrir en el navegador";
|
||||
"status.title.shareStatus" = "Compartir estado";
|
||||
"status.title.yourStatus" = "Tu estado";
|
||||
"status.title.delete" = "Eliminar";
|
||||
"status.title.reboosted" = "Compartido";
|
||||
"status.title.unreboosted" = "No compartido";
|
||||
"status.title.favourited" = "Le ha gustado";
|
||||
"status.title.unfavourited" = "No le ha gustado";
|
||||
"status.title.bookmarked" = "Marcado";
|
||||
"status.title.unbookmarked" = "No marcado";
|
||||
"status.title.statusDeleted" = "Estado eliminado";
|
||||
"status.title.reboost" = "Compartir";
|
||||
"status.title.unreboost" = "No compartir";
|
||||
"status.title.favourite" = "Me gusta";
|
||||
"status.title.unfavourite" = "No me gusta";
|
||||
"status.title.bookmark" = "Marcar";
|
||||
"status.title.unbookmark" = "Desmarcar";
|
||||
"status.title.comment" = "Comentario";
|
||||
"status.title.report" = "Informar";
|
||||
"status.title.saveImage" = "Guardar imagen";
|
||||
"status.title.showMediaDescription" = "Mostrar descripción de medios";
|
||||
"status.title.mediaDescription" = "Descripción de medios";
|
||||
"status.title.shareImage" = "Compartir imagen";
|
||||
"status.title.altText" = "ALT";
|
||||
"status.error.loadingStatusFailed" = "Error al cargar el estado.";
|
||||
"status.error.notFound" = "El estado ya no existe.";
|
||||
"status.error.loadingCommentsFailed" = "No se pueden cargar los comentarios.";
|
||||
"status.error.reboostFailed" = "Error al compartir.";
|
||||
"status.error.favouriteFailed" = "Error al dar me gusta.";
|
||||
"status.error.bookmarkFailed" = "Error al marcar.";
|
||||
"status.error.deleteFailed" = "Error al eliminar.";
|
||||
|
||||
// Mark: Accounts view.
|
||||
"accounts.navigationBar.followers" = "Seguidores";
|
||||
"accounts.navigationBar.following" = "Siguiendo";
|
||||
"accounts.navigationBar.favouritedBy" = "Le ha gustado a";
|
||||
"accounts.navigationBar.reboostedBy" = "Compartido por";
|
||||
"accounts.navigationBar.blocked" = "Cuentas bloqueadas";
|
||||
"accounts.navigationBar.mutes" = "Cuentas silenciadas";
|
||||
"accounts.title.noAccounts" = "Desafortunadamente, aquí no hay nadie.";
|
||||
"accounts.error.loadingAccountsFailed" = "Error al cargar las cuentas.";
|
||||
|
||||
// Mark: Third party view.
|
||||
"thirdParty.navigationBar.title" = "Terceros";
|
||||
|
||||
// Mark: Widget view.
|
||||
"widget.title.photoDescription" = "Widget con fotos de Pixelfed.";
|
||||
"widget.title.qrCodeDescription" = "Widget con el código QR de tu perfil de Pixelfed.";
|
||||
|
||||
// Mark: In-app purchases.
|
||||
"purchase.donut.title" = "Rosquilla";
|
||||
"purchase.donut.description" = "Dame una rosquilla.";
|
||||
"purchase.coffee.title" = "Café";
|
||||
"purchase.coffee.description" = "Dame un café.";
|
||||
"purchase.cake.title" = "Café y pastel";
|
||||
"purchase.cake.description" = "Dame un café y un pastel.";
|
||||
|
||||
// Mark: Edit profile.
|
||||
"editProfile.navigationBar.title" = "Editar perfil";
|
||||
"editProfile.title.displayName" = "Nombre para mostrar";
|
||||
"editProfile.title.bio" = "Biografía";
|
||||
"editProfile.title.website" = "Sitio web";
|
||||
"editProfile.title.save" = "Guardar";
|
||||
"editProfile.title.accountSaved" = "Perfil actualizado.";
|
||||
"editProfile.title.photoInfo" = "La foto cambiada se mostrará en la aplicación y en el sitio web con un pequeño retraso.";
|
||||
"editProfile.title.privateAccount" = "Cuenta privada";
|
||||
"editProfile.title.privateAccountInfo" = "Cuando tu cuenta es privada, sólo las personas a las que apruebas pueden ver tus fotos y vídeos en Pixelfed. Tus seguidores existentes no se verán afectados.";
|
||||
"editProfile.error.saveAccountFailed" = "Error al guardar el perfil.";
|
||||
"editProfile.error.loadingAvatarFailed" = "Error al cargar el avatar.";
|
||||
"editProfile.error.noProfileData" = "No se pueden mostrar los datos del perfil.";
|
||||
"editProfile.error.loadingAccountFailed" = "Error al cargar los datos de la cuenta desde el servidor.";
|
||||
|
||||
// Mark: Instance information.
|
||||
"instance.navigationBar.title" = "Instancia";
|
||||
"instance.title.instanceInfo" = "Información de la instancia";
|
||||
"instance.title.name" = "Nombre";
|
||||
"instance.title.address" = "Dirección";
|
||||
"instance.title.email" = "Correo electrónico";
|
||||
"instance.title.version" = "Versión";
|
||||
"instance.title.users" = "Usuarios";
|
||||
"instance.title.posts" = "Publicaciones";
|
||||
"instance.title.domains" = "Dominios";
|
||||
"instance.title.registrations" = "Registros";
|
||||
"instance.title.approvalRequired" = "Se requiere aprobación";
|
||||
"instance.title.rules" = "Reglas de la instancia";
|
||||
"instance.title.contact" = "Contacto";
|
||||
"instance.title.pixelfedAccount" = "Cuenta de Pixelfed";
|
||||
"instance.error.noInstanceData" = "No se pueden mostrar los datos de la instancia.";
|
||||
"instance.error.loadingDataFailed" = "Error al cargar los datos de la instancia desde el servidor.";
|
||||
|
||||
// Mark: Report screen.
|
||||
"report.navigationBar.title" = "Informe";
|
||||
"report.title.close" = "Cerrar";
|
||||
"report.title.send" = "Enviar";
|
||||
"report.title.userReported" = "El usuario ha sido denunciado";
|
||||
"report.title.postReported" = "La publicación ha sido denunciada";
|
||||
"report.title.reportType" = "Tipo de abuso";
|
||||
"report.title.spam" = "No deseado (spam)";
|
||||
"report.title.sensitive" = "Desnudos o actividad sexual";
|
||||
"report.title.abusive" = "Discurso o símbolos de odio";
|
||||
"report.title.underage" = "Cuenta de menor de edad";
|
||||
"report.title.violence" = "Violencia u organizaciones peligrosas";
|
||||
"report.title.copyright" = "Infracción de derechos de autor";
|
||||
"report.title.impersonation" = "Suplantación de identidad";
|
||||
"report.title.scam" = "Acoso u hostigamiento";
|
||||
"report.title.terrorism" = "Terrorismo";
|
||||
"report.error.notReported" = "Error al enviar el informe.";
|
||||
|
||||
// Mark: Following requests.
|
||||
"followingRequests.navigationBar.title" = "Solicitudes de seguimiento";
|
||||
"followingRequests.title.approve" = "Aprobar";
|
||||
"followingRequests.title.reject" = "Rechazar";
|
||||
"followingRequests.error.approve" = "Error al aprobar la solicitud.";
|
||||
"followingRequests.error.reject" = "Error al rechazar la solicitud.";
|
|
@ -8,7 +8,7 @@ import Foundation
|
|||
import RegexBuilder
|
||||
|
||||
/// Link returned in header for paging feature/
|
||||
public struct Link {
|
||||
public struct Link: Codable {
|
||||
|
||||
/// Raw value of header link.
|
||||
public let rawLink: String
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import Foundation
|
||||
|
||||
/// Some of endpoint returns JSON data and additional information in header, like link for paging functionality.
|
||||
public struct Linkable<T> where T: Codable {
|
||||
public struct Linkable<T> : Codable where T: Codable {
|
||||
|
||||
/// Data retunred in HTTP reponse body (mostly JSON data/entities).
|
||||
public let data: T
|
||||
|
@ -20,3 +20,29 @@ public struct Linkable<T> where T: Codable {
|
|||
self.link = link
|
||||
}
|
||||
}
|
||||
|
||||
public extension Linkable<[Status]> {
|
||||
func getMinId() -> String? {
|
||||
if let link = self.link {
|
||||
return link.minId
|
||||
}
|
||||
|
||||
if let firstItemId = self.data.first?.id {
|
||||
return firstItemId
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getMaxId() -> String? {
|
||||
if let link = self.link {
|
||||
return link.maxId
|
||||
}
|
||||
|
||||
if let lastItemId = self.data.last?.id {
|
||||
return lastItemId
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,12 @@
|
|||
"global.error.notSuccessResponse" : {
|
||||
"comment" : "It's error returned from remote server. Request URL: '(response.url?.string ?? \"unknown\")'.",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Serverantwort: %@."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -39,6 +45,12 @@
|
|||
"global.error.unknownError" : {
|
||||
"comment" : "Response doesn't contains any information about request status.",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Unbekannter Fehler."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -74,6 +86,12 @@
|
|||
"report.error.duplicate" : {
|
||||
"comment" : "The report has already been sent.",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Der Bericht wurde bereits gesendet."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -109,6 +127,12 @@
|
|||
"report.error.invalidObject" : {
|
||||
"comment" : "Invalid object type.",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Ungültiges Objekt."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -144,6 +168,12 @@
|
|||
"report.error.invalidObjectId" : {
|
||||
"comment" : "Incorrect object Id.",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Fehlerhafte ID."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -179,6 +209,12 @@
|
|||
"report.error.invalidParameters" : {
|
||||
"comment" : "Invalid report parameters.",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Ungültige Parameter."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -214,6 +250,12 @@
|
|||
"report.error.invalidType" : {
|
||||
"comment" : "Invalid report type.",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Ungültiger Berichtstyp."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -249,6 +291,12 @@
|
|||
"report.error.noSelfReports" : {
|
||||
"comment" : "Self-reporting is not allowed.",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Du darfst Dich nicht selbst melden."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
|
|
@ -13,7 +13,7 @@ public extension PixelfedClientAuthenticated {
|
|||
minId: EntityId? = nil,
|
||||
limit: Int? = nil,
|
||||
includeReblogs: Bool? = nil,
|
||||
timeoutInterval: Double? = nil) async throws -> [Status] {
|
||||
timeoutInterval: Double? = nil) async throws -> Linkable<[Status]> {
|
||||
|
||||
let request = try Self.request(
|
||||
for: baseURL,
|
||||
|
@ -22,7 +22,7 @@ public extension PixelfedClientAuthenticated {
|
|||
timeoutInterval: timeoutInterval
|
||||
)
|
||||
|
||||
return try await downloadJson([Status].self, request: request)
|
||||
return try await downloadJsonWithLink([Status].self, request: request)
|
||||
}
|
||||
|
||||
func getPublicTimeline(local: Bool? = nil,
|
||||
|
@ -31,7 +31,7 @@ public extension PixelfedClientAuthenticated {
|
|||
maxId: EntityId? = nil,
|
||||
sinceId: EntityId? = nil,
|
||||
minId: EntityId? = nil,
|
||||
limit: Limit? = nil) async throws -> [Status] {
|
||||
limit: Limit? = nil) async throws -> Linkable<[Status]> {
|
||||
|
||||
let request = try Self.request(
|
||||
for: baseURL,
|
||||
|
@ -39,7 +39,7 @@ public extension PixelfedClientAuthenticated {
|
|||
withBearerToken: token
|
||||
)
|
||||
|
||||
return try await downloadJson([Status].self, request: request)
|
||||
return try await downloadJsonWithLink([Status].self, request: request)
|
||||
}
|
||||
|
||||
func getTagTimeline(tag: String,
|
||||
|
@ -49,7 +49,7 @@ public extension PixelfedClientAuthenticated {
|
|||
maxId: EntityId? = nil,
|
||||
sinceId: EntityId? = nil,
|
||||
minId: EntityId? = nil,
|
||||
limit: Int? = nil) async throws -> [Status] {
|
||||
limit: Int? = nil) async throws -> Linkable<[Status]> {
|
||||
|
||||
let request = try Self.request(
|
||||
for: baseURL,
|
||||
|
@ -57,7 +57,7 @@ public extension PixelfedClientAuthenticated {
|
|||
withBearerToken: token
|
||||
)
|
||||
|
||||
return try await downloadJson([Status].self, request: request)
|
||||
return try await downloadJsonWithLink([Status].self, request: request)
|
||||
}
|
||||
|
||||
func setMarkers(_ markers: [Pixelfed.Markers.Timeline: EntityId]) async throws -> Markers {
|
||||
|
|
|
@ -2,10 +2,47 @@
|
|||
"sourceLanguage" : "en",
|
||||
"strings" : {
|
||||
"" : {
|
||||
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ""
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ""
|
||||
}
|
||||
},
|
||||
"eu" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ""
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ""
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"global.error.downloadingImageFailed" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Das Herunterladen des Bildes in den Cache ist fehlgeschlagen."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -18,6 +55,18 @@
|
|||
"value" : "Error al descargar la imagen en la caché."
|
||||
}
|
||||
},
|
||||
"eu" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Ezin izan da irudia cachean deskargatu."
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Le téléchargement de l'image dans le cache a échoué."
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -25,41 +74,6 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"global.error.unexpected" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Unexpected error."
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Error inesperado."
|
||||
}
|
||||
},
|
||||
"eu" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Espero ez zen errorea."
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Erreur inattendue."
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Wystąpił nieoczekiwany błąd."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"version" : "1.0"
|
||||
|
|
|
@ -957,6 +957,7 @@
|
|||
eu,
|
||||
fr,
|
||||
es,
|
||||
de,
|
||||
);
|
||||
mainGroup = F88C245F295C37B80006098B;
|
||||
packageReferences = (
|
||||
|
@ -1209,7 +1210,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.0.0;
|
||||
MARKETING_VERSION = 2.0.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage.widget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
@ -1243,7 +1244,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.0.0;
|
||||
MARKETING_VERSION = 2.0.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage.widget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
@ -1276,7 +1277,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.0.0;
|
||||
MARKETING_VERSION = 2.0.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage.share;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
@ -1308,7 +1309,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.0.0;
|
||||
MARKETING_VERSION = 2.0.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage.share;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
@ -1474,7 +1475,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.0.0;
|
||||
MARKETING_VERSION = 2.0.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -1517,7 +1518,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.0.0;
|
||||
MARKETING_VERSION = 2.0.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = dev.mczachurski.vernissage;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
|
|
|
@ -77,8 +77,8 @@
|
|||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/kean/Nuke",
|
||||
"state" : {
|
||||
"revision" : "3f666f120b63ea7de57d42e9a7c9b47f8e7a290b",
|
||||
"version" : "12.1.6"
|
||||
"revision" : "1694798e876113d44f6ec6ead965d7286695981d",
|
||||
"version" : "12.2.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -20,7 +20,7 @@ public class HomeTimelineService {
|
|||
public static let shared = HomeTimelineService()
|
||||
private init() { }
|
||||
|
||||
private let maximumAmountOfDownloadedStatuses = 80
|
||||
private let maximumAmountOfDownloadedStatuses = 40
|
||||
private let imagePrefetcher = ImagePrefetcher(destination: .diskCache)
|
||||
private let semaphore = AsyncSemaphore(value: 1)
|
||||
|
||||
|
@ -43,27 +43,49 @@ public class HomeTimelineService {
|
|||
|
||||
let client = PixelfedClient(baseURL: accountData.serverUrl).getAuthenticated(token: accessToken)
|
||||
var statuses: [Status] = []
|
||||
var newestStatusId = lastSeenStatusId
|
||||
var latestStatusId: String? = nil
|
||||
var breakProcesssing = false;
|
||||
|
||||
// There can be more then 80 newest statuses, that's why we have to sometimes send more then one request.
|
||||
// There can be more then 40 newest statuses, that's why we have to sometimes send more then one request.
|
||||
while true {
|
||||
do {
|
||||
let downloadedStatuses = try await client.getHomeTimeline(minId: newestStatusId,
|
||||
// Download statuses from the top or the list.
|
||||
let downloadedStatuses = try await client.getHomeTimeline(maxId: latestStatusId,
|
||||
limit: self.maximumAmountOfDownloadedStatuses,
|
||||
includeReblogs: includeReblogs)
|
||||
|
||||
guard let firstStatus = downloadedStatuses.first else {
|
||||
// Iterate througt the list until we go to already visible status by the user.
|
||||
var temporaryList: [Status] = []
|
||||
for downloadedStatus in downloadedStatuses.data {
|
||||
guard downloadedStatus.id != lastSeenStatusId else {
|
||||
breakProcesssing = true
|
||||
break
|
||||
}
|
||||
|
||||
temporaryList.append(downloadedStatus)
|
||||
}
|
||||
|
||||
// Remove from the list duplicated statuses.
|
||||
let visibleStatuses = self.getVisibleStatuses(accountId: accountData.id,
|
||||
statuses: downloadedStatuses,
|
||||
statuses: temporaryList,
|
||||
hideStatusesWithoutAlt: hideStatusesWithoutAlt,
|
||||
modelContext: modelContext)
|
||||
|
||||
// Add statuses to the list.
|
||||
statuses.append(contentsOf: visibleStatuses)
|
||||
|
||||
newestStatusId = firstStatus.id
|
||||
// Break when we go to the already visible status.
|
||||
if breakProcesssing {
|
||||
break
|
||||
}
|
||||
|
||||
// When we discovered more then 100 statuses we can break.
|
||||
if statuses.count > 100 {
|
||||
break
|
||||
}
|
||||
|
||||
// Set status Id which should be used to download next portion of the statuses.
|
||||
latestStatusId = downloadedStatuses.getMaxId()
|
||||
} catch {
|
||||
ErrorService.shared.handle(error, message: "global.error.errorDuringDownloadingNewStatuses")
|
||||
break
|
||||
|
@ -80,9 +102,10 @@ public class HomeTimelineService {
|
|||
public func getVisibleStatuses(accountId: String, statuses: [Status], hideStatusesWithoutAlt: Bool, modelContext: ModelContext) -> [Status] {
|
||||
// We have to include in the counter only statuses with images.
|
||||
let statusesWithImagesOnly = statuses.getStatusesWithImagesOnly()
|
||||
let statusesFromOldestToNewest = statusesWithImagesOnly.reversed()
|
||||
var visibleStatuses: [Status] = []
|
||||
|
||||
for status in statusesWithImagesOnly {
|
||||
for status in statusesFromOldestToNewest {
|
||||
|
||||
// We have to hide statuses without ALT text.
|
||||
if hideStatusesWithoutAlt && status.statusContainsAltText() == false {
|
||||
|
@ -112,7 +135,8 @@ public class HomeTimelineService {
|
|||
visibleStatuses.append(status)
|
||||
}
|
||||
|
||||
return visibleStatuses
|
||||
// Return statuses from newest to oldest.
|
||||
return visibleStatuses.reversed()
|
||||
}
|
||||
|
||||
private func hasBeenAlreadyOnTimeline(accountId: String, status: Status, modelContext: ModelContext) -> Bool {
|
||||
|
|
|
@ -27,7 +27,7 @@ struct HomeTimelineView: View {
|
|||
@State private var opacity = 0.0
|
||||
@State private var offset = -50.0
|
||||
|
||||
private let defaultLimit = 80
|
||||
private let defaultLimit = 40
|
||||
private let imagePrefetcher = ImagePrefetcher(destination: .diskCache)
|
||||
private let timelineDoubleTapTip = TimelineDoubleTapTip()
|
||||
|
||||
|
@ -143,8 +143,14 @@ struct HomeTimelineView: View {
|
|||
HStack {
|
||||
Image(systemName: "arrow.up")
|
||||
.fontWeight(.light)
|
||||
|
||||
if self.applicationState.amountOfNewStatuses < 100 {
|
||||
Text("\(self.applicationState.amountOfNewStatuses)")
|
||||
.fontWeight(.semibold)
|
||||
} else {
|
||||
Text("+99")
|
||||
.fontWeight(.semibold)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 12)
|
||||
.padding(.horizontal, 18)
|
||||
|
@ -183,28 +189,28 @@ struct HomeTimelineView: View {
|
|||
// Download statuses from API (which are older then last visible status).
|
||||
let statuses = try await self.loadFromCacheOrApi(timelineCache: accountData.timelineCache)
|
||||
|
||||
if statuses.isEmpty {
|
||||
if statuses.data.isEmpty {
|
||||
self.allItemsLoaded = true
|
||||
return
|
||||
}
|
||||
|
||||
// Remember last status id returned by API.
|
||||
self.lastStatusId = statuses.last?.id
|
||||
self.lastStatusId = statuses.getMaxId()
|
||||
|
||||
// Get only visible statuses.
|
||||
let visibleStatuses = HomeTimelineService.shared.getVisibleStatuses(accountId: accountId,
|
||||
statuses: statuses,
|
||||
statuses: statuses.data,
|
||||
hideStatusesWithoutAlt: self.applicationState.hideStatusesWithoutAlt,
|
||||
modelContext: modelContext)
|
||||
|
||||
// Remeber first status returned by API in user context (when it's newer then remembered).
|
||||
try AccountDataHandler.shared.update(lastSeenStatusId: nil,
|
||||
lastLoadedStatusId: statuses.first?.id,
|
||||
lastLoadedStatusId: statuses.getMinId(),
|
||||
applicationState: self.applicationState,
|
||||
modelContext: modelContext)
|
||||
|
||||
// Append statuses to viewed.
|
||||
try ViewedStatusHandler.shared.append(contentsOf: statuses, accountId: accountId, modelContext: modelContext)
|
||||
try ViewedStatusHandler.shared.append(contentsOf: statuses.data, accountId: accountId, modelContext: modelContext)
|
||||
|
||||
// Map to view models.
|
||||
let statusModels = visibleStatuses.map({ StatusModel(status: $0) })
|
||||
|
@ -222,24 +228,24 @@ struct HomeTimelineView: View {
|
|||
// Download statuses from API.
|
||||
let statuses = try await self.loadFromApi(maxId: lastStatusId)
|
||||
|
||||
if statuses.isEmpty {
|
||||
if statuses.data.isEmpty {
|
||||
self.allItemsLoaded = true
|
||||
return
|
||||
}
|
||||
|
||||
// Now we have new last status.
|
||||
if let lastStatusId = statuses.last?.id {
|
||||
if let lastStatusId = statuses.getMaxId() {
|
||||
self.lastStatusId = lastStatusId
|
||||
}
|
||||
|
||||
// Get only visible statuses.
|
||||
let visibleStatuses = HomeTimelineService.shared.getVisibleStatuses(accountId: accountId,
|
||||
statuses: statuses,
|
||||
statuses: statuses.data,
|
||||
hideStatusesWithoutAlt: self.applicationState.hideStatusesWithoutAlt,
|
||||
modelContext: modelContext)
|
||||
|
||||
// Append statuses to viewed.
|
||||
try ViewedStatusHandler.shared.append(contentsOf: statuses, accountId: accountId, modelContext: modelContext)
|
||||
try ViewedStatusHandler.shared.append(contentsOf: statuses.data, accountId: accountId, modelContext: modelContext)
|
||||
|
||||
// Map to view models.
|
||||
let statusModels = visibleStatuses.map({ StatusModel(status: $0) })
|
||||
|
@ -260,29 +266,29 @@ struct HomeTimelineView: View {
|
|||
// Download statuses from API.
|
||||
let statuses = try await self.loadFromApi()
|
||||
|
||||
if statuses.isEmpty {
|
||||
if statuses.data.isEmpty {
|
||||
self.allItemsLoaded = true
|
||||
return
|
||||
}
|
||||
|
||||
// Remember last status id returned by API.
|
||||
self.lastStatusId = statuses.last?.id
|
||||
self.lastStatusId = statuses.getMaxId()
|
||||
|
||||
// Get only visible statuses.
|
||||
let visibleStatuses = HomeTimelineService.shared.getVisibleStatuses(accountId: accountId,
|
||||
statuses: statuses,
|
||||
statuses: statuses.data,
|
||||
hideStatusesWithoutAlt: self.applicationState.hideStatusesWithoutAlt,
|
||||
modelContext: modelContext)
|
||||
|
||||
// Remeber first status returned by API in user context (when it's newer then remembered).
|
||||
try AccountDataHandler.shared.update(lastSeenStatusId: self.statusViewModels.first?.id,
|
||||
lastLoadedStatusId: statuses.first?.id,
|
||||
lastLoadedStatusId: statuses.getMinId(),
|
||||
statuses: statuses,
|
||||
applicationState: self.applicationState,
|
||||
modelContext: modelContext)
|
||||
|
||||
// Append statuses to viewed.
|
||||
try ViewedStatusHandler.shared.append(contentsOf: statuses, accountId: accountId, modelContext: modelContext)
|
||||
try ViewedStatusHandler.shared.append(contentsOf: statuses.data, accountId: accountId, modelContext: modelContext)
|
||||
|
||||
// Map to view models.
|
||||
let statusModels = visibleStatuses.map({ StatusModel(status: $0) })
|
||||
|
@ -297,24 +303,22 @@ struct HomeTimelineView: View {
|
|||
self.applicationState.amountOfNewStatuses = 0
|
||||
}
|
||||
|
||||
private func loadFromCacheOrApi(timelineCache: String?) async throws -> [Status] {
|
||||
if let timelineCache, let timelineCacheData = timelineCache.data(using: .utf8) {
|
||||
let statusesFromCache = try? JSONDecoder().decode([Status].self, from: timelineCacheData)
|
||||
if let statusesFromCache {
|
||||
private func loadFromCacheOrApi(timelineCache: String?) async throws -> Linkable<[Status]> {
|
||||
if let timelineCache, let timelineCacheData = timelineCache.data(using: .utf8),
|
||||
let statusesFromCache = try? JSONDecoder().decode(Linkable<[Status]>.self, from: timelineCacheData) {
|
||||
return statusesFromCache
|
||||
}
|
||||
}
|
||||
|
||||
return try await self.loadFromApi()
|
||||
}
|
||||
|
||||
private func loadFromApi(maxId: String? = nil, sinceId: String? = nil, minId: String? = nil) async throws -> [Status] {
|
||||
private func loadFromApi(maxId: String? = nil, sinceId: String? = nil, minId: String? = nil) async throws -> Linkable<[Status]> {
|
||||
return try await self.client.publicTimeline?.getHomeTimeline(
|
||||
maxId: maxId,
|
||||
sinceId: sinceId,
|
||||
minId: minId,
|
||||
limit: self.defaultLimit,
|
||||
includeReblogs: self.applicationState.showReboostedStatuses) ?? []
|
||||
includeReblogs: self.applicationState.showReboostedStatuses) ?? Linkable(data: [])
|
||||
}
|
||||
|
||||
private func calculateOffset() {
|
||||
|
|
|
@ -61,7 +61,7 @@ struct StatusesView: View {
|
|||
@State private var containerWidth: Double = UIDevice.isIPad ? UIScreen.main.bounds.width / 3 : UIScreen.main.bounds.width
|
||||
@State private var containerHeight: Double = UIDevice.isIPad ? UIScreen.main.bounds.height / 3 : UIScreen.main.bounds.height
|
||||
|
||||
private let defaultLimit = 80
|
||||
private let defaultLimit = 40
|
||||
private let imagePrefetcher = ImagePrefetcher(destination: .diskCache)
|
||||
|
||||
var body: some View {
|
||||
|
@ -182,29 +182,29 @@ struct StatusesView: View {
|
|||
|
||||
let statuses = try await self.loadFromApi()
|
||||
|
||||
if statuses.isEmpty {
|
||||
if statuses.data.isEmpty {
|
||||
self.allItemsLoaded = true
|
||||
return
|
||||
}
|
||||
|
||||
// Remember last status id returned by API.
|
||||
self.lastStatusId = statuses.last?.id
|
||||
self.lastStatusId = statuses.getMaxId()
|
||||
|
||||
// Get only visible statuses.
|
||||
let visibleStatuses = HomeTimelineService.shared.getVisibleStatuses(accountId: accountId,
|
||||
statuses: statuses,
|
||||
statuses: statuses.data,
|
||||
hideStatusesWithoutAlt: self.applicationState.hideStatusesWithoutAlt,
|
||||
modelContext: modelContext)
|
||||
|
||||
if self.listType == .home {
|
||||
// Remeber first status returned by API in user context (when it's newer then remembered).
|
||||
try AccountDataHandler.shared.update(lastSeenStatusId: nil,
|
||||
lastLoadedStatusId: statuses.first?.id,
|
||||
lastLoadedStatusId: statuses.getMinId(),
|
||||
applicationState: self.applicationState,
|
||||
modelContext: modelContext)
|
||||
|
||||
// Append statuses to viewed.
|
||||
try ViewedStatusHandler.shared.append(contentsOf: statuses, accountId: accountId, modelContext: modelContext)
|
||||
try ViewedStatusHandler.shared.append(contentsOf: statuses.data, accountId: accountId, modelContext: modelContext)
|
||||
}
|
||||
|
||||
// Map to view models.
|
||||
|
@ -221,25 +221,25 @@ struct StatusesView: View {
|
|||
if let lastStatusId = self.lastStatusId, let accountId = self.applicationState.account?.id {
|
||||
let statuses = try await self.loadFromApi(maxId: lastStatusId)
|
||||
|
||||
if statuses.isEmpty {
|
||||
if statuses.data.isEmpty {
|
||||
self.allItemsLoaded = true
|
||||
return
|
||||
}
|
||||
|
||||
// Now we have new last status.
|
||||
if let lastStatusId = statuses.last?.id {
|
||||
if let lastStatusId = statuses.getMaxId() {
|
||||
self.lastStatusId = lastStatusId
|
||||
}
|
||||
|
||||
// Get only visible statuses.
|
||||
let visibleStatuses = HomeTimelineService.shared.getVisibleStatuses(accountId: accountId,
|
||||
statuses: statuses,
|
||||
statuses: statuses.data,
|
||||
hideStatusesWithoutAlt: self.applicationState.hideStatusesWithoutAlt,
|
||||
modelContext: modelContext)
|
||||
|
||||
if self.listType == .home {
|
||||
// Append statuses to viewed.
|
||||
try ViewedStatusHandler.shared.append(contentsOf: statuses, accountId: accountId, modelContext: modelContext)
|
||||
try ViewedStatusHandler.shared.append(contentsOf: statuses.data, accountId: accountId, modelContext: modelContext)
|
||||
}
|
||||
|
||||
// Map to view models.
|
||||
|
@ -260,29 +260,29 @@ struct StatusesView: View {
|
|||
|
||||
let statuses = try await self.loadFromApi()
|
||||
|
||||
if statuses.isEmpty {
|
||||
if statuses.data.isEmpty {
|
||||
self.allItemsLoaded = true
|
||||
return
|
||||
}
|
||||
|
||||
// Remember last status id returned by API.
|
||||
self.lastStatusId = statuses.last?.id
|
||||
self.lastStatusId = statuses.getMaxId()
|
||||
|
||||
// Get only visible statuses.
|
||||
let visibleStatuses = HomeTimelineService.shared.getVisibleStatuses(accountId: accountId,
|
||||
statuses: statuses,
|
||||
statuses: statuses.data,
|
||||
hideStatusesWithoutAlt: self.applicationState.hideStatusesWithoutAlt,
|
||||
modelContext: modelContext)
|
||||
|
||||
if self.listType == .home {
|
||||
// Remeber first status returned by API in user context (when it's newer then remembered).
|
||||
try AccountDataHandler.shared.update(lastSeenStatusId: self.statusViewModels.first?.id,
|
||||
lastLoadedStatusId: statuses.first?.id,
|
||||
lastLoadedStatusId: statuses.getMinId(),
|
||||
applicationState: self.applicationState,
|
||||
modelContext: modelContext)
|
||||
|
||||
// Append statuses to viewed.
|
||||
try ViewedStatusHandler.shared.append(contentsOf: statuses, accountId: accountId, modelContext: modelContext)
|
||||
try ViewedStatusHandler.shared.append(contentsOf: statuses.data, accountId: accountId, modelContext: modelContext)
|
||||
}
|
||||
|
||||
// Map to view models.
|
||||
|
@ -296,7 +296,7 @@ struct StatusesView: View {
|
|||
self.statusViewModels = statusModels
|
||||
}
|
||||
|
||||
private func loadFromApi(maxId: String? = nil, sinceId: String? = nil, minId: String? = nil) async throws -> [Status] {
|
||||
private func loadFromApi(maxId: String? = nil, sinceId: String? = nil, minId: String? = nil) async throws -> Linkable<[Status]> {
|
||||
switch self.listType {
|
||||
case .home:
|
||||
return try await self.client.publicTimeline?.getHomeTimeline(
|
||||
|
@ -304,40 +304,44 @@ struct StatusesView: View {
|
|||
sinceId: sinceId,
|
||||
minId: minId,
|
||||
limit: self.defaultLimit,
|
||||
includeReblogs: self.applicationState.showReboostedStatuses) ?? []
|
||||
includeReblogs: self.applicationState.showReboostedStatuses) ?? Linkable(data: [])
|
||||
case .local:
|
||||
return try await self.client.publicTimeline?.getStatuses(
|
||||
local: true,
|
||||
maxId: maxId,
|
||||
sinceId: sinceId,
|
||||
minId: minId,
|
||||
limit: self.defaultLimit) ?? []
|
||||
limit: self.defaultLimit) ?? Linkable(data: [])
|
||||
case .federated:
|
||||
return try await self.client.publicTimeline?.getStatuses(
|
||||
remote: true,
|
||||
maxId: maxId,
|
||||
sinceId: sinceId,
|
||||
minId: minId,
|
||||
limit: self.defaultLimit) ?? []
|
||||
limit: self.defaultLimit) ?? Linkable(data: [])
|
||||
case .favourites:
|
||||
return try await self.client.accounts?.favourites(
|
||||
let favourites = try await self.client.accounts?.favourites(
|
||||
maxId: maxId,
|
||||
sinceId: sinceId,
|
||||
minId: minId,
|
||||
limit: self.defaultLimit) ?? []
|
||||
|
||||
return Linkable(data: favourites)
|
||||
case .bookmarks:
|
||||
return try await self.client.accounts?.bookmarks(
|
||||
let bookmarks = try await self.client.accounts?.bookmarks(
|
||||
maxId: maxId,
|
||||
sinceId: sinceId,
|
||||
minId: minId,
|
||||
limit: self.defaultLimit) ?? []
|
||||
|
||||
return Linkable(data: bookmarks)
|
||||
case .hashtag(let tag):
|
||||
let hashtagsFromApi = try await self.client.search?.search(query: tag, resultsType: .hashtags)
|
||||
guard let hashtagsFromApi = hashtagsFromApi, hashtagsFromApi.hashtags.isEmpty == false else {
|
||||
ToastrService.shared.showError(title: LocalizedStringResource("global.error.hashtagNotExists"), imageSystemName: "exclamationmark.octagon")
|
||||
dismiss()
|
||||
|
||||
return []
|
||||
return Linkable(data: [])
|
||||
}
|
||||
|
||||
return try await self.client.publicTimeline?.getTagStatuses(
|
||||
|
@ -345,7 +349,7 @@ struct StatusesView: View {
|
|||
maxId: maxId,
|
||||
sinceId: sinceId,
|
||||
minId: minId,
|
||||
limit: self.defaultLimit) ?? []
|
||||
limit: self.defaultLimit) ?? Linkable(data: [])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ struct ImagesGrid: View {
|
|||
do {
|
||||
let statusesFromApi = try await self.loadStatuses()
|
||||
|
||||
let statusesWithImages = statusesFromApi.getStatusesWithImagesOnly()
|
||||
let statusesWithImages = statusesFromApi.data.getStatusesWithImagesOnly()
|
||||
|
||||
let photoUrls = self.getPhotoUrls(statuses: statusesWithImages)
|
||||
self.prefetch(photoUrls: photoUrls)
|
||||
|
@ -119,15 +119,21 @@ struct ImagesGrid: View {
|
|||
}
|
||||
}
|
||||
|
||||
private func loadStatuses() async throws -> [Status] {
|
||||
private func loadStatuses() async throws -> Linkable<[Status]> {
|
||||
switch self.gridType {
|
||||
case .hashtag(let name):
|
||||
return try await self.client.publicTimeline?.getTagStatuses(
|
||||
tag: name,
|
||||
local: true,
|
||||
limit: 10) ?? []
|
||||
limit: 10) ?? Linkable(data: [])
|
||||
case .account(let accountId, _, _):
|
||||
return try await self.client.accounts?.statuses(createdBy: accountId, onlyMedia: true, limit: 10) ?? []
|
||||
let accountStatuses = try await self.client.accounts?.statuses(
|
||||
createdBy: accountId,
|
||||
onlyMedia: true,
|
||||
limit: 10
|
||||
) ?? []
|
||||
|
||||
return Linkable(data: accountStatuses)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ public class StatusFetcher {
|
|||
let client = PixelfedClient(baseURL: account.serverUrl).getAuthenticated(token: accessToken)
|
||||
let statuses = try await client.getHomeTimeline(limit: 20, includeReblogs: defaultSettings.showReboostedStatuses, timeoutInterval: 5.0)
|
||||
|
||||
let widgetEntries = await self.prepare(statuses: statuses, length: length)
|
||||
let widgetEntries = await self.prepare(statuses: statuses.data, length: length)
|
||||
return widgetEntries
|
||||
}
|
||||
|
||||
|
@ -49,11 +49,11 @@ public class StatusFetcher {
|
|||
let accountData = AccountDataHandler.shared.getAccountData(accountId: accountId, modelContext: modelContext)
|
||||
guard let timelineCache = accountData?.timelineCache,
|
||||
let timelineCacheData = timelineCache.data(using: .utf8),
|
||||
let statusesFromCache = try? JSONDecoder().decode([Status].self, from: timelineCacheData) else {
|
||||
let statusesFromCache = try? JSONDecoder().decode(Linkable<[Status]>.self, from: timelineCacheData) else {
|
||||
return [self.placeholder()]
|
||||
}
|
||||
|
||||
let widgetEntries = await self.prepare(statuses: statusesFromCache, length: length)
|
||||
let widgetEntries = await self.prepare(statuses: statusesFromCache.data, length: length)
|
||||
return widgetEntries
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,12 @@
|
|||
"strings" : {
|
||||
"" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ""
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -31,6 +37,12 @@
|
|||
},
|
||||
"@%@" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "@%@"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -59,6 +71,12 @@
|
|||
},
|
||||
"#%@" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "#%@"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -87,6 +105,12 @@
|
|||
},
|
||||
"%@" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "%@"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -115,6 +139,12 @@
|
|||
},
|
||||
"%@, %@" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "%1$@, %2$@"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "new",
|
||||
|
@ -149,6 +179,12 @@
|
|||
},
|
||||
"%lld" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "%lld"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -177,6 +213,12 @@
|
|||
},
|
||||
"compose.error.cannotLoadImageFromExternalLibrary" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Bild kann nicht aus externer Bibliothek geladen werden."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -199,6 +241,12 @@
|
|||
},
|
||||
"compose.error.errorDuringComposingAttributeString" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Fehler beim Zusammenstellen der Attributzeichenfolge."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -221,6 +269,12 @@
|
|||
},
|
||||
"compose.error.errorDuringDownloadingAutocomplete" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Fehler beim Herunterladen von Autocomplete."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -243,6 +297,12 @@
|
|||
},
|
||||
"compose.error.loadingPhotosFailed" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Kann das Foto nicht aus der Bibliothek laden."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -277,6 +337,12 @@
|
|||
},
|
||||
"compose.error.postingStatusFailed" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Fehler beim Veröffentlichen des Beitrags."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -311,6 +377,12 @@
|
|||
},
|
||||
"compose.title.attachPhotoFull" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Füge ein Foto hinzu und beschreibe, was Du denkst."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -345,6 +417,12 @@
|
|||
},
|
||||
"compose.title.attachPhotoMini" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Beschreibe was Du denkst."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -380,6 +458,12 @@
|
|||
"compose.title.camera" : {
|
||||
"comment" : "Camera",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Foto aufnehmen"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -415,6 +499,12 @@
|
|||
"compose.title.cancel" : {
|
||||
"comment" : "Cancel",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Abbrechen"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -450,6 +540,12 @@
|
|||
"compose.title.commentsWillBeDisabled" : {
|
||||
"comment" : "Comments disabled",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Kommentare werden nicht möglich sein"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -484,6 +580,12 @@
|
|||
},
|
||||
"compose.title.delete" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Löschen"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -518,6 +620,12 @@
|
|||
},
|
||||
"compose.title.edit" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Bearbeiten"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -552,6 +660,12 @@
|
|||
},
|
||||
"compose.title.everyone" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Öffentlich"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -587,6 +701,12 @@
|
|||
"compose.title.files" : {
|
||||
"comment" : "Files",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Dateien durchsuchen"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -621,6 +741,12 @@
|
|||
},
|
||||
"compose.title.followers" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "für Follower"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -656,6 +782,12 @@
|
|||
"compose.title.missingAltTexts" : {
|
||||
"comment" : "Missing ALT texts",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Fehlende ALT-Texte"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -691,6 +823,12 @@
|
|||
"compose.title.missingAltTextsWarning" : {
|
||||
"comment" : "Missing ALT texts warning",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Es haben nicht alle Fotos eine Beschreibung für Sehbehinderte. Möchtest Du trotzdem senden?"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -726,6 +864,12 @@
|
|||
"compose.title.photos" : {
|
||||
"comment" : "Photo",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Fotobibliothek"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -761,6 +905,12 @@
|
|||
"compose.title.publish" : {
|
||||
"comment" : "Publish",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Veröffentlichen"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -796,6 +946,12 @@
|
|||
"compose.title.tryToUpload" : {
|
||||
"comment" : "Try to upload",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Versuche hochzuladen"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -830,6 +986,12 @@
|
|||
},
|
||||
"compose.title.unlisted" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "nicht gelistet"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -865,6 +1027,12 @@
|
|||
"compose.title.writeContentWarning" : {
|
||||
"comment" : "Content warning",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Inhaltswarnung hinzufügen"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -899,6 +1067,12 @@
|
|||
},
|
||||
"global.error.errorDuringDeletingFileFromTmpDirectory" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Fehler beim Löschen einer Datei aus dem tmp-Verzeichnis."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -921,6 +1095,12 @@
|
|||
},
|
||||
"global.error.errorDuringGettingTmpDirectoryContents" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Fehler beim Abrufen des Inhalts des tmp-Verzeichnisses."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -943,6 +1123,12 @@
|
|||
},
|
||||
"global.error.errorDuringRemovingTransferredImage" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Fehler beim Entfernen des übertragenen Bildes aus dem tmp-Verzeichnis."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -966,6 +1152,12 @@
|
|||
"global.title.contentWarning" : {
|
||||
"comment" : "Sensitive content",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Inhaltswarnung"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1001,6 +1193,12 @@
|
|||
"global.title.momentsAgo" : {
|
||||
"comment" : "moments ago",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "gerade eben"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1036,6 +1234,12 @@
|
|||
"global.title.refresh" : {
|
||||
"comment" : "Refresh",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Aktualisieren"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1071,6 +1275,12 @@
|
|||
"global.title.seePost" : {
|
||||
"comment" : "See post",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Beitrag ansehen"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1105,6 +1315,12 @@
|
|||
},
|
||||
"global.title.showLess" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Weniger anzeigen"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1139,6 +1355,12 @@
|
|||
},
|
||||
"global.title.showMore" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Mehr anzeigen"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1173,6 +1395,12 @@
|
|||
},
|
||||
"photoEdit.error.updatePhotoFailed" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Fehler beim Aktualisieren des Fotos."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1208,6 +1436,12 @@
|
|||
"photoEdit.navigationBar.title" : {
|
||||
"comment" : "Title",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Fotodetails"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1243,6 +1477,12 @@
|
|||
"photoEdit.title.accessibility" : {
|
||||
"comment" : "Accessibility",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Barrierefreiheit"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1278,6 +1518,12 @@
|
|||
"photoEdit.title.accessibilityDescription" : {
|
||||
"comment" : "Accesibility",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Beschreibung für Sehbehinderte"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1313,6 +1559,12 @@
|
|||
"photoEdit.title.cancel" : {
|
||||
"comment" : "Cancel",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Abbrechen"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1348,6 +1600,12 @@
|
|||
"photoEdit.title.photo" : {
|
||||
"comment" : "Photo",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Foto"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1383,6 +1641,12 @@
|
|||
"photoEdit.title.save" : {
|
||||
"comment" : "Save",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Speichern"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1417,6 +1681,12 @@
|
|||
},
|
||||
"placeSelector.error.loadingPlacesFailed" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Benachrichtigungen konnten nicht geladen werden."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1452,6 +1722,12 @@
|
|||
"placeSelector.navigationBar.title" : {
|
||||
"comment" : "Title",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Orte"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1487,6 +1763,12 @@
|
|||
"placeSelector.title.buttonSearch" : {
|
||||
"comment" : "Search",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Suchen"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1522,6 +1804,12 @@
|
|||
"placeSelector.title.cancel" : {
|
||||
"comment" : "Cancel",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Abbrechen"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1557,6 +1845,12 @@
|
|||
"placeSelector.title.search" : {
|
||||
"comment" : "Search",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Suchen..."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1592,6 +1886,12 @@
|
|||
"status.title.altText" : {
|
||||
"comment" : "ALT",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "ALT"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1627,6 +1927,12 @@
|
|||
"tip.mainNavigation.message" : {
|
||||
"comment" : "Main navigation tip message.",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Sie können die Position des Hauptnavigationsmenüs in den Einstellungen der App anpassen."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1644,6 +1950,12 @@
|
|||
"tip.mainNavigation.title" : {
|
||||
"comment" : "Main navigation tip title.",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Position im Menü"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1661,6 +1973,12 @@
|
|||
"tip.menuCustomizable.message" : {
|
||||
"comment" : "Menu customizable tip message.",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Sie können die Standardoptionen im Menü ändern, indem Sie lange auf die jeweilige Option drücken."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1678,6 +1996,12 @@
|
|||
"tip.menuCustomizable.title" : {
|
||||
"comment" : "Menu customizable tip title.",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Ändern der Standardoptionen"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1695,6 +2019,12 @@
|
|||
"tip.timelineDoubleTap.message" : {
|
||||
"comment" : "Timeline double tip message.",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Ein Doppeltippen auf ein Foto führt dazu, dass es favorisiert wird."
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
@ -1712,6 +2042,12 @@
|
|||
"tip.timelineDoubleTap.title" : {
|
||||
"comment" : "Timeline double tip title.",
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Als Favorit markieren"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
|
|
Loading…
Reference in New Issue