mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Merge branch 'main' into feat-1844-scroll-mark-as-read
This commit is contained in:
@@ -5,7 +5,7 @@ We welcome contributions!
|
||||
If you’d like to contribute:
|
||||
|
||||
1. File a ticket describing the bug you want to fix or feature you want to add. Or find an existing ticket.
|
||||
2. On the Slack group, bring it up on the #work channel for discussion (which may or may not include implementation discussion). **This is very important, because there might be things you need to know before you start work.**
|
||||
2. On the [Slack group](https://netnewswire.com/slack), bring it up on the #work channel for discussion (which may or may not include implementation discussion). **This is very important, because there might be things you need to know before you start work.**
|
||||
3. Once approved, then go for it. Write the code, then do a pull request. We’ll either have comments or we’ll merge it. (We might revise it afterward, of course.)
|
||||
|
||||
## Notes
|
||||
@@ -88,7 +88,7 @@ members of the project's leadership.
|
||||
### Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
available at [https://www.contributor-covenant.org/version/1/4/code-of-conduct/][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
[homepage]: https://www.contributor-covenant.org/
|
||||
[version]: https://www.contributor-covenant.org/version/1/4/code-of-conduct/
|
||||
|
||||
@@ -155,6 +155,7 @@ final class DetailWebViewController: NSViewController {
|
||||
|
||||
@objc func userDefaultsDidChange(_ note: Notification) {
|
||||
if articleTextSize != AppDefaults.shared.articleTextSize {
|
||||
articleTextSize = AppDefaults.shared.articleTextSize
|
||||
reloadHTMLMaintainingScrollPosition()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>UIAppFonts</key>
|
||||
<array>
|
||||
<string>AtkinsonHyperlegible-Regular.ttf</string>
|
||||
</array>
|
||||
<key>AppGroup</key>
|
||||
<string>group.$(ORGANIZATION_IDENTIFIER).NetNewsWire-Evergreen</string>
|
||||
<key>AppIdentifierPrefix</key>
|
||||
|
||||
@@ -136,6 +136,9 @@
|
||||
5126EE97226CB48A00C22AFC /* SceneCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5126EE96226CB48A00C22AFC /* SceneCoordinator.swift */; };
|
||||
5127B238222B4849006D641D /* DetailKeyboardDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5127B236222B4849006D641D /* DetailKeyboardDelegate.swift */; };
|
||||
5127B23A222B4849006D641D /* DetailKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5127B237222B4849006D641D /* DetailKeyboardShortcuts.plist */; };
|
||||
512955E72730BDF10041B863 /* AtkinsonHyperlegible-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 512955E62730BDF10041B863 /* AtkinsonHyperlegible-Regular.ttf */; };
|
||||
512955E82730BDF10041B863 /* AtkinsonHyperlegible-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 512955E62730BDF10041B863 /* AtkinsonHyperlegible-Regular.ttf */; };
|
||||
512955E92730BDF10041B863 /* AtkinsonHyperlegible-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 512955E62730BDF10041B863 /* AtkinsonHyperlegible-Regular.ttf */; };
|
||||
512AF9C2236ED52C0066F8BE /* ImageHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 512AF9C1236ED52C0066F8BE /* ImageHeaderView.swift */; };
|
||||
512AF9DD236F05230066F8BE /* InteractiveLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 512AF9DC236F05230066F8BE /* InteractiveLabel.swift */; };
|
||||
512D554423C804DE0023FFFA /* OpenInSafariActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 512D554323C804DE0023FFFA /* OpenInSafariActivity.swift */; };
|
||||
@@ -168,6 +171,9 @@
|
||||
5137C2E526F3F52D009EFEDB /* Sepia.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = 5137C2E326F3F52D009EFEDB /* Sepia.nnwtheme */; };
|
||||
5137C2E626F3F52D009EFEDB /* Sepia.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = 5137C2E326F3F52D009EFEDB /* Sepia.nnwtheme */; };
|
||||
5137C2EA26F63AE6009EFEDB /* ArticleThemeImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5137C2E926F63AE6009EFEDB /* ArticleThemeImporter.swift */; };
|
||||
51384DED2730CECC00C7997D /* Hyperlegible.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = 51384DEC2730CECC00C7997D /* Hyperlegible.nnwtheme */; };
|
||||
51384DEE2730CECC00C7997D /* Hyperlegible.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = 51384DEC2730CECC00C7997D /* Hyperlegible.nnwtheme */; };
|
||||
51384DEF2730CECC00C7997D /* Hyperlegible.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = 51384DEC2730CECC00C7997D /* Hyperlegible.nnwtheme */; };
|
||||
51386A8E25673277005F3762 /* AccountCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51386A8D25673276005F3762 /* AccountCell.swift */; };
|
||||
51386A8F25673277005F3762 /* AccountCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51386A8D25673276005F3762 /* AccountCell.swift */; };
|
||||
5138E93A24D33E5600AFF0FE /* RSTree in Frameworks */ = {isa = PBXBuildFile; productRef = 5138E93924D33E5600AFF0FE /* RSTree */; };
|
||||
@@ -1189,6 +1195,7 @@
|
||||
5126EE96226CB48A00C22AFC /* SceneCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneCoordinator.swift; sourceTree = "<group>"; };
|
||||
5127B236222B4849006D641D /* DetailKeyboardDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailKeyboardDelegate.swift; sourceTree = "<group>"; };
|
||||
5127B237222B4849006D641D /* DetailKeyboardShortcuts.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = DetailKeyboardShortcuts.plist; sourceTree = "<group>"; };
|
||||
512955E62730BDF10041B863 /* AtkinsonHyperlegible-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "AtkinsonHyperlegible-Regular.ttf"; sourceTree = "<group>"; };
|
||||
512AF9C1236ED52C0066F8BE /* ImageHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageHeaderView.swift; sourceTree = "<group>"; };
|
||||
512AF9DC236F05230066F8BE /* InteractiveLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractiveLabel.swift; sourceTree = "<group>"; };
|
||||
512D554323C804DE0023FFFA /* OpenInSafariActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenInSafariActivity.swift; sourceTree = "<group>"; };
|
||||
@@ -1207,6 +1214,7 @@
|
||||
51333D3A2468615D00EB5C91 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Mac/Base.lproj/AddRedditFeedSheet.xib; sourceTree = SOURCE_ROOT; };
|
||||
5137C2E326F3F52D009EFEDB /* Sepia.nnwtheme */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Sepia.nnwtheme; sourceTree = "<group>"; };
|
||||
5137C2E926F63AE6009EFEDB /* ArticleThemeImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleThemeImporter.swift; sourceTree = "<group>"; };
|
||||
51384DEC2730CECC00C7997D /* Hyperlegible.nnwtheme */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Hyperlegible.nnwtheme; sourceTree = "<group>"; };
|
||||
51386A8D25673276005F3762 /* AccountCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountCell.swift; sourceTree = "<group>"; };
|
||||
513C5CE6232571C2003D4054 /* NetNewsWire iOS Share Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "NetNewsWire iOS Share Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
513C5CE8232571C2003D4054 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
|
||||
@@ -1856,13 +1864,15 @@
|
||||
511D43CE231FA51100FB1562 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
51DEE81126FB9233006DAA56 /* Appanoose.nnwtheme */,
|
||||
51384DEC2730CECC00C7997D /* Hyperlegible.nnwtheme */,
|
||||
51DEE81726FBFF84006DAA56 /* Promenade.nnwtheme */,
|
||||
5137C2E326F3F52D009EFEDB /* Sepia.nnwtheme */,
|
||||
5127B237222B4849006D641D /* DetailKeyboardShortcuts.plist */,
|
||||
844B5B641FEA11F200C7C76A /* GlobalKeyboardShortcuts.plist */,
|
||||
844B5B681FEA20DF00C7C76A /* SidebarKeyboardShortcuts.plist */,
|
||||
845479871FEB77C000AD8B59 /* TimelineKeyboardShortcuts.plist */,
|
||||
5127B237222B4849006D641D /* DetailKeyboardShortcuts.plist */,
|
||||
51DEE81126FB9233006DAA56 /* Appanoose.nnwtheme */,
|
||||
51DEE81726FBFF84006DAA56 /* Promenade.nnwtheme */,
|
||||
5137C2E326F3F52D009EFEDB /* Sepia.nnwtheme */,
|
||||
512955E62730BDF10041B863 /* AtkinsonHyperlegible-Regular.ttf */,
|
||||
);
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
@@ -3364,6 +3374,7 @@
|
||||
65ED404F235DEF6C0081F399 /* GlobalKeyboardShortcuts.plist in Resources */,
|
||||
65ED4050235DEF6C0081F399 /* DetailKeyboardShortcuts.plist in Resources */,
|
||||
65ED4051235DEF6C0081F399 /* TimelineKeyboardShortcuts.plist in Resources */,
|
||||
512955E82730BDF10041B863 /* AtkinsonHyperlegible-Regular.ttf in Resources */,
|
||||
65ED4052235DEF6C0081F399 /* template.html in Resources */,
|
||||
65ED4054235DEF6C0081F399 /* Main.storyboard in Resources */,
|
||||
5137C2E526F3F52D009EFEDB /* Sepia.nnwtheme in Resources */,
|
||||
@@ -3379,6 +3390,7 @@
|
||||
65ED405D235DEF6C0081F399 /* SidebarKeyboardShortcuts.plist in Resources */,
|
||||
514A89A3244FD63F0085E65D /* AddTwitterFeedSheet.xib in Resources */,
|
||||
51D0214726ED617100FF2E0F /* core.css in Resources */,
|
||||
51384DEE2730CECC00C7997D /* Hyperlegible.nnwtheme in Resources */,
|
||||
5103A9F5242258C600410853 /* AccountsAddCloudKit.xib in Resources */,
|
||||
65ED405E235DEF6C0081F399 /* DefaultFeeds.opml in Resources */,
|
||||
51333D3C2468615D00EB5C91 /* AddRedditFeedSheet.xib in Resources */,
|
||||
@@ -3429,6 +3441,7 @@
|
||||
511D43D2231FA62C00FB1562 /* GlobalKeyboardShortcuts.plist in Resources */,
|
||||
84C9FCA12262A1B300D921D6 /* Main.storyboard in Resources */,
|
||||
51BB7C312335ACDE008E8144 /* page.html in Resources */,
|
||||
512955E92730BDF10041B863 /* AtkinsonHyperlegible-Regular.ttf in Resources */,
|
||||
512392C324E3451400F11704 /* TwitterAdd.storyboard in Resources */,
|
||||
516A093723609A3600EAE89B /* SettingsComboTableViewCell.xib in Resources */,
|
||||
51F85BF32272531500C787DC /* Dedication.rtf in Resources */,
|
||||
@@ -3442,6 +3455,7 @@
|
||||
516A093B2360A4A000EAE89B /* SettingsTableViewCell.xib in Resources */,
|
||||
511D43D1231FA62800FB1562 /* SidebarKeyboardShortcuts.plist in Resources */,
|
||||
516A09402361240900EAE89B /* Account.storyboard in Resources */,
|
||||
51384DEF2730CECC00C7997D /* Hyperlegible.nnwtheme in Resources */,
|
||||
51C452AB22650DC600C03939 /* template.html in Resources */,
|
||||
51F85BF12272524100C787DC /* Credits.rtf in Resources */,
|
||||
84A3EE61223B667F00557320 /* DefaultFeeds.opml in Resources */,
|
||||
@@ -3473,6 +3487,7 @@
|
||||
84C9FC7D22629E1200D921D6 /* AccountsDetail.xib in Resources */,
|
||||
5137C2E426F3F52D009EFEDB /* Sepia.nnwtheme in Resources */,
|
||||
517630042336215100E15FFF /* main.js in Resources */,
|
||||
512955E72730BDF10041B863 /* AtkinsonHyperlegible-Regular.ttf in Resources */,
|
||||
65ED40A0235DEFF00081F399 /* container-migration.plist in Resources */,
|
||||
5144EA362279FC3D00D19003 /* AccountsAddLocal.xib in Resources */,
|
||||
51D0214626ED617100FF2E0F /* core.css in Resources */,
|
||||
@@ -3499,6 +3514,7 @@
|
||||
49F40DF82335B71000552BF4 /* newsfoot.js in Resources */,
|
||||
51333D3B2468615D00EB5C91 /* AddRedditFeedSheet.xib in Resources */,
|
||||
BDCB516724282C8A00102A80 /* AccountsNewsBlur.xib in Resources */,
|
||||
51384DED2730CECC00C7997D /* Hyperlegible.nnwtheme in Resources */,
|
||||
514A89A2244FD63F0085E65D /* AddTwitterFeedSheet.xib in Resources */,
|
||||
5103A9982421643300410853 /* blank.html in Resources */,
|
||||
515A516E243E7F950089E588 /* ExtensionPointDetail.xib in Resources */,
|
||||
@@ -3744,7 +3760,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "xcrun -sdk macosx swiftc -target x86_64-macosx10.11 buildscripts/VerifyNoBuildSettings.swift -o $CONFIGURATION_TEMP_DIR/VerifyNoBS\n$CONFIGURATION_TEMP_DIR/VerifyNoBS ${PROJECT_NAME}.xcodeproj/project.pbxproj\n\n\nif [ $? -ne 0 ]\nthen\n echo \"error: Build Setting were found in the project.pbxproj file. Most likely you didn't intend to change this file and should revert it.\"\n exit 1\nfi\n";
|
||||
shellScript = "xcrun -sdk macosx swift buildscripts/VerifyNoBS.swift --xcode ${PROJECT_DIR}/${PROJECT_NAME}.xcodeproj/project.pbxproj\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
@@ -4726,8 +4742,6 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 65ED40F2235DF5E00081F399 /* NetNewsWire_macapp_target_macappstore.xcconfig */;
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
PRODUCT_NAME = NetNewsWire;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -4735,8 +4749,6 @@
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 65ED40F2235DF5E00081F399 /* NetNewsWire_macapp_target_macappstore.xcconfig */;
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
PRODUCT_NAME = NetNewsWire;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
16
README.md
16
README.md
@@ -1,8 +1,8 @@
|
||||
#  NetNewsWire
|
||||
|
||||
It’s a free and open source feed reader for macOS and iOS.
|
||||
It’s a free and open-source feed reader for macOS and iOS.
|
||||
|
||||
It supports [RSS](http://cyber.harvard.edu/rss/rss.html), [Atom](https://tools.ietf.org/html/rfc4287), [JSON Feed](https://jsonfeed.org/), and [RSS-in-JSON](https://github.com/scripting/Scripting-News/blob/master/rss-in-json/README.md) formats.
|
||||
It supports [RSS](https://cyber.harvard.edu/rss/rss.html), [Atom](https://datatracker.ietf.org/doc/html/rfc4287), [JSON Feed](https://jsonfeed.org/), and [RSS-in-JSON](https://github.com/scripting/Scripting-News/blob/master/rss-in-json/README.md) formats.
|
||||
|
||||
More info: [https://netnewswire.com/](https://netnewswire.com/)
|
||||
|
||||
@@ -16,7 +16,7 @@ Here’s [How to Support NetNewsWire](Technotes/HowToSupportNetNewsWire.markdown
|
||||
|
||||
[Join the Slack group](https://netnewswire.com/slack) to talk with other NetNewsWire users — and to help out, if you’d like to, by testing, coding, writing, providing feedback, or just helping us think things through. Everybody is welcome and encouraged to join.
|
||||
|
||||
Every community member is expected to abide by the code of conduct which is included in the [Contributing](CONTRIBUTING.md) page.
|
||||
Every community member is expected to abide by the [code of conduct](CONTRIBUTING.md#code-of-conduct) which is included in the [Contributing](CONTRIBUTING.md) page.
|
||||
|
||||
#### Pull Requests
|
||||
|
||||
@@ -33,10 +33,10 @@ git clone https://github.com/Ranchero-Software/NetNewsWire.git
|
||||
You can locally override the Xcode settings for code signing
|
||||
by creating a `DeveloperSettings.xcconfig` file locally at the appropriate path.
|
||||
This allows for a pristine project with code signing set up with the appropriate
|
||||
developer ID and certificates, and for dev to be able to have local settings
|
||||
developer ID and certificates, and for developer to be able to have local settings
|
||||
without needing to check in anything into source control.
|
||||
|
||||
You can do this in one of two ways: using the included `setup.sh` script or by creating the folder structure and file manually.
|
||||
You can do this in one of two ways: using the included `setup.sh` script or by creating the folder structure and file manually.
|
||||
|
||||
##### Using `setup.sh`
|
||||
|
||||
@@ -46,7 +46,7 @@ You can do this in one of two ways: using the included `setup.sh` script or by c
|
||||
|
||||
##### Manually
|
||||
|
||||
Make a directory SharedXcodeSettings next to where you have this repository.
|
||||
Make a directory `SharedXcodeSettings` next to where you have this repository.
|
||||
|
||||
The directory structure is:
|
||||
|
||||
@@ -54,7 +54,7 @@ The directory structure is:
|
||||
aDirectory/
|
||||
SharedXcodeSettings/
|
||||
DeveloperSettings.xcconfig
|
||||
NetNewsWire
|
||||
NetNewsWire/
|
||||
NetNewsWire.xcworkspace
|
||||
```
|
||||
Example:
|
||||
@@ -90,4 +90,4 @@ functionality disabled. This is because we have API keys that can't be stored i
|
||||
repository or shared between developers. Certain account types, like Feedly, aren't
|
||||
enabled and the Reader View isn't enabled because of this.
|
||||
|
||||
If you have any problems, we will help you out in Slack (see above).
|
||||
If you have any problems, we will help you out in Slack ([see above](README.md#Community)).
|
||||
|
||||
BIN
Shared/Resources/AtkinsonHyperlegible-Regular.ttf
Normal file
BIN
Shared/Resources/AtkinsonHyperlegible-Regular.ttf
Normal file
Binary file not shown.
16
Shared/Resources/Hyperlegible.nnwtheme/Info.plist
Normal file
16
Shared/Resources/Hyperlegible.nnwtheme/Info.plist
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Name</key>
|
||||
<string>Hyperlegible</string>
|
||||
<key>ThemeIdentifier</key>
|
||||
<string>com.netnewswire.themes.hyperlegible</string>
|
||||
<key>CreatorHomePage</key>
|
||||
<string>http://netnewswire.com/</string>
|
||||
<key>CreatorName</key>
|
||||
<string>Ranchero Software</string>
|
||||
<key>Version</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</plist>
|
||||
510
Shared/Resources/Hyperlegible.nnwtheme/stylesheet.css
Normal file
510
Shared/Resources/Hyperlegible.nnwtheme/stylesheet.css
Normal file
@@ -0,0 +1,510 @@
|
||||
/* Shared iOS and macOS CSS rules. Platform specific rules are at the bottom of this file. */
|
||||
|
||||
@font-face
|
||||
{
|
||||
font-family: 'Atkinson Hyperlegible';
|
||||
src: local('AtkinsonHyperlegible-Regular'),url('AtkinsonHyperlegible-Regular.ttf') format('truetype');
|
||||
}
|
||||
|
||||
body {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
word-wrap: break-word;
|
||||
max-width: 44em;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.feedlink {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.headerTable {
|
||||
width: 100%;
|
||||
height: 68px;
|
||||
}
|
||||
|
||||
.systemMessage {
|
||||
position: absolute;
|
||||
top: 45%;
|
||||
left: 50%;
|
||||
transform: translateX(-55%) translateY(-50%);
|
||||
-webkit-user-select: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
:root {
|
||||
--header-table-border-color: rgba(0, 0, 0, 0.1);
|
||||
--header-color: rgba(8, 106, 238, 1);
|
||||
--body-code-color: #666;
|
||||
--system-message-color: #cbcbcb;
|
||||
--feedlink-color: rgba(255, 0, 0, 0.6);
|
||||
--article-title-color: #333;
|
||||
--article-date-color: rgba(0, 0, 0, 0.5);
|
||||
--table-cell-border-color: lightgray;
|
||||
}
|
||||
|
||||
@media(prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--header-color: rgba(94, 158, 244, 1);
|
||||
--body-code-color: #b2b2b2;
|
||||
--system-message-color: #5f5f5f;
|
||||
--feedlink-color: rgba(94, 158, 244, 1);
|
||||
--article-title-color: #e0e0e0;
|
||||
--article-date-color: rgba(255, 255, 255, 0.8);
|
||||
--table-cell-border-color: dimgray;
|
||||
}
|
||||
}
|
||||
|
||||
body .headerTable {
|
||||
border-bottom: 1px solid var(--header-table-border-color);
|
||||
color: var(--header-color);
|
||||
}
|
||||
|
||||
body .header {
|
||||
color: var(--header-color);
|
||||
}
|
||||
|
||||
body .header a:link, .header a:visited {
|
||||
color: var(--header-color);
|
||||
}
|
||||
|
||||
body code, body pre {
|
||||
color: var(--body-code-color);
|
||||
}
|
||||
|
||||
body > .systemMessage {
|
||||
color: var(--system-message-color);
|
||||
}
|
||||
|
||||
.feedlink a:link, .feedlink a:visited {
|
||||
color: var(--feedlink-color);
|
||||
}
|
||||
|
||||
.avatar img {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.feedIcon {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.rightAlign {
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
.leftAlign {
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.articleTitle a:link, .articleTitle a:visited {
|
||||
color: var(--article-title-color);
|
||||
margin-top: 26px;
|
||||
}
|
||||
|
||||
.articleDateline {
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.articleDateline a:link, .articleDateline a:visited {
|
||||
color: var(--article-date-color);
|
||||
}
|
||||
|
||||
.articleDatelineTitle {
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.articleDatelineTitle a:link, .articleDatelineTitle a:visited {
|
||||
color: var(--article-title-color);
|
||||
}
|
||||
|
||||
.externalLink {
|
||||
margin-bottom: 5px;
|
||||
font-style: italic;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.articleBody {
|
||||
margin-top: 20px;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
line-height: 1.15em;
|
||||
font-weight: bold;
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
pre {
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
overflow: auto;
|
||||
overflow-y: hidden;
|
||||
word-wrap: normal;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
pre {
|
||||
line-height: 1.4286em;
|
||||
}
|
||||
|
||||
code, pre {
|
||||
font-family: "SF Mono", Menlo, "Courier New", Courier, monospace;
|
||||
font-size: 1em;
|
||||
-webkit-hyphens: none;
|
||||
}
|
||||
|
||||
pre code {
|
||||
letter-spacing: -.027em;
|
||||
font-size: 0.9375em;
|
||||
}
|
||||
|
||||
.nnw-overflow {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
/*
|
||||
Instead of the last-child bits, border-collapse: collapse
|
||||
could have been used. However, then the inter-cell borders
|
||||
overlap the table border, which looks bad.
|
||||
*/
|
||||
.nnw-overflow table {
|
||||
margin-bottom: 1px;
|
||||
border-spacing: 0;
|
||||
border: 1px solid var(--secondary-accent-color);
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.nnw-overflow table table {
|
||||
margin-bottom: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.nnw-overflow td, .nnw-overflow th {
|
||||
-webkit-hyphens: none;
|
||||
word-break: normal;
|
||||
border: 1px solid var(--table-cell-border-color);
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.nnw-overflow tr :matches(td, th):last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.nnw-overflow :matches(thead, tbody, tfoot):last-child > tr:last-child :matches(td, th) {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.nnw-overflow td pre {
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.nnw-overflow table[border="0"] {
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
img, figure, video, div, object {
|
||||
max-width: 100%;
|
||||
height: auto !important;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
iframe {
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
iframe.nnw-constrained {
|
||||
max-height: 50vw;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin-bottom: 1em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
figcaption {
|
||||
font-size: 14px;
|
||||
line-height: 1.3em;
|
||||
}
|
||||
|
||||
sup {
|
||||
vertical-align: top;
|
||||
position: relative;
|
||||
bottom: 0.2rem;
|
||||
}
|
||||
|
||||
sub {
|
||||
vertical-align: bottom;
|
||||
position: relative;
|
||||
top: 0.2rem;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1.5px solid var(--table-cell-border-color);
|
||||
}
|
||||
|
||||
.iframeWrap {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding-top: 56.25%;
|
||||
}
|
||||
|
||||
.iframeWrap iframe {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: 0;
|
||||
padding-inline-start: 15px;
|
||||
border-inline-start: 3px solid var(--block-quote-border-color);
|
||||
}
|
||||
|
||||
/* Feed Specific */
|
||||
|
||||
.feedbin--article-wrap {
|
||||
border-top: 1px solid var(--header-table-border-color);
|
||||
}
|
||||
|
||||
/* Twitter */
|
||||
|
||||
.twitterAvatar {
|
||||
vertical-align: middle;
|
||||
border-radius: 4px;
|
||||
height: 1.7em;
|
||||
width: 1.7em;
|
||||
}
|
||||
|
||||
.twitterUsername {
|
||||
line-height: 1.2;
|
||||
margin-left: 4px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.twitterScreenName {
|
||||
font-size: 66%;
|
||||
}
|
||||
|
||||
.twitterTimestamp {
|
||||
font-size: 66%;
|
||||
}
|
||||
|
||||
/* Newsfoot theme for light mode (default) */
|
||||
.newsfoot-footnote-popover {
|
||||
background: #ccc;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5), 0 3px 6px rgba(0, 0, 0, 0.25);
|
||||
color: black;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
.newsfoot-footnote-popover-arrow {
|
||||
background: #fafafa;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.newsfoot-footnote-popover-inner {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
body a.footnote,
|
||||
body a.footnote:visited,
|
||||
.newsfoot-footnote-popover + a.footnote:hover {
|
||||
background: #aaa;
|
||||
color: white;
|
||||
transition: background-color 200ms ease-out;
|
||||
}
|
||||
|
||||
a.footnote:hover,
|
||||
.newsfoot-footnote-popover + a.footnote {
|
||||
background: #666;
|
||||
transition: background-color 200ms ease-out;
|
||||
}
|
||||
|
||||
/* Newsfoot theme for dark mode */
|
||||
@media screen and (prefers-color-scheme: dark) {
|
||||
.newsfoot-footnote-popover {
|
||||
background: #444;
|
||||
color: rgb(224, 224, 224);
|
||||
}
|
||||
|
||||
.newsfoot-footnote-popover-arrow {
|
||||
background: #242424;
|
||||
border: 1px solid #444;
|
||||
}
|
||||
|
||||
.newsfoot-footnote-popover-inner {
|
||||
background: #242424;
|
||||
}
|
||||
|
||||
body a.footnote,
|
||||
body a.footnote:visited,
|
||||
.newsfoot-footnote-popover + a.footnote:hover {
|
||||
background: #aaa;
|
||||
color: white;
|
||||
transition: background-color 200ms ease-out;
|
||||
}
|
||||
|
||||
a.footnote:hover,
|
||||
.newsfoot-footnote-popover + a.footnote {
|
||||
background: #666;
|
||||
transition: background-color 200ms ease-out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* iOS Specific */
|
||||
@supports (-webkit-touch-callout: none) {
|
||||
|
||||
body {
|
||||
margin-top: 3px;
|
||||
margin-bottom: 20px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
|
||||
font-size: 135%;
|
||||
|
||||
word-break: break-word;
|
||||
-webkit-hyphens: auto;
|
||||
-webkit-text-size-adjust: none;
|
||||
}
|
||||
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
font: font-family: 'Atkinson Hyperlegible', -apple-system-body;
|
||||
/* The font-size is replaced at runtime by the dynamic type size */
|
||||
font-size: [[font-size]]px;
|
||||
--primary-accent-color: #086AEE;
|
||||
--secondary-accent-color: #086AEE;
|
||||
--block-quote-border-color: rgba(8, 106, 238, 0.75);
|
||||
}
|
||||
|
||||
@media(prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--primary-accent-color: #2D80F1;
|
||||
--secondary-accent-color: #5E9EF4;
|
||||
--block-quote-border-color: rgba(94, 158, 244, 0.75);
|
||||
--header-table-border-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
body a, body a:visited {
|
||||
color: var(--secondary-accent-color);
|
||||
}
|
||||
|
||||
body .header {
|
||||
font: font-family: 'Atkinson Hyperlegible', -apple-system-body;
|
||||
font-size: 135%;
|
||||
}
|
||||
|
||||
body .header a:link, body .header a:visited {
|
||||
color: var(--primary-accent-color);
|
||||
}
|
||||
|
||||
pre {
|
||||
border: 1px solid var(--secondary-accent-color);
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.nnw-overflow table {
|
||||
border: 1px solid var(--secondary-accent-color);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* macOS Specific */
|
||||
@supports not (-webkit-touch-callout: none) {
|
||||
|
||||
body {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 64px;
|
||||
padding-left: 48px;
|
||||
padding-right: 48px;
|
||||
font-family: 'Atkinson Hyperlegible', -apple-system;
|
||||
}
|
||||
|
||||
.smallText {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.mediumText {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.largeText {
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
.xlargeText {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.xxlargeText {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
--accent-color: rgba(8, 106, 238, 1);
|
||||
--block-quote-border-color: rgba(8, 106, 238, .50);
|
||||
}
|
||||
|
||||
@media(prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--accent-color: rgba(94, 158, 244, 1);
|
||||
--block-quote-border-color: rgba(94, 158, 244, .50);
|
||||
--header-table-border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
body .header {
|
||||
font-size: 135%;
|
||||
}
|
||||
|
||||
body .articleTitle {
|
||||
font-size: 135%;
|
||||
}
|
||||
|
||||
body .articleDateline {
|
||||
font-size: 135%;
|
||||
}
|
||||
|
||||
body .externalLink {
|
||||
font-size: 135%;
|
||||
}
|
||||
|
||||
body a, body a:visited {
|
||||
color: var(--accent-color);
|
||||
}
|
||||
|
||||
pre {
|
||||
border: 1px solid var(--accent-color);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.nnw-overflow table {
|
||||
border: 1px solid var(--accent-color);
|
||||
}
|
||||
|
||||
}
|
||||
47
Shared/Resources/Hyperlegible.nnwtheme/template.html
Normal file
47
Shared/Resources/Hyperlegible.nnwtheme/template.html
Normal file
@@ -0,0 +1,47 @@
|
||||
<!-- Template Variables
|
||||
|
||||
title: The title of the article
|
||||
preferred_link: The best link to associate with the article for linking out.
|
||||
|
||||
external_link_label: A localized label for the external link.
|
||||
external_link_stripped: The external link minus the scheme. Useful for displaying the external link.
|
||||
external_link: The external link of the article if there is one provided by the author.
|
||||
|
||||
feed_link_title: The name of the feed associated with this article.
|
||||
feed_link: The URL of the feed associated with this article.
|
||||
byline: HTML that combines all the authors and links to them if available.
|
||||
avatar_src: The image source URL for the feed icon / avatar.
|
||||
dateline_style: Either "articleDateline" or "articleDatelineTitle" depending on if the title was populated or not.
|
||||
|
||||
datetime_long: Long version of a combined publish date and time.
|
||||
datetime_medium: Medium length version of a combined publish date and time.
|
||||
datetime_short: Short version of a combined publish date and time.
|
||||
|
||||
date_long: Long version of the publish date.
|
||||
date_medium: Medium version of the publish date.
|
||||
date_short: Long version of the publish date.
|
||||
|
||||
time_long: Long version of the publish time.
|
||||
time_medium: Medium version of the publish time.
|
||||
time_short: Long version of the publish time.
|
||||
|
||||
text_size_class: The size class that the user has selected in Preferences for article text.
|
||||
body: The body of the article.
|
||||
|
||||
-->
|
||||
|
||||
<header class="headerContainer">
|
||||
<table cellpadding=0 cellspacing=0 border=0 class="headerTable">
|
||||
<tr>
|
||||
<td class="header leftAlign"><a class="feedlink" href="[[feed_link]]">[[feed_link_title]]</a><br />[[byline]]</td>
|
||||
<td class="header rightAlign avatar"><img id="nnwImageIcon" src="[[avatar_src]]" height=48 width=48 /></td>
|
||||
</tr>
|
||||
</table>
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="articleTitle"><h1><a href="[[preferred_link]]">[[title]]</a></h1></div>
|
||||
<div class="[[dateline_style]]"><a href="[[preferred_link]]">[[datetime_medium]]</a></div>
|
||||
<div class="externalLink">[[external_link_label]] <a href="[[external_link]]">[[external_link_stripped]]</a></div>
|
||||
<div id="bodyContainer" class="articleBody [[text_size_class]]">[[body]]</div>
|
||||
</article>
|
||||
@@ -1,11 +1,11 @@
|
||||
# Accessibility
|
||||
|
||||
Millions of Mac users have some disability or special needs. They use screen readers and special
|
||||
hardware to open up a world that they would otherwise be cut off from. With a small amount of
|
||||
hardware to open up a world that they would otherwise be cut off from. With a small amount of
|
||||
developer work, we can help these users live better lives.
|
||||
|
||||
Because NetNewsWire utilizes standard AppKit controls and views, accessibility is already built in.
|
||||
However this is only a starting point. Any customized controls and views will have accessibility
|
||||
However, this is only a starting point. Any customized controls and views will have accessibility
|
||||
work and the application as a whole has to be tested to make sure users can operate if efficiently.
|
||||
|
||||
This document lays the groundwork to ensure that NetNewsWire has first class accessibility features.
|
||||
|
||||
@@ -14,7 +14,7 @@ This separation is deliberate. There are two main reasons: syncing, and strange
|
||||
|
||||
When syncing with another service, it’s entirely likely that the service will report article status information in calls that are separate from calls to retrieve articles.
|
||||
|
||||
Thus the app might learn about statuses for articles it hasn’t seen yet.
|
||||
Thus, the app might learn about statuses for articles it hasn’t seen yet.
|
||||
|
||||
This way the app can store those statuses without having to have their corresponding articles. And then, when the app does download those articles, it has their statuses already in the database.
|
||||
|
||||
|
||||
@@ -17,15 +17,15 @@ That is Three-Flow applied to NetNewsWire. It would be that simple, but we have
|
||||
|
||||
Today (6/12/2019) we have 2 branches, main and macOS Candidate, in the main repository which will eventually grow to be 5 branches.
|
||||
|
||||
There will also be a number of repository forks that NetNewWire developers will create to do bug fixes and implement new features (not shown here). Typically contributers will fork the Main branch to thier own repository. They would then create a feature/bugfix branch on their repository. Once work on thier forked branch is complete, they will submit a pull request to be merged back into the main repository main.
|
||||
There will also be a number of repository forks that NetNewWire developers will create to do bug fixes and implement new features (not shown here). Typically, contributors will fork the Main branch to their own repository. They would then create a feature/bugfix branch on their repository. Once work on their forked branch is complete, they will submit a pull request to be merged back into the main repository main.
|
||||
|
||||
## Tagging
|
||||
|
||||
Each release should be tagged using [Semantic Versioning](https://semver.org/). Candidates will continue to be tagged using the current convention which denotes the difference between developer, alpha and beta releases. Additionally, we will need to use a convention to avoid tag name collisions between iOS and macOS products. macOS releases will be suffixed with "mac-" and iOS releases will be suffixed with "ios-". (See the above diagram for examples.)
|
||||
Each release should be tagged using [Semantic Versioning](https://semver.org/). Candidates will continue to be tagged using the current convention which denotes the difference between developer, alpha and beta releases. Additionally, we will need to use a convention to avoid tag name collisions between iOS and macOS products. macOS releases will be suffixed with "mac-" and iOS releases will be suffixed with "ios-". (See the above diagram for examples.)
|
||||
|
||||
## Packages
|
||||
|
||||
NetNewsWire uses Swift Packages to manage project dependencies. All the packages are under the same project umbrella as NetNewWire and there are no third party dependencies to manage. These packages are mostly stable at this point. For simplicity sake, all development on the packages will continue on their repository Main branch. These packages won’t be managed as separate projects with separate releases/tags at this time.
|
||||
NetNewsWire uses Swift Packages to manage project dependencies. All the packages are under the same project umbrella as NetNewWire and there are no third-party dependencies to manage. These packages are mostly stable at this point. For simplicity’s sake, all development on the packages will continue on their repository Main branch. These packages won’t be managed as separate projects with separate releases/tags at this time.
|
||||
|
||||
## Summary
|
||||
|
||||
|
||||
@@ -5,39 +5,26 @@ First thing: don’t send money. This app is [written for love](https://inessent
|
||||
NetNewsWire is all about three things:
|
||||
|
||||
* The open web
|
||||
* High-quality open source Mac and iOS apps
|
||||
* High-quality open-source Mac and iOS apps
|
||||
* The community that loves both of the above
|
||||
|
||||
Supporting all these things takes *work*.
|
||||
|
||||
### Here are some things you can do
|
||||
|
||||
In no particular order…
|
||||
In no particular order …
|
||||
|
||||
Write a blog instead of posting to Twitter or Facebook. (You can always re-post to those places if you want to extend your reach.) [Micro.blog](https://micro.blog/) is one good place to get going, but it’s not the only one.
|
||||
|
||||
Use an RSS reader even if it’s not NetNewsWire. (There are a bunch of good ones!)
|
||||
|
||||
Teach other people to use RSS readers. Blog about RSS readers. And about other open web technologies and apps.
|
||||
|
||||
Suggest apps for [macopenweb.com](https://macopenweb.com/).
|
||||
|
||||
Write Mac and iOS apps that promote use of the open web.
|
||||
|
||||
Donate to charities that promote literacy.
|
||||
|
||||
Tell other people about cool blogs and feeds you’ve found.
|
||||
|
||||
Support indie podcast apps.
|
||||
|
||||
Vote for candidates whose policies are not cruel.
|
||||
|
||||
Support your local library.
|
||||
|
||||
Be bold and do your best work.
|
||||
|
||||
Support indie developers — pay for apps that cost money. Even though NetNewsWire is free, apps are most definitely *not* free to make, and it costs money to keep improving them. It’s worth it.
|
||||
|
||||
Finally: report bugs and make feature requests on our Issues tracker. You can also join the Slack group — it’s not just for coders. We also need testers, writers, and, especially, people who are willing to talk things over. Most of software development is just making decisions, and we appreciate all the help we can get!
|
||||
|
||||
Or: skip helping us, and, instead, help people who need help more than we do. Those people should not be hard to find.
|
||||
* Write a blog instead of posting to Twitter or Facebook. (You can always re-post to those places if you want to extend your reach.) [Micro.blog](https://micro.blog/) is one good place to get going, but it’s not the only one.
|
||||
* Use an RSS reader even if it’s not NetNewsWire. (There are a bunch of good ones!)
|
||||
* Teach other people to use RSS readers. Blog about RSS readers. And about other open web technologies and apps.
|
||||
* Suggest apps for [macopenweb.com](https://macopenweb.com/).
|
||||
* Write Mac and iOS apps that promote use of the open web.
|
||||
* Donate to charities that promote literacy.
|
||||
* Tell other people about cool blogs and feeds you’ve found.
|
||||
* Support indie podcast apps.
|
||||
* Vote for candidates whose policies are not cruel.
|
||||
* Support your local library.
|
||||
* Be bold and do your best work.
|
||||
* Support indie developers — pay for apps that cost money. Even though NetNewsWire is free, apps are most definitely *not* free to make, and it costs money to keep improving them. It’s worth it.
|
||||
* Finally: report bugs and make feature requests on our Issues tracker. You can also join the Slack group — it’s not just for coders. We also need testers, writers, and, especially, people who are willing to talk things over. Most of software development is just making decisions, and we appreciate all the help we can get!
|
||||
* Or: skip helping us, and, instead, help people who need help more than we do. Those people should not be hard to find.
|
||||
|
||||
155
buildscripts/VerifyNoBS.swift
Executable file
155
buildscripts/VerifyNoBS.swift
Executable file
@@ -0,0 +1,155 @@
|
||||
#!/usr/bin/swift
|
||||
|
||||
// This script is meant to be called from an Xcode run script build phase
|
||||
// It verifies there are no buildSettings embedded in the Xcode project
|
||||
// as it is preferable to have build settings specified in .xcconfig files
|
||||
|
||||
// How to use:
|
||||
// Put this script in a folder called 'buildscripts' next to your xcode project
|
||||
// Then, add a Run script build phase to one of your targets with this as the script
|
||||
//
|
||||
// xcrun -sdk macosx swift buildscripts/VerifyNoBS.swift --xcode ${PROJECT_DIR}/${PROJECT_NAME}.xcodeproj/project.pbxproj
|
||||
//
|
||||
|
||||
import Darwin
|
||||
import Foundation
|
||||
|
||||
/// A message with its file name and location
|
||||
struct LocatedMessage {
|
||||
let message: String
|
||||
let fileUrl: URL
|
||||
let line: Int
|
||||
}
|
||||
|
||||
/// Utility to process the pbxproj file
|
||||
struct BuildSettingsVerifier {
|
||||
|
||||
public enum ProcessXcodeprojResult {
|
||||
case foundBuildSettings([LocatedMessage])
|
||||
case error(String)
|
||||
case success(String)
|
||||
}
|
||||
|
||||
/// Mode to run the utility in. Mode defines the output format
|
||||
public enum Mode {
|
||||
/// Write errors to stderr
|
||||
case cmd
|
||||
/// Write errors to stdout in a format that is picked up by Xcode
|
||||
case xcode
|
||||
}
|
||||
|
||||
/// The mode to run in
|
||||
let mode: Mode
|
||||
|
||||
/// The absolute file URL to the pbxproj file
|
||||
let projUrl: URL
|
||||
|
||||
init(mode: Mode, projUrl: URL) {
|
||||
self.mode = mode
|
||||
self.projUrl = projUrl
|
||||
}
|
||||
|
||||
/// Reports an error either to stderr or to stdout, depending on the mode
|
||||
func reportError(message: String, fileUrl: URL? = nil, line: Int? = nil) {
|
||||
switch mode {
|
||||
case .cmd:
|
||||
let stderr = FileHandle.standardError
|
||||
if let data = "\(message)\n".data(using: String.Encoding.utf8, allowLossyConversion: false) {
|
||||
stderr.write(data)
|
||||
} else {
|
||||
print("There was an error. Could not convert error message to printable string")
|
||||
}
|
||||
case .xcode:
|
||||
var messageParts = [String]()
|
||||
|
||||
if let fileUrl = fileUrl {
|
||||
messageParts.append("\(fileUrl.path):")
|
||||
}
|
||||
|
||||
if let line = line {
|
||||
messageParts.append("\(line): ")
|
||||
}
|
||||
|
||||
messageParts.append("error: \(message)")
|
||||
|
||||
print(messageParts.joined())
|
||||
}
|
||||
}
|
||||
|
||||
/// Inspect the pbxproj file for non-empty buildSettings
|
||||
func processXcodeprojAt(url: URL) -> ProcessXcodeprojResult {
|
||||
let startTime = Date()
|
||||
guard let xcodeproj = try? String(contentsOf: url, encoding: String.Encoding.utf8) else {
|
||||
return .error("Failed to read xcodeproj contents from \(url)")
|
||||
}
|
||||
let lines = xcodeproj.components(separatedBy: CharacterSet.newlines)
|
||||
print("Found \(lines.count) lines")
|
||||
|
||||
var locatedMessages: [LocatedMessage] = []
|
||||
var inBuildSettingsBlock = false
|
||||
for (lineIndex, nthLine) in lines.enumerated() {
|
||||
if inBuildSettingsBlock {
|
||||
if nthLine.range(of: "\\u007d[:space:]*;", options: .regularExpression) != nil {
|
||||
inBuildSettingsBlock = false
|
||||
} else if nthLine.range(of: "CODE_SIGN_IDENTITY") != nil {
|
||||
|
||||
} else {
|
||||
let message = mode == .cmd ? " \(nthLine)\n" : "Setting '\(nthLine.trimmingCharacters(in: .whitespacesAndNewlines))' should be in an xcconfig file"
|
||||
locatedMessages.append(LocatedMessage(
|
||||
message: message,
|
||||
fileUrl: url,
|
||||
line: lineIndex + 1
|
||||
))
|
||||
}
|
||||
} else {
|
||||
if nthLine.range(of: "buildSettings[:space:]*=", options: .regularExpression) != nil {
|
||||
inBuildSettingsBlock = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let timeInterval = Date().timeIntervalSince(startTime)
|
||||
print("Process took \(timeInterval) seconds")
|
||||
if locatedMessages.count > 0 {
|
||||
return .foundBuildSettings(locatedMessages)
|
||||
}
|
||||
return .success(":-)")
|
||||
}
|
||||
|
||||
public func verify() -> Int32 {
|
||||
print("Verifying there are no build settings...")
|
||||
|
||||
let result = processXcodeprojAt(url: projUrl)
|
||||
|
||||
switch result {
|
||||
case .error(let str):
|
||||
reportError(message: "Error verifying build settings: \(str)")
|
||||
return EXIT_FAILURE
|
||||
case .foundBuildSettings(let locatedMessages):
|
||||
reportError(message: "Found build settings in project file")
|
||||
for msg in locatedMessages {
|
||||
reportError(message: msg.message, fileUrl: msg.fileUrl, line: msg.line)
|
||||
}
|
||||
return EXIT_FAILURE
|
||||
case .success:
|
||||
print("No build settings found in project file")
|
||||
return EXIT_SUCCESS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var commandLineArgs = CommandLine.arguments.dropFirst()
|
||||
//print("processArgs were \(commandLineArgs)")
|
||||
|
||||
if commandLineArgs.count < 1 {
|
||||
print("Usage: \(#file) [--xcode] /path/to/Project.xcodeproj/project.pbxproj")
|
||||
exit(EXIT_FAILURE)
|
||||
} else {
|
||||
let xcodeProjFilePath = commandLineArgs.removeLast()
|
||||
let mode: BuildSettingsVerifier.Mode = commandLineArgs.count > 0 && commandLineArgs.last == "--xcode" ? .xcode : .cmd
|
||||
let myUrl = URL(fileURLWithPath: xcodeProjFilePath)
|
||||
let verifier = BuildSettingsVerifier(mode: mode, projUrl: myUrl)
|
||||
let exitCode = verifier.verify()
|
||||
|
||||
exit(exitCode)
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
#!/usr/bin/swift
|
||||
|
||||
// This script is originally from github.com/olofhellman/VerifyNoBS
|
||||
// The idea is that all build settings should be kept in .xcconfig files,
|
||||
// rather than in the xcode pbxproj file inside an Xcode project bundle
|
||||
// Having the script run as part of a regular build ensures that the project file
|
||||
// doesn't accidentally accumulate build settings
|
||||
|
||||
import Darwin
|
||||
import Foundation
|
||||
|
||||
func reportError(message: String) {
|
||||
print("error message was \(message)")
|
||||
let stderr = FileHandle.standardError
|
||||
if let data = message.data(using: String.Encoding.utf8, allowLossyConversion: false) {
|
||||
stderr.write(data)
|
||||
} else {
|
||||
print("there was an error. script \"VerifyNoBuildSettings\" could not convert error message to printable string")
|
||||
}
|
||||
}
|
||||
|
||||
public enum ProcessXcodeprojResult {
|
||||
case FoundBuildSettings([String])
|
||||
case Error(String)
|
||||
case OK(String)
|
||||
}
|
||||
|
||||
public func processXcodeprojAt(url: URL) -> ProcessXcodeprojResult {
|
||||
let startTime = Date()
|
||||
guard let xcodeproj = try? String(contentsOf: url, encoding: String.Encoding.utf8) else {
|
||||
return .Error("script \"VerifyNoBuildSettings\" failed making xcodeproj from url")
|
||||
}
|
||||
let lines = xcodeproj.components(separatedBy: CharacterSet.newlines)
|
||||
print ("found \(lines.count) lines")
|
||||
|
||||
var badLines: [String] = []
|
||||
var inBuildSettingsBlock = false
|
||||
for nthLine in lines {
|
||||
if inBuildSettingsBlock {
|
||||
if let _ = nthLine.range(of:"\\u007d[:space:]*;", options: .regularExpression) {
|
||||
inBuildSettingsBlock = false
|
||||
} else if let _ = nthLine.range(of:"CODE_SIGN_IDENTITY") {
|
||||
|
||||
} else if let _ = nthLine.range(of:"PRODUCT_NAME") {
|
||||
|
||||
} else {
|
||||
badLines.append(nthLine)
|
||||
}
|
||||
} else {
|
||||
if let _ = nthLine.range(of:"buildSettings[:space:]*=", options: .regularExpression) {
|
||||
inBuildSettingsBlock = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let timeInterval = Date().timeIntervalSince(startTime)
|
||||
print ("process took \(timeInterval) seconds")
|
||||
if (badLines.count > 0) {
|
||||
return .FoundBuildSettings(badLines)
|
||||
}
|
||||
return .OK(":-)")
|
||||
}
|
||||
print("Verifying no buildSettings...")
|
||||
|
||||
let commandLineArgs = CommandLine.arguments
|
||||
print("processArgs were \(commandLineArgs)")
|
||||
let xcodeprojfilepath = commandLineArgs[1]
|
||||
let myUrl = URL(fileURLWithPath:xcodeprojfilepath)
|
||||
let result = processXcodeprojAt(url: myUrl)
|
||||
|
||||
switch result {
|
||||
case .Error(let str):
|
||||
reportError (message: "error script \"VerifyNoBuildSettings\" encountered an error: \(str)")
|
||||
exit(EXIT_FAILURE)
|
||||
case .FoundBuildSettings(let badLines):
|
||||
reportError (message: "script \"VerifyNoBuildSettings\" found build settings in the project file:")
|
||||
for badLine in badLines {
|
||||
reportError (message: " \(badLine)\n")
|
||||
}
|
||||
exit(EXIT_FAILURE)
|
||||
case .OK:
|
||||
print ("script \"VerifyNoBuildSettings\" verified the project contained no buildSettings")
|
||||
exit(EXIT_SUCCESS)
|
||||
}
|
||||
@@ -119,7 +119,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
||||
#if DEBUG
|
||||
syncTimer!.update()
|
||||
#endif
|
||||
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
|
||||
override var canBecomeFirstResponder: Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
private var reloadCoalescingQueue = CoalescingQueue(name: "Reload Visible", interval: 0.5)
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
||||
@@ -113,16 +115,7 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
|
||||
return
|
||||
}
|
||||
|
||||
var node: Node? = nil
|
||||
if let coordinator = representedObject as? SceneCoordinator, let feed = coordinator.timelineFeed {
|
||||
node = coordinator.rootNode.descendantNodeRepresentingObject(feed as AnyObject)
|
||||
} else {
|
||||
node = coordinator.rootNode.descendantNodeRepresentingObject(representedObject as AnyObject)
|
||||
}
|
||||
|
||||
guard let unreadCountNode = node, let indexPath = coordinator.indexPathFor(unreadCountNode) else { return }
|
||||
tableView.reloadRows(at: [indexPath], with: .none)
|
||||
restoreSelectionIfNecessary(adjustScroll: false)
|
||||
queueReloadAllVisible()
|
||||
}
|
||||
|
||||
@objc func faviconDidBecomeAvailable(_ note: Notification) {
|
||||
@@ -840,6 +833,14 @@ private extension MasterFeedViewController {
|
||||
return ""
|
||||
}
|
||||
|
||||
func queueReloadAllVisible() {
|
||||
reloadCoalescingQueue.add(self, #selector(reloadQueuedAllVisible))
|
||||
}
|
||||
|
||||
@objc func reloadQueuedAllVisible() {
|
||||
reloadAllVisibleCells()
|
||||
}
|
||||
|
||||
func configureCellsForRepresentedObject(_ representedObject: AnyObject) {
|
||||
applyToCellsForRepresentedObject(representedObject, configure)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>UIAppFonts</key>
|
||||
<array>
|
||||
<string>AtkinsonHyperlegible-Regular.ttf</string>
|
||||
</array>
|
||||
<key>AppGroup</key>
|
||||
<string>group.$(ORGANIZATION_IDENTIFIER).NetNewsWire.iOS</string>
|
||||
<key>AppIdentifierPrefix</key>
|
||||
|
||||
Reference in New Issue
Block a user