Skip to content
This repository was archived by the owner on Aug 18, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions brain-marks.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
/* Begin PBXBuildFile section */
20636BDDDBEF4EAE9CCE9D9E /* amplifyconfiguration.json in Resources */ = {isa = PBXBuildFile; fileRef = ECA1CF04DB754255822691F2 /* amplifyconfiguration.json */; };
684E2F2D3FCC4D36AC68E57D /* AWSCategory+Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 551BA45F30D640118D2F0CE2 /* AWSCategory+Schema.swift */; };
6961687B2949756D00D68070 /* BrainMarks.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 696168792949756D00D68070 /* BrainMarks.xcdatamodeld */; };
6961687F294976A600D68070 /* StorageProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6961687E294976A600D68070 /* StorageProvider.swift */; };
696168812949856100D68070 /* StoreageProvider+Category.swift in Sources */ = {isa = PBXBuildFile; fileRef = 696168802949856100D68070 /* StoreageProvider+Category.swift */; };
69616883294988E700D68070 /* StorageProvider+Tweet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69616882294988E700D68070 /* StorageProvider+Tweet.swift */; };
6961688629498D0600D68070 /* MigrationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6961688529498D0600D68070 /* MigrationService.swift */; };
91739DEB2622D2A7000F982A /* AddURLView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91739DEA2622D2A7000F982A /* AddURLView.swift */; };
91C8958926228D1500689196 /* Tweet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91C8958826228D1500689196 /* Tweet.swift */; };
9C9314E5631F4C39AA06BF35 /* awsconfiguration.json in Resources */ = {isa = PBXBuildFile; fileRef = DA7D79B731BC4ECFAAE8E817 /* awsconfiguration.json */; };
Expand Down Expand Up @@ -72,6 +77,11 @@
1E886624D4EE4F64B9160A75 /* amplifytools.xcconfig */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = text.xcconfig; path = amplifytools.xcconfig; sourceTree = "<group>"; };
551BA45F30D640118D2F0CE2 /* AWSCategory+Schema.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = "AWSCategory+Schema.swift"; path = "amplify/generated/models/AWSCategory+Schema.swift"; sourceTree = "<group>"; };
63D0518628EF45A382F08352 /* AWSCategory.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = AWSCategory.swift; path = amplify/generated/models/AWSCategory.swift; sourceTree = "<group>"; };
6961687A2949756D00D68070 /* BrainMarks.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = BrainMarks.xcdatamodel; sourceTree = "<group>"; };
6961687E294976A600D68070 /* StorageProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageProvider.swift; sourceTree = "<group>"; };
696168802949856100D68070 /* StoreageProvider+Category.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StoreageProvider+Category.swift"; sourceTree = "<group>"; };
69616882294988E700D68070 /* StorageProvider+Tweet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StorageProvider+Tweet.swift"; sourceTree = "<group>"; };
6961688529498D0600D68070 /* MigrationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationService.swift; sourceTree = "<group>"; };
91739DEA2622D2A7000F982A /* AddURLView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddURLView.swift; sourceTree = "<group>"; };
91C8958826228D1500689196 /* Tweet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tweet.swift; sourceTree = "<group>"; };
A205CD412622A3EB00517DB5 /* TweetList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TweetList.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -155,6 +165,25 @@
path = .;
sourceTree = "<group>";
};
69616871294973F500D68070 /* CoreData */ = {
isa = PBXGroup;
children = (
696168792949756D00D68070 /* BrainMarks.xcdatamodeld */,
6961687E294976A600D68070 /* StorageProvider.swift */,
69616882294988E700D68070 /* StorageProvider+Tweet.swift */,
696168802949856100D68070 /* StoreageProvider+Category.swift */,
);
path = CoreData;
sourceTree = "<group>";
};
6961688429498CF100D68070 /* Services */ = {
isa = PBXGroup;
children = (
6961688529498D0600D68070 /* MigrationService.swift */,
);
path = Services;
sourceTree = "<group>";
};
6D7FDBA2D37342B39C7F1C69 /* AmplifyConfig */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -279,7 +308,9 @@
isa = PBXGroup;
children = (
FF39430E262E863000A3623B /* AmplifyModelExtensions */,
69616871294973F500D68070 /* CoreData */,
FF39430C262E860E00A3623B /* Managers */,
6961688429498CF100D68070 /* Services */,
91C8958726228CF600689196 /* Models */,
FF39432A262FD05700A3623B /* Categories */,
FF39432D262FD0AD00A3623B /* Tweets */,
Expand Down Expand Up @@ -485,18 +516,22 @@
buildActionMask = 2147483647;
files = (
91C8958926228D1500689196 /* Tweet.swift in Sources */,
6961687F294976A600D68070 /* StorageProvider.swift in Sources */,
FFEBBB3C26223F75000F475F /* ContentView.swift in Sources */,
FF554149282E9609002AEBED /* JSONDataManager.swift in Sources */,
A224A9E62622BCED00AC12AF /* TweetCard.swift in Sources */,
6961687B2949756D00D68070 /* BrainMarks.xcdatamodeld in Sources */,
FFCB1097263E31D400544309 /* ReturnedTweet.swift in Sources */,
FFC4CA7726867B4C00427C81 /* BMButton.swift in Sources */,
69616883294988E700D68070 /* StorageProvider+Tweet.swift in Sources */,
FF21986F269FE57D00FFB406 /* AsyncImage.swift in Sources */,
FFEB1B5826A9F9C300682C37 /* Alert.swift in Sources */,
FF36B6712623678D007A6D7F /* AWSTweet+Extension.swift in Sources */,
FFEBBB7626226A39000F475F /* Secrets.swift in Sources */,
A2F449912622829D00725FEA /* CategoryList.swift in Sources */,
A2F4498C2622802B00725FEA /* CategoryRow.swift in Sources */,
FF5990692622DD61004DF328 /* DataStoreManager.swift in Sources */,
6961688629498D0600D68070 /* MigrationService.swift in Sources */,
FFCB1099263E3E2D00544309 /* CategorySheetView.swift in Sources */,
FF394316262FCF3900A3623B /* User.swift in Sources */,
FFEBBB3A26223F75000F475F /* brain_marksApp.swift in Sources */,
Expand All @@ -507,6 +542,7 @@
CF16AFB9BE3F401E98C85114 /* AWSTweet.swift in Sources */,
FF36B661262357F9007A6D7F /* AWSCategory+Extension.swift in Sources */,
FFD5152E28F9FAA500665625 /* TelemetrySignals.swift in Sources */,
696168812949856100D68070 /* StoreageProvider+Category.swift in Sources */,
FF36B66C26235FE6007A6D7F /* TweetListViewModel.swift in Sources */,
C4392E80BFE640DAA2625F9D /* AWSTweet+Schema.swift in Sources */,
A205CD422622A3EB00517DB5 /* TweetList.swift in Sources */,
Expand Down Expand Up @@ -879,6 +915,19 @@
productName = TelemetryClient;
};
/* End XCSwiftPackageProductDependency section */

/* Begin XCVersionGroup section */
696168792949756D00D68070 /* BrainMarks.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
6961687A2949756D00D68070 /* BrainMarks.xcdatamodel */,
);
currentVersion = 6961687A2949756D00D68070 /* BrainMarks.xcdatamodel */;
path = BrainMarks.xcdatamodeld;
sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel;
};
/* End XCVersionGroup section */
};
rootObject = FFEBBB2E26223F75000F475F /* Project object */;
}
56 changes: 32 additions & 24 deletions brain-marks/Add/AddURLView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,49 +11,60 @@ import UIKit

struct AddURLView: View {
@State private var showingAlert = false
@State private var selectedCategory = AWSCategory(name: "")
@State private var selectedCategory: CategoryEntity
@State var newEntry = ""
@Environment(\.presentationMode) var presentationMode
let categories: [AWSCategory]
let categories: [CategoryEntity]

@StateObject var viewModel = AddURLViewModel()

let pasteBoard = UIPasteboard.general

private let storageProvider = StorageProvider.shared

init(categories: [CategoryEntity]) {
self.categories = categories
self._selectedCategory = State(initialValue: categories.first!)
}

var body: some View {
NavigationView {
Form {
TextField("Enter copied url", text: $newEntry)
.autocapitalization(.none)
Picker(selection: $selectedCategory , label: Text("Category"), content: {
ForEach(categories,id:\.self) { category in
Text(category.name).tag(category.id)
ForEach(categories, id:\.self) { category in
Text(category.name ?? "No name").tag(category)
}
})
}
.navigationBarItems(
trailing: Button("Save") {
if selectedCategory.name == "" {
viewModel.alertItem = AlertContext.noCategory
showingAlert = true
} else {
viewModel.fetchTweet(url: newEntry) { result in
switch result {
case .success(let tweet):

DataStoreManger.shared.fetchCategories { (result) in
if case .success(_) = result {
DataStoreManger.shared.createTweet(
tweet: tweet,
category: selectedCategory)
}
viewModel.fetchTweet(url: newEntry) { result in
switch result {
case .success(let tweet):
let tweetEntity = TweetEntity(context: storageProvider.context)
tweetEntity.authorName = tweet.authorName
tweetEntity.authorUsername = tweet.authorUsername
tweetEntity.dateCreated = Date()
tweetEntity.id = UUID()
tweetEntity.profileImageURL = tweet.profileImageURL
tweetEntity.text = tweet.text
tweetEntity.tweetID = tweet.id

// Category edits
selectedCategory.addToTweets(tweetEntity)
selectedCategory.dateModified = Date()

do {
try storageProvider.context.save()
TelemetryManager.send(TelemetrySignals.addTweet)
presentationMode.wrappedValue.dismiss()
} catch {
print("❌ AddURLView.save() Error: \(error)")
}

case .failure(_):
case .failure:
viewModel.alertItem = AlertContext.badURL
}
}
}
})
Expand All @@ -63,9 +74,6 @@ struct AddURLView: View {
newEntry = pasteBoard.string ?? ""
}
}
.onDisappear {
selectedCategory.name = ""
}
.alert(item: $viewModel.alertItem) { alertItem in
Alert(title: Text(alertItem.title),
message: Text(alertItem.message),
Expand Down
59 changes: 38 additions & 21 deletions brain-marks/Categories/CategoryListViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,49 @@
import SwiftUI

final class CategoryListViewModel: ObservableObject {

@Published var categories = [AWSCategory]()

let storageProvider: StorageProvider

@Published var categories: [CategoryEntity]

init() {
/// Using a compiler statement here to determine where the code is being ran.
/// A compiler statement was chosen so that it doesn't interfere with run time
/// in production.
///
/// If it's being ran in the canvas (preview) then we want to use the preview container
/// If it's being ran not in the canvas, then we want to use the CoreData file for existing data.
#if DEBUG
// Checks if the code is running in the cancas (preview)
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
storageProvider = .preview
} else {
storageProvider = .shared
}
#else
storageProvider = .shared
#endif
categories = []
}

func getCategories() {
categories = []
DataStoreManger.shared.fetchCategories { result in
switch result {
case .success(let categories):
DispatchQueue.main.async {
self.categories = categories
}
case .failure(let error):
print("Error fetching categories: \(error)")
}
}
categories = storageProvider.getAllCategories()
}

func deleteCategory(at offsets: IndexSet) {
for offset in offsets {
let category = categories[offset]
DataStoreManger.shared.deleteCategory(category: category)
for _ in offsets {
offsets.sorted(by: >).forEach { index in
let category = categories[index]
storageProvider.context.delete(category)
do {
try storageProvider.context.save()
} catch {
print("❌ CategoryListViewModel.deleteCategory(at:) Error \(error)")
}
}
}
withAnimation {
categories.remove(atOffsets: offsets)
}
categories.remove(atOffsets: offsets)
}

func editCategoryName(category: AWSCategory, newName: String) {
DataStoreManger.shared.editCategory(category: category, newName: newName)
}
}
23 changes: 11 additions & 12 deletions brain-marks/Categories/Views/CategoryList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,15 @@ enum CategoryState {
}

struct CategoryList: View {

@State private var categorySheetState: CategoryState = .new
@State private var editCategory: AWSCategory?
@State private var editCategory: CategoryEntity?
@State private var indexSetToDelete: IndexSet?
@State private var showAddURLView = false
@State private var showingCategorySheet = false
@State private var showingDeleteActionSheet = false

@StateObject var viewModel = CategoryListViewModel()
@StateObject private var viewModel = CategoryListViewModel()

var body: some View {
NavigationView {
categoryList
Expand Down Expand Up @@ -52,6 +51,9 @@ struct CategoryList: View {
}
.sheet(isPresented: $showAddURLView) {
AddURLView(categories: viewModel.categories)
.onDisappear {
viewModel.getCategories()
}
}
}
}
Expand All @@ -66,12 +68,6 @@ struct CategoryList: View {
@ViewBuilder
var categoryList: some View {
categories
// removing for now, this makes the UI "flash" when updating a category
// if viewModel.categories.isEmpty {
// emptyListView
// } else {
// categories
// }
}

var emptyListView: some View {
Expand All @@ -82,9 +78,12 @@ struct CategoryList: View {

var categories: some View {
List {
ForEach(viewModel.categories) { category in
ForEach(viewModel.categories, id: \.self) { category in
NavigationLink(destination: TweetList(category: category)) {
CategoryRow(category: category)
CategoryRow(
categoryName: category.name ?? "",
categoryImage: category.imageName ?? "folder"
)
}
.contextMenu {
Button {
Expand Down
17 changes: 12 additions & 5 deletions brain-marks/Categories/Views/CategoryRow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@
import SwiftUI

struct CategoryRow: View {
let category: AWSCategory
let categoryName: String
let categoryImage: String

var body: some View {
HStack {
Image(systemName: category.imageName ?? "folder")
Image(systemName: categoryImage)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 40, height: 40)
Text(category.name)
Text(categoryName)
Spacer()
}
}
Expand All @@ -25,8 +26,14 @@ struct CategoryRow: View {
struct CategoryRow_Previews: PreviewProvider {
static var previews: some View {
Group {
CategoryRow(category: AWSCategory(id: "234", name: "SwiftUI", imageName: "swift"))
CategoryRow(category: AWSCategory(id: "987", name: "BigBrainHacks", imageName: "laptopcomputer"))
CategoryRow(
categoryName: "iOS Tips and Tricks",
categoryImage: "folder"
)
CategoryRow(
categoryName: "macOS Tips and Tricks",
categoryImage: "swift"
)
}
.previewLayout(.fixed(width: 300, height: 70))
}
Expand Down
Loading