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 @@
+
+
+
+
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 @@
-