Tidy up on the themes view

This commit is contained in:
Stuart Breckenridge
2022-12-20 22:04:04 +08:00
parent 53e49aa699
commit fe5a7d185b
14 changed files with 77 additions and 1642 deletions

View File

@@ -44,7 +44,7 @@ struct ArticleThemeManagerView: View {
switch result {
case .success(let success):
do {
let theme = try ArticleTheme(path: success.path, isAppTheme: true)
let theme = try ArticleTheme(path: success.path, isAppTheme: false)
showImportConfirmationAlert = (theme, true)
} catch {
showImportErrorAlert = (error, true)
@@ -55,7 +55,7 @@ struct ArticleThemeManagerView: View {
}
.alert(Text("DELETE_THEME_ALERT_TITLE_\(showDeleteConfirmation.0)", tableName: "Settings"), isPresented: $showDeleteConfirmation.1, actions: {
Button(role: .destructive) {
ArticleThemesManager.shared.deleteTheme(themeName: showDeleteConfirmation.0)
themeManager.deleteTheme(themeName: showDeleteConfirmation.0)
} label: {
Text("DELETE_THEME_BUTTON_TITLE", tableName: "Buttons")
}
@@ -73,14 +73,27 @@ struct ArticleThemeManagerView: View {
actions: {
Button {
do {
try ArticleThemesManager.shared.importTheme(filename: showImportConfirmationAlert.0!.path!)
showImportSuccessAlert = true
if themeManager.themeExists(filename: showImportConfirmationAlert.0!.path!) {
if try! themeManager.articleThemeWithThemeName(showImportConfirmationAlert.0!.name).isAppTheme {
showImportErrorAlert = (LocalizedNetNewsWireError.duplicateDefaultTheme, true)
} else {
try themeManager.importTheme(filename: showImportConfirmationAlert.0!.path!)
showImportSuccessAlert = true
}
} else {
try themeManager.importTheme(filename: showImportConfirmationAlert.0!.path!)
showImportSuccessAlert = true
}
} catch {
showImportErrorAlert = (error, true)
}
} label: {
Text("IMPORT_THEME_BUTTON_TITLE", tableName: "Buttons")
let exists = themeManager.themeExists(filename: showImportConfirmationAlert.0?.path ?? "")
if exists == true {
Text("IMPORT_AND_OVERWRITE_THEME_BUTTON_TITLE", tableName: "Buttons")
} else {
Text("IMPORT_THEME_BUTTON_TITLE", tableName: "Buttons")
}
}
Button(role: .cancel) {
@@ -89,7 +102,12 @@ struct ArticleThemeManagerView: View {
Text("CANCEL_BUTTON_TITLE", tableName: "Buttons")
}
}, message: {
Text("IMPORT_THEME_CONFIRMATION_MESSAGE_\(showImportConfirmationAlert.0?.name ?? "")_\(showImportConfirmationAlert.0?.creatorName ?? "")", tableName: "Settings")
let exists = themeManager.themeExists(filename: showImportConfirmationAlert.0?.path ?? "")
if exists {
Text("IMPORT_AND_OVERWRITE_THEME_CONFIRMATION_MESSAGE_\(showImportConfirmationAlert.0?.name ?? "")", tableName: "Settings")
} else {
Text("IMPORT_THEME_CONFIRMATION_MESSAGE_\(showImportConfirmationAlert.0?.name ?? "")_\(showImportConfirmationAlert.0?.creatorName ?? "")", tableName: "Settings")
}
})
.alert(Text("IMPORT_THEME_SUCCESS_TITLE", tableName: "Settings"),
isPresented: $showImportSuccessAlert,
@@ -102,32 +120,52 @@ struct ArticleThemeManagerView: View {
}, message: {
Text("IMPORT_THEME_SUCCESS_MESSAGE_\(showImportConfirmationAlert.0?.name ?? "")", tableName: "Settings")
})
.alert(Text("ERROR_TITLE", tableName: "Errors"),
isPresented: $showImportErrorAlert.1,
actions: {
Button(role: .cancel) {
} label: {
Text("DISMISS_BUTTON_TITLE", tableName: "Buttons")
}
}, message: {
Text("\(showImportErrorAlert.0?.localizedDescription ?? "")")
})
}
func articleThemeRow(_ theme: String) -> some View {
Button {
ArticleThemesManager.shared.currentThemeName = theme
themeManager.currentThemeName = theme
} label: {
HStack {
Text(theme)
.foregroundColor(.primary)
VStack(alignment: .leading) {
Text(theme)
.foregroundColor(.primary)
if let articleTheme = try? themeManager.articleThemeWithThemeName(theme) {
Text("ARTICLE_THEME_CREATOR_\(articleTheme.creatorName)", tableName: "Settings")
.font(.caption)
.foregroundColor(.secondary)
}
}
Spacer()
if ArticleThemesManager.shared.currentThemeName == theme {
if themeManager.currentThemeName == theme {
Image(systemName: "checkmark")
.foregroundColor(Color(uiColor: AppAssets.primaryAccentColor))
}
}
}
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
if theme == "Default" || ArticleThemesManager.shared.currentThemeName == theme { }
else {
Button {
showDeleteConfirmation = (theme, true)
} label: {
Text("DELETE_BUTTON_TITLE", tableName: "Buttons")
Image(systemName: "trash")
if theme == themeManager.currentThemeName { }
if let currentTheme = try? themeManager.articleThemeWithThemeName(theme) {
if currentTheme.isAppTheme { } else {
Button {
showDeleteConfirmation = (theme, true)
} label: {
Text("DELETE_BUTTON_TITLE", tableName: "Buttons")
Image(systemName: "trash")
}
.tint(.red)
}
.tint(.red)
}
}
}

View File

@@ -1,150 +0,0 @@
//
// ArticleThemesTableViewController.swift
// NetNewsWire-iOS
//
// Created by Maurice Parker on 9/12/21.
// Copyright © 2021 Ranchero Software. All rights reserved.
//
import Foundation
import UniformTypeIdentifiers
import RSCore
import UIKit
import SwiftUI
struct ArticleThemesWrapper: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> ArticleThemesTableViewController {
let storyboard = UIStoryboard(name: "Settings", bundle: .main)
let controller = storyboard.instantiateViewController(withIdentifier: "ArticleThemesTableViewController") as! ArticleThemesTableViewController
context.coordinator.parentObserver = controller.observe(\.parent, changeHandler: { vc, _ in
vc.parent?.title = vc.title
vc.parent?.navigationItem.rightBarButtonItems = vc.navigationItem.rightBarButtonItems
})
return controller
}
func updateUIViewController(_ uiViewController: ArticleThemesTableViewController, context: Context) {
//
}
typealias UIViewControllerType = ArticleThemesTableViewController
class Coordinator {
var parentObserver: NSKeyValueObservation?
}
func makeCoordinator() -> Self.Coordinator { Coordinator() }
}
class ArticleThemesTableViewController: UITableViewController, Logging {
override func viewDidLoad() {
let importBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(importTheme(_:)));
importBarButtonItem.title = NSLocalizedString("Import Theme", comment: "Import Theme");
navigationItem.rightBarButtonItem = importBarButtonItem
NotificationCenter.default.addObserver(self, selector: #selector(articleThemeNamesDidChangeNotification(_:)), name: .ArticleThemeNamesDidChangeNotification, object: nil)
}
// MARK: Notifications
@objc func articleThemeNamesDidChangeNotification(_ note: Notification) {
tableView.reloadData()
}
@objc func importTheme(_ sender: Any?) {
let docPicker = UIDocumentPickerViewController(forOpeningContentTypes: [.nnwTheme], asCopy: true)
docPicker.delegate = self
docPicker.modalPresentationStyle = .formSheet
self.present(docPicker, animated: true)
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return ArticleThemesManager.shared.themeNames.count + 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let themeName: String
if indexPath.row == 0 {
themeName = ArticleTheme.defaultTheme.name
} else {
themeName = ArticleThemesManager.shared.themeNames[indexPath.row - 1]
}
cell.textLabel?.text = themeName
if themeName == ArticleThemesManager.shared.currentTheme.name {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath), let themeName = cell.textLabel?.text else { return }
ArticleThemesManager.shared.currentThemeName = themeName
navigationController?.popViewController(animated: true)
}
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
guard let cell = tableView.cellForRow(at: indexPath),
let themeName = cell.textLabel?.text else { return nil }
guard let theme = try? ArticleThemesManager.shared.articleThemeWithThemeName(themeName), !theme.isAppTheme else { return nil }
let deleteTitle = NSLocalizedString("Delete", comment: "Delete")
let deleteAction = UIContextualAction(style: .normal, title: deleteTitle) { [weak self] (action, view, completion) in
let title = NSLocalizedString("Delete Theme?", comment: "Delete Theme")
let localizedMessageText = NSLocalizedString("Are you sure you want to delete the theme “%@”?.", comment: "Delete Theme Message")
let message = NSString.localizedStringWithFormat(localizedMessageText as NSString, themeName) as String
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel")
let cancelAction = UIAlertAction(title: cancelTitle, style: .cancel) { action in
completion(true)
}
alertController.addAction(cancelAction)
let deleteTitle = NSLocalizedString("Delete", comment: "Delete")
let deleteAction = UIAlertAction(title: deleteTitle, style: .destructive) { action in
ArticleThemesManager.shared.deleteTheme(themeName: themeName)
completion(true)
}
alertController.addAction(deleteAction)
self?.present(alertController, animated: true)
}
deleteAction.image = AppAssets.trashImage
deleteAction.backgroundColor = UIColor.systemRed
return UISwipeActionsConfiguration(actions: [deleteAction])
}
}
// MARK: UIDocumentPickerDelegate
extension ArticleThemesTableViewController: UIDocumentPickerDelegate {
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard let url = urls.first else { return }
try ArticleThemeImporter.importTheme(controller: self, filename: url.standardizedFileURL.path)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,30 +0,0 @@
//
// SettingsAccountTableViewCell.swift
// NetNewsWire-iOS
//
// Created by Maurice Parker on 10/23/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import UIKit
class SettingsComboTableViewCell: VibrantTableViewCell {
@IBOutlet weak var comboImage: UIImageView!
@IBOutlet weak var comboNameLabel: UILabel!
override func updateVibrancy(animated: Bool) {
super.updateVibrancy(animated: animated)
updateLabelVibrancy(comboNameLabel, color: labelColor, animated: animated)
let tintColor = isHighlighted || isSelected ? AppAssets.vibrantTextColor : UIColor.label
if animated {
UIView.animate(withDuration: Self.duration) {
self.comboImage?.tintColor = tintColor
}
} else {
self.comboImage?.tintColor = tintColor
}
}
}

View File

@@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="JCb-QB-CrO" customClass="SettingsComboTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="JCb-QB-CrO" id="FzD-t2-JGy">
<rect key="frame" x="0.0" y="0.0" width="383" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="yiw-9t-gil">
<rect key="frame" x="12" y="11" width="22" height="22"/>
<constraints>
<constraint firstAttribute="width" constant="22" id="43E-Em-Z6O"/>
<constraint firstAttribute="height" constant="22" id="mTY-cQ-1R1"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TRx-RV-za8">
<rect key="frame" x="42" y="14" width="42" height="16"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="TRx-RV-za8" firstAttribute="leading" secondItem="yiw-9t-gil" secondAttribute="trailing" constant="8" symbolic="YES" id="RUN-Ol-xSl"/>
<constraint firstItem="TRx-RV-za8" firstAttribute="top" secondItem="FzD-t2-JGy" secondAttribute="top" constant="14" id="cze-hi-8Uh"/>
<constraint firstItem="yiw-9t-gil" firstAttribute="leading" secondItem="FzD-t2-JGy" secondAttribute="leading" constant="12" id="oU9-E3-lEt"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="TRx-RV-za8" secondAttribute="trailing" constant="8" id="sJ6-wr-JIw"/>
<constraint firstItem="yiw-9t-gil" firstAttribute="centerY" secondItem="FzD-t2-JGy" secondAttribute="centerY" id="tUD-tI-dgr"/>
<constraint firstAttribute="bottom" secondItem="TRx-RV-za8" secondAttribute="bottom" constant="14" id="zls-MW-Ffp"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="comboImage" destination="yiw-9t-gil" id="WqT-gf-Pwq"/>
<outlet property="comboNameLabel" destination="TRx-RV-za8" id="CX9-Cp-qZP"/>
</connections>
<point key="canvasLocation" x="7" y="-9"/>
</tableViewCell>
</objects>
</document>

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="SettingsTableViewCell" id="JCb-QB-CrO" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="JCb-QB-CrO" id="FzD-t2-JGy">
<rect key="frame" x="0.0" y="0.0" width="385.5" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</tableViewCellContentView>
<point key="canvasLocation" x="7" y="-9"/>
</tableViewCell>
</objects>
</document>