mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Tidy up on the themes view
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user