Merge pull request #1139 from kiwix/donation-button-ipad

Re-arrange donation button on iPad
This commit is contained in:
Kelson 2025-03-13 11:26:14 +01:00 committed by GitHub
commit 80dc7f3eb2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
47 changed files with 220 additions and 173 deletions

View File

@ -13,20 +13,21 @@
// You should have received a copy of the GNU General Public License
// along with Kiwix; If not, see https://www.gnu.org/licenses/.
#if os(iOS)
import SwiftUI
import Combine
import UserNotifications
#if os(iOS)
@main
struct Kiwix: App {
@Environment(\.scenePhase) private var scenePhase
@StateObject private var library = LibraryViewModel()
@StateObject private var navigation = NavigationViewModel()
@UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
private let fileMonitor: DirectoryMonitor
private let activityService: ActivityService?
init() {
fileMonitor = DirectoryMonitor(url: URL.documentDirectory) { LibraryOperations.scanDirectory($0) }
// MARK: - live activities
@ -99,6 +100,8 @@ struct Kiwix: App {
navigation.navigateToMostRecentTab()
}
}
.modifier(DonationViewModifier())
}
.commands {
CommandGroup(replacing: .undoRedo) {

View File

@ -167,12 +167,12 @@ struct RootView: View {
@Environment(\.openWindow) var openWindow
@Environment(\.controlActiveState) var controlActiveState
@StateObject private var navigation = NavigationViewModel()
@State private var currentNavItem: NavigationItem?
@State private var currentNavItem: MenuItem?
@StateObject private var windowTracker = WindowTracker()
@State private var paymentButtonLabel: PayWithApplePayButtonLabel?
private let primaryItems: [NavigationItem] = [.bookmarks]
private let libraryItems: [NavigationItem] = [.opened, .categories, .downloads, .new]
private let primaryItems: [MenuItem] = [.bookmarks]
private let libraryItems: [MenuItem] = [.opened, .categories, .downloads, .new]
private let openURL = NotificationCenter.default.publisher(for: .openURL)
private let appTerminates = NotificationCenter.default.publisher(for: NSApplication.willTerminateNotification)
private let tabCloses = NotificationCenter.default.publisher(for: NSWindow.willCloseNotification)
@ -183,15 +183,15 @@ struct RootView: View {
NavigationSplitView {
List(selection: $currentNavItem) {
ForEach(
[NavigationItem.tab(objectID: navigation.currentTabId)] + primaryItems,
[MenuItem.tab(objectID: navigation.currentTabId)] + primaryItems,
id: \.self
) { navigationItem in
Label(navigationItem.name, systemImage: navigationItem.icon)
) { menuItem in
Label(menuItem.name, systemImage: menuItem.icon)
}
if FeatureFlags.hasLibrary {
Section(LocalString.app_macos_navigation_button_library) {
ForEach(libraryItems, id: \.self) { navigationItem in
Label(navigationItem.name, systemImage: navigationItem.icon)
ForEach(libraryItems, id: \.self) { menuItem in
Label(menuItem.name, systemImage: menuItem.icon)
}
}
}
@ -232,7 +232,7 @@ struct RootView: View {
.modifier(SaveContentHandler())
.environmentObject(navigation)
.onChange(of: currentNavItem) { newValue in
navigation.currentItem = newValue
navigation.currentItem = newValue?.navigationItem
}
.onOpenURL { url in
if url.isFileURL {

View File

@ -18,9 +18,9 @@ import CoreData
import SwiftUI
import UIKit
class SidebarViewController: UICollectionViewController, NSFetchedResultsControllerDelegate {
final class SidebarViewController: UICollectionViewController, NSFetchedResultsControllerDelegate {
private lazy var dataSource = {
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, NavigationItem> {
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, MenuItem> {
[unowned self] cell, indexPath, item in
configureCell(cell: cell, indexPath: indexPath, item: item)
}
@ -29,7 +29,7 @@ class SidebarViewController: UICollectionViewController, NSFetchedResultsControl
) { [unowned self] headerView, elementKind, indexPath in
configureHeader(headerView: headerView, elementKind: elementKind, indexPath: indexPath)
}
let dataSource = UICollectionViewDiffableDataSource<Section, NavigationItem>(collectionView: collectionView) {
let dataSource = UICollectionViewDiffableDataSource<Section, MenuItem>(collectionView: collectionView) {
collectionView, indexPath, item in
collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item)
}
@ -50,16 +50,22 @@ class SidebarViewController: UICollectionViewController, NSFetchedResultsControl
}
enum Section: String, CaseIterable {
case primary
case tabs
case primary
case library
case settings
case donation
static var allSections: [Section] {
if FeatureFlags.hasLibrary {
switch (FeatureFlags.hasLibrary, Brand.hideDonation) {
case (true, true):
allCases.filter { [.donation].contains($0) }
case (false, true):
allCases.filter { [.donation, .library].contains($0) }
case (true, false):
allCases
} else {
allCases.filter { $0 != .library }
case (false, false):
allCases.filter { [.library].contains($0) }
}
}
}
@ -84,7 +90,8 @@ class SidebarViewController: UICollectionViewController, NSFetchedResultsControl
func updateSelection() {
guard let navigationViewModel,
let currentItem = navigationViewModel.currentItem,
let indexPath = dataSource.indexPath(for: currentItem),
let currentMenuItem = MenuItem(from: currentItem),
let indexPath = dataSource.indexPath(for: currentMenuItem),
collectionView.indexPathsForSelectedItems?.first != indexPath else { return }
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: [])
}
@ -124,13 +131,16 @@ class SidebarViewController: UICollectionViewController, NSFetchedResultsControl
)
// apply initial snapshot
var snapshot = NSDiffableDataSourceSnapshot<Section, NavigationItem>()
var snapshot = NSDiffableDataSourceSnapshot<Section, MenuItem>()
snapshot.appendSections(Section.allSections)
snapshot.appendItems([.bookmarks], toSection: .primary)
if FeatureFlags.hasLibrary {
if snapshot.sectionIdentifiers.contains(.library) {
snapshot.appendItems([.opened, .categories, .downloads, .new], toSection: .library)
}
snapshot.appendItems([.settings], toSection: .settings)
if snapshot.sectionIdentifiers.contains(.donation) {
snapshot.appendItems([.donation], toSection: .donation)
}
dataSource.apply(snapshot, animatingDifferences: false)
try? fetchedResultController.performFetch()
}
@ -153,8 +163,8 @@ class SidebarViewController: UICollectionViewController, NSFetchedResultsControl
) {
let tabIds = snapshot.itemIdentifiers
.compactMap { $0 as? NSManagedObjectID }
let tabs = tabIds.map { NavigationItem.tab(objectID: $0) }
var tabsSnapshot = NSDiffableDataSourceSectionSnapshot<NavigationItem>()
let tabs = tabIds.map { MenuItem.tab(objectID: $0) }
var tabsSnapshot = NSDiffableDataSourceSectionSnapshot<MenuItem>()
tabsSnapshot.append(tabs)
Task { [tabsSnapshot] in
await MainActor.run { [tabsSnapshot] in
@ -173,11 +183,20 @@ class SidebarViewController: UICollectionViewController, NSFetchedResultsControl
}
}
}
override func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
guard dataSource.itemIdentifier(for: indexPath) != .donation else {
// trigger the donation pop-up, but do not select the menu item itself
NotificationCenter.openDonations()
return false
}
return true
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let splitViewController,
let navigationViewModel,
let navigationItem = dataSource.itemIdentifier(for: indexPath) else { return }
let navigationItem = dataSource.itemIdentifier(for: indexPath)?.navigationItem else { return }
if navigationViewModel.currentItem != navigationItem {
navigationViewModel.currentItem = navigationItem
}
@ -192,7 +211,7 @@ class SidebarViewController: UICollectionViewController, NSFetchedResultsControl
// MARK: - Collection View Configuration
private func configureCell(cell: UICollectionViewListCell, indexPath: IndexPath, item: NavigationItem) {
private func configureCell(cell: UICollectionViewListCell, indexPath: IndexPath, item: MenuItem) {
if case let .tab(objectID) = item,
let tab = try? Database.shared.viewContext.existingObject(with: objectID) as? Tab {
var config = cell.defaultContentConfiguration()
@ -214,9 +233,9 @@ class SidebarViewController: UICollectionViewController, NSFetchedResultsControl
var config = cell.defaultContentConfiguration()
config.text = item.name
config.image = UIImage(systemName: item.icon)
config.imageProperties.tintColor = item.iconForegroundColor
cell.contentConfiguration = config
}
}
private func configureHeader(headerView: UICollectionViewListCell, elementKind: String, indexPath: IndexPath) {

View File

@ -163,9 +163,7 @@
"enum.libray_tab_item.categories" = "Rummadoù";
"enum.libray_tab_item.downloads" = "Pellgargadurioù";
"enum.libray_tab_item.new" = "Nevez";
"enum.navigation_item.loading" = "O kargañ";
"enum.navigation_item.bookmarks" = "Sinedoù";
"enum.navigation_item.map" = "Kartenn";
"enum.navigation_item.new_tab" = "Steudenn nevez";
"enum.navigation_item.opened" = "Digor";
"enum.navigation_item.categories" = "Rummadoù";

View File

@ -191,10 +191,8 @@
"enum.libray_tab_item.categories" = "Pubu nima";
"enum.libray_tab_item.downloads" = "Deebu";
"enum.libray_tab_item.new" = "Palli";
"enum.navigation_item.loading" = "Ʒili";
"enum.navigation_item.reading" = "Kariŋ";
"enum.navigation_item.bookmarks" = "Buku'dalima";
"enum.navigation_item.map" = "Tiŋgbani";
"enum.navigation_item.new_tab" = "Binshɛɣ'kam palli";
"enum.navigation_item.opened" = "Yooma";
"enum.navigation_item.categories" = "Pubu nima";

View File

@ -216,10 +216,8 @@
"enum.libray_tab_item.categories" = "Kategorien";
"enum.libray_tab_item.downloads" = "Downloads";
"enum.libray_tab_item.new" = "Neu";
"enum.navigation_item.loading" = "Lade …";
"enum.navigation_item.reading" = "Lese …";
"enum.navigation_item.bookmarks" = "Lesezeichen";
"enum.navigation_item.map" = "Karte";
"enum.navigation_item.new_tab" = "Neuer Tab";
"enum.navigation_item.opened" = "Geöffnet";
"enum.navigation_item.categories" = "Kategorien";

View File

@ -261,10 +261,8 @@
"enum.libray_tab_item.downloads" = "Downloads";
"enum.libray_tab_item.new" = "New";
"enum.navigation_item.loading" = "Loading";
"enum.navigation_item.reading" = "Reading";
"enum.navigation_item.bookmarks" = "Bookmarks";
"enum.navigation_item.map" = "Map";
"enum.navigation_item.new_tab" = "New Tab";
"enum.navigation_item.opened" = "Opened";
"enum.navigation_item.categories" = "Categories";

View File

@ -216,10 +216,8 @@
"enum.libray_tab_item.categories" = "Categorías";
"enum.libray_tab_item.downloads" = "Descargas";
"enum.libray_tab_item.new" = "Nuevo";
"enum.navigation_item.loading" = "Cargando…";
"enum.navigation_item.reading" = "Lectura";
"enum.navigation_item.bookmarks" = "Marcadores";
"enum.navigation_item.map" = "Mapa";
"enum.navigation_item.new_tab" = "Pestaña nueva";
"enum.navigation_item.opened" = "Abierto";
"enum.navigation_item.categories" = "Categorías";

View File

@ -123,7 +123,6 @@
"enum.external_link_loading_policy.never_load" = "Älä koskaan lataa";
"enum.library_language_sorting_model.a-z" = "A-Ö";
"enum.libray_tab_item.new" = "Uusi";
"enum.navigation_item.loading" = "Ladataan";
"enum.navigation_item.bookmarks" = "Kirjanmerkit";
"enum.navigation_item.new_tab" = "Uusi välilehti";
"enum.navigation_item.opened" = "Avattu";

View File

@ -226,10 +226,8 @@
"enum.libray_tab_item.categories" = "Catégories";
"enum.libray_tab_item.downloads" = "Téléchargements";
"enum.libray_tab_item.new" = "Nouveau";
"enum.navigation_item.loading" = "Chargement";
"enum.navigation_item.reading" = "Lecture";
"enum.navigation_item.bookmarks" = "Signets";
"enum.navigation_item.map" = "Carte";
"enum.navigation_item.new_tab" = "Nouvel onglet";
"enum.navigation_item.opened" = "Ouvert";
"enum.navigation_item.categories" = "Catégories";

View File

@ -211,10 +211,8 @@
"enum.libray_tab_item.categories" = "Bangarori";
"enum.libray_tab_item.downloads" = "Saukewa";
"enum.libray_tab_item.new" = "Sabo";
"enum.navigation_item.loading" = "Ana lodawa";
"enum.navigation_item.reading" = "Karatu";
"enum.navigation_item.bookmarks" = "Alamomi";
"enum.navigation_item.map" = "Taswira";
"enum.navigation_item.new_tab" = "Sabon shafi";
"enum.navigation_item.opened" = "An buɗe shi";
"enum.navigation_item.categories" = "Bangarori";

View File

@ -214,10 +214,8 @@
"enum.libray_tab_item.categories" = "קטגוריות";
"enum.libray_tab_item.downloads" = "הורדות";
"enum.libray_tab_item.new" = "חדש";
"enum.navigation_item.loading" = "טעינה";
"enum.navigation_item.reading" = "קריאה";
"enum.navigation_item.bookmarks" = "סימניות";
"enum.navigation_item.map" = "מפה";
"enum.navigation_item.new_tab" = "לשונית חדשה";
"enum.navigation_item.opened" = "פתוחים";
"enum.navigation_item.categories" = "קטגוריות";

View File

@ -80,8 +80,6 @@
"enum.flavor.max" = "अधिकतम";
"enum.libray_tab_item.categories" = "श्रेणियाँ";
"enum.libray_tab_item.new" = "नया";
"enum.navigation_item.loading" = "लोड हो रहा है…";
"enum.navigation_item.map" = "नक्शा";
"enum.navigation_item.new" = "नया";
"enum.navigation_item.downloads" = "डाउनलोड";
"enum.search_result_snippet_mode.disabled" = "अक्षम किया गया";

View File

@ -213,10 +213,8 @@
"enum.libray_tab_item.categories" = "Categorias";
"enum.libray_tab_item.downloads" = "Discargamentos";
"enum.libray_tab_item.new" = "Nove";
"enum.navigation_item.loading" = "Cargamento";
"enum.navigation_item.reading" = "Lectura";
"enum.navigation_item.bookmarks" = "Marcapaginas";
"enum.navigation_item.map" = "Carta";
"enum.navigation_item.new_tab" = "Nove scheda";
"enum.navigation_item.opened" = "Aperite";
"enum.navigation_item.categories" = "Categorias";

View File

@ -211,10 +211,8 @@
"enum.libray_tab_item.categories" = "Kategori";
"enum.libray_tab_item.downloads" = "Unduhan";
"enum.libray_tab_item.new" = "Baru";
"enum.navigation_item.loading" = "Memuat";
"enum.navigation_item.reading" = "Membaca";
"enum.navigation_item.bookmarks" = "Markah";
"enum.navigation_item.map" = "Peta";
"enum.navigation_item.new_tab" = "Tab Baru";
"enum.navigation_item.opened" = "Dibuka";
"enum.navigation_item.categories" = "Kategori";

View File

@ -221,10 +221,8 @@
"enum.libray_tab_item.categories" = "Otu";
"enum.libray_tab_item.downloads" = "Nbudata";
"enum.libray_tab_item.new" = "Ọhụrụ";
"enum.navigation_item.loading" = "ọ ka na-ebudata";
"enum.navigation_item.reading" = "Ọgụgụ";
"enum.navigation_item.bookmarks" = "Akara Akwụkwọ";
"enum.navigation_item.map" = "Maapụ";
"enum.navigation_item.new_tab" = "Taabụ ọhụrụ";
"enum.navigation_item.opened" = "Mepere";
"enum.navigation_item.categories" = "Otu";

View File

@ -56,7 +56,6 @@
"enum.libray_tab_item.categories" = "Amí gbúgbe";
"enum.libray_tab_item.downloads" = "Downloadu";
"enum.libray_tab_item.new" = "Etito";
"enum.navigation_item.loading" = "Ya wa";
"enum.navigation_item.reading" = "Egba";
"enum.navigation_item.opened" = "Bi";
"enum.navigation_item.categories" = "Amí gbúgbe";

View File

@ -102,8 +102,6 @@
"enum.libray_tab_item.opened" = "Aperto";
"enum.libray_tab_item.categories" = "Categorie";
"enum.libray_tab_item.new" = "Nuovo";
"enum.navigation_item.loading" = "Caricamento";
"enum.navigation_item.map" = "Mappa";
"enum.navigation_item.new_tab" = "Nuova scheda";
"enum.navigation_item.opened" = "Aperto";
"enum.navigation_item.new" = "Nuovo";

View File

@ -208,10 +208,8 @@
"enum.libray_tab_item.categories" = "カテゴリ";
"enum.libray_tab_item.downloads" = "ダウンロード";
"enum.libray_tab_item.new" = "新規";
"enum.navigation_item.loading" = "読み込み中";
"enum.navigation_item.reading" = "閲覧";
"enum.navigation_item.bookmarks" = "ブックマーク";
"enum.navigation_item.map" = "地図";
"enum.navigation_item.new_tab" = "新規タブ";
"enum.navigation_item.opened" = "読み込み済み";
"enum.navigation_item.categories" = "カテゴリ";

View File

@ -193,7 +193,6 @@
"enum.library_language_sorting_model.a-z" = "A-Z";
"enum.libray_tab_item.categories" = "분류";
"enum.libray_tab_item.downloads" = "다운로드";
"enum.navigation_item.loading" = "불러오는 중";
"enum.navigation_item.bookmarks" = "북마크";
"enum.navigation_item.new_tab" = "새 탭";
"enum.navigation_item.categories" = "분류";

View File

@ -159,7 +159,6 @@
"enum.libray_tab_item.new" = "Nei";
"enum.navigation_item.reading" = "Liesen";
"enum.navigation_item.bookmarks" = "Lieszeechen";
"enum.navigation_item.map" = "Kaart";
"enum.navigation_item.new_tab" = "Neien Tab";
"enum.navigation_item.opened" = "Opgemaach";
"enum.navigation_item.categories" = "Kategorien";

View File

@ -59,7 +59,6 @@
"enum.libray_tab_item.categories" = "Ndéngé";
"enum.libray_tab_item.downloads" = "Bokɔ́ngɔli";
"enum.libray_tab_item.new" = "Sika";
"enum.navigation_item.loading" = "Ezali ko luka";
"enum.navigation_item.reading" = "Kotanga";
"enum.navigation_item.bookmarks" = "Makomi ya mikanda";
"enum.navigation_item.opened" = "Efungolami";

View File

@ -213,10 +213,8 @@
"enum.libray_tab_item.categories" = "Категории";
"enum.libray_tab_item.downloads" = "Преземања";
"enum.libray_tab_item.new" = "Ново";
"enum.navigation_item.loading" = "Вчитувам";
"enum.navigation_item.reading" = "Читање";
"enum.navigation_item.bookmarks" = "Обележани";
"enum.navigation_item.map" = "Карта";
"enum.navigation_item.new_tab" = "Ново јазиче";
"enum.navigation_item.opened" = "Отворено";
"enum.navigation_item.categories" = "Категории";

View File

@ -141,9 +141,7 @@
"enum.libray_tab_item.categories" = "ਸ਼੍ਰੇਣੀਆਂ";
"enum.libray_tab_item.downloads" = "ਉਤਾਰੋ/ਲਾਹੋ";
"enum.libray_tab_item.new" = "ਨਵਾਂ";
"enum.navigation_item.loading" = "ਲੱਦ ਰਿਹਾ ਐ";
"enum.navigation_item.reading" = "ਪੜ੍ਹ ਰਿਹਾ ਐ";
"enum.navigation_item.map" = "ਨਕਸ਼ਾ";
"enum.navigation_item.opened" = "ਖੋਲ੍ਹਿਆ ਗਿਆ";
"enum.navigation_item.categories" = "ਸ਼੍ਰੇਣੀਆਂ";
"enum.navigation_item.new" = "ਨਵਾਂ";

View File

@ -157,10 +157,8 @@
"enum.libray_tab_item.categories" = "Kategorie";
"enum.libray_tab_item.downloads" = "Pobierz";
"enum.libray_tab_item.new" = "Nowy";
"enum.navigation_item.loading" = "Wczytywanie";
"enum.navigation_item.reading" = "Czytanie";
"enum.navigation_item.bookmarks" = "Zakładki";
"enum.navigation_item.map" = "Mapa";
"enum.navigation_item.new_tab" = "Nowa zakładka";
"enum.navigation_item.opened" = "Otwarte";
"enum.navigation_item.categories" = "Kategorie";

View File

@ -216,10 +216,8 @@
"enum.libray_tab_item.categories" = "Bottom Tab bar item title under Library on iOS";
"enum.libray_tab_item.downloads" = "Bottom Tab bar item title under Library on iOS";
"enum.libray_tab_item.new" = "Bottom Tab bar item title under Library on iOS";
"enum.navigation_item.loading" = "Loading label displayed on application start";
"enum.navigation_item.reading" = "Side navigation menu item title";
"enum.navigation_item.bookmarks" = "Side navigation menu item title";
"enum.navigation_item.map" = "Side navigation menu item title";
"enum.navigation_item.new_tab" = "Side navigation menu item title";
"enum.navigation_item.opened" = "Side navigation menu item title";
"enum.navigation_item.categories" = "Side navigation menu item title";

View File

@ -213,10 +213,8 @@
"enum.libray_tab_item.categories" = "Categorii";
"enum.libray_tab_item.downloads" = "Descărcări";
"enum.libray_tab_item.new" = "Nou";
"enum.navigation_item.loading" = "Încărcare";
"enum.navigation_item.reading" = "Lectură";
"enum.navigation_item.bookmarks" = "Semne de carte";
"enum.navigation_item.map" = "Hartă";
"enum.navigation_item.new_tab" = "Filă Nouă";
"enum.navigation_item.opened" = "Deschis";
"enum.navigation_item.categories" = "Categorii";

View File

@ -218,10 +218,8 @@
"enum.libray_tab_item.categories" = "Категории";
"enum.libray_tab_item.downloads" = "Загрузки";
"enum.libray_tab_item.new" = "Новое";
"enum.navigation_item.loading" = "Загружается";
"enum.navigation_item.reading" = "Чтение";
"enum.navigation_item.bookmarks" = "Закладки";
"enum.navigation_item.map" = "Карта";
"enum.navigation_item.new_tab" = "Новая вкладка";
"enum.navigation_item.opened" = "Открыто";
"enum.navigation_item.categories" = "Категории";

View File

@ -84,9 +84,7 @@
"enum.category.wiktionary" = "Wikisátnegirji";
"enum.libray_tab_item.categories" = "Kategoriijat";
"enum.libray_tab_item.new" = "Ođđa";
"enum.navigation_item.loading" = "Viežžamin";
"enum.navigation_item.bookmarks" = "Girjemearkkat";
"enum.navigation_item.map" = "Kárta";
"enum.navigation_item.new_tab" = "Ođđa leavga";
"enum.navigation_item.categories" = "Kategoriijat";
"enum.navigation_item.new" = "Ođđa";

View File

@ -119,10 +119,8 @@
"enum.libray_tab_item.categories" = "ونکیاں";
"enum.libray_tab_item.downloads" = "ڈاؤن لوڈ";
"enum.libray_tab_item.new" = "نواں";
"enum.navigation_item.loading" = "لوڈ تھین٘دا پئے";
"enum.navigation_item.reading" = "پڑھݨ";
"enum.navigation_item.bookmarks" = "نشانیاں";
"enum.navigation_item.map" = "نقشہ";
"enum.navigation_item.new_tab" = "نویں ٹیب";
"enum.navigation_item.opened" = "کھُل ڳیا";
"enum.navigation_item.categories" = "ونکیاں";

View File

@ -209,10 +209,8 @@
"enum.libray_tab_item.categories" = "Kategorije";
"enum.libray_tab_item.downloads" = "Prenosi";
"enum.libray_tab_item.new" = "Novo";
"enum.navigation_item.loading" = "Nalaganje";
"enum.navigation_item.reading" = "Branje";
"enum.navigation_item.bookmarks" = "Zaznamki";
"enum.navigation_item.map" = "Zemljevid";
"enum.navigation_item.new_tab" = "Nov zavihek";
"enum.navigation_item.opened" = "Odprto";
"enum.navigation_item.categories" = "Kategorije";

View File

@ -211,10 +211,8 @@
"enum.libray_tab_item.categories" = "Kategori";
"enum.libray_tab_item.downloads" = "Shkarkime";
"enum.libray_tab_item.new" = "E re";
"enum.navigation_item.loading" = "Po ngarkohet";
"enum.navigation_item.reading" = "Lexim";
"enum.navigation_item.bookmarks" = "Faqerojtës";
"enum.navigation_item.map" = "Hartë";
"enum.navigation_item.new_tab" = "Skedë e Re";
"enum.navigation_item.opened" = "Hapur";
"enum.navigation_item.categories" = "Kategori";

View File

@ -216,10 +216,8 @@
"enum.libray_tab_item.categories" = "Kategorier";
"enum.libray_tab_item.downloads" = "Nedladdningar";
"enum.libray_tab_item.new" = "Nytt";
"enum.navigation_item.loading" = "Laddar";
"enum.navigation_item.reading" = "Läser";
"enum.navigation_item.bookmarks" = "Bokmärken";
"enum.navigation_item.map" = "Karta";
"enum.navigation_item.new_tab" = "Ny flik";
"enum.navigation_item.opened" = "Öppnade";
"enum.navigation_item.categories" = "Kategorier";

View File

@ -217,10 +217,8 @@
"enum.libray_tab_item.categories" = "Kategoriler";
"enum.libray_tab_item.downloads" = "İndirilenler";
"enum.libray_tab_item.new" = "Yeni";
"enum.navigation_item.loading" = "Yükleniyor";
"enum.navigation_item.reading" = "Okuma";
"enum.navigation_item.bookmarks" = "Yer İşaretleri";
"enum.navigation_item.map" = "Harita";
"enum.navigation_item.new_tab" = "Yeni Sekme";
"enum.navigation_item.opened" = "Açıldı";
"enum.navigation_item.categories" = "Kategoriler";

View File

@ -201,7 +201,6 @@
"enum.libray_tab_item.categories" = "Категорії";
"enum.libray_tab_item.downloads" = "Завантаження";
"enum.libray_tab_item.new" = "Нове";
"enum.navigation_item.loading" = "Завантаження";
"enum.navigation_item.reading" = "Читання";
"enum.navigation_item.bookmarks" = "Закладки";
"enum.navigation_item.new_tab" = "Нова вкладка";

View File

@ -218,10 +218,8 @@
"enum.libray_tab_item.categories" = "分类";
"enum.libray_tab_item.downloads" = "下载";
"enum.libray_tab_item.new" = "新";
"enum.navigation_item.loading" = "加载中";
"enum.navigation_item.reading" = "阅读";
"enum.navigation_item.bookmarks" = "书签";
"enum.navigation_item.map" = "地图";
"enum.navigation_item.new_tab" = "新建标签页";
"enum.navigation_item.opened" = "已打开";
"enum.navigation_item.categories" = "分类";

View File

@ -214,10 +214,8 @@
"enum.libray_tab_item.categories" = "分類";
"enum.libray_tab_item.downloads" = "下載";
"enum.libray_tab_item.new" = "新";
"enum.navigation_item.loading" = "載入中";
"enum.navigation_item.reading" = "閱讀";
"enum.navigation_item.bookmarks" = "書籤";
"enum.navigation_item.map" = "地圖";
"enum.navigation_item.new_tab" = "新分頁";
"enum.navigation_item.opened" = "已開啟";
"enum.navigation_item.categories" = "分類";

View File

@ -225,21 +225,54 @@ enum NavigationItem: Hashable, Identifiable {
case bookmarks, map(location: CLLocation?), tab(objectID: NSManagedObjectID)
case opened, categories, new, downloads
case settings
}
enum MenuItem: Hashable {
case tab(objectID: NSManagedObjectID)
case bookmarks
case opened
case categories
case new
case downloads
case settings
case donation
init?(from navigationItem: NavigationItem) {
switch navigationItem {
case .loading, .map: return nil
case .bookmarks: self = .bookmarks
case .tab(let objectID): self = .tab(objectID: objectID)
case .opened: self = .opened
case .categories: self = .categories
case .new: self = .new
case .downloads: self = .downloads
case .settings: self = .settings
}
}
var navigationItem: NavigationItem? {
switch self {
case .tab(objectID: let objectID): .tab(objectID: objectID)
case .bookmarks: .bookmarks
case .opened: .opened
case .categories: .categories
case .new: .new
case .downloads: .downloads
case .settings: .settings
case .donation: nil
}
}
var name: String {
switch self {
case .loading:
return LocalString.enum_navigation_item_loading
case .bookmarks:
return LocalString.enum_navigation_item_bookmarks
case .map:
return LocalString.enum_navigation_item_map
case .tab:
#if os(macOS)
#if os(macOS)
return LocalString.enum_navigation_item_reading
#else
#else
return LocalString.enum_navigation_item_new_tab
#endif
#endif
case .opened:
return LocalString.enum_navigation_item_opened
case .categories:
@ -250,17 +283,15 @@ enum NavigationItem: Hashable, Identifiable {
return LocalString.enum_navigation_item_downloads
case .settings:
return LocalString.enum_navigation_item_settings
case .donation:
return LocalString.payment_support_button_label
}
}
var icon: String {
switch self {
case .loading:
return "loading"
case .bookmarks:
return "star"
case .map:
return "map"
case .tab:
#if os(macOS)
return "book"
@ -277,8 +308,20 @@ enum NavigationItem: Hashable, Identifiable {
return "tray.and.arrow.down"
case .settings:
return "gear"
case .donation:
return "heart.fill"
}
}
#if os(iOS)
var iconForegroundColor: UIColor? {
switch self {
case .donation:
return UIColor.red
case .tab, .bookmarks, .opened, .categories, .new, .downloads, .settings:
return nil
}
}
#endif
}
/// Note: The cases were reduced from:

View File

@ -77,6 +77,9 @@ extension Notification.Name {
#if os(macOS)
static let keepOnlyTabs = Notification.Name("keepOnlyTabs")
#endif
#if os(iOS)
static let openDonations = Notification.Name("openDonations")
#endif
}
extension UTType {
@ -127,4 +130,10 @@ extension NotificationCenter {
userInfo: ["tabIds": tabIds])
}
#endif
#if os(iOS)
@MainActor static func openDonations() {
NotificationCenter.default.post(name: .openDonations, object: nil, userInfo: nil)
}
#endif
}

View File

@ -87,6 +87,7 @@ struct PageZoomCommands: View {
}
}
#if os(macOS)
/// Only used on macOS
struct SidebarNavigationCommands: View {
@FocusedBinding(\.navigationItem) var navigationItem: NavigationItem??
@ -99,13 +100,14 @@ struct SidebarNavigationCommands: View {
}
}
private func buildButtons(_ navigationItems: [NavigationItem], modifiers: EventModifiers = []) -> some View {
private func buildButtons(_ navigationItems: [MenuItem], modifiers: EventModifiers = []) -> some View {
ForEach(Array(navigationItems.enumerated()), id: \.element) { index, item in
Button(item.name) {
navigationItem = item
navigationItem = item.navigationItem
}
.keyboardShortcut(KeyEquivalent(Character("\(index + 1)")), modifiers: modifiers)
.disabled(navigationItem == nil)
}
}
}
#endif

View File

@ -56,7 +56,7 @@ struct Library: View {
}
}
.listStyle(.plain)
.navigationTitle(NavigationItem.categories.name)
.navigationTitle(MenuItem.categories.name)
case .opened:
ZimFilesOpened(dismiss: dismiss)
case .downloads:

View File

@ -36,7 +36,7 @@ struct ZimFilesCategories: View {
var body: some View {
ZimFilesCategory(category: $selected, dismiss: dismiss)
.modifier(ToolbarRoleBrowser())
.navigationTitle(NavigationItem.categories.name)
.navigationTitle(MenuItem.categories.name)
.toolbar {
#if os(iOS)
ToolbarItem(placement: .navigationBarLeading) {

View File

@ -44,7 +44,7 @@ struct ZimFilesDownloads: View {
}
.modifier(GridCommon())
.modifier(ToolbarRoleBrowser())
.navigationTitle(NavigationItem.downloads.name)
.navigationTitle(MenuItem.downloads.name)
.overlay {
if downloadTasks.isEmpty {
Message(text: LocalString.zim_file_downloads_overlay_empty_message)

View File

@ -121,7 +121,7 @@ struct ZimFilesNew: View {
}
.modifier(GridCommon())
.modifier(ToolbarRoleBrowser())
.navigationTitle(NavigationItem.new.name)
.navigationTitle(MenuItem.new.name)
.searchable(text: $searchText)
.onAppear {
viewModel.update(searchText: searchText)

View File

@ -43,7 +43,7 @@ struct ZimFilesOpened: View {
}
.modifier(GridCommon(edges: .all))
.modifier(ToolbarRoleBrowser())
.navigationTitle(NavigationItem.opened.name)
.navigationTitle(MenuItem.opened.name)
.overlay {
if zimFiles.isEmpty {
Message(text: LocalString.zim_file_opened_overlay_no_opened_message)

View File

@ -0,0 +1,92 @@
// This file is part of Kiwix for iOS & macOS.
//
// Kiwix is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// any later version.
//
// Kiwix is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kiwix; If not, see https://www.gnu.org/licenses/.
#if os(iOS)
import SwiftUI
import Combine
struct DonationViewModifier: ViewModifier {
enum DonationPopupState {
case selection
case selectedAmount(SelectedAmount)
case thankYou
case error
}
private let openDonations = NotificationCenter.default.publisher(for: .openDonations)
private var amountSelected = PassthroughSubject<SelectedAmount?, Never>()
@State private var showDonationPopUp: Bool = false
@State private var donationPopUpState: DonationPopupState = .selection
// swiftlint:disable:next function_body_length
func body(content: Content) -> some View {
content
.onReceive(openDonations) { _ in
showDonationPopUp = true
}
.sheet(isPresented: $showDonationPopUp, onDismiss: {
let result = Payment.showResult()
switch result {
case .none:
// reset
donationPopUpState = .selection
return
case .some(let finalResult):
Task {
// we need to close the sheet in order to dismiss ApplePay,
// and we need to re-open it again with a delay to show thank you state
// Swift UI cannot yet handle multiple sheets
try? await Task.sleep(for: .milliseconds(100))
await MainActor.run {
switch finalResult {
case .thankYou:
donationPopUpState = .thankYou
case .error:
donationPopUpState = .error
}
showDonationPopUp = true
}
}
}
}, content: {
Group {
switch donationPopUpState {
case .selection:
PaymentForm(amountSelected: amountSelected)
.presentationDetents([.fraction(0.65)])
case .selectedAmount(let selectedAmount):
PaymentSummary(selectedAmount: selectedAmount, onComplete: {
showDonationPopUp = false
})
.presentationDetents([.fraction(0.65)])
case .thankYou:
PaymentResultPopUp(state: .thankYou)
.presentationDetents([.fraction(0.33)])
case .error:
PaymentResultPopUp(state: .error)
.presentationDetents([.fraction(0.33)])
}
}
.onReceive(amountSelected) { value in
if let amount = value {
donationPopUpState = .selectedAmount(amount)
} else {
donationPopUpState = .selection
}
}
})
}
}
#endif

View File

@ -131,19 +131,6 @@ import Combine
struct Settings: View {
enum DonationPopupState {
case selection
case selectedAmount(SelectedAmount)
case thankYou
case error
}
private var amountSelected = PassthroughSubject<SelectedAmount?, Never>()
@State private var showDonationPopUp: Bool = false
@State private var donationPopUpState: DonationPopupState = .selection
func openDonation() {
showDonationPopUp = true
}
@Default(.backupDocumentDirectory) private var backupDocumentDirectory
@Default(.downloadUsingCellular) private var downloadUsingCellular
@Default(.externalLinkLoadingPolicy) private var externalLinkLoadingPolicy
@ -151,10 +138,15 @@ struct Settings: View {
@Default(.searchResultSnippetMode) private var searchResultSnippetMode
@Default(.webViewPageZoom) private var webViewPageZoom
@EnvironmentObject private var library: LibraryViewModel
@Environment(\.horizontalSizeClass) var horizontalSizeClass
enum Route {
case languageSelector, about
}
func openDonation() {
NotificationCenter.openDonations()
}
var body: some View {
Group {
@ -177,57 +169,6 @@ struct Settings: View {
.navigationTitle(LocalString.settings_navigation_title)
}
}
.sheet(isPresented: $showDonationPopUp, onDismiss: {
let result = Payment.showResult()
switch result {
case .none:
// reset
donationPopUpState = .selection
return
case .some(let finalResult):
Task {
// we need to close the sheet in order to dismiss ApplePay,
// and we need to re-open it again with a delay to show thank you state
// Swift UI cannot yet handle multiple sheets
try? await Task.sleep(for: .milliseconds(100))
await MainActor.run {
switch finalResult {
case .thankYou:
donationPopUpState = .thankYou
case .error:
donationPopUpState = .error
}
showDonationPopUp = true
}
}
}
}, content: {
Group {
switch donationPopUpState {
case .selection:
PaymentForm(amountSelected: amountSelected)
.presentationDetents([.fraction(0.65)])
case .selectedAmount(let selectedAmount):
PaymentSummary(selectedAmount: selectedAmount, onComplete: {
showDonationPopUp = false
})
.presentationDetents([.fraction(0.65)])
case .thankYou:
PaymentResultPopUp(state: .thankYou)
.presentationDetents([.fraction(0.33)])
case .error:
PaymentResultPopUp(state: .error)
.presentationDetents([.fraction(0.33)])
}
}
.onReceive(amountSelected) { value in
if let amount = value {
donationPopUpState = .selectedAmount(amount)
} else {
donationPopUpState = .selection
}
}
})
}
var readingSettings: some View {
@ -314,7 +255,7 @@ struct Settings: View {
var miscellaneous: some View {
Section(LocalString.settings_miscellaneous_title) {
if Payment.paymentButtonType() != nil {
if Payment.paymentButtonType() != nil, horizontalSizeClass != .regular {
SupportKiwixButton {
openDonation()
}