diff --git a/Assets/Icons/help/help.afdesign b/Assets/Icons/help/help.afdesign new file mode 100644 index 000000000..e0eb5aa34 Binary files /dev/null and b/Assets/Icons/help/help.afdesign differ diff --git a/Assets/Icons/help/help@1x.png b/Assets/Icons/help/help@1x.png new file mode 100644 index 000000000..27cf1c0ab Binary files /dev/null and b/Assets/Icons/help/help@1x.png differ diff --git a/Assets/Icons/help/help@2x.png b/Assets/Icons/help/help@2x.png new file mode 100644 index 000000000..ab277bd61 Binary files /dev/null and b/Assets/Icons/help/help@2x.png differ diff --git a/Assets/Icons/help/help@3x.png b/Assets/Icons/help/help@3x.png new file mode 100644 index 000000000..37ebd1b19 Binary files /dev/null and b/Assets/Icons/help/help@3x.png differ diff --git a/Assets/Icons/help/helpCompact@1x.png b/Assets/Icons/help/helpCompact@1x.png new file mode 100644 index 000000000..10ac8498a Binary files /dev/null and b/Assets/Icons/help/helpCompact@1x.png differ diff --git a/Assets/Icons/help/helpCompact@2x.png b/Assets/Icons/help/helpCompact@2x.png new file mode 100644 index 000000000..f14f982a1 Binary files /dev/null and b/Assets/Icons/help/helpCompact@2x.png differ diff --git a/Assets/Icons/help/helpCompact@3x.png b/Assets/Icons/help/helpCompact@3x.png new file mode 100644 index 000000000..8be7e8d3e Binary files /dev/null and b/Assets/Icons/help/helpCompact@3x.png differ diff --git a/Assets/Icons/help/questionmark.circle.svg b/Assets/Icons/help/questionmark.circle.svg new file mode 100644 index 000000000..487195d06 --- /dev/null +++ b/Assets/Icons/help/questionmark.circle.svg @@ -0,0 +1,161 @@ + + + + + + + + + Weight/Scale Variations + Ultralight + Thin + Light + Regular + Medium + Semibold + Bold + Heavy + Black + + + + + + + + + + + Design Variations + Symbols are supported in up to nine weights and three scales. + For optimal layout with text and other symbols, vertically align + symbols with the adjacent text. + + + + + + Margins + Leading and trailing margins on the left and right side of each symbol + can be adjusted by modifying the x-location of the margin guidelines. + Modifications are automatically applied proportionally to all + scales and weights. + + + + Exporting + Symbols should be outlined when exporting to ensure the + design is preserved when submitting to Xcode. + Template v.3.0 + Requires Xcode 13 or greater + Generated from questionmark.circle + Typeset at 100 points + Small + Medium + Large + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Assets/Images - Help/help08-bot.png b/Assets/Images - Help/help08-bot.png new file mode 100644 index 000000000..81ac99c64 Binary files /dev/null and b/Assets/Images - Help/help08-bot.png differ diff --git a/Assets/Images - Help/help08-top.png b/Assets/Images - Help/help08-top.png new file mode 100644 index 000000000..efefdd85d Binary files /dev/null and b/Assets/Images - Help/help08-top.png differ diff --git a/Assets/Images - Help/iPhone 12 Pro - Silver - Vertical.afdesign b/Assets/Images - Help/iPhone 12 Pro - Silver - Vertical.afdesign index 0a5555476..b634c13f5 100644 Binary files a/Assets/Images - Help/iPhone 12 Pro - Silver - Vertical.afdesign and b/Assets/Images - Help/iPhone 12 Pro - Silver - Vertical.afdesign differ diff --git a/Supporting Targets/piwigoKit/Info.plist b/Supporting Targets/piwigoKit/Info.plist index 27a1dc5a9..c53bbdd27 100644 --- a/Supporting Targets/piwigoKit/Info.plist +++ b/Supporting Targets/piwigoKit/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 480 + 486 diff --git a/piwigo.xcodeproj/project.pbxproj b/piwigo.xcodeproj/project.pbxproj index 45466c8ef..e656fc3a7 100644 --- a/piwigo.xcodeproj/project.pbxproj +++ b/piwigo.xcodeproj/project.pbxproj @@ -86,7 +86,6 @@ AD3DB4132773958200017542 /* ImagePreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD3DB4122773958200017542 /* ImagePreviewViewController.swift */; }; AD3DB4152773958A00017542 /* ImageDescriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD3DB4142773958A00017542 /* ImageDescriptionView.swift */; }; AD3FF5F42682908000D2F52A /* UIImage+AppTools.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADCC996425B452670034CB4A /* UIImage+AppTools.swift */; }; - AD3FF5F82683B5C700D2F52A /* PwgNotificationsObjc.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD3FF5F52683B49900D2F52A /* PwgNotificationsObjc.swift */; }; AD41530F27C6D35D00DE01CB /* LoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD41530E27C6D35D00DE01CB /* LoginViewController.swift */; }; AD41531527C6D37D00DE01CB /* LoginNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD41531427C6D37C00DE01CB /* LoginNavigationController.swift */; }; AD42D08124448B7C00F0BAC1 /* LocalAlbumsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD42D08024448B7C00F0BAC1 /* LocalAlbumsViewController.swift */; }; @@ -150,6 +149,9 @@ AD865777284D153F00C06EF4 /* pwg.categories.getList.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD865776284D153F00C06EF4 /* pwg.categories.getList.swift */; }; AD865778284D163800C06EF4 /* pwg.categories.getList.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD865776284D153F00C06EF4 /* pwg.categories.getList.swift */; }; AD8709AB259A8E66008C4E4C /* Help04ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD8709AA259A8E66008C4E4C /* Help04ViewController.swift */; }; + AD8A1E7D28846E1300752948 /* Help08ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD8A1E7C28846E1300752948 /* Help08ViewController.swift */; }; + AD8A1E80288478FA00752948 /* help08-top.png in Resources */ = {isa = PBXBuildFile; fileRef = AD8A1E7E288478FA00752948 /* help08-top.png */; }; + AD8A1E81288478FA00752948 /* help08-bot.png in Resources */ = {isa = PBXBuildFile; fileRef = AD8A1E7F288478FA00752948 /* help08-bot.png */; }; AD8D212626ACC15F0008E907 /* InAppIntents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = AD8D212826ACC15F0008E907 /* InAppIntents.intentdefinition */; }; AD8D214A26B094DC0008E907 /* Help07ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD8D214926B094DC0008E907 /* Help07ViewController.swift */; }; AD8D214C26B0A4450008E907 /* ImageUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD8D214B26B0A4450008E907 /* ImageUtilities.swift */; }; @@ -290,6 +292,7 @@ ADEAFB8F25F8198800EEDB1D /* ColorPaletteViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ADEAFB8E25F8198800EEDB1D /* ColorPaletteViewController.storyboard */; }; ADEC6B032455A3520011527C /* LocalAlbumsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADEC6B022455A3520011527C /* LocalAlbumsProvider.swift */; }; ADEC6B052455BC6F0011527C /* LocalAlbumsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADEC6B042455BC6F0011527C /* LocalAlbumsTableViewCell.swift */; }; + ADEEAB6B289410AD00825C7D /* AlbumViewController+DataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADEEAB6A289410AD00825C7D /* AlbumViewController+DataSource.swift */; }; ADEEC5D328560DF00065BA6D /* AlbumViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADEEC5D228560DF00065BA6D /* AlbumViewController.swift */; }; ADEEC5D5285619120065BA6D /* AlbumViewController+Menus.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADEEC5D4285619120065BA6D /* AlbumViewController+Menus.swift */; }; ADEEC5D7285640290065BA6D /* AlbumViewController+MenusOld.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADEEC5D6285640290065BA6D /* AlbumViewController+MenusOld.swift */; }; @@ -513,7 +516,6 @@ AD3FDDE91F2E23F700F71C81 /* da */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/About.strings; sourceTree = ""; }; AD3FDDEA1F2E23F700F71C81 /* da */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/ReleaseNotes.strings; sourceTree = ""; }; AD3FDDEB1F2E23F700F71C81 /* da */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/AppStore.strings; sourceTree = ""; }; - AD3FF5F52683B49900D2F52A /* PwgNotificationsObjc.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PwgNotificationsObjc.swift; sourceTree = ""; }; AD41530E27C6D35D00DE01CB /* LoginViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginViewController.swift; sourceTree = ""; }; AD41531427C6D37C00DE01CB /* LoginNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginNavigationController.swift; sourceTree = ""; }; AD42D08024448B7C00F0BAC1 /* LocalAlbumsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalAlbumsViewController.swift; sourceTree = ""; }; @@ -604,6 +606,9 @@ AD865774284D060400C06EF4 /* pwg.categories.getList.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = pwg.categories.getList.json; path = "Supporting Targets/piwigoWebAPI/pwg.categories/pwg.categories.getList.json"; sourceTree = SOURCE_ROOT; }; AD865776284D153F00C06EF4 /* pwg.categories.getList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = pwg.categories.getList.swift; path = piwigoKit/Network/pwg.categories/pwg.categories.getList.swift; sourceTree = SOURCE_ROOT; }; AD8709AA259A8E66008C4E4C /* Help04ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Help04ViewController.swift; sourceTree = ""; }; + AD8A1E7C28846E1300752948 /* Help08ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Help08ViewController.swift; sourceTree = ""; }; + AD8A1E7E288478FA00752948 /* help08-top.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "help08-top.png"; sourceTree = ""; }; + AD8A1E7F288478FA00752948 /* help08-bot.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "help08-bot.png"; sourceTree = ""; }; AD8D212726ACC15F0008E907 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = Base; path = Base.lproj/InAppIntents.intentdefinition; sourceTree = ""; }; AD8D212A26ACC1660008E907 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InAppIntents.strings; sourceTree = ""; }; AD8D212E26ACC1700008E907 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/InAppIntents.strings; sourceTree = ""; }; @@ -790,6 +795,7 @@ ADEAFB8E25F8198800EEDB1D /* ColorPaletteViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ColorPaletteViewController.storyboard; sourceTree = ""; }; ADEC6B022455A3520011527C /* LocalAlbumsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalAlbumsProvider.swift; sourceTree = ""; }; ADEC6B042455BC6F0011527C /* LocalAlbumsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalAlbumsTableViewCell.swift; sourceTree = ""; }; + ADEEAB6A289410AD00825C7D /* AlbumViewController+DataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AlbumViewController+DataSource.swift"; sourceTree = ""; }; ADEEC5D228560DF00065BA6D /* AlbumViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlbumViewController.swift; sourceTree = ""; }; ADEEC5D4285619120065BA6D /* AlbumViewController+Menus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AlbumViewController+Menus.swift"; sourceTree = ""; }; ADEEC5D6285640290065BA6D /* AlbumViewController+MenusOld.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AlbumViewController+MenusOld.swift"; sourceTree = ""; }; @@ -1115,6 +1121,7 @@ AD5A31642847F61700948FEE /* Extensions */ = { isa = PBXGroup; children = ( + ADEEAB6A289410AD00825C7D /* AlbumViewController+DataSource.swift */, ADEEC5D4285619120065BA6D /* AlbumViewController+Menus.swift */, ADC69F22285B7C40009BF9AF /* AlbumViewController+Buttons.swift */, ADEEC5D6285640290065BA6D /* AlbumViewController+MenusOld.swift */, @@ -1281,6 +1288,7 @@ ADC74CCD259C9E9C00581ADE /* Help05ViewController.swift */, AD3CD639259DE34C000C26ED /* Help06ViewController.swift */, AD8D214926B094DC0008E907 /* Help07ViewController.swift */, + AD8A1E7C28846E1300752948 /* Help08ViewController.swift */, AD61D2F92571555A00B8DEA0 /* HelpViewController.storyboard */, ); path = Help; @@ -1302,6 +1310,8 @@ AD8D217826B0B16A0008E907 /* help05-top.png */, AD8D217526B0B1690008E907 /* help06.png */, AD8D217726B0B16A0008E907 /* help07-top.png */, + AD8A1E7F288478FA00752948 /* help08-bot.png */, + AD8A1E7E288478FA00752948 /* help08-top.png */, AD96F42F2748601D004C8DFF /* piwigo.png */, ); path = Images; @@ -1696,7 +1706,6 @@ AD91127B28146B6C002FB78F /* SceneConfigurations.swift */, AD91127D28154CC2002FB78F /* SceneDelegate+StateRestoration.swift */, AD767BD52680B4E200EBD6E8 /* KeychainUtilitiesObjc.swift */, - AD3FF5F52683B49900D2F52A /* PwgNotificationsObjc.swift */, ); path = "Supporting Files"; sourceTree = ""; @@ -2098,6 +2107,7 @@ AD311FFA27CB7B730044AC5A /* LoginViewController.storyboard in Resources */, ADC80E4823BDCBAA003A6960 /* EditImageThumbCollectionViewCell.xib in Resources */, AD42D08324448F2400F0BAC1 /* LocalAlbumsViewController.storyboard in Resources */, + AD8A1E80288478FA00752948 /* help08-top.png in Resources */, ADE03D3025FCC1B7002F5C7B /* ColorPaletteViewControllerOld.storyboard in Resources */, ADC8167D244B5FA800650223 /* LocalImagesViewController.storyboard in Resources */, AD3207E9240AD93900F00FEB /* PrivacyPolicyViewController.storyboard in Resources */, @@ -2114,6 +2124,7 @@ ADFA89042438CF4500F73F0F /* ShareMetadataViewController.storyboard in Resources */, ADD741F82699976100B47056 /* UploadPhotoSizeViewController.storyboard in Resources */, AD6FD1FA24BEFFAA009AA3B7 /* UploadSwitchViewController.storyboard in Resources */, + AD8A1E81288478FA00752948 /* help08-bot.png in Resources */, ADC019742471A70F00532A81 /* UploadQueueViewController.storyboard in Resources */, ADBE9515279DC61700397426 /* AlbumTableViewCell.xib in Resources */, AD8F4B8B23F04B8C009483B6 /* TagSelectorViewController.storyboard in Resources */, @@ -2385,6 +2396,7 @@ ADF8AE7A24A8A6EB00F86515 /* CategoryImageSort.swift in Sources */, AD2B0A19243D063E00AF1FEE /* CategorySortViewController.swift in Sources */, AD074F6623F8498B00D6016A /* ClearCache.swift in Sources */, + AD8A1E7D28846E1300752948 /* Help08ViewController.swift in Sources */, ADEAFB8D25F8182C00EEDB1D /* ColorPaletteViewController.swift in Sources */, AD2B0A17243D00CD00AF1FEE /* DefaultAlbumThumbnailSizeViewController.swift in Sources */, ADA24DB1243A692200864D1F /* DefaultImageThumbnailSizeViewController.swift in Sources */, @@ -2400,6 +2412,7 @@ ADC3280B2480311100D5D11D /* LocalAlbumsMoreTableViewCell.swift in Sources */, ADC328072480238300D5D11D /* LocalAlbumsNoDatesTableViewCell.swift in Sources */, ADEC6B052455BC6F0011527C /* LocalAlbumsTableViewCell.swift in Sources */, + ADEEAB6B289410AD00825C7D /* AlbumViewController+DataSource.swift in Sources */, AD42D08124448B7C00F0BAC1 /* LocalAlbumsViewController.swift in Sources */, AD42D08524449FF000F0BAC1 /* LocalImageCollectionViewCell.swift in Sources */, ADC8FAAA244C7307006BDA6A /* LocalImagesFooterReusableView.swift in Sources */, @@ -2460,7 +2473,6 @@ AD3369BF23F035F700F3FA80 /* TagSelectorViewController.swift in Sources */, ADEA26A8285FA2C300B6C9A0 /* ImageViewController+AlbumThumnail.swift in Sources */, ADF26FBF24C200040036E778 /* TagTableViewCell.swift in Sources */, - AD3FF5F82683B5C700D2F52A /* PwgNotificationsObjc.swift in Sources */, ADF26FC024C200040036E778 /* TagsViewController.swift in Sources */, AD0ED1042441F65B00C69178 /* TextFieldTableViewCell.swift in Sources */, AD58F77F24EFC62F00ECF6BD /* UploadImageHeaderView.swift in Sources */, @@ -3185,7 +3197,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.12.1; + MARKETING_VERSION = 2.12.2; OTHER_LDFLAGS = ( "$(inherited)", "-all_load", @@ -3247,7 +3259,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.12.1; + MARKETING_VERSION = 2.12.2; OTHER_LDFLAGS = ( "$(inherited)", "-all_load", diff --git a/piwigo.xcodeproj/xcshareddata/xcschemes/piwigo.xcscheme b/piwigo.xcodeproj/xcshareddata/xcschemes/piwigo.xcscheme index 17f3ba860..668c52748 100644 --- a/piwigo.xcodeproj/xcshareddata/xcschemes/piwigo.xcscheme +++ b/piwigo.xcodeproj/xcshareddata/xcschemes/piwigo.xcscheme @@ -46,6 +46,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + enableASanStackUseAfterReturn = "YES" + enableUBSanitizer = "YES" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" @@ -70,9 +72,16 @@ + isEnabled = "YES"> + + + + diff --git a/piwigo/Album/AlbumUtilities.swift b/piwigo/Album/AlbumUtilities.swift index 06c301586..5f7019d42 100644 --- a/piwigo/Album/AlbumUtilities.swift +++ b/piwigo/Album/AlbumUtilities.swift @@ -789,7 +789,16 @@ class AlbumUtilities: NSObject { } - // MARK: - Album/Images Collections | Footers + // MARK: - Album/Images Collections | Headers & Footers + static func headerLegend(for categoryId: Int) -> NSAttributedString { + if let album = CategoriesData.sharedInstance().getCategoryById(categoryId), + let comment = album.comment, comment.isEmpty == false { + return comment.htmlToAttributedString + } else { + return NSAttributedString() + } + } + static func footerLegend(for nberOfImages: Int) -> String { var legend = "" if nberOfImages == NSNotFound { @@ -814,4 +823,26 @@ class AlbumUtilities: NSObject { } return legend } + + + // MARK: - Favorites + static func loadFavoritesInBckg() { + DispatchQueue.global(qos: .default).async { + // Should we load favorites? + if NetworkVars.hasGuestRights { return } + if "2.10.0".compare(NetworkVars.pwgVersion, options: .numeric) == .orderedDescending { return } + + // Initialise favorites album + if let favoritesAlbum = PiwigoAlbumData(id: kPiwigoFavoritesCategoryId, andQuery: "") { + CategoriesData.sharedInstance().updateCategories([favoritesAlbum]) + } + + // Load favorites data in the background with dedicated URL session + CategoriesData.sharedInstance().getCategoryById(kPiwigoFavoritesCategoryId).loadAllCategoryImageData( + withSort: kPiwigoSortObjc(rawValue: UInt32(AlbumVars.shared.defaultSort)), + forProgress: nil, + onCompletion: nil, + onFailure: nil) + } + } } diff --git a/piwigo/Album/AlbumViewController.swift b/piwigo/Album/AlbumViewController.swift index 8d1836e66..d72770f1d 100644 --- a/piwigo/Album/AlbumViewController.swift +++ b/piwigo/Album/AlbumViewController.swift @@ -32,6 +32,7 @@ class AlbumViewController: UIViewController, UICollectionViewDelegate, UICollect var imagesCollection: UICollectionView? var albumData: AlbumData? + var albumDescription = NSAttributedString() var userHasUploadRights = false private var didScrollToImageIndex = 0 private var imageOfInterest = IndexPath(item: 0, section: 1) @@ -82,8 +83,8 @@ class AlbumViewController: UIViewController, UICollectionViewDelegate, UICollect } else { // Fallback on earlier versions discoverBarButton = UIBarButtonItem(image: UIImage(named: "action"), landscapeImagePhone: UIImage(named: "actionCompact"), style: .plain, target: self, action: #selector(discoverMenuOld)) - discoverBarButton?.accessibilityIdentifier = "discover" } + discoverBarButton?.accessibilityIdentifier = "discover" // For iOS 11 and later: place search bar in navigation bar for root album if #available(iOS 11.0, *) { @@ -107,6 +108,7 @@ class AlbumViewController: UIViewController, UICollectionViewDelegate, UICollect imagesCollection?.translatesAutoresizingMaskIntoConstraints = false imagesCollection?.alwaysBounceVertical = true imagesCollection?.showsVerticalScrollIndicator = true + imagesCollection?.backgroundColor = UIColor.clear imagesCollection?.dataSource = self imagesCollection?.delegate = self @@ -134,7 +136,9 @@ class AlbumViewController: UIViewController, UICollectionViewDelegate, UICollect // "Add" button above collection view and other buttons addButton = getAddButton() - view.addSubview(addButton) + if let imagesCollection = imagesCollection { + view.insertSubview(addButton, aboveSubview: imagesCollection) + } // "Upload Queue" button above collection view uploadQueueButton = getUploadQueueButton() @@ -305,7 +309,6 @@ class AlbumViewController: UIViewController, UICollectionViewDelegate, UICollect } // Collection view - imagesCollection?.backgroundColor = UIColor.clear imagesCollection?.indicatorStyle = AppVars.shared.isDarkPaletteActive ? .white : .black let headers = imagesCollection?.visibleSupplementaryViews(ofKind: UICollectionView.elementKindSectionHeader) if (headers?.count ?? 0) > 0 { @@ -337,11 +340,20 @@ class AlbumViewController: UIViewController, UICollectionViewDelegate, UICollect // Initialise data source if categoryId != 0 { albumData = AlbumData(categoryId: categoryId, andQuery: "") + albumDescription = AlbumUtilities.headerLegend(for: categoryId) } - + // Set colors, fonts, etc. applyColorPalette() + // Always open this view with a navigation bar + // (might have been hidden during Image Previewing) + navigationController?.setNavigationBarHidden(false, animated: true) + + // Set navigation bar buttons + initButtonsInPreviewMode() + updateButtonsInPreviewMode() + // Register upload manager changes NotificationCenter.default.addObserver(self, selector: #selector(updateNberOfUploads(_:)), name: .pwgLeftUploads, object: nil) @@ -353,8 +365,8 @@ class AlbumViewController: UIViewController, UICollectionViewDelegate, UICollect let userInfo = ["currentCategoryId": NSNumber(value: categoryId)] NotificationCenter.default.post(name: NSNotification.Name(rawValue: kPiwigoNotificationChangedCurrentCategory), object: nil, userInfo: userInfo) - // Display the album/images collection - if categoryId < 0 { // i.e. smart albums + // If displaying smart album —> reload images + if categoryId < 0 { // Load, sort images and reload collection let oldImageList = albumData?.images ?? [] albumData?.updateImageSort(kPiwigoSortObjc(rawValue: UInt32(AlbumVars.shared.defaultSort)), onCompletion: { [self] in @@ -364,18 +376,10 @@ class AlbumViewController: UIViewController, UICollectionViewDelegate, UICollect }, onFailure: { [self] _, error in dismissPiwigoError(withTitle: NSLocalizedString("albumPhotoError_title", comment: "Get Album Photos Error"), message: NSLocalizedString("albumPhotoError_message", comment: "Failed to get album photos (corrupt image in your album?)"), errorMessage: error?.localizedDescription ?? "") { } }) - } - else { + } else { // Images will be loaded if needed after displaying cells imagesCollection?.reloadData() } - - // Always open this view with a navigation bar - // (might have been hidden during Image Previewing) - navigationController?.setNavigationBarHidden(false, animated: true) - - // Set navigation bar buttons - updateButtonsInPreviewMode() } override func viewDidAppear(_ animated: Bool) { @@ -396,6 +400,62 @@ class AlbumViewController: UIViewController, UICollectionViewDelegate, UICollect } } + // Stop here if app is reloading album data + if AppVars.shared.isReloadingData { + return + } + + // Determine for how long the session was open + /// Piwigo 11 session duration defaults to an hour. + let timeSinceLastLogin = NetworkVars.dateOfLastLogin.timeIntervalSinceNow + let allAlbums = CategoriesData.sharedInstance().allCategories?.filter({ $0.numberOfImages != NSNotFound}) + AppVars.shared.nberOfAlbumsInCache = allAlbums?.count ?? 0 + if NetworkVars.serverPath.isEmpty == false, NetworkVars.username.isEmpty == false, + ((timeSinceLastLogin < TimeInterval(-1800)) || AppVars.shared.nberOfAlbumsInCache == 0) { + // Check if we have album data + AppVars.shared.isReloadingData = true + if AppVars.shared.nberOfAlbumsInCache == 0 { + reloginAndReloadAlbumData { + AppVars.shared.isReloadingData = false + } + } else { + // Check if session is active in the background + let pwgToken = NetworkVars.pwgToken + LoginUtilities.sessionGetStatus { [unowned self] in + if NetworkVars.pwgToken != pwgToken { + reloginAndReloadAlbumData { + AppVars.shared.isReloadingData = false + } + } + } failure: { _ in + print("••> Failed to check session status…") + AppVars.shared.isReloadingData = false + // Will re-check later… + } + } + return + } + + if NetworkVars.serverPath.isEmpty == false, NetworkVars.username.isEmpty == true, + AppVars.shared.nberOfAlbumsInCache == 0 { + // Apparently this is the first time we load album data as Guest + /// - Reload album data + print("••> Reload album data…") + AppVars.shared.isReloadingData = true + reloadAlbumData { + AppVars.shared.isReloadingData = false + } + return + } + + // Resume upload operations in background queue + // and update badge, upload button of album navigator + if UploadManager.shared.isPaused { + UploadManager.shared.backgroundQueue.async { + UploadManager.shared.resumeAll() + } + } + // Should we highlight the image of interest? if categoryId != 0, (albumData?.images.count ?? 0) > 0, imageOfInterest.item != 0 { @@ -415,23 +475,30 @@ class AlbumViewController: UIViewController, UICollectionViewDelegate, UICollect } // Determine which help pages should be presented - var displayHelpPagesWithIndex = [Int]() + var displayHelpPagesWithID = [UInt16]() if categoryId != 0, (albumData?.images.count ?? 0) > 5, - (AppVars.shared.didWatchHelpViews & 0b0000000000000001) == 0 { - displayHelpPagesWithIndex.append(0) // i.e. multiple selection of images - } - let numberOfAlbums = CategoriesData.sharedInstance().getCategoriesForParentCategory(categoryId).count - if categoryId != 0, numberOfAlbums > 2, NetworkVars.hasAdminRights, - (AppVars.shared.didWatchHelpViews & 0b0000000000000100) == 0 { - displayHelpPagesWithIndex.append(2) // i.e. management of albums - } - if displayHelpPagesWithIndex.count > 0 { + (AppVars.shared.didWatchHelpViews & 0b00000000_00000001) == 0 { + displayHelpPagesWithID.append(1) // i.e. multiple selection of images + } + if categoryId != 0, + let albums = CategoriesData.sharedInstance().getCategoriesForParentCategory(categoryId), + albums.count > 2, NetworkVars.hasAdminRights, + (AppVars.shared.didWatchHelpViews & 0b00000000_00000100) == 0 { + displayHelpPagesWithID.append(3) // i.e. management of albums + } + if categoryId != 0, + let album = CategoriesData.sharedInstance().getCategoryById(categoryId), + let parents = album.upperCategories, parents.count > 2, + (AppVars.shared.didWatchHelpViews & 0b00000000_10000000) == 0 { + displayHelpPagesWithID.append(8) // i.e. back to parent album + } + if displayHelpPagesWithID.count > 0 { // Present unseen help views let helpSB = UIStoryboard(name: "HelpViewController", bundle: nil) guard let helpVC = helpSB.instantiateViewController(withIdentifier: "HelpViewController") as? HelpViewController else { fatalError("No HelpViewController available!") } - helpVC.displayHelpPagesWithIndex = displayHelpPagesWithIndex + helpVC.displayHelpPagesWithID = displayHelpPagesWithID if UIDevice.current.userInterfaceIdiom == .phone { helpVC.popoverPresentationController?.permittedArrowDirections = .up present(helpVC, animated: true) @@ -475,30 +542,11 @@ class AlbumViewController: UIViewController, UICollectionViewDelegate, UICollect initButtonsInSelectionMode() } else { // Update position of buttons (recalculated after device rotation) - let xPos = UIScreen.main.bounds.size.width - 3 * kRadius - let yPos = UIScreen.main.bounds.size.height - 3 * kRadius - addButton.frame = CGRect(x: xPos, y: yPos, width: 2 * kRadius, height: 2 * kRadius) - if addButton.isHidden { - homeAlbumButton.frame = addButton.frame - } else { - homeAlbumButton?.frame = CGRect(x: xPos - 3 * kRadius, y: yPos, width: 2 * kRadius, height: 2 * kRadius) - } - if uploadQueueButton?.isHidden ?? false { - uploadQueueButton?.frame = addButton.frame - } else { - // Elongate the button if needed - var botFrame = uploadQueueButton?.frame - botFrame?.origin.x = xPos - 3 * kRadius - ((uploadQueueButton?.frame.size.width ?? 0.0) - 2 * kRadius) - botFrame?.origin.y = yPos - uploadQueueButton?.frame = botFrame ?? CGRect.zero - } - if createAlbumButton?.isHidden ?? false { - createAlbumButton?.frame = addButton.frame - uploadImagesButton?.frame = addButton.frame - } else { - createAlbumButton?.frame = CGRect(x: xPos - 3 * kRadius * cos(15 * kDeg2Rad), y: yPos - 3 * kRadius * sin(15 * kDeg2Rad), width: 1.72 * kRadius, height: 1.72 * kRadius) - uploadImagesButton?.frame = CGRect(x: xPos - 3 * kRadius * cos(75 * kDeg2Rad), y: yPos - 3 * kRadius * sin(75 * kDeg2Rad), width: 1.72 * kRadius, height: 1.72 * kRadius) - } + addButton?.frame = getAddButtonFrame() + homeAlbumButton?.frame = getHomeAlbumButtonFrame(isHidden: homeAlbumButton?.isHidden ?? true) + uploadQueueButton?.frame = getUploadQueueButtonFrame(isHidden: uploadQueueButton?.isHidden ?? true) + createAlbumButton?.frame = getCreateAlbumButtonFrame(isHidden: createAlbumButton?.isHidden ?? true) + uploadImagesButton?.frame = getUploadImagesButtonFrame(isHidden: uploadImagesButton?.isHidden ?? true) } }) } @@ -551,124 +599,26 @@ class AlbumViewController: UIViewController, UICollectionViewDelegate, UICollect // Unregister upload progress NotificationCenter.default.removeObserver(self, name: .pwgUploadProgress, object: nil) - - // Clear memory - imagesCollection = nil - albumData = nil } // MARK: - Category Data @objc func refresh(_ refreshControl: UIRefreshControl?) { - // Display HUD while downloading albums data recursively - navigationController?.showPiwigoHUD( - withTitle: NSLocalizedString("loadingHUD_label", comment: "Loading…"), - detail: NSLocalizedString("tabBar_albums", comment: "Albums"), - buttonTitle: "", buttonTarget: nil, buttonSelector: nil, inMode: .indeterminate) - - // Load category data in recursive mode - AlbumUtilities.getAlbums { didUpdateCats in - DispatchQueue.main.async { [self] in - // Check data source and reload collection if needed - checkDataSource(withChangedCategories: didUpdateCats) { [self] in - // End refreshing - if #available(iOS 10.0, *) { - if imagesCollection?.refreshControl != nil { - imagesCollection?.refreshControl?.endRefreshing() - } - } else { - if self.refreshControl != nil { - self.refreshControl?.endRefreshing() - } - } - - // Hide HUD - navigationController?.hidePiwigoHUD() { } - } - } - } failure: { error in - DispatchQueue.main.async { [self] in - // Set navigation bar buttons - initButtonsInSelectionMode() - // Hide HUD if needed - navigationController?.hidePiwigoHUD() { [self] in - dismissPiwigoError(withTitle: "", message: error.localizedDescription) { } + reloginAndReloadAlbumData { [self] in + // End refreshing + if #available(iOS 10.0, *) { + if imagesCollection?.refreshControl != nil { + imagesCollection?.refreshControl?.endRefreshing() } - } - } - } - - func checkDataSource(withChangedCategories didChange: Bool, - completion: @escaping () -> Void) { - print(String(format: "checkDataSource...=> ID:%ld - Categories did change:%@", - categoryId, didChange ? "YES" : "NO")) - - // Does this album still exist? - let album = CategoriesData.sharedInstance().getCategoryById(categoryId) - if categoryId > 0, albumData == nil { - // This album does not exist anymore - let VCs = navigationController?.children - var index = (VCs?.count ?? 0) - 1 - while index >= 0 { - if let vc = VCs?[index] as? AlbumViewController { - if vc.categoryId == 0 || CategoriesData.sharedInstance().getCategoryById(vc.categoryId) != nil { - // Present the album - navigationController?.popToViewController(vc, animated: true) - completion() - return - } - } - index -= 1 - } - // We did not find a parent album — should never happen… - completion() - return - } - - // Root album -> reload collection - if categoryId == 0 { - if didChange { - // Reload album collection - imagesCollection?.reloadData() - // Set navigation bar buttons - updateButtonsInPreviewMode() - } - completion() - return - } - - // Other album -> Reload albums - if didChange, categoryId >= 0 { - // Reload album collection - imagesCollection?.reloadSections(IndexSet(integer: 0)) - // Set navigation bar buttons - updateButtonsInPreviewMode() - } - - // Other album —> If the number of images in cache is null, reload collection - if album == nil || album?.imageList?.count == 0 { - // Something did change… reset album data - albumData = AlbumData(categoryId: categoryId, andQuery: "") - // Reload collection - if categoryId < 0 { - // Load, sort images and reload collection - albumData?.updateImageSort(kPiwigoSortObjc(rawValue: UInt32(AlbumVars.shared.defaultSort)), onCompletion: { [self] in - // Reset navigation bar buttons after image load - updateButtonsInPreviewMode() - imagesCollection?.reloadData() - }, onFailure: { [self] _, error in - dismissPiwigoError(withTitle: NSLocalizedString("albumPhotoError_title", comment: "Get Album Photos Error"), message: NSLocalizedString("albumPhotoError_message", comment: "Failed to get album photos (corrupt image in your album?)"), errorMessage: error?.localizedDescription ?? "") { } - }) } else { - imagesCollection?.reloadData() + if refreshControl != nil { + refreshControl?.endRefreshing() + } } - // Cancel selection - cancelSelect() } - completion() } - func reloadImagesCollection(from oldImages: [PiwigoImageData]) { + private func reloadImagesCollection(from oldImages: [PiwigoImageData]) { if oldImages.count != albumData?.images?.count ?? NSNotFound { // List of images has changed imagesCollection?.reloadData() @@ -873,10 +823,7 @@ class AlbumViewController: UIViewController, UICollectionViewDelegate, UICollect if kind == UICollectionView.elementKindSectionHeader { header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "CategoryHeader", for: indexPath) as? AlbumHeaderReusableView - if let albumData = CategoriesData.sharedInstance().getCategoryById(categoryId), - albumData.comment.count > 0 { - header?.commentLabel?.text = albumData.comment - } + header?.commentLabel?.attributedText = albumDescription header?.commentLabel?.textColor = UIColor.piwigoColorHeader() return header! } @@ -930,17 +877,14 @@ class AlbumViewController: UIViewController, UICollectionViewDelegate, UICollect guard let albumData = CategoriesData.sharedInstance().getCategoryById(categoryId) else { return CGSize.zero } - if let desc = albumData.comment, !desc.isEmpty, + if let desc = albumData.comment, desc.isEmpty == false, collectionView.frame.size.width - 30.0 > 0 { - let header = albumData.comment ?? "" - let attributes = [NSAttributedString.Key.font: UIFont.piwigoFontNormal()] let context = NSStringDrawingContext() context.minimumScaleFactor = 1.0 - let headerRect = header.boundingRect( + let headerRect = albumDescription.boundingRect( with: CGSize(width: collectionView.frame.size.width - 30.0, height: CGFloat.greatestFiniteMagnitude), - options: .usesLineFragmentOrigin, - attributes: attributes, context: context) + options: .usesLineFragmentOrigin, context: context) return CGSize(width: collectionView.frame.size.width - 30.0, height: ceil(headerRect.size.height)) } @@ -1097,7 +1041,7 @@ class AlbumViewController: UIViewController, UICollectionViewDelegate, UICollect // Configure cell with album data let albumData = parentAlbums[indexPath.item] - cell.config(withAlbumData: albumData) + cell.config(withAlbumData: albumData, description: albumDescription) // Disable category cells in Image selection mode if isSelect { @@ -1272,11 +1216,12 @@ class AlbumViewController: UIViewController, UICollectionViewDelegate, UICollect imagesCollection?.reloadItems(at: indexPaths) // Display HUD if it will take more than a second to load image data + let didProgress = (newDownloadedImageCount != downloadedImageCount) let diff: CFAbsoluteTime = Double((CFAbsoluteTimeGetCurrent() - start)) * 1000.0 let perImage = abs(Float(Double(diff) / Double(newDownloadedImageCount - downloadedImageCount))) let left: Double = Double(perImage) * Double(max(0, (didScrollToImageIndex - newDownloadedImageCount))) print(String(format: "expected time: %.2f ms (diff: %.0f, perImage: %.0f)", left, diff, perImage)) - if left > 1000.0 { + if left > 1000.0, didProgress { if view.viewWithTag(loadingViewTag) == nil { showPiwigoHUD(withTitle: NSLocalizedString("loadingHUD_label", comment: "Loading…"), detail: "", buttonTitle: "", buttonTarget: nil, buttonSelector: nil, inMode: .annularDeterminate) } else { @@ -1290,7 +1235,20 @@ class AlbumViewController: UIViewController, UICollectionViewDelegate, UICollect // Should we continue loading images? print(String(format: "==> Should we continue loading images? (scrolled to %ld)", didScrollToImageIndex)) if didScrollToImageIndex >= newDownloadedImageCount { - needToLoadMoreImages() + if didProgress { + // Continue loadding images + needToLoadMoreImages() + } else { + // Re-login before continuing to load images + LoginUtilities.reloginAndRetry() { [self] in + DispatchQueue.main.async { [self] in + needToLoadMoreImages() + } + } failure: { [self] error in + let title = NSLocalizedString("imageDetailsFetchError_title", comment: "Image Details Fetch Failed") + dismissPiwigoError(withTitle: title, completion: {}) + } + } } }) }, onFailure: nil) diff --git a/piwigo/Album/Cells/AlbumCollectionViewCell.swift b/piwigo/Album/Cells/AlbumCollectionViewCell.swift index e0e2e0d22..4600cde97 100644 --- a/piwigo/Album/Cells/AlbumCollectionViewCell.swift +++ b/piwigo/Album/Cells/AlbumCollectionViewCell.swift @@ -17,12 +17,12 @@ protocol AlbumCollectionViewCellDelegate: NSObjectProtocol { func removeCategory(_ albumCell: AlbumCollectionViewCell?) } -@objc class AlbumCollectionViewCell: UICollectionViewCell { weak var categoryDelegate: AlbumCollectionViewCellDelegate? var albumData: PiwigoAlbumData? + private var albumDescription = NSAttributedString() private var tableView: UITableView? private var renameAlert: UIAlertController? private var renameAction: UIAlertAction? @@ -57,8 +57,8 @@ class AlbumCollectionViewCell: UICollectionViewCell tableView?.reloadData() } - @objc - func config(withAlbumData albumData: PiwigoAlbumData? = nil) { + func config(withAlbumData albumData: PiwigoAlbumData? = nil, + description: NSAttributedString = NSAttributedString()) { self.albumData = albumData tableView?.reloadData() } @@ -218,7 +218,7 @@ class AlbumCollectionViewCell: UICollectionViewCell // Update cell and hide swipe buttons let cell = tableView?.cellForRow(at: IndexPath(row: 0, section: 0)) as? AlbumTableViewCell - cell?.config(withAlbumData: albumData) + cell?.config(withAlbumData: albumData, description: albumDescription) cell?.hideSwipe(animated: true) } } @@ -492,7 +492,7 @@ extension AlbumCollectionViewCell: UITableViewDataSource } // Configure cell - cell.config(withAlbumData: albumData) + cell.config(withAlbumData: albumData, description: albumDescription) // Album modifications are possible only if data are known if albumData != nil { diff --git a/piwigo/Album/Cells/AlbumTableViewCell.swift b/piwigo/Album/Cells/AlbumTableViewCell.swift index 16f80638a..9ed8463eb 100644 --- a/piwigo/Album/Cells/AlbumTableViewCell.swift +++ b/piwigo/Album/Cells/AlbumTableViewCell.swift @@ -11,7 +11,6 @@ import UIKit import piwigoKit -@objc class AlbumTableViewCell: MGSwipeTableCell { @IBOutlet weak var backgroundImage: UIImageView! @@ -24,8 +23,7 @@ class AlbumTableViewCell: MGSwipeTableCell { @IBOutlet weak var recentBckg: UIImageView! @IBOutlet weak var recentImage: UIImageView! - @objc - func config(withAlbumData albumData: PiwigoAlbumData?) { + func config(withAlbumData albumData: PiwigoAlbumData?, description: NSAttributedString) { // General settings backgroundColor = UIColor.piwigoColorBackground() contentView.backgroundColor = UIColor.piwigoColorCellBackground() @@ -38,8 +36,8 @@ class AlbumTableViewCell: MGSwipeTableCell { albumName.font = albumName.font.withSize(UIFont.fontSizeFor(label: albumName, nberLines: 2)) // Album comment - if let comment = albumData?.comment, comment.isEmpty == false { - albumComment.text = comment + if description.isEqual(to: NSAttributedString()) == false { + albumComment.attributedText = description albumComment.textColor = UIColor.piwigoColorText() } else { // No comment diff --git a/piwigo/Album/Cells/AlbumTableViewCell.xib b/piwigo/Album/Cells/AlbumTableViewCell.xib index 48df9f87e..31c679b55 100644 --- a/piwigo/Album/Cells/AlbumTableViewCell.xib +++ b/piwigo/Album/Cells/AlbumTableViewCell.xib @@ -3,7 +3,7 @@ - + @@ -70,11 +70,17 @@ -