Fix visibility issues

This commit is contained in:
William Brawner 2021-12-23 06:10:33 -07:00
parent c29bf1c33d
commit fde82a960f
9 changed files with 171 additions and 172 deletions

View file

@ -4,7 +4,7 @@
import PackageDescription
let package = Package(
name: "twigs",
name: "Twigs",
platforms: [
.macOS(.v12),
.iOS(.v15)
@ -26,7 +26,7 @@ let package = Package(
name: "Twigs",
dependencies: []),
.testTarget(
name: "twigsTests",
name: "TwigsTests",
dependencies: ["Twigs"]),
]
)

View file

@ -0,0 +1,25 @@
import Foundation
public struct Budget: Identifiable, Hashable, Codable {
public let id: String
public let name: String
public let description: String?
public let currencyCode: String?
}
public struct BudgetOverview {
public let budget: Budget
public let balance: Int
public var expectedIncome: Int = 0
public var actualIncome: Int = 0
public var expectedExpenses: Int = 0
public var actualExpenses: Int = 0
}
public protocol BudgetRepository {
func getBudgets(count: Int?, page: Int?) async throws -> [Budget]
func getBudget(_ id: String) async throws -> Budget
func newBudget(_ budget: Budget) async throws -> Budget
func updateBudget(_ budget: Budget) async throws -> Budget
func deleteBudget(_ id: String) async throws
}

View file

@ -1,16 +1,16 @@
import Foundation
struct Category: Identifiable, Hashable, Codable {
let budgetId: String
let id: String
let title: String
let description: String?
let amount: Int
let expense: Bool
let archived: Bool
public struct Category: Identifiable, Hashable, Codable {
public let budgetId: String
public let id: String
public let title: String
public let description: String?
public let amount: Int
public let expense: Bool
public let archived: Bool
}
protocol CategoryRepository {
public protocol CategoryRepository {
func getCategories(budgetId: String?, expense: Bool?, archived: Bool?, count: Int?, page: Int?) async throws -> [Category]
func getCategory(_ categoryId: String) async throws -> Category
func createCategory(_ category: Category) async throws -> Category

View file

@ -7,26 +7,26 @@
import Foundation
struct RecurringTransaction: Identifiable, Hashable, Codable {
let id: String
let title: String
let description: String?
let frequency: Frequency
let start: Date
let end: Date?
let amount: Int
let categoryId: String?
let expense: Bool
let createdBy: String
let budgetId: String
public struct RecurringTransaction: Identifiable, Hashable, Codable {
public let id: String
public let title: String
public let description: String?
public let frequency: Frequency
public let start: Date
public let end: Date?
public let amount: Int
public let categoryId: String?
public let expense: Bool
public let createdBy: String
public let budgetId: String
}
struct Frequency: Hashable, Codable, CustomStringConvertible {
let unit: FrequencyUnit
let count: Int
let time: Time
public struct Frequency: Hashable, Codable, CustomStringConvertible {
public let unit: FrequencyUnit
public let count: Int
public let time: Time
init?(unit: FrequencyUnit, count: Int, time: Time) {
public init?(unit: FrequencyUnit, count: Int, time: Time) {
if count < 1 {
return nil
}
@ -35,7 +35,7 @@ struct Frequency: Hashable, Codable, CustomStringConvertible {
self.time = time
}
init?(from string: String) {
public init?(from string: String) {
let parts = string.split(separator: ";")
guard let count = Int(parts[1]) else {
return nil
@ -73,18 +73,18 @@ struct Frequency: Hashable, Codable, CustomStringConvertible {
self.count = count
}
init(from decoder: Decoder) throws {
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let frequencyString = try container.decode(String.self)
self.init(from: frequencyString)!
}
func encode(to encoder: Encoder) throws {
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(description)
}
var description: String {
public var description: String {
// TODO: Make the backend representation of this more sensible and then use this
// return [unit.description, count.description, time.description].joined(separator: ";")
let unitParts = "\(unit)".split(separator: ";")
@ -94,19 +94,19 @@ struct Frequency: Hashable, Codable, CustomStringConvertible {
return [unitParts[0].description, count.description, unitParts[1].description, time.description].joined(separator: ";")
}
}
var naturalDescription: String {
public var naturalDescription: String {
return unit.format(count: count, time: time)
}
}
enum FrequencyUnit: Hashable, CustomStringConvertible {
public enum FrequencyUnit: Hashable, CustomStringConvertible {
case daily
case weekly(Set<DayOfWeek>)
case monthly(DayOfMonth)
case yearly(DayOfYear)
var description: String {
public var description: String {
switch self {
case .daily:
return "D"
@ -133,12 +133,12 @@ enum FrequencyUnit: Hashable, CustomStringConvertible {
}
}
struct Time: Hashable, CustomStringConvertible {
let hours: Int
let minutes: Int
let seconds: Int
public struct Time: Hashable, CustomStringConvertible {
public let hours: Int
public let minutes: Int
public let seconds: Int
init?(hours: Int, minutes: Int, seconds: Int) {
public init?(hours: Int, minutes: Int, seconds: Int) {
if hours < 0 || hours > 23 {
return nil
}
@ -153,7 +153,7 @@ struct Time: Hashable, CustomStringConvertible {
self.seconds = seconds
}
init?(from string: String) {
public init?(from string: String) {
let parts = string.split(separator: ":").compactMap {
Int($0)
}
@ -163,29 +163,29 @@ struct Time: Hashable, CustomStringConvertible {
self.init(hours: parts[0], minutes: parts[1], seconds: parts[2])
}
var description: String {
public var description: String {
return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
}
}
enum DayOfMonth: Hashable, CustomStringConvertible {
public enum DayOfMonth: Hashable, CustomStringConvertible {
case positional(Position, DayOfWeek)
case fixed(Int)
init?(position: Position, dayOfWeek: DayOfWeek) {
public init?(position: Position, dayOfWeek: DayOfWeek) {
if position == .day {
return nil
}
self = .positional(position, dayOfWeek)
}
init?(day: Int) {
public init?(day: Int) {
if day < 1 || day > 31 {
return nil
}
self = .fixed(day)
}
init?(from string: String) {
public init?(from string: String) {
let parts = string.split(separator: "-")
guard let position = Position.init(rawValue: String(parts[0])) else {
return nil
@ -203,7 +203,7 @@ enum DayOfMonth: Hashable, CustomStringConvertible {
}
}
var description: String {
public var description: String {
switch self {
case .positional(let position, let dayOfWeek):
return "\(position)-\(dayOfWeek)"
@ -213,7 +213,7 @@ enum DayOfMonth: Hashable, CustomStringConvertible {
}
}
enum Position: String, Hashable {
public enum Position: String, Hashable {
case day = "DAY"
case first = "FIRST"
case second = "SECOND"
@ -222,7 +222,7 @@ enum Position: String, Hashable {
case last = "LAST"
}
enum DayOfWeek: String, Hashable {
public enum DayOfWeek: String, Hashable {
case monday = "MONDAY"
case tuesday = "TUESDAY"
case wednesday = "WEDNESDAY"
@ -232,11 +232,11 @@ enum DayOfWeek: String, Hashable {
case sunday = "SUNDAY"
}
struct DayOfYear: Hashable, CustomStringConvertible {
let month: Int
let day: Int
public struct DayOfYear: Hashable, CustomStringConvertible {
public let month: Int
public let day: Int
init?(month: Int, day: Int) {
public init?(month: Int, day: Int) {
var maxDay: Int
switch month {
case 2:
@ -258,7 +258,7 @@ struct DayOfYear: Hashable, CustomStringConvertible {
self.month = month
}
init?(from string: String) {
public init?(from string: String) {
let parts = string.split(separator: "-").compactMap {
Int($0)
}
@ -268,12 +268,12 @@ struct DayOfYear: Hashable, CustomStringConvertible {
self.init(month: parts[0], day: parts[1])
}
var description: String {
public var description: String {
return String(format: "%02d-%02d", self.month, self.day)
}
}
protocol RecurringTransactionsRepository {
public protocol RecurringTransactionsRepository {
func getRecurringTransactions(budgetId: String) async throws -> [RecurringTransaction]
func getRecurringTransaction(_ id: String) async throws -> RecurringTransaction
func createRecurringTransaction(_ transaction: RecurringTransaction) async throws -> RecurringTransaction

View file

@ -7,31 +7,31 @@
import Foundation
struct Transaction: Identifiable, Hashable, Codable {
let id: String
let title: String
let description: String?
let date: Date
let amount: Int
let categoryId: String?
let expense: Bool
let createdBy: String
let budgetId: String
public struct Transaction: Identifiable, Hashable, Codable {
public let id: String
public let title: String
public let description: String?
public let date: Date
public let amount: Int
public let categoryId: String?
public let expense: Bool
public let createdBy: String
public let budgetId: String
}
struct BalanceResponse: Codable {
let balance: Int
public struct BalanceResponse: Codable {
public let balance: Int
}
enum TransactionType: Int, CaseIterable, Identifiable, Hashable {
public enum TransactionType: Int, CaseIterable, Identifiable, Hashable {
case expense
case income
var id: TransactionType { self }
public var id: TransactionType { self }
}
extension Transaction {
var type: TransactionType {
public var type: TransactionType {
if (self.expense) {
return .expense
} else {
@ -39,12 +39,12 @@ extension Transaction {
}
}
var amountString: String {
public var amountString: String {
return String(Double(self.amount) / 100.0)
}
}
protocol TransactionRepository {
public protocol TransactionRepository {
func getTransactions(budgetIds: [String], categoryIds: [String]?, from: Date?, to: Date?, count: Int?, page: Int?) async throws -> [Transaction]
func getTransaction(_ transactionId: String) async throws -> Transaction
func createTransaction(_ transaction: Transaction) async throws -> Transaction

View file

@ -7,10 +7,10 @@
import Foundation
class TwigsApiService: BudgetRepository, CategoryRepository, RecurringTransactionsRepository, TransactionRepository, UserRepository {
public class TwigsApiService: BudgetRepository, CategoryRepository, RecurringTransactionsRepository, TransactionRepository, UserRepository {
let requestHelper: RequestHelper
convenience init(_ serverUrl: String) {
public convenience init(_ serverUrl: String) {
self.init(RequestHelper(serverUrl))
}
@ -18,7 +18,7 @@ class TwigsApiService: BudgetRepository, CategoryRepository, RecurringTransactio
self.requestHelper = requestHelper
}
var token: String? {
public var token: String? {
get {
return requestHelper.token
}
@ -28,7 +28,7 @@ class TwigsApiService: BudgetRepository, CategoryRepository, RecurringTransactio
}
// MARK: Budgets
func getBudgets(count: Int? = nil, page: Int? = nil) async throws -> [Budget] {
public func getBudgets(count: Int? = nil, page: Int? = nil) async throws -> [Budget] {
var queries = [String: Array<String>]()
if count != nil {
queries["count"] = [String(count!)]
@ -39,25 +39,25 @@ class TwigsApiService: BudgetRepository, CategoryRepository, RecurringTransactio
return try await requestHelper.get("/api/budgets", queries: queries)
}
func getBudget(_ id: String) async throws -> Budget {
public func getBudget(_ id: String) async throws -> Budget {
return try await requestHelper.get("/api/budgets/\(id)")
}
func newBudget(_ budget: Budget) async throws -> Budget {
public func newBudget(_ budget: Budget) async throws -> Budget {
return try await requestHelper.post("/api/budgets", data: budget, type: Budget.self)
}
func updateBudget(_ budget: Budget) async throws -> Budget {
public func updateBudget(_ budget: Budget) async throws -> Budget {
return try await requestHelper.put("/api/budgets/\(budget.id)", data: budget)
}
func deleteBudget(_ id: String) async throws {
public func deleteBudget(_ id: String) async throws {
return try await requestHelper.delete("/api/budgets/\(id)")
}
// MARK: Transactions
func getTransactions(
public func getTransactions(
budgetIds: [String],
categoryIds: [String]? = nil,
from: Date? = nil,
@ -85,23 +85,23 @@ class TwigsApiService: BudgetRepository, CategoryRepository, RecurringTransactio
return try await requestHelper.get("/api/transactions", queries: queries)
}
func getTransaction(_ id: String) async throws -> Transaction {
public func getTransaction(_ id: String) async throws -> Transaction {
return try await requestHelper.get("/api/transactions/\(id)")
}
func createTransaction(_ transaction: Transaction) async throws -> Transaction {
public func createTransaction(_ transaction: Transaction) async throws -> Transaction {
return try await requestHelper.post("/api/transactions", data: transaction, type: Transaction.self)
}
func updateTransaction(_ transaction: Transaction) async throws -> Transaction {
public func updateTransaction(_ transaction: Transaction) async throws -> Transaction {
return try await requestHelper.put("/api/transactions/\(transaction.id)", data: transaction)
}
func deleteTransaction(_ id: String) async throws {
public func deleteTransaction(_ id: String) async throws {
return try await requestHelper.delete("/api/transactions/\(id)")
}
func sumTransactions(budgetId: String? = nil, categoryId: String? = nil, from: Date? = nil, to: Date? = nil) async throws -> BalanceResponse {
public func sumTransactions(budgetId: String? = nil, categoryId: String? = nil, from: Date? = nil, to: Date? = nil) async throws -> BalanceResponse {
var queries = [String: Array<String>]()
if let budgetId = budgetId {
queries["budgetId"] = [budgetId]
@ -119,8 +119,7 @@ class TwigsApiService: BudgetRepository, CategoryRepository, RecurringTransactio
}
// MARK: Categories
func getCategories(budgetId: String? = nil, expense: Bool? = nil, archived: Bool? = nil, count: Int? = nil, page: Int? = nil) async throws -> [Category] {
public func getCategories(budgetId: String? = nil, expense: Bool? = nil, archived: Bool? = nil, count: Int? = nil, page: Int? = nil) async throws -> [Category] {
var queries = [String: Array<String>]()
if budgetId != nil {
queries["budgetIds"] = [String(budgetId!)]
@ -140,28 +139,28 @@ class TwigsApiService: BudgetRepository, CategoryRepository, RecurringTransactio
return try await requestHelper.get("/api/categories", queries: queries)
}
func getCategory(_ id: String) async throws -> Category {
public func getCategory(_ id: String) async throws -> Category {
return try await requestHelper.get("/api/categories/\(id)")
}
func getCategoryBalance(_ id: String) async throws -> Int {
public func getCategoryBalance(_ id: String) async throws -> Int {
return try await requestHelper.get("/api/categories/\(id)/balance")
}
func createCategory(_ category: Category) async throws -> Category {
public func createCategory(_ category: Category) async throws -> Category {
return try await requestHelper.post("/api/categories", data: category, type: Category.self)
}
func updateCategory(_ category: Category) async throws -> Category {
public func updateCategory(_ category: Category) async throws -> Category {
return try await requestHelper.put("/api/categories/\(category.id)", data: category)
}
func deleteCategory(_ id: String) async throws {
public func deleteCategory(_ id: String) async throws {
return try await requestHelper.delete("/api/categories/\(id)")
}
// MARK: Users
func login(username: String, password: String) async throws -> LoginResponse {
public func login(username: String, password: String) async throws -> LoginResponse {
let response = try await requestHelper.post(
"/api/users/login",
data: LoginRequest(username: username, password: password),
@ -171,7 +170,7 @@ class TwigsApiService: BudgetRepository, CategoryRepository, RecurringTransactio
return response
}
func register(username: String, email: String, password: String) async throws -> User {
public func register(username: String, email: String, password: String) async throws -> User {
return try await requestHelper.post(
"/api/users/register",
data: RegistrationRequest(username: username, email: email, password: password),
@ -179,18 +178,18 @@ class TwigsApiService: BudgetRepository, CategoryRepository, RecurringTransactio
)
}
func getUser(_ id: String) async throws -> User {
public func getUser(_ id: String) async throws -> User {
return try await requestHelper.get("/api/users/\(id)")
}
func searchUsers(_ query: String) async throws -> [User] {
public func searchUsers(_ query: String) async throws -> [User] {
return try await requestHelper.get(
"/api/users/search",
queries: ["query": [query]]
)
}
func getUsers(count: Int? = nil, page: Int? = nil) async throws -> [User] {
public func getUsers(count: Int? = nil, page: Int? = nil) async throws -> [User] {
var queries = [String: Array<String>]()
if count != nil {
queries["count"] = [String(count!)]
@ -201,36 +200,36 @@ class TwigsApiService: BudgetRepository, CategoryRepository, RecurringTransactio
return try await requestHelper.get("/api/Users", queries: queries)
}
func newUser(_ user: User) async throws -> User {
public func newUser(_ user: User) async throws -> User {
return try await requestHelper.post("/api/users", data: user, type: User.self)
}
func updateUser(_ user: User) async throws -> User {
public func updateUser(_ user: User) async throws -> User {
return try await requestHelper.put("/api/users/\(user.id)", data: user)
}
func deleteUser(_ user: User) async throws {
public func deleteUser(_ user: User) async throws {
return try await requestHelper.delete("/api/users/\(user.id)")
}
// MARK: Recurring Transactions
func getRecurringTransactions(budgetId: String) async throws -> [RecurringTransaction] {
public func getRecurringTransactions(budgetId: String) async throws -> [RecurringTransaction] {
return try await requestHelper.get("/api/recurringtransactions", queries: ["budgetId": [budgetId]])
}
func getRecurringTransaction(_ id: String) async throws -> RecurringTransaction {
public func getRecurringTransaction(_ id: String) async throws -> RecurringTransaction {
return try await requestHelper.get("/api/recurringtransactions/\(id)")
}
func createRecurringTransaction(_ transaction: RecurringTransaction) async throws -> RecurringTransaction {
public func createRecurringTransaction(_ transaction: RecurringTransaction) async throws -> RecurringTransaction {
return try await requestHelper.post("/api/recurringtransactions", data: transaction, type: RecurringTransaction.self)
}
func updateRecurringTransaction(_ transaction: RecurringTransaction) async throws -> RecurringTransaction {
public func updateRecurringTransaction(_ transaction: RecurringTransaction) async throws -> RecurringTransaction {
return try await requestHelper.put("/api/recurringtransactions/\(transaction.id)", data: transaction)
}
func deleteRecurringTransaction(_ id: String) async throws {
public func deleteRecurringTransaction(_ id: String) async throws {
return try await requestHelper.delete("/api/recurringtransactions/\(id)")
}
}

39
Sources/Twigs/User.swift Normal file
View file

@ -0,0 +1,39 @@
//
// File.swift
//
//
// Created by William Brawner on 12/22/21.
//
import Foundation
public struct User: Codable, Equatable, Hashable {
public let id: String
public let username: String
public let email: String?
public let avatar: String?
}
public struct LoginRequest: Codable {
public let username: String
public let password: String
}
public struct LoginResponse: Codable {
public let token: String
public let expiration: String
public let userId: String
}
public struct RegistrationRequest: Codable {
public let username: String
public let email: String
public let password: String
}
public protocol UserRepository {
func getUser(_ id: String) async throws -> User
func searchUsers(_ withUsername: String) async throws -> [User]
func login(username: String, password: String) async throws -> LoginResponse
func register(username: String, email: String, password: String) async throws -> User
}

View file

@ -1,25 +0,0 @@
import Foundation
struct Budget: Identifiable, Hashable, Codable {
let id: String
let name: String
let description: String?
let currencyCode: String?
}
struct BudgetOverview {
let budget: Budget
let balance: Int
var expectedIncome: Int = 0
var actualIncome: Int = 0
var expectedExpenses: Int = 0
var actualExpenses: Int = 0
}
protocol BudgetRepository {
func getBudgets(count: Int?, page: Int?) async throws -> [Budget]
func getBudget(_ id: String) async throws -> Budget
func newBudget(_ budget: Budget) async throws -> Budget
func updateBudget(_ budget: Budget) async throws -> Budget
func deleteBudget(_ id: String) async throws
}

View file

@ -1,39 +0,0 @@
//
// File.swift
//
//
// Created by William Brawner on 12/22/21.
//
import Foundation
struct User: Codable, Equatable, Hashable {
let id: String
let username: String
let email: String?
let avatar: String?
}
struct LoginRequest: Codable {
let username: String
let password: String
}
struct LoginResponse: Codable {
let token: String
let expiration: String
let userId: String
}
struct RegistrationRequest: Codable {
let username: String
let email: String
let password: String
}
protocol UserRepository {
func getUser(_ id: String) async throws -> User
func searchUsers(_ withUsername: String) async throws -> [User]
func login(username: String, password: String) async throws -> LoginResponse
func register(username: String, email: String, password: String) async throws -> User
}