diff --git a/.gitignore b/.gitignore index 1bc0c9242..9e6cc67d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ AppStore/screenshots CoreKiwix.xcframework *.zim +!Tests/TestResources/test_small.zim # Xcode # diff --git a/Model/LibBookmarks/LibBookmark.h b/Model/LibBookmarks/LibBookmark.h new file mode 100644 index 000000000..4186d783d --- /dev/null +++ b/Model/LibBookmarks/LibBookmark.h @@ -0,0 +1,22 @@ +// +// LibBookmark.h +// Kiwix + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface LibBookmark : NSObject + +@property std::string zimID_c; +@property std::string url_c; +@property std::string title_c; + +- (nonnull instancetype) init: (nonnull NSURL *) url inZIM: (nonnull NSUUID *) zimFileID withTitle: (nonnull NSString *) title; + +//- (const kiwix::Bookmark&) bridged; +- (kiwix::Book) book; + +NS_ASSUME_NONNULL_END + +@end diff --git a/Model/LibBookmarks/LibBookmark.mm b/Model/LibBookmarks/LibBookmark.mm new file mode 100644 index 000000000..fb59d9cd4 --- /dev/null +++ b/Model/LibBookmarks/LibBookmark.mm @@ -0,0 +1,39 @@ +// +// LibBookmark.m +// Kiwix + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" +#include "kiwix/bookmark.h" +#include "kiwix/book.h" +#include "zim/archive.h" +#pragma clang diagnostic pop + +#import +#import "LibBookmark.h" +#import "ZimFileService.h" + +@interface LibBookmark() +@property (nonatomic, strong) NSURL *_Nonnull url; +@property (nonatomic, strong) NSUUID *_Nonnull zimFileID; +@end + +@implementation LibBookmark + +- (instancetype) init: (NSURL *) url inZIM: (NSUUID *) zimFileID withTitle: (nonnull NSString *) title{ + self = [super init]; + if (self) { + self.url = url; + self.zimFileID = zimFileID; + self.zimID_c = [[[zimFileID UUIDString] lowercaseString] cStringUsingEncoding:NSUTF8StringEncoding]; + self.url_c = [url fileSystemRepresentation]; + self.title_c = [title cStringUsingEncoding:NSUTF8StringEncoding]; + } + return self; +} + +- (kiwix::Book) book { + return [ZimFileService.sharedInstance getBookBy: self.zimFileID]; +} + +@end diff --git a/Model/LibBookmarks/LibBookmarks.swift b/Model/LibBookmarks/LibBookmarks.swift new file mode 100644 index 000000000..e636d887d --- /dev/null +++ b/Model/LibBookmarks/LibBookmarks.swift @@ -0,0 +1,42 @@ +// +// LibBookmarks.swift +// Kiwix + +import Foundation + +struct LibBookmarks { + + static let shared = LibBookmarks() + private let bridge = LibBookmarksBridge() + + private init() {} + + func isBookmarked(url: URL) -> Bool { + guard let zimID = UUID(fromZimURL: url) else { return false } + return bridge.__isBookmarked(url, inZIM: zimID) + } + + func addBookmark(_ bookmark: LibBookmark) { + bridge.__add(bookmark) + } + + func removeBookmark(_ bookmark: LibBookmark) { + bridge.__remove(bookmark) + } +} + +extension LibBookmark { + convenience init?(withUrl url: URL, withTitle title: String) { + guard let zimFileID = UUID(fromZimURL: url) else { return nil } + self.init(url, inZIM: zimFileID, withTitle: title) + } +} + +extension UUID { + init?(fromZimURL url: URL) { + guard let uuid = UUID(uuidString: url.host ?? "") else { + return nil + } + self = uuid + } +} diff --git a/Model/LibBookmarks/LibBookmarksBridge.h b/Model/LibBookmarks/LibBookmarksBridge.h new file mode 100644 index 000000000..3ddacce74 --- /dev/null +++ b/Model/LibBookmarks/LibBookmarksBridge.h @@ -0,0 +1,17 @@ +// +// LibBookmarksBridge.h +// Kiwix + +#import +#import "kiwix/library.h" +#import "kiwix/bookmark.h" +#import "LibBookmark.h" + +@interface LibBookmarksBridge : NSObject + +- (nonnull instancetype) init; +- (BOOL) isBookmarked: (nonnull NSURL *) url inZIM: (nonnull NSUUID *) zimFileID NS_REFINED_FOR_SWIFT; +- (void) add: (nonnull LibBookmark *) bookmark NS_REFINED_FOR_SWIFT; +- (void) remove: (nonnull LibBookmark *) bookmark NS_REFINED_FOR_SWIFT; + +@end diff --git a/Model/LibBookmarks/LibBookmarksBridge.mm b/Model/LibBookmarks/LibBookmarksBridge.mm new file mode 100644 index 000000000..564a7ee6d --- /dev/null +++ b/Model/LibBookmarks/LibBookmarksBridge.mm @@ -0,0 +1,56 @@ +// +// LibBookmarksBridge.mm +// Kiwix + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" +#include "kiwix/library.h" +#include "kiwix/bookmark.h" +#pragma clang diagnostic pop + +#import "LibBookmarksBridge.h" + +# pragma mark - Private properties +@interface LibBookmarksBridge () + +@property kiwix::LibraryPtr library; + +@end + + +# pragma mark - Implementation + +@implementation LibBookmarksBridge + +- (instancetype _Nonnull)init { + self = [super init]; + if (self) { + self.library = kiwix::Library::create(); + } + return self; +} + +- (BOOL) isBookmarked: (nonnull NSURL *) url inZIM: (nonnull NSUUID *) zimFileID { + std::string url_c = [url fileSystemRepresentation]; + std::string fileID_c = [[[zimFileID UUIDString] lowercaseString] cStringUsingEncoding:NSUTF8StringEncoding]; + const std::vector bookmarks = self.library->getBookmarks(true); + for (kiwix::Bookmark bookmark: bookmarks) { + if (bookmark.getUrl() == url_c && bookmark.getBookId() == fileID_c) { + return true; + } + } + return false; +} + +- (void) add: (LibBookmark *) bookmark { + kiwix::Book book = [bookmark book]; + self.library->addBook(book); + kiwix::Bookmark bridgedBookmark = kiwix::Bookmark(book, bookmark.url_c, bookmark.title_c); + self.library->addBookmark(bridgedBookmark); +} + +- (void) remove: (LibBookmark *) bookmark { + self.library->removeBookmark(bookmark.zimID_c, bookmark.url_c); +} + +@end diff --git a/Model/ZimFileService/ZimFileService.h b/Model/ZimFileService/ZimFileService.h index 6658c9b68..7c82a4daa 100644 --- a/Model/ZimFileService/ZimFileService.h +++ b/Model/ZimFileService/ZimFileService.h @@ -8,6 +8,7 @@ #import #import "ZimFileMetaData.h" +#import "kiwix/book.h" @interface ZimFileService : NSObject @@ -23,6 +24,7 @@ - (void)close:(NSUUID *_Nonnull)zimFileID NS_REFINED_FOR_SWIFT; - (NSArray *_Nonnull)getReaderIdentifiers NS_REFINED_FOR_SWIFT; - (nonnull void *) getArchives; +- (kiwix::Book) getBookBy: (nonnull NSUUID*) fileZimID NS_REFINED_FOR_SWIFT; # pragma mark - Metadata diff --git a/Model/ZimFileService/ZimFileService.mm b/Model/ZimFileService/ZimFileService.mm index 7d30a801b..b08c9f165 100644 --- a/Model/ZimFileService/ZimFileService.mm +++ b/Model/ZimFileService/ZimFileService.mm @@ -115,6 +115,16 @@ + (ZimFileMetaData *)getMetaDataWithFileURL:(NSURL *)url { return metaData; } +- (kiwix::Book) getBookBy:(nonnull NSUUID *) fileZimID { + kiwix::Book book = kiwix::Book(); + try { + NSURL *fileURL = [ZimFileService.sharedInstance getFileURL: fileZimID]; + book.update(zim::Archive([fileURL fileSystemRepresentation])); + } catch (std::exception e) { } + return book; +} + + # pragma mark - URL Handling - (NSURL *)getFileURL:(NSUUID *)zimFileID { diff --git a/Support/Kiwix-Bridging-Header.h b/Support/Kiwix-Bridging-Header.h index c88c6a4b3..19575bca4 100644 --- a/Support/Kiwix-Bridging-Header.h +++ b/Support/Kiwix-Bridging-Header.h @@ -7,6 +7,8 @@ #import "ZimFileMetaData.h" #import "SearchOperation.h" #import "SearchResult.h" +#import "LibBookMarksBridge.h" +#import "LibBookmark.h" NS_INLINE NSException * _Nullable objCTryBlock(void(^_Nonnull tryBlock)(void)) { diff --git a/Tests/LibBookmarkTests.swift b/Tests/LibBookmarkTests.swift new file mode 100644 index 000000000..1e4fd0eb4 --- /dev/null +++ b/Tests/LibBookmarkTests.swift @@ -0,0 +1,30 @@ +// +// LibBookmarkTests.swift +// UnitTests + +import XCTest +@testable import Kiwix + +final class LibBookmarkTests: XCTestCase { + + private let testZimURL: URL = Bundle(for: LibBookmarkTests.self).url(forResource: "test_small", withExtension: "zim")! + private let testTitle: String = "Dionysius of Halicarnassus On Literary Composition" + private let bookmarkURL = URL(string: "kiwix://FF7D59DE-0FD8-F486-09FA-C57904646707/A/Dionysius%20of%20Halicarnassus%20On%20Literary%20Composition.50212.html")! + + func testIfZimFileExists() throws { + XCTAssertNotNil(testZimURL) + } + + func testAddingBookmark() { + let fileURLData = ZimFileService.getFileURLBookmarkData(for: testZimURL)! + try! ZimFileService.shared.open(fileURLBookmark: fileURLData) + let bookmarks = LibBookmarks.shared + XCTAssertFalse(bookmarks.isBookmarked(url: bookmarkURL)) + + let bookmark = LibBookmark(withUrl: bookmarkURL, withTitle: testTitle)! + bookmarks.addBookmark(bookmark) + + XCTAssertTrue(bookmarks.isBookmarked(url: bookmarkURL)) + } + +} diff --git a/Tests/TestResources/test_small.zim b/Tests/TestResources/test_small.zim new file mode 100644 index 000000000..f6706fb8a Binary files /dev/null and b/Tests/TestResources/test_small.zim differ