Native app facelift, extension UI tweaks, bug fixes.
Show/Hide Button for private key in Options page. Move experimental page into separate sub-folder. Move delegation wizard to sub-folder. Move permission page into separate folder. Basic functional SwiftUI look for the app. Beginning to define the main app view. NavigationStack and Privacy Policy Show App Icon on main screen. Getting Started: macOS Getting Started: iPhone Getting Started: iPad Removing old default UIKit code. Added "No Thanks" toggle to the relay reminder. Clearly indicate in the Settings page when a profile is a delegated profile. Changed recommended relays to all public relays. Use x-cloak in all the places. Fix bundle display name to use capital N. Added copy button to pubkey in settings. Window default size. Updating event kind list. Allow events to be copied by clicking on them in the event log. Tweaking the colors for a more purple-ish look. Added Tips and Tricks view to native app. Move utilities modules into separate folder. Rename event_log files to event_history to escape some content blockers. Renamed Event Log to Event History in the UI as well.
@@ -1,6 +1,15 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "display-p3",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.665",
|
||||
"green" : "0.271",
|
||||
"red" : "0.509"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
|
||||
21
Shared (App)/Assets.xcassets/bigicon.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Icon-512.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Shared (App)/Assets.xcassets/bigicon.imageset/Icon-512.png
vendored
Normal file
|
After Width: | Height: | Size: 32 KiB |
6
Shared (App)/Assets.xcassets/iPad/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
21
Shared (App)/Assets.xcassets/iPad/ipad-menu.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ipad-menu.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Shared (App)/Assets.xcassets/iPad/ipad-menu.imageset/ipad-menu.png
vendored
Normal file
|
After Width: | Height: | Size: 160 KiB |
21
Shared (App)/Assets.xcassets/iPad/ipad-popup.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ipad-popup.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Shared (App)/Assets.xcassets/iPad/ipad-popup.imageset/ipad-popup.png
vendored
Normal file
|
After Width: | Height: | Size: 61 KiB |
21
Shared (App)/Assets.xcassets/iPad/ipad-url-bar.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ipad-url-bar.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Shared (App)/Assets.xcassets/iPad/ipad-url-bar.imageset/ipad-url-bar.png
vendored
Normal file
|
After Width: | Height: | Size: 27 KiB |
6
Shared (App)/Assets.xcassets/iPhone/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
21
Shared (App)/Assets.xcassets/iPhone/iphone-menu.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "iphone-menu.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Shared (App)/Assets.xcassets/iPhone/iphone-menu.imageset/iphone-menu.png
vendored
Normal file
|
After Width: | Height: | Size: 416 KiB |
21
Shared (App)/Assets.xcassets/iPhone/iphone-popup.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "iphone-popup.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Shared (App)/Assets.xcassets/iPhone/iphone-popup.imageset/iphone-popup.png
vendored
Normal file
|
After Width: | Height: | Size: 124 KiB |
21
Shared (App)/Assets.xcassets/iPhone/iphone-url-bar.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "iphone-url-bar.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Shared (App)/Assets.xcassets/iPhone/iphone-url-bar.imageset/iphone-url-bar.png
vendored
Normal file
|
After Width: | Height: | Size: 66 KiB |
6
Shared (App)/Assets.xcassets/macOS/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
21
Shared (App)/Assets.xcassets/macOS/macos-default-popup.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "default-popup.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Shared (App)/Assets.xcassets/macOS/macos-default-popup.imageset/default-popup.png
vendored
Normal file
|
After Width: | Height: | Size: 102 KiB |
21
Shared (App)/Assets.xcassets/macOS/macos-toolbar-inactive.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "toolbar-inactive.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
Shared (App)/Assets.xcassets/macOS/macos-toolbar-inactive.imageset/toolbar-inactive.png
vendored
Normal file
|
After Width: | Height: | Size: 14 KiB |
62
Shared (App)/GettingStartediPad.swift
Normal file
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// GettingStartediPad.swift
|
||||
// Nostore
|
||||
//
|
||||
// Created by Ryan Breen on 2/18/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct GettingStartediPad: View {
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
Text("Getting Started")
|
||||
.font(.largeTitle)
|
||||
.foregroundColor(.accentColor)
|
||||
Text("iPad")
|
||||
.font(.title)
|
||||
.foregroundColor(.accentColor)
|
||||
Text("")
|
||||
Text("""
|
||||
Upon installation of the app, go to **Settings -> Safari -> Extensions** and enable **Nostore**. Open Safari and look in the toolbar, where you will see the \(Image(systemName: "puzzlepiece.extension")) icon:
|
||||
""")
|
||||
.padding([.horizontal, .top], 20)
|
||||
|
||||
Image("ipad-url-bar")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(maxWidth: 512)
|
||||
.border(Color.accentColor, width: 2)
|
||||
.padding([.top])
|
||||
|
||||
Text("You will be greeted by a menu like below:").padding([.top], 20)
|
||||
|
||||
Image("ipad-menu")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(maxWidth: 512)
|
||||
.border(Color.accentColor, width: 2)
|
||||
.padding([.top])
|
||||
|
||||
Text("""
|
||||
The **Nostore** logo is gray, indicating the extension is inactive for this site, and must be activated first. Click on the button, and give Nostore permission to access the current site. Now the Nostore logo will appear in color, and you can click it again to access the extension.
|
||||
""").multilineTextAlignment(.leading)
|
||||
.padding([.horizontal, .top], 20)
|
||||
|
||||
Image("ipad-popup")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(maxWidth: 512)
|
||||
.border(Color.accentColor, width: 2)
|
||||
.padding([.top])
|
||||
|
||||
Text("You have a default profile (with a random key) setup to start. Click the **Settings** button to configure your own keys, if you have them.").padding([.top, .bottom], 20)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct GettingStartediPad_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
GettingStartediPad()
|
||||
}
|
||||
}
|
||||
56
Shared (App)/GettingStartedmacOS.swift
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// GettingStartedmacOS.swift
|
||||
// Nostore
|
||||
//
|
||||
// Created by Ryan Breen on 2/18/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct GettingStartedmacOS: View {
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
Text("Getting Started")
|
||||
.font(.largeTitle)
|
||||
.foregroundColor(.accentColor)
|
||||
Text("macOS")
|
||||
.font(.title)
|
||||
.foregroundColor(.accentColor)
|
||||
Text("")
|
||||
Text("Upon installation of the app, open Safari. Click on the **Safari menu -> Settings... -> Extensions tab** and activate the **Nostore** extension. You will now see the Nostore icon in your Safari toolbar. For example:")
|
||||
.padding([.horizontal, .top], 20)
|
||||
|
||||
Image("macos-toolbar-inactive")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(maxWidth: 512)
|
||||
.border(Color.accentColor, width: 2)
|
||||
.padding([.top])
|
||||
|
||||
Text("""
|
||||
On the right, you can see the Nostore logo, and it is gray (or **inactive**). This means that it does not have permission to access the current website.
|
||||
|
||||
The first time you visit a Nostr client, you will need to click the icon to give Nostore permission to access the site.
|
||||
|
||||
Once active, the icon will become colored and you can select it again, where you will be greeted with a similar popup:
|
||||
""").multilineTextAlignment(.leading)
|
||||
.padding([.horizontal, .top], 20)
|
||||
|
||||
Image("macos-default-popup")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(maxWidth: 512)
|
||||
.border(Color.accentColor, width: 2)
|
||||
.padding([.top])
|
||||
|
||||
Text("You have a default profile (with a random key) setup to start. Click the **Settings** button to configure your own keys, if you have them.").padding([.top, .bottom], 20)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
struct GettingStartedmacOS_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
GettingStartedmacOS()
|
||||
}
|
||||
}
|
||||
60
Shared (App)/GettingStartiPhone.swift
Normal file
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// GettingStartediPhone.swift
|
||||
// Nostore
|
||||
//
|
||||
// Created by Ryan Breen on 2/18/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct GettingStartediPhone: View {
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
Text("Getting Started")
|
||||
.font(.largeTitle)
|
||||
.foregroundColor(.accentColor)
|
||||
Text("iPhone")
|
||||
.font(.title)
|
||||
.foregroundColor(.accentColor)
|
||||
Spacer(minLength: 20.0)
|
||||
Text("Upon installation of the app, goto **Settings -> Safari -> Extension** and enable the **Nostore** extension. Then open Safari and look in the toolbar, where you will see the \(Image(systemName: "textformat.size")) icon:")
|
||||
.padding([.horizontal, .top], 20)
|
||||
|
||||
Image("iphone-url-bar")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(maxWidth: 512)
|
||||
.border(Color.accentColor, width: 2)
|
||||
.padding([.top])
|
||||
|
||||
Text("You will be greeted by a menu like below:").padding([.top], 20)
|
||||
|
||||
Image("iphone-menu")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(maxWidth: 512)
|
||||
.border(Color.accentColor, width: 2)
|
||||
.padding([.top])
|
||||
|
||||
Text("""
|
||||
The **Nostore** logo is gray, indicating the extension is inactive for this site, and must be activated first. Click on the button, and give Nostore permission to access the current site. Now the Nostore logo will appear in color, and you can click it again to access the extension.
|
||||
""").multilineTextAlignment(.leading)
|
||||
.padding([.horizontal, .top], 20)
|
||||
|
||||
Image("iphone-popup")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(maxWidth: 512)
|
||||
.border(Color.accentColor, width: 2)
|
||||
.padding([.top])
|
||||
|
||||
Text("You have a default profile (with a random key) setup to start. Click the **Settings** button to configure your own keys, if you have them.").padding([.top, .bottom], 20)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct GettingStartediPhone_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
GettingStartediPhone()
|
||||
}
|
||||
}
|
||||
65
Shared (App)/MainView.swift
Normal file
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// HelloView.swift
|
||||
// Nostore
|
||||
//
|
||||
// Created by Ryan Breen on 2/17/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct MainView: View {
|
||||
var body: some View {
|
||||
VStack {
|
||||
NavigationStack {
|
||||
Image("bigicon").resizable().frame(width: 150.0, height: 150.0)
|
||||
Text("Nostore").font(.title)
|
||||
Text("A Safari Nostr Extension").font(.title2)
|
||||
NavigationLink("Privacy Policy") {
|
||||
PrivacyPolicyView()
|
||||
}
|
||||
#if macOS
|
||||
.buttonStyle(.link)
|
||||
#endif
|
||||
.padding(.all, 3.0)
|
||||
|
||||
NavigationLink("Getting Started: iPhone") {
|
||||
GettingStartediPhone()
|
||||
}
|
||||
#if macOS
|
||||
.buttonStyle(.link)
|
||||
#endif
|
||||
.padding(.all, 3.0)
|
||||
|
||||
NavigationLink("Getting Started: iPad") {
|
||||
GettingStartediPad()
|
||||
}
|
||||
#if macOS
|
||||
.buttonStyle(.link)
|
||||
#endif
|
||||
.padding(.all, 3.0)
|
||||
|
||||
NavigationLink("Getting Started: MacOS") {
|
||||
GettingStartedmacOS()
|
||||
}
|
||||
#if macOS
|
||||
.buttonStyle(.link)
|
||||
#endif
|
||||
.padding(.all, 3.0)
|
||||
|
||||
NavigationLink("Tips and Tricks") {
|
||||
TipsAndTricks()
|
||||
}
|
||||
#if macOS
|
||||
.buttonStyle(.link)
|
||||
#endif
|
||||
.padding(.all, 3.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MainView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
MainView()
|
||||
}
|
||||
}
|
||||
20
Shared (App)/NostoreApp.swift
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// File.swift
|
||||
// Nostore
|
||||
//
|
||||
// Created by Ryan Breen on 2/17/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
@main
|
||||
struct NostoreApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup("Nostore") {
|
||||
MainView()
|
||||
}
|
||||
#if macOS
|
||||
.defaultSize(width: 400, height: 500)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
32
Shared (App)/PrivacyPolicyView.swift
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// SwiftUIView.swift
|
||||
// Nostore
|
||||
//
|
||||
// Created by Ryan Breen on 2/17/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct PrivacyPolicyView: View {
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
Text("Privacy Policy")
|
||||
.font(.largeTitle)
|
||||
.foregroundColor(.accentColor)
|
||||
Spacer(minLength: 20)
|
||||
Text("""
|
||||
**Nostore** is developed in the spirit of Nostr.
|
||||
|
||||
You, the user, own your data. The developers of this app collect no data, anonymous or otherwise.
|
||||
|
||||
This code of this application is fully auditable and available on our [GitHub page](https://github.com/ursuscamp/nostore).
|
||||
""").multilineTextAlignment(.leading)
|
||||
}.padding(.all)
|
||||
}
|
||||
}
|
||||
|
||||
struct PrivacyPolicyView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
PrivacyPolicyView()
|
||||
}
|
||||
}
|
||||
41
Shared (App)/TipsAndTricks.swift
Normal file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// SwiftUIView.swift
|
||||
// Nostore
|
||||
//
|
||||
// Created by Ryan Breen on 2/19/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct TipsAndTricks: View {
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
Text("Tips and Tricks")
|
||||
.font(.largeTitle)
|
||||
.foregroundColor(.accentColor)
|
||||
Spacer(minLength: 20.0)
|
||||
Text("Try a few of these:")
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
Spacer(minLength: 20)
|
||||
Text("""
|
||||
1. You can have multiple profiles, each corresponding to a different key.
|
||||
|
||||
2. Click **Event History** in settings to see a list of all events signed by the extension.
|
||||
|
||||
3. Each client has its own set of permissions. You can review them at any time in **Settings**. They are organized by application host.
|
||||
|
||||
4. Clicking the event text in the **Event History** will copy a the raw event JSON.
|
||||
|
||||
5. If you have authorized the extension to talk to the client, but still don't see a special extension login button on the site, try hitting refresh on the site. The client may not recognize the extension code until you do that.
|
||||
""")
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding([.horizontal], 25)
|
||||
}.padding(.all)
|
||||
}
|
||||
}
|
||||
|
||||
struct Tipsandtricks_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
TipsAndTricks()
|
||||
}
|
||||
}
|
||||