index — walletdrain @ 5f1d8fd78ee8974f9b98b5fcc352ead370265b9c

Little app to track my spendings, for the time being only for music

master view without adding functionality
crispy-caesus 114518720+crispy-caesus@users.noreply.github.com
Wed, 08 Jan 2025 13:03:43 +0100
commit

5f1d8fd78ee8974f9b98b5fcc352ead370265b9c

parent

645fbfa5bf318421015a75a6c4af8a571a9127f3

3 files changed, 207 insertions(+), 136 deletions(-)

jump to
M app.dbapp.db

          
M main.gomain.go

@@ -11,28 +11,35 @@ "fyne.io/fyne/v2/widget"

_ "github.com/mattn/go-sqlite3" ) -// Data structures for our tables type TableData struct { - ID string - Name string - Value string - Section int + ID int + name string + price float32 + currency string + returned_price float32 + returned_currency string + category string + seller string + note string } -// Database functions func initDB(dbPath string) *sql.DB { db, err := sql.Open("sqlite3", dbPath) if err != nil { log.Fatal(err) } - // Create table if it doesn't exist createTableSQL := ` - CREATE TABLE IF NOT EXISTS items ( - id TEXT PRIMARY KEY, - name TEXT, - value TEXT, - section INTEGER + CREATE TABLE IF NOT EXISTS music ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + price FLOAT, + currency TEXT, + returned_price FLOAT, + returned_currency TEXT, + category TEXT, + seller TEXT, + note TEXT );` _, err = db.Exec(createTableSQL)

@@ -43,8 +50,8 @@

return db } -func getItemsForSection(db *sql.DB, section int) []TableData { - rows, err := db.Query("SELECT id, name, value, section FROM items WHERE section = ?", section) +func getItemsForCategory(db *sql.DB, category string) []TableData { + rows, err := db.Query("SELECT * FROM music WHERE category = ?", category) if err != nil { log.Printf("Query error: %v", err) return nil

@@ -54,7 +61,17 @@

var items []TableData for rows.Next() { var item TableData - err := rows.Scan(&item.ID, &item.Name, &item.Value, &item.Section) + err := rows.Scan( + &item.ID, + &item.name, + &item.price, + &item.currency, + &item.returned_price, + &item.returned_currency, + &item.category, + &item.seller, + &item.note, + ) if err != nil { log.Printf("Row scan error: %v", err) continue

@@ -65,167 +82,223 @@ return items

} func updateItem(db *sql.DB, item TableData) error { - _, err := db.Exec( - "UPDATE items SET name = ?, value = ? WHERE id = ? AND section = ?", - item.Name, item.Value, item.ID, item.Section, + _, err := db.Exec(` + UPDATE music + SET name = ?, + price = ?, + currency = ?, + returned_price = ?, + returned_currency = ?, + category = ?, + seller = ?, + note = ? + WHERE id = ?`, + item.name, + item.price, + item.currency, + item.returned_price, + item.returned_currency, + item.category, + item.seller, + item.note, + item.ID, ) + if err != nil { + log.Printf("Update error: %v", err) + } return err } +func createSectionView(db *sql.DB, category string, onBack func()) *fyne.Container { + data := getItemsForCategory(db, category) + + // Create edit panel widgets + var currentItem TableData // Store the currently selected item + + nameEntry := widget.NewEntry() + priceEntry := widget.NewEntry() + currencyEntry := widget.NewEntry() + returnedPriceEntry := widget.NewEntry() + returnedCurrencyEntry := widget.NewEntry() + sellerEntry := widget.NewEntry() + noteEntry := widget.NewMultiLineEntry() + + refreshData := func() { + data = getItemsForCategory(db, category) + } + + // Set up column headers + headers := []string{"Name", "Seller", "Price"} + columnWidths := []float32{300, 200, 150} + + table := widget.NewTable( + func() (int, int) { + return len(data) + 1, len(headers) // +1 for header row + }, + func() fyne.CanvasObject { + label := widget.NewLabel("") + label.Wrapping = fyne.TextWrapWord + return label + }, + func(i widget.TableCellID, o fyne.CanvasObject) { + label := o.(*widget.Label) + label.TextStyle = fyne.TextStyle{} // Reset text style + + // Header row + if i.Row == 0 { + label.TextStyle = fyne.TextStyle{Bold: true} + if i.Col < len(headers) { + label.SetText(headers[i.Col]) + } + return + } + + // Data rows + dataRow := i.Row - 1 // Adjust for header row + if dataRow < len(data) { + item := data[dataRow] + switch i.Col { + case 0: + label.SetText(item.name) + case 1: + label.SetText(item.seller) + case 2: + label.SetText(fmt.Sprintf("%.2f %s", item.price, item.currency)) + } + } + }, + ) + + // Set column widths + for i, width := range columnWidths { + table.SetColumnWidth(i, width) + } + + editPanel := container.NewVBox( + widget.NewLabel("Edit Item"), + widget.NewLabel("Name:"), + nameEntry, + widget.NewLabel("Price:"), + priceEntry, + widget.NewLabel("Currency:"), + currencyEntry, + widget.NewLabel("Returned Price:"), + returnedPriceEntry, + widget.NewLabel("Returned Currency:"), + returnedCurrencyEntry, + widget.NewLabel("Seller:"), + sellerEntry, + widget.NewLabel("Note:"), + noteEntry, + widget.NewButton("Save", func() { + var price, returnedPrice float32 + fmt.Sscanf(priceEntry.Text, "%f", &price) + fmt.Sscanf(returnedPriceEntry.Text, "%f", &returnedPrice) + + item := TableData{ + ID: currentItem.ID, + name: nameEntry.Text, + price: price, + currency: currencyEntry.Text, + returned_price: returnedPrice, + returned_currency: returnedCurrencyEntry.Text, + category: category, + seller: sellerEntry.Text, + note: noteEntry.Text, + } + + err := updateItem(db, item) + if err != nil { + log.Printf("Error updating item: %v", err) + } else { + refreshData() + table.Refresh() + } + }), + ) + + table.OnSelected = func(id widget.TableCellID) { + if id.Row > 0 && (id.Row-1) < len(data) { + currentItem = data[id.Row-1] // Store the currently selected item + nameEntry.SetText(currentItem.name) + priceEntry.SetText(fmt.Sprintf("%.2f", currentItem.price)) + currencyEntry.SetText(currentItem.currency) + returnedPriceEntry.SetText(fmt.Sprintf("%.2f", currentItem.returned_price)) + returnedCurrencyEntry.SetText(currentItem.returned_currency) + sellerEntry.SetText(currentItem.seller) + noteEntry.SetText(currentItem.note) + } + } + + header := container.NewHBox( + widget.NewButton("Back", onBack), + widget.NewLabel(fmt.Sprintf("Category: %s", category)), + ) + + split := container.NewHSplit(table, editPanel) + split.SetOffset(0.7) // Give table 70% of the width + + return container.NewBorder(header, nil, nil, nil, split) +} + func main() { myApp := app.New() window := myApp.NewWindow("walletdrain") - // Initialize database db := initDB("./app.db") defer db.Close() - // Insert some sample data if the database is empty var count int - err := db.QueryRow("SELECT COUNT(*) FROM items").Scan(&count) + err := db.QueryRow("SELECT COUNT(*) FROM music").Scan(&count) if err != nil { log.Fatal(err) } if count == 0 { sampleData := []TableData{ - {"1", "Item 1", "Value 1", 1}, - {"2", "Item 2", "Value 2", 1}, - {"3", "Section 2 Item 1", "Value 1", 2}, - {"4", "Section 2 Item 2", "Value 2", 2}, - {"5", "Section 3 Item 1", "Value 1", 3}, - {"6", "Section 3 Item 2", "Value 2", 3}, + {name: "Sample Album 1", price: 29.99, currency: "USD", returned_price: 0, returned_currency: "", category: "vinyl", seller: "Record Store", note: "New condition"}, + {name: "Sample Album 2", price: 19.99, currency: "EUR", returned_price: 15.00, returned_currency: "EUR", category: "cd", seller: "Online Shop", note: "Used"}, } for _, item := range sampleData { _, err := db.Exec( - "INSERT INTO items (id, name, value, section) VALUES (?, ?, ?, ?)", - item.ID, item.Name, item.Value, item.Section, + "INSERT INTO music (name, price, currency, returned_price, returned_currency, category, seller, note) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + item.name, item.price, item.currency, item.returned_price, item.returned_currency, item.category, item.seller, item.note, ) if err != nil { log.Printf("Error inserting sample data: %v", err) } } } - - // Function to create a section view with table and side panel - createSectionView := func(sectionNum int, onBack func()) *fyne.Container { - // Get initial data for this section - data := getItemsForSection(db, sectionNum) - - // Create edit panel widgets - idEntry := widget.NewEntry() - nameEntry := widget.NewEntry() - valueEntry := widget.NewEntry() - - // Function to refresh data and update table - refreshData := func() { - data = getItemsForSection(db, sectionNum) - } - - // Create table - table := widget.NewTable( - func() (int, int) { - return len(data), 3 // Rows and columns - }, - func() fyne.CanvasObject { - return widget.NewLabel("Cell") - }, - func(i widget.TableCellID, o fyne.CanvasObject) { - label := o.(*widget.Label) - if i.Row < len(data) { - switch i.Col { - case 0: - label.SetText(data[i.Row].ID) - case 1: - label.SetText(data[i.Row].Name) - case 2: - label.SetText(data[i.Row].Value) - } - } - }, - ) - - // Create the side panel - editPanel := container.NewVBox( - widget.NewLabel("Edit Item"), - widget.NewLabel("ID:"), - idEntry, - widget.NewLabel("Name:"), - nameEntry, - widget.NewLabel("Value:"), - valueEntry, - widget.NewButton("Save", func() { - item := TableData{ - ID: idEntry.Text, - Name: nameEntry.Text, - Value: valueEntry.Text, - Section: sectionNum, - } - err := updateItem(db, item) - if err != nil { - log.Printf("Error updating item: %v", err) - } else { - refreshData() - table.Refresh() - } - }), - ) - editPanel.Hide() - - // Handle table selection - table.OnSelected = func(id widget.TableCellID) { - editPanel.Show() - if id.Row < len(data) { - idEntry.SetText(data[id.Row].ID) - nameEntry.SetText(data[id.Row].Name) - valueEntry.SetText(data[id.Row].Value) - } - } - - // Create header with back button - header := container.NewHBox( - widget.NewButton("Back", onBack), - widget.NewLabel(fmt.Sprintf("Section %d", sectionNum)), - ) - - // Create split container for table and edit panel - split := container.NewHSplit(table, editPanel) - - // Arrange everything vertically - return container.NewBorder(header, nil, nil, nil, split) - } - - // Create the main content container that will hold our views + content := container.NewStack() - // Declare sectionSelect before using it in closures - var sectionSelect *fyne.Container + var categorySelect *fyne.Container - sectionSelect = container.NewVBox( - widget.NewLabel("Select a Section"), - widget.NewButton("Section 1", func() { + categorySelect = container.NewVBox( + widget.NewLabel("Select a Category"), + widget.NewButton("Vinyl", func() { content.Objects = []fyne.CanvasObject{ - createSectionView(1, func() { - content.Objects = []fyne.CanvasObject{sectionSelect} + createSectionView(db, "vinyl", func() { + content.Objects = []fyne.CanvasObject{categorySelect} content.Refresh() }), } content.Refresh() }), - widget.NewButton("Section 2", func() { + widget.NewButton("CD", func() { content.Objects = []fyne.CanvasObject{ - createSectionView(2, func() { - content.Objects = []fyne.CanvasObject{sectionSelect} + createSectionView(db, "cd", func() { + content.Objects = []fyne.CanvasObject{categorySelect} content.Refresh() }), } content.Refresh() }), - widget.NewButton("Section 3", func() { + widget.NewButton("Cassette", func() { content.Objects = []fyne.CanvasObject{ - createSectionView(3, func() { - content.Objects = []fyne.CanvasObject{sectionSelect} + createSectionView(db, "cassette", func() { + content.Objects = []fyne.CanvasObject{categorySelect} content.Refresh() }), }

@@ -233,11 +306,9 @@ content.Refresh()

}), ) - // Initialize with section selection screen - content.Objects = []fyne.CanvasObject{sectionSelect} + content.Objects = []fyne.CanvasObject{categorySelect} - // Set up the window window.SetContent(content) - window.Resize(fyne.NewSize(800, 600)) + window.Resize(fyne.NewSize(1024, 768)) window.ShowAndRun() }