diff --git a/.godocdown.import b/.godocdown.import new file mode 100644 index 0000000000..65b64165a0 --- /dev/null +++ b/.godocdown.import @@ -0,0 +1 @@ +fyne.io/fyne/v2 diff --git a/.travis.yml b/.travis.yml index 3219363389..aa8e7bc774 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: go -go_import_path: fyne.io/fyne +go_import_path: fyne.io/fyne/v2 addons: apt: diff --git a/AUTHORS b/AUTHORS index 48bff52d58..133acd1a83 100644 --- a/AUTHORS +++ b/AUTHORS @@ -7,3 +7,5 @@ Tilo Prütz Stephen Houston Storm Hess Stuart Scott +Jacob Alzén <> +Charles A. Daniels diff --git a/CHANGELOG.md b/CHANGELOG.md index d0dba88bed..5e46023c30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,19 +3,20 @@ This file lists the main changes with each version of the Fyne toolkit. More detailed release notes can be found on the [releases page](https://github.com/fyne-io/fyne/releases). -## 2.0 - Ongoing +## 2.0 - 22 January 2021 ### Changes that are not backward compatible -These changes likely break some apps, please read the +These changes may break some apps, please read the [upgrading doc](https://developer.fyne.io/api/v2.0/upgrading) for more info +The import path is now `fyne.io/fyne/v2` when you are ready to make the update. * Coordinate system to float32 * Size and Position units were changed from int to float32 * `Text.TextSize` moved to float32 and `fyne.MeasureText` now takes a float32 size parameter * Removed `Size.Union` (use `Size.Max` instead) - * Added fyne.Delta for difference based X, Y representation - * DraggedEvent.DraggedX and DraggedX (int, int) to DraggedEvent.Dragged (Delta) + * Added fyne.Delta for difference-based X, Y float32 representation + * DraggedEvent.DraggedX and DraggedY (int, int) to DraggedEvent.Dragged (Delta) * ScrollEvent.DeltaX and DeltaY (int, int) moved to ScrollEvent.Scrolled (Delta) * Theme API update @@ -38,25 +39,58 @@ These changes likely break some apps, please read the - `widget.ScrollContainer` (now `container.Scroll`) - `widget.SplitContainer` (now `container.Spilt`) - `widget.Group` (replaced by `widget.Card`) - - `widget.Box` (now `container.NewH/VBox`) + - `widget.Box` (now `container.NewH/VBox`, with `Children` field moved to `Objects`) + - `widget.TabContainer` and `widget.AppTabs` (now `container.AppTabs`) +* Many deprecated fields have been removed, replacements listed in API docs 1.4 + - for specific information you can browse https://developer.fyne.io/api/v1.4/ ### Added +* Data binding API to connect data sources to widgets and sync data + - Add preferences data binding and `Preferences.AddChangeListener` + - Add bind support to `Check`, `Entry`, `Label`, `List`, `ProgressBar` and `Slider` widgets +* Animation API for handling smooth element transitions + - Add animations to buttons, tabs and entry cursor +* Storage repository API for connecting custom file sources + - Add storage functions `Copy`, `Delete` and `Move` for `URI` + - Add `CanRead`, `CanWrite` and `CanList` to storage APIs +* New Theme API for easier customisation of apps + - Add ability for custom themes to support light/dark preference + - Support for custom icons in theme definition + - New `theme.FromLegacy` helper to use old theme API definitions +* Add fyne.Vector for managing x/y float32 coordinates * Add MouseButtonTertiary for middle mouse button events on desktop -* Add fyne.Vector for simple x/y coordinates +* Add `canvas.ImageScaleFastest` for faster, less precise, scaling +* Add new `dialog.Form` that will phase out `dialog.Entry` +* Add keyboard control for main menu +* Add `Scroll.OnScrolled` event for seeing changes in scroll container +* Add `TextStyle` and `OnSubmitted` to `Entry` widget +* Add support for `HintText` and showing validation errors in `Form` widget +* Added basic support for tab character in `Entry`, `Label` and `TextGrid` ### Changed * Coordinate system is now float32 - see breaking changes above * ScrollEvent and DragEvent moved to Delta from (int, int) - * Change bundled resources to use more efficient string storage -* Desktop left and right mouse buttons renamed to MouseButtonPrimary and MouseButtonSecondary +* Left and Right mouse buttons on Desktop are being moved to `MouseButtonPrimary` and `MouseButtonSecondary` * Many optimisations and widget performance enhancements +* Moving to new `container.New()` and `container.NewWithoutLayout()` constructors (replacing `fyne.NewContainer` and `fyne.NewContainerWithoutLayout`) +* Moving storage APIs `OpenFileFromURI`, `SaveFileToURI` and `ListerForURI` to `Reader`, `Writer` and `List` functions + ### Fixed * Validating a widget in widget.Form before renderer was created could cause a panic +* Added file and folder support for mobile simulation support (#1470) +* Appending options to a disabled widget.RadioGroup shows them as enabled (#1697) +* Toggling toolbar icons does not refresh (#1809) +* Black screen when slide up application on iPhone (#1610) +* Properly align Label in FormItem (#1531) +* Mobile dropdowns are too low (#1771) +* Cursor does not go down to next line with wrapping (#1737) +* MacOS Notifications are not shown on subsequent app runs after first run due to duplicate identifier (#1699) +* Entry: while adding text beyond visible reagion there is no auto-scroll (#912) ## 1.4.3 - 4 January 2021 diff --git a/README.md b/README.md index c49d9a07eb..6553cb8ae4 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@

- Go API Reference - 1.4.3 release + Go API Reference + 2.0.0 release Join us on Slack
- Code Status + Code Status Build Status Coverage Status

@@ -14,12 +14,13 @@ It is designed to build applications that run on desktop and mobile devices with a single codebase. -Version 1.4 is the current release - it introduced high performance collection widgets, -Card, Separator and FileIcon widgets as well as a folder open dialog. -It also saw a theme refresh updating the colors and button styles for a more -material design look. -We are now working towards [2.0](https://github.com/fyne-io/fyne/milestone/6) -which aims to add data bindings, animations and more! +Version 2.0 is the current release of the Fyne API, this represented the first release since +1.0 that may break some API usage. It also added new features including data binding, animation, +storage repositories and a new more flexible theme API. +We also refreshed the default theme, adding animations, a focus colour and +redesigning the Entry, Select, SelectEntry, ProgressBar and ProgressBarInfinite widgets. +We are now working towards the next [big release](https://github.com/fyne-io/fyne/milestone/14) +and more news will follow in our news feeds and GitHub project. # Prerequisites @@ -29,13 +30,13 @@ If you're not sure if that's all installed or you don't know how then check out Using the standard go tools you can install Fyne's core library using: - $ go get fyne.io/fyne + $ go get fyne.io/fyne/v2 # Widget demo To run a showcase of the features of Fyne execute the following: - $ go get fyne.io/fyne/cmd/fyne_demo/ + $ go get fyne.io/fyne/v2/cmd/fyne_demo/ $ fyne_demo And you should see something like this (after you click a few buttons): @@ -62,9 +63,9 @@ Open a new file and you're ready to write your first app! package main import ( - "fyne.io/fyne/app" - "fyne.io/fyne/container" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" ) func main() { @@ -108,7 +109,7 @@ Using `go install` will copy the executable into your go `bin` dir. To install the application with icons etc into your operating system's standard application location you can use the fyne utility and the "install" subcommand. - $ go get fyne.io/fyne/cmd/fyne + $ go get fyne.io/fyne/v2/cmd/fyne $ fyne install # Packaging a release @@ -125,7 +126,7 @@ The above command will create a '.ipa' file that can then be uploaded to the iOS # Documentation -More documentation is available at the [Fyne developer website](https://developer.fyne.io/) or on [pkg.go.dev](https://pkg.go.dev/fyne.io/fyne?tab=doc). +More documentation is available at the [Fyne developer website](https://developer.fyne.io/) or on [pkg.go.dev](https://pkg.go.dev/fyne.io/fyne/v2?tab=doc). # Examples diff --git a/animation.go b/animation.go index 6c364b594f..a8aeba12fb 100644 --- a/animation.go +++ b/animation.go @@ -10,32 +10,32 @@ type AnimationCurve func(float32) float32 // AnimationRepeatForever is an AnimationCount value that indicates it should not stop looping. // -// Since 2.0.0 +// Since: 2.0 const AnimationRepeatForever = -1 var ( // AnimationEaseInOut is the default easing, it starts slowly, accelerates to the middle and slows to the end. // - // Since 2.0.0 + // Since: 2.0 AnimationEaseInOut = animationEaseInOut // AnimationEaseIn starts slowly and accelerates to the end. // - // Since 2.0.0 + // Since: 2.0 AnimationEaseIn = animationEaseIn // AnimationEaseOut starts at speed and slows to the end. // - // Since 2.0.0 + // Since: 2.0 AnimationEaseOut = animationEaseOut // AnimationLinear is a linear mapping for animations that progress uniformly through their duration. // - // Since 2.0.0 + // Since: 2.0 AnimationLinear = animationLinear ) // Animation represents an animated element within a Fyne canvas. // These animations may control individual objects or entire scenes. // -// Since 2.0.0 +// Since: 2.0 type Animation struct { AutoReverse bool Curve AnimationCurve @@ -48,7 +48,7 @@ type Animation struct { // rendered frame between time.Now() and the specified duration. The callback values start at 0.0 and // will be 1.0 when the animation completes. // -// Since 2.0.0 +// Since: 2.0 func NewAnimation(d time.Duration, fn func(float32)) *Animation { return &Animation{Duration: d, Tick: fn} } diff --git a/app/app.go b/app/app.go index 07242ba906..dbc338b07b 100644 --- a/app/app.go +++ b/app/app.go @@ -1,7 +1,7 @@ // Package app provides app implementations for working with Fyne graphical interfaces. // The fastest way to get started is to call app.New() which will normally load a new desktop application. // If the "ci" tag is passed to go (go run -tags ci myapp.go) it will run an in-memory application. -package app // import "fyne.io/fyne/app" +package app // import "fyne.io/fyne/v2/app" import ( "fmt" @@ -9,9 +9,9 @@ import ( "sync" "time" - "fyne.io/fyne" - "fyne.io/fyne/internal" - helper "fyne.io/fyne/internal/app" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal" + helper "fyne.io/fyne/v2/internal/app" ) // Declare conformity with App interface diff --git a/app/app_darwin.go b/app/app_darwin.go index 80a1b4bdee..76cbdf2e4e 100644 --- a/app/app_darwin.go +++ b/app/app_darwin.go @@ -25,8 +25,8 @@ import ( "strings" "unsafe" - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) func defaultVariant() fyne.ThemeVariant { diff --git a/app/app_debug.go b/app/app_debug.go index e363e04cf3..cdb43d4e46 100644 --- a/app/app_debug.go +++ b/app/app_debug.go @@ -2,6 +2,6 @@ package app -import "fyne.io/fyne" +import "fyne.io/fyne/v2" const buildMode = fyne.BuildDebug diff --git a/app/app_gl.go b/app/app_gl.go index 1da8989fc0..730c9d49d8 100644 --- a/app/app_gl.go +++ b/app/app_gl.go @@ -3,8 +3,8 @@ package app import ( - "fyne.io/fyne" - "fyne.io/fyne/internal/driver/glfw" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/driver/glfw" ) // NewWithID returns a new app instance using the appropriate runtime driver. diff --git a/app/app_mobile.go b/app/app_mobile.go index f9d03e1bb6..426f653141 100644 --- a/app/app_mobile.go +++ b/app/app_mobile.go @@ -5,8 +5,8 @@ package app import ( - "fyne.io/fyne" - "fyne.io/fyne/internal/driver/gomobile" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/driver/gomobile" ) // NewWithID returns a new app instance using the appropriate runtime driver. diff --git a/app/app_mobile_and.go b/app/app_mobile_and.go index 16da0108bf..e68aa82a23 100644 --- a/app/app_mobile_and.go +++ b/app/app_mobile_and.go @@ -20,8 +20,8 @@ import ( mobileApp "github.com/fyne-io/mobile/app" - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) func defaultVariant() fyne.ThemeVariant { diff --git a/app/app_mobile_ios.go b/app/app_mobile_ios.go index 6f9a837c50..d9425f4621 100644 --- a/app/app_mobile_ios.go +++ b/app/app_mobile_ios.go @@ -20,8 +20,8 @@ import ( "path/filepath" "unsafe" - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) func defaultVariant() fyne.ThemeVariant { diff --git a/app/app_other.go b/app/app_other.go index 84d5072eac..91d2320504 100644 --- a/app/app_other.go +++ b/app/app_other.go @@ -6,8 +6,8 @@ import ( "errors" "net/url" - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) func defaultVariant() fyne.ThemeVariant { diff --git a/app/app_release.go b/app/app_release.go index 962cb6b88d..e47815935c 100644 --- a/app/app_release.go +++ b/app/app_release.go @@ -2,6 +2,6 @@ package app -import "fyne.io/fyne" +import "fyne.io/fyne/v2" const buildMode = fyne.BuildRelease diff --git a/app/app_software.go b/app/app_software.go index 33584afef4..a84c27ec1e 100644 --- a/app/app_software.go +++ b/app/app_software.go @@ -3,9 +3,9 @@ package app import ( - "fyne.io/fyne" - "fyne.io/fyne/internal/painter/software" - "fyne.io/fyne/test" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/painter/software" + "fyne.io/fyne/v2/test" ) // NewWithID returns a new app instance using the test (headless) driver. diff --git a/app/app_standard.go b/app/app_standard.go index 9ab14b8f28..779d4f8a50 100644 --- a/app/app_standard.go +++ b/app/app_standard.go @@ -2,6 +2,6 @@ package app -import "fyne.io/fyne" +import "fyne.io/fyne/v2" const buildMode = fyne.BuildStandard diff --git a/app/app_test.go b/app/app_test.go index f511e2358f..156ba93124 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -6,8 +6,8 @@ import ( "strings" "testing" - "fyne.io/fyne" - _ "fyne.io/fyne/test" + "fyne.io/fyne/v2" + _ "fyne.io/fyne/v2/test" "github.com/stretchr/testify/assert" ) diff --git a/app/app_windows.go b/app/app_windows.go index 351b7bed24..acebcff7fe 100644 --- a/app/app_windows.go +++ b/app/app_windows.go @@ -16,8 +16,8 @@ import ( "golang.org/x/sys/windows/registry" - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) const notificationTemplate = `$title = "%s" diff --git a/app/app_xdg.go b/app/app_xdg.go index d99ca9c031..2d719703ea 100644 --- a/app/app_xdg.go +++ b/app/app_xdg.go @@ -12,8 +12,8 @@ import ( "github.com/godbus/dbus/v5" - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) func defaultVariant() fyne.ThemeVariant { diff --git a/app/preferences.go b/app/preferences.go index c5d700ed50..1a711ba974 100644 --- a/app/preferences.go +++ b/app/preferences.go @@ -6,8 +6,8 @@ import ( "path/filepath" "time" - "fyne.io/fyne" - "fyne.io/fyne/internal" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal" ) type preferences struct { diff --git a/app/settings.go b/app/settings.go index 8808e6277a..8da8ccc207 100644 --- a/app/settings.go +++ b/app/settings.go @@ -7,8 +7,8 @@ import ( "path/filepath" "sync" - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) // SettingsSchema is used for loading and storing global settings diff --git a/app/settings_desktop.go b/app/settings_desktop.go index eefe3c4430..6f7f785558 100644 --- a/app/settings_desktop.go +++ b/app/settings_desktop.go @@ -6,7 +6,7 @@ import ( "os" "path/filepath" - "fyne.io/fyne" + "fyne.io/fyne/v2" "github.com/fsnotify/fsnotify" ) diff --git a/app/settings_desktop_test.go b/app/settings_desktop_test.go index 0f1b03f9e1..35989264ae 100644 --- a/app/settings_desktop_test.go +++ b/app/settings_desktop_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) func TestDefaultTheme(t *testing.T) { diff --git a/app/settings_test.go b/app/settings_test.go index f727e7023b..ea2368883e 100644 --- a/app/settings_test.go +++ b/app/settings_test.go @@ -5,11 +5,11 @@ import ( "path/filepath" "testing" - "fyne.io/fyne" + "fyne.io/fyne/v2" "github.com/stretchr/testify/assert" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" ) func TestSettingsBuildType(t *testing.T) { diff --git a/app/storage.go b/app/storage.go index 82afb879f4..f2a4f4a524 100644 --- a/app/storage.go +++ b/app/storage.go @@ -3,8 +3,8 @@ package app import ( "os" - "fyne.io/fyne" - "fyne.io/fyne/storage" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" ) type store struct { diff --git a/canvas.go b/canvas.go index a8c33e5a6b..8869af25a0 100644 --- a/canvas.go +++ b/canvas.go @@ -17,13 +17,13 @@ type Canvas interface { // If no item is currently focused, the first focusable item is focused. // If the last focusable item is currently focused, the first focusable item is focused. // - // Since 2.0.0 + // Since: 2.0 FocusNext() // FocusPrevious focuses the previous focusable item. // If no item is currently focused, the last focusable item is focused. // If the first focusable item is currently focused, the last focusable item is focused. // - // Since 2.0.0 + // Since: 2.0 FocusPrevious() Unfocus() Focused() Focusable diff --git a/canvas/animation.go b/canvas/animation.go index d467778fe7..68d5112998 100644 --- a/canvas/animation.go +++ b/canvas/animation.go @@ -4,17 +4,17 @@ import ( "image/color" "time" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) const ( // DurationStandard is the time a standard interface animation will run. // - // Since 2.0.0 + // Since: 2.0 DurationStandard = time.Millisecond * 300 // DurationShort is the time a subtle or small transition should use. // - // Since 2.0.0 + // Since: 2.0 DurationShort = time.Millisecond * 150 ) @@ -23,7 +23,7 @@ const ( // The content of fn should apply the color values to an object and refresh it. // You should call Start() on the returned animation to start it. // -// Since 2.0.0 +// Since: 2.0 func NewColorRGBAAnimation(start, stop color.Color, d time.Duration, fn func(color.Color)) *fyne.Animation { r1, g1, b1, a1 := start.RGBA() r2, g2, b2, a2 := stop.RGBA() @@ -49,7 +49,7 @@ func NewColorRGBAAnimation(start, stop color.Color, d time.Duration, fn func(col // the specified Duration. The content of fn should apply the position value to an object for the change // to be visible. You should call Start() on the returned animation to start it. // -// Since 2.0.0 +// Since: 2.0 func NewPositionAnimation(start, stop fyne.Position, d time.Duration, fn func(fyne.Position)) *fyne.Animation { xDelta := float32(stop.X - start.X) yDelta := float32(stop.Y - start.Y) @@ -65,7 +65,7 @@ func NewPositionAnimation(start, stop fyne.Position, d time.Duration, fn func(fy // the specified Duration. The content of fn should apply the size value to an object for the change // to be visible. You should call Start() on the returned animation to start it. // -// Since 2.0.0 +// Since: 2.0 func NewSizeAnimation(start, stop fyne.Size, d time.Duration, fn func(fyne.Size)) *fyne.Animation { widthDelta := float32(stop.Width - start.Width) heightDelta := float32(stop.Height - start.Height) diff --git a/canvas/animation_test.go b/canvas/animation_test.go index f1a277253f..40607dddeb 100644 --- a/canvas/animation_test.go +++ b/canvas/animation_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "fyne.io/fyne" + "fyne.io/fyne/v2" "github.com/stretchr/testify/assert" ) diff --git a/canvas/base.go b/canvas/base.go index 8091d93ed1..da2ff35419 100644 --- a/canvas/base.go +++ b/canvas/base.go @@ -5,12 +5,12 @@ // non-interactive, by design. If additional functonality is required, // it's usually a sign that this type should be used as part of a custom // Widget. -package canvas // import "fyne.io/fyne/canvas" +package canvas // import "fyne.io/fyne/v2/canvas" import ( "sync" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) type baseObject struct { diff --git a/canvas/base_internal_test.go b/canvas/base_internal_test.go index c863d18144..324ffe8752 100644 --- a/canvas/base_internal_test.go +++ b/canvas/base_internal_test.go @@ -3,7 +3,7 @@ package canvas import ( "testing" - "fyne.io/fyne" + "fyne.io/fyne/v2" "github.com/stretchr/testify/assert" ) diff --git a/canvas/circle.go b/canvas/circle.go index 2fad7b5c59..6a98f1962e 100644 --- a/canvas/circle.go +++ b/canvas/circle.go @@ -3,7 +3,7 @@ package canvas import ( "image/color" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // Declare conformity with CanvasObject interface diff --git a/canvas/circle_test.go b/canvas/circle_test.go index 2f2776c7bd..b03ce1d339 100644 --- a/canvas/circle_test.go +++ b/canvas/circle_test.go @@ -4,8 +4,8 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" "github.com/stretchr/testify/assert" ) diff --git a/canvas/gradient_test.go b/canvas/gradient_test.go index 7084c6cbc1..68dbf5bd42 100644 --- a/canvas/gradient_test.go +++ b/canvas/gradient_test.go @@ -7,9 +7,9 @@ import ( "image/draw" "testing" - "fyne.io/fyne/canvas" - internalTest "fyne.io/fyne/internal/test" - "fyne.io/fyne/test" + "fyne.io/fyne/v2/canvas" + internalTest "fyne.io/fyne/v2/internal/test" + "fyne.io/fyne/v2/test" "github.com/stretchr/testify/assert" ) diff --git a/canvas/image.go b/canvas/image.go index 154c10d529..01c668332e 100644 --- a/canvas/image.go +++ b/canvas/image.go @@ -6,8 +6,8 @@ import ( "io/ioutil" "path/filepath" - "fyne.io/fyne" - "fyne.io/fyne/storage" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" ) // ImageFill defines the different type of ways an image can stretch to fill its space. @@ -38,7 +38,7 @@ const ( ImageScalePixels ImageScale = 1 // ImageScaleFastest will scale the image using hardware GPU if available // - // Since: 2.0.0 + // Since: 2.0 ImageScaleFastest ImageScale = 2 ) @@ -98,7 +98,7 @@ func NewImageFromFile(file string) *Image { // Images returned from this method will scale to fit the canvas object. // The method for scaling can be set using the Fill field. // -// Since: 2.0.0 +// Since: 2.0 func NewImageFromURI(uri fyne.URI) *Image { if uri.Scheme() == "file" && len(uri.String()) > 7 { return &Image{ @@ -108,7 +108,7 @@ func NewImageFromURI(uri fyne.URI) *Image { var read io.ReadCloser - read, err := storage.OpenFileFromURI(uri) // attempt unknown file type + read, err := storage.Reader(uri) // attempt unknown file type if err != nil { fyne.LogError("Failed to open image URI", err) return nil @@ -124,7 +124,7 @@ func NewImageFromURI(uri fyne.URI) *Image { // Images returned from this method will scale to fit the canvas object. // The method for scaling can be set using the Fill field. // -// Since: 2.0.0 +// Since: 2.0 func NewImageFromReader(read io.Reader, name string) *Image { data, err := ioutil.ReadAll(read) if err != nil { diff --git a/canvas/image_test.go b/canvas/image_test.go index fee250c5e7..27a71aa157 100644 --- a/canvas/image_test.go +++ b/canvas/image_test.go @@ -7,8 +7,8 @@ import ( "strings" "testing" - "fyne.io/fyne/canvas" - "fyne.io/fyne/storage" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/storage" "github.com/stretchr/testify/assert" ) diff --git a/canvas/line.go b/canvas/line.go index a3b8a58d54..ef4827bccd 100644 --- a/canvas/line.go +++ b/canvas/line.go @@ -4,7 +4,7 @@ import ( "image/color" "math" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // Declare conformity with CanvasObject interface diff --git a/canvas/line_test.go b/canvas/line_test.go index 7d53edb068..1aae0783e2 100644 --- a/canvas/line_test.go +++ b/canvas/line_test.go @@ -4,8 +4,8 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" "github.com/stretchr/testify/assert" ) diff --git a/canvas/raster.go b/canvas/raster.go index 0c9bb2bbb3..50972cb48d 100644 --- a/canvas/raster.go +++ b/canvas/raster.go @@ -5,7 +5,7 @@ import ( "image/color" "image/draw" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // Declare conformity with CanvasObject interface diff --git a/canvas/raster_test.go b/canvas/raster_test.go index 5fa1e0ce05..8387f144d2 100644 --- a/canvas/raster_test.go +++ b/canvas/raster_test.go @@ -4,7 +4,7 @@ import ( "image" "testing" - "fyne.io/fyne/canvas" + "fyne.io/fyne/v2/canvas" "github.com/stretchr/testify/assert" ) diff --git a/canvas/rectangle.go b/canvas/rectangle.go index af559c116f..6700a488a1 100644 --- a/canvas/rectangle.go +++ b/canvas/rectangle.go @@ -3,7 +3,7 @@ package canvas import ( "image/color" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // Declare conformity with CanvasObject interface diff --git a/canvas/rectangle_test.go b/canvas/rectangle_test.go index c6f566c47e..a92c228ada 100644 --- a/canvas/rectangle_test.go +++ b/canvas/rectangle_test.go @@ -4,7 +4,7 @@ import ( "image/color" "testing" - "fyne.io/fyne/canvas" + "fyne.io/fyne/v2/canvas" "github.com/stretchr/testify/assert" ) diff --git a/canvas/text.go b/canvas/text.go index e37636f2d0..81c05a5f98 100644 --- a/canvas/text.go +++ b/canvas/text.go @@ -3,7 +3,7 @@ package canvas import ( "image/color" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // Declare conformity with CanvasObject interface diff --git a/canvas/text_test.go b/canvas/text_test.go index 843d8aec5f..67ff9d13f4 100644 --- a/canvas/text_test.go +++ b/canvas/text_test.go @@ -4,10 +4,10 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/cmd/fyne/commands/bundle.go b/cmd/fyne/commands/bundle.go index 2f58daa77e..296a4e45c0 100644 --- a/cmd/fyne/commands/bundle.go +++ b/cmd/fyne/commands/bundle.go @@ -11,7 +11,7 @@ import ( "regexp" "strings" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) const fileHeader = "// auto-generated\n" + // to exclude this file in goreportcard (it has to be first) @@ -143,7 +143,7 @@ func writeHeader(pkg string, out *os.File) { fmt.Fprintln(out) fmt.Fprintln(out, "package", pkg) fmt.Fprintln(out) - fmt.Fprintln(out, "import \"fyne.io/fyne\"") + fmt.Fprintln(out, "import \"fyne.io/fyne/v2\"") fmt.Fprintln(out) } diff --git a/cmd/fyne/commands/get.go b/cmd/fyne/commands/get.go index e1947aff91..449afe260b 100644 --- a/cmd/fyne/commands/get.go +++ b/cmd/fyne/commands/get.go @@ -9,7 +9,7 @@ import ( "github.com/pkg/errors" - "fyne.io/fyne/cmd/fyne/internal/util" + "fyne.io/fyne/v2/cmd/fyne/internal/util" ) // Declare conformity to Command interface diff --git a/cmd/fyne/commands/install.go b/cmd/fyne/commands/install.go index e712e37779..a9e5d7a53a 100644 --- a/cmd/fyne/commands/install.go +++ b/cmd/fyne/commands/install.go @@ -9,8 +9,8 @@ import ( "path/filepath" "strings" - "fyne.io/fyne" - "fyne.io/fyne/cmd/fyne/internal/mobile" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/cmd/fyne/internal/mobile" ) // Declare conformity to Command interface diff --git a/cmd/fyne/commands/package-darwin.go b/cmd/fyne/commands/package-darwin.go index abc92a320e..0b707700ec 100644 --- a/cmd/fyne/commands/package-darwin.go +++ b/cmd/fyne/commands/package-darwin.go @@ -6,8 +6,8 @@ import ( "path/filepath" "strings" - "fyne.io/fyne/cmd/fyne/internal/templates" - "fyne.io/fyne/cmd/fyne/internal/util" + "fyne.io/fyne/v2/cmd/fyne/internal/templates" + "fyne.io/fyne/v2/cmd/fyne/internal/util" "github.com/jackmordaunt/icns" "github.com/pkg/errors" diff --git a/cmd/fyne/commands/package-mobile.go b/cmd/fyne/commands/package-mobile.go index 1eed16390e..991a7600b2 100644 --- a/cmd/fyne/commands/package-mobile.go +++ b/cmd/fyne/commands/package-mobile.go @@ -7,10 +7,10 @@ import ( "os/exec" "path/filepath" - "fyne.io/fyne" - "fyne.io/fyne/cmd/fyne/internal/mobile" - "fyne.io/fyne/cmd/fyne/internal/templates" - "fyne.io/fyne/cmd/fyne/internal/util" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/cmd/fyne/internal/mobile" + "fyne.io/fyne/v2/cmd/fyne/internal/templates" + "fyne.io/fyne/v2/cmd/fyne/internal/util" "github.com/pkg/errors" ) diff --git a/cmd/fyne/commands/package-unix.go b/cmd/fyne/commands/package-unix.go index 06d17b6ab6..300bf23fd4 100644 --- a/cmd/fyne/commands/package-unix.go +++ b/cmd/fyne/commands/package-unix.go @@ -5,8 +5,8 @@ import ( "os/exec" "path/filepath" - "fyne.io/fyne/cmd/fyne/internal/templates" - "fyne.io/fyne/cmd/fyne/internal/util" + "fyne.io/fyne/v2/cmd/fyne/internal/templates" + "fyne.io/fyne/v2/cmd/fyne/internal/util" "github.com/pkg/errors" ) diff --git a/cmd/fyne/commands/package-windows.go b/cmd/fyne/commands/package-windows.go index e425038ebf..82aba0ca7f 100644 --- a/cmd/fyne/commands/package-windows.go +++ b/cmd/fyne/commands/package-windows.go @@ -9,7 +9,7 @@ import ( "runtime" "strings" - "fyne.io/fyne/cmd/fyne/internal/templates" + "fyne.io/fyne/v2/cmd/fyne/internal/templates" ico "github.com/Kodeworks/golang-image-ico" "github.com/josephspurrier/goversioninfo" "github.com/pkg/errors" diff --git a/cmd/fyne/commands/package.go b/cmd/fyne/commands/package.go index 57cfd300b3..ed29ed1227 100644 --- a/cmd/fyne/commands/package.go +++ b/cmd/fyne/commands/package.go @@ -12,7 +12,7 @@ import ( "os" "path/filepath" - "fyne.io/fyne/cmd/fyne/internal/util" + "fyne.io/fyne/v2/cmd/fyne/internal/util" "github.com/pkg/errors" ) diff --git a/cmd/fyne/commands/release.go b/cmd/fyne/commands/release.go index c8f1501367..7950f5128b 100644 --- a/cmd/fyne/commands/release.go +++ b/cmd/fyne/commands/release.go @@ -9,10 +9,10 @@ import ( "path/filepath" "strings" - "fyne.io/fyne" - "fyne.io/fyne/cmd/fyne/internal/mobile" - "fyne.io/fyne/cmd/fyne/internal/templates" - "fyne.io/fyne/cmd/fyne/internal/util" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/cmd/fyne/internal/mobile" + "fyne.io/fyne/v2/cmd/fyne/internal/templates" + "fyne.io/fyne/v2/cmd/fyne/internal/util" ) var ( diff --git a/cmd/fyne/env.go b/cmd/fyne/env.go index a48b88ed3d..5105d309c0 100644 --- a/cmd/fyne/env.go +++ b/cmd/fyne/env.go @@ -4,8 +4,8 @@ import ( "fmt" "os" - "fyne.io/fyne" - "fyne.io/fyne/cmd/fyne/commands" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/cmd/fyne/commands" "github.com/lucor/goinfo" "github.com/lucor/goinfo/format" @@ -13,7 +13,7 @@ import ( ) const ( - fyneModule = "fyne.io/fyne" + fyneModule = "fyne.io/fyne/v2" ) // Declare conformity to Command interface diff --git a/cmd/fyne/internal/mobile/build_androidapp.go b/cmd/fyne/internal/mobile/build_androidapp.go index 788636a3d9..c27c4d0128 100644 --- a/cmd/fyne/internal/mobile/build_androidapp.go +++ b/cmd/fyne/internal/mobile/build_androidapp.go @@ -19,7 +19,7 @@ import ( "path/filepath" "strings" - "fyne.io/fyne/cmd/fyne/internal/mobile/binres" + "fyne.io/fyne/v2/cmd/fyne/internal/mobile/binres" "golang.org/x/tools/go/packages" ) diff --git a/cmd/fyne/internal/mobile/env.go b/cmd/fyne/internal/mobile/env.go index b1e1710a93..429da1b185 100644 --- a/cmd/fyne/internal/mobile/env.go +++ b/cmd/fyne/internal/mobile/env.go @@ -10,7 +10,7 @@ import ( "runtime" "strings" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // General mobile build environment. Initialized by envInit. diff --git a/cmd/fyne/internal/templates/bundled.go b/cmd/fyne/internal/templates/bundled.go index 35a9c74130..30f88cf0af 100644 --- a/cmd/fyne/internal/templates/bundled.go +++ b/cmd/fyne/internal/templates/bundled.go @@ -3,7 +3,7 @@ package templates -import "fyne.io/fyne" +import "fyne.io/fyne/v2" var resourceInfoPlist = &fyne.StaticResource{ StaticName: "Info.plist", diff --git a/cmd/fyne/internal/util/file.go b/cmd/fyne/internal/util/file.go index 53f4b2a72e..74fcb1d609 100644 --- a/cmd/fyne/internal/util/file.go +++ b/cmd/fyne/internal/util/file.go @@ -5,7 +5,7 @@ import ( "os" "path/filepath" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // Exists will return true if the passed path exists on the current system. diff --git a/cmd/fyne/main.go b/cmd/fyne/main.go index fb920275cb..085f8c56b9 100644 --- a/cmd/fyne/main.go +++ b/cmd/fyne/main.go @@ -6,8 +6,8 @@ import ( "fmt" "os" - "fyne.io/fyne" - "fyne.io/fyne/cmd/fyne/commands" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/cmd/fyne/commands" ) var commandList []idCommandPair diff --git a/cmd/fyne/vendor.go b/cmd/fyne/vendor.go index 9bcd7cbf37..ed6794261d 100644 --- a/cmd/fyne/vendor.go +++ b/cmd/fyne/vendor.go @@ -12,9 +12,9 @@ import ( "regexp" "strings" - "fyne.io/fyne" - "fyne.io/fyne/cmd/fyne/commands" - "fyne.io/fyne/cmd/fyne/internal/util" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/cmd/fyne/commands" + "fyne.io/fyne/v2/cmd/fyne/internal/util" ) const ( diff --git a/cmd/fyne/version.go b/cmd/fyne/version.go index 6949f9de9e..4cee250599 100644 --- a/cmd/fyne/version.go +++ b/cmd/fyne/version.go @@ -5,8 +5,8 @@ import ( "os" "runtime/debug" - "fyne.io/fyne" - "fyne.io/fyne/cmd/fyne/commands" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/cmd/fyne/commands" ) // Declare conformity to command interface diff --git a/cmd/fyne_demo/data/bundled-scene.go b/cmd/fyne_demo/data/bundled-scene.go index f4e06d5022..1e7040bc12 100644 --- a/cmd/fyne_demo/data/bundled-scene.go +++ b/cmd/fyne_demo/data/bundled-scene.go @@ -2,7 +2,7 @@ package data -import "fyne.io/fyne" +import "fyne.io/fyne/v2" var fynescenedark = &fyne.StaticResource{ StaticName: "fyne_scene_dark.png", diff --git a/cmd/fyne_demo/data/gen.go b/cmd/fyne_demo/data/gen.go index 18fb983c12..97e660af34 100644 --- a/cmd/fyne_demo/data/gen.go +++ b/cmd/fyne_demo/data/gen.go @@ -8,7 +8,7 @@ import ( "path" "runtime" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) func bundleFile(name string, filepath string, f *os.File) { @@ -33,7 +33,7 @@ func openFile(filename string) *os.File { return nil } - _, err = f.WriteString("// **** THIS FILE IS AUTO-GENERATED, PLEASE DO NOT EDIT IT **** //\n\npackage data\n\nimport \"fyne.io/fyne\"\n\n") + _, err = f.WriteString("// **** THIS FILE IS AUTO-GENERATED, PLEASE DO NOT EDIT IT **** //\n\npackage data\n\nimport \"fyne.io/fyne/v2\"\n\n") if err != nil { fyne.LogError("Unable to write file "+filename, err) return nil diff --git a/cmd/fyne_demo/data/icons.go b/cmd/fyne_demo/data/icons.go index 035ab37c54..952a941195 100644 --- a/cmd/fyne_demo/data/icons.go +++ b/cmd/fyne_demo/data/icons.go @@ -1,8 +1,8 @@ package data import ( - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) // ThemedResource is a resource wrapper that will return an appropriate resource diff --git a/cmd/fyne_demo/main.go b/cmd/fyne_demo/main.go index 0f208087a7..7e444e3600 100644 --- a/cmd/fyne_demo/main.go +++ b/cmd/fyne_demo/main.go @@ -5,14 +5,14 @@ import ( "fmt" "net/url" - "fyne.io/fyne" - "fyne.io/fyne/app" - "fyne.io/fyne/cmd/fyne_demo/tutorials" - "fyne.io/fyne/cmd/fyne_settings/settings" - "fyne.io/fyne/container" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/cmd/fyne_demo/tutorials" + "fyne.io/fyne/v2/cmd/fyne_settings/settings" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) const preferenceCurrentTutorial = "currentTutorial" diff --git a/cmd/fyne_demo/tutorials/advanced.go b/cmd/fyne_demo/tutorials/advanced.go index 941ca013dd..a78d40df1d 100644 --- a/cmd/fyne_demo/tutorials/advanced.go +++ b/cmd/fyne_demo/tutorials/advanced.go @@ -4,10 +4,10 @@ import ( "fmt" "time" - "fyne.io/fyne" - "fyne.io/fyne/container" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/widget" ) func scaleString(c fyne.Canvas) string { diff --git a/cmd/fyne_demo/tutorials/animation.go b/cmd/fyne_demo/tutorials/animation.go index 482ae3743d..29da0d43a2 100644 --- a/cmd/fyne_demo/tutorials/animation.go +++ b/cmd/fyne_demo/tutorials/animation.go @@ -4,10 +4,10 @@ import ( "image/color" "time" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) func makeAnimationScreen(_ fyne.Window) fyne.CanvasObject { diff --git a/cmd/fyne_demo/tutorials/bind.go b/cmd/fyne_demo/tutorials/bind.go index 2598c15334..30de497d25 100644 --- a/cmd/fyne_demo/tutorials/bind.go +++ b/cmd/fyne_demo/tutorials/bind.go @@ -3,10 +3,10 @@ package tutorials import ( "fmt" - "fyne.io/fyne" - "fyne.io/fyne/container" - "fyne.io/fyne/data/binding" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/data/binding" + "fyne.io/fyne/v2/widget" ) func bindingScreen(_ fyne.Window) fyne.CanvasObject { diff --git a/cmd/fyne_demo/tutorials/canvas.go b/cmd/fyne_demo/tutorials/canvas.go index 98c2eeba85..01acfea1b1 100644 --- a/cmd/fyne_demo/tutorials/canvas.go +++ b/cmd/fyne_demo/tutorials/canvas.go @@ -4,10 +4,10 @@ import ( "image/color" "time" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" ) func rgbGradient(x, y, w, h int) color.Color { diff --git a/cmd/fyne_demo/tutorials/collection.go b/cmd/fyne_demo/tutorials/collection.go index 4bd696a90e..4553bfee36 100644 --- a/cmd/fyne_demo/tutorials/collection.go +++ b/cmd/fyne_demo/tutorials/collection.go @@ -3,10 +3,10 @@ package tutorials import ( "fmt" - "fyne.io/fyne" - "fyne.io/fyne/container" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) // collectionScreen loads a tab panel for collection widgets diff --git a/cmd/fyne_demo/tutorials/container.go b/cmd/fyne_demo/tutorials/container.go index 9071832bc7..c4ba856be7 100644 --- a/cmd/fyne_demo/tutorials/container.go +++ b/cmd/fyne_demo/tutorials/container.go @@ -4,11 +4,11 @@ import ( "fmt" "image/color" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/container" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) // containerScreen loads a tab panel for containers diff --git a/cmd/fyne_demo/tutorials/data.go b/cmd/fyne_demo/tutorials/data.go index 7ce269815e..cdaf08d0e3 100644 --- a/cmd/fyne_demo/tutorials/data.go +++ b/cmd/fyne_demo/tutorials/data.go @@ -1,7 +1,7 @@ package tutorials import ( - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // Tutorial defines the data structure for a tutorial diff --git a/cmd/fyne_demo/tutorials/dialog.go b/cmd/fyne_demo/tutorials/dialog.go index 27b0b078a9..54fd28d121 100644 --- a/cmd/fyne_demo/tutorials/dialog.go +++ b/cmd/fyne_demo/tutorials/dialog.go @@ -7,14 +7,14 @@ import ( "io/ioutil" "log" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/container" - "fyne.io/fyne/data/validation" - "fyne.io/fyne/dialog" - "fyne.io/fyne/storage" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/data/validation" + "fyne.io/fyne/v2/dialog" + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) func confirmCallback(response bool) { @@ -45,7 +45,7 @@ func dialogScreen(win fyne.Window) fyne.CanvasObject { cnf.SetConfirmText("Oh Yes!") cnf.Show() }), - widget.NewButton("File Open With Filter (.txt or .png)", func() { + widget.NewButton("File Open With Filter (.jpg or .png)", func() { fd := dialog.NewFileOpen(func(reader fyne.URIReadCloser, err error) { if err == nil && reader == nil { return @@ -55,9 +55,9 @@ func dialogScreen(win fyne.Window) fyne.CanvasObject { return } - fileOpened(reader) + imageOpened(reader) }, win) - fd.SetFilter(storage.NewExtensionFileFilter([]string{".png", ".txt"})) + fd.SetFilter(storage.NewExtensionFileFilter([]string{".png", ".jpg", ".jpeg"})) fd.Show() }), widget.NewButton("File Save", func() { @@ -131,22 +131,14 @@ func dialogScreen(win fyne.Window) fyne.CanvasObject { )) } -func fileOpened(f fyne.URIReadCloser) { +func imageOpened(f fyne.URIReadCloser) { if f == nil { log.Println("Cancelled") return } + defer f.Close() - ext := f.URI().Extension() - if ext == ".png" { - showImage(f) - } else if ext == ".txt" { - showText(f) - } - err := f.Close() - if err != nil { - fyne.LogError("Failed to close stream", err) - } + showImage(f) } func fileSaved(f fyne.URIWriteCloser) { @@ -169,19 +161,6 @@ func loadImage(f fyne.URIReadCloser) *canvas.Image { return canvas.NewImageFromResource(res) } -func loadText(f fyne.URIReadCloser) string { - data, err := ioutil.ReadAll(f) - if err != nil { - fyne.LogError("Failed to load text data", err) - return "" - } - if data == nil { - return "" - } - - return string(data) -} - func showImage(f fyne.URIReadCloser) { img := loadImage(f) if img == nil { @@ -194,13 +173,3 @@ func showImage(f fyne.URIReadCloser) { w.Resize(fyne.NewSize(320, 240)) w.Show() } - -func showText(f fyne.URIReadCloser) { - text := widget.NewLabel(loadText(f)) - text.Wrapping = fyne.TextWrapWord - - w := fyne.CurrentApp().NewWindow(f.URI().Name()) - w.SetContent(container.NewScroll(text)) - w.Resize(fyne.NewSize(320, 240)) - w.Show() -} diff --git a/cmd/fyne_demo/tutorials/icons.go b/cmd/fyne_demo/tutorials/icons.go index 9bbdeedf21..8bbaba3349 100644 --- a/cmd/fyne_demo/tutorials/icons.go +++ b/cmd/fyne_demo/tutorials/icons.go @@ -3,12 +3,12 @@ package tutorials import ( "image/color" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/container" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) type iconInfo struct { diff --git a/cmd/fyne_demo/tutorials/theme.go b/cmd/fyne_demo/tutorials/theme.go index 2c9bbe0000..71b1b7dd16 100644 --- a/cmd/fyne_demo/tutorials/theme.go +++ b/cmd/fyne_demo/tutorials/theme.go @@ -3,8 +3,8 @@ package tutorials import ( "image/color" - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) var ( diff --git a/cmd/fyne_demo/tutorials/welcome.go b/cmd/fyne_demo/tutorials/welcome.go index d45dd5dda0..120ef24964 100644 --- a/cmd/fyne_demo/tutorials/welcome.go +++ b/cmd/fyne_demo/tutorials/welcome.go @@ -3,11 +3,11 @@ package tutorials import ( "net/url" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/cmd/fyne_demo/data" - "fyne.io/fyne/container" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/cmd/fyne_demo/data" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" ) func parseURL(urlStr string) *url.URL { diff --git a/cmd/fyne_demo/tutorials/widget.go b/cmd/fyne_demo/tutorials/widget.go index 984d253a2e..924499dfd6 100644 --- a/cmd/fyne_demo/tutorials/widget.go +++ b/cmd/fyne_demo/tutorials/widget.go @@ -6,13 +6,13 @@ import ( "net/url" "time" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/container" - "fyne.io/fyne/data/validation" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/data/validation" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) const ( diff --git a/cmd/fyne_demo/tutorials/window.go b/cmd/fyne_demo/tutorials/window.go index d64990b2f5..69d4d357ac 100644 --- a/cmd/fyne_demo/tutorials/window.go +++ b/cmd/fyne_demo/tutorials/window.go @@ -3,11 +3,11 @@ package tutorials import ( "time" - "fyne.io/fyne" - "fyne.io/fyne/container" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/layout" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/widget" ) func windowScreen(_ fyne.Window) fyne.CanvasObject { diff --git a/cmd/fyne_settings/data/gen.go b/cmd/fyne_settings/data/gen.go index 5b8ae1baf6..e7b1ea3700 100644 --- a/cmd/fyne_settings/data/gen.go +++ b/cmd/fyne_settings/data/gen.go @@ -8,7 +8,7 @@ import ( "path" "runtime" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) func bundleFile(name string, filepath string, f *os.File) { @@ -38,7 +38,7 @@ func openFile(filename string) *os.File { return nil } - _, err = f.WriteString("// **** THIS FILE IS AUTO-GENERATED, PLEASE DO NOT EDIT IT **** //\n\npackage settings\n\nimport \"fyne.io/fyne\"\n\n") + _, err = f.WriteString("// **** THIS FILE IS AUTO-GENERATED, PLEASE DO NOT EDIT IT **** //\n\npackage settings\n\nimport \"fyne.io/fyne/v2\"\n\n") if err != nil { fyne.LogError("Unable to write file "+filename, err) return nil diff --git a/cmd/fyne_settings/main.go b/cmd/fyne_settings/main.go index 39b0f577f5..936374cc4d 100644 --- a/cmd/fyne_settings/main.go +++ b/cmd/fyne_settings/main.go @@ -1,10 +1,10 @@ package main import ( - "fyne.io/fyne" - "fyne.io/fyne/app" - "fyne.io/fyne/cmd/fyne_settings/settings" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/cmd/fyne_settings/settings" + "fyne.io/fyne/v2/container" ) func main() { @@ -14,9 +14,9 @@ func main() { w := a.NewWindow("Fyne Settings") appearance := s.LoadAppearanceScreen(w) - tabs := widget.NewTabContainer( - &widget.TabItem{Text: "Appearance", Icon: s.AppearanceIcon(), Content: appearance}) - tabs.SetTabLocation(widget.TabLocationLeading) + tabs := container.NewAppTabs( + &container.TabItem{Text: "Appearance", Icon: s.AppearanceIcon(), Content: appearance}) + tabs.SetTabLocation(container.TabLocationLeading) w.SetContent(tabs) w.Resize(fyne.NewSize(480, 480)) diff --git a/cmd/fyne_settings/settings/appearance.go b/cmd/fyne_settings/settings/appearance.go index 5be56355b4..96552341bc 100644 --- a/cmd/fyne_settings/settings/appearance.go +++ b/cmd/fyne_settings/settings/appearance.go @@ -9,15 +9,15 @@ import ( "path/filepath" "runtime" - "fyne.io/fyne" - "fyne.io/fyne/app" - "fyne.io/fyne/canvas" - "fyne.io/fyne/container" - "fyne.io/fyne/internal/painter" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" - "fyne.io/fyne/tools/playground" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/internal/painter" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/tools/playground" + "fyne.io/fyne/v2/widget" ) const ( @@ -116,12 +116,12 @@ func (s *Settings) createPreview() image.Image { fyne.CurrentApp().Settings().(overrideTheme).OverrideTheme(th, s.fyneSettings.PrimaryColor) empty := widget.NewLabel("") - tabs := widget.NewTabContainer( - widget.NewTabItemWithIcon("Home", theme.HomeIcon(), widget.NewLabel("Home")), - widget.NewTabItemWithIcon("Browse", theme.ComputerIcon(), empty), - widget.NewTabItemWithIcon("Settings", theme.SettingsIcon(), empty), - widget.NewTabItemWithIcon("Help", theme.HelpIcon(), empty)) - tabs.SetTabLocation(widget.TabLocationLeading) + tabs := container.NewAppTabs( + container.NewTabItemWithIcon("Home", theme.HomeIcon(), widget.NewLabel("Home")), + container.NewTabItemWithIcon("Browse", theme.ComputerIcon(), empty), + container.NewTabItemWithIcon("Settings", theme.SettingsIcon(), empty), + container.NewTabItemWithIcon("Help", theme.HelpIcon(), empty)) + tabs.SetTabLocation(container.TabLocationLeading) showOverlay(c) c.SetContent(tabs) diff --git a/cmd/fyne_settings/settings/bundled.go b/cmd/fyne_settings/settings/bundled.go index d4202b7046..ba0f5b51b4 100644 --- a/cmd/fyne_settings/settings/bundled.go +++ b/cmd/fyne_settings/settings/bundled.go @@ -2,7 +2,7 @@ package settings -import "fyne.io/fyne" +import "fyne.io/fyne/v2" var appearanceIcon = &fyne.StaticResource{ StaticName: "appearance.svg", diff --git a/cmd/fyne_settings/settings/scale.go b/cmd/fyne_settings/settings/scale.go index 9ab1352481..363d0ffc48 100644 --- a/cmd/fyne_settings/settings/scale.go +++ b/cmd/fyne_settings/settings/scale.go @@ -1,12 +1,12 @@ package settings import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/container" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) type scaleItems struct { diff --git a/cmd/fyne_settings/settings/scale_test.go b/cmd/fyne_settings/settings/scale_test.go index 7dd39f1dc3..8368979fea 100644 --- a/cmd/fyne_settings/settings/scale_test.go +++ b/cmd/fyne_settings/settings/scale_test.go @@ -3,10 +3,10 @@ package settings import ( "testing" - "fyne.io/fyne/canvas" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/cmd/hello/main.go b/cmd/hello/main.go index ee48c958c6..42c0cc9540 100644 --- a/cmd/hello/main.go +++ b/cmd/hello/main.go @@ -2,9 +2,9 @@ package main import ( - "fyne.io/fyne/app" - "fyne.io/fyne/container" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" ) func main() { diff --git a/widget/tabcontainer_test.go b/container/appTabs_test.go similarity index 58% rename from widget/tabcontainer_test.go rename to container/appTabs_test.go index df22fc1767..f7e0f4cc1b 100644 --- a/widget/tabcontainer_test.go +++ b/container/appTabs_test.go @@ -1,33 +1,34 @@ -package widget_test +package container_test import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) func TestTabContainer_CurrentTab(t *testing.T) { - tab1 := &widget.TabItem{Text: "Test1", Content: widget.NewLabel("Test1")} - tab2 := &widget.TabItem{Text: "Test2", Content: widget.NewLabel("Test2")} - tabs := widget.NewTabContainer(tab1, tab2) + tab1 := &container.TabItem{Text: "Test1", Content: widget.NewLabel("Test1")} + tab2 := &container.TabItem{Text: "Test2", Content: widget.NewLabel("Test2")} + tabs := container.NewAppTabs(tab1, tab2) assert.Equal(t, 2, len(tabs.Items)) assert.Equal(t, tab1, tabs.CurrentTab()) } func TestTabContainer_CurrentTabIndex(t *testing.T) { - tabs := widget.NewTabContainer(&widget.TabItem{Text: "Test", Content: widget.NewLabel("Test")}) + tabs := container.NewAppTabs(&container.TabItem{Text: "Test", Content: widget.NewLabel("Test")}) assert.Equal(t, 1, len(tabs.Items)) assert.Equal(t, 0, tabs.CurrentTabIndex()) } func TestTabContainer_Empty(t *testing.T) { - tabs := widget.NewTabContainer() + tabs := container.NewAppTabs() assert.Equal(t, 0, len(tabs.Items)) assert.Equal(t, -1, tabs.CurrentTabIndex()) assert.Nil(t, tabs.CurrentTab()) @@ -39,9 +40,9 @@ func TestTabContainer_Empty(t *testing.T) { func TestTabContainer_Hidden_AsChild(t *testing.T) { c1 := widget.NewLabel("Tab 1 content") c2 := widget.NewLabel("Tab 2 content\nTab 2 content\nTab 2 content") - ti1 := widget.NewTabItem("Tab 1", c1) - ti2 := widget.NewTabItem("Tab 2", c2) - tabs := widget.NewTabContainer(ti1, ti2) + ti1 := container.NewTabItem("Tab 1", c1) + ti2 := container.NewTabItem("Tab 2", c2) + tabs := container.NewAppTabs(ti1, ti2) tabs.Refresh() assert.True(t, c1.Visible()) @@ -53,7 +54,7 @@ func TestTabContainer_Hidden_AsChild(t *testing.T) { } func TestTabContainer_Resize_Empty(t *testing.T) { - tabs := widget.NewTabContainer() + tabs := container.NewAppTabs() tabs.Resize(fyne.NewSize(10, 10)) size := tabs.Size() assert.Equal(t, float32(10), size.Height) @@ -61,37 +62,37 @@ func TestTabContainer_Resize_Empty(t *testing.T) { } func TestTabContainer_SelectTab(t *testing.T) { - tab1 := &widget.TabItem{Text: "Test1", Content: widget.NewLabel("Test1")} - tab2 := &widget.TabItem{Text: "Test2", Content: widget.NewLabel("Test2")} - tabs := widget.NewTabContainer(tab1, tab2) + tab1 := &container.TabItem{Text: "Test1", Content: widget.NewLabel("Test1")} + tab2 := &container.TabItem{Text: "Test2", Content: widget.NewLabel("Test2")} + tabs := container.NewAppTabs(tab1, tab2) assert.Equal(t, 2, len(tabs.Items)) assert.Equal(t, tab1, tabs.CurrentTab()) - var selectedTab *widget.TabItem - tabs.OnChanged = func(tab *widget.TabItem) { + var selectedTab *container.TabItem + tabs.OnChanged = func(tab *container.TabItem) { selectedTab = tab } tabs.SelectTab(tab2) assert.Equal(t, tab2, tabs.CurrentTab()) assert.Equal(t, tab2, selectedTab) - tabs.OnChanged = func(tab *widget.TabItem) { + tabs.OnChanged = func(tab *container.TabItem) { assert.Fail(t, "unexpected tab selection") } - tabs.SelectTab(widget.NewTabItem("Test3", widget.NewLabel("Test3"))) + tabs.SelectTab(container.NewTabItem("Test3", widget.NewLabel("Test3"))) assert.Equal(t, tab2, tabs.CurrentTab()) } func TestTabContainer_SelectTabIndex(t *testing.T) { - tabs := widget.NewTabContainer(&widget.TabItem{Text: "Test1", Content: widget.NewLabel("Test1")}, - &widget.TabItem{Text: "Test2", Content: widget.NewLabel("Test2")}) + tabs := container.NewAppTabs(&container.TabItem{Text: "Test1", Content: widget.NewLabel("Test1")}, + &container.TabItem{Text: "Test2", Content: widget.NewLabel("Test2")}) assert.Equal(t, 2, len(tabs.Items)) assert.Equal(t, 0, tabs.CurrentTabIndex()) - var selectedTab *widget.TabItem - tabs.OnChanged = func(tab *widget.TabItem) { + var selectedTab *container.TabItem + tabs.OnChanged = func(tab *container.TabItem) { selectedTab = tab } tabs.SelectTabIndex(1) @@ -100,8 +101,8 @@ func TestTabContainer_SelectTabIndex(t *testing.T) { } func TestTabContainer_RemoveIndex(t *testing.T) { - tabs := widget.NewTabContainer(&widget.TabItem{Text: "Test1", Content: widget.NewLabel("Test1")}, - &widget.TabItem{Text: "Test2", Content: widget.NewLabel("Test2")}) + tabs := container.NewAppTabs(&container.TabItem{Text: "Test1", Content: widget.NewLabel("Test1")}, + &container.TabItem{Text: "Test2", Content: widget.NewLabel("Test2")}) tabs.SelectTabIndex(1) tabs.RemoveIndex(1) diff --git a/widget/tabcontainer.go b/container/apptabs.go similarity index 84% rename from widget/tabcontainer.go rename to container/apptabs.go index fbfacf6e9f..9f2631e1e0 100644 --- a/widget/tabcontainer.go +++ b/container/apptabs.go @@ -1,20 +1,22 @@ -package widget +package container import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) -// TabContainer widget allows switching visible content from a list of TabItems. -// Each item is represented by a button at the top of the widget. +// AppTabs container is used to split your application into various different areas identified by tabs. +// The tabs contain text and/or an icon and allow the user to switch between the content specified in each TabItem. +// Each item is represented by a button at the edge of the container. // -// Deprecated: use container.Tabs instead. -type TabContainer struct { - BaseWidget +// Since: 1.4 +type AppTabs struct { + widget.BaseWidget Items []*TabItem OnChanged func(tab *TabItem) @@ -22,36 +24,34 @@ type TabContainer struct { tabLocation TabLocation } -// TabItem represents a single view in a TabContainer. +// TabItem represents a single view in a AppTabs. // The Text and Icon are used for the tab button and the Content is shown when the corresponding tab is active. // -// Deprecated: use container.TabItem instead. +// Since: 1.4 type TabItem struct { Text string Icon fyne.Resource Content fyne.CanvasObject } -// TabLocation is the location where the tabs of a tab container should be rendered. +// TabLocation is the location where the tabs of a tab container should be rendered // -// Deprecated: use container.TabLocation instead. +// Since: 1.4 type TabLocation int // TabLocation values const ( - // Deprecated: use container.TabLocationTop TabLocationTop TabLocation = iota - // Deprecated: use container.TabLocationLeading TabLocationLeading - // Deprecated: use container.TabLocationBottom TabLocationBottom - // Deprecated: use container.TabLocationTrailing TabLocationTrailing ) -// NewTabContainer creates a new tab bar widget that allows the user to choose between different visible containers -func NewTabContainer(items ...*TabItem) *TabContainer { - tabs := &TabContainer{BaseWidget: BaseWidget{}, Items: items, current: -1} +// NewAppTabs creates a new tab container that allows the user to choose between different areas of an app. +// +// Since: 1.4 +func NewAppTabs(items ...*TabItem) *AppTabs { + tabs := &AppTabs{BaseWidget: widget.BaseWidget{}, Items: items, current: -1} if len(items) > 0 { // Current is first tab item tabs.current = 0 @@ -59,38 +59,42 @@ func NewTabContainer(items ...*TabItem) *TabContainer { tabs.ExtendBaseWidget(tabs) if tabs.mismatchedContent() { - internal.LogHint("TabContainer items should all have the same type of content (text, icons or both)") + internal.LogHint("AppTabs items should all have the same type of content (text, icons or both)") } return tabs } // NewTabItem creates a new item for a tabbed widget - each item specifies the content and a label for its tab. +// +// Since: 1.4 func NewTabItem(text string, content fyne.CanvasObject) *TabItem { return &TabItem{Text: text, Content: content} } // NewTabItemWithIcon creates a new item for a tabbed widget - each item specifies the content and a label with an icon for its tab. +// +// Since: 1.4 func NewTabItemWithIcon(text string, icon fyne.Resource, content fyne.CanvasObject) *TabItem { return &TabItem{Text: text, Icon: icon, Content: content} } // Append adds a new TabItem to the rightmost side of the tab panel -func (c *TabContainer) Append(item *TabItem) { +func (c *AppTabs) Append(item *TabItem) { c.SetItems(append(c.Items, item)) } // CreateRenderer is a private method to Fyne which links this widget to its renderer -func (c *TabContainer) CreateRenderer() fyne.WidgetRenderer { +func (c *AppTabs) CreateRenderer() fyne.WidgetRenderer { c.ExtendBaseWidget(c) - r := &tabContainerRenderer{line: canvas.NewRectangle(theme.ShadowColor()), + r := &appTabsRenderer{line: canvas.NewRectangle(theme.ShadowColor()), underline: canvas.NewRectangle(theme.PrimaryColor()), container: c} r.updateTabs() return r } // CurrentTab returns the currently selected TabItem. -func (c *TabContainer) CurrentTab() *TabItem { +func (c *AppTabs) CurrentTab() *TabItem { if c.current < 0 || c.current >= len(c.Items) { return nil } @@ -98,18 +102,18 @@ func (c *TabContainer) CurrentTab() *TabItem { } // CurrentTabIndex returns the index of the currently selected TabItem. -func (c *TabContainer) CurrentTabIndex() int { +func (c *AppTabs) CurrentTabIndex() int { return c.current } // MinSize returns the size that this widget should not shrink below -func (c *TabContainer) MinSize() fyne.Size { +func (c *AppTabs) MinSize() fyne.Size { c.ExtendBaseWidget(c) return c.BaseWidget.MinSize() } // Remove tab by value -func (c *TabContainer) Remove(item *TabItem) { +func (c *AppTabs) Remove(item *TabItem) { for index, existingItem := range c.Items { if existingItem == item { c.RemoveIndex(index) @@ -119,12 +123,12 @@ func (c *TabContainer) Remove(item *TabItem) { } // RemoveIndex removes tab by index -func (c *TabContainer) RemoveIndex(index int) { +func (c *AppTabs) RemoveIndex(index int) { c.SetItems(append(c.Items[:index], c.Items[index+1:]...)) } // SetItems sets the container’s items and refreshes. -func (c *TabContainer) SetItems(items []*TabItem) { +func (c *AppTabs) SetItems(items []*TabItem) { c.Items = items if l := len(c.Items); c.current >= l { c.current = l - 1 @@ -133,7 +137,7 @@ func (c *TabContainer) SetItems(items []*TabItem) { } // SelectTab sets the specified TabItem to be selected and its content visible. -func (c *TabContainer) SelectTab(item *TabItem) { +func (c *AppTabs) SelectTab(item *TabItem) { for i, child := range c.Items { if child == item { c.SelectTabIndex(i) @@ -143,7 +147,7 @@ func (c *TabContainer) SelectTab(item *TabItem) { } // SelectTabIndex sets the TabItem at the specific index to be selected and its content visible. -func (c *TabContainer) SelectTabIndex(index int) { +func (c *AppTabs) SelectTabIndex(index int) { if index < 0 || index >= len(c.Items) || c.current == index { return } @@ -156,19 +160,19 @@ func (c *TabContainer) SelectTabIndex(index int) { } // SetTabLocation sets the location of the tab bar -func (c *TabContainer) SetTabLocation(l TabLocation) { +func (c *AppTabs) SetTabLocation(l TabLocation) { c.tabLocation = l c.Refresh() } // Show this widget, if it was previously hidden -func (c *TabContainer) Show() { +func (c *AppTabs) Show() { c.BaseWidget.Show() c.SelectTabIndex(c.current) c.Refresh() } -func (c *TabContainer) mismatchedContent() bool { +func (c *AppTabs) mismatchedContent() bool { var hasText, hasIcon bool for _, tab := range c.Items { hasText = hasText || tab.Text != "" @@ -186,19 +190,19 @@ func (c *TabContainer) mismatchedContent() bool { return mismatch } -type tabContainerRenderer struct { +type appTabsRenderer struct { animation *fyne.Animation - container *TabContainer + container *AppTabs tabLoc TabLocation line, underline *canvas.Rectangle objects []fyne.CanvasObject // holds only the CanvasObject of the tabs' content tabBar *fyne.Container } -func (r *tabContainerRenderer) Destroy() { +func (r *appTabsRenderer) Destroy() { } -func (r *tabContainerRenderer) Layout(size fyne.Size) { +func (r *appTabsRenderer) Layout(size fyne.Size) { tabBarMinSize := r.tabBar.MinSize() var tabBarPos fyne.Position var tabBarSize fyne.Size @@ -257,7 +261,7 @@ func (r *tabContainerRenderer) Layout(size fyne.Size) { r.moveSelection() } -func (r *tabContainerRenderer) MinSize() fyne.Size { +func (r *appTabsRenderer) MinSize() fyne.Size { buttonsMin := r.tabBar.MinSize() childMin := fyne.NewSize(0, 0) @@ -279,11 +283,11 @@ func (r *tabContainerRenderer) MinSize() fyne.Size { } } -func (r *tabContainerRenderer) Objects() []fyne.CanvasObject { +func (r *appTabsRenderer) Objects() []fyne.CanvasObject { return append(r.objects, r.tabBar, r.line, r.underline) } -func (r *tabContainerRenderer) Refresh() { +func (r *appTabsRenderer) Refresh() { r.line.FillColor = theme.ShadowColor() r.line.Refresh() r.underline.FillColor = theme.PrimaryColor() @@ -304,9 +308,9 @@ func (r *tabContainerRenderer) Refresh() { } for i, button := range r.tabBar.Objects { if i == current { - button.(*tabButton).Importance = HighImportance + button.(*tabButton).Importance = widget.HighImportance } else { - button.(*tabButton).Importance = MediumImportance + button.(*tabButton).Importance = widget.MediumImportance } button.Refresh() @@ -316,7 +320,7 @@ func (r *tabContainerRenderer) Refresh() { canvas.Refresh(r.container) } -func (r *tabContainerRenderer) adaptedLocation() TabLocation { +func (r *appTabsRenderer) adaptedLocation() TabLocation { tabLocation := r.container.tabLocation if fyne.CurrentDevice().IsMobile() && (tabLocation == TabLocationLeading || tabLocation == TabLocationTrailing) { return TabLocationBottom @@ -325,7 +329,7 @@ func (r *tabContainerRenderer) adaptedLocation() TabLocation { return r.container.tabLocation } -func (r *tabContainerRenderer) buildButton(item *TabItem, iconPos buttonIconPosition) *tabButton { +func (r *appTabsRenderer) buildButton(item *TabItem, iconPos buttonIconPosition) *tabButton { return &tabButton{ Text: item.Text, Icon: item.Icon, @@ -334,7 +338,7 @@ func (r *tabContainerRenderer) buildButton(item *TabItem, iconPos buttonIconPosi } } -func (r *tabContainerRenderer) buildTabBar(buttons []fyne.CanvasObject) *fyne.Container { +func (r *appTabsRenderer) buildTabBar(buttons []fyne.CanvasObject) *fyne.Container { var lay fyne.Layout if fyne.CurrentDevice().IsMobile() { cells := len(buttons) @@ -351,7 +355,7 @@ func (r *tabContainerRenderer) buildTabBar(buttons []fyne.CanvasObject) *fyne.Co return fyne.NewContainerWithLayout(lay, buttons...) } -func (r *tabContainerRenderer) moveSelection() { +func (r *appTabsRenderer) moveSelection() { if r.container.current < 0 { r.underline.Hide() return @@ -396,7 +400,7 @@ func (r *tabContainerRenderer) moveSelection() { } } -func (r *tabContainerRenderer) tabsInSync() bool { +func (r *appTabsRenderer) tabsInSync() bool { if r.tabBar == nil { return false } @@ -424,7 +428,7 @@ func (r *tabContainerRenderer) tabsInSync() bool { return true } -func (r *tabContainerRenderer) updateTabs() bool { +func (r *appTabsRenderer) updateTabs() bool { if r.tabsInSync() { return false } @@ -443,7 +447,7 @@ func (r *tabContainerRenderer) updateTabs() bool { for i, item := range r.container.Items { button := r.buildButton(item, iconPos) if i == r.container.current { - button.Importance = HighImportance + button.Importance = widget.HighImportance item.Content.Show() } else { item.Content.Hide() @@ -470,11 +474,11 @@ var _ fyne.Tappable = (*tabButton)(nil) var _ desktop.Hoverable = (*tabButton)(nil) type tabButton struct { - BaseWidget + widget.BaseWidget hovered bool Icon fyne.Resource IconPosition buttonIconPosition - Importance ButtonImportance + Importance widget.ButtonImportance OnTap func() Text string } @@ -625,7 +629,7 @@ func (r *tabButtonRenderer) Refresh() { r.background.Refresh() r.label.Text = r.button.Text - if r.button.Importance == HighImportance { + if r.button.Importance == widget.HighImportance { r.label.Color = theme.PrimaryColor() } else { r.label.Color = theme.ForegroundColor() @@ -640,12 +644,12 @@ func (r *tabButtonRenderer) Refresh() { if r.icon != nil && r.icon.Resource != nil { switch res := r.icon.Resource.(type) { case *theme.ThemedResource: - if r.button.Importance == HighImportance { + if r.button.Importance == widget.HighImportance { r.icon.Resource = theme.NewPrimaryThemedResource(res) r.icon.Refresh() } case *theme.PrimaryThemedResource: - if r.button.Importance != HighImportance { + if r.button.Importance != widget.HighImportance { r.icon.Resource = res.Original() r.icon.Refresh() } diff --git a/container/apptabs_desktop_test.go b/container/apptabs_desktop_test.go new file mode 100644 index 0000000000..8a2ed0a6bc --- /dev/null +++ b/container/apptabs_desktop_test.go @@ -0,0 +1,347 @@ +// +build !mobile + +package container_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" +) + +func TestTabContainer_ApplyTheme(t *testing.T) { + test.NewApp() + defer test.NewApp() + + w := test.NewWindow( + container.NewAppTabs(&container.TabItem{Text: "Test", Content: widget.NewLabel("Text")}), + ) + defer w.Close() + w.SetPadded(false) + w.Resize(fyne.NewSize(150, 150)) + c := w.Canvas() + + test.AssertImageMatches(t, "apptabs/desktop/single_initial.png", c.Capture()) + + test.ApplyTheme(t, test.NewTheme()) + test.AssertImageMatches(t, "apptabs/desktop/single_custom_theme.png", c.Capture()) +} + +func TestTabContainer_ChangeItemContent(t *testing.T) { + test.NewApp() + defer test.NewApp() + + item1 := &container.TabItem{Text: "Test1", Content: widget.NewLabel("Text1")} + item2 := &container.TabItem{Text: "Test2", Content: widget.NewLabel("Text2")} + tabs := container.NewAppTabs(item1, item2) + w := test.NewWindow(tabs) + defer w.Close() + w.SetPadded(false) + w.Resize(fyne.NewSize(150, 150)) + c := w.Canvas() + + test.AssertRendersToMarkup(t, "apptabs/desktop/change_content_initial.xml", c) + + item1.Content = widget.NewLabel("Text3") + tabs.Refresh() + test.AssertRendersToMarkup(t, "apptabs/desktop/change_content_change_visible.xml", c) + + item2.Content = widget.NewLabel("Text4") + tabs.Refresh() + test.AssertRendersToMarkup(t, "apptabs/desktop/change_content_change_hidden.xml", c) +} + +func TestTabContainer_ChangeItemIcon(t *testing.T) { + test.NewApp() + defer test.NewApp() + + item1 := &container.TabItem{Icon: theme.CancelIcon(), Content: widget.NewLabel("Text1")} + item2 := &container.TabItem{Icon: theme.ConfirmIcon(), Content: widget.NewLabel("Text2")} + tabs := container.NewAppTabs(item1, item2) + w := test.NewWindow(tabs) + defer w.Close() + w.SetPadded(false) + w.Resize(fyne.NewSize(150, 150)) + c := w.Canvas() + + test.AssertRendersToMarkup(t, "apptabs/desktop/change_icon_initial.xml", c) + + item1.Icon = theme.InfoIcon() + tabs.Refresh() + test.AssertRendersToMarkup(t, "apptabs/desktop/change_icon_change_selected.xml", c) + + item2.Icon = theme.ContentAddIcon() + tabs.Refresh() + test.AssertRendersToMarkup(t, "apptabs/desktop/change_icon_change_unselected.xml", c) +} + +func TestTabContainer_ChangeItemText(t *testing.T) { + test.NewApp() + defer test.NewApp() + + item1 := &container.TabItem{Text: "Test1", Content: widget.NewLabel("Text1")} + item2 := &container.TabItem{Text: "Test2", Content: widget.NewLabel("Text2")} + tabs := container.NewAppTabs(item1, item2) + w := test.NewWindow(tabs) + defer w.Close() + w.SetPadded(false) + w.Resize(fyne.NewSize(150, 150)) + c := w.Canvas() + + test.AssertRendersToMarkup(t, "apptabs/desktop/change_label_initial.xml", c) + + item1.Text = "New 1" + tabs.Refresh() + test.AssertRendersToMarkup(t, "apptabs/desktop/change_label_change_selected.xml", c) + + item2.Text = "New 2" + tabs.Refresh() + test.AssertRendersToMarkup(t, "apptabs/desktop/change_label_change_unselected.xml", c) +} + +func TestTabContainer_DynamicTabs(t *testing.T) { + test.NewApp() + defer test.NewApp() + + item1 := &container.TabItem{Text: "Test1", Content: widget.NewLabel("Text 1")} + tabs := container.NewAppTabs(item1) + w := test.NewWindow(tabs) + defer w.Close() + w.SetPadded(false) + w.Resize(fyne.NewSize(300, 150)) + c := w.Canvas() + + test.AssertRendersToMarkup(t, "apptabs/desktop/dynamic_initial.xml", c) + + appendedItem := container.NewTabItem("Test2", widget.NewLabel("Text 2")) + tabs.Append(appendedItem) + assert.Equal(t, 2, len(tabs.Items)) + assert.Equal(t, "Test2", tabs.Items[1].Text) + test.AssertRendersToMarkup(t, "apptabs/desktop/dynamic_appended.xml", c) + + tabs.RemoveIndex(1) + assert.Equal(t, len(tabs.Items), 1) + assert.Equal(t, "Test1", tabs.Items[0].Text) + test.AssertRendersToMarkup(t, "apptabs/desktop/dynamic_initial.xml", c) + + tabs.Append(appendedItem) + tabs.Remove(tabs.Items[0]) + assert.Equal(t, len(tabs.Items), 1) + assert.Equal(t, "Test2", tabs.Items[0].Text) + test.AssertRendersToMarkup(t, "apptabs/desktop/dynamic_appended_and_removed.xml", c) + + tabs.Append(container.NewTabItem("Test3", canvas.NewCircle(theme.BackgroundColor()))) + tabs.Append(container.NewTabItem("Test4", canvas.NewCircle(theme.BackgroundColor()))) + tabs.Append(container.NewTabItem("Test5", canvas.NewCircle(theme.BackgroundColor()))) + assert.Equal(t, 4, len(tabs.Items)) + assert.Equal(t, "Test3", tabs.Items[1].Text) + assert.Equal(t, "Test4", tabs.Items[2].Text) + assert.Equal(t, "Test5", tabs.Items[3].Text) + test.AssertRendersToMarkup(t, "apptabs/desktop/dynamic_appended_another_three.xml", c) + + tabs.SetItems([]*container.TabItem{ + container.NewTabItem("Test6", widget.NewLabel("Text 6")), + container.NewTabItem("Test7", widget.NewLabel("Text 7")), + container.NewTabItem("Test8", widget.NewLabel("Text 8")), + }) + assert.Equal(t, 3, len(tabs.Items)) + assert.Equal(t, "Test6", tabs.Items[0].Text) + assert.Equal(t, "Test7", tabs.Items[1].Text) + assert.Equal(t, "Test8", tabs.Items[2].Text) + test.AssertRendersToMarkup(t, "apptabs/desktop/dynamic_replaced_completely.xml", c) +} + +func TestTabContainer_HoverButtons(t *testing.T) { + test.NewApp() + defer test.NewApp() + + item1 := &container.TabItem{Text: "Test1", Content: widget.NewLabel("Text1")} + item2 := &container.TabItem{Text: "Test2", Content: widget.NewLabel("Text2")} + tabs := container.NewAppTabs(item1, item2) + w := test.NewWindow(tabs) + defer w.Close() + w.SetPadded(false) + w.Resize(fyne.NewSize(150, 150)) + c := w.Canvas() + + test.AssertRendersToMarkup(t, "apptabs/desktop/hover_none.xml", c) + + test.MoveMouse(c, fyne.NewPos(10, 10)) + test.AssertRendersToMarkup(t, "apptabs/desktop/hover_first.xml", c) + + test.MoveMouse(c, fyne.NewPos(75, 10)) + test.AssertRendersToMarkup(t, "apptabs/desktop/hover_second.xml", c) + + test.MoveMouse(c, fyne.NewPos(10, 10)) + test.AssertRendersToMarkup(t, "apptabs/desktop/hover_first.xml", c) +} + +func TestTabContainer_Layout(t *testing.T) { + test.NewApp() + defer test.NewApp() + + w := test.NewWindow(nil) + defer w.Close() + w.SetPadded(false) + c := w.Canvas() + + tests := []struct { + name string + item *container.TabItem + location container.TabLocation + want string + }{ + { + name: "top: tab with icon and text", + item: container.NewTabItemWithIcon("Text1", theme.CancelIcon(), canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationTop, + want: "apptabs/desktop/layout_top_icon_and_text.xml", + }, + { + name: "top: tab with text only", + item: container.NewTabItem("Text2", canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationTop, + want: "apptabs/desktop/layout_top_text.xml", + }, + { + name: "top: tab with icon only", + item: container.NewTabItemWithIcon("", theme.InfoIcon(), canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationTop, + want: "apptabs/desktop/layout_top_icon.xml", + }, + { + name: "bottom: tab with icon and text", + item: container.NewTabItemWithIcon("Text1", theme.CancelIcon(), canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationBottom, + want: "apptabs/desktop/layout_bottom_icon_and_text.xml", + }, + { + name: "bottom: tab with text only", + item: container.NewTabItem("Text2", canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationBottom, + want: "apptabs/desktop/layout_bottom_text.xml", + }, + { + name: "bottom: tab with icon only", + item: container.NewTabItemWithIcon("", theme.InfoIcon(), canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationBottom, + want: "apptabs/desktop/layout_bottom_icon.xml", + }, + { + name: "leading: tab with icon and text", + item: container.NewTabItemWithIcon("Text1", theme.CancelIcon(), canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationLeading, + want: "apptabs/desktop/layout_leading_icon_and_text.xml", + }, + { + name: "leading: tab with text only", + item: container.NewTabItem("Text2", canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationLeading, + want: "apptabs/desktop/layout_leading_text.xml", + }, + { + name: "leading: tab with icon only", + item: container.NewTabItemWithIcon("", theme.InfoIcon(), canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationLeading, + want: "apptabs/desktop/layout_leading_icon.xml", + }, + { + name: "trailing: tab with icon and text", + item: container.NewTabItemWithIcon("Text1", theme.CancelIcon(), canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationTrailing, + want: "apptabs/desktop/layout_trailing_icon_and_text.xml", + }, + { + name: "trailing: tab with text only", + item: container.NewTabItem("Text2", canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationTrailing, + want: "apptabs/desktop/layout_trailing_text.xml", + }, + { + name: "trailing: tab with icon only", + item: container.NewTabItemWithIcon("", theme.InfoIcon(), canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationTrailing, + want: "apptabs/desktop/layout_trailing_icon.xml", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tabs := container.NewAppTabs(tt.item) + tabs.SetTabLocation(tt.location) + w.SetContent(tabs) + w.Resize(fyne.NewSize(150, 150)) + + test.AssertRendersToMarkup(t, tt.want, c) + }) + } +} + +func TestTabContainer_SetTabLocation(t *testing.T) { + test.NewApp() + defer test.NewApp() + + item1 := &container.TabItem{Text: "Test1", Content: widget.NewLabel("Text 1")} + item2 := &container.TabItem{Text: "Test2", Content: widget.NewLabel("Text 2")} + item3 := &container.TabItem{Text: "Test3", Content: widget.NewLabel("Text 3")} + tabs := container.NewAppTabs(item1, item2, item3) + w := test.NewWindow(tabs) + defer w.Close() + w.SetPadded(false) + c := w.Canvas() + + w.Resize(tabs.MinSize()) + test.AssertRendersToMarkup(t, "apptabs/desktop/tab_location_top.xml", c) + + tabs.SetTabLocation(container.TabLocationLeading) + w.Resize(tabs.MinSize()) + test.AssertRendersToMarkup(t, "apptabs/desktop/tab_location_leading.xml", c) + + tabs.SetTabLocation(container.TabLocationBottom) + w.Resize(tabs.MinSize()) + test.AssertRendersToMarkup(t, "apptabs/desktop/tab_location_bottom.xml", c) + + tabs.SetTabLocation(container.TabLocationTrailing) + w.Resize(tabs.MinSize()) + test.AssertRendersToMarkup(t, "apptabs/desktop/tab_location_trailing.xml", c) + + tabs.SetTabLocation(container.TabLocationTop) + w.Resize(tabs.MinSize()) + test.AssertRendersToMarkup(t, "apptabs/desktop/tab_location_top.xml", c) +} + +func TestTabContainer_Tapped(t *testing.T) { + test.NewApp() + defer test.NewApp() + + item1 := &container.TabItem{Text: "Test1", Content: widget.NewLabel("Text 1")} + item2 := &container.TabItem{Text: "Test2", Content: widget.NewLabel("Text 2")} + item3 := &container.TabItem{Text: "Test3", Content: widget.NewLabel("Text 3")} + tabs := container.NewAppTabs(item1, item2, item3) + w := test.NewWindow(tabs) + defer w.Close() + w.SetPadded(false) + w.Resize(fyne.NewSize(200, 100)) + c := w.Canvas() + + require.Equal(t, 0, tabs.CurrentTabIndex()) + test.AssertRendersToMarkup(t, "apptabs/desktop/tapped_first_selected.xml", c) + + test.TapCanvas(c, fyne.NewPos(75, 10)) + assert.Equal(t, 1, tabs.CurrentTabIndex()) + test.AssertRendersToMarkup(t, "apptabs/desktop/tapped_second_selected.xml", c) + + test.TapCanvas(c, fyne.NewPos(150, 10)) + assert.Equal(t, 2, tabs.CurrentTabIndex()) + test.AssertRendersToMarkup(t, "apptabs/desktop/tapped_third_selected.xml", c) + + test.TapCanvas(c, fyne.NewPos(10, 10)) + require.Equal(t, 0, tabs.CurrentTabIndex()) + test.AssertRendersToMarkup(t, "apptabs/desktop/tapped_first_selected.xml", c) +} diff --git a/widget/tabcontainer_extend_test.go b/container/apptabs_extend_test.go similarity index 86% rename from widget/tabcontainer_extend_test.go rename to container/apptabs_extend_test.go index e4005bae61..9f0ef06de6 100644 --- a/widget/tabcontainer_extend_test.go +++ b/container/apptabs_extend_test.go @@ -1,17 +1,19 @@ -package widget +package container import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) type extendedTabContainer struct { - TabContainer + AppTabs } func newExtendedTabContainer(items ...*TabItem) *extendedTabContainer { @@ -24,10 +26,10 @@ func newExtendedTabContainer(items ...*TabItem) *extendedTabContainer { func TestTabContainer_Extended_Tapped(t *testing.T) { tabs := newExtendedTabContainer( - NewTabItem("Test1", NewLabel("Test1")), - NewTabItem("Test2", NewLabel("Test2")), + NewTabItem("Test1", widget.NewLabel("Test1")), + NewTabItem("Test2", widget.NewLabel("Test2")), ) - r := test.WidgetRenderer(tabs).(*tabContainerRenderer) + r := test.WidgetRenderer(tabs).(*appTabsRenderer) tab1 := r.tabBar.Objects[0].(*tabButton) tab2 := r.tabBar.Objects[1].(*tabButton) diff --git a/widget/tabcontainer_internal_test.go b/container/apptabs_internal_test.go similarity index 70% rename from widget/tabcontainer_internal_test.go rename to container/apptabs_internal_test.go index 4766868418..57199b8240 100644 --- a/widget/tabcontainer_internal_test.go +++ b/container/apptabs_internal_test.go @@ -1,17 +1,18 @@ -package widget +package container import ( "testing" - "fyne.io/fyne/internal/cache" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) func Test_tabButtonRenderer_SetText(t *testing.T) { - item := &TabItem{Text: "Test", Content: NewLabel("Content")} - tabs := NewTabContainer(item) - tabRenderer := cache.Renderer(tabs).(*tabContainerRenderer) + item := &TabItem{Text: "Test", Content: widget.NewLabel("Content")} + tabs := NewAppTabs(item) + tabRenderer := cache.Renderer(tabs).(*appTabsRenderer) button := tabRenderer.tabBar.Objects[0].(*tabButton) renderer := cache.Renderer(button).(*tabButtonRenderer) diff --git a/container/apptabs_mobile_test.go b/container/apptabs_mobile_test.go new file mode 100644 index 0000000000..8a7533d5cb --- /dev/null +++ b/container/apptabs_mobile_test.go @@ -0,0 +1,347 @@ +// +build mobile + +package container_test + +import ( + "testing" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestTabContainer_ApplyTheme(t *testing.T) { + test.NewApp() + defer test.NewApp() + + w := test.NewWindow( + container.NewAppTabs(&container.TabItem{Text: "Test", Content: widget.NewLabel("Text")}), + ) + defer w.Close() + w.SetPadded(false) + w.Resize(fyne.NewSize(150, 150)) + c := w.Canvas() + + test.AssertImageMatches(t, "apptabs/mobile/theme_default.png", c.Capture()) + + test.ApplyTheme(t, test.NewTheme()) + test.AssertImageMatches(t, "apptabs/mobile/theme_ugly.png", c.Capture()) +} + +func TestTabContainer_ChangeItemContent(t *testing.T) { + test.NewApp() + defer test.NewApp() + + item1 := &container.TabItem{Text: "Test1", Content: widget.NewLabel("Text1")} + item2 := &container.TabItem{Text: "Test2", Content: widget.NewLabel("Text2")} + tabs := container.NewAppTabs(item1, item2) + w := test.NewWindow(tabs) + defer w.Close() + w.SetPadded(false) + w.Resize(fyne.NewSize(150, 150)) + c := w.Canvas() + + test.AssertRendersToMarkup(t, "apptabs/mobile/change_content_initial.xml", c) + + item1.Content = widget.NewLabel("Text3") + tabs.Refresh() + test.AssertRendersToMarkup(t, "apptabs/mobile/change_content_change_visible.xml", c) + + item2.Content = widget.NewLabel("Text4") + tabs.Refresh() + test.AssertRendersToMarkup(t, "apptabs/mobile/change_content_change_hidden.xml", c) +} + +func TestTabContainer_ChangeItemIcon(t *testing.T) { + test.NewApp() + defer test.NewApp() + + item1 := &container.TabItem{Icon: theme.CancelIcon(), Content: widget.NewLabel("Text1")} + item2 := &container.TabItem{Icon: theme.ConfirmIcon(), Content: widget.NewLabel("Text2")} + tabs := container.NewAppTabs(item1, item2) + w := test.NewWindow(tabs) + defer w.Close() + w.SetPadded(false) + w.Resize(fyne.NewSize(150, 150)) + c := w.Canvas() + + test.AssertRendersToMarkup(t, "apptabs/mobile/change_icon_initial.xml", c) + + item1.Icon = theme.InfoIcon() + tabs.Refresh() + test.AssertRendersToMarkup(t, "apptabs/mobile/change_icon_change_selected.xml", c) + + item2.Icon = theme.ContentAddIcon() + tabs.Refresh() + test.AssertRendersToMarkup(t, "apptabs/mobile/change_icon_change_unselected.xml", c) +} + +func TestTabContainer_ChangeItemText(t *testing.T) { + test.NewApp() + defer test.NewApp() + + item1 := &container.TabItem{Text: "Test1", Content: widget.NewLabel("Text1")} + item2 := &container.TabItem{Text: "Test2", Content: widget.NewLabel("Text2")} + tabs := container.NewAppTabs(item1, item2) + w := test.NewWindow(tabs) + defer w.Close() + w.SetPadded(false) + w.Resize(fyne.NewSize(150, 150)) + c := w.Canvas() + + test.AssertRendersToMarkup(t, "apptabs/mobile/change_label_initial.xml", c) + + item1.Text = "New 1" + tabs.Refresh() + test.AssertRendersToMarkup(t, "apptabs/mobile/change_label_change_selected.xml", c) + + item2.Text = "New 2" + tabs.Refresh() + test.AssertRendersToMarkup(t, "apptabs/mobile/change_label_change_unselected.xml", c) +} + +func TestTabContainer_DynamicTabs(t *testing.T) { + test.NewApp() + defer test.NewApp() + + item1 := &container.TabItem{Text: "Test1", Content: widget.NewLabel("Text 1")} + tabs := container.NewAppTabs(item1) + w := test.NewWindow(tabs) + defer w.Close() + w.SetPadded(false) + w.Resize(fyne.NewSize(300, 150)) + c := w.Canvas() + + test.AssertRendersToMarkup(t, "apptabs/mobile/dynamic_initial.xml", c) + + appendedItem := container.NewTabItem("Test2", widget.NewLabel("Text 2")) + tabs.Append(appendedItem) + assert.Equal(t, 2, len(tabs.Items)) + assert.Equal(t, "Test2", tabs.Items[1].Text) + test.AssertRendersToMarkup(t, "apptabs/mobile/dynamic_appended.xml", c) + + tabs.RemoveIndex(1) + assert.Equal(t, len(tabs.Items), 1) + assert.Equal(t, "Test1", tabs.Items[0].Text) + test.AssertRendersToMarkup(t, "apptabs/mobile/dynamic_initial.xml", c) + + tabs.Append(appendedItem) + tabs.Remove(tabs.Items[0]) + assert.Equal(t, len(tabs.Items), 1) + assert.Equal(t, "Test2", tabs.Items[0].Text) + test.AssertRendersToMarkup(t, "apptabs/mobile/dynamic_appended_and_removed.xml", c) + + tabs.Append(container.NewTabItem("Test3", canvas.NewCircle(theme.BackgroundColor()))) + tabs.Append(container.NewTabItem("Test4", canvas.NewCircle(theme.BackgroundColor()))) + tabs.Append(container.NewTabItem("Test5", canvas.NewCircle(theme.BackgroundColor()))) + assert.Equal(t, 4, len(tabs.Items)) + assert.Equal(t, "Test3", tabs.Items[1].Text) + assert.Equal(t, "Test4", tabs.Items[2].Text) + assert.Equal(t, "Test5", tabs.Items[3].Text) + test.AssertRendersToMarkup(t, "apptabs/mobile/dynamic_appended_another_three.xml", c) + + tabs.SetItems([]*container.TabItem{ + container.NewTabItem("Test6", widget.NewLabel("Text 6")), + container.NewTabItem("Test7", widget.NewLabel("Text 7")), + container.NewTabItem("Test8", widget.NewLabel("Text 8")), + }) + assert.Equal(t, 3, len(tabs.Items)) + assert.Equal(t, "Test6", tabs.Items[0].Text) + assert.Equal(t, "Test7", tabs.Items[1].Text) + assert.Equal(t, "Test8", tabs.Items[2].Text) + test.AssertRendersToMarkup(t, "apptabs/mobile/dynamic_replaced_completely.xml", c) +} + +func TestTabContainer_HoverButtons(t *testing.T) { + test.NewApp() + defer test.NewApp() + test.ApplyTheme(t, theme.LightTheme()) + + item1 := &container.TabItem{Text: "Test1", Content: widget.NewLabel("Text1")} + item2 := &container.TabItem{Text: "Test2", Content: widget.NewLabel("Text2")} + tabs := container.NewAppTabs(item1, item2) + w := test.NewWindow(tabs) + defer w.Close() + w.SetPadded(false) + w.Resize(fyne.NewSize(150, 150)) + c := w.Canvas() + + test.AssertRendersToMarkup(t, "apptabs/mobile/hover_none.xml", c) + + test.MoveMouse(c, fyne.NewPos(10, 10)) + test.AssertRendersToMarkup(t, "apptabs/mobile/hover_none.xml", c, "no hovering on mobile") + + test.MoveMouse(c, fyne.NewPos(75, 10)) + test.AssertRendersToMarkup(t, "apptabs/mobile/hover_none.xml", c, "no hovering on mobile") + + test.MoveMouse(c, fyne.NewPos(10, 10)) + test.AssertRendersToMarkup(t, "apptabs/mobile/hover_none.xml", c, "no hovering on mobile") +} + +func TestTabContainer_Layout(t *testing.T) { + test.NewApp() + defer test.NewApp() + + w := test.NewWindow(nil) + defer w.Close() + w.SetPadded(false) + c := w.Canvas() + + tests := []struct { + name string + item *container.TabItem + location container.TabLocation + want string + }{ + { + name: "top: tab with icon and text", + item: container.NewTabItemWithIcon("Text1", theme.CancelIcon(), canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationTop, + want: "apptabs/mobile/layout_top_icon_and_text.xml", + }, + { + name: "top: tab with text only", + item: container.NewTabItem("Text2", canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationTop, + want: "apptabs/mobile/layout_top_text.xml", + }, + { + name: "top: tab with icon only", + item: container.NewTabItemWithIcon("", theme.InfoIcon(), canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationTop, + want: "apptabs/mobile/layout_top_icon.xml", + }, + { + name: "bottom: tab with icon and text", + item: container.NewTabItemWithIcon("Text1", theme.CancelIcon(), canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationBottom, + want: "apptabs/mobile/layout_bottom_icon_and_text.xml", + }, + { + name: "bottom: tab with text only", + item: container.NewTabItem("Text2", canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationBottom, + want: "apptabs/mobile/layout_bottom_text.xml", + }, + { + name: "bottom: tab with icon only", + item: container.NewTabItemWithIcon("", theme.InfoIcon(), canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationBottom, + want: "apptabs/mobile/layout_bottom_ico.xml", + }, + { + name: "leading: tab with icon and text", + item: container.NewTabItemWithIcon("Text1", theme.CancelIcon(), canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationLeading, + want: "apptabs/mobile/layout_bottom_icon_and_text.xml", + }, + { + name: "leading: tab with text only", + item: container.NewTabItem("Text2", canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationLeading, + want: "apptabs/mobile/layout_bottom_text.xml", + }, + { + name: "leading: tab with icon only", + item: container.NewTabItemWithIcon("", theme.InfoIcon(), canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationLeading, + want: "apptabs/mobile/layout_bottom_icon.xml", + }, + { + name: "trailing: tab with icon and text", + item: container.NewTabItemWithIcon("Text1", theme.CancelIcon(), canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationTrailing, + want: "apptabs/mobile/layout_bottom_icon_and_text.xml", + }, + { + name: "trailing: tab with text only", + item: container.NewTabItem("Text2", canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationTrailing, + want: "apptabs/mobile/layout_bottom_text.xml", + }, + { + name: "trailing: tab with icon only", + item: container.NewTabItemWithIcon("", theme.InfoIcon(), canvas.NewCircle(theme.BackgroundColor())), + location: container.TabLocationTrailing, + want: "apptabs/mobile/layout_bottom_icon.xml", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tabs := container.NewAppTabs(tt.item) + tabs.SetTabLocation(tt.location) + w.SetContent(tabs) + w.Resize(fyne.NewSize(150, 150)) + + test.AssertRendersToMarkup(t, tt.want, c) + }) + } +} + +func TestTabContainer_SetTabLocation(t *testing.T) { + test.NewApp() + defer test.NewApp() + + item1 := &container.TabItem{Text: "Test1", Content: widget.NewLabel("Text 1")} + item2 := &container.TabItem{Text: "Test2", Content: widget.NewLabel("Text 2")} + item3 := &container.TabItem{Text: "Test3", Content: widget.NewLabel("Text 3")} + tabs := container.NewAppTabs(item1, item2, item3) + w := test.NewWindow(tabs) + defer w.Close() + w.SetPadded(false) + c := w.Canvas() + + w.Resize(tabs.MinSize()) + test.AssertRendersToMarkup(t, "apptabs/mobile/tab_location_top.xml", c) + + tabs.SetTabLocation(container.TabLocationLeading) + w.Resize(tabs.MinSize()) + test.AssertRendersToMarkup(t, "apptabs/mobile/tab_location_bottom.xml", c, "leading is the same as bottom on mobile") + + tabs.SetTabLocation(container.TabLocationBottom) + w.Resize(tabs.MinSize()) + test.AssertRendersToMarkup(t, "apptabs/mobile/tab_location_bottom.xml", c) + + tabs.SetTabLocation(container.TabLocationTrailing) + w.Resize(tabs.MinSize()) + test.AssertRendersToMarkup(t, "apptabs/mobile/tab_location_bottom.xml", c, "trailing is the same as bottom on mobile") + + tabs.SetTabLocation(container.TabLocationTop) + w.Resize(tabs.MinSize()) + test.AssertRendersToMarkup(t, "apptabs/mobile/tab_location_top.xml", c) +} + +func TestTabContainer_Tapped(t *testing.T) { + test.NewApp() + defer test.NewApp() + + item1 := &container.TabItem{Text: "Test1", Content: widget.NewLabel("Text 1")} + item2 := &container.TabItem{Text: "Test2", Content: widget.NewLabel("Text 2")} + item3 := &container.TabItem{Text: "Test3", Content: widget.NewLabel("Text 3")} + tabs := container.NewAppTabs(item1, item2, item3) + w := test.NewWindow(tabs) + defer w.Close() + w.SetPadded(false) + w.Resize(fyne.NewSize(200, 100)) + c := w.Canvas() + + require.Equal(t, 0, tabs.CurrentTabIndex()) + test.AssertRendersToMarkup(t, "apptabs/mobile/tapped_first_selected.xml", c) + + test.TapCanvas(c, fyne.NewPos(75, 10)) + assert.Equal(t, 1, tabs.CurrentTabIndex()) + test.AssertRendersToMarkup(t, "apptabs/mobile/tapped_second_selected.xml", c) + + test.TapCanvas(c, fyne.NewPos(150, 10)) + assert.Equal(t, 2, tabs.CurrentTabIndex()) + test.AssertRendersToMarkup(t, "apptabs/mobile/tapped_third_selected.xml", c) + + test.TapCanvas(c, fyne.NewPos(10, 10)) + require.Equal(t, 0, tabs.CurrentTabIndex()) + test.AssertRendersToMarkup(t, "apptabs/mobile/tapped_first_selected.xml", c) +} diff --git a/container/container.go b/container/container.go index 1adc9d3943..fa4525fe61 100644 --- a/container/container.go +++ b/container/container.go @@ -2,19 +2,19 @@ package container import ( - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // New returns a new Container instance holding the specified CanvasObjects which will be laid out according to the specified Layout. // -// Since 2.0.0 +// Since: 2.0 func New(layout fyne.Layout, objects ...fyne.CanvasObject) *fyne.Container { return fyne.NewContainerWithLayout(layout, objects...) } // NewWithoutLayout returns a new Container instance holding the specified CanvasObjects that are manually arranged. // -// Since 2.0.0 +// Since: 2.0 func NewWithoutLayout(objects ...fyne.CanvasObject) *fyne.Container { return fyne.NewContainerWithoutLayout(objects...) } diff --git a/container/layouts.go b/container/layouts.go index 16753a0178..6bd7034172 100644 --- a/container/layouts.go +++ b/container/layouts.go @@ -1,8 +1,8 @@ -package container // import "fyne.io/fyne/container" +package container // import "fyne.io/fyne/v2/container" import ( - "fyne.io/fyne" - "fyne.io/fyne/layout" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/layout" ) // NewAdaptiveGrid creates a new container with the specified objects and using the grid layout. diff --git a/container/scroll.go b/container/scroll.go index 8b76816026..ace8c0359d 100644 --- a/container/scroll.go +++ b/container/scroll.go @@ -1,8 +1,8 @@ package container import ( - "fyne.io/fyne" - "fyne.io/fyne/internal/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/widget" ) // Scroll defines a container that is smaller than the Content. diff --git a/container/split.go b/container/split.go index 9340c76624..10fdbdc881 100644 --- a/container/split.go +++ b/container/split.go @@ -1,11 +1,11 @@ package container import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) // Declare conformity with CanvasObject interface diff --git a/container/split_test.go b/container/split_test.go index c03abed601..5dbf5bba70 100644 --- a/container/split_test.go +++ b/container/split_test.go @@ -4,9 +4,9 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" "github.com/stretchr/testify/assert" ) diff --git a/container/tabs.go b/container/tabs.go deleted file mode 100644 index 8a4d60594a..0000000000 --- a/container/tabs.go +++ /dev/null @@ -1,56 +0,0 @@ -package container - -import ( - "fyne.io/fyne" - "fyne.io/fyne/widget" -) - -// AppTabs container is used to split your application into various different areas identified by tabs. -// The tabs contain text and/or an icon and allow the user to switch between the content specified in each TabItem. -// Each item is represented by a button at the edge of the container. -// -// Since: 1.4 -type AppTabs = widget.TabContainer - -// TabItem represents a single view in a TabContainer. -// The Text and Icon are used for the tab button and the Content is shown when the corresponding tab is active. -// -// Since: 1.4 -type TabItem = widget.TabItem - -// TabLocation is the location where the tabs of a tab container should be rendered -// -// Since: 1.4 -type TabLocation = widget.TabLocation - -// TabLocation values -const ( - TabLocationTop TabLocation = iota - TabLocationLeading - TabLocationBottom - TabLocationTrailing -) - -// NewAppTabs creates a new tab container that allows the user to choose between different areas of an app. -// -// Since: 1.4 -func NewAppTabs(items ...*TabItem) *AppTabs { - return widget.NewTabContainer(items...) -} - -// NewTabItem creates a new item for a tabbed widget - each item specifies the content and a label for its tab. -// -// Since: 1.4 -func NewTabItem(text string, content fyne.CanvasObject) *TabItem { - return widget.NewTabItem(text, content) -} - -// NewTabItemWithIcon creates a new item for a tabbed widget - each item specifies the content and a label with an icon for its tab. -// -// Since: 1.4 -func NewTabItemWithIcon(text string, icon fyne.Resource, content fyne.CanvasObject) *TabItem { - return widget.NewTabItemWithIcon(text, icon, content) -} - -// TODO move the implementation into here in 2.0 when we delete the old API. -// we cannot do that right now due to Scroll dependency order. diff --git a/widget/testdata/tabcontainer/desktop/change_content_change_hidden.xml b/container/testdata/apptabs/desktop/change_content_change_hidden.xml similarity index 75% rename from widget/testdata/tabcontainer/desktop/change_content_change_hidden.xml rename to container/testdata/apptabs/desktop/change_content_change_hidden.xml index c9adf5cf7a..40e6092b23 100644 --- a/widget/testdata/tabcontainer/desktop/change_content_change_hidden.xml +++ b/container/testdata/apptabs/desktop/change_content_change_hidden.xml @@ -1,14 +1,14 @@ - + Text3 - + Test1 - + Test2 diff --git a/widget/testdata/tabcontainer/desktop/change_content_change_visible.xml b/container/testdata/apptabs/desktop/change_content_change_visible.xml similarity index 75% rename from widget/testdata/tabcontainer/desktop/change_content_change_visible.xml rename to container/testdata/apptabs/desktop/change_content_change_visible.xml index c9adf5cf7a..40e6092b23 100644 --- a/widget/testdata/tabcontainer/desktop/change_content_change_visible.xml +++ b/container/testdata/apptabs/desktop/change_content_change_visible.xml @@ -1,14 +1,14 @@ - + Text3 - + Test1 - + Test2 diff --git a/widget/testdata/tabcontainer/desktop/change_content_initial.xml b/container/testdata/apptabs/desktop/change_content_initial.xml similarity index 75% rename from widget/testdata/tabcontainer/desktop/change_content_initial.xml rename to container/testdata/apptabs/desktop/change_content_initial.xml index c658878014..00cdc02f2a 100644 --- a/widget/testdata/tabcontainer/desktop/change_content_initial.xml +++ b/container/testdata/apptabs/desktop/change_content_initial.xml @@ -1,14 +1,14 @@ - + Text1 - + Test1 - + Test2 diff --git a/widget/testdata/tabcontainer/desktop/change_icon_change_selected.xml b/container/testdata/apptabs/desktop/change_icon_change_selected.xml similarity index 75% rename from widget/testdata/tabcontainer/desktop/change_icon_change_selected.xml rename to container/testdata/apptabs/desktop/change_icon_change_selected.xml index 928a06c464..a8f09cdc20 100644 --- a/widget/testdata/tabcontainer/desktop/change_icon_change_selected.xml +++ b/container/testdata/apptabs/desktop/change_icon_change_selected.xml @@ -1,14 +1,14 @@ - + Text1 - + - + diff --git a/widget/testdata/tabcontainer/desktop/change_icon_change_unselected.xml b/container/testdata/apptabs/desktop/change_icon_change_unselected.xml similarity index 75% rename from widget/testdata/tabcontainer/desktop/change_icon_change_unselected.xml rename to container/testdata/apptabs/desktop/change_icon_change_unselected.xml index 021978d645..83dfbe449b 100644 --- a/widget/testdata/tabcontainer/desktop/change_icon_change_unselected.xml +++ b/container/testdata/apptabs/desktop/change_icon_change_unselected.xml @@ -1,14 +1,14 @@ - + Text1 - + - + diff --git a/widget/testdata/tabcontainer/desktop/change_icon_initial.xml b/container/testdata/apptabs/desktop/change_icon_initial.xml similarity index 75% rename from widget/testdata/tabcontainer/desktop/change_icon_initial.xml rename to container/testdata/apptabs/desktop/change_icon_initial.xml index f35d6b23c2..ff7f3e8635 100644 --- a/widget/testdata/tabcontainer/desktop/change_icon_initial.xml +++ b/container/testdata/apptabs/desktop/change_icon_initial.xml @@ -1,14 +1,14 @@ - + Text1 - + - + diff --git a/widget/testdata/tabcontainer/desktop/change_label_change_selected.xml b/container/testdata/apptabs/desktop/change_label_change_selected.xml similarity index 75% rename from widget/testdata/tabcontainer/desktop/change_label_change_selected.xml rename to container/testdata/apptabs/desktop/change_label_change_selected.xml index 0ee7669b58..d9e14ef920 100644 --- a/widget/testdata/tabcontainer/desktop/change_label_change_selected.xml +++ b/container/testdata/apptabs/desktop/change_label_change_selected.xml @@ -1,14 +1,14 @@ - + Text1 - + New 1 - + Test2 diff --git a/widget/testdata/tabcontainer/desktop/change_label_change_unselected.xml b/container/testdata/apptabs/desktop/change_label_change_unselected.xml similarity index 75% rename from widget/testdata/tabcontainer/desktop/change_label_change_unselected.xml rename to container/testdata/apptabs/desktop/change_label_change_unselected.xml index 356d9c830f..c657035a70 100644 --- a/widget/testdata/tabcontainer/desktop/change_label_change_unselected.xml +++ b/container/testdata/apptabs/desktop/change_label_change_unselected.xml @@ -1,14 +1,14 @@ - + Text1 - + New 1 - + New 2 diff --git a/widget/testdata/tabcontainer/desktop/change_label_initial.xml b/container/testdata/apptabs/desktop/change_label_initial.xml similarity index 75% rename from widget/testdata/tabcontainer/desktop/change_label_initial.xml rename to container/testdata/apptabs/desktop/change_label_initial.xml index c658878014..00cdc02f2a 100644 --- a/widget/testdata/tabcontainer/desktop/change_label_initial.xml +++ b/container/testdata/apptabs/desktop/change_label_initial.xml @@ -1,14 +1,14 @@ - + Text1 - + Test1 - + Test2 diff --git a/widget/testdata/tabcontainer/desktop/dynamic_appended.xml b/container/testdata/apptabs/desktop/dynamic_appended.xml similarity index 75% rename from widget/testdata/tabcontainer/desktop/dynamic_appended.xml rename to container/testdata/apptabs/desktop/dynamic_appended.xml index a975eab866..4fbb658872 100644 --- a/widget/testdata/tabcontainer/desktop/dynamic_appended.xml +++ b/container/testdata/apptabs/desktop/dynamic_appended.xml @@ -1,14 +1,14 @@ - + Text 1 - + Test1 - + Test2 diff --git a/widget/testdata/tabcontainer/desktop/dynamic_appended_and_removed.xml b/container/testdata/apptabs/desktop/dynamic_appended_and_removed.xml similarity index 81% rename from widget/testdata/tabcontainer/desktop/dynamic_appended_and_removed.xml rename to container/testdata/apptabs/desktop/dynamic_appended_and_removed.xml index 0549484bcc..40082ad5fa 100644 --- a/widget/testdata/tabcontainer/desktop/dynamic_appended_and_removed.xml +++ b/container/testdata/apptabs/desktop/dynamic_appended_and_removed.xml @@ -1,11 +1,11 @@ - + Text 2 - + Test2 diff --git a/widget/testdata/tabcontainer/desktop/dynamic_appended_another_three.xml b/container/testdata/apptabs/desktop/dynamic_appended_another_three.xml similarity index 70% rename from widget/testdata/tabcontainer/desktop/dynamic_appended_another_three.xml rename to container/testdata/apptabs/desktop/dynamic_appended_another_three.xml index 4291bd8733..c87e9f4c00 100644 --- a/widget/testdata/tabcontainer/desktop/dynamic_appended_another_three.xml +++ b/container/testdata/apptabs/desktop/dynamic_appended_another_three.xml @@ -1,20 +1,20 @@ - + Text 2 - + Test2 - + Test3 - + Test4 - + Test5 diff --git a/widget/testdata/tabcontainer/desktop/dynamic_initial.xml b/container/testdata/apptabs/desktop/dynamic_initial.xml similarity index 81% rename from widget/testdata/tabcontainer/desktop/dynamic_initial.xml rename to container/testdata/apptabs/desktop/dynamic_initial.xml index e73ace9887..d00ca13516 100644 --- a/widget/testdata/tabcontainer/desktop/dynamic_initial.xml +++ b/container/testdata/apptabs/desktop/dynamic_initial.xml @@ -1,11 +1,11 @@ - + Text 1 - + Test1 diff --git a/widget/testdata/tabcontainer/desktop/dynamic_replaced_completely.xml b/container/testdata/apptabs/desktop/dynamic_replaced_completely.xml similarity index 72% rename from widget/testdata/tabcontainer/desktop/dynamic_replaced_completely.xml rename to container/testdata/apptabs/desktop/dynamic_replaced_completely.xml index d10f1d55ea..f6dba008ea 100644 --- a/widget/testdata/tabcontainer/desktop/dynamic_replaced_completely.xml +++ b/container/testdata/apptabs/desktop/dynamic_replaced_completely.xml @@ -1,17 +1,17 @@ - + Text 6 - + Test6 - + Test7 - + Test8 diff --git a/widget/testdata/tabcontainer/desktop/hover_first.xml b/container/testdata/apptabs/desktop/hover_first.xml similarity index 77% rename from widget/testdata/tabcontainer/desktop/hover_first.xml rename to container/testdata/apptabs/desktop/hover_first.xml index 379b9ba1fa..90533fd6c0 100644 --- a/widget/testdata/tabcontainer/desktop/hover_first.xml +++ b/container/testdata/apptabs/desktop/hover_first.xml @@ -1,15 +1,15 @@ - + Text1 - + Test1 - + Test2 diff --git a/widget/testdata/tabcontainer/desktop/hover_none.xml b/container/testdata/apptabs/desktop/hover_none.xml similarity index 75% rename from widget/testdata/tabcontainer/desktop/hover_none.xml rename to container/testdata/apptabs/desktop/hover_none.xml index c658878014..00cdc02f2a 100644 --- a/widget/testdata/tabcontainer/desktop/hover_none.xml +++ b/container/testdata/apptabs/desktop/hover_none.xml @@ -1,14 +1,14 @@ - + Text1 - + Test1 - + Test2 diff --git a/widget/testdata/tabcontainer/desktop/hover_second.xml b/container/testdata/apptabs/desktop/hover_second.xml similarity index 77% rename from widget/testdata/tabcontainer/desktop/hover_second.xml rename to container/testdata/apptabs/desktop/hover_second.xml index 0d5fa6e736..eb4d7a705f 100644 --- a/widget/testdata/tabcontainer/desktop/hover_second.xml +++ b/container/testdata/apptabs/desktop/hover_second.xml @@ -1,14 +1,14 @@ - + Text1 - + Test1 - + Test2 diff --git a/widget/testdata/tabcontainer/desktop/layout_bottom_icon.xml b/container/testdata/apptabs/desktop/layout_bottom_icon.xml similarity index 78% rename from widget/testdata/tabcontainer/desktop/layout_bottom_icon.xml rename to container/testdata/apptabs/desktop/layout_bottom_icon.xml index 2d64f5e468..51c0da57d7 100644 --- a/widget/testdata/tabcontainer/desktop/layout_bottom_icon.xml +++ b/container/testdata/apptabs/desktop/layout_bottom_icon.xml @@ -1,9 +1,9 @@ - + - + diff --git a/widget/testdata/tabcontainer/desktop/layout_bottom_icon_and_text.xml b/container/testdata/apptabs/desktop/layout_bottom_icon_and_text.xml similarity index 81% rename from widget/testdata/tabcontainer/desktop/layout_bottom_icon_and_text.xml rename to container/testdata/apptabs/desktop/layout_bottom_icon_and_text.xml index 821319cbea..f8b0bf0875 100644 --- a/widget/testdata/tabcontainer/desktop/layout_bottom_icon_and_text.xml +++ b/container/testdata/apptabs/desktop/layout_bottom_icon_and_text.xml @@ -1,9 +1,9 @@ - + - + Text1 diff --git a/widget/testdata/tabcontainer/desktop/layout_bottom_text.xml b/container/testdata/apptabs/desktop/layout_bottom_text.xml similarity index 78% rename from widget/testdata/tabcontainer/desktop/layout_bottom_text.xml rename to container/testdata/apptabs/desktop/layout_bottom_text.xml index 8d6c83b4aa..23e5321976 100644 --- a/widget/testdata/tabcontainer/desktop/layout_bottom_text.xml +++ b/container/testdata/apptabs/desktop/layout_bottom_text.xml @@ -1,9 +1,9 @@ - + - + Text2 diff --git a/widget/testdata/tabcontainer/desktop/layout_leading_icon.xml b/container/testdata/apptabs/desktop/layout_leading_icon.xml similarity index 78% rename from widget/testdata/tabcontainer/desktop/layout_leading_icon.xml rename to container/testdata/apptabs/desktop/layout_leading_icon.xml index 94fcd49763..6f0ed4afec 100644 --- a/widget/testdata/tabcontainer/desktop/layout_leading_icon.xml +++ b/container/testdata/apptabs/desktop/layout_leading_icon.xml @@ -1,9 +1,9 @@ - + - + diff --git a/widget/testdata/tabcontainer/desktop/layout_leading_icon_and_text.xml b/container/testdata/apptabs/desktop/layout_leading_icon_and_text.xml similarity index 81% rename from widget/testdata/tabcontainer/desktop/layout_leading_icon_and_text.xml rename to container/testdata/apptabs/desktop/layout_leading_icon_and_text.xml index 2771309118..8d40cdf05a 100644 --- a/widget/testdata/tabcontainer/desktop/layout_leading_icon_and_text.xml +++ b/container/testdata/apptabs/desktop/layout_leading_icon_and_text.xml @@ -1,9 +1,9 @@ - + - + Text1 diff --git a/widget/testdata/tabcontainer/desktop/layout_leading_text.xml b/container/testdata/apptabs/desktop/layout_leading_text.xml similarity index 78% rename from widget/testdata/tabcontainer/desktop/layout_leading_text.xml rename to container/testdata/apptabs/desktop/layout_leading_text.xml index 1dc93bfbe8..43bb505493 100644 --- a/widget/testdata/tabcontainer/desktop/layout_leading_text.xml +++ b/container/testdata/apptabs/desktop/layout_leading_text.xml @@ -1,9 +1,9 @@ - + - + Text2 diff --git a/widget/testdata/tabcontainer/desktop/layout_top_icon.xml b/container/testdata/apptabs/desktop/layout_top_icon.xml similarity index 78% rename from widget/testdata/tabcontainer/desktop/layout_top_icon.xml rename to container/testdata/apptabs/desktop/layout_top_icon.xml index f67b0ade33..e2ab7be294 100644 --- a/widget/testdata/tabcontainer/desktop/layout_top_icon.xml +++ b/container/testdata/apptabs/desktop/layout_top_icon.xml @@ -1,9 +1,9 @@ - + - + diff --git a/widget/testdata/tabcontainer/desktop/layout_top_icon_and_text.xml b/container/testdata/apptabs/desktop/layout_top_icon_and_text.xml similarity index 81% rename from widget/testdata/tabcontainer/desktop/layout_top_icon_and_text.xml rename to container/testdata/apptabs/desktop/layout_top_icon_and_text.xml index bc6a8ae173..8f34687a25 100644 --- a/widget/testdata/tabcontainer/desktop/layout_top_icon_and_text.xml +++ b/container/testdata/apptabs/desktop/layout_top_icon_and_text.xml @@ -1,9 +1,9 @@ - + - + Text1 diff --git a/widget/testdata/tabcontainer/desktop/layout_top_text.xml b/container/testdata/apptabs/desktop/layout_top_text.xml similarity index 78% rename from widget/testdata/tabcontainer/desktop/layout_top_text.xml rename to container/testdata/apptabs/desktop/layout_top_text.xml index 4aaa79828a..d8ca4efb18 100644 --- a/widget/testdata/tabcontainer/desktop/layout_top_text.xml +++ b/container/testdata/apptabs/desktop/layout_top_text.xml @@ -1,9 +1,9 @@ - + - + Text2 diff --git a/widget/testdata/tabcontainer/desktop/layout_trailing_icon.xml b/container/testdata/apptabs/desktop/layout_trailing_icon.xml similarity index 78% rename from widget/testdata/tabcontainer/desktop/layout_trailing_icon.xml rename to container/testdata/apptabs/desktop/layout_trailing_icon.xml index 18f59ac2c9..f9b7db9fff 100644 --- a/widget/testdata/tabcontainer/desktop/layout_trailing_icon.xml +++ b/container/testdata/apptabs/desktop/layout_trailing_icon.xml @@ -1,9 +1,9 @@ - + - + diff --git a/widget/testdata/tabcontainer/desktop/layout_trailing_icon_and_text.xml b/container/testdata/apptabs/desktop/layout_trailing_icon_and_text.xml similarity index 81% rename from widget/testdata/tabcontainer/desktop/layout_trailing_icon_and_text.xml rename to container/testdata/apptabs/desktop/layout_trailing_icon_and_text.xml index fe362da639..59b7c87467 100644 --- a/widget/testdata/tabcontainer/desktop/layout_trailing_icon_and_text.xml +++ b/container/testdata/apptabs/desktop/layout_trailing_icon_and_text.xml @@ -1,9 +1,9 @@ - + - + Text1 diff --git a/widget/testdata/tabcontainer/desktop/layout_trailing_text.xml b/container/testdata/apptabs/desktop/layout_trailing_text.xml similarity index 78% rename from widget/testdata/tabcontainer/desktop/layout_trailing_text.xml rename to container/testdata/apptabs/desktop/layout_trailing_text.xml index e96e020d5e..c99076dcd0 100644 --- a/widget/testdata/tabcontainer/desktop/layout_trailing_text.xml +++ b/container/testdata/apptabs/desktop/layout_trailing_text.xml @@ -1,9 +1,9 @@ - + - + Text2 diff --git a/widget/testdata/tabcontainer/desktop/single_custom_theme.png b/container/testdata/apptabs/desktop/single_custom_theme.png similarity index 100% rename from widget/testdata/tabcontainer/desktop/single_custom_theme.png rename to container/testdata/apptabs/desktop/single_custom_theme.png diff --git a/widget/testdata/tabcontainer/desktop/single_initial.png b/container/testdata/apptabs/desktop/single_initial.png similarity index 100% rename from widget/testdata/tabcontainer/desktop/single_initial.png rename to container/testdata/apptabs/desktop/single_initial.png diff --git a/widget/testdata/tabcontainer/desktop/tab_location_bottom.xml b/container/testdata/apptabs/desktop/tab_location_bottom.xml similarity index 72% rename from widget/testdata/tabcontainer/desktop/tab_location_bottom.xml rename to container/testdata/apptabs/desktop/tab_location_bottom.xml index 044bf0e387..30e263a3f2 100644 --- a/widget/testdata/tabcontainer/desktop/tab_location_bottom.xml +++ b/container/testdata/apptabs/desktop/tab_location_bottom.xml @@ -1,17 +1,17 @@ - + Text 1 - + Test1 - + Test2 - + Test3 diff --git a/widget/testdata/tabcontainer/desktop/tab_location_leading.xml b/container/testdata/apptabs/desktop/tab_location_leading.xml similarity index 72% rename from widget/testdata/tabcontainer/desktop/tab_location_leading.xml rename to container/testdata/apptabs/desktop/tab_location_leading.xml index bce7253613..fd6f863487 100644 --- a/widget/testdata/tabcontainer/desktop/tab_location_leading.xml +++ b/container/testdata/apptabs/desktop/tab_location_leading.xml @@ -1,17 +1,17 @@ - + Text 1 - + Test1 - + Test2 - + Test3 diff --git a/widget/testdata/tabcontainer/desktop/tab_location_top.xml b/container/testdata/apptabs/desktop/tab_location_top.xml similarity index 72% rename from widget/testdata/tabcontainer/desktop/tab_location_top.xml rename to container/testdata/apptabs/desktop/tab_location_top.xml index 42135a4ffd..9254aa733c 100644 --- a/widget/testdata/tabcontainer/desktop/tab_location_top.xml +++ b/container/testdata/apptabs/desktop/tab_location_top.xml @@ -1,17 +1,17 @@ - + Text 1 - + Test1 - + Test2 - + Test3 diff --git a/widget/testdata/tabcontainer/desktop/tab_location_trailing.xml b/container/testdata/apptabs/desktop/tab_location_trailing.xml similarity index 72% rename from widget/testdata/tabcontainer/desktop/tab_location_trailing.xml rename to container/testdata/apptabs/desktop/tab_location_trailing.xml index 2d244f46d6..a5cdf55e4d 100644 --- a/widget/testdata/tabcontainer/desktop/tab_location_trailing.xml +++ b/container/testdata/apptabs/desktop/tab_location_trailing.xml @@ -1,17 +1,17 @@ - + Text 1 - + Test1 - + Test2 - + Test3 diff --git a/widget/testdata/tabcontainer/desktop/tapped_first_selected.xml b/container/testdata/apptabs/desktop/tapped_first_selected.xml similarity index 72% rename from widget/testdata/tabcontainer/desktop/tapped_first_selected.xml rename to container/testdata/apptabs/desktop/tapped_first_selected.xml index 02360cdd4d..41af09bb4b 100644 --- a/widget/testdata/tabcontainer/desktop/tapped_first_selected.xml +++ b/container/testdata/apptabs/desktop/tapped_first_selected.xml @@ -1,17 +1,17 @@ - + Text 1 - + Test1 - + Test2 - + Test3 diff --git a/widget/testdata/tabcontainer/desktop/tapped_second_selected.xml b/container/testdata/apptabs/desktop/tapped_second_selected.xml similarity index 72% rename from widget/testdata/tabcontainer/desktop/tapped_second_selected.xml rename to container/testdata/apptabs/desktop/tapped_second_selected.xml index 20abca3a56..646a0c6e26 100644 --- a/widget/testdata/tabcontainer/desktop/tapped_second_selected.xml +++ b/container/testdata/apptabs/desktop/tapped_second_selected.xml @@ -1,17 +1,17 @@ - + Text 2 - + Test1 - + Test2 - + Test3 diff --git a/widget/testdata/tabcontainer/desktop/tapped_third_selected.xml b/container/testdata/apptabs/desktop/tapped_third_selected.xml similarity index 72% rename from widget/testdata/tabcontainer/desktop/tapped_third_selected.xml rename to container/testdata/apptabs/desktop/tapped_third_selected.xml index a5b1583ee6..1582684498 100644 --- a/widget/testdata/tabcontainer/desktop/tapped_third_selected.xml +++ b/container/testdata/apptabs/desktop/tapped_third_selected.xml @@ -1,17 +1,17 @@ - + Text 3 - + Test1 - + Test2 - + Test3 diff --git a/widget/testdata/tabcontainer/mobile/change_content_change_hidden.xml b/container/testdata/apptabs/mobile/change_content_change_hidden.xml similarity index 75% rename from widget/testdata/tabcontainer/mobile/change_content_change_hidden.xml rename to container/testdata/apptabs/mobile/change_content_change_hidden.xml index b490543e72..1aca7c473b 100644 --- a/widget/testdata/tabcontainer/mobile/change_content_change_hidden.xml +++ b/container/testdata/apptabs/mobile/change_content_change_hidden.xml @@ -1,14 +1,14 @@ - + Text3 - + Test1 - + Test2 diff --git a/widget/testdata/tabcontainer/mobile/change_content_change_visible.xml b/container/testdata/apptabs/mobile/change_content_change_visible.xml similarity index 75% rename from widget/testdata/tabcontainer/mobile/change_content_change_visible.xml rename to container/testdata/apptabs/mobile/change_content_change_visible.xml index b490543e72..1aca7c473b 100644 --- a/widget/testdata/tabcontainer/mobile/change_content_change_visible.xml +++ b/container/testdata/apptabs/mobile/change_content_change_visible.xml @@ -1,14 +1,14 @@ - + Text3 - + Test1 - + Test2 diff --git a/widget/testdata/tabcontainer/mobile/change_content_initial.xml b/container/testdata/apptabs/mobile/change_content_initial.xml similarity index 75% rename from widget/testdata/tabcontainer/mobile/change_content_initial.xml rename to container/testdata/apptabs/mobile/change_content_initial.xml index 0aabe43b21..f84948ef92 100644 --- a/widget/testdata/tabcontainer/mobile/change_content_initial.xml +++ b/container/testdata/apptabs/mobile/change_content_initial.xml @@ -1,14 +1,14 @@ - + Text1 - + Test1 - + Test2 diff --git a/widget/testdata/tabcontainer/mobile/change_icon_change_selected.xml b/container/testdata/apptabs/mobile/change_icon_change_selected.xml similarity index 74% rename from widget/testdata/tabcontainer/mobile/change_icon_change_selected.xml rename to container/testdata/apptabs/mobile/change_icon_change_selected.xml index 54aa08e627..dcafeaa3d4 100644 --- a/widget/testdata/tabcontainer/mobile/change_icon_change_selected.xml +++ b/container/testdata/apptabs/mobile/change_icon_change_selected.xml @@ -1,14 +1,14 @@ - + Text1 - + - + diff --git a/widget/testdata/tabcontainer/mobile/change_icon_change_unselected.xml b/container/testdata/apptabs/mobile/change_icon_change_unselected.xml similarity index 74% rename from widget/testdata/tabcontainer/mobile/change_icon_change_unselected.xml rename to container/testdata/apptabs/mobile/change_icon_change_unselected.xml index 339a49bb5c..c29619ca6d 100644 --- a/widget/testdata/tabcontainer/mobile/change_icon_change_unselected.xml +++ b/container/testdata/apptabs/mobile/change_icon_change_unselected.xml @@ -1,14 +1,14 @@ - + Text1 - + - + diff --git a/widget/testdata/tabcontainer/mobile/change_icon_initial.xml b/container/testdata/apptabs/mobile/change_icon_initial.xml similarity index 74% rename from widget/testdata/tabcontainer/mobile/change_icon_initial.xml rename to container/testdata/apptabs/mobile/change_icon_initial.xml index eeba3e9c28..76f2dd6b23 100644 --- a/widget/testdata/tabcontainer/mobile/change_icon_initial.xml +++ b/container/testdata/apptabs/mobile/change_icon_initial.xml @@ -1,14 +1,14 @@ - + Text1 - + - + diff --git a/widget/testdata/tabcontainer/mobile/change_label_change_selected.xml b/container/testdata/apptabs/mobile/change_label_change_selected.xml similarity index 75% rename from widget/testdata/tabcontainer/mobile/change_label_change_selected.xml rename to container/testdata/apptabs/mobile/change_label_change_selected.xml index 9e952e615e..37771f7182 100644 --- a/widget/testdata/tabcontainer/mobile/change_label_change_selected.xml +++ b/container/testdata/apptabs/mobile/change_label_change_selected.xml @@ -1,14 +1,14 @@ - + Text1 - + New 1 - + Test2 diff --git a/widget/testdata/tabcontainer/mobile/change_label_change_unselected.xml b/container/testdata/apptabs/mobile/change_label_change_unselected.xml similarity index 75% rename from widget/testdata/tabcontainer/mobile/change_label_change_unselected.xml rename to container/testdata/apptabs/mobile/change_label_change_unselected.xml index 81bd385e25..373c8461fb 100644 --- a/widget/testdata/tabcontainer/mobile/change_label_change_unselected.xml +++ b/container/testdata/apptabs/mobile/change_label_change_unselected.xml @@ -1,14 +1,14 @@ - + Text1 - + New 1 - + New 2 diff --git a/widget/testdata/tabcontainer/mobile/change_label_initial.xml b/container/testdata/apptabs/mobile/change_label_initial.xml similarity index 75% rename from widget/testdata/tabcontainer/mobile/change_label_initial.xml rename to container/testdata/apptabs/mobile/change_label_initial.xml index 0aabe43b21..f84948ef92 100644 --- a/widget/testdata/tabcontainer/mobile/change_label_initial.xml +++ b/container/testdata/apptabs/mobile/change_label_initial.xml @@ -1,14 +1,14 @@ - + Text1 - + Test1 - + Test2 diff --git a/widget/testdata/tabcontainer/mobile/dynamic_appended.xml b/container/testdata/apptabs/mobile/dynamic_appended.xml similarity index 75% rename from widget/testdata/tabcontainer/mobile/dynamic_appended.xml rename to container/testdata/apptabs/mobile/dynamic_appended.xml index 6609238554..b5f09e2458 100644 --- a/widget/testdata/tabcontainer/mobile/dynamic_appended.xml +++ b/container/testdata/apptabs/mobile/dynamic_appended.xml @@ -1,14 +1,14 @@ - + Text 1 - + Test1 - + Test2 diff --git a/widget/testdata/tabcontainer/mobile/dynamic_appended_and_removed.xml b/container/testdata/apptabs/mobile/dynamic_appended_and_removed.xml similarity index 80% rename from widget/testdata/tabcontainer/mobile/dynamic_appended_and_removed.xml rename to container/testdata/apptabs/mobile/dynamic_appended_and_removed.xml index b9fb6b4c83..e4793b66e4 100644 --- a/widget/testdata/tabcontainer/mobile/dynamic_appended_and_removed.xml +++ b/container/testdata/apptabs/mobile/dynamic_appended_and_removed.xml @@ -1,11 +1,11 @@ - + Text 2 - + Test2 diff --git a/widget/testdata/tabcontainer/mobile/dynamic_appended_another_three.xml b/container/testdata/apptabs/mobile/dynamic_appended_another_three.xml similarity index 70% rename from widget/testdata/tabcontainer/mobile/dynamic_appended_another_three.xml rename to container/testdata/apptabs/mobile/dynamic_appended_another_three.xml index 4dc346e876..05a34e4db3 100644 --- a/widget/testdata/tabcontainer/mobile/dynamic_appended_another_three.xml +++ b/container/testdata/apptabs/mobile/dynamic_appended_another_three.xml @@ -1,20 +1,20 @@ - + Text 2 - + Test2 - + Test3 - + Test4 - + Test5 diff --git a/widget/testdata/tabcontainer/mobile/dynamic_initial.xml b/container/testdata/apptabs/mobile/dynamic_initial.xml similarity index 80% rename from widget/testdata/tabcontainer/mobile/dynamic_initial.xml rename to container/testdata/apptabs/mobile/dynamic_initial.xml index a522576416..f0d5e67dbc 100644 --- a/widget/testdata/tabcontainer/mobile/dynamic_initial.xml +++ b/container/testdata/apptabs/mobile/dynamic_initial.xml @@ -1,11 +1,11 @@ - + Text 1 - + Test1 diff --git a/widget/testdata/tabcontainer/mobile/dynamic_replaced_completely.xml b/container/testdata/apptabs/mobile/dynamic_replaced_completely.xml similarity index 72% rename from widget/testdata/tabcontainer/mobile/dynamic_replaced_completely.xml rename to container/testdata/apptabs/mobile/dynamic_replaced_completely.xml index c856e6447a..7465c2f5fc 100644 --- a/widget/testdata/tabcontainer/mobile/dynamic_replaced_completely.xml +++ b/container/testdata/apptabs/mobile/dynamic_replaced_completely.xml @@ -1,17 +1,17 @@ - + Text 6 - + Test6 - + Test7 - + Test8 diff --git a/widget/testdata/tabcontainer/mobile/hover_none.xml b/container/testdata/apptabs/mobile/hover_none.xml similarity index 75% rename from widget/testdata/tabcontainer/mobile/hover_none.xml rename to container/testdata/apptabs/mobile/hover_none.xml index 0aabe43b21..f84948ef92 100644 --- a/widget/testdata/tabcontainer/mobile/hover_none.xml +++ b/container/testdata/apptabs/mobile/hover_none.xml @@ -1,14 +1,14 @@ - + Text1 - + Test1 - + Test2 diff --git a/widget/testdata/tabcontainer/mobile/layout_bottom_ico.xml b/container/testdata/apptabs/mobile/layout_bottom_ico.xml similarity index 77% rename from widget/testdata/tabcontainer/mobile/layout_bottom_ico.xml rename to container/testdata/apptabs/mobile/layout_bottom_ico.xml index f559f4aca3..9bfe21d353 100644 --- a/widget/testdata/tabcontainer/mobile/layout_bottom_ico.xml +++ b/container/testdata/apptabs/mobile/layout_bottom_ico.xml @@ -1,9 +1,9 @@ - + - + diff --git a/widget/testdata/tabcontainer/mobile/layout_bottom_icon.xml b/container/testdata/apptabs/mobile/layout_bottom_icon.xml similarity index 77% rename from widget/testdata/tabcontainer/mobile/layout_bottom_icon.xml rename to container/testdata/apptabs/mobile/layout_bottom_icon.xml index f559f4aca3..9bfe21d353 100644 --- a/widget/testdata/tabcontainer/mobile/layout_bottom_icon.xml +++ b/container/testdata/apptabs/mobile/layout_bottom_icon.xml @@ -1,9 +1,9 @@ - + - + diff --git a/widget/testdata/tabcontainer/mobile/layout_bottom_icon_and_text.xml b/container/testdata/apptabs/mobile/layout_bottom_icon_and_text.xml similarity index 81% rename from widget/testdata/tabcontainer/mobile/layout_bottom_icon_and_text.xml rename to container/testdata/apptabs/mobile/layout_bottom_icon_and_text.xml index b564841495..2e6415c7bb 100644 --- a/widget/testdata/tabcontainer/mobile/layout_bottom_icon_and_text.xml +++ b/container/testdata/apptabs/mobile/layout_bottom_icon_and_text.xml @@ -1,9 +1,9 @@ - + - + Text1 diff --git a/widget/testdata/tabcontainer/mobile/layout_bottom_text.xml b/container/testdata/apptabs/mobile/layout_bottom_text.xml similarity index 78% rename from widget/testdata/tabcontainer/mobile/layout_bottom_text.xml rename to container/testdata/apptabs/mobile/layout_bottom_text.xml index 237a39f878..8e160a5a17 100644 --- a/widget/testdata/tabcontainer/mobile/layout_bottom_text.xml +++ b/container/testdata/apptabs/mobile/layout_bottom_text.xml @@ -1,9 +1,9 @@ - + - + Text2 diff --git a/widget/testdata/tabcontainer/mobile/layout_top_icon.xml b/container/testdata/apptabs/mobile/layout_top_icon.xml similarity index 77% rename from widget/testdata/tabcontainer/mobile/layout_top_icon.xml rename to container/testdata/apptabs/mobile/layout_top_icon.xml index 3013315f1b..59623f977d 100644 --- a/widget/testdata/tabcontainer/mobile/layout_top_icon.xml +++ b/container/testdata/apptabs/mobile/layout_top_icon.xml @@ -1,9 +1,9 @@ - + - + diff --git a/widget/testdata/tabcontainer/mobile/layout_top_icon_and_text.xml b/container/testdata/apptabs/mobile/layout_top_icon_and_text.xml similarity index 81% rename from widget/testdata/tabcontainer/mobile/layout_top_icon_and_text.xml rename to container/testdata/apptabs/mobile/layout_top_icon_and_text.xml index 8551dc7946..69678f0a5a 100644 --- a/widget/testdata/tabcontainer/mobile/layout_top_icon_and_text.xml +++ b/container/testdata/apptabs/mobile/layout_top_icon_and_text.xml @@ -1,9 +1,9 @@ - + - + Text1 diff --git a/widget/testdata/tabcontainer/mobile/layout_top_text.xml b/container/testdata/apptabs/mobile/layout_top_text.xml similarity index 78% rename from widget/testdata/tabcontainer/mobile/layout_top_text.xml rename to container/testdata/apptabs/mobile/layout_top_text.xml index 2b70989652..d7af8c568a 100644 --- a/widget/testdata/tabcontainer/mobile/layout_top_text.xml +++ b/container/testdata/apptabs/mobile/layout_top_text.xml @@ -1,9 +1,9 @@ - + - + Text2 diff --git a/widget/testdata/tabcontainer/mobile/single_custom_theme.png b/container/testdata/apptabs/mobile/single_custom_theme.png similarity index 100% rename from widget/testdata/tabcontainer/mobile/single_custom_theme.png rename to container/testdata/apptabs/mobile/single_custom_theme.png diff --git a/widget/testdata/tabcontainer/mobile/single_dark.png b/container/testdata/apptabs/mobile/single_dark.png similarity index 100% rename from widget/testdata/tabcontainer/mobile/single_dark.png rename to container/testdata/apptabs/mobile/single_dark.png diff --git a/widget/testdata/tabcontainer/mobile/single_initial.png b/container/testdata/apptabs/mobile/single_initial.png similarity index 100% rename from widget/testdata/tabcontainer/mobile/single_initial.png rename to container/testdata/apptabs/mobile/single_initial.png diff --git a/widget/testdata/tabcontainer/mobile/tab_location_bottom.xml b/container/testdata/apptabs/mobile/tab_location_bottom.xml similarity index 72% rename from widget/testdata/tabcontainer/mobile/tab_location_bottom.xml rename to container/testdata/apptabs/mobile/tab_location_bottom.xml index dd916fc326..324c304df1 100644 --- a/widget/testdata/tabcontainer/mobile/tab_location_bottom.xml +++ b/container/testdata/apptabs/mobile/tab_location_bottom.xml @@ -1,17 +1,17 @@ - + Text 1 - + Test1 - + Test2 - + Test3 diff --git a/widget/testdata/tabcontainer/mobile/tab_location_top.xml b/container/testdata/apptabs/mobile/tab_location_top.xml similarity index 72% rename from widget/testdata/tabcontainer/mobile/tab_location_top.xml rename to container/testdata/apptabs/mobile/tab_location_top.xml index 9ecf3991d9..13b8e15c83 100644 --- a/widget/testdata/tabcontainer/mobile/tab_location_top.xml +++ b/container/testdata/apptabs/mobile/tab_location_top.xml @@ -1,17 +1,17 @@ - + Text 1 - + Test1 - + Test2 - + Test3 diff --git a/widget/testdata/tabcontainer/mobile/tapped_first_selected.xml b/container/testdata/apptabs/mobile/tapped_first_selected.xml similarity index 72% rename from widget/testdata/tabcontainer/mobile/tapped_first_selected.xml rename to container/testdata/apptabs/mobile/tapped_first_selected.xml index 33a93d4996..7100d0e2f8 100644 --- a/widget/testdata/tabcontainer/mobile/tapped_first_selected.xml +++ b/container/testdata/apptabs/mobile/tapped_first_selected.xml @@ -1,17 +1,17 @@ - + Text 1 - + Test1 - + Test2 - + Test3 diff --git a/widget/testdata/tabcontainer/mobile/tapped_second_selected.xml b/container/testdata/apptabs/mobile/tapped_second_selected.xml similarity index 72% rename from widget/testdata/tabcontainer/mobile/tapped_second_selected.xml rename to container/testdata/apptabs/mobile/tapped_second_selected.xml index 1bace5ac5e..b8d4f953f3 100644 --- a/widget/testdata/tabcontainer/mobile/tapped_second_selected.xml +++ b/container/testdata/apptabs/mobile/tapped_second_selected.xml @@ -1,17 +1,17 @@ - + Text 2 - + Test1 - + Test2 - + Test3 diff --git a/widget/testdata/tabcontainer/mobile/tapped_third_selected.xml b/container/testdata/apptabs/mobile/tapped_third_selected.xml similarity index 72% rename from widget/testdata/tabcontainer/mobile/tapped_third_selected.xml rename to container/testdata/apptabs/mobile/tapped_third_selected.xml index a7eedbb707..067976f045 100644 --- a/widget/testdata/tabcontainer/mobile/tapped_third_selected.xml +++ b/container/testdata/apptabs/mobile/tapped_third_selected.xml @@ -1,17 +1,17 @@ - + Text 3 - + Test1 - + Test2 - + Test3 diff --git a/container/testdata/apptabs/mobile/theme_default.png b/container/testdata/apptabs/mobile/theme_default.png new file mode 100644 index 0000000000..6a60930a41 Binary files /dev/null and b/container/testdata/apptabs/mobile/theme_default.png differ diff --git a/widget/testdata/tabcontainer/mobile/theme_ugly.png b/container/testdata/apptabs/mobile/theme_ugly.png similarity index 100% rename from widget/testdata/tabcontainer/mobile/theme_ugly.png rename to container/testdata/apptabs/mobile/theme_ugly.png diff --git a/data/binding/binding.go b/data/binding/binding.go index 4aee1c96a0..8e1547870f 100644 --- a/data/binding/binding.go +++ b/data/binding/binding.go @@ -6,7 +6,7 @@ import ( "errors" "sync" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) var ( @@ -21,7 +21,7 @@ var ( // DataItem is the base interface for all bindable data items. // -// Since: 2.0.0 +// Since: 2.0 type DataItem interface { // AddListener attaches a new change listener to this DataItem. // Listeners are called each time the data inside this DataItem changes. @@ -35,14 +35,14 @@ type DataItem interface { // DataListener is any object that can register for changes in a bindable DataItem. // See NewDataListener to define a new listener using just an inline function. // -// Since: 2.0.0 +// Since: 2.0 type DataListener interface { DataChanged() } // NewDataListener is a helper function that creates a new listener type from a simple callback function. // -// Since: 2.0.0 +// Since: 2.0 func NewDataListener(fn func()) DataListener { return &listener{fn} } diff --git a/data/binding/binditems.go b/data/binding/binditems.go index 585f89f0fe..b10b8a8b60 100644 --- a/data/binding/binditems.go +++ b/data/binding/binditems.go @@ -5,7 +5,7 @@ package binding // Bool supports binding a bool value. // -// Since: 2.0.0 +// Since: 2.0 type Bool interface { DataItem Get() (bool, error) @@ -14,7 +14,7 @@ type Bool interface { // ExternalBool supports binding a bool value to an external value. // -// Since: 2.0.0 +// Since: 2.0 type ExternalBool interface { Bool Reload() error @@ -22,7 +22,7 @@ type ExternalBool interface { // NewBool returns a bindable bool value that is managed internally. // -// Since: 2.0.0 +// Since: 2.0 func NewBool() Bool { blank := false return &boundBool{val: &blank} @@ -31,7 +31,7 @@ func NewBool() Bool { // BindBool returns a new bindable value that controls the contents of the provided bool variable. // If your code changes the content of the variable this refers to you should call Reload() to inform the bindings. // -// Since: 2.0.0 +// Since: 2.0 func BindBool(v *bool) ExternalBool { if v == nil { return NewBool().(ExternalBool) // never allow a nil value pointer @@ -71,7 +71,7 @@ func (b *boundBool) Set(val bool) error { // Float supports binding a float64 value. // -// Since: 2.0.0 +// Since: 2.0 type Float interface { DataItem Get() (float64, error) @@ -80,7 +80,7 @@ type Float interface { // ExternalFloat supports binding a float64 value to an external value. // -// Since: 2.0.0 +// Since: 2.0 type ExternalFloat interface { Float Reload() error @@ -88,7 +88,7 @@ type ExternalFloat interface { // NewFloat returns a bindable float64 value that is managed internally. // -// Since: 2.0.0 +// Since: 2.0 func NewFloat() Float { blank := 0.0 return &boundFloat{val: &blank} @@ -97,7 +97,7 @@ func NewFloat() Float { // BindFloat returns a new bindable value that controls the contents of the provided float64 variable. // If your code changes the content of the variable this refers to you should call Reload() to inform the bindings. // -// Since: 2.0.0 +// Since: 2.0 func BindFloat(v *float64) ExternalFloat { if v == nil { return NewFloat().(ExternalFloat) // never allow a nil value pointer @@ -137,7 +137,7 @@ func (b *boundFloat) Set(val float64) error { // Int supports binding a int value. // -// Since: 2.0.0 +// Since: 2.0 type Int interface { DataItem Get() (int, error) @@ -146,7 +146,7 @@ type Int interface { // ExternalInt supports binding a int value to an external value. // -// Since: 2.0.0 +// Since: 2.0 type ExternalInt interface { Int Reload() error @@ -154,7 +154,7 @@ type ExternalInt interface { // NewInt returns a bindable int value that is managed internally. // -// Since: 2.0.0 +// Since: 2.0 func NewInt() Int { blank := 0 return &boundInt{val: &blank} @@ -163,7 +163,7 @@ func NewInt() Int { // BindInt returns a new bindable value that controls the contents of the provided int variable. // If your code changes the content of the variable this refers to you should call Reload() to inform the bindings. // -// Since: 2.0.0 +// Since: 2.0 func BindInt(v *int) ExternalInt { if v == nil { return NewInt().(ExternalInt) // never allow a nil value pointer @@ -203,7 +203,7 @@ func (b *boundInt) Set(val int) error { // Rune supports binding a rune value. // -// Since: 2.0.0 +// Since: 2.0 type Rune interface { DataItem Get() (rune, error) @@ -212,7 +212,7 @@ type Rune interface { // ExternalRune supports binding a rune value to an external value. // -// Since: 2.0.0 +// Since: 2.0 type ExternalRune interface { Rune Reload() error @@ -220,7 +220,7 @@ type ExternalRune interface { // NewRune returns a bindable rune value that is managed internally. // -// Since: 2.0.0 +// Since: 2.0 func NewRune() Rune { blank := rune(0) return &boundRune{val: &blank} @@ -229,7 +229,7 @@ func NewRune() Rune { // BindRune returns a new bindable value that controls the contents of the provided rune variable. // If your code changes the content of the variable this refers to you should call Reload() to inform the bindings. // -// Since: 2.0.0 +// Since: 2.0 func BindRune(v *rune) ExternalRune { if v == nil { return NewRune().(ExternalRune) // never allow a nil value pointer @@ -269,7 +269,7 @@ func (b *boundRune) Set(val rune) error { // String supports binding a string value. // -// Since: 2.0.0 +// Since: 2.0 type String interface { DataItem Get() (string, error) @@ -278,7 +278,7 @@ type String interface { // ExternalString supports binding a string value to an external value. // -// Since: 2.0.0 +// Since: 2.0 type ExternalString interface { String Reload() error @@ -286,7 +286,7 @@ type ExternalString interface { // NewString returns a bindable string value that is managed internally. // -// Since: 2.0.0 +// Since: 2.0 func NewString() String { blank := "" return &boundString{val: &blank} @@ -295,7 +295,7 @@ func NewString() String { // BindString returns a new bindable value that controls the contents of the provided string variable. // If your code changes the content of the variable this refers to you should call Reload() to inform the bindings. // -// Since: 2.0.0 +// Since: 2.0 func BindString(v *string) ExternalString { if v == nil { return NewString().(ExternalString) // never allow a nil value pointer diff --git a/data/binding/bindlists.go b/data/binding/bindlists.go index ea33eabac6..df569dfad7 100644 --- a/data/binding/bindlists.go +++ b/data/binding/bindlists.go @@ -5,7 +5,7 @@ package binding // BoolList supports binding a list of bool values. // -// Since: 2.0.0 +// Since: 2.0 type BoolList interface { DataList @@ -19,7 +19,7 @@ type BoolList interface { // ExternalBoolList supports binding a list of bool values from an external variable. // -// Since: 2.0.0 +// Since: 2.0 type ExternalBoolList interface { BoolList @@ -28,7 +28,7 @@ type ExternalBoolList interface { // NewBoolList returns a bindable list of bool values. // -// Since: 2.0.0 +// Since: 2.0 func NewBoolList() BoolList { return &boundBoolList{val: &[]bool{}} } @@ -36,7 +36,7 @@ func NewBoolList() BoolList { // BindBoolList returns a bound list of bool values, based on the contents of the passed slice. // If your code changes the content of the slice this refers to you should call Reload() to inform the bindings. // -// Since: 2.0.0 +// Since: 2.0 func BindBoolList(v *[]bool) ExternalBoolList { if v == nil { return NewBoolList().(ExternalBoolList) @@ -218,7 +218,7 @@ func (b *boundExternalBoolListItem) setIfChanged(val bool) error { // FloatList supports binding a list of float64 values. // -// Since: 2.0.0 +// Since: 2.0 type FloatList interface { DataList @@ -232,7 +232,7 @@ type FloatList interface { // ExternalFloatList supports binding a list of float64 values from an external variable. // -// Since: 2.0.0 +// Since: 2.0 type ExternalFloatList interface { FloatList @@ -241,7 +241,7 @@ type ExternalFloatList interface { // NewFloatList returns a bindable list of float64 values. // -// Since: 2.0.0 +// Since: 2.0 func NewFloatList() FloatList { return &boundFloatList{val: &[]float64{}} } @@ -249,7 +249,7 @@ func NewFloatList() FloatList { // BindFloatList returns a bound list of float64 values, based on the contents of the passed slice. // If your code changes the content of the slice this refers to you should call Reload() to inform the bindings. // -// Since: 2.0.0 +// Since: 2.0 func BindFloatList(v *[]float64) ExternalFloatList { if v == nil { return NewFloatList().(ExternalFloatList) @@ -431,7 +431,7 @@ func (b *boundExternalFloatListItem) setIfChanged(val float64) error { // IntList supports binding a list of int values. // -// Since: 2.0.0 +// Since: 2.0 type IntList interface { DataList @@ -445,7 +445,7 @@ type IntList interface { // ExternalIntList supports binding a list of int values from an external variable. // -// Since: 2.0.0 +// Since: 2.0 type ExternalIntList interface { IntList @@ -454,7 +454,7 @@ type ExternalIntList interface { // NewIntList returns a bindable list of int values. // -// Since: 2.0.0 +// Since: 2.0 func NewIntList() IntList { return &boundIntList{val: &[]int{}} } @@ -462,7 +462,7 @@ func NewIntList() IntList { // BindIntList returns a bound list of int values, based on the contents of the passed slice. // If your code changes the content of the slice this refers to you should call Reload() to inform the bindings. // -// Since: 2.0.0 +// Since: 2.0 func BindIntList(v *[]int) ExternalIntList { if v == nil { return NewIntList().(ExternalIntList) @@ -644,7 +644,7 @@ func (b *boundExternalIntListItem) setIfChanged(val int) error { // RuneList supports binding a list of rune values. // -// Since: 2.0.0 +// Since: 2.0 type RuneList interface { DataList @@ -658,7 +658,7 @@ type RuneList interface { // ExternalRuneList supports binding a list of rune values from an external variable. // -// Since: 2.0.0 +// Since: 2.0 type ExternalRuneList interface { RuneList @@ -667,7 +667,7 @@ type ExternalRuneList interface { // NewRuneList returns a bindable list of rune values. // -// Since: 2.0.0 +// Since: 2.0 func NewRuneList() RuneList { return &boundRuneList{val: &[]rune{}} } @@ -675,7 +675,7 @@ func NewRuneList() RuneList { // BindRuneList returns a bound list of rune values, based on the contents of the passed slice. // If your code changes the content of the slice this refers to you should call Reload() to inform the bindings. // -// Since: 2.0.0 +// Since: 2.0 func BindRuneList(v *[]rune) ExternalRuneList { if v == nil { return NewRuneList().(ExternalRuneList) @@ -857,7 +857,7 @@ func (b *boundExternalRuneListItem) setIfChanged(val rune) error { // StringList supports binding a list of string values. // -// Since: 2.0.0 +// Since: 2.0 type StringList interface { DataList @@ -871,7 +871,7 @@ type StringList interface { // ExternalStringList supports binding a list of string values from an external variable. // -// Since: 2.0.0 +// Since: 2.0 type ExternalStringList interface { StringList @@ -880,7 +880,7 @@ type ExternalStringList interface { // NewStringList returns a bindable list of string values. // -// Since: 2.0.0 +// Since: 2.0 func NewStringList() StringList { return &boundStringList{val: &[]string{}} } @@ -888,7 +888,7 @@ func NewStringList() StringList { // BindStringList returns a bound list of string values, based on the contents of the passed slice. // If your code changes the content of the slice this refers to you should call Reload() to inform the bindings. // -// Since: 2.0.0 +// Since: 2.0 func BindStringList(v *[]string) ExternalStringList { if v == nil { return NewStringList().(ExternalStringList) diff --git a/data/binding/convert.go b/data/binding/convert.go index 8abafbf171..2151e0e306 100644 --- a/data/binding/convert.go +++ b/data/binding/convert.go @@ -18,7 +18,7 @@ type stringFromBool struct { // Changes to the Bool will be pushed to the String and setting the string will parse and set the // Bool if the parse was successful. // -// Since: 2.0.0 +// Since: 2.0 func BoolToString(v Bool) String { return BoolToStringWithFormat(v, "%t") } @@ -27,7 +27,7 @@ func BoolToString(v Bool) String { // presented using the specified format. Changes to the Bool will be pushed to the String and setting // the string will parse and set the Bool if the string matches the format and its parse was successful. // -// Since: 2.0.0 +// Since: 2.0 func BoolToStringWithFormat(v Bool, format string) String { str := &stringFromBool{from: v, format: format} v.AddListener(str) @@ -85,7 +85,7 @@ type stringFromFloat struct { // Changes to the Float will be pushed to the String and setting the string will parse and set the // Float if the parse was successful. // -// Since: 2.0.0 +// Since: 2.0 func FloatToString(v Float) String { return FloatToStringWithFormat(v, "%f") } @@ -94,7 +94,7 @@ func FloatToString(v Float) String { // presented using the specified format. Changes to the Float will be pushed to the String and setting // the string will parse and set the Float if the string matches the format and its parse was successful. // -// Since: 2.0.0 +// Since: 2.0 func FloatToStringWithFormat(v Float, format string) String { str := &stringFromFloat{from: v, format: format} v.AddListener(str) @@ -152,7 +152,7 @@ type stringFromInt struct { // Changes to the Int will be pushed to the String and setting the string will parse and set the // Int if the parse was successful. // -// Since: 2.0.0 +// Since: 2.0 func IntToString(v Int) String { return IntToStringWithFormat(v, "%d") } @@ -161,7 +161,7 @@ func IntToString(v Int) String { // presented using the specified format. Changes to the Int will be pushed to the String and setting // the string will parse and set the Int if the string matches the format and its parse was successful. // -// Since: 2.0.0 +// Since: 2.0 func IntToStringWithFormat(v Int, format string) String { str := &stringFromInt{from: v, format: format} v.AddListener(str) @@ -219,7 +219,7 @@ type stringToBool struct { // Changes to the String will be parsed and pushed to the Bool if the parse was successful, and setting // the Bool update the String binding. // -// Since: 2.0.0 +// Since: 2.0 func StringToBool(str String) Bool { return StringToBoolWithFormat(str, "%t") } @@ -229,7 +229,7 @@ func StringToBool(str String) Bool { // the parse is successful it will be pushed to the String. Setting the Bool will push a formatted value // into the String. // -// Since: 2.0.0 +// Since: 2.0 func StringToBoolWithFormat(str String, format string) Bool { v := &stringToBool{from: str, format: format} str.AddListener(v) @@ -286,7 +286,7 @@ type stringToFloat struct { // Changes to the String will be parsed and pushed to the Float if the parse was successful, and setting // the Float update the String binding. // -// Since: 2.0.0 +// Since: 2.0 func StringToFloat(str String) Float { return StringToFloatWithFormat(str, "%f") } @@ -296,7 +296,7 @@ func StringToFloat(str String) Float { // the parse is successful it will be pushed to the String. Setting the Float will push a formatted value // into the String. // -// Since: 2.0.0 +// Since: 2.0 func StringToFloatWithFormat(str String, format string) Float { v := &stringToFloat{from: str, format: format} str.AddListener(v) @@ -353,7 +353,7 @@ type stringToInt struct { // Changes to the String will be parsed and pushed to the Int if the parse was successful, and setting // the Int update the String binding. // -// Since: 2.0.0 +// Since: 2.0 func StringToInt(str String) Int { return StringToIntWithFormat(str, "%d") } @@ -363,7 +363,7 @@ func StringToInt(str String) Int { // the parse is successful it will be pushed to the String. Setting the Int will push a formatted value // into the String. // -// Since: 2.0.0 +// Since: 2.0 func StringToIntWithFormat(str String, format string) Int { v := &stringToInt{from: str, format: format} str.AddListener(v) diff --git a/data/binding/gen.go b/data/binding/gen.go index 2b0565381e..f5040fa3eb 100644 --- a/data/binding/gen.go +++ b/data/binding/gen.go @@ -8,13 +8,13 @@ import ( "runtime" "text/template" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) const itemBindTemplate = ` // {{ .Name }} supports binding a {{ .Type }} value. // -// Since: 2.0.0 +// Since: 2.0 type {{ .Name }} interface { DataItem Get() ({{ .Type }}, error) @@ -23,7 +23,7 @@ type {{ .Name }} interface { // External{{ .Name }} supports binding a {{ .Type }} value to an external value. // -// Since: 2.0.0 +// Since: 2.0 type External{{ .Name }} interface { {{ .Name }} Reload() error @@ -31,7 +31,7 @@ type External{{ .Name }} interface { // New{{ .Name }} returns a bindable {{ .Type }} value that is managed internally. // -// Since: 2.0.0 +// Since: 2.0 func New{{ .Name }}() {{ .Name }} { blank := {{ .Default }} return &bound{{ .Name }}{val: &blank} @@ -40,7 +40,7 @@ func New{{ .Name }}() {{ .Name }} { // Bind{{ .Name }} returns a new bindable value that controls the contents of the provided {{ .Type }} variable. // If your code changes the content of the variable this refers to you should call Reload() to inform the bindings. // -// Since: 2.0.0 +// Since: 2.0 func Bind{{ .Name }}(v *{{ .Type }}) External{{ .Name }} { if v == nil { return New{{ .Name }}().(External{{ .Name }}) // never allow a nil value pointer @@ -90,7 +90,7 @@ type prefBound{{ .Name }} struct { // BindPreference{{ .Name }} returns a bindable {{ .Type }} value that is managed by the application preferences. // Changes to this value will be saved to application storage and when the app starts the previous values will be read. // -// Since: 2.0.0 +// Since: 2.0 func BindPreference{{ .Name }}(key string, p fyne.Preferences) {{ .Name }} { if prefBinds[p] != nil { if listen, ok := prefBinds[p][key]; ok { @@ -142,7 +142,7 @@ type stringFrom{{ .Name }} struct { // Changes to the {{ .Name }} will be pushed to the String and setting the string will parse and set the // {{ .Name }} if the parse was successful. // -// Since: 2.0.0 +// Since: 2.0 func {{ .Name }}ToString(v {{ .Name }}) String { return {{ .Name }}ToStringWithFormat(v, "{{ .Format }}") } @@ -151,7 +151,7 @@ func {{ .Name }}ToString(v {{ .Name }}) String { // presented using the specified format. Changes to the {{ .Name }} will be pushed to the String and setting // the string will parse and set the {{ .Name }} if the string matches the format and its parse was successful. // -// Since: 2.0.0 +// Since: 2.0 func {{ .Name }}ToStringWithFormat(v {{ .Name }}, format string) String { str := &stringFrom{{ .Name }}{from: v, format: format} v.AddListener(str) @@ -211,7 +211,7 @@ type stringTo{{ .Name }} struct { // Changes to the String will be parsed and pushed to the {{ .Name }} if the parse was successful, and setting // the {{ .Name }} update the String binding. // -// Since: 2.0.0 +// Since: 2.0 func StringTo{{ .Name }}(str String) {{ .Name }} { return StringTo{{ .Name }}WithFormat(str, "{{ .Format }}") } @@ -221,7 +221,7 @@ func StringTo{{ .Name }}(str String) {{ .Name }} { // the parse is successful it will be pushed to the String. Setting the {{ .Name }} will push a formatted value // into the String. // -// Since: 2.0.0 +// Since: 2.0 func StringTo{{ .Name }}WithFormat(str String, format string) {{ .Name }} { v := &stringTo{{ .Name }}{from: str, format: format} str.AddListener(v) @@ -271,7 +271,7 @@ func (s *stringTo{{ .Name }}) DataChanged() { const listBindTemplate = ` // {{ .Name }}List supports binding a list of {{ .Type }} values. // -// Since: 2.0.0 +// Since: 2.0 type {{ .Name }}List interface { DataList @@ -285,7 +285,7 @@ type {{ .Name }}List interface { // External{{ .Name }}List supports binding a list of {{ .Type }} values from an external variable. // -// Since: 2.0.0 +// Since: 2.0 type External{{ .Name }}List interface { {{ .Name }}List @@ -294,7 +294,7 @@ type External{{ .Name }}List interface { // New{{ .Name }}List returns a bindable list of {{ .Type }} values. // -// Since: 2.0.0 +// Since: 2.0 func New{{ .Name }}List() {{ .Name }}List { return &bound{{ .Name }}List{val: &[]{{ .Type }}{}} } @@ -302,7 +302,7 @@ func New{{ .Name }}List() {{ .Name }}List { // Bind{{ .Name }}List returns a bound list of {{ .Type }} values, based on the contents of the passed slice. // If your code changes the content of the slice this refers to you should call Reload() to inform the bindings. // -// Since: 2.0.0 +// Since: 2.0 func Bind{{ .Name }}List(v *[]{{ .Type }}) External{{ .Name }}List { if v == nil { return New{{ .Name }}List().(External{{ .Name }}List) @@ -535,7 +535,7 @@ import ( } defer prefFile.Close() prefFile.WriteString(` -import "fyne.io/fyne" +import "fyne.io/fyne/v2" const keyTypeMismatchError = "A previous preference binding exists with different type for key: " `) diff --git a/data/binding/listbinding.go b/data/binding/listbinding.go index f46b97f7d6..dfcffc937c 100644 --- a/data/binding/listbinding.go +++ b/data/binding/listbinding.go @@ -2,7 +2,7 @@ package binding // DataList is the base interface for all bindable data lists. // -// Since: 2.0.0 +// Since: 2.0 type DataList interface { DataItem GetItem(int) (DataItem, error) diff --git a/data/binding/mapbinding.go b/data/binding/mapbinding.go index e18dee34b0..c7c400f6ff 100644 --- a/data/binding/mapbinding.go +++ b/data/binding/mapbinding.go @@ -4,12 +4,12 @@ import ( "errors" "reflect" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // DataMap is the base interface for all bindable data maps. // -// Since: 2.0.0 +// Since: 2.0 type DataMap interface { DataItem GetItem(string) (DataItem, error) @@ -18,7 +18,7 @@ type DataMap interface { // ExternalUntypedMap is a map data binding with all values untyped (interface{}), connected to an external data source. // -// Since: 2.0.0 +// Since: 2.0 type ExternalUntypedMap interface { UntypedMap Reload() error @@ -26,7 +26,7 @@ type ExternalUntypedMap interface { // UntypedMap is a map data binding with all values Untyped (interface{}). // -// Since: 2.0.0 +// Since: 2.0 type UntypedMap interface { DataMap Delete(string) @@ -38,7 +38,7 @@ type UntypedMap interface { // NewUntypedMap creates a new, empty map binding of string to interface{}. // -// Since: 2.0.0 +// Since: 2.0 func NewUntypedMap() UntypedMap { return &mapBase{items: make(map[string]DataItem), val: &map[string]interface{}{}} } @@ -46,7 +46,7 @@ func NewUntypedMap() UntypedMap { // BindUntypedMap creates a new map binding of string to interface{} based on the data passed. // If your code changes the content of the map this refers to you should call Reload() to inform the bindings. // -// Since: 2.0.0 +// Since: 2.0 func BindUntypedMap(d *map[string]interface{}) ExternalUntypedMap { if d == nil { return NewUntypedMap().(ExternalUntypedMap) @@ -62,7 +62,7 @@ func BindUntypedMap(d *map[string]interface{}) ExternalUntypedMap { // Struct is the base interface for a bound struct type. // -// Since: 2.0.0 +// Since: 2.0 type Struct interface { DataMap GetValue(string) (interface{}, error) @@ -74,7 +74,7 @@ type Struct interface { // The key for each item is a string representation of each exported field with the value set as an interface{}. // Only exported fields are included. // -// Since: 2.0.0 +// Since: 2.0 func BindStruct(i interface{}) Struct { if i == nil { return NewUntypedMap().(Struct) @@ -109,7 +109,7 @@ func BindStruct(i interface{}) Struct { // Untyped id used tpo represent binding an interface{} value. // -// Since: 2.0.0 +// Since: 2.0 type Untyped interface { DataItem get() (interface{}, error) diff --git a/data/binding/preference.go b/data/binding/preference.go index e16856d3fc..acb986b42f 100644 --- a/data/binding/preference.go +++ b/data/binding/preference.go @@ -3,7 +3,7 @@ package binding -import "fyne.io/fyne" +import "fyne.io/fyne/v2" const keyTypeMismatchError = "A previous preference binding exists with different type for key: " @@ -17,7 +17,7 @@ type prefBoundBool struct { // BindPreferenceBool returns a bindable bool value that is managed by the application preferences. // Changes to this value will be saved to application storage and when the app starts the previous values will be read. // -// Since: 2.0.0 +// Since: 2.0 func BindPreferenceBool(key string, p fyne.Preferences) Bool { if prefBinds[p] != nil { if listen, ok := prefBinds[p][key]; ok { @@ -66,7 +66,7 @@ type prefBoundFloat struct { // BindPreferenceFloat returns a bindable float64 value that is managed by the application preferences. // Changes to this value will be saved to application storage and when the app starts the previous values will be read. // -// Since: 2.0.0 +// Since: 2.0 func BindPreferenceFloat(key string, p fyne.Preferences) Float { if prefBinds[p] != nil { if listen, ok := prefBinds[p][key]; ok { @@ -115,7 +115,7 @@ type prefBoundInt struct { // BindPreferenceInt returns a bindable int value that is managed by the application preferences. // Changes to this value will be saved to application storage and when the app starts the previous values will be read. // -// Since: 2.0.0 +// Since: 2.0 func BindPreferenceInt(key string, p fyne.Preferences) Int { if prefBinds[p] != nil { if listen, ok := prefBinds[p][key]; ok { @@ -164,7 +164,7 @@ type prefBoundString struct { // BindPreferenceString returns a bindable string value that is managed by the application preferences. // Changes to this value will be saved to application storage and when the app starts the previous values will be read. // -// Since: 2.0.0 +// Since: 2.0 func BindPreferenceString(key string, p fyne.Preferences) String { if prefBinds[p] != nil { if listen, ok := prefBinds[p][key]; ok { diff --git a/data/binding/preference_test.go b/data/binding/preference_test.go index b3cbf49a1f..8985b56848 100644 --- a/data/binding/preference_test.go +++ b/data/binding/preference_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - "fyne.io/fyne/test" + "fyne.io/fyne/v2/test" "github.com/stretchr/testify/assert" ) diff --git a/data/validation/regexp.go b/data/validation/regexp.go index e8846f27b3..35b7f9a73b 100644 --- a/data/validation/regexp.go +++ b/data/validation/regexp.go @@ -5,7 +5,7 @@ import ( "errors" "regexp" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // NewRegexp creates a new validator that uses regular expression parsing. diff --git a/data/validation/regexp_test.go b/data/validation/regexp_test.go index 9dac60b1ab..f55d971715 100644 --- a/data/validation/regexp_test.go +++ b/data/validation/regexp_test.go @@ -3,7 +3,7 @@ package validation_test import ( "testing" - "fyne.io/fyne/data/validation" + "fyne.io/fyne/v2/data/validation" "github.com/stretchr/testify/assert" ) diff --git a/dialog/base.go b/dialog/base.go index 231860f11a..b375fec83c 100644 --- a/dialog/base.go +++ b/dialog/base.go @@ -1,15 +1,15 @@ // Package dialog defines standard dialog windows for application GUIs. -package dialog // import "fyne.io/fyne/dialog" +package dialog // import "fyne.io/fyne/v2/dialog" import ( "image/color" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/container" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) const ( diff --git a/dialog/base_test.go b/dialog/base_test.go index c481779396..7ab1240645 100644 --- a/dialog/base_test.go +++ b/dialog/base_test.go @@ -4,10 +4,10 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/test" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/widget" ) func TestShowCustom_ApplyTheme(t *testing.T) { diff --git a/dialog/color.go b/dialog/color.go index e3f9f7a0b8..0cfdf4d779 100644 --- a/dialog/color.go +++ b/dialog/color.go @@ -6,11 +6,11 @@ import ( "math" "strings" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) // ColorPickerDialog is a simple dialog window that displays a color picker. diff --git a/dialog/color_button.go b/dialog/color_button.go index a56c8302bd..75e134d1dc 100644 --- a/dialog/color_button.go +++ b/dialog/color_button.go @@ -3,12 +3,12 @@ package dialog import ( "image/color" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - internalwidget "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" + internalwidget "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) var _ fyne.Widget = (*colorButton)(nil) diff --git a/dialog/color_button_test.go b/dialog/color_button_test.go index 2708b765a3..e9b56a73ed 100644 --- a/dialog/color_button_test.go +++ b/dialog/color_button_test.go @@ -4,10 +4,10 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/layout" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" ) func Test_colorButton_Layout(t *testing.T) { diff --git a/dialog/color_channel.go b/dialog/color_channel.go index be75097543..313698c964 100644 --- a/dialog/color_channel.go +++ b/dialog/color_channel.go @@ -3,11 +3,11 @@ package dialog import ( "strconv" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - internalwidget "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + internalwidget "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) var _ fyne.Widget = (*colorChannel)(nil) diff --git a/dialog/color_channel_test.go b/dialog/color_channel_test.go index a866a51481..8068891201 100644 --- a/dialog/color_channel_test.go +++ b/dialog/color_channel_test.go @@ -3,8 +3,8 @@ package dialog import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/test" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/test" ) func Test_colorChannel_Layout(t *testing.T) { diff --git a/dialog/color_picker.go b/dialog/color_picker.go index 94eb026898..835c9fadde 100644 --- a/dialog/color_picker.go +++ b/dialog/color_picker.go @@ -3,13 +3,13 @@ package dialog import ( "image/color" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/container" - internalwidget "fyne.io/fyne/internal/widget" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + internalwidget "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) // newColorBasicPicker returns a component for selecting basic colors. diff --git a/dialog/color_picker_test.go b/dialog/color_picker_test.go index d857d006a1..7dd1529611 100644 --- a/dialog/color_picker_test.go +++ b/dialog/color_picker_test.go @@ -3,10 +3,10 @@ package dialog import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/layout" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" ) func Test_colorGreyscalePicker_Layout(t *testing.T) { diff --git a/dialog/color_test.go b/dialog/color_test.go index 814d38a84a..80379c98be 100644 --- a/dialog/color_test.go +++ b/dialog/color_test.go @@ -4,9 +4,9 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/test" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/test" "github.com/stretchr/testify/assert" ) diff --git a/dialog/color_wheel.go b/dialog/color_wheel.go index 748bdadf43..8dbb64ca47 100644 --- a/dialog/color_wheel.go +++ b/dialog/color_wheel.go @@ -7,12 +7,12 @@ import ( "math" "math/cmplx" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - internalwidget "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" + internalwidget "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) var _ fyne.Widget = (*colorWheel)(nil) diff --git a/dialog/color_wheel_test.go b/dialog/color_wheel_test.go index a5c6a0a2c4..ba8ed05973 100644 --- a/dialog/color_wheel_test.go +++ b/dialog/color_wheel_test.go @@ -3,8 +3,8 @@ package dialog import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/test" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/test" ) func Test_colorWheel_Layout(t *testing.T) { diff --git a/dialog/confirm.go b/dialog/confirm.go index b67b6b27f4..0cc8f43580 100644 --- a/dialog/confirm.go +++ b/dialog/confirm.go @@ -1,9 +1,9 @@ package dialog import ( - "fyne.io/fyne" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) // ConfirmDialog is like the standard Dialog but with an additional confirmation button diff --git a/dialog/confirm_test.go b/dialog/confirm_test.go index e9c4e2e925..afb1e7f15a 100644 --- a/dialog/confirm_test.go +++ b/dialog/confirm_test.go @@ -3,9 +3,9 @@ package dialog import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/dialog/entry.go b/dialog/entry.go index d9c1ee9a03..1964797ea0 100644 --- a/dialog/entry.go +++ b/dialog/entry.go @@ -1,8 +1,8 @@ package dialog import ( - "fyne.io/fyne" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/widget" ) // EntryDialog is a variation of a dialog which prompts the user to enter some text. diff --git a/dialog/file.go b/dialog/file.go index c12d87a978..d81c620abc 100644 --- a/dialog/file.go +++ b/dialog/file.go @@ -1,17 +1,19 @@ package dialog import ( + "errors" "fmt" "os" "path/filepath" "strings" - "fyne.io/fyne" - "fyne.io/fyne/container" - "fyne.io/fyne/layout" - "fyne.io/fyne/storage" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/storage/repository" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) type textWidget interface { @@ -92,16 +94,16 @@ func (f *fileDialog) makeUI() fyne.CanvasObject { exists, _ := storage.Exists(location) // check if a directory is selected - _, err := storage.ListerForURI(location) + listable, err := storage.CanList(location) if !exists { f.win.Hide() if f.file.onClosedCallback != nil { f.file.onClosedCallback(true) } - callback(storage.SaveFileToURI(location)) + callback(storage.Writer(location)) return - } else if err == nil { + } else if err == nil && listable { // a directory has been selected ShowInformation("Cannot overwrite", "Files cannot replace a directory,\ncheck the file name and try again", f.file.parent) @@ -115,7 +117,7 @@ func (f *fileDialog) makeUI() fyne.CanvasObject { } f.win.Hide() - callback(storage.SaveFileToURI(location)) + callback(storage.Writer(location)) if f.file.onClosedCallback != nil { f.file.onClosedCallback(true) } @@ -126,7 +128,7 @@ func (f *fileDialog) makeUI() fyne.CanvasObject { if f.file.onClosedCallback != nil { f.file.onClosedCallback(true) } - callback(storage.OpenFileFromURI(f.selected.location)) + callback(storage.Reader(f.selected.location)) } else if f.file.isDirectory() { callback := f.file.callback.(func(fyne.ListableURI, error)) f.win.Hide() @@ -244,7 +246,7 @@ func (f *fileDialog) refreshDir(dir fyne.ListableURI) { var icons []fyne.CanvasObject parent, err := storage.Parent(dir) - if err != nil && err != storage.URIRootError { + if err != nil && err != repository.ErrURIRoot { fyne.LogError("Unable to get parent of "+dir.String(), err) return } @@ -259,11 +261,11 @@ func (f *fileDialog) refreshDir(dir fyne.ListableURI) { continue } - listable, err := storage.ListerForURI(file) + listable, err := storage.CanList(file) if f.file.isDirectory() && err != nil { continue - } else if err == nil { // URI points to a directory - icons = append(icons, f.newFileItem(listable, true)) // Pass the listable URI to avoid doing the same check in FileIcon + } else if err == nil && listable { // URI points to a directory + icons = append(icons, f.newFileItem(file, true)) // Pass the listable URI to avoid doing the same check in FileIcon } else if f.file.filter == nil || f.file.filter.Matches(file) { icons = append(icons, f.newFileItem(file, false)) } @@ -275,13 +277,17 @@ func (f *fileDialog) refreshDir(dir fyne.ListableURI) { f.fileScroll.Refresh() } -func (f *fileDialog) setLocation(dir fyne.ListableURI) error { +func (f *fileDialog) setLocation(dir fyne.URI) error { if dir == nil { return fmt.Errorf("failed to open nil directory") } + list, err := storage.ListerForURI(dir) + if err != nil { + return err + } f.setSelected(nil) - f.dir = dir + f.dir = list f.breadcrumb.Objects = nil @@ -302,10 +308,15 @@ func (f *fileDialog) setLocation(dir fyne.ListableURI) error { buildDir = d + string(os.PathSeparator) } - newDir, err := storage.ListerForURI(storage.NewFileURI(buildDir)) + newDir := storage.NewFileURI(buildDir) + isDir, err := storage.CanList(newDir) if err != nil { return err } + + if !isDir { + return errors.New("location was not a listable URI") + } f.breadcrumb.Add( widget.NewButton(d, func() { err := f.setLocation(newDir) @@ -320,7 +331,7 @@ func (f *fileDialog) setLocation(dir fyne.ListableURI) error { f.fileName.SetText(dir.Name()) f.open.Enable() } - f.refreshDir(dir) + f.refreshDir(list) return nil } @@ -331,11 +342,11 @@ func (f *fileDialog) setSelected(file *fileDialogItem) { f.selected.Refresh() } if file != nil && file.isDirectory() { - lister, err := storage.ListerForURI(file.location) - if err != nil { + listable, err := storage.CanList(file.location) + if err != nil || !listable { fyne.LogError("Failed to create lister for URI"+file.location.String(), err) } - f.setLocation(lister) + f.setLocation(file.location) return } f.selected = file diff --git a/dialog/file_darwin.go b/dialog/file_darwin.go index 599d6da831..3c751afc52 100644 --- a/dialog/file_darwin.go +++ b/dialog/file_darwin.go @@ -5,8 +5,8 @@ package dialog import ( "os" - "fyne.io/fyne" - "fyne.io/fyne/storage" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" ) func getFavoriteLocations() (map[string]fyne.ListableURI, error) { diff --git a/dialog/file_mobile.go b/dialog/file_mobile.go index 4af1729699..8e9350f620 100644 --- a/dialog/file_mobile.go +++ b/dialog/file_mobile.go @@ -5,9 +5,9 @@ package dialog import ( "os" - "fyne.io/fyne" - "fyne.io/fyne/internal/driver/gomobile" - "fyne.io/fyne/storage" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/driver/gomobile" + "fyne.io/fyne/v2/storage" ) func (f *fileDialog) loadPlaces() []fyne.CanvasObject { diff --git a/dialog/file_other_test.go b/dialog/file_other_test.go index 671c9620fe..d2b584400c 100644 --- a/dialog/file_other_test.go +++ b/dialog/file_other_test.go @@ -5,8 +5,8 @@ package dialog import ( "testing" - "fyne.io/fyne/storage" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/dialog/file_test.go b/dialog/file_test.go index 0bc26f268b..e6c7bc405c 100644 --- a/dialog/file_test.go +++ b/dialog/file_test.go @@ -9,13 +9,13 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" - "fyne.io/fyne/container" - "fyne.io/fyne/layout" - "fyne.io/fyne/storage" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) // comparePaths compares if two file paths point to the same thing, and calls diff --git a/dialog/file_unix.go b/dialog/file_unix.go index 0f77e69294..181b4687e4 100644 --- a/dialog/file_unix.go +++ b/dialog/file_unix.go @@ -5,9 +5,9 @@ package dialog import ( "path/filepath" - "fyne.io/fyne" - "fyne.io/fyne/storage" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/theme" ) func (f *fileDialog) loadPlaces() []fyne.CanvasObject { diff --git a/dialog/file_windows.go b/dialog/file_windows.go index 2d88bc51c0..e952c71c2b 100644 --- a/dialog/file_windows.go +++ b/dialog/file_windows.go @@ -4,9 +4,9 @@ import ( "os" "syscall" - "fyne.io/fyne" - "fyne.io/fyne/storage" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/theme" ) func driveMask() uint32 { diff --git a/dialog/file_windows_test.go b/dialog/file_windows_test.go index 7abb965355..31d9e14e5c 100644 --- a/dialog/file_windows_test.go +++ b/dialog/file_windows_test.go @@ -3,7 +3,7 @@ package dialog import ( "testing" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/dialog/file_xdg.go b/dialog/file_xdg.go index c77ddfae8a..748d116273 100644 --- a/dialog/file_xdg.go +++ b/dialog/file_xdg.go @@ -8,8 +8,8 @@ import ( "os" "os/exec" - "fyne.io/fyne" - "fyne.io/fyne/storage" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" ) func getFavoriteLocation(homeURI fyne.URI, name, fallbackName string) (fyne.URI, error) { diff --git a/dialog/file_xdg_test.go b/dialog/file_xdg_test.go index 9254f9bd41..c8f28c2ba7 100644 --- a/dialog/file_xdg_test.go +++ b/dialog/file_xdg_test.go @@ -7,7 +7,7 @@ import ( "os" "testing" - "fyne.io/fyne/storage" + "fyne.io/fyne/v2/storage" "github.com/stretchr/testify/assert" ) diff --git a/dialog/fileitem.go b/dialog/fileitem.go index 2d8f85d7c5..608d341e12 100644 --- a/dialog/fileitem.go +++ b/dialog/fileitem.go @@ -3,10 +3,10 @@ package dialog import ( "path/filepath" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) const ( diff --git a/dialog/fileitem_test.go b/dialog/fileitem_test.go index 19a6c4aab1..31702f7f26 100644 --- a/dialog/fileitem_test.go +++ b/dialog/fileitem_test.go @@ -4,9 +4,9 @@ import ( "path/filepath" "testing" - "fyne.io/fyne/storage" + "fyne.io/fyne/v2/storage" - "fyne.io/fyne/test" + "fyne.io/fyne/v2/test" "github.com/stretchr/testify/assert" ) diff --git a/dialog/folder.go b/dialog/folder.go index d0c9d7f94f..d3872fb9e6 100644 --- a/dialog/folder.go +++ b/dialog/folder.go @@ -1,8 +1,8 @@ package dialog import ( - "fyne.io/fyne" - "fyne.io/fyne/storage" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" ) var folderFilter = storage.NewMimeTypeFileFilter([]string{"application/x-directory"}) diff --git a/dialog/folder_test.go b/dialog/folder_test.go index 773c65176a..f61e7c2db1 100644 --- a/dialog/folder_test.go +++ b/dialog/folder_test.go @@ -6,11 +6,11 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" - "fyne.io/fyne/container" - "fyne.io/fyne/storage" - "fyne.io/fyne/test" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/widget" ) func TestShowFolderOpen(t *testing.T) { diff --git a/dialog/form.go b/dialog/form.go index 9e149452cd..5a492698a6 100644 --- a/dialog/form.go +++ b/dialog/form.go @@ -1,11 +1,11 @@ package dialog import ( - "fyne.io/fyne" - "fyne.io/fyne/container" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) // formDialog is a simple dialog window for displaying FormItems inside a form. @@ -44,7 +44,7 @@ func (d *formDialog) validateItems(err error) { // button will be disabled. The initial state of the confirm button will reflect the initial // validation state of the items added to the form dialog. // -// Since: 2.0.0 +// Since: 2.0 func NewForm(title, confirm, dismiss string, items []*widget.FormItem, callback func(bool), parent fyne.Window) Dialog { var itemObjects = make([]fyne.CanvasObject, len(items)*2) for i, item := range items { @@ -86,7 +86,7 @@ func NewForm(title, confirm, dismiss string, items []*widget.FormItem, callback // validation state of the items added to the form dialog. // The MinSize() of the CanvasObject passed will be used to set the size of the window. // -// Since: 2.0.0 +// Since: 2.0 func ShowForm(title, confirm, dismiss string, content []*widget.FormItem, callback func(bool), parent fyne.Window) { NewForm(title, confirm, dismiss, content, callback, parent).Show() } diff --git a/dialog/form_test.go b/dialog/form_test.go index 7d283b21c6..b913f46f2c 100644 --- a/dialog/form_test.go +++ b/dialog/form_test.go @@ -4,9 +4,9 @@ import ( "errors" "testing" - "fyne.io/fyne" - "fyne.io/fyne/test" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/dialog/information.go b/dialog/information.go index 71823622ff..98aff0dd84 100644 --- a/dialog/information.go +++ b/dialog/information.go @@ -1,9 +1,9 @@ package dialog import ( - "fyne.io/fyne" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) func createTextDialog(title, message string, icon fyne.Resource, parent fyne.Window) Dialog { diff --git a/dialog/information_test.go b/dialog/information_test.go index 36711b4db6..2b4309bb85 100644 --- a/dialog/information_test.go +++ b/dialog/information_test.go @@ -4,9 +4,9 @@ import ( "errors" "testing" - "fyne.io/fyne" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/dialog/progress.go b/dialog/progress.go index 0535211fe5..72da3794db 100644 --- a/dialog/progress.go +++ b/dialog/progress.go @@ -1,9 +1,9 @@ package dialog import ( - "fyne.io/fyne" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) // ProgressDialog is a simple dialog window that displays text and a progress bar. diff --git a/dialog/progressinfinite.go b/dialog/progressinfinite.go index 3b507b57b8..af937f04fe 100644 --- a/dialog/progressinfinite.go +++ b/dialog/progressinfinite.go @@ -1,9 +1,9 @@ package dialog import ( - "fyne.io/fyne" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) // ProgressInfiniteDialog is a simple dialog window that displays text and a infinite progress bar. diff --git a/dialog/progressinfinite_test.go b/dialog/progressinfinite_test.go index 1a7f9493d5..9b59214c38 100644 --- a/dialog/progressinfinite_test.go +++ b/dialog/progressinfinite_test.go @@ -3,10 +3,10 @@ package dialog import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/driver.go b/driver.go index 9cfc81d150..e425614238 100644 --- a/driver.go +++ b/driver.go @@ -12,17 +12,6 @@ type Driver interface { // font size and style. RenderedTextSize(string, float32, TextStyle) Size - // FileReaderForURI opens a file reader for the given resource indicator. - // This may refer to a filesystem (typical on desktop) or data from another application. - FileReaderForURI(URI) (URIReadCloser, error) - - // FileWriterForURI opens a file writer for the given resource indicator. - // This should refer to a filesystem resource as external data will not be writable. - FileWriterForURI(URI) (URIWriteCloser, error) - - // ListerForURI converts a URI to a listable URI, if it is possible to do so. - ListerForURI(URI) (ListableURI, error) - // CanvasForObject returns the canvas that is associated with a given CanvasObject. CanvasForObject(CanvasObject) Canvas // AbsolutePositionForObject returns the position of a given CanvasObject relative to the top/left of a canvas. diff --git a/driver/desktop/canvas.go b/driver/desktop/canvas.go index d379546a09..0a2ab0c047 100644 --- a/driver/desktop/canvas.go +++ b/driver/desktop/canvas.go @@ -1,6 +1,6 @@ package desktop -import "fyne.io/fyne" +import "fyne.io/fyne/v2" // Canvas defines the desktop specific extensions to a fyne.Canvas. type Canvas interface { diff --git a/driver/desktop/cursor.go b/driver/desktop/cursor.go index 1e00140433..f5f3b51c9a 100644 --- a/driver/desktop/cursor.go +++ b/driver/desktop/cursor.go @@ -4,7 +4,7 @@ import "image" // Cursor interface is used for objects that desire a specific cursor. // -// Since: 2.0.0 +// Since: 2.0 type Cursor interface { // Image returns the image for the given cursor, or nil if none should be shown. // It also returns the x and y pixels that should act as the hot-spot (measured from top left corner). @@ -14,12 +14,12 @@ type Cursor interface { // StandardCursor represents a standard Fyne cursor. // These values were previously of type `fyne.Cursor`. // -// Since: 2.0.0 +// Since: 2.0 type StandardCursor int // Image is not used for any of the StandardCursor types. // -// Since: 2.0.0 +// Since: 2.0 func (d StandardCursor) Image() (image.Image, int, int) { return nil, 0, 0 } diff --git a/driver/desktop/driver.go b/driver/desktop/driver.go index 35d52d50a2..0037c5ba61 100644 --- a/driver/desktop/driver.go +++ b/driver/desktop/driver.go @@ -1,7 +1,7 @@ // Package desktop provides desktop specific driver functionality. package desktop -import "fyne.io/fyne" +import "fyne.io/fyne/v2" // Driver represents the extended capabilities of a desktop driver type Driver interface { diff --git a/driver/desktop/key.go b/driver/desktop/key.go index df069ef438..da0b685472 100644 --- a/driver/desktop/key.go +++ b/driver/desktop/key.go @@ -1,7 +1,7 @@ package desktop import ( - "fyne.io/fyne" + "fyne.io/fyne/v2" ) const ( diff --git a/driver/desktop/mouse.go b/driver/desktop/mouse.go index 3e1c9b507c..5228506746 100644 --- a/driver/desktop/mouse.go +++ b/driver/desktop/mouse.go @@ -1,6 +1,6 @@ package desktop -import "fyne.io/fyne" +import "fyne.io/fyne/v2" // MouseButton represents a single button in a desktop MouseEvent type MouseButton int @@ -9,18 +9,18 @@ const ( // MouseButtonPrimary is the most common mouse button - on some systems the only one. // This will normally be on the left side of a mouse. // - // Since: 2.0.0 + // Since: 2.0 MouseButtonPrimary MouseButton = 1 << iota // MouseButtonSecondary is the secondary button on most mouse input devices. // This will normally be on the right side of a mouse. // - // Since: 2.0.0 + // Since: 2.0 MouseButtonSecondary // MouseButtonTertiary is the middle button on the mouse, assuming it has one. // - // Since: 2.0.0 + // Since: 2.0 MouseButtonTertiary // LeftMouseButton is the most common mouse button - on some systems the only one. diff --git a/driver/desktop/shortcut.go b/driver/desktop/shortcut.go index 0cc9da04c3..cc1e1009f2 100644 --- a/driver/desktop/shortcut.go +++ b/driver/desktop/shortcut.go @@ -4,7 +4,7 @@ import ( "runtime" "strings" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // Declare conformity with Shortcut interface diff --git a/driver/desktop/shortcut_test.go b/driver/desktop/shortcut_test.go index cb7afbe610..8a3e7ca00c 100644 --- a/driver/desktop/shortcut_test.go +++ b/driver/desktop/shortcut_test.go @@ -3,7 +3,7 @@ package desktop import ( "testing" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) func TestCustomShortcut_Shortcut(t *testing.T) { diff --git a/driver/mobile/keyboard.go b/driver/mobile/keyboard.go index 81cf97f363..8243e1206c 100644 --- a/driver/mobile/keyboard.go +++ b/driver/mobile/keyboard.go @@ -1,7 +1,7 @@ package mobile import ( - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // KeyboardType represents a type of virtual keyboard diff --git a/driver/mobile/touch.go b/driver/mobile/touch.go index 927b8afc4d..3c11f1b34d 100644 --- a/driver/mobile/touch.go +++ b/driver/mobile/touch.go @@ -1,6 +1,6 @@ package mobile -import "fyne.io/fyne" +import "fyne.io/fyne/v2" // TouchEvent contains data relating to mobile touch events type TouchEvent struct { diff --git a/driver/software/render.go b/driver/software/render.go index 5419761318..1e2829e3b7 100644 --- a/driver/software/render.go +++ b/driver/software/render.go @@ -3,8 +3,8 @@ package software import ( "image" - "fyne.io/fyne" - "fyne.io/fyne/internal/app" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/app" ) // RenderCanvas takes a canvas and renders it to a regular Go image using the provided Theme. diff --git a/driver/software/render_test.go b/driver/software/render_test.go index 8fccf94851..d5f2b3b747 100644 --- a/driver/software/render_test.go +++ b/driver/software/render_test.go @@ -3,11 +3,11 @@ package software import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/container" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) func TestRender(t *testing.T) { diff --git a/driver/software/softwarecanvas.go b/driver/software/softwarecanvas.go index fa57988039..cc0adde107 100644 --- a/driver/software/softwarecanvas.go +++ b/driver/software/softwarecanvas.go @@ -1,8 +1,8 @@ package software import ( - "fyne.io/fyne/internal/painter/software" - "fyne.io/fyne/test" + "fyne.io/fyne/v2/internal/painter/software" + "fyne.io/fyne/v2/test" ) // NewCanvas creates a new canvas in memory that can render without hardware support diff --git a/fyne.go b/fyne.go index 0fc4ab6b5a..36cb43972a 100644 --- a/fyne.go +++ b/fyne.go @@ -7,8 +7,8 @@ // // package main // -// import "fyne.io/fyne/app" -// import "fyne.io/fyne/widget" +// import "fyne.io/fyne/v2/app" +// import "fyne.io/fyne/v2/widget" // // func main() { // a := app.New() @@ -24,4 +24,4 @@ // // w.ShowAndRun() // } -package fyne // import "fyne.io/fyne" +package fyne // import "fyne.io/fyne/v2" diff --git a/go.mod b/go.mod index 76ff9402a4..07c230894f 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module fyne.io/fyne +module fyne.io/fyne/v2 go 1.12 @@ -28,6 +28,7 @@ require ( golang.org/x/tools v0.0.0-20200328031815-3db5fc6bac03 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v2 v2.2.8 // indirect + github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 ) replace github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3 => github.com/fyne-io/glfw/v3.3/glfw v0.0.0-20201123143003-f2279069162d diff --git a/go.sum b/go.sum index 95ac3751fb..112f526ce0 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 h1:FDqhDm7pcsLhhWl1QtD8vlzI4mm59llRvNzrFg6/LAA= +github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3/go.mod h1:CzM2G82Q9BDUvMTGHnXf/6OExw/Dz2ivDj48nVg7Lg8= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fyne-io/glfw/v3.3/glfw v0.0.0-20201123143003-f2279069162d h1:WfVxpuVm+5Gr3ipAoWrxV8lJFYkaBWoEwFRrWThWRSU= @@ -44,6 +46,7 @@ github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCE github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/internal/animation/animation.go b/internal/animation/animation.go index 276ae59355..246455115e 100644 --- a/internal/animation/animation.go +++ b/internal/animation/animation.go @@ -3,7 +3,7 @@ package animation import ( "time" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) type anim struct { diff --git a/internal/animation/animation_test.go b/internal/animation/animation_test.go index 1e3009752f..2808c1f18f 100644 --- a/internal/animation/animation_test.go +++ b/internal/animation/animation_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) func TestGLDriver_StartAnimation(t *testing.T) { diff --git a/internal/animation/runner.go b/internal/animation/runner.go index 8eda6da51c..6b729775f8 100644 --- a/internal/animation/runner.go +++ b/internal/animation/runner.go @@ -4,7 +4,7 @@ import ( "sync" "time" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // Runner is the main driver for animations package diff --git a/internal/app/focus_manager.go b/internal/app/focus_manager.go index dfa1b98c5b..1eff4bb605 100644 --- a/internal/app/focus_manager.go +++ b/internal/app/focus_manager.go @@ -3,8 +3,8 @@ package app import ( "sync" - "fyne.io/fyne" - "fyne.io/fyne/internal/driver" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/driver" ) // FocusManager represents a standard manager of input focus for a canvas diff --git a/internal/app/focus_manager_test.go b/internal/app/focus_manager_test.go index 43b7e92cae..6bf961db9c 100644 --- a/internal/app/focus_manager_test.go +++ b/internal/app/focus_manager_test.go @@ -3,11 +3,11 @@ package app_test import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/container" - "fyne.io/fyne/internal/app" - internalWidget "fyne.io/fyne/internal/widget" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/internal/app" + internalWidget "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/internal/app/theme.go b/internal/app/theme.go index 57a9496743..292c4cf077 100644 --- a/internal/app/theme.go +++ b/internal/app/theme.go @@ -1,8 +1,8 @@ package app import ( - "fyne.io/fyne" - "fyne.io/fyne/internal/cache" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/cache" ) // ApplyThemeTo ensures that the specified canvasobject and all widgets and themeable objects will diff --git a/internal/app/theme_test.go b/internal/app/theme_test.go index 41a8a5b873..a628fbe3a9 100644 --- a/internal/app/theme_test.go +++ b/internal/app/theme_test.go @@ -3,8 +3,8 @@ package app_test import ( "testing" - "fyne.io/fyne/internal/app" - "fyne.io/fyne/test" + "fyne.io/fyne/v2/internal/app" + "fyne.io/fyne/v2/test" ) func TestApplySettings_BeforeContentSet(t *testing.T) { diff --git a/internal/cache/widget.go b/internal/cache/widget.go index 7b068bb737..e705df680e 100644 --- a/internal/cache/widget.go +++ b/internal/cache/widget.go @@ -3,7 +3,7 @@ package cache import ( "sync" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) var renderers sync.Map diff --git a/internal/clip.go b/internal/clip.go index 66bb0310a6..d8983ce80d 100644 --- a/internal/clip.go +++ b/internal/clip.go @@ -1,6 +1,6 @@ package internal -import "fyne.io/fyne" +import "fyne.io/fyne/v2" // ClipStack keeps track of the areas that should be clipped when drawing a canvas. // If no clips are present then adding one will be added as-is. diff --git a/internal/clip_test.go b/internal/clip_test.go index 3eca38a238..feafb9f6c5 100644 --- a/internal/clip_test.go +++ b/internal/clip_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) func TestClipStack_Intersect(t *testing.T) { diff --git a/internal/driver/glfw/animation.go b/internal/driver/glfw/animation.go index 1896ead3c5..d6dfde69f9 100644 --- a/internal/driver/glfw/animation.go +++ b/internal/driver/glfw/animation.go @@ -1,6 +1,6 @@ package glfw -import "fyne.io/fyne" +import "fyne.io/fyne/v2" func (g *gLDriver) StartAnimation(a *fyne.Animation) { g.animation.Start(a) diff --git a/internal/driver/glfw/canvas.go b/internal/driver/glfw/canvas.go index 04ee177f8a..265763cc3f 100644 --- a/internal/driver/glfw/canvas.go +++ b/internal/driver/glfw/canvas.go @@ -5,15 +5,15 @@ import ( "math" "sync" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal" - "fyne.io/fyne/internal/app" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/internal/driver" - "fyne.io/fyne/internal/painter/gl" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal" + "fyne.io/fyne/v2/internal/app" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/internal/driver" + "fyne.io/fyne/v2/internal/painter/gl" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) // Declare conformity with Canvas interface diff --git a/internal/driver/glfw/canvas_other_test.go b/internal/driver/glfw/canvas_other_test.go index f7e2ab4efe..e3ebfdb1c0 100644 --- a/internal/driver/glfw/canvas_other_test.go +++ b/internal/driver/glfw/canvas_other_test.go @@ -7,8 +7,8 @@ package glfw import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/container" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" "github.com/stretchr/testify/assert" ) @@ -19,6 +19,7 @@ func TestGlCanvas_FocusHandlingWhenActivatingOrDeactivatingTheMenu(t *testing.T) w.SetMainMenu( fyne.NewMainMenu( fyne.NewMenu("test", fyne.NewMenuItem("item", func() {})), + fyne.NewMenu("other", fyne.NewMenuItem("item", func() {})), ), ) c := w.Canvas().(*glCanvas) @@ -38,22 +39,20 @@ func TestGlCanvas_FocusHandlingWhenActivatingOrDeactivatingTheMenu(t *testing.T) m.Items[0].(*menuBarItem).Tapped(&fyne.PointEvent{}) assert.True(t, m.IsActive()) - ctxt := "activating the menu changes focus handler but does not remove focus from content" + ctxt := "activating the menu changes focus handler and focuses the menu bar item but does not remove focus from content" assert.True(t, ce2.focused, ctxt) - assert.Nil(t, c.Focused(), ctxt) + assert.Equal(t, m.Items[0], c.Focused(), ctxt) c.FocusNext() - // TODO: changes menu focus as soon as menu has focus support ctxt = "changing focus with active menu does not affect content focus" assert.True(t, ce2.focused, ctxt) - assert.Nil(t, c.Focused(), ctxt) + assert.Equal(t, m.Items[1], c.Focused(), ctxt) m.Items[0].(*menuBarItem).Tapped(&fyne.PointEvent{}) assert.False(t, m.IsActive()) - // TODO: does not remove focus from focused menu item as soon as menu has focus support ctxt = "deactivating the menu restores focus handler from content" assert.True(t, ce2.focused, ctxt) - assert.Equal(t, ce2, c.Focused()) + assert.Equal(t, ce2, c.Focused(), ctxt) c.FocusPrevious() assert.Equal(t, ce1, c.Focused(), ctxt) diff --git a/internal/driver/glfw/canvas_test.go b/internal/driver/glfw/canvas_test.go index 9b9861dcdf..f5f6ccfe0e 100644 --- a/internal/driver/glfw/canvas_test.go +++ b/internal/driver/glfw/canvas_test.go @@ -7,11 +7,11 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/container" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/internal/driver/glfw/clipboard.go b/internal/driver/glfw/clipboard.go index 59a2699a60..4006c9f31f 100644 --- a/internal/driver/glfw/clipboard.go +++ b/internal/driver/glfw/clipboard.go @@ -4,7 +4,7 @@ import ( "runtime" "time" - "fyne.io/fyne" + "fyne.io/fyne/v2" "github.com/go-gl/glfw/v3.3/glfw" ) diff --git a/internal/driver/glfw/device.go b/internal/driver/glfw/device.go index 393076fe2d..23f8fed7b6 100644 --- a/internal/driver/glfw/device.go +++ b/internal/driver/glfw/device.go @@ -3,7 +3,7 @@ package glfw import ( "runtime" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) type glDevice struct { diff --git a/internal/driver/glfw/driver.go b/internal/driver/glfw/driver.go index 4d58d9ff7b..4964b5c022 100644 --- a/internal/driver/glfw/driver.go +++ b/internal/driver/glfw/driver.go @@ -8,10 +8,12 @@ import ( "strings" "sync" - "fyne.io/fyne" - "fyne.io/fyne/internal/animation" - "fyne.io/fyne/internal/driver" - "fyne.io/fyne/internal/painter" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/animation" + "fyne.io/fyne/v2/internal/driver" + "fyne.io/fyne/v2/internal/painter" + intRepo "fyne.io/fyne/v2/internal/repository" + "fyne.io/fyne/v2/storage/repository" ) const mainGoroutineID = 1 @@ -128,5 +130,7 @@ func NewGLDriver() fyne.Driver { d.drawDone = make(chan interface{}) d.animation = &animation.Runner{} + repository.Register("file", intRepo.NewFileRepository()) + return d } diff --git a/internal/driver/glfw/driver_test.go b/internal/driver/glfw/driver_test.go index ba7c4331b5..95fb3a9217 100644 --- a/internal/driver/glfw/driver_test.go +++ b/internal/driver/glfw/driver_test.go @@ -7,10 +7,10 @@ import ( "sync" "testing" - "fyne.io/fyne" - "fyne.io/fyne/container" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/internal/driver/glfw/file.go b/internal/driver/glfw/file.go deleted file mode 100644 index ad11c9bb26..0000000000 --- a/internal/driver/glfw/file.go +++ /dev/null @@ -1,94 +0,0 @@ -package glfw - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - - "fyne.io/fyne" - "fyne.io/fyne/storage" -) - -type file struct { - *os.File - path string -} - -type directory struct { - fyne.URI -} - -// Declare conformity to the ListableURI interface -var _ fyne.ListableURI = (*directory)(nil) - -func (d *directory) List() ([]fyne.URI, error) { - if d.Scheme() != "file" { - return nil, fmt.Errorf("unsupported URL protocol") - } - - path := d.String()[len(d.Scheme())+3 : len(d.String())] - files, err := ioutil.ReadDir(path) - if err != nil { - return nil, err - } - - urilist := []fyne.URI{} - - for _, f := range files { - uri := storage.NewURI("file://" + filepath.Join(path, f.Name())) - urilist = append(urilist, uri) - } - - return urilist, nil -} - -func (d *gLDriver) ListerForURI(uri fyne.URI) (fyne.ListableURI, error) { - if uri.Scheme() != "file" { - return nil, fmt.Errorf("unsupported URL protocol") - } - - path := uri.String()[len(uri.Scheme())+3 : len(uri.String())] - s, err := os.Stat(path) - if err != nil { - return nil, err - } - - if !s.IsDir() { - return nil, fmt.Errorf("path '%s' is not a directory, cannot convert to listable URI", path) - } - - return &directory{URI: uri}, nil -} - -func (d *gLDriver) FileReaderForURI(uri fyne.URI) (fyne.URIReadCloser, error) { - return openFile(uri, false) -} - -func (f *file) Name() string { - return f.URI().Name() -} - -func (f *file) URI() fyne.URI { - return storage.NewURI("file://" + f.path) -} - -func (d *gLDriver) FileWriterForURI(uri fyne.URI) (fyne.URIWriteCloser, error) { - return openFile(uri, true) -} - -func openFile(uri fyne.URI, create bool) (*file, error) { - if uri.Scheme() != "file" { - return nil, fmt.Errorf("invalid URI for file: %s", uri) - } - - path := uri.String()[7:] - var f *os.File - var err error - if create { - f, err = os.Create(path) // If it exists this will truncate which is what we wanted - } else { - f, err = os.Open(path) - } - return &file{File: f, path: path}, err -} diff --git a/internal/driver/glfw/file_test.go b/internal/driver/glfw/file_test.go deleted file mode 100644 index 144d98261b..0000000000 --- a/internal/driver/glfw/file_test.go +++ /dev/null @@ -1,112 +0,0 @@ -// +build !mobile - -package glfw - -import ( - "io/ioutil" - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" - - "fyne.io/fyne" - "fyne.io/fyne/storage" -) - -func TestGLDriver_FileReaderForURI(t *testing.T) { - uri, _ := testURI("text.txt") - read, err := NewGLDriver().FileReaderForURI(uri) - assert.Nil(t, err) - - defer read.Close() - - assert.Equal(t, uri, read.URI()) - - data, err := ioutil.ReadAll(read) - assert.Nil(t, err) - assert.Equal(t, "content", string(data)) -} - -func TestGLDriver_FileReaderForURI_Again(t *testing.T) { // a bug blanked files - TestGLDriver_FileReaderForURI(t) -} - -func TestGLDriver_FileWriterForURI(t *testing.T) { - uri, path := testURI("text2.txt") - defer os.Remove(path) - write, err := NewGLDriver().FileWriterForURI(uri) - assert.Nil(t, err) - - defer write.Close() - - assert.Equal(t, uri, write.URI()) - - count, err := write.Write([]byte("another")) - assert.Equal(t, 7, count) - assert.Nil(t, err) -} - -func testURI(file string) (fyne.URI, string) { - path, _ := filepath.Abs(filepath.Join("testdata", file)) - uri := storage.NewURI("file://" + path) - - return uri, path -} - -func Test_ListableURI(t *testing.T) { - tempdir, err := ioutil.TempDir("", "file_test") - if err != nil { - t.Fatal(err) - } - - defer os.RemoveAll(tempdir) - - content := []byte("Test Content!") - - err = ioutil.WriteFile(filepath.Join(tempdir, "aaa"), content, 0666) - if err != nil { - t.Fatal(err) - } - - err = ioutil.WriteFile(filepath.Join(tempdir, "bbb"), content, 0666) - if err != nil { - t.Fatal(err) - } - - err = ioutil.WriteFile(filepath.Join(tempdir, "ccc"), content, 0666) - if err != nil { - t.Fatal(err) - } - - uri := storage.NewURI("file://" + tempdir) - - luri, err := NewGLDriver().ListerForURI(uri) - if err != nil { - t.Fatal(err) - } - - listing, err := luri.List() - if err != nil { - t.Fatal(err) - } - - if len(listing) != 3 { - t.Errorf("Expected directory listing to contain exactly 3 items") - } - - listingStrings := []string{} - for _, v := range listing { - t.Logf("stringify URI %v to %s", v, v.String()) - listingStrings = append(listingStrings, v.String()) - } - - expect := []string{ - "file://" + filepath.ToSlash(filepath.Join(tempdir, "aaa")), - "file://" + filepath.ToSlash(filepath.Join(tempdir, "bbb")), - "file://" + filepath.ToSlash(filepath.Join(tempdir, "ccc")), - } - - assert.ElementsMatch(t, listingStrings, expect) - -} diff --git a/internal/driver/glfw/loop.go b/internal/driver/glfw/loop.go index 73c7fba0d1..f76d69dded 100644 --- a/internal/driver/glfw/loop.go +++ b/internal/driver/glfw/loop.go @@ -6,10 +6,10 @@ import ( "sync" "time" - "fyne.io/fyne" - "fyne.io/fyne/internal" - "fyne.io/fyne/internal/driver" - "fyne.io/fyne/internal/painter" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal" + "fyne.io/fyne/v2/internal/driver" + "fyne.io/fyne/v2/internal/painter" "github.com/go-gl/glfw/v3.3/glfw" ) diff --git a/internal/driver/glfw/menu.go b/internal/driver/glfw/menu.go index b7604ddc4d..72eba7e196 100644 --- a/internal/driver/glfw/menu.go +++ b/internal/driver/glfw/menu.go @@ -1,7 +1,7 @@ package glfw import ( - "fyne.io/fyne" + "fyne.io/fyne/v2" ) func buildMenuOverlay(menus *fyne.MainMenu, c fyne.Canvas) fyne.CanvasObject { diff --git a/internal/driver/glfw/menu_bar.go b/internal/driver/glfw/menu_bar.go index 93f660cb68..b6c103b2b6 100644 --- a/internal/driver/glfw/menu_bar.go +++ b/internal/driver/glfw/menu_bar.go @@ -1,12 +1,12 @@ package glfw import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" ) var _ fyne.Widget = (*MenuBar)(nil) diff --git a/internal/driver/glfw/menu_bar_item.go b/internal/driver/glfw/menu_bar_item.go index 5247425584..2eea3da95a 100644 --- a/internal/driver/glfw/menu_bar_item.go +++ b/internal/driver/glfw/menu_bar_item.go @@ -1,12 +1,12 @@ package glfw import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" - publicWidget "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" + publicWidget "fyne.io/fyne/v2/widget" ) var _ desktop.Hoverable = (*menuBarItem)(nil) diff --git a/internal/driver/glfw/menu_bar_test.go b/internal/driver/glfw/menu_bar_test.go index e860f22ea6..bace3f7b2a 100644 --- a/internal/driver/glfw/menu_bar_test.go +++ b/internal/driver/glfw/menu_bar_test.go @@ -7,10 +7,10 @@ import ( "strconv" "testing" - "fyne.io/fyne" - "fyne.io/fyne/internal/driver/glfw" - "fyne.io/fyne/test" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/driver/glfw" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/internal/driver/glfw/menu_darwin.go b/internal/driver/glfw/menu_darwin.go index 8b0769628d..20a88e3789 100644 --- a/internal/driver/glfw/menu_darwin.go +++ b/internal/driver/glfw/menu_darwin.go @@ -5,7 +5,7 @@ package glfw import ( "unsafe" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) /* diff --git a/internal/driver/glfw/menu_darwin_test.go b/internal/driver/glfw/menu_darwin_test.go index e67affab73..c3133e5173 100644 --- a/internal/driver/glfw/menu_darwin_test.go +++ b/internal/driver/glfw/menu_darwin_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) func TestDarwinMenu(t *testing.T) { diff --git a/internal/driver/glfw/menu_other.go b/internal/driver/glfw/menu_other.go index 196458ee68..a56665dffa 100644 --- a/internal/driver/glfw/menu_other.go +++ b/internal/driver/glfw/menu_other.go @@ -2,7 +2,7 @@ package glfw -import "fyne.io/fyne" +import "fyne.io/fyne/v2" func hasNativeMenu() bool { return false diff --git a/internal/driver/glfw/menu_test.go b/internal/driver/glfw/menu_test.go index f72089c381..b07c343ef5 100644 --- a/internal/driver/glfw/menu_test.go +++ b/internal/driver/glfw/menu_test.go @@ -6,7 +6,7 @@ package glfw import ( "testing" - "fyne.io/fyne" + "fyne.io/fyne/v2" "github.com/stretchr/testify/assert" ) diff --git a/internal/driver/glfw/scale.go b/internal/driver/glfw/scale.go index 74d2f9ab73..90eb62cfa9 100644 --- a/internal/driver/glfw/scale.go +++ b/internal/driver/glfw/scale.go @@ -5,7 +5,7 @@ import ( "os" "strconv" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) const ( diff --git a/internal/driver/glfw/scale_test.go b/internal/driver/glfw/scale_test.go index 1dab840865..b5c9559f1c 100644 --- a/internal/driver/glfw/scale_test.go +++ b/internal/driver/glfw/scale_test.go @@ -6,8 +6,8 @@ import ( "os" "testing" - "fyne.io/fyne" - _ "fyne.io/fyne/test" + "fyne.io/fyne/v2" + _ "fyne.io/fyne/v2/test" "github.com/stretchr/testify/assert" ) diff --git a/internal/driver/glfw/window.go b/internal/driver/glfw/window.go index cbb7456de4..baf63bffbd 100644 --- a/internal/driver/glfw/window.go +++ b/internal/driver/glfw/window.go @@ -10,13 +10,13 @@ import ( "sync" "time" - "fyne.io/fyne" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/internal/driver" - "fyne.io/fyne/internal/painter/gl" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/internal/driver" + "fyne.io/fyne/v2/internal/painter/gl" + "fyne.io/fyne/v2/widget" "github.com/go-gl/glfw/v3.3/glfw" ) @@ -67,19 +67,20 @@ type window struct { centered bool visible bool - mousePos fyne.Position - mouseDragged fyne.Draggable - mouseDraggedOffset fyne.Position - mouseDragPos fyne.Position - mouseDragStarted bool - mouseButton desktop.MouseButton - mouseOver desktop.Hoverable - mouseLastClick fyne.CanvasObject - mousePressed fyne.CanvasObject - mouseClickCount int - mouseCancelFunc context.CancelFunc - onClosed func() - onCloseIntercepted func() + mousePos fyne.Position + mouseDragged fyne.Draggable + mouseDraggedObjStart fyne.Position + mouseDraggedOffset fyne.Position + mouseDragPos fyne.Position + mouseDragStarted bool + mouseButton desktop.MouseButton + mouseOver desktop.Hoverable + mouseLastClick fyne.CanvasObject + mousePressed fyne.CanvasObject + mouseClickCount int + mouseCancelFunc context.CancelFunc + onClosed func() + onCloseIntercepted func() menuTogglePending fyne.KeyName menuDeactivationPending fyne.KeyName @@ -632,6 +633,7 @@ func (w *window) mouseMoved(viewport *glfw.Window, xpos float64, ypos float64) { w.mouseDragPos = previousPos w.mouseDragged = wid w.mouseDraggedOffset = previousPos.Subtract(pos) + w.mouseDraggedObjStart = obj.Position() w.mouseDragStarted = true } } @@ -656,10 +658,10 @@ func (w *window) mouseMoved(viewport *glfw.Window, xpos float64, ypos float64) { if w.mouseDragged != nil { if w.mouseButton > 0 { - draggedObjPos := w.mouseDragged.(fyne.CanvasObject).Position() + draggedObjDelta := w.mouseDraggedObjStart.Subtract(w.mouseDragged.(fyne.CanvasObject).Position()) ev := new(fyne.DragEvent) ev.AbsolutePosition = w.mousePos - ev.Position = w.mousePos.Subtract(w.mouseDraggedOffset).Subtract(draggedObjPos) + ev.Position = w.mousePos.Subtract(w.mouseDraggedOffset).Add(draggedObjDelta) ev.Dragged = fyne.NewDelta(w.mousePos.X-w.mouseDragPos.X, w.mousePos.Y-w.mouseDragPos.Y) wd := w.mouseDragged w.queueEvent(func() { wd.Dragged(ev) }) @@ -724,13 +726,15 @@ func (w *window) mouseClicked(_ *glfw.Window, btn glfw.MouseButton, action glfw. if action == glfw.Press { w.queueEvent(func() { wid.MouseDown(mev) }) } else if action == glfw.Release { - dragged := w.mouseDragged.(interface{}).(fyne.CanvasObject) - _, tappableDrag := dragged.(desktop.Mouseable) - if dragged != nil && tappableDrag { - mev.Position = w.mousePos.Subtract(w.mouseDraggedOffset) - w.queueEvent(func() { dragged.(desktop.Mouseable).MouseUp(mev) }) - } else { + if w.mouseDragged == nil { w.queueEvent(func() { wid.MouseUp(mev) }) + } else { + if dragged, ok := w.mouseDragged.(desktop.Mouseable); ok { + mev.Position = w.mousePos.Subtract(w.mouseDraggedOffset) + w.queueEvent(func() { dragged.MouseUp(mev) }) + } else { + w.queueEvent(func() { wid.MouseUp(mev) }) + } } } } diff --git a/internal/driver/glfw/window_linux.go b/internal/driver/glfw/window_linux.go index 0e50aa739d..11e3da0808 100644 --- a/internal/driver/glfw/window_linux.go +++ b/internal/driver/glfw/window_linux.go @@ -1,6 +1,6 @@ package glfw -import "fyne.io/fyne" +import "fyne.io/fyne/v2" func (w *window) platformResize(canvasSize fyne.Size) { w.canvas.Resize(canvasSize) diff --git a/internal/driver/glfw/window_other.go b/internal/driver/glfw/window_other.go index 04eb1f9338..d0b7ec0347 100644 --- a/internal/driver/glfw/window_other.go +++ b/internal/driver/glfw/window_other.go @@ -2,7 +2,7 @@ package glfw -import "fyne.io/fyne" +import "fyne.io/fyne/v2" func (w *window) platformResize(canvasSize fyne.Size) { d, ok := fyne.CurrentApp().Driver().(*gLDriver) diff --git a/internal/driver/glfw/window_test.go b/internal/driver/glfw/window_test.go index 7652010951..c78474bb9d 100644 --- a/internal/driver/glfw/window_test.go +++ b/internal/driver/glfw/window_test.go @@ -11,15 +11,15 @@ import ( "testing" "time" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/container" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal" - "fyne.io/fyne/layout" - _ "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal" + "fyne.io/fyne/v2/layout" + _ "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" "github.com/go-gl/glfw/v3.3/glfw" "github.com/stretchr/testify/assert" @@ -45,6 +45,11 @@ func TestMain(m *testing.M) { initMainMenu() os.Exit(m.Run()) }() + + master := d.CreateWindow("Master") + master.SetOnClosed(func() { + // we do not close, keeping the driver running + }) d.Run() } diff --git a/internal/driver/gomobile/animation.go b/internal/driver/gomobile/animation.go index d0f87014fa..2768dcc840 100644 --- a/internal/driver/gomobile/animation.go +++ b/internal/driver/gomobile/animation.go @@ -1,6 +1,6 @@ package gomobile -import "fyne.io/fyne" +import "fyne.io/fyne/v2" func (d *mobileDriver) StartAnimation(a *fyne.Animation) { d.animation.Start(a) diff --git a/internal/driver/gomobile/canvas.go b/internal/driver/gomobile/canvas.go index 4431fa7785..eeab19cfad 100644 --- a/internal/driver/gomobile/canvas.go +++ b/internal/driver/gomobile/canvas.go @@ -6,15 +6,15 @@ import ( "math" "time" - "fyne.io/fyne" - "fyne.io/fyne/driver/mobile" - "fyne.io/fyne/internal" - "fyne.io/fyne/internal/app" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/internal/driver" - "fyne.io/fyne/internal/painter/gl" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver/mobile" + "fyne.io/fyne/v2/internal" + "fyne.io/fyne/v2/internal/app" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/internal/driver" + "fyne.io/fyne/v2/internal/painter/gl" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) const ( diff --git a/internal/driver/gomobile/canvas_test.go b/internal/driver/gomobile/canvas_test.go index 3b3016c4a7..8d4cc37bcb 100644 --- a/internal/driver/gomobile/canvas_test.go +++ b/internal/driver/gomobile/canvas_test.go @@ -7,14 +7,14 @@ import ( "testing" "time" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/container" - "fyne.io/fyne/driver/mobile" - "fyne.io/fyne/layout" - _ "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/driver/mobile" + "fyne.io/fyne/v2/layout" + _ "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/internal/driver/gomobile/clipboard.go b/internal/driver/gomobile/clipboard.go index 1932c3068c..9ad8559b66 100644 --- a/internal/driver/gomobile/clipboard.go +++ b/internal/driver/gomobile/clipboard.go @@ -1,7 +1,7 @@ package gomobile import ( - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // Declare conformity with Clipboard interface diff --git a/internal/driver/gomobile/clipboard_desktop.go b/internal/driver/gomobile/clipboard_desktop.go index 52155cefe2..b8ec41fc9f 100644 --- a/internal/driver/gomobile/clipboard_desktop.go +++ b/internal/driver/gomobile/clipboard_desktop.go @@ -2,7 +2,7 @@ package gomobile -import "fyne.io/fyne" +import "fyne.io/fyne/v2" // Content returns the clipboard content for mobile simulator runs func (c *mobileClipboard) Content() string { diff --git a/internal/driver/gomobile/device.go b/internal/driver/gomobile/device.go index e940fe2bf0..88a651f2ae 100644 --- a/internal/driver/gomobile/device.go +++ b/internal/driver/gomobile/device.go @@ -1,10 +1,10 @@ package gomobile import ( - "fyne.io/fyne/driver/mobile" + "fyne.io/fyne/v2/driver/mobile" "github.com/fyne-io/mobile/event/size" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) type device struct { diff --git a/internal/driver/gomobile/device_android.go b/internal/driver/gomobile/device_android.go index 616f3109ce..c78b6fc4f0 100644 --- a/internal/driver/gomobile/device_android.go +++ b/internal/driver/gomobile/device_android.go @@ -2,7 +2,7 @@ package gomobile -import "fyne.io/fyne" +import "fyne.io/fyne/v2" func (*device) SystemScaleForWindow(_ fyne.Window) float32 { if currentDPI >= 600 { diff --git a/internal/driver/gomobile/device_desktop.go b/internal/driver/gomobile/device_desktop.go index 0f311bd338..1c5fcb8afc 100644 --- a/internal/driver/gomobile/device_desktop.go +++ b/internal/driver/gomobile/device_desktop.go @@ -2,7 +2,7 @@ package gomobile -import "fyne.io/fyne" +import "fyne.io/fyne/v2" func (*device) SystemScaleForWindow(_ fyne.Window) float32 { return 2 // this is simply due to the high number of pixels on a mobile device - just an approximation diff --git a/internal/driver/gomobile/device_ios.go b/internal/driver/gomobile/device_ios.go index f9aaf0191c..ba2ed7a94d 100644 --- a/internal/driver/gomobile/device_ios.go +++ b/internal/driver/gomobile/device_ios.go @@ -2,7 +2,7 @@ package gomobile -import "fyne.io/fyne" +import "fyne.io/fyne/v2" func (*device) SystemScaleForWindow(_ fyne.Window) float32 { if currentDPI >= 450 { diff --git a/internal/driver/gomobile/driver.go b/internal/driver/gomobile/driver.go index 3de95bc504..d5ba90d241 100644 --- a/internal/driver/gomobile/driver.go +++ b/internal/driver/gomobile/driver.go @@ -13,14 +13,14 @@ import ( "github.com/fyne-io/mobile/event/touch" "github.com/fyne-io/mobile/gl" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal" - "fyne.io/fyne/internal/animation" - "fyne.io/fyne/internal/driver" - "fyne.io/fyne/internal/painter" - pgl "fyne.io/fyne/internal/painter/gl" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal" + "fyne.io/fyne/v2/internal/animation" + "fyne.io/fyne/v2/internal/driver" + "fyne.io/fyne/v2/internal/painter" + pgl "fyne.io/fyne/v2/internal/painter/gl" + "fyne.io/fyne/v2/theme" ) const ( @@ -133,6 +133,10 @@ func (d *mobileDriver) Run() { switch e.Crosses(lifecycle.StageFocused) { case lifecycle.CrossOff: // will enter background if runtime.GOOS == "darwin" { + if d.glctx == nil { + continue + } + size := fyne.NewSize(float32(currentSize.WidthPx)/canvas.scale, float32(currentSize.HeightPx)/canvas.scale) d.paintWindow(current, size) a.Publish() @@ -437,5 +441,7 @@ func (d *mobileDriver) Device() fyne.Device { func NewGoMobileDriver() fyne.Driver { d := new(mobileDriver) d.animation = &animation.Runner{} + + registerRepository(d) return d } diff --git a/internal/driver/gomobile/file.go b/internal/driver/gomobile/file.go index b723464d15..8afe32e5ba 100644 --- a/internal/driver/gomobile/file.go +++ b/internal/driver/gomobile/file.go @@ -1,13 +1,12 @@ package gomobile import ( - "errors" "io" "github.com/fyne-io/mobile/app" - "fyne.io/fyne" - "fyne.io/fyne/storage" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" ) type fileOpen struct { @@ -16,15 +15,11 @@ type fileOpen struct { done func() } -func (f *fileOpen) Name() string { - return f.uri.Name() -} - func (f *fileOpen) URI() fyne.URI { return f.uri } -func (d *mobileDriver) FileReaderForURI(u fyne.URI) (fyne.URIReadCloser, error) { +func fileReaderForURI(u fyne.URI) (fyne.URIReadCloser, error) { file := &fileOpen{uri: u} read, err := nativeFileOpen(file) if read == nil { @@ -34,10 +29,6 @@ func (d *mobileDriver) FileReaderForURI(u fyne.URI) (fyne.URIReadCloser, error) return file, err } -func (d *mobileDriver) FileWriterForURI(u fyne.URI) (fyne.URIWriteCloser, error) { - return nil, errors.New("file writing is not supported on mobile") -} - func mobileFilter(filter storage.FileFilter) *app.FileFilter { mobile := &app.FileFilter{} @@ -61,7 +52,11 @@ func ShowFileOpenPicker(callback func(fyne.URIReadCloser, error), filter storage drv := fyne.CurrentApp().Driver().(*mobileDriver) if a, ok := drv.app.(hasPicker); ok { a.ShowFileOpenPicker(func(uri string, closer func()) { - f, err := drv.FileReaderForURI(storage.NewURI(uri)) + if uri == "" { + callback(nil, nil) + return + } + f, err := fileReaderForURI(storage.NewURI(uri)) if f != nil { f.(*fileOpen).done = closer } @@ -76,7 +71,11 @@ func ShowFolderOpenPicker(callback func(fyne.ListableURI, error)) { drv := fyne.CurrentApp().Driver().(*mobileDriver) if a, ok := drv.app.(hasPicker); ok { a.ShowFileOpenPicker(func(uri string, _ func()) { - f, err := drv.ListerForURI(storage.NewURI(uri)) + if uri == "" { + callback(nil, nil) + return + } + f, err := listerForURI(storage.NewURI(uri)) callback(f, err) }, mobileFilter(filter)) } diff --git a/internal/driver/gomobile/file_android.go b/internal/driver/gomobile/file_android.go index 4e049f9abb..5c69c8af45 100644 --- a/internal/driver/gomobile/file_android.go +++ b/internal/driver/gomobile/file_android.go @@ -18,6 +18,7 @@ import ( "os" "unsafe" + "fyne.io/fyne/v2/storage/repository" "github.com/fyne-io/mobile/app" ) @@ -90,3 +91,9 @@ func nativeFileOpen(f *fileOpen) (io.ReadCloser, error) { stream.stream = ret return stream, nil } + +func registerRepository(d *mobileDriver) { + repo := &mobileFileRepo{driver: d} + repository.Register("file", repo) + repository.Register("content", repo) +} diff --git a/internal/driver/gomobile/file_desktop.go b/internal/driver/gomobile/file_desktop.go index ebbff6fa81..d8833575f2 100644 --- a/internal/driver/gomobile/file_desktop.go +++ b/internal/driver/gomobile/file_desktop.go @@ -3,15 +3,17 @@ package gomobile import ( - "errors" "io" - "os" + + intRepo "fyne.io/fyne/v2/internal/repository" + "fyne.io/fyne/v2/storage/repository" ) -func nativeFileOpen(f *fileOpen) (io.ReadCloser, error) { - if f.uri.Scheme() != "file" { - return nil, errors.New("mobile simulator mode only supports file:// URIs") - } +func nativeFileOpen(*fileOpen) (io.ReadCloser, error) { + // no-op as we use the internal FileRepository + return nil, nil +} - return os.Open(f.uri.String()[7:]) +func registerRepository(d *mobileDriver) { + repository.Register("file", intRepo.NewFileRepository()) } diff --git a/internal/driver/gomobile/file_ios.go b/internal/driver/gomobile/file_ios.go index bc69585190..21cc47697b 100644 --- a/internal/driver/gomobile/file_ios.go +++ b/internal/driver/gomobile/file_ios.go @@ -15,6 +15,8 @@ import "C" import ( "io" "unsafe" + + "fyne.io/fyne/v2/storage/repository" ) type secureReadCloser struct { @@ -74,3 +76,8 @@ func nativeFileOpen(f *fileOpen) (io.ReadCloser, error) { fileStruct := &secureReadCloser{url: url, closer: f.done} return fileStruct, nil } + +func registerRepository(d *mobileDriver) { + repo := &mobileFileRepo{driver: d} + repository.Register("file", repo) +} diff --git a/internal/driver/gomobile/folder.go b/internal/driver/gomobile/folder.go index 1d098039c9..870ceacff4 100644 --- a/internal/driver/gomobile/folder.go +++ b/internal/driver/gomobile/folder.go @@ -3,7 +3,7 @@ package gomobile import ( "fmt" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) type lister struct { @@ -14,7 +14,7 @@ func (l *lister) List() ([]fyne.URI, error) { return listURI(l) } -func (d *mobileDriver) ListerForURI(uri fyne.URI) (fyne.ListableURI, error) { +func listerForURI(uri fyne.URI) (fyne.ListableURI, error) { if !canListURI(uri) { return nil, fmt.Errorf("specified URI is not listable") } diff --git a/internal/driver/gomobile/folder_android.go b/internal/driver/gomobile/folder_android.go index 34c010f734..ebbfcfe968 100644 --- a/internal/driver/gomobile/folder_android.go +++ b/internal/driver/gomobile/folder_android.go @@ -18,8 +18,8 @@ import ( "github.com/fyne-io/mobile/app" - "fyne.io/fyne" - "fyne.io/fyne/storage" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" ) func canListURI(uri fyne.URI) bool { diff --git a/internal/driver/gomobile/folder_desktop.go b/internal/driver/gomobile/folder_desktop.go index 72218bc25f..6229b7a434 100644 --- a/internal/driver/gomobile/folder_desktop.go +++ b/internal/driver/gomobile/folder_desktop.go @@ -2,12 +2,16 @@ package gomobile -import "fyne.io/fyne" +import ( + "fyne.io/fyne/v2" +) func canListURI(fyne.URI) bool { + // no-op as we use the internal FileRepository return false } func listURI(fyne.URI) ([]fyne.URI, error) { + // no-op as we use the internal FileRepository return nil, nil } diff --git a/internal/driver/gomobile/folder_ios.go b/internal/driver/gomobile/folder_ios.go index 22e9772020..cba2ec71af 100644 --- a/internal/driver/gomobile/folder_ios.go +++ b/internal/driver/gomobile/folder_ios.go @@ -17,8 +17,8 @@ import ( "strings" "unsafe" - "fyne.io/fyne" - "fyne.io/fyne/storage" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" ) func canListURI(uri fyne.URI) bool { diff --git a/internal/driver/gomobile/keyboard.go b/internal/driver/gomobile/keyboard.go index 7370523744..967878b218 100644 --- a/internal/driver/gomobile/keyboard.go +++ b/internal/driver/gomobile/keyboard.go @@ -1,8 +1,8 @@ package gomobile import ( - "fyne.io/fyne" - "fyne.io/fyne/driver/mobile" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver/mobile" "github.com/fyne-io/mobile/app" ) diff --git a/internal/driver/gomobile/menu.go b/internal/driver/gomobile/menu.go index f1d53eb9ad..2c2fc0fe98 100644 --- a/internal/driver/gomobile/menu.go +++ b/internal/driver/gomobile/menu.go @@ -3,12 +3,12 @@ package gomobile import ( "image/color" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/container" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) type menuLabel struct { diff --git a/internal/driver/gomobile/menu_test.go b/internal/driver/gomobile/menu_test.go index 93c83f2b5d..1e41e3fc70 100644 --- a/internal/driver/gomobile/menu_test.go +++ b/internal/driver/gomobile/menu_test.go @@ -5,11 +5,11 @@ package gomobile import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - internalWidget "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + internalWidget "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/internal/driver/gomobile/menubutton.go b/internal/driver/gomobile/menubutton.go new file mode 100644 index 0000000000..330c14328c --- /dev/null +++ b/internal/driver/gomobile/menubutton.go @@ -0,0 +1,52 @@ +package gomobile + +import ( + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" +) + +type menuButton struct { + widget.BaseWidget + win *window + menu *fyne.MainMenu +} + +func (w *window) newMenuButton(menu *fyne.MainMenu) *menuButton { + b := &menuButton{win: w, menu: menu} + b.ExtendBaseWidget(b) + return b +} + +func (m *menuButton) CreateRenderer() fyne.WidgetRenderer { + return &menuButtonRenderer{btn: widget.NewButtonWithIcon("", theme.MenuIcon(), func() { + m.win.canvas.showMenu(m.menu) + }), bg: canvas.NewRectangle(theme.BackgroundColor())} +} + +type menuButtonRenderer struct { + btn *widget.Button + bg *canvas.Rectangle +} + +func (m *menuButtonRenderer) Destroy() { +} + +func (m *menuButtonRenderer) Layout(size fyne.Size) { + m.bg.Move(fyne.NewPos(theme.Padding()/2, theme.Padding()/2)) + m.bg.Resize(size.Subtract(fyne.NewSize(theme.Padding(), theme.Padding()))) + m.btn.Resize(size) +} + +func (m *menuButtonRenderer) MinSize() fyne.Size { + return m.btn.MinSize() +} + +func (m *menuButtonRenderer) Objects() []fyne.CanvasObject { + return []fyne.CanvasObject{m.bg, m.btn} +} + +func (m *menuButtonRenderer) Refresh() { + m.bg.FillColor = theme.BackgroundColor() +} diff --git a/internal/driver/gomobile/repository.go b/internal/driver/gomobile/repository.go new file mode 100644 index 0000000000..4b2d33f5a6 --- /dev/null +++ b/internal/driver/gomobile/repository.go @@ -0,0 +1,48 @@ +// +build ios android + +package gomobile + +import ( + "fyne.io/fyne/v2" + + "fyne.io/fyne/v2/storage/repository" +) + +// declare conformance with repository types +var _ repository.Repository = (*mobileFileRepo)(nil) +var _ repository.ListableRepository = (*mobileFileRepo)(nil) + +// TODO add write support (not yet supported on mobile) +// var _ repository.WritableRepository = (*mobileFileRepo)(nil) + +type mobileFileRepo struct { + driver *mobileDriver +} + +func (m *mobileFileRepo) Exists(u fyne.URI) (bool, error) { + return true, nil // TODO check a file exists +} + +func (m *mobileFileRepo) Reader(u fyne.URI) (fyne.URIReadCloser, error) { + return fileReaderForURI(u) +} + +func (m *mobileFileRepo) CanRead(u fyne.URI) (bool, error) { + return true, nil // TODO check a file can be read +} + +func (m *mobileFileRepo) Destroy(string) { +} + +func (m *mobileFileRepo) CanList(u fyne.URI) (bool, error) { + return canListURI(u), nil +} + +func (m *mobileFileRepo) List(u fyne.URI) ([]fyne.URI, error) { + return listURI(u) +} + +func (m *mobileFileRepo) CreateListable(u fyne.URI) error { + // TODO: implement this + return repository.ErrOperationNotSupported +} diff --git a/internal/driver/gomobile/window.go b/internal/driver/gomobile/window.go index a0b6fbe185..8bc00a3985 100644 --- a/internal/driver/gomobile/window.go +++ b/internal/driver/gomobile/window.go @@ -1,12 +1,12 @@ package gomobile import ( - "fyne.io/fyne" - "fyne.io/fyne/container" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) type window struct { @@ -100,9 +100,7 @@ func (w *window) SetCloseIntercept(callback func()) { func (w *window) Show() { menu := fyne.CurrentApp().Driver().(*mobileDriver).findMenu(w) - menuButton := widget.NewButtonWithIcon("", theme.MenuIcon(), func() { - w.canvas.showMenu(menu) - }) + menuButton := w.newMenuButton(menu) if menu == nil { menuButton.Hide() } diff --git a/internal/driver/util.go b/internal/driver/util.go index 66a1be51b3..11dcc43d0b 100644 --- a/internal/driver/util.go +++ b/internal/driver/util.go @@ -3,8 +3,8 @@ package driver import ( "math" - "fyne.io/fyne" - "fyne.io/fyne/internal/cache" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/cache" ) // AbsolutePositionForObject returns the absolute position of an object in a set of object trees. diff --git a/internal/driver/util_test.go b/internal/driver/util_test.go index d4e549f584..b9a006e539 100644 --- a/internal/driver/util_test.go +++ b/internal/driver/util_test.go @@ -4,14 +4,14 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/container" - "fyne.io/fyne/internal/driver" - internal_widget "fyne.io/fyne/internal/widget" - "fyne.io/fyne/layout" - _ "fyne.io/fyne/test" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/internal/driver" + internal_widget "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/layout" + _ "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/internal/overlay_stack.go b/internal/overlay_stack.go index 9de588eb24..6b9bb05712 100644 --- a/internal/overlay_stack.go +++ b/internal/overlay_stack.go @@ -3,9 +3,9 @@ package internal import ( "sync" - "fyne.io/fyne" - "fyne.io/fyne/internal/app" - "fyne.io/fyne/internal/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/app" + "fyne.io/fyne/v2/internal/widget" ) // OverlayStack implements fyne.OverlayStack diff --git a/internal/overlay_stack_test.go b/internal/overlay_stack_test.go index 2aa3be499c..8baaf159fd 100644 --- a/internal/overlay_stack_test.go +++ b/internal/overlay_stack_test.go @@ -5,11 +5,11 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" - "fyne.io/fyne/internal" - "fyne.io/fyne/internal/app" - "fyne.io/fyne/test" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal" + "fyne.io/fyne/v2/internal/app" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/widget" ) func TestOverlayStack(t *testing.T) { diff --git a/internal/painter/draw.go b/internal/painter/draw.go index 91049d69d8..408182c422 100644 --- a/internal/painter/draw.go +++ b/internal/painter/draw.go @@ -4,7 +4,7 @@ import ( "image" "math" - "fyne.io/fyne/canvas" + "fyne.io/fyne/v2/canvas" "github.com/srwiley/rasterx" "golang.org/x/image/math/fixed" diff --git a/internal/painter/font.go b/internal/painter/font.go index a9a91c8b70..034f4dec5a 100644 --- a/internal/painter/font.go +++ b/internal/painter/font.go @@ -8,8 +8,8 @@ import ( "golang.org/x/image/font" "golang.org/x/image/math/fixed" - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) // TextDPI is a global constant that determines how text scales to interface sizes diff --git a/internal/painter/gl/capture.go b/internal/painter/gl/capture.go index 85c95eca69..02f6f72972 100644 --- a/internal/painter/gl/capture.go +++ b/internal/painter/gl/capture.go @@ -4,7 +4,7 @@ import ( "image" "image/color" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) type captureImage struct { diff --git a/internal/painter/gl/draw.go b/internal/painter/gl/draw.go index df563fac8a..50d67629cb 100644 --- a/internal/painter/gl/draw.go +++ b/internal/painter/gl/draw.go @@ -3,9 +3,9 @@ package gl import ( "math" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/painter" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/painter" ) func (p *glPainter) drawTextureWithDetails(o fyne.CanvasObject, creator func(canvasObject fyne.CanvasObject) Texture, diff --git a/internal/painter/gl/draw_test.go b/internal/painter/gl/draw_test.go index 8ac3e9225b..fe749667e6 100644 --- a/internal/painter/gl/draw_test.go +++ b/internal/painter/gl/draw_test.go @@ -5,8 +5,8 @@ package gl import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" "github.com/stretchr/testify/assert" ) diff --git a/internal/painter/gl/gl_common.go b/internal/painter/gl/gl_common.go index 0e98f7034d..03a16b197b 100644 --- a/internal/painter/gl/gl_common.go +++ b/internal/painter/gl/gl_common.go @@ -9,9 +9,9 @@ import ( "github.com/goki/freetype/truetype" "golang.org/x/image/font" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/painter" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/painter" ) var textures = make(map[fyne.CanvasObject]Texture, 1024) diff --git a/internal/painter/gl/gl_core.go b/internal/painter/gl/gl_core.go index 4e21ce37b1..b7f5e49c48 100644 --- a/internal/painter/gl/gl_core.go +++ b/internal/painter/gl/gl_core.go @@ -10,9 +10,9 @@ import ( "github.com/go-gl/gl/v3.2-core/gl" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/theme" ) // Buffer represents a GL buffer diff --git a/internal/painter/gl/gl_es.go b/internal/painter/gl/gl_es.go index 02e2e904e4..817ffe937a 100644 --- a/internal/painter/gl/gl_es.go +++ b/internal/painter/gl/gl_es.go @@ -11,9 +11,9 @@ import ( gl "github.com/go-gl/gl/v3.1/gles2" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/theme" ) // Buffer represents a GL buffer diff --git a/internal/painter/gl/gl_gomobile.go b/internal/painter/gl/gl_gomobile.go index 7e40907134..52df739b90 100644 --- a/internal/painter/gl/gl_gomobile.go +++ b/internal/painter/gl/gl_gomobile.go @@ -11,9 +11,9 @@ import ( "github.com/fyne-io/mobile/exp/f32" "github.com/fyne-io/mobile/gl" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/theme" ) // Buffer represents a GL buffer diff --git a/internal/painter/gl/gl_test.go b/internal/painter/gl/gl_test.go index c3e04e0170..2cd3b17cfc 100644 --- a/internal/painter/gl/gl_test.go +++ b/internal/painter/gl/gl_test.go @@ -6,9 +6,9 @@ import ( "runtime" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/theme" ) func init() { diff --git a/internal/painter/gl/painter.go b/internal/painter/gl/painter.go index 913db70f0a..bc17a1c965 100644 --- a/internal/painter/gl/painter.go +++ b/internal/painter/gl/painter.go @@ -6,9 +6,9 @@ import ( "math" "sync" - "fyne.io/fyne" - "fyne.io/fyne/internal/driver" - "fyne.io/fyne/internal/painter" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/driver" + "fyne.io/fyne/v2/internal/painter" ) // Painter defines the functionality of our OpenGL based renderer diff --git a/internal/painter/image.go b/internal/painter/image.go index 67e3073df5..0beb024c16 100644 --- a/internal/painter/image.go +++ b/internal/painter/image.go @@ -11,9 +11,9 @@ import ( "path/filepath" "strings" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal" "github.com/srwiley/oksvg" "github.com/srwiley/rasterx" diff --git a/internal/painter/image_internal_test.go b/internal/painter/image_internal_test.go index 949780c838..1641df5ce3 100644 --- a/internal/painter/image_internal_test.go +++ b/internal/painter/image_internal_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) func TestIsFileSVG(t *testing.T) { diff --git a/internal/painter/image_test.go b/internal/painter/image_test.go index 325eb05067..ed0a0127ae 100644 --- a/internal/painter/image_test.go +++ b/internal/painter/image_test.go @@ -3,10 +3,10 @@ package painter_test import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/painter/software" - "fyne.io/fyne/test" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/painter/software" + "fyne.io/fyne/v2/test" ) func TestPaintImage_SVG(t *testing.T) { diff --git a/internal/painter/software/draw.go b/internal/painter/software/draw.go index 0a3a6cbd79..2dc8819f38 100644 --- a/internal/painter/software/draw.go +++ b/internal/painter/software/draw.go @@ -5,10 +5,10 @@ import ( "image" "math" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal" - "fyne.io/fyne/internal/painter" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal" + "fyne.io/fyne/v2/internal/painter" "github.com/goki/freetype" "github.com/goki/freetype/truetype" diff --git a/internal/painter/software/painter.go b/internal/painter/software/painter.go index df89acae2d..14ddff1c91 100644 --- a/internal/painter/software/painter.go +++ b/internal/painter/software/painter.go @@ -3,10 +3,10 @@ package software import ( "image" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal" - "fyne.io/fyne/internal/driver" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal" + "fyne.io/fyne/v2/internal/driver" ) // Painter is a simple software painter that can paint a canvas in memory. diff --git a/internal/painter/software/painter_test.go b/internal/painter/software/painter_test.go index 4508dda213..bbbcdd78c6 100644 --- a/internal/painter/software/painter_test.go +++ b/internal/painter/software/painter_test.go @@ -5,14 +5,14 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/container" - "fyne.io/fyne/internal/painter/software" - internalTest "fyne.io/fyne/internal/test" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/internal/painter/software" + internalTest "fyne.io/fyne/v2/internal/test" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) func makeTestImage(w, h int) image.Image { diff --git a/internal/painter/svg_cache.go b/internal/painter/svg_cache.go index 672bf8087d..510c387535 100644 --- a/internal/painter/svg_cache.go +++ b/internal/painter/svg_cache.go @@ -6,8 +6,8 @@ import ( "sync" "time" - "fyne.io/fyne" - "fyne.io/fyne/canvas" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" ) type rasterInfo struct { diff --git a/internal/painter/svg_cache_test.go b/internal/painter/svg_cache_test.go index b104f001cb..72c34763d7 100644 --- a/internal/painter/svg_cache_test.go +++ b/internal/painter/svg_cache_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" - "fyne.io/fyne/canvas" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" ) func TestSvgCacheGet(t *testing.T) { diff --git a/internal/painter/vector.go b/internal/painter/vector.go index ef1cf41ddb..e9130741fb 100644 --- a/internal/painter/vector.go +++ b/internal/painter/vector.go @@ -1,8 +1,8 @@ package painter import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" ) // VectorPad returns the number of additional points that should be added around a texture. diff --git a/internal/preferences.go b/internal/preferences.go index 802bb7bd8c..1032d4f68a 100644 --- a/internal/preferences.go +++ b/internal/preferences.go @@ -3,7 +3,7 @@ package internal import ( "sync" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // InMemoryPreferences provides an implementation of the fyne.Preferences API that is stored in memory. diff --git a/internal/repository/file.go b/internal/repository/file.go new file mode 100644 index 0000000000..8cba9fe4a9 --- /dev/null +++ b/internal/repository/file.go @@ -0,0 +1,299 @@ +package repository + +import ( + "io" + "io/ioutil" + "os" + "path" + "path/filepath" + "strings" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/storage/repository" +) + +// fileSchemePrefix is used for when we need a hard-coded version of "file://" +// for string processing +const fileSchemePrefix string = "file://" + +// declare conformance with repository types +var _ repository.Repository = (*FileRepository)(nil) +var _ repository.WritableRepository = (*FileRepository)(nil) +var _ repository.HierarchicalRepository = (*FileRepository)(nil) +var _ repository.ListableRepository = (*FileRepository)(nil) +var _ repository.MovableRepository = (*FileRepository)(nil) +var _ repository.CopyableRepository = (*FileRepository)(nil) + +var _ fyne.URIReadCloser = (*file)(nil) +var _ fyne.URIWriteCloser = (*file)(nil) + +type file struct { + *os.File + uri fyne.URI +} + +func (f *file) URI() fyne.URI { + return f.uri +} + +// FileRepository implements a simple wrapper around golang's filesystem +// interface libraries. It should be registered by the driver on platforms +// where it is appropriate to do so. +// +// This repository is suitable to handle the file:// scheme. +// +// Since: 2.0 +type FileRepository struct { +} + +// NewFileRepository creates a new FileRepository instance. +// The caller needs to call repository.Register() with the result of this function. +// +// Since: 2.0 +func NewFileRepository() *FileRepository { + return &FileRepository{} +} + +// Exists implements repository.Repository.Exists +// +// Since: 2.0 +func (r *FileRepository) Exists(u fyne.URI) (bool, error) { + p := u.Path() + + _, err := os.Stat(p) + ok := false + + if err == nil { + ok = true + } else if os.IsNotExist(err) { + err = nil + } + + return ok, err +} + +func openFile(uri fyne.URI, create bool) (*file, error) { + path := uri.Path() + var f *os.File + var err error + if create { + f, err = os.Create(path) // If it exists this will truncate which is what we wanted + } else { + f, err = os.Open(path) + } + return &file{File: f, uri: uri}, err +} + +// Reader implements repository.Repository.Reader +// +// Since: 2.0 +func (r *FileRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { + return openFile(u, false) +} + +// CanRead implements repository.Repository.CanRead +// +// Since: 2.0 +func (r *FileRepository) CanRead(u fyne.URI) (bool, error) { + f, err := os.OpenFile(u.Path(), os.O_RDONLY, 0666) + if err == nil { + f.Close() + } else { + + if os.IsPermission(err) { + return false, nil + } + + if os.IsNotExist(err) { + return false, nil + } + + return false, err + } + + return true, nil +} + +// Destroy implements repository.Repository.Destroy +func (r *FileRepository) Destroy(scheme string) { + // do nothing +} + +// Writer implements repository.WritableRepository.Writer +// +// Since: 2.0 +func (r *FileRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { + return openFile(u, true) +} + +// CanWrite implements repository.WritableRepository.CanWrite +// +// Since: 2.0 +func (r *FileRepository) CanWrite(u fyne.URI) (bool, error) { + f, err := os.OpenFile(u.Path(), os.O_WRONLY, 0666) + if err == nil { + f.Close() + } else { + + if os.IsPermission(err) { + return false, nil + } + + if os.IsNotExist(err) { + // We may need to do extra logic to check if the + // directory is writable, but presumably the + // IsPermission check covers this. + return true, nil + } + + return false, err + } + + return true, nil +} + +// Delete implements repository.WritableRepository.Delete +// +// Since: 2.0 +func (r *FileRepository) Delete(u fyne.URI) error { + return os.Remove(u.Path()) +} + +// Parent implements repository.HierarchicalRepository.Parent +// +// Since: 2.0 +func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { + s := u.String() + + // trim trailing slash + s = strings.TrimSuffix(s, "/") + + // trim the scheme + s = strings.TrimPrefix(s, fileSchemePrefix) + + // Completely empty URI with just a scheme + if len(s) == 0 { + return nil, repository.ErrURIRoot + } + + parent := "" + // use the system native path resolution + parent = filepath.Dir(s) + if parent[len(parent)-1] != filepath.Separator { + parent += "/" + } + + // only root is it's own parent + if filepath.Clean(parent) == filepath.Clean(s) { + return nil, repository.ErrURIRoot + } + + return storage.NewFileURI(parent), nil +} + +// Child implements repository.HierarchicalRepository.Child +// +// Since: 2.0 +func (r *FileRepository) Child(u fyne.URI, component string) (fyne.URI, error) { + newURI := u.Scheme() + "://" + u.Authority() + newURI += path.Join(u.Path(), component) + + // stick the query and fragment back on the end + if query := u.Query(); len(query) > 0 { + newURI += "?" + query + } + if fragment := u.Fragment(); len(fragment) > 0 { + newURI += "#" + fragment + } + + return storage.ParseURI(newURI) +} + +// List implements repository.ListableRepository.List() +// +// Since: 2.0 +func (r *FileRepository) List(u fyne.URI) ([]fyne.URI, error) { + + path := u.Path() + files, err := ioutil.ReadDir(path) + if err != nil { + return nil, err + } + + urilist := []fyne.URI{} + + for _, f := range files { + uri := storage.NewFileURI(filepath.Join(path, f.Name())) + urilist = append(urilist, uri) + } + + return urilist, nil +} + +// CreateListable implements repository.ListableRepository.CreateListable. +func (r *FileRepository) CreateListable(u fyne.URI) error { + path := u.Path() + err := os.Mkdir(path, 0755) + return err +} + +// CanList implements repository.ListableRepository.CanList() +// +// Since: 2.0 +func (r *FileRepository) CanList(u fyne.URI) (bool, error) { + p := u.Path() + info, err := os.Stat(p) + + if err != nil { + if os.IsNotExist(err) { + return false, nil + } + return false, err + } + + if !info.IsDir() { + return false, nil + } + + // We know it is a directory, but we don't know if we can read it, so + // we'll just try to do so and see if we get a permissions error. + f, err := os.Open(p) + if err == nil { + _, err = f.Readdir(1) + f.Close() + } + + if err != nil && err != io.EOF { + return false, err + } + + if os.IsPermission(err) { + return false, nil + } + + // it is a directory, and checking the permissions did not error out + return true, nil +} + +// Copy implements repository.CopyableRepository.Copy() +// +// Since: 2.0 +func (r *FileRepository) Copy(source, destination fyne.URI) error { + // NOTE: as far as I can tell, golang does not have an optimized Copy + // function - everything I can find on the 'net suggests doing more + // or less the equivalent of GenericCopy(), hence why that is used. + + return repository.GenericCopy(source, destination) +} + +// Move implements repository.MovableRepository.Move() +// +// Since: 2.0 +func (r *FileRepository) Move(source, destination fyne.URI) error { + // NOTE: as far as I can tell, golang does not have an optimized Move + // function - everything I can find on the 'net suggests doing more + // or less the equivalent of GenericMove(), hence why that is used. + + return repository.GenericMove(source, destination) +} diff --git a/internal/repository/file_test.go b/internal/repository/file_test.go new file mode 100644 index 0000000000..bc78fbaa26 --- /dev/null +++ b/internal/repository/file_test.go @@ -0,0 +1,499 @@ +package repository + +import ( + "io/ioutil" + "os" + "path" + "path/filepath" + "runtime" + "testing" + + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/storage/repository" + + "github.com/stretchr/testify/assert" +) + +func checkExistance(path string) bool { + _, err := os.Stat(path) + if err == nil { + return true + } + if os.IsNotExist(err) { + return false + } + return false +} + +func TestFileRepositoryRegistration(t *testing.T) { + f := NewFileRepository() + repository.Register("file", f) + + // this should never fail, and we assume it doesn't in other tests here + // for brevity + foo, err := storage.ParseURI("file:///foo") + assert.Nil(t, err) + + // make sure we get the same repo back + repo, err := repository.ForURI(foo) + assert.Nil(t, err) + assert.Equal(t, f, repo) +} + +func TestFileRepositoryExists(t *testing.T) { + dir, err := ioutil.TempDir("", "FyneInternalRepositoryFileTest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + existsPath := path.Join(dir, "exists") + notExistsPath := path.Join(dir, "notExists") + + err = ioutil.WriteFile(existsPath, []byte{1, 2, 3, 4}, 0755) + if err != nil { + t.Fatal(err) + } + + ex, err := storage.Exists(storage.NewFileURI(existsPath)) + assert.Nil(t, err) + assert.True(t, ex) + + ex, err = storage.Exists(storage.NewFileURI(notExistsPath)) + assert.Nil(t, err) + assert.False(t, ex) +} + +func TestFileRepositoryReader(t *testing.T) { + // Set up a temporary directory. + dir, err := ioutil.TempDir("", "FyneInternalRepositoryFileTest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + // Create some files to test with. + fooPath := path.Join(dir, "foo") + barPath := path.Join(dir, "bar") + bazPath := path.Join(dir, "baz") + err = ioutil.WriteFile(fooPath, []byte{}, 0755) + if err != nil { + t.Fatal(err) + } + err = ioutil.WriteFile(barPath, []byte{1, 2, 3}, 0755) + if err != nil { + t.Fatal(err) + } + + // Set up our repository - it's OK if we already registered it... + f := NewFileRepository() + repository.Register("file", f) + + // ...and some URIs - we know that they will not fail parsing + foo := storage.NewFileURI(fooPath) + bar := storage.NewFileURI(barPath) + baz := storage.NewFileURI(bazPath) + + // Make sure we can read the empty file. + fooReader, err := storage.Reader(foo) + assert.Nil(t, err) + fooData, err := ioutil.ReadAll(fooReader) + assert.Equal(t, []byte{}, fooData) + assert.Nil(t, err) + + // Make sure we can read the file with data. + barReader, err := storage.Reader(bar) + assert.Nil(t, err) + barData, err := ioutil.ReadAll(barReader) + assert.Equal(t, []byte{1, 2, 3}, barData) + assert.Nil(t, err) + + // Make sure we get an error if the file doesn't exist. + _, err = storage.Reader(baz) + assert.NotNil(t, err) + + // Also test that CanRead returns the expected results. + fooCanRead, err := storage.CanRead(foo) + assert.True(t, fooCanRead) + assert.Nil(t, err) + + barCanRead, err := storage.CanRead(bar) + assert.True(t, barCanRead) + assert.Nil(t, err) + + bazCanRead, err := storage.CanRead(baz) + assert.False(t, bazCanRead) + assert.Nil(t, err) +} + +func TestFileRepositoryWriter(t *testing.T) { + // Set up a temporary directory. + dir, err := ioutil.TempDir("", "FyneInternalRepositoryFileTest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + // Create some files to test with. + fooPath := path.Join(dir, "foo") + barPath := path.Join(dir, "bar") + bazPath := path.Join(dir, "baz") + spamHamPath := path.Join(dir, "spam", "ham") + err = ioutil.WriteFile(fooPath, []byte{}, 0755) + if err != nil { + t.Fatal(err) + } + err = ioutil.WriteFile(barPath, []byte{1, 2, 3}, 0755) + if err != nil { + t.Fatal(err) + } + + // Set up our repository - it's OK if we already registered it... + f := NewFileRepository() + repository.Register("file", f) + + // ...and some URIs - we know that they will not fail parsing + foo := storage.NewFileURI(fooPath) + bar := storage.NewFileURI(barPath) + baz := storage.NewFileURI(bazPath) + spamHam := storage.NewFileURI(spamHamPath) + + // Make sure that spamHam errors, since writing to a non-existant + // parent directory should be an error. + spamHamWriter, err := storage.Writer(spamHam) + assert.NotNil(t, err) + if err == nil { + // Keep this from bodging up the Windows tests if this is + // created in error, and then we try to delete it while there + // is an open handle. + spamHamWriter.Close() + } + + // write some data and assert there are no errors + fooWriter, err := storage.Writer(foo) + assert.Nil(t, err) + assert.NotNil(t, fooWriter) + + barWriter, err := storage.Writer(bar) + assert.Nil(t, err) + assert.NotNil(t, barWriter) + + bazWriter, err := storage.Writer(baz) + assert.Nil(t, err) + assert.NotNil(t, bazWriter) + + n, err := fooWriter.Write([]byte{1, 2, 3, 4, 5}) + assert.Nil(t, err) + assert.Equal(t, 5, n) + + n, err = barWriter.Write([]byte{6, 7, 8, 9}) + assert.Nil(t, err) + assert.Equal(t, 4, n) + + n, err = bazWriter.Write([]byte{5, 4, 3, 2, 1, 0}) + assert.Nil(t, err) + assert.Equal(t, 6, n) + + fooWriter.Close() + barWriter.Close() + bazWriter.Close() + + // now make sure we can read the data back correctly + fooReader, err := storage.Reader(foo) + assert.Nil(t, err) + fooData, err := ioutil.ReadAll(fooReader) + assert.Equal(t, []byte{1, 2, 3, 4, 5}, fooData) + assert.Nil(t, err) + + barReader, err := storage.Reader(bar) + assert.Nil(t, err) + barData, err := ioutil.ReadAll(barReader) + assert.Equal(t, []byte{6, 7, 8, 9}, barData) + assert.Nil(t, err) + + bazReader, err := storage.Reader(baz) + assert.Nil(t, err) + bazData, err := ioutil.ReadAll(bazReader) + assert.Equal(t, []byte{5, 4, 3, 2, 1, 0}, bazData) + assert.Nil(t, err) + + // close the readers, since Windows won't let us delete things with + // open handles to them + fooReader.Close() + barReader.Close() + bazReader.Close() + + // now let's test deletion + err = storage.Delete(foo) + assert.Nil(t, err) + + err = storage.Delete(bar) + assert.Nil(t, err) + + err = storage.Delete(baz) + assert.Nil(t, err) + + fooExists, err := storage.Exists(foo) + assert.False(t, fooExists) + assert.Nil(t, err) + + barExists, err := storage.Exists(bar) + assert.False(t, barExists) + assert.Nil(t, err) + + bazExists, err := storage.Exists(baz) + assert.False(t, bazExists) + assert.Nil(t, err) +} + +func TestFileRepositoryCanWrite(t *testing.T) { + // Set up a temporary directory. + dir, err := ioutil.TempDir("", "FyneInternalRepositoryFileTest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + // Create some files to test with. + fooPath := path.Join(dir, "foo") + barPath := path.Join(dir, "bar") + bazPath := path.Join(dir, "baz") + err = ioutil.WriteFile(fooPath, []byte{}, 0755) + if err != nil { + t.Fatal(err) + } + err = ioutil.WriteFile(barPath, []byte{1, 2, 3}, 0755) + if err != nil { + t.Fatal(err) + } + + // Set up our repository - it's OK if we already registered it... + f := NewFileRepository() + repository.Register("file", f) + + // ...and some URIs - we know that they will not fail parsing + foo := storage.NewFileURI(fooPath) + bar := storage.NewFileURI(barPath) + baz := storage.NewFileURI(bazPath) + + fooCanWrite, err := storage.CanWrite(foo) + assert.True(t, fooCanWrite) + assert.Nil(t, err) + + barCanWrite, err := storage.CanWrite(bar) + assert.True(t, barCanWrite) + assert.Nil(t, err) + + bazCanWrite, err := storage.CanWrite(baz) + assert.True(t, bazCanWrite) + assert.Nil(t, err) +} + +func TestFileRepositoryParent(t *testing.T) { + // Set up our repository - it's OK if we already registered it. + f := NewFileRepository() + repository.Register("file", f) + + // note the trailing slashes are significant, as they tend to belie a + // directory + + parent, err := storage.Parent(storage.NewURI("file:///foo/bar/baz")) + assert.Nil(t, err) + assert.Equal(t, "file:///foo/bar/", parent.String()) + + parent, err = storage.Parent(storage.NewFileURI("/foo/bar/baz/")) + assert.Nil(t, err) + assert.Equal(t, "file:///foo/bar/", parent.String()) + + parent, err = storage.Parent(storage.NewURI("file://C:/foo/bar/baz/")) + assert.Nil(t, err) + assert.Equal(t, "file://C:/foo/bar/", parent.String()) + + if runtime.GOOS == "windows" { + // Only the Windows version of filepath will know how to handle + // backslashes. + uri := storage.NewURI("file://C:\\foo\\bar\\baz\\") + assert.Equal(t, "file://C:/foo/bar/baz/", uri.String()) + uri = storage.NewFileURI("C:\\foo\\bar\\baz\\") + assert.Equal(t, "file://C:/foo/bar/baz/", uri.String()) + + parent, err = storage.Parent(uri) + assert.Nil(t, err) + assert.Equal(t, "file://C:/foo/bar/", parent.String()) + } + + _, err = storage.Parent(storage.NewURI("file:///")) + assert.Equal(t, repository.ErrURIRoot, err) + + if runtime.GOOS == "windows" { + // This is only an error under Windows, on *NIX this is a + // relative path to a directory named "C:", which is completely + // valid. + + // This should cause an error, since this is a Windows-style + // path and thus we can't get the parent of a drive letter. + _, err = storage.Parent(storage.NewURI("file://C:/")) + assert.Equal(t, repository.ErrURIRoot, err) + } + + // Windows supports UNIX-style paths. /C:/ is also a valid path. + parent, err = storage.Parent(storage.NewURI("file:///C:/")) + assert.Nil(t, err) + assert.Equal(t, "file:///", parent.String()) +} + +func TestFileRepositoryChild(t *testing.T) { + // Set up our repository - it's OK if we already registered it. + f := NewFileRepository() + repository.Register("file", f) + + p, _ := storage.Child(storage.NewURI("file:///foo/bar"), "baz") + assert.Equal(t, "file:///foo/bar/baz", p.String()) + + p, _ = storage.Child(storage.NewURI("file:///foo/bar/"), "baz") + assert.Equal(t, "file:///foo/bar/baz", p.String()) + + if runtime.GOOS == "windows" { + // Only the Windows version of filepath will know how to handle + // backslashes. + uri := storage.NewURI("file://C:\\foo\\bar\\") + assert.Equal(t, "file://C:/foo/bar/", uri.String()) + + p, _ = storage.Child(uri, "baz") + assert.Equal(t, "file://C:/foo/bar/baz", p.String()) + } +} + +func TestFileRepositoryCopy(t *testing.T) { + // Set up a temporary directory. + dir, err := ioutil.TempDir("", "FyneInternalRepositoryFileTest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + // Create some files to test with. + fooPath := path.Join(dir, "foo") + barPath := path.Join(dir, "bar") + err = ioutil.WriteFile(fooPath, []byte{1, 2, 3, 4, 5}, 0755) + if err != nil { + t.Fatal(err) + } + + foo := storage.NewFileURI(fooPath) + bar := storage.NewFileURI(barPath) + + err = storage.Copy(foo, bar) + assert.Nil(t, err) + + fooData, err := ioutil.ReadFile(fooPath) + assert.Nil(t, err) + + barData, err := ioutil.ReadFile(barPath) + assert.Nil(t, err) + + assert.Equal(t, fooData, barData) +} + +func TestFileRepositoryMove(t *testing.T) { + // Set up a temporary directory. + dir, err := ioutil.TempDir("", "FyneInternalRepositoryFileTest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + // Create some files to test with. + fooPath := path.Join(dir, "foo") + barPath := path.Join(dir, "bar") + err = ioutil.WriteFile(fooPath, []byte{1, 2, 3, 4, 5}, 0755) + if err != nil { + t.Fatal(err) + } + + foo := storage.NewFileURI(fooPath) + bar := storage.NewFileURI(barPath) + + err = storage.Move(foo, bar) + assert.Nil(t, err) + + barData, err := ioutil.ReadFile(barPath) + assert.Nil(t, err) + + assert.Equal(t, []byte{1, 2, 3, 4, 5}, barData) + + // Make sure that the source doesn't exist anymore. + ex, err := storage.Exists(foo) + assert.Nil(t, err) + assert.False(t, ex) +} + +func TestFileRepositoryListing(t *testing.T) { + // Set up a temporary directory. + dir, err := ioutil.TempDir("", "FyneInternalRepositoryFileTest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + // Create some files to tests with. + fooPath := path.Join(dir, "foo") + os.Mkdir(fooPath, 0755) + os.Mkdir(path.Join(fooPath, "bar"), 0755) + os.Mkdir(path.Join(fooPath, "baz"), 0755) + os.Mkdir(path.Join(fooPath, "baz", "quux"), 0755) + + foo := storage.NewFileURI(fooPath) + + canList, err := storage.CanList(foo) + assert.Nil(t, err) + assert.True(t, canList) + + // also check the empty dir + childDir := storage.NewFileURI(path.Join(fooPath, "baz", "quux")) + canList, err = storage.CanList(childDir) + assert.Nil(t, err) + assert.True(t, canList) + + listing, err := storage.List(foo) + assert.Nil(t, err) + assert.Equal(t, 2, len(listing)) + stringListing := []string{} + for _, u := range listing { + stringListing = append(stringListing, u.String()) + } + assert.ElementsMatch(t, []string{"file://" + filepath.ToSlash(path.Join(dir, "foo", "bar")), "file://" + filepath.ToSlash(path.Join(dir, "foo", "baz"))}, stringListing) +} + +func TestFileRepositoryCreateListable(t *testing.T) { + // Set up a temporary directory. + dir, err := ioutil.TempDir("", "FyneInternalRepositoryFileTest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + f := NewFileRepository() + repository.Register("file", f) + + fooPath := path.Join(dir, "foo") + fooBarPath := path.Join(dir, "foo", "bar") + foo := storage.NewFileURI(fooPath) + fooBar := storage.NewFileURI(fooBarPath) + + // Creating a dir with no parent should fail + err = storage.CreateListable(fooBar) + assert.NotNil(t, err) + + // Creating foo should work though + err = storage.CreateListable(foo) + assert.Nil(t, err) + + // and now we should be able to create fooBar + err = storage.CreateListable(fooBar) + assert.Nil(t, err) + + // make sure the OS thinks these dirs really exist + assert.True(t, checkExistance(fooPath)) + assert.True(t, checkExistance(fooBarPath)) +} diff --git a/internal/repository/memory.go b/internal/repository/memory.go new file mode 100644 index 0000000000..25ac22886c --- /dev/null +++ b/internal/repository/memory.go @@ -0,0 +1,330 @@ +package repository + +import ( + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/storage/repository" + + "fmt" + "io" + "strings" +) + +// declare conformance to interfaces +var _ io.ReadCloser = (*nodeReaderWriter)(nil) +var _ io.WriteCloser = (*nodeReaderWriter)(nil) +var _ fyne.URIReadCloser = (*nodeReaderWriter)(nil) +var _ fyne.URIWriteCloser = (*nodeReaderWriter)(nil) + +// declare conformance with repository types +var _ repository.Repository = (*InMemoryRepository)(nil) +var _ repository.WritableRepository = (*InMemoryRepository)(nil) +var _ repository.HierarchicalRepository = (*InMemoryRepository)(nil) +var _ repository.CopyableRepository = (*InMemoryRepository)(nil) +var _ repository.MovableRepository = (*InMemoryRepository)(nil) +var _ repository.ListableRepository = (*InMemoryRepository)(nil) + +// nodeReaderWriter allows reading or writing to elements in a InMemoryRepository +type nodeReaderWriter struct { + path string + repo *InMemoryRepository + writing bool + readCursor int + writeCursor int +} + +// InMemoryRepository implements an in-memory version of the +// repository.Repository type. It is useful for writing test cases, and may +// also be of use as a template for people wanting to implement their own +// "virtual repository". In future, we may consider moving this into the public +// API. +// +// Because of it's design, this repository has several quirks: +// +// * The Parent() of a path that exists does not necessarily exist +// +// * Listing takes O(number of extant paths in the repository), rather than +// O(number of children of path being listed). +// +// This repository is not designed to be particularly fast or robust, but +// rather to be simple and easy to read. If you need performance, look +// elsewhere. +// +// Since: 2.0 +type InMemoryRepository struct { + // Data is exposed to allow tests to directly insert their own data + // without having to go through the API + Data map[string][]byte + + scheme string +} + +// Read implements io.Reader.Read +func (n *nodeReaderWriter) Read(p []byte) (int, error) { + + // first make sure the requested path actually exists + data, ok := n.repo.Data[n.path] + if !ok { + return 0, fmt.Errorf("path '%s' not present in InMemoryRepository", n.path) + } + + // copy it into p - we maintain counts since len(data) may be smaller + // than len(p) + count := 0 + j := 0 // index into p + for ; (j < len(p)) && (n.readCursor < len(data)); n.readCursor++ { + p[j] = data[n.readCursor] + count++ + j++ + } + + // generate EOF if needed + var err error = nil + if n.readCursor >= len(data) { + err = io.EOF + } + + return count, err +} + +// Close implements io.Closer.Close +func (n *nodeReaderWriter) Close() error { + n.readCursor = 0 + n.writeCursor = 0 + n.writing = false + return nil +} + +// Write implements io.Writer.Write +// +// This implementation automatically creates the path n.path if it does not +// exist. If it does exist, it is overwritten. +func (n *nodeReaderWriter) Write(p []byte) (int, error) { + + // guarantee that the path exists + _, ok := n.repo.Data[n.path] + if !ok { + n.repo.Data[n.path] = []byte{} + } + + // overwrite the file if we haven't already started writing to it + if !n.writing { + n.repo.Data[n.path] = make([]byte, 0) + n.writing = true + } + + // copy the data into the node buffer + count := 0 + start := n.writeCursor + for ; n.writeCursor < start+len(p); n.writeCursor++ { + // extend the file if needed + if len(n.repo.Data) < n.writeCursor+len(p) { + n.repo.Data[n.path] = append(n.repo.Data[n.path], 0) + } + n.repo.Data[n.path][n.writeCursor] = p[n.writeCursor-start] + count++ + } + + return count, nil +} + +// Name implements fyne.URIReadCloser.URI and fyne.URIWriteCloser.URI +func (n *nodeReaderWriter) URI() fyne.URI { + + // discarding the error because this should never fail + u, _ := storage.ParseURI(n.repo.scheme + "://" + n.path) + + return u +} + +// NewInMemoryRepository creates a new InMemoryRepository instance. It must be +// given the scheme it is registered for. The caller needs to call +// repository.Register() on the result of this function. +// +// Since: 2.0 +func NewInMemoryRepository(scheme string) *InMemoryRepository { + return &InMemoryRepository{ + Data: make(map[string][]byte), + scheme: scheme, + } +} + +// Exists implements repository.Repository.Exists +// +// Since: 2.0 +func (m *InMemoryRepository) Exists(u fyne.URI) (bool, error) { + path := u.Path() + if path == "" { + return false, fmt.Errorf("invalid path '%s'", path) + } + + _, ok := m.Data[path] + return ok, nil +} + +// Reader implements repository.Repository.Reader +// +// Since: 2.0 +func (m *InMemoryRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { + path := u.Path() + + if path == "" { + return nil, fmt.Errorf("invalid path '%s'", path) + } + + _, ok := m.Data[path] + if !ok { + return nil, fmt.Errorf("no such path '%s' in InMemoryRepository", path) + } + + return &nodeReaderWriter{path: path, repo: m}, nil +} + +// CanRead implements repository.Repository.CanRead +// +// Since: 2.0 +func (m *InMemoryRepository) CanRead(u fyne.URI) (bool, error) { + path := u.Path() + if path == "" { + return false, fmt.Errorf("invalid path '%s'", path) + } + + _, ok := m.Data[path] + return ok, nil +} + +// Destroy implements repository.Repository.Destroy +func (m *InMemoryRepository) Destroy(scheme string) { + // do nothing +} + +// Writer implements repository.WritableRepository.Writer +// +// Since: 2.0 +func (m *InMemoryRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { + path := u.Path() + if path == "" { + return nil, fmt.Errorf("invalid path '%s'", path) + } + + return &nodeReaderWriter{path: path, repo: m}, nil +} + +// CanWrite implements repository.WritableRepository.CanWrite +// +// Since: 2.0 +func (m *InMemoryRepository) CanWrite(u fyne.URI) (bool, error) { + if p := u.Path(); p == "" { + return false, fmt.Errorf("invalid path '%s'", p) + } + + return true, nil +} + +// Delete implements repository.WritableRepository.Delete +// +// Since: 2.0 +func (m *InMemoryRepository) Delete(u fyne.URI) error { + path := u.Path() + _, ok := m.Data[path] + if ok { + delete(m.Data, path) + } + + return nil +} + +// Parent implements repository.HierarchicalRepository.Parent +// +// Since: 2.0 +func (m *InMemoryRepository) Parent(u fyne.URI) (fyne.URI, error) { + return repository.GenericParent(u) +} + +// Child implements repository.HierarchicalRepository.Child +// +// Since: 2.0 +func (m *InMemoryRepository) Child(u fyne.URI, component string) (fyne.URI, error) { + return repository.GenericChild(u, component) +} + +// Copy implements repository.CopyableRepository.Copy() +// +// Since: 2.0 +func (m *InMemoryRepository) Copy(source, destination fyne.URI) error { + return repository.GenericCopy(source, destination) +} + +// Move implements repository.MovableRepository.Move() +// +// Since: 2.0 +func (m *InMemoryRepository) Move(source, destination fyne.URI) error { + return repository.GenericMove(source, destination) +} + +// CanList implements repository.ListableRepository.CanList() +// +// Since: 2.0 +func (m *InMemoryRepository) CanList(u fyne.URI) (bool, error) { + return m.Exists(u) +} + +// List implements repository.ListableRepository.List() +// +// Since: 2.0 +func (m *InMemoryRepository) List(u fyne.URI) ([]fyne.URI, error) { + // Get the prefix, and make sure it ends with a path separator so that + // HasPrefix() will only find things that are children of it - this + // solves the edge case where you have say '/foo/bar' and + // '/foo/barbaz'. + prefix := u.Path() + if prefix[len(prefix)-1] != '/' { + prefix = prefix + "/" + } + + prefixSplit := strings.Split(prefix, "/") + prefixSplitLen := len(prefixSplit) + + // Now we can simply loop over all the paths and find the ones with an + // appropriate prefix, then eliminate those with too many path + // components. + listing := []fyne.URI{} + for p := range m.Data { + // We are going to compare ncomp with the number of elements in + // prefixSplit, which is guaranteed to have a trailing slash, + // so we want to also make pSplit be counted in ncomp like it + // does not have one. + pSplit := strings.Split(p, "/") + ncomp := len(pSplit) + if p[len(p)-1] == '/' { + ncomp-- + } + + if strings.HasPrefix(p, prefix) && ncomp == prefixSplitLen { + uri, err := storage.ParseURI(m.scheme + "://" + p) + if err != nil { + return nil, err + } + + listing = append(listing, uri) + } + } + + return listing, nil +} + +// CreateListable impelements repository.ListableRepository.CreateListable. +// +// Since: 2.0 +func (m *InMemoryRepository) CreateListable(u fyne.URI) error { + ex, err := m.Exists(u) + if err != nil { + return err + } + path := u.Path() + if ex { + return fmt.Errorf("cannot create '%s' as a listable path because it already exists", path) + } + m.Data[path] = []byte{} + return nil +} diff --git a/internal/repository/memory_test.go b/internal/repository/memory_test.go new file mode 100644 index 0000000000..2f3047b96b --- /dev/null +++ b/internal/repository/memory_test.go @@ -0,0 +1,353 @@ +package repository + +import ( + "io/ioutil" + "testing" + + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/storage/repository" + + "github.com/stretchr/testify/assert" +) + +func TestInMemoryRepositoryRegistration(t *testing.T) { + m := NewInMemoryRepository("mem") + repository.Register("mem", m) + + // this should never fail, and we assume it doesn't in other tests here + // for brevity + foo, err := storage.ParseURI("mem://foo") + assert.Nil(t, err) + + // make sure we get the same repo back + repo, err := repository.ForURI(foo) + assert.Nil(t, err) + assert.Equal(t, m, repo) + + // test that re-registration also works + m2 := NewInMemoryRepository("mem") + repository.Register("mem", m2) + assert.False(t, m == m2) // this is explicitly intended to be pointer comparison + repo, err = repository.ForURI(foo) + assert.Nil(t, err) + assert.Equal(t, m2, repo) +} + +func TestInMemoryRepositoryParsing(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewInMemoryRepository("mem") + repository.Register("mem", m) + + // since we assume in some other places that these can be parsed + // without error, lets also explicitly test to make sure + + foo, err := storage.ParseURI("mem:///foo") + assert.Nil(t, err) + assert.NotNil(t, foo) + + bar, err := storage.ParseURI("mem:///bar") + assert.Nil(t, err) + assert.NotNil(t, bar) + + baz, _ := storage.ParseURI("mem:///baz") + assert.Nil(t, err) + assert.NotNil(t, baz) +} + +func TestInMemoryRepositoryExists(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewInMemoryRepository("mem") + repository.Register("mem", m) + m.Data["/foo"] = []byte{} + m.Data["/bar"] = []byte{1, 2, 3} + + // and some URIs - we know that they will not fail parsing + foo, _ := storage.ParseURI("mem:///foo") + bar, _ := storage.ParseURI("mem:///bar") + baz, _ := storage.ParseURI("mem:///baz") + + fooExists, err := storage.Exists(foo) + assert.True(t, fooExists) + assert.Nil(t, err) + + barExists, err := storage.Exists(bar) + assert.True(t, barExists) + assert.Nil(t, err) + + bazExists, err := storage.Exists(baz) + assert.False(t, bazExists) + assert.Nil(t, err) +} + +func TestInMemoryRepositoryReader(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewInMemoryRepository("mem") + repository.Register("mem", m) + m.Data["/foo"] = []byte{} + m.Data["/bar"] = []byte{1, 2, 3} + + // and some URIs - we know that they will not fail parsing + foo, _ := storage.ParseURI("mem:///foo") + bar, _ := storage.ParseURI("mem:///bar") + baz, _ := storage.ParseURI("mem:///baz") + + fooReader, err := storage.Reader(foo) + assert.Nil(t, err) + fooData, err := ioutil.ReadAll(fooReader) + assert.Equal(t, []byte{}, fooData) + assert.Nil(t, err) + + barReader, err := storage.Reader(bar) + assert.Nil(t, err) + barData, err := ioutil.ReadAll(barReader) + assert.Equal(t, []byte{1, 2, 3}, barData) + assert.Nil(t, err) + + bazReader, err := storage.Reader(baz) + assert.Nil(t, bazReader) + assert.NotNil(t, err) +} + +func TestInMemoryRepositoryCanRead(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewInMemoryRepository("mem") + repository.Register("mem", m) + m.Data["/foo"] = []byte{} + m.Data["/bar"] = []byte{1, 2, 3} + + // and some URIs - we know that they will not fail parsing + foo, _ := storage.ParseURI("mem:///foo") + bar, _ := storage.ParseURI("mem:///bar") + baz, _ := storage.ParseURI("mem:///baz") + + fooCanRead, err := storage.CanRead(foo) + assert.True(t, fooCanRead) + assert.Nil(t, err) + + barCanRead, err := storage.CanRead(bar) + assert.True(t, barCanRead) + assert.Nil(t, err) + + bazCanRead, err := storage.CanRead(baz) + assert.False(t, bazCanRead) + assert.Nil(t, err) +} + +func TestInMemoryRepositoryWriter(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewInMemoryRepository("mem") + repository.Register("mem", m) + m.Data["/foo"] = []byte{} + m.Data["/bar"] = []byte{1, 2, 3} + + // and some URIs - we know that they will not fail parsing + foo, _ := storage.ParseURI("mem:///foo") + bar, _ := storage.ParseURI("mem:///bar") + baz, _ := storage.ParseURI("mem:///baz") + + // write some data and assert there are no errors + fooWriter, err := storage.Writer(foo) + assert.Nil(t, err) + assert.NotNil(t, fooWriter) + + barWriter, err := storage.Writer(bar) + assert.Nil(t, err) + assert.NotNil(t, barWriter) + + bazWriter, err := storage.Writer(baz) + assert.Nil(t, err) + assert.NotNil(t, bazWriter) + + n, err := fooWriter.Write([]byte{1, 2, 3, 4, 5}) + assert.Nil(t, err) + assert.Equal(t, 5, n) + + n, err = barWriter.Write([]byte{6, 7, 8, 9}) + assert.Nil(t, err) + assert.Equal(t, 4, n) + + n, err = bazWriter.Write([]byte{5, 4, 3, 2, 1, 0}) + assert.Nil(t, err) + assert.Equal(t, 6, n) + + fooWriter.Close() + barWriter.Close() + bazWriter.Close() + + // now make sure we can read the data back correctly + fooReader, err := storage.Reader(foo) + assert.Nil(t, err) + fooData, err := ioutil.ReadAll(fooReader) + assert.Equal(t, []byte{1, 2, 3, 4, 5}, fooData) + assert.Nil(t, err) + + barReader, err := storage.Reader(bar) + assert.Nil(t, err) + barData, err := ioutil.ReadAll(barReader) + assert.Equal(t, []byte{6, 7, 8, 9}, barData) + assert.Nil(t, err) + + bazReader, err := storage.Reader(baz) + assert.Nil(t, err) + bazData, err := ioutil.ReadAll(bazReader) + assert.Equal(t, []byte{5, 4, 3, 2, 1, 0}, bazData) + assert.Nil(t, err) + + // now let's test deletion + err = storage.Delete(foo) + assert.Nil(t, err) + + err = storage.Delete(bar) + assert.Nil(t, err) + + err = storage.Delete(baz) + assert.Nil(t, err) + + fooExists, err := storage.Exists(foo) + assert.False(t, fooExists) + assert.Nil(t, err) + + barExists, err := storage.Exists(bar) + assert.False(t, barExists) + assert.Nil(t, err) + + bazExists, err := storage.Exists(baz) + assert.False(t, bazExists) + assert.Nil(t, err) + +} + +func TestInMemoryRepositoryCanWrite(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewInMemoryRepository("mem") + repository.Register("mem", m) + m.Data["/foo"] = []byte{} + m.Data["/bar"] = []byte{1, 2, 3} + + // and some URIs - we know that they will not fail parsing + foo, _ := storage.ParseURI("mem:///foo") + bar, _ := storage.ParseURI("mem:///bar") + baz, _ := storage.ParseURI("mem:///baz") + + fooCanWrite, err := storage.CanWrite(foo) + assert.True(t, fooCanWrite) + assert.Nil(t, err) + + barCanWrite, err := storage.CanWrite(bar) + assert.True(t, barCanWrite) + assert.Nil(t, err) + + bazCanWrite, err := storage.CanWrite(baz) + assert.True(t, bazCanWrite) + assert.Nil(t, err) +} + +func TestInMemoryRepositoryParent(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewInMemoryRepository("mem") + repository.Register("mem", m) + m.Data["/foo/bar/baz"] = []byte{} + + // and some URIs - we know that they will not fail parsing + foo, _ := storage.ParseURI("mem:///foo/bar/baz") + fooExpectedParent, _ := storage.ParseURI("mem:///foo/bar") + fooExists, err := storage.Exists(foo) + assert.True(t, fooExists) + assert.Nil(t, err) + + fooParent, err := storage.Parent(foo) + assert.Nil(t, err) + assert.Equal(t, fooExpectedParent.String(), fooParent.String()) +} + +func TestInMemoryRepositoryChild(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewInMemoryRepository("mem") + repository.Register("mem", m) + + // and some URIs - we know that they will not fail parsing + foo, _ := storage.ParseURI("mem:///foo/bar/baz") + fooExpectedChild, _ := storage.ParseURI("mem:///foo/bar/baz/quux") + + fooChild, err := storage.Child(foo, "quux") + assert.Nil(t, err) + assert.Equal(t, fooExpectedChild.String(), fooChild.String()) +} + +func TestInMemoryRepositoryCopy(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewInMemoryRepository("mem") + repository.Register("mem", m) + m.Data["/foo"] = []byte{1, 2, 3} + + foo, _ := storage.ParseURI("mem:///foo") + bar, _ := storage.ParseURI("mem:///bar") + + err := storage.Copy(foo, bar) + assert.Nil(t, err) + + assert.Equal(t, m.Data["/foo"], m.Data["/bar"]) +} + +func TestInMemoryRepositoryMove(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewInMemoryRepository("mem") + repository.Register("mem", m) + m.Data["/foo"] = []byte{1, 2, 3} + + foo, _ := storage.ParseURI("mem:///foo") + bar, _ := storage.ParseURI("mem:///bar") + + err := storage.Move(foo, bar) + assert.Nil(t, err) + + assert.Equal(t, []byte{1, 2, 3}, m.Data["/bar"]) + + exists, err := m.Exists(foo) + assert.Nil(t, err) + assert.False(t, exists) +} + +func TestInMemoryRepositoryListing(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewInMemoryRepository("mem") + repository.Register("mem", m) + m.Data["/foo"] = []byte{1, 2, 3} + m.Data["/foo/bar"] = []byte{1, 2, 3} + m.Data["/foo/baz/"] = []byte{1, 2, 3} + m.Data["/foo/baz/quux"] = []byte{1, 2, 3} + + foo, _ := storage.ParseURI("mem:///foo") + + canList, err := storage.CanList(foo) + assert.Nil(t, err) + assert.True(t, canList) + + listing, err := storage.List(foo) + assert.Nil(t, err) + stringListing := []string{} + for _, u := range listing { + stringListing = append(stringListing, u.String()) + } + assert.ElementsMatch(t, []string{"mem:///foo/bar", "mem:///foo/baz/"}, stringListing) +} + +func TestInMemoryRepositoryCreateListable(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewInMemoryRepository("mem") + repository.Register("mem", m) + + foo, _ := storage.ParseURI("mem:///foo") + + err := storage.CreateListable(foo) + assert.Nil(t, err) + + assert.Equal(t, m.Data["/foo"], []byte{}) + + // trying to create something we already created should fail + err = storage.CreateListable(foo) + assert.NotNil(t, err) + + // NOTE: creating an InMemoryRepository path with a non-extant parent + // is specifically not an error, so that case is not tested. +} diff --git a/internal/scale.go b/internal/scale.go index a56a692ed8..eac2021c0e 100644 --- a/internal/scale.go +++ b/internal/scale.go @@ -3,7 +3,7 @@ package internal import ( "math" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // ScaleInt converts a fyne coordinate in the given canvas to a screen coordinate diff --git a/internal/test/util_test.go b/internal/test/util_test.go index 9477ad4e74..938046b370 100644 --- a/internal/test/util_test.go +++ b/internal/test/util_test.go @@ -13,8 +13,8 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/image/font" - "fyne.io/fyne/internal/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2/internal/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/internal/widget/base.go b/internal/widget/base.go index c01398ed95..3b424cfb5e 100644 --- a/internal/widget/base.go +++ b/internal/widget/base.go @@ -3,9 +3,9 @@ package widget import ( "sync" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/cache" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/cache" ) // Base is a simple base widget for internal use. diff --git a/internal/widget/base_renderer.go b/internal/widget/base_renderer.go index 7e35f92938..f29799ddd4 100644 --- a/internal/widget/base_renderer.go +++ b/internal/widget/base_renderer.go @@ -1,6 +1,6 @@ package widget -import "fyne.io/fyne" +import "fyne.io/fyne/v2" // BaseRenderer is a renderer base providing the most common implementations of a part of the // widget.Renderer interface. diff --git a/internal/widget/overlay_container.go b/internal/widget/overlay_container.go index f068111841..1ea1e47149 100644 --- a/internal/widget/overlay_container.go +++ b/internal/widget/overlay_container.go @@ -1,8 +1,8 @@ package widget import ( - "fyne.io/fyne" - "fyne.io/fyne/driver/desktop" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver/desktop" ) var _ fyne.Widget = (*OverlayContainer)(nil) diff --git a/internal/widget/scroller.go b/internal/widget/scroller.go index d1d484671c..504132d3b0 100644 --- a/internal/widget/scroller.go +++ b/internal/widget/scroller.go @@ -1,11 +1,11 @@ package widget import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/theme" ) // ScrollDirection represents the directions in which a Scroll can scroll its child content. @@ -21,7 +21,7 @@ const ( ScrollVerticalOnly // ScrollNone turns off scrolling for this container. // - // Since: 2.0.0 + // Since: 2.0 ScrollNone ) @@ -444,7 +444,7 @@ type Scroll struct { // OnScrolled can be set to be notified when the Scroll has changed position. // You should not update the Scroll.Offset from this method. // - // Since: 2.0.0 + // Since: 2.0 OnScrolled func(fyne.Position) } diff --git a/internal/widget/scroller_test.go b/internal/widget/scroller_test.go index 3c33fa114f..f374b59a57 100644 --- a/internal/widget/scroller_test.go +++ b/internal/widget/scroller_test.go @@ -7,11 +7,11 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/theme" ) func TestNewScroll(t *testing.T) { diff --git a/internal/widget/shadow.go b/internal/widget/shadow.go index 9ba4528969..f505b7b9fd 100644 --- a/internal/widget/shadow.go +++ b/internal/widget/shadow.go @@ -3,9 +3,9 @@ package widget import ( "image/color" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/theme" ) var _ fyne.Widget = (*Shadow)(nil) diff --git a/internal/widget/shadow_test.go b/internal/widget/shadow_test.go index 71dd9f4e26..e27e7cbafc 100644 --- a/internal/widget/shadow_test.go +++ b/internal/widget/shadow_test.go @@ -3,9 +3,9 @@ package widget_test import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/test" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/test" "github.com/stretchr/testify/assert" ) diff --git a/internal/widget/shadowing_renderer.go b/internal/widget/shadowing_renderer.go index 4b6786d667..77b20d9dc5 100644 --- a/internal/widget/shadowing_renderer.go +++ b/internal/widget/shadowing_renderer.go @@ -1,7 +1,7 @@ package widget import ( - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // ShadowingRenderer is a renderer that adds a shadow arount the rendered content. diff --git a/internal/widget/shadowing_renderer_test.go b/internal/widget/shadowing_renderer_test.go index d17e535759..e37f6e28fd 100644 --- a/internal/widget/shadowing_renderer_test.go +++ b/internal/widget/shadowing_renderer_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" - w "fyne.io/fyne/internal/widget" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + w "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/widget" ) func TestShadowingRenderer_Objects(t *testing.T) { diff --git a/layout/borderlayout.go b/layout/borderlayout.go index d329331f69..88e89f0582 100644 --- a/layout/borderlayout.go +++ b/layout/borderlayout.go @@ -1,8 +1,8 @@ package layout import ( - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) // Declare conformity with Layout interface diff --git a/layout/borderlayout_test.go b/layout/borderlayout_test.go index 7fff3c8027..f0abab2237 100644 --- a/layout/borderlayout_test.go +++ b/layout/borderlayout_test.go @@ -4,11 +4,11 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/layout" - _ "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/layout" + _ "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/layout/boxlayout.go b/layout/boxlayout.go index 7737d66b22..bb87144ece 100644 --- a/layout/boxlayout.go +++ b/layout/boxlayout.go @@ -1,8 +1,8 @@ package layout import ( - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) // Declare conformity with Layout interface diff --git a/layout/boxlayout_test.go b/layout/boxlayout_test.go index e8ecee42a0..430fa857c3 100644 --- a/layout/boxlayout_test.go +++ b/layout/boxlayout_test.go @@ -3,10 +3,10 @@ package layout_test import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/layout/centerlayout.go b/layout/centerlayout.go index fc733c69aa..d2b1ad5491 100644 --- a/layout/centerlayout.go +++ b/layout/centerlayout.go @@ -1,6 +1,6 @@ package layout -import "fyne.io/fyne" +import "fyne.io/fyne/v2" // Declare conformity with Layout interface var _ fyne.Layout = (*centerLayout)(nil) diff --git a/layout/centerlayout_test.go b/layout/centerlayout_test.go index ede3012218..e71c537693 100644 --- a/layout/centerlayout_test.go +++ b/layout/centerlayout_test.go @@ -4,9 +4,9 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/layout" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/layout" "github.com/stretchr/testify/assert" ) diff --git a/layout/formlayout.go b/layout/formlayout.go index 5a8cf40354..7695dcf7b6 100644 --- a/layout/formlayout.go +++ b/layout/formlayout.go @@ -1,8 +1,8 @@ package layout import ( - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) const formLayoutCols = 2 diff --git a/layout/formlayout_test.go b/layout/formlayout_test.go index 33691f246f..5e8fbec78a 100644 --- a/layout/formlayout_test.go +++ b/layout/formlayout_test.go @@ -4,10 +4,10 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/layout/gridlayout.go b/layout/gridlayout.go index b76b583d64..32e4e69443 100644 --- a/layout/gridlayout.go +++ b/layout/gridlayout.go @@ -3,8 +3,8 @@ package layout import ( "math" - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) // Declare conformity with Layout interface diff --git a/layout/gridlayout_test.go b/layout/gridlayout_test.go index 8ddce35986..0718736e51 100644 --- a/layout/gridlayout_test.go +++ b/layout/gridlayout_test.go @@ -4,10 +4,10 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/layout/gridwraplayout.go b/layout/gridwraplayout.go index ab077462cd..3fd8b76b4d 100644 --- a/layout/gridwraplayout.go +++ b/layout/gridwraplayout.go @@ -3,8 +3,8 @@ package layout import ( "math" - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) // Declare conformity with Layout interface diff --git a/layout/gridwraplayout_test.go b/layout/gridwraplayout_test.go index 82b59b8d0c..575b52ba14 100644 --- a/layout/gridwraplayout_test.go +++ b/layout/gridwraplayout_test.go @@ -4,10 +4,10 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/layout/maxlayout.go b/layout/maxlayout.go index 492b5fcade..ff1e2efb67 100644 --- a/layout/maxlayout.go +++ b/layout/maxlayout.go @@ -1,7 +1,7 @@ // Package layout defines the various layouts available to Fyne apps -package layout // import "fyne.io/fyne/layout" +package layout // import "fyne.io/fyne/v2/layout" -import "fyne.io/fyne" +import "fyne.io/fyne/v2" // Declare conformity with Layout interface var _ fyne.Layout = (*maxLayout)(nil) diff --git a/layout/maxlayout_test.go b/layout/maxlayout_test.go index 5be5a9156d..282e18801f 100644 --- a/layout/maxlayout_test.go +++ b/layout/maxlayout_test.go @@ -4,9 +4,9 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/layout" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/layout" "github.com/stretchr/testify/assert" ) diff --git a/layout/paddedlayout.go b/layout/paddedlayout.go index 2d15202fd7..075289408e 100644 --- a/layout/paddedlayout.go +++ b/layout/paddedlayout.go @@ -1,8 +1,8 @@ package layout import ( - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) // Declare conformity with Layout interface diff --git a/layout/paddedlayout_test.go b/layout/paddedlayout_test.go index b1f079248c..b8422368f3 100644 --- a/layout/paddedlayout_test.go +++ b/layout/paddedlayout_test.go @@ -4,10 +4,10 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/layout/spacer.go b/layout/spacer.go index 88aa8c5943..589ea691af 100644 --- a/layout/spacer.go +++ b/layout/spacer.go @@ -1,6 +1,6 @@ package layout -import "fyne.io/fyne" +import "fyne.io/fyne/v2" // SpacerObject is any object that can be used to space out child objects type SpacerObject interface { diff --git a/settings.go b/settings.go index c70e929bac..dcf19cf80c 100644 --- a/settings.go +++ b/settings.go @@ -19,12 +19,12 @@ type Settings interface { SetTheme(Theme) // ThemeVariant defines which preferred version of a theme should be used (i.e. light or dark) // - // Since 2.0.0 + // Since: 2.0 ThemeVariant() ThemeVariant Scale() float32 // PrimaryColor indicates a user preference for a named primary color // - // Since 1.4.0 + // Since: 1.4 PrimaryColor() string AddChangeListener(chan Settings) diff --git a/storage/file.go b/storage/file.go index 67e401823f..42813fd8f5 100644 --- a/storage/file.go +++ b/storage/file.go @@ -2,19 +2,25 @@ package storage import ( - "fyne.io/fyne" + "errors" + + "fyne.io/fyne/v2" ) // OpenFileFromURI loads a file read stream from a resource identifier. // This is mostly provided so that file references can be saved using their URI and loaded again later. +// +// Deprecated: this has been replaced by storage.Reader(URI) func OpenFileFromURI(uri fyne.URI) (fyne.URIReadCloser, error) { - return fyne.CurrentApp().Driver().FileReaderForURI(uri) + return Reader(uri) } // SaveFileToURI loads a file write stream to a resource identifier. // This is mostly provided so that file references can be saved using their URI and written to again later. +// +// Deprecated: this has been replaced by storage.Writer(URI) func SaveFileToURI(uri fyne.URI) (fyne.URIWriteCloser, error) { - return fyne.CurrentApp().Driver().FileWriterForURI(uri) + return Writer(uri) } // ListerForURI will attempt to use the application's driver to convert a @@ -22,8 +28,21 @@ func SaveFileToURI(uri fyne.URI) (fyne.URIWriteCloser, error) { // // Since: 1.4 func ListerForURI(uri fyne.URI) (fyne.ListableURI, error) { - if lister, ok := uri.(fyne.ListableURI); ok { - return lister, nil + listable, err := CanList(uri) + if err != nil { + return nil, err } - return fyne.CurrentApp().Driver().ListerForURI(uri) + if !listable { + return nil, errors.New("uri is not listable") + } + + return &legacyListable{uri}, nil +} + +type legacyListable struct { + fyne.URI +} + +func (l *legacyListable) List() ([]fyne.URI, error) { + return List(l.URI) } diff --git a/storage/filter.go b/storage/filter.go index 1837eaccbf..c6bec67c42 100644 --- a/storage/filter.go +++ b/storage/filter.go @@ -3,7 +3,7 @@ package storage import ( "strings" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // FileFilter is an interface that can be implemented to provide a filter to a file dialog. diff --git a/storage/filter_test.go b/storage/filter_test.go index 2aed27850a..549d8a7657 100644 --- a/storage/filter_test.go +++ b/storage/filter_test.go @@ -3,14 +3,14 @@ package storage_test import ( "testing" - "fyne.io/fyne/storage" + "fyne.io/fyne/v2/storage" - _ "fyne.io/fyne/test" + _ "fyne.io/fyne/v2/test" "github.com/stretchr/testify/assert" ) -func TestFIleFilter(t *testing.T) { +func TestFileFilter(t *testing.T) { filter := storage.NewExtensionFileFilter([]string{".jpg", ".png"}) assert.NotNil(t, filter) diff --git a/storage/repository/errors.go b/storage/repository/errors.go new file mode 100644 index 0000000000..734d1dc599 --- /dev/null +++ b/storage/repository/errors.go @@ -0,0 +1,24 @@ +package repository + +import ( + "errors" +) + +var ( + // ErrOperationNotSupported may be thrown by certain functions in the storage + // or repository packages which operate on URIs if an operation is attempted + // that is not supported for the scheme relevant to the URI, normally because + // the underlying repository has either not implemented the relevant function, + // or has explicitly returned this error. + // + // Since: 2.0 + ErrOperationNotSupported = errors.New("operation not supported for this URI") + + // ErrURIRoot should be thrown by fyne.URI implementations when the caller + // attempts to take the parent of the root. This way, downstream code that + // wants to programmatically walk up a URIs parent's will know when to stop + // iterating. + // + // Since: 2.0 + ErrURIRoot = errors.New("cannot take the parent of the root element in a URI") +) diff --git a/storage/repository/generic.go b/storage/repository/generic.go new file mode 100644 index 0000000000..ebe314c5d9 --- /dev/null +++ b/storage/repository/generic.go @@ -0,0 +1,212 @@ +package repository + +import ( + "io" + "strings" + + "fyne.io/fyne/v2" +) + +// splitNonEmpty works exactly like strings.Split(), but only returns non-empty +// components. +func splitNonEmpty(str, sep string) []string { + components := []string{} + for _, v := range strings.Split(str, sep) { + if len(v) > 0 { + components = append(components, v) + } + } + return components +} + +// GenericParent can be used as a common-case implementation of +// HierarchicalRepository.Parent(). It will create a parent URI based on +// IETF RFC3986. +// +// In short, the URI is separated into it's component parts, the path component +// is split along instances of '/', and the trailing element is removed. The +// result is concatenated and parsed as a new URI. +// +// If the URI path is empty or '/', then a nil URI is returned, along with +// ErrURIRoot. +// +// NOTE: this function should not be called except by an implementation of +// the Repository interface - using this for unknown URIs may break. +// +// Since: 2.0 +func GenericParent(u fyne.URI) (fyne.URI, error) { + p := u.Path() + + if p == "" || p == "/" { + return nil, ErrURIRoot + } + + components := splitNonEmpty(p, "/") + + newURI := u.Scheme() + "://" + u.Authority() + + // there will be at least one component, since we know we don't have + // '/' or ''. + newURI += "/" + if len(components) > 1 { + newURI += strings.Join(components[:len(components)-1], "/") + } + + // stick the query and fragment back on the end + if q := u.Query(); len(q) > 0 { + newURI += "?" + q + } + + if f := u.Fragment(); len(f) > 0 { + newURI += "#" + f + } + + // NOTE: we specifically want to use ParseURI, rather than &uri{}, + // since the repository for the URI we just created might be a + // CustomURIRepository that implements it's own ParseURI. + return ParseURI(newURI) +} + +// GenericChild can be used as a common-case implementation of +// HierarchicalRepository.Child(). It will create a child URI by separating the +// URI into it's component parts as described in IETF RFC 3986, then appending +// "/" + component to the path, then concatenating the result and parsing it as +// a new URI. +// +// NOTE: this function should not be called except by an implementation of +// the Repository interface - using this for unknown URIs may break. +// +// Since: 2.0 +func GenericChild(u fyne.URI, component string) (fyne.URI, error) { + + // split into components and add the new one + components := splitNonEmpty(u.Path(), "/") + components = append(components, component) + + // generate the scheme, authority, and path + newURI := u.Scheme() + "://" + u.Authority() + newURI += "/" + strings.Join(components, "/") + + // stick the query and fragment back on the end + if q := u.Query(); len(q) > 0 { + newURI += "?" + q + } + if f := u.Fragment(); len(f) > 0 { + newURI += "#" + f + } + + // NOTE: we specifically want to use ParseURI, rather than &uri{}, + // since the repository for the URI we just created might be a + // CustomURIRepository that implements it's own ParseURI. + return ParseURI(newURI) +} + +// GenericCopy can be used a common-case implementation of +// CopyableRepository.Copy(). It will perform the copy by obtaining a reader +// for the source URI, a writer for the destination URI, then writing the +// contents of the source to the destination. +// +// For obvious reasons, the destination URI must have a registered +// WritableRepository. +// +// NOTE: this function should not be called except by an implementation of +// the Repository interface - using this for unknown URIs may break. +// +// Since: 2.0 +func GenericCopy(source fyne.URI, destination fyne.URI) error { + // Look up repositories for the source and destination. + srcrepo, err := ForURI(source) + if err != nil { + return err + } + + dstrepo, err := ForURI(destination) + if err != nil { + return err + } + + // The destination must be writable. + destwrepo, ok := dstrepo.(WritableRepository) + if !ok { + return ErrOperationNotSupported + } + + // Create a reader and a writer. + srcReader, err := srcrepo.Reader(source) + if err != nil { + return err + } + defer srcReader.Close() + + dstWriter, err := destwrepo.Writer(destination) + if err != nil { + return err + } + defer dstWriter.Close() + + // Perform the copy. + _, err = io.Copy(dstWriter, srcReader) + return err +} + +// GenericMove can be used a common-case implementation of +// MovableRepository.Move(). It will perform the move by obtaining a reader +// for the source URI, a writer for the destination URI, then writing the +// contents of the source to the destination. Following this, the source +// will be deleted using WritableRepository.Delete. +// +// For obvious reasons, the source and destination URIs must both be writable. +// +// NOTE: this function should not be called except by an implementation of +// the Repository interface - using this for unknown URIs may break. +// +// Since: 2.0 +func GenericMove(source fyne.URI, destination fyne.URI) error { + // This looks a lot like GenericCopy(), but I duplicated the code + // to avoid having to look up the repositories more than once. + + // Look up repositories for the source and destination. + srcrepo, err := ForURI(source) + if err != nil { + return err + } + + dstrepo, err := ForURI(destination) + if err != nil { + return err + } + + // The source and destination must both be writable, since the source + // is being deleted, which requires WritableRepository. + destwrepo, ok := dstrepo.(WritableRepository) + if !ok { + return ErrOperationNotSupported + } + + srcwrepo, ok := srcrepo.(WritableRepository) + if !ok { + return ErrOperationNotSupported + } + + // Create the reader and writer to perform the copy operation. + srcReader, err := srcrepo.Reader(source) + if err != nil { + return err + } + + dstWriter, err := destwrepo.Writer(destination) + if err != nil { + return err + } + defer dstWriter.Close() + + // Perform the copy. + _, err = io.Copy(dstWriter, srcReader) + if err != nil { + return err + } + + // Finally, delete the source only if the move finished without error. + srcReader.Close() + return srcwrepo.Delete(source) +} diff --git a/storage/repository/generic_test.go b/storage/repository/generic_test.go new file mode 100644 index 0000000000..32e87d83da --- /dev/null +++ b/storage/repository/generic_test.go @@ -0,0 +1,61 @@ +package repository + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGenericParent(t *testing.T) { + cases := []struct { + input string + expect string + err error + }{ + {"foo://example.com:8042/over/there?name=ferret#nose", "foo://example.com:8042/over?name=ferret#nose", nil}, + {"file:///", "file:///", ErrURIRoot}, + {"file:///foo", "file:///", nil}, + } + + for i, c := range cases { + t.Logf("case %d, input='%s', expect='%s', err='%v'\n", i, c.input, c.expect, c.err) + + u, err := ParseURI(c.input) + assert.Nil(t, err) + + res, err := GenericParent(u) + assert.Equal(t, c.err, err) + + // In the case where there is a non-nil error, res is defined + // to be nil, so we cannot call res.String() without causing + // a panic. + if err == nil { + assert.Equal(t, c.expect, res.String()) + } + } +} + +func TestGenericChild(t *testing.T) { + cases := []struct { + input string + component string + expect string + err error + }{ + {"foo://example.com:8042/over/there?name=ferret#nose", "bar", "foo://example.com:8042/over/there/bar?name=ferret#nose", nil}, + {"file:///", "quux", "file:///quux", nil}, + {"file:///foo", "baz", "file:///foo/baz", nil}, + } + + for i, c := range cases { + t.Logf("case %d, input='%s', component='%s', expect='%s', err='%v'\n", i, c.input, c.component, c.expect, c.err) + + u, err := ParseURI(c.input) + assert.Nil(t, err) + + res, err := GenericChild(u, c.component) + assert.Equal(t, c.err, err) + + assert.Equal(t, c.expect, res.String()) + } +} diff --git a/storage/repository/parse.go b/storage/repository/parse.go new file mode 100644 index 0000000000..71ae590d78 --- /dev/null +++ b/storage/repository/parse.go @@ -0,0 +1,127 @@ +package repository + +import ( + "path/filepath" + "runtime" + "strings" + + uriParser "github.com/fredbi/uri" + + "fyne.io/fyne/v2" +) + +// NewFileURI implements the back-end logic to storage.NewFileURI, which you +// should use instead. This is only here because other functions in repository +// need to call it, and it prevents a circular import. +// +// Since: 2.0 +func NewFileURI(path string) fyne.URI { + // URIs are supposed to use forward slashes. On Windows, it + // should be OK to use the platform native filepath with UNIX + // or NT style paths, with / or \, but when we reconstruct + // the URI, we want to have / only. + if runtime.GOOS == "windows" { + // seems that sometimes we end up with + // double-backslashes + path = filepath.ToSlash(path) + } + + return &uri{ + scheme: "file", + haveAuthority: true, + authority: "", + path: path, + query: "", + fragment: "", + } +} + +// ParseURI implements the back-end logic for storage.ParseURI, which you +// should use instead. This is only here because other functions in repository +// need to call it, and it prevents a circular import. +// +// Since: 2.0 +func ParseURI(s string) (fyne.URI, error) { + // Extract the scheme. + scheme := "" + for i := 0; i < len(s); i++ { + if s[i] == ':' { + break + } + scheme += string(s[i]) + } + scheme = strings.ToLower(scheme) + + if scheme == "file" { + // Does this really deserve to be special? In principle, the + // purpose of this check is to pass it to NewFileURI, which + // allows platform path seps in the URI (against the RFC, but + // easier for people building URIs naively on Windows). Maybe + // we should punt this to whoever generated the URI in the + // first place? + + path := s[5:] // everything after file: + if len(path) > 2 && path[:2] == "//" { + path = path[2:] + } + + // Windows files can break authority checks, so just return the parsed file URI + return NewFileURI(path), nil + } + + repo, err := ForScheme(scheme) + if err == nil { + // If the repository registered for this scheme implements a parser + if c, ok := repo.(CustomURIRepository); ok { + return c.ParseURI(s) + } + } + + // There was no repository registered, or it did not provide a parser + + // Ugly hack to work around fredbi/uri. Technically, something like + // foo:/// is invalid because it implies a host, but also has an empty + // host. However, this is a very common occurrence, so we convert a + // leading ":///" to "://". + rest := strings.TrimPrefix(s, scheme+":") + dummyHost := false + if len(rest) >= 3 && rest[0:3] == "///" { + rest = "//" + "TEMP.TEMP/" + strings.TrimPrefix(rest, "///") + dummyHost = true + } + s = scheme + ":" + rest + + l, err := uriParser.Parse(s) + if err != nil { + return nil, err + } + + authority := "" + if !dummyHost { + // User info makes no sense without a host, see next comment. + if userInfo := l.Authority().UserInfo(); len(userInfo) > 0 { + authority += userInfo + "@" + } + + // In this case, we had to insert a "host" to make the parser + // happy, but it isn't really a host, so we can just drop it. + // If dummyHost isn't set, then we should have a valid host and + // we can include it as normal. + authority += l.Authority().Host() + + // Port obviously makes no sense without a host. + if port := l.Authority().Port(); len(port) > 0 { + authority += ":" + port + } + } + + return &uri{ + scheme: l.Scheme(), + authority: authority, + // workaround for net/url, see type uri struct comments + haveAuthority: true, + path: l.Authority().Path(), + query: l.Query().Encode(), + fragment: l.Fragment(), + }, nil +} diff --git a/storage/repository/parse_test.go b/storage/repository/parse_test.go new file mode 100644 index 0000000000..87c8ada016 --- /dev/null +++ b/storage/repository/parse_test.go @@ -0,0 +1,26 @@ +package repository + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewFileURI(t *testing.T) { + assert.Equal(t, "file:///tmp/foo.txt", NewFileURI("/tmp/foo.txt").String()) + assert.Equal(t, "file://C:/tmp/foo.txt", NewFileURI("C:/tmp/foo.txt").String()) +} + +func TestParseURI(t *testing.T) { + uri, err := ParseURI("file:///tmp/foo.txt") + assert.Nil(t, err) + assert.Equal(t, "file:///tmp/foo.txt", uri.String()) + + uri, err = ParseURI("file:/tmp/foo.txt") + assert.Nil(t, err) + assert.Equal(t, "file:///tmp/foo.txt", uri.String()) + + uri, err = ParseURI("file://C:/tmp/foo.txt") + assert.Nil(t, err) + assert.Equal(t, "file://C:/tmp/foo.txt", uri.String()) +} diff --git a/storage/repository/repository.go b/storage/repository/repository.go new file mode 100644 index 0000000000..530c469015 --- /dev/null +++ b/storage/repository/repository.go @@ -0,0 +1,274 @@ +package repository + +import ( + "fmt" + "strings" + + "fyne.io/fyne/v2" +) + +// repositoryTable stores the mapping of schemes to Repository implementations. +// It should only ever be used by ForURI() and Register(). +var repositoryTable map[string]Repository = map[string]Repository{} + +// Repository represents a storage repository, which is a set of methods which +// implement specific functions on a URI. Repositories are registered to handle +// specific URI schemes, and the higher-level functions that operate on URIs +// internally look up an appropriate method from the relevant Repository. +// +// The repository interface includes only methods which must be implemented at +// a minimum. Without implementing all of the methods in this interface, a URI +// would not be usable in a useful way. Additional functionality can be exposed +// by using interfaces which extend Repository. +// +// Repositories are registered to handle a specific URI scheme (or schemes) +// using the Register() method. When a higher-level URI function such as +// storage.Copy() is called, the storage package will internally look up +// the repository associated with the scheme of the URI, then it will use +// a type assertion to check if the repository implements CopyableRepository. +// If so, the Copy() function will be run from the repository, otherwise +// storage.Copy() will return NotSupportedError. This works similarly for +// all other methods in repository-related interfaces. +// +// Note that a repository can be registered for multiple URI schemes. In such +// cases, the repository must internally select and implement the correct +// behavior for each URI scheme. +// +// A repository will only ever need to handle URIs with schemes for which it +// was registered, with the exception that functions with more than 1 operand +// such as Copy() and Move(), in which cases only the first operand is +// guaranteed to match a scheme for which the repository is registered. +// +// NOTE: most developers who use Fyne should *not* generally attempt to +// call repository methods directly. You should use the methods in the storage +// package, which will automatically detect the scheme of a URI and call into +// the appropriate repository. +// +// Since: 2.0 +type Repository interface { + + // Exists will be used to implement calls to storage.Exists() for the + // registered scheme of this repository. + // + // Since: 2.0 + Exists(u fyne.URI) (bool, error) + + // Reader will be used to implement calls to storage.Reader() + // for the registered scheme of this repository. + // + // Since: 2.0 + Reader(u fyne.URI) (fyne.URIReadCloser, error) + + // CanRead will be used to implement calls to storage.CanRead() for the + // registered scheme of this repository. + // + // Since: 2.0 + CanRead(u fyne.URI) (bool, error) + + // Destroy is called when the repository is un-registered from a given + // URI scheme. + // + // The string parameter will be the URI scheme that the repository was + // registered for. This may be useful for repositories that need to + // handle more than one URI scheme internally. + // + // Since: 2.0 + Destroy(string) +} + +// CustomURIRepository is an extension of the repository interface which +// allows the behavior of storage.ParseURI to be overridden. This is only +// needed if you wish to generate custom URI types, rather than using Fyne's +// URI implementation and net/url based parsing. +// +// NOTE: even for URIs with non-RFC3986-compliant encoding, the URI MUST begin +// with 'scheme:', or storage.ParseURI() will not be able to determine which +// storage repository to delegate to for parsing. +// +// Since: 2.0 +type CustomURIRepository interface { + Repository + + // ParseURI will be used to implement calls to storage.ParseURI() + // for the registered scheme of this repository. + ParseURI(string) (fyne.URI, error) +} + +// WritableRepository is an extension of the Repository interface which also +// supports obtaining a writer for URIs of the scheme it is registered to. +// +// Since: 2.0 +type WritableRepository interface { + Repository + + // Writer will be used to implement calls to storage.WriterTo() for + // the registered scheme of this repository. + // + // Since: 2.0 + Writer(u fyne.URI) (fyne.URIWriteCloser, error) + + // CanWrite will be used to implement calls to storage.CanWrite() for + // the registered scheme of this repository. + // + // Since: 2.0 + CanWrite(u fyne.URI) (bool, error) + + // Delete will be used to implement calls to storage.Delete() for the + // registered scheme of this repository. + // + // Since: 2.0 + Delete(u fyne.URI) error +} + +// ListableRepository is an extension of the Repository interface which also +// supports obtaining directory listings (generally analogous to a directory +// listing) for URIs of the scheme it is registered to. +// +// Since: 2.0 +type ListableRepository interface { + Repository + + // CanList will be used to implement calls to storage.Listable() for + // the registered scheme of this repository. + // + // Since: 2.0 + CanList(u fyne.URI) (bool, error) + + // List will be used to implement calls to storage.List() for the + // registered scheme of this repository. + // + // Since: 2.0 + List(u fyne.URI) ([]fyne.URI, error) + + // CreateListable will be used to implement calls to + // storage.CreateListable() for the registered scheme of this + // repository. + // + // Since: 2.0 + CreateListable(u fyne.URI) error +} + +// HierarchicalRepository is an extension of the Repository interface which +// also supports determining the parent and child items of a URI. +// +// Since: 2.0 +type HierarchicalRepository interface { + Repository + + // Parent will be used to implement calls to storage.Parent() for the + // registered scheme of this repository. + // + // A generic implementation is provided in GenericParent(), which + // is based on the RFC3986 definition of a URI parent. + // + // Since: 2.0 + Parent(fyne.URI) (fyne.URI, error) + + // Child will be used to implement calls to storage.Child() for + // the registered scheme of this repository. + // + // A generic implementation is provided in GenericParent(), which + // is based on RFC3986. + // + // Since: 2.0 + Child(fyne.URI, string) (fyne.URI, error) +} + +// CopyableRepository is an extension of the Repository interface which also +// supports copying referenced resources from one URI to another. +// +// Since: 2.0 +type CopyableRepository interface { + Repository + + // Copy will be used to implement calls to storage.Copy() for the + // registered scheme of this repository. + // + // A generic implementation is provided by GenericCopy(). + // + // NOTE: the first parameter is the source, the second is the + // destination. + // + // NOTE: if storage.Copy() is given two URIs of different schemes, it + // is possible that only the source URI will be of the type this + // repository is registered to handle. In such cases, implementations + // are suggested to fail-over to GenericCopy(). + // + // Since: 2.0 + Copy(fyne.URI, fyne.URI) error +} + +// MovableRepository is an extension of the Repository interface which also +// supports moving referenced resources from one URI to another. +// +// Note: both Moveable and Movable are correct spellings, but Movable is newer +// and more accepted. Source: https://grammarist.com/spelling/movable-moveable/ +// +// Since: 2.0 +type MovableRepository interface { + Repository + + // Move will be used to implement calls to storage.Move() for the + // registered scheme of this repository. + // + // A generic implementation is provided by GenericMove(). + // + // NOTE: the first parameter is the source, the second is the + // destination. + // + // NOTE: if storage.Move() is given two URIs of different schemes, it + // is possible that only the source URI will be of the type this + // repository is registered to handle. In such cases, implementations + // are suggested to fail-over to GenericMove(). + // + // Since: 2.0 + Move(fyne.URI, fyne.URI) error +} + +// Register registers a storage repository so that operations on URIs of the +// registered scheme will use methods implemented by the relevant repository +// implementation. +// +// Since: 2.0 +func Register(scheme string, repository Repository) { + scheme = strings.ToLower(scheme) + + prev, ok := repositoryTable[scheme] + + if ok { + prev.Destroy(scheme) + } + + repositoryTable[scheme] = repository +} + +// ForURI returns the Repository instance which is registered to handle URIs of +// the given scheme. This is a helper method that calls ForScheme() on the +// scheme of the given URI. +// +// NOTE: this function is intended to be used specifically by the storage +// package. It generally should not be used outside of the fyne package - +// instead you should use the methods in the storage package. +// +// Since: 2.0 +func ForURI(u fyne.URI) (Repository, error) { + return ForScheme(u.Scheme()) +} + +// ForScheme returns the Repository instance which is registered to handle URIs +// of the given scheme. +// +// NOTE: this function is intended to be used specifically by the storage +// package. It generally should not be used outside of the fyne package - +// instead you should use the methods in the storage package. +// +// Since: 2.0 +func ForScheme(scheme string) (Repository, error) { + repo, ok := repositoryTable[scheme] + + if !ok { + return nil, fmt.Errorf("no repository registered for scheme '%s'", scheme) + } + + return repo, nil +} diff --git a/storage/repository/uri.go b/storage/repository/uri.go new file mode 100644 index 0000000000..c3c96eed23 --- /dev/null +++ b/storage/repository/uri.go @@ -0,0 +1,96 @@ +package repository + +import ( + "bufio" + "mime" + "path/filepath" + "strings" + "unicode/utf8" + + "fyne.io/fyne/v2" +) + +// Declare conformance with fyne.URI interface. +var _ fyne.URI = &uri{} + +type uri struct { + scheme string + authority string + // haveAuthority lets us distinguish between a present-but-empty + // authority, and having no authority. This is needed because net/url + // incorrectly handles scheme:/absolute/path URIs. + haveAuthority bool + path string + query string + fragment string +} + +func (u *uri) Extension() string { + return filepath.Ext(u.path) +} + +func (u *uri) Name() string { + return filepath.Base(u.path) +} + +func (u *uri) MimeType() string { + + mimeTypeFull := mime.TypeByExtension(u.Extension()) + if mimeTypeFull == "" { + mimeTypeFull = "text/plain" + + repo, err := ForURI(u) + if err != nil { + return "application/octet-stream" + } + + readCloser, err := repo.Reader(u) + if err == nil { + defer readCloser.Close() + scanner := bufio.NewScanner(readCloser) + if scanner.Scan() && !utf8.Valid(scanner.Bytes()) { + mimeTypeFull = "application/octet-stream" + } + } + } + + return strings.Split(mimeTypeFull, ";")[0] +} + +func (u *uri) Scheme() string { + return u.scheme +} + +func (u *uri) String() string { + // NOTE: this string reconstruction is mandated by IETF RFC3986, + // section 5.3, pp. 35. + + s := u.scheme + ":" + if u.haveAuthority { + s += "//" + u.authority + } + s += u.path + if len(u.query) > 0 { + s += "?" + u.query + } + if len(u.fragment) > 0 { + s += "#" + u.fragment + } + return s +} + +func (u *uri) Authority() string { + return u.authority +} + +func (u *uri) Path() string { + return u.path +} + +func (u *uri) Query() string { + return u.query +} + +func (u *uri) Fragment() string { + return u.fragment +} diff --git a/storage/resource.go b/storage/resource.go index 1e1c13087d..18118efab3 100644 --- a/storage/resource.go +++ b/storage/resource.go @@ -3,14 +3,14 @@ package storage import ( "io/ioutil" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // LoadResourceFromURI creates a new StaticResource in memory using the contents of the specified URI. // The URI will be opened using the current driver, so valid schemas will vary from platform to platform. // The file:// schema will always work. func LoadResourceFromURI(u fyne.URI) (fyne.Resource, error) { - read, err := OpenFileFromURI(u) + read, err := Reader(u) if err != nil { return nil, err } diff --git a/storage/uri.go b/storage/uri.go index b3591e2f3b..768a59b99e 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -1,204 +1,534 @@ package storage import ( - "bufio" - "fmt" - "mime" - "os" - "path/filepath" - "runtime" - "strings" - "unicode/utf8" - - "fyne.io/fyne" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage/repository" ) -type uri struct { - raw string -} - // NewFileURI creates a new URI from the given file path. func NewFileURI(path string) fyne.URI { - // URIs are supposed to use forward slashes. On Windows, it - // should be OK to use the platform native filepath with UNIX - // or NT style paths, with / or \, but when we reconstruct - // the URI, we want to have / only. - if runtime.GOOS == "windows" { - // seems that sometimes we end up with - // double-backslashes - path = filepath.ToSlash(path) - } - return &uri{raw: "file://" + path} + return repository.NewFileURI(path) } -// NewURI creates a new URI from the given string representation. -// This could be a URI from an external source or one saved from URI.String() -func NewURI(u string) fyne.URI { - if len(u) > 5 && u[:5] == "file:" { - path := u[5:] - if len(path) > 2 && path[:2] == "//" { - path = path[2:] - } - return NewFileURI(path) - } - - return &uri{raw: u} +// NewURI creates a new URI from the given string representation. This could be +// a URI from an external source or one saved from URI.String() +// +// Deprecated: use ParseURI instead +func NewURI(s string) fyne.URI { + u, _ := ParseURI(s) + return u } -func (u *uri) Extension() string { - return filepath.Ext(u.raw) +// ParseURI creates a new URI instance by parsing a URI string. +// +// Parse URI will parse up to the first ':' present in the URI string to +// extract the scheme, and then delegate further parsing to the registered +// repository for the given scheme. If no repository is registered for that +// scheme, the URI is parsed on a best-effort basis using net/url. +// +// As a special exception, URIs beginning with 'file:' are always parsed using +// NewFileURI(), which will correctly handle back-slashes appearing in the URI +// path component on Windows. +// +// Since: 2.0 +func ParseURI(s string) (fyne.URI, error) { + return repository.ParseURI(s) } -func (u *uri) Name() string { - return filepath.Base(u.raw) +// Parent returns a URI referencing the parent resource of the resource +// referenced by the URI. For example, the Parent() of 'file://foo/bar.baz' is +// 'file://foo'. The URI which is returned will be listable. +// +// NOTE: it is not a given that Parent() return a parent URI with the same +// Scheme(), though this will normally be the case. +// +// This can fail in several ways: +// +// * If the URI refers to a filesystem root, then the Parent() implementation +// must return (nil, URIRootError). +// +// * If the URI refers to a resource which does not exist in a hierarchical +// context (e.g. the URI references something which does not have a +// semantically meaningful "parent"), the Parent() implementation may return +// an error. +// +// * If determining the parent of the referenced resource requires +// interfacing with some external system, failures may propagate +// through the Parent() implementation. For example if determining +// the parent of a file:// URI requires reading information from +// the filesystem, it could fail with a permission error. +// +// * If the scheme of the given URI does not have a registered +// HierarchicalRepository instance, then this method will fail with a +// repository.ErrOperationNotSupported. +// +// NOTE: since v2.0.0, Parent() is backed by the repository system - this +// function is a helper which calls into an appropriate repository instance for +// the scheme of the URI it is given. +// +// Since: 1.4 +func Parent(u fyne.URI) (fyne.URI, error) { + + repo, err := repository.ForURI(u) + if err != nil { + return nil, err + } + + hrepo, ok := repo.(repository.HierarchicalRepository) + if !ok { + return nil, repository.ErrOperationNotSupported + } + + return hrepo.Parent(u) } -func (u *uri) MimeType() string { - mimeTypeFull := mime.TypeByExtension(u.Extension()) - if mimeTypeFull == "" { - mimeTypeFull = "text/plain" - readCloser, err := fyne.CurrentApp().Driver().FileReaderForURI(u) - if err == nil { - defer readCloser.Close() - scanner := bufio.NewScanner(readCloser) - if scanner.Scan() && !utf8.Valid(scanner.Bytes()) { - mimeTypeFull = "application/octet-stream" - } - } +// Child returns a URI referencing a resource nested hierarchically below the +// given URI, identified by a string. For example, the child with the string +// component 'quux' of 'file://foo/bar' is 'file://foo/bar/quux'. +// +// This can fail in several ways: +// +// * If the URI refers to a resource which does not exist in a hierarchical +// context (e.g. the URI references something which does not have a +// semantically meaningful "child"), the Child() implementation may return an +// error. +// +// * If generating a reference to a child of the referenced resource requires +// interfacing with some external system, failures may propagate through the +// Child() implementation. It is expected that this case would occur very +// rarely if ever. +// +// * If the scheme of the given URI does not have a registered +// HierarchicalRepository instance, then this method will fail with a +// repository.ErrOperationNotSupported. +// +// NOTE: since v2.0.0, Child() is backed by the repository system - this +// function is a helper which calls into an appropriate repository instance for +// the scheme of the URI it is given. +// +// Since: 1.4 +func Child(u fyne.URI, component string) (fyne.URI, error) { + repo, err := repository.ForURI(u) + if err != nil { + return nil, err + } + + hrepo, ok := repo.(repository.HierarchicalRepository) + if !ok { + return nil, repository.ErrOperationNotSupported } - return strings.Split(mimeTypeFull, ";")[0] + return hrepo.Child(u, component) } -func (u *uri) Scheme() string { - pos := strings.Index(u.raw, ":") - if pos == -1 { - return "" +// Exists determines if the resource referenced by the URI exists. +// +// This can fail in several ways: +// +// * If checking the existence of a resource requires interfacing with some +// external system, then failures may propagate through Exists(). For +// example, checking the existence of a resource requires reading a directory +// may result in a permissions error. +// +// It is understood that a non-nil error value signals that the existence or +// non-existence of the resource cannot be determined and is undefined. +// +// NOTE: since v2.0.0, Exists is backed by the repository system - this function +// calls into a scheme-specific implementation from a registered repository. +// +// Exists may call into either a generic implementation, or into a +// scheme-specific implementation depending on which storage repositories have +// been registered. +// +// Since: 1.4 +func Exists(u fyne.URI) (bool, error) { + repo, err := repository.ForURI(u) + if err != nil { + return false, err } - return strings.ToLower(u.raw[:pos]) + return repo.Exists(u) } -func (u *uri) String() string { - return u.raw +// Delete destroys, deletes, or otherwise removes the resource referenced +// by the URI. +// +// This can fail in several ways: +// +// * If removing the resource requires interfacing with some external system, +// failures may propagate through Destroy(). For example, deleting a file may +// fail with a permissions error. +// +// * If the referenced resource does not exist, attempting to destroy it should +// throw an error. +// +// * If the scheme of the given URI does not have a registered +// WritableRepository instance, then this method will fail with a +// repository.ErrOperationNotSupported. +// +// Delete is backed by the repository system - this function calls +// into a scheme-specific implementation from a registered repository. +// +// Since: 2.0 +func Delete(u fyne.URI) error { + repo, err := repository.ForURI(u) + if err != nil { + return err + } + + wrepo, ok := repo.(repository.WritableRepository) + if !ok { + return repository.ErrOperationNotSupported + } + + return wrepo.Delete(u) + } -// parentGeneric is a generic function that returns the last element of a -// path after splitting it on "/". It should be suitable for most URIs. -func parentGeneric(location string) (string, error) { +// Reader returns URIReadCloser set up to read from the resource that the +// URI references. +// +// This method can fail in several ways: +// +// * Different permissions or credentials are required to read the +// referenced resource. +// +// * This URI scheme could represent some resources that can be read, +// but this particular URI references a resources that is not +// something that can be read. +// +// * Attempting to set up the reader depended on a lower level +// operation such as a network or filesystem access that has failed +// in some way. +// +// Reader is backed by the repository system - this function calls +// into a scheme-specific implementation from a registered repository. +// +// Since: 2.0 +func Reader(u fyne.URI) (fyne.URIReadCloser, error) { + repo, err := repository.ForURI(u) + if err != nil { + return nil, err + } - // trim leading forward slashes - trimmed := 0 - for location[0] == '/' { - location = location[1:] - trimmed++ + return repo.Reader(u) +} - // if all we have left is an empty string, than this URI - // pointed to a UNIX-style root - if len(location) == 0 { - return "", URIRootError - } +// CanRead determines if a given URI could be written to using the Reader() +// method. It is preferred to check if a URI is readable using this method +// before calling Reader(), because the underlying operations required to +// attempt to read and then report an error may be slower than the operations +// needed to test if a URI is readable. Keep in mind however that even if +// CanRead returns true, you must still do appropriate error handling for +// Reader(), as the underlying filesystem may have changed since you called +// CanRead. +// +// The non-existence of a resource should not be treated as an error. In other +// words, a Repository implementation which for some URI u returns false, nil +// for Exists(u), CanRead(u) should also return false, nil. +// +// CanRead is backed by the repository system - this function calls into a +// scheme-specific implementation from a registered repository. +// +// Since: 2.0 +func CanRead(u fyne.URI) (bool, error) { + repo, err := repository.ForURI(u) + if err != nil { + return false, err } - components := strings.Split(location, "/") + return repo.CanRead(u) +} - if len(components) == 1 { - return "", URIRootError +// Writer returns URIWriteCloser set up to write to the resource that the +// URI references. +// +// Writing to a non-extant resource should create that resource if possible +// (and if not possible, this should be reflected in the return of CanWrite()). +// Writing to an extant resource should overwrite it in-place. At present, this +// API does not provide a mechanism for appending to an already-extant +// resource, except for reading it in and writing all the data back out. +// +// This method can fail in several ways: +// +// * Different permissions or credentials are required to write to the +// referenced resource. +// +// * This URI scheme could represent some resources that can be +// written, but this particular URI references a resources that is +// not something that can be written. +// +// * Attempting to set up the writer depended on a lower level +// operation such as a network or filesystem access that has failed +// in some way. +// +// * If the scheme of the given URI does not have a registered +// WritableRepository instance, then this method will fail with a +// repository.ErrOperationNotSupported. +// +// Writer is backed by the repository system - this function calls into a +// scheme-specific implementation from a registered repository. +// +// Since: 2.0 +func Writer(u fyne.URI) (fyne.URIWriteCloser, error) { + repo, err := repository.ForURI(u) + if err != nil { + return nil, err } - parent := "" - if trimmed > 2 && len(components) > 1 { - // Because we trimmed all the leading '/' characters, for UNIX - // style paths we want to insert one back in. Presumably we - // trimmed two instances of / for the scheme. - parent = parent + "/" + wrepo, ok := repo.(repository.WritableRepository) + if !ok { + return nil, repository.ErrOperationNotSupported } - parent = parent + strings.Join(components[0:len(components)-1], "/") + "/" - return parent, nil + return wrepo.Writer(u) } -// Parent gets the parent of a URI by splitting it along '/' separators and -// removing the last item. +// CanWrite determines if a given URI could be written to using the Writer() +// method. It is preferred to check if a URI is writable using this method +// before calling Writer(), because the underlying operations required to +// attempt to write and then report an error may be slower than the operations +// needed to test if a URI is writable. Keep in mind however that even if +// CanWrite returns true, you must still do appropriate error handling for +// Writer(), as the underlying filesystem may have changed since you called +// CanWrite. + // -// Since: 1.4 -func Parent(u fyne.URI) (fyne.URI, error) { - s := u.String() +// CanWrite is backed by the repository system - this function calls into a +// scheme-specific implementation from a registered repository. +// +// Since: 2.0 +func CanWrite(u fyne.URI) (bool, error) { + repo, err := repository.ForURI(u) + if err != nil { + return false, err + } - // trim trailing slash - if s[len(s)-1] == '/' { - s = s[0 : len(s)-1] + wrepo, ok := repo.(repository.WritableRepository) + if !ok { + return false, repository.ErrOperationNotSupported } - // trim the scheme - s = s[len(u.Scheme())+3:] + return wrepo.CanWrite(u) +} - // Completely empty URI with just a scheme - if len(s) == 0 { - return nil, URIRootError +// Copy given two URIs, 'src', and 'dest' both of the same scheme, will copy +// one to the other. If the source and destination are of different schemes, +// then the Copy implementation for the storage repository registered to the +// scheme of the source will be used. Implementations are recommended to use +// repository.GenericCopy() as a fail-over in the case that they do not +// understand how to operate on the scheme of the destination URI. However, the +// behavior of calling Copy() on URIs of non-matching schemes is ultimately +// defined by the storage repository registered to the scheme of the source +// URI. +// +// This method may fail in several ways: +// +// * Different permissions or credentials are required to perform the +// copy operation. +// +// * This URI scheme could represent some resources that can be copied, +// but either the source, destination, or both are not resources +// that support copying. +// +// * Performing the copy operation depended on a lower level operation +// such as network or filesystem access that has failed in some way. +// +// * If the scheme of the given URI does not have a registered +// CopyableRepository instance, then this method will fail with a +// repository.ErrOperationNotSupported. +// +// Copy is backed by the repository system - this function calls into a +// scheme-specific implementation from a registered repository. +// +// Since: 2.0 +func Copy(source fyne.URI, destination fyne.URI) error { + repo, err := repository.ForURI(source) + if err != nil { + return err } - parent := "" - if u.Scheme() == "file" { - // use the system native path resolution - parent = filepath.Dir(s) - if parent[len(parent)-1] != filepath.Separator { - parent += "/" - } + crepo, ok := repo.(repository.CopyableRepository) + if !ok { + return repository.ErrOperationNotSupported + } + + return crepo.Copy(source, destination) +} - // only root is it's own parent - if filepath.Clean(parent) == filepath.Clean(s) { - return nil, URIRootError - } +// Move returns a method that given two URIs, 'src' and 'dest' both of the same +// scheme this will move src to dest. This means the resource referenced by +// src will be copied into the resource referenced by dest, and the resource +// referenced by src will no longer exist after the operation is complete. +// +// If the source and destination are of different schemes, then the Move +// implementation for the storage repository registered to the scheme of the +// source will be used. Implementations are recommended to use +// repository.GenericMove() as a fail-over in the case that they do not +// understand how to operate on the scheme of the destination URI. However, the +// behavior of calling Move() on URIs of non-matching schemes is ultimately +// defined by the storage repository registered to the scheme of the source +// URI. +// +// +// This method may fail in several ways: +// +// * Different permissions or credentials are required to perform the +// rename operation. +// +// * This URI scheme could represent some resources that can be renamed, +// but either the source, destination, or both are not resources +// that support renaming. +// +// * Performing the rename operation depended on a lower level operation +// such as network or filesystem access that has failed in some way. +// +// * If the scheme of the given URI does not have a registered +// MovableRepository instance, then this method will fail with a +// repository.ErrOperationNotSupported. +// +// Move is backed by the repository system - this function calls into a +// scheme-specific implementation from a registered repository. +// +// Since: 2.0 +func Move(source fyne.URI, destination fyne.URI) error { + repo, err := repository.ForURI(source) + if err != nil { + return err + } - } else { - var err error - parent, err = parentGeneric(s) - if err != nil { - return nil, err - } + mrepo, ok := repo.(repository.MovableRepository) + if !ok { + return repository.ErrOperationNotSupported } - return NewURI(u.Scheme() + "://" + parent), nil + return mrepo.Move(source, destination) } -// Child appends a new path element to a URI, separated by a '/' character. +// CanList will determine if the URI is listable or not. // -// Since: 1.4 -func Child(u fyne.URI, component string) (fyne.URI, error) { - // While as implemented this does not need to return an error, it is - // reasonable to expect that future implementations of this, especially - // once it gets moved into the URI interface will need to do so. This - // also brings it in line with Parent(). - - s := u.String() +// This method may fail in several ways: +// +// * Different permissions or credentials are required to check if the +// URI supports listing. +// +// * This URI scheme could represent some resources that can be listed, +// but this specific URI is not one of them (e.g. a file on a +// filesystem, as opposed to a directory). +// +// * Checking for listability depended on a lower level operation +// such as network or filesystem access that has failed in some way. +// +// * If the scheme of the given URI does not have a registered +// ListableRepository instance, then this method will fail with a +// repository.ErrOperationNotSupported. +// +// CanList is backed by the repository system - this function calls into a +// scheme-specific implementation from a registered repository. +// +// Since: 2.0 +func CanList(u fyne.URI) (bool, error) { + repo, err := repository.ForURI(u) + if err != nil { + return false, err + } - // guarantee that there will be a path separator - if s[len(s)-1:] != "/" { - s += "/" + lrepo, ok := repo.(repository.ListableRepository) + if !ok { + return false, repository.ErrOperationNotSupported } - return NewURI(s + component), nil + return lrepo.CanList(u) } -// Exists will return true if the resource the URI refers to exists, and false -// otherwise. If an error occurs while checking, false is returned as the first -// return. +// List returns a list of URIs that reference resources which are nested below +// the resource referenced by the argument. For example, listing a directory on +// a filesystem should return a list of files and directories it contains. // -// Since: 1.4 -func Exists(u fyne.URI) (bool, error) { - if u.Scheme() != "file" { - return false, fmt.Errorf("don't know how to check existence of %s scheme", u.Scheme()) +// This method may fail in several ways: +// +// * Different permissions or credentials are required to obtain a +// listing for the given URI. +// +// * This URI scheme could represent some resources that can be listed, +// but this specific URI is not one of them (e.g. a file on a +// filesystem, as opposed to a directory). This can be tested in advance +// using the Listable() function. +// +// * Obtaining the listing depended on a lower level operation such as +// network or filesystem access that has failed in some way. +// +// * If the scheme of the given URI does not have a registered +// ListableRepository instance, then this method will fail with a +// repository.ErrOperationNotSupported. +// +// List is backed by the repository system - this function either calls into a +// scheme-specific implementation from a registered repository, or fails with a +// URIOperationNotSupported error. +// +// Since: 2.0 +func List(u fyne.URI) ([]fyne.URI, error) { + repo, err := repository.ForURI(u) + if err != nil { + return nil, err } - _, err := os.Stat(u.String()[len(u.Scheme())+3:]) - if os.IsNotExist(err) { - return false, nil + lrepo, ok := repo.(repository.ListableRepository) + if !ok { + return nil, repository.ErrOperationNotSupported } + return lrepo.List(u) +} + +// CreateListable creates a new listable resource referenced by the given URI. +// CreateListable will error if the URI already references an extant resource. +// This method is used for storage repositories where listable resources are of +// a different underlying type than other resources - for example, in a typical +// filesystem ('file://'), CreateListable() corresponds to directory creation, +// and Writer() implies file creation for non-extant operands. +// +// For storage repositories where listable and non-listable resources are the +// of the same underlying type, CreateListable should be equivalent to calling +// Writer(), writing zero bytes, and then closing the `URIWriteCloser - in +// filesystem terms, the same as calling 'touch;'. +// +// Storage repositories which support listing, but not creation of listable +// objects may return repository.ErrOperationNotSupported. +// +// CreateListable should generally fail if the parent of it's operand does not +// exist, however this can vary by the implementation details of the specific +// storage repository. In filesystem terms, this function is "mkdir" not "mkdir +// -p". +// +// This method may fail in several ways: +// +// * Different permissions or credentials are required to create the requested +// resource. +// +// * Creating the resource depended on a lower level operation such as network +// or filesystem access that has failed in some way. +// +// * If the scheme of the given URI does not have a registered +// ListableRepository instance, then this method will fail with a +// repository.ErrOperationNotSupported. +// +// CreateListable is backed by the repository system - this function either +// calls into a scheme-specific implementation from a registered repository, or +// fails with a URIOperationNotSupported error. +// +// Since: 2.0 +func CreateListable(u fyne.URI) error { + repo, err := repository.ForURI(u) if err != nil { - return false, err + return err + } + + lrepo, ok := repo.(repository.ListableRepository) + if !ok { + return repository.ErrOperationNotSupported } - return true, nil + return lrepo.CreateListable(u) + } diff --git a/storage/uri_root_error.go b/storage/uri_root_error.go index c595516e18..d397181b31 100644 --- a/storage/uri_root_error.go +++ b/storage/uri_root_error.go @@ -1,16 +1,10 @@ package storage -// Declare conformance with Error interface -var _ error = URIRootError - -type uriRootError string - -// URIRootError should be thrown by fyne.URI implementations when the caller -// attempts to take the parent of the root. This way, downstream code that -// wants to programmatically walk up a URIs parent's will know when to stop -// iterating. -const URIRootError uriRootError = uriRootError("Cannot take the parent of the root element in a URI") - -func (e uriRootError) Error() string { - return string(URIRootError) -} +import ( + "fyne.io/fyne/v2/storage/repository" +) + +// URIRootError is a wrapper for repository.URIRootError +// +// Deprecated - use repository.ErrURIRoot instead +var URIRootError = repository.ErrURIRoot diff --git a/storage/uri_test.go b/storage/uri_test.go index a67b7f3f28..48c40db4f6 100644 --- a/storage/uri_test.go +++ b/storage/uri_test.go @@ -1,16 +1,87 @@ package storage_test import ( + "io/ioutil" "runtime" "testing" - "fyne.io/fyne/storage" + intRepo "fyne.io/fyne/v2/internal/repository" + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/storage/repository" - _ "fyne.io/fyne/test" + _ "fyne.io/fyne/v2/test" "github.com/stretchr/testify/assert" ) +func TestURIAuthority(t *testing.T) { + + // from IETF RFC 3986 + s := "foo://example.com:8042/over/there?name=ferret#nose" + u, err := storage.ParseURI(s) + assert.Nil(t, err) + assert.Equal(t, "example.com:8042", u.Authority()) + + // from IETF RFC 3986 + s = "urn:example:animal:ferret:nose" + u, err = storage.ParseURI(s) + assert.Nil(t, err) + assert.Equal(t, "", u.Authority()) +} + +func TestURIPath(t *testing.T) { + // from IETF RFC 3986 + s := "foo://example.com:8042/over/there?name=ferret#nose" + u, err := storage.ParseURI(s) + assert.Nil(t, err) + assert.Equal(t, "/over/there", u.Path()) + + s = "foo:///over/there" + u, err = storage.ParseURI(s) + assert.Nil(t, err) + assert.Equal(t, "/over/there", u.Path()) + + // NOTE: if net/url supported RFC3986, this would pass + // s = "foo://over/there" + // u, err = storage.ParseURI(s) + // assert.Nil(t, err) + // assert.Equal(t, "over/there", u.Path()) + + // from IETF RFC 3986 + s = "urn:example:animal:ferret:nose" + u, err = storage.ParseURI(s) + assert.Nil(t, err) + assert.Equal(t, "example:animal:ferret:nose", u.Path()) +} + +func TestURIQuery(t *testing.T) { + // from IETF RFC 3986 + s := "foo://example.com:8042/over/there?name=ferret#nose" + u, err := storage.ParseURI(s) + assert.Nil(t, err) + assert.Equal(t, "name=ferret", u.Query()) + + // from IETF RFC 3986 + s = "urn:example:animal:ferret:nose" + u, err = storage.ParseURI(s) + assert.Nil(t, err) + assert.Equal(t, "", u.Query()) +} + +func TestURIFragment(t *testing.T) { + // from IETF RFC 3986 + s := "foo://example.com:8042/over/there?name=ferret#nose" + u, err := storage.ParseURI(s) + assert.Nil(t, err) + assert.Equal(t, "nose", u.Fragment()) + + // from IETF RFC 3986 + s = "urn:example:animal:ferret:nose" + u, err = storage.ParseURI(s) + assert.Nil(t, err) + assert.Equal(t, "", u.Fragment()) +} + func TestNewURI(t *testing.T) { uriStr := "file:///nothere.txt" u := storage.NewURI(uriStr) @@ -63,23 +134,24 @@ func TestURI_Parent(t *testing.T) { assert.Nil(t, err) assert.Equal(t, "file://C:/foo/bar/", parent.String()) - parent, err = storage.Parent(storage.NewURI("http://foo/bar/baz/")) - assert.Nil(t, err) - assert.Equal(t, "http://foo/bar/", parent.String()) - - parent, err = storage.Parent(storage.NewURI("http:////foo/bar/baz/")) - assert.Nil(t, err) - assert.Equal(t, "http://foo/bar/", parent.String()) - - _, err = storage.Parent(storage.NewURI("http://foo")) - assert.Equal(t, storage.URIRootError, err) - - _, err = storage.Parent(storage.NewURI("http:///")) - assert.Equal(t, storage.URIRootError, err) - - parent, err = storage.Parent(storage.NewURI("https://///foo/bar/")) - assert.Nil(t, err) - assert.Equal(t, "https:///foo/", parent.String()) + // TODO hook in an http/https handler + //parent, err = storage.Parent(storage.NewURI("http://foo/bar/baz/")) + //assert.Nil(t, err) + //assert.Equal(t, "http://foo/bar/", parent.String()) + // + //parent, err = storage.Parent(storage.NewURI("http:////foo/bar/baz/")) + //assert.Nil(t, err) + //assert.Equal(t, "http://foo/bar/", parent.String()) + // + //_, err = storage.Parent(storage.NewURI("http://foo")) + //assert.Equal(t, repository.ErrURIRoot, err) + // + //_, err = storage.Parent(storage.NewURI("http:///")) + //assert.Equal(t, repository.ErrURIRoot, err) + // + //parent, err = storage.Parent(storage.NewURI("https://///foo/bar/")) + //assert.Nil(t, err) + //assert.Equal(t, "https:///foo/", parent.String()) if runtime.GOOS == "windows" { // Only the Windows version of filepath will know how to handle @@ -95,7 +167,7 @@ func TestURI_Parent(t *testing.T) { } _, err = storage.Parent(storage.NewURI("file:///")) - assert.Equal(t, storage.URIRootError, err) + assert.Equal(t, repository.ErrURIRoot, err) if runtime.GOOS == "windows" { // This is only an error under Windows, on *NIX this is a @@ -105,7 +177,7 @@ func TestURI_Parent(t *testing.T) { // This should cause an error, since this is a Windows-style // path and thus we can't get the parent of a drive letter. _, err = storage.Parent(storage.NewURI("file://C:/")) - assert.Equal(t, storage.URIRootError, err) + assert.Equal(t, repository.ErrURIRoot, err) } // Windows supports UNIX-style paths. /C:/ is also a valid path. @@ -138,3 +210,233 @@ func TestURI_Child(t *testing.T) { assert.Equal(t, "file://C:/foo/bar/baz", p.String()) } } + +func TestExists(t *testing.T) { + m := intRepo.NewInMemoryRepository("uritest") + repository.Register("uritest", m) + m.Data["/foo/bar/baz"] = []byte{} + + // and some URIs - we know that they will not fail parsing + foo, _ := storage.ParseURI("uritest:///foo/bar/baz") + fooExpectedParent, _ := storage.ParseURI("uritest:///foo/bar") + fooExists, err := storage.Exists(foo) + assert.True(t, fooExists) + assert.Nil(t, err) + + fooParent, err := storage.Parent(foo) + assert.Nil(t, err) + assert.Equal(t, fooExpectedParent.String(), fooParent.String()) + +} + +func TestWriteAndDelete(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := intRepo.NewInMemoryRepository("uritest") + repository.Register("uritest", m) + m.Data["/foo"] = []byte{} + m.Data["/bar"] = []byte{1, 2, 3} + + // and some URIs - we know that they will not fail parsing + foo, _ := storage.ParseURI("uritest:///foo") + bar, _ := storage.ParseURI("uritest:///bar") + baz, _ := storage.ParseURI("uritest:///baz") + + // write some data and assert there are no errors + fooWriter, err := storage.Writer(foo) + assert.Nil(t, err) + assert.NotNil(t, fooWriter) + + barWriter, err := storage.Writer(bar) + assert.Nil(t, err) + assert.NotNil(t, barWriter) + + bazWriter, err := storage.Writer(baz) + assert.Nil(t, err) + assert.NotNil(t, bazWriter) + + n, err := fooWriter.Write([]byte{1, 2, 3, 4, 5}) + assert.Nil(t, err) + assert.Equal(t, 5, n) + + n, err = barWriter.Write([]byte{6, 7, 8, 9}) + assert.Nil(t, err) + assert.Equal(t, 4, n) + + n, err = bazWriter.Write([]byte{5, 4, 3, 2, 1, 0}) + assert.Nil(t, err) + assert.Equal(t, 6, n) + + fooWriter.Close() + barWriter.Close() + bazWriter.Close() + + // now make sure we can read the data back correctly + fooReader, err := storage.Reader(foo) + assert.Nil(t, err) + fooData, err := ioutil.ReadAll(fooReader) + assert.Equal(t, []byte{1, 2, 3, 4, 5}, fooData) + assert.Nil(t, err) + + barReader, err := storage.Reader(bar) + assert.Nil(t, err) + barData, err := ioutil.ReadAll(barReader) + assert.Equal(t, []byte{6, 7, 8, 9}, barData) + assert.Nil(t, err) + + bazReader, err := storage.Reader(baz) + assert.Nil(t, err) + bazData, err := ioutil.ReadAll(bazReader) + assert.Equal(t, []byte{5, 4, 3, 2, 1, 0}, bazData) + assert.Nil(t, err) + + // now let's test deletion + err = storage.Delete(foo) + assert.Nil(t, err) + + err = storage.Delete(bar) + assert.Nil(t, err) + + err = storage.Delete(baz) + assert.Nil(t, err) + + fooExists, err := storage.Exists(foo) + assert.False(t, fooExists) + assert.Nil(t, err) + + barExists, err := storage.Exists(bar) + assert.False(t, barExists) + assert.Nil(t, err) + + bazExists, err := storage.Exists(baz) + assert.False(t, bazExists) + assert.Nil(t, err) + +} + +func TestCanWrite(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := intRepo.NewInMemoryRepository("uritest") + repository.Register("uritest", m) + m.Data["/foo"] = []byte{} + m.Data["/bar"] = []byte{1, 2, 3} + + // and some URIs - we know that they will not fail parsing + foo, _ := storage.ParseURI("uritest:///foo") + bar, _ := storage.ParseURI("uritest:///bar") + baz, _ := storage.ParseURI("uritest:///baz") + + fooCanWrite, err := storage.CanWrite(foo) + assert.True(t, fooCanWrite) + assert.Nil(t, err) + + barCanWrite, err := storage.CanWrite(bar) + assert.True(t, barCanWrite) + assert.Nil(t, err) + + bazCanWrite, err := storage.CanWrite(baz) + assert.True(t, bazCanWrite) + assert.Nil(t, err) +} + +func TestCanRead(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := intRepo.NewInMemoryRepository("uritest") + repository.Register("uritest", m) + m.Data["/foo"] = []byte{} + m.Data["/bar"] = []byte{1, 2, 3} + + // and some URIs - we know that they will not fail parsing + foo, _ := storage.ParseURI("uritest:///foo") + bar, _ := storage.ParseURI("uritest:///bar") + baz, _ := storage.ParseURI("uritest:///baz") + + fooCanRead, err := storage.CanRead(foo) + assert.True(t, fooCanRead) + assert.Nil(t, err) + + barCanRead, err := storage.CanRead(bar) + assert.True(t, barCanRead) + assert.Nil(t, err) + + bazCanRead, err := storage.CanRead(baz) + assert.False(t, bazCanRead) + assert.Nil(t, err) +} + +func TestCopy(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := intRepo.NewInMemoryRepository("uritest") + repository.Register("uritest", m) + m.Data["/foo"] = []byte{1, 2, 3} + + foo, _ := storage.ParseURI("uritest:///foo") + bar, _ := storage.ParseURI("uritest:///bar") + + err := storage.Copy(foo, bar) + assert.Nil(t, err) + + assert.Equal(t, m.Data["/foo"], m.Data["/bar"]) +} + +func TestRepositoryMove(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := intRepo.NewInMemoryRepository("uritest") + repository.Register("uritest", m) + m.Data["/foo"] = []byte{1, 2, 3} + + foo, _ := storage.ParseURI("uritest:///foo") + bar, _ := storage.ParseURI("uritest:///bar") + + err := storage.Move(foo, bar) + assert.Nil(t, err) + + assert.Equal(t, []byte{1, 2, 3}, m.Data["/bar"]) + + exists, err := m.Exists(foo) + assert.Nil(t, err) + assert.False(t, exists) +} + +func TestRepositoryListing(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := intRepo.NewInMemoryRepository("uritest") + repository.Register("uritest", m) + m.Data["/foo"] = []byte{1, 2, 3} + m.Data["/foo/bar"] = []byte{1, 2, 3} + m.Data["/foo/baz/"] = []byte{1, 2, 3} + m.Data["/foo/baz/quux"] = []byte{1, 2, 3} + + foo, _ := storage.ParseURI("uritest:///foo") + + canList, err := storage.CanList(foo) + assert.Nil(t, err) + assert.True(t, canList) + + listing, err := storage.List(foo) + assert.Nil(t, err) + stringListing := []string{} + for _, u := range listing { + stringListing = append(stringListing, u.String()) + } + assert.ElementsMatch(t, []string{"uritest:///foo/bar", "uritest:///foo/baz/"}, stringListing) +} + +func TestCreateListable(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := intRepo.NewInMemoryRepository("uritest") + repository.Register("uritest", m) + + foo, _ := storage.ParseURI("uritest:///foo") + + err := storage.CreateListable(foo) + assert.Nil(t, err) + + assert.Equal(t, m.Data["/foo"], []byte{}) + + // trying to create something we already created should fail + err = storage.CreateListable(foo) + assert.NotNil(t, err) + + // NOTE: creating an InMemoryRepository path with a non-extant parent + // is specifically not an error, so that case is not tested. +} diff --git a/test/device.go b/test/device.go index 034210bd04..8d8c6a39eb 100644 --- a/test/device.go +++ b/test/device.go @@ -1,6 +1,6 @@ package test -import "fyne.io/fyne" +import "fyne.io/fyne/v2" type device struct { } diff --git a/test/markup_renderer.go b/test/markup_renderer.go index c752dfaedd..df67331234 100644 --- a/test/markup_renderer.go +++ b/test/markup_renderer.go @@ -8,11 +8,11 @@ import ( "strings" "unsafe" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/driver" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/driver" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" ) type markupRenderer struct { diff --git a/test/markup_renderer_test.go b/test/markup_renderer_test.go index 11fed4c2a8..0dc948cd42 100644 --- a/test/markup_renderer_test.go +++ b/test/markup_renderer_test.go @@ -7,12 +7,12 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/container" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) func Test_snapshot(t *testing.T) { diff --git a/test/notification.go b/test/notification.go index d6419c76e8..0e8bc12878 100644 --- a/test/notification.go +++ b/test/notification.go @@ -3,7 +3,7 @@ package test import ( "testing" - "fyne.io/fyne" + "fyne.io/fyne/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/test/notification_test.go b/test/notification_test.go index b1d53b740c..e7f9442b84 100644 --- a/test/notification_test.go +++ b/test/notification_test.go @@ -3,8 +3,8 @@ package test_test import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/test" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/test" "github.com/stretchr/testify/assert" ) diff --git a/test/storage.go b/test/storage.go index d03d34db6d..339edece37 100644 --- a/test/storage.go +++ b/test/storage.go @@ -3,8 +3,8 @@ package test import ( "os" - "fyne.io/fyne" - "fyne.io/fyne/storage" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" ) type testStorage struct { diff --git a/test/test.go b/test/test.go index 234ebdf801..616bbdce3a 100644 --- a/test/test.go +++ b/test/test.go @@ -10,11 +10,11 @@ import ( "testing" "time" - "fyne.io/fyne" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/internal/driver" - "fyne.io/fyne/internal/test" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/internal/driver" + "fyne.io/fyne/v2/internal/test" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -49,7 +49,7 @@ func AssertImageMatches(t *testing.T, masterFilename string, img image.Image, ms // Closing elements stand on their own line, too, using the same indentation as the opening element. // The only exception to this are text elements which do not contain line breaks unless the text includes them. // -// Since: 2.0.0 +// Since: 2.0 func AssertRendersToMarkup(t *testing.T, masterFilename string, c fyne.Canvas, msgAndArgs ...interface{}) bool { wd, err := os.Getwd() require.NoError(t, err) diff --git a/test/test_test.go b/test/test_test.go index d9c213fb0c..d14591d0cf 100644 --- a/test/test_test.go +++ b/test/test_test.go @@ -9,10 +9,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/test" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/widget" ) func TestAssertCanvasTappableAt(t *testing.T) { diff --git a/test/testapp.go b/test/testapp.go index 02736c698a..729436b916 100644 --- a/test/testapp.go +++ b/test/testapp.go @@ -1,15 +1,15 @@ // Package test provides utility drivers for running UI tests without rendering -package test // import "fyne.io/fyne/test" +package test // import "fyne.io/fyne/v2/test" import ( "net/url" "sync" - "fyne.io/fyne" - "fyne.io/fyne/internal" - "fyne.io/fyne/internal/app" - "fyne.io/fyne/internal/painter" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal" + "fyne.io/fyne/v2/internal/app" + "fyne.io/fyne/v2/internal/painter" + "fyne.io/fyne/v2/theme" ) // ensure we have a dummy app loaded and ready to test diff --git a/test/testcanvas.go b/test/testcanvas.go index ded6155a14..24ac67b32c 100644 --- a/test/testcanvas.go +++ b/test/testcanvas.go @@ -5,11 +5,11 @@ import ( "image/draw" "sync" - "fyne.io/fyne" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal" - "fyne.io/fyne/internal/app" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal" + "fyne.io/fyne/v2/internal/app" + "fyne.io/fyne/v2/theme" ) var ( diff --git a/test/testcanvas_test.go b/test/testcanvas_test.go index 058d5e3177..d05ad135ce 100644 --- a/test/testcanvas_test.go +++ b/test/testcanvas_test.go @@ -5,8 +5,8 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) func TestTestCanvas_Capture(t *testing.T) { diff --git a/test/testclipboard.go b/test/testclipboard.go index 9f844b901d..d98f689aa0 100644 --- a/test/testclipboard.go +++ b/test/testclipboard.go @@ -1,6 +1,6 @@ package test -import "fyne.io/fyne" +import "fyne.io/fyne/v2" type testClipboard struct { content string diff --git a/test/testdriver.go b/test/testdriver.go index 0895512486..6c26e49465 100644 --- a/test/testdriver.go +++ b/test/testdriver.go @@ -5,10 +5,12 @@ import ( "log" "sync" - "fyne.io/fyne" - "fyne.io/fyne/internal/driver" - "fyne.io/fyne/internal/painter" - "fyne.io/fyne/internal/painter/software" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/driver" + "fyne.io/fyne/v2/internal/painter" + "fyne.io/fyne/v2/internal/painter/software" + intRepo "fyne.io/fyne/v2/internal/repository" + "fyne.io/fyne/v2/storage/repository" "github.com/goki/freetype/truetype" "golang.org/x/image/font" @@ -33,6 +35,7 @@ var _ fyne.Driver = (*testDriver)(nil) func NewDriver() fyne.Driver { drv := new(testDriver) drv.windowsMutex = sync.RWMutex{} + repository.Register("file", intRepo.NewFileRepository()) // make a single dummy window for rendering tests drv.CreateWindow("") diff --git a/test/testfile.go b/test/testfile.go index eaa7d8045a..f40048a2ff 100644 --- a/test/testfile.go +++ b/test/testfile.go @@ -7,8 +7,8 @@ import ( "os" "path/filepath" - "fyne.io/fyne" - "fyne.io/fyne/storage" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" ) type file struct { diff --git a/test/testtheme.go b/test/testtheme.go index 685bfacd85..3ba558cc28 100644 --- a/test/testtheme.go +++ b/test/testtheme.go @@ -3,8 +3,8 @@ package test import ( "image/color" - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) var ( diff --git a/test/testwindow.go b/test/testwindow.go index 2178d7c852..25eb4cbb66 100644 --- a/test/testwindow.go +++ b/test/testwindow.go @@ -1,7 +1,7 @@ package test import ( - "fyne.io/fyne" + "fyne.io/fyne/v2" ) type testWindow struct { diff --git a/test/theme.go b/test/theme.go index b3889d07fb..4f10b9fd1d 100644 --- a/test/theme.go +++ b/test/theme.go @@ -3,8 +3,8 @@ package test import ( "image/color" - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) var defaultTheme fyne.Theme diff --git a/theme.go b/theme.go index 0296213e5d..5d0223363f 100644 --- a/theme.go +++ b/theme.go @@ -4,27 +4,27 @@ import "image/color" // ThemeVariant indicates a variation of a theme, such as light or dark. // -// Since 2.0.0 +// Since: 2.0 type ThemeVariant uint // ThemeColorName is used to look up a colour based on its name. // -// Since 2.0.0 +// Since: 2.0 type ThemeColorName string // ThemeIconName is used to look up an icon based on its name. // -// Since 2.0.0 +// Since: 2.0 type ThemeIconName string // ThemeSizeName is used to look up a size based on its name. // -// Since 2.0.0 +// Since: 2.0 type ThemeSizeName string // Theme defines the method to look up colors, sizes and fonts that make up a Fyne theme. // -// Since 2.0.0 +// Since: 2.0 type Theme interface { Color(ThemeColorName, ThemeVariant) color.Color Font(TextStyle) Resource @@ -33,9 +33,9 @@ type Theme interface { } // LegacyTheme defines the requirements of any Fyne theme. -// This was previously called Theme and is kept for simpler transition of applications built before 2.0.0. +// This was previously called Theme and is kept for simpler transition of applications built before v2.0.0. // -// Since 2.0.0 +// Since: 2.0 type LegacyTheme interface { BackgroundColor() color.Color ButtonColor() color.Color diff --git a/theme/bundled-fonts.go b/theme/bundled-fonts.go index 2bdf424514..7a60654a6e 100644 --- a/theme/bundled-fonts.go +++ b/theme/bundled-fonts.go @@ -3,7 +3,7 @@ package theme -import "fyne.io/fyne" +import "fyne.io/fyne/v2" var regular = &fyne.StaticResource{ StaticName: "NotoSans-Regular.ttf", diff --git a/theme/bundled-icons.go b/theme/bundled-icons.go index 4fd22644c5..1776a785e5 100644 --- a/theme/bundled-icons.go +++ b/theme/bundled-icons.go @@ -3,7 +3,7 @@ package theme -import "fyne.io/fyne" +import "fyne.io/fyne/v2" var fynelogo = &fyne.StaticResource{ StaticName: "fyne.png", diff --git a/theme/gen.go b/theme/gen.go index bd77bb9b43..0d56f56ebf 100644 --- a/theme/gen.go +++ b/theme/gen.go @@ -13,7 +13,7 @@ import ( "runtime" "strings" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) const fontFace = "NotoSans" @@ -79,7 +79,7 @@ func writeFile(filename string, contents []byte) error { func main() { f := &bytes.Buffer{} - f.WriteString(fileHeader + "\n\npackage theme\n\nimport \"fyne.io/fyne\"\n\n") + f.WriteString(fileHeader + "\n\npackage theme\n\nimport \"fyne.io/fyne/v2\"\n\n") bundleFont(fontFace, "Regular", f) bundleFont(fontFace, "Bold", f) bundleFont(fontFace, "Italic", f) @@ -92,7 +92,7 @@ func main() { } f = &bytes.Buffer{} - f.WriteString(fileHeader + "\n\npackage theme\n\nimport \"fyne.io/fyne\"\n\n") + f.WriteString(fileHeader + "\n\npackage theme\n\nimport \"fyne.io/fyne/v2\"\n\n") icon := path.Join(iconDir(), "fyne.png") bundleFile("fyne-logo", icon, f) diff --git a/theme/icons.go b/theme/icons.go index 5fcae9c4ef..927913845c 100644 --- a/theme/icons.go +++ b/theme/icons.go @@ -6,403 +6,403 @@ import ( "fmt" "image/color" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) const ( // IconNameCancel is the name of theme lookup for cancel icon. // - // Since 2.0.0 + // Since: 2.0 IconNameCancel fyne.ThemeIconName = "cancel" // IconNameConfirm is the name of theme lookup for confirm icon. // - // Since 2.0.0 + // Since: 2.0 IconNameConfirm fyne.ThemeIconName = "confirm" // IconNameDelete is the name of theme lookup for delete icon. // - // Since 2.0.0 + // Since: 2.0 IconNameDelete fyne.ThemeIconName = "delete" // IconNameSearch is the name of theme lookup for search icon. // - // Since 2.0.0 + // Since: 2.0 IconNameSearch fyne.ThemeIconName = "search" // IconNameSearchReplace is the name of theme lookup for search and replace icon. // - // Since 2.0.0 + // Since: 2.0 IconNameSearchReplace fyne.ThemeIconName = "searchReplace" // IconNameMenu is the name of theme lookup for menu icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMenu fyne.ThemeIconName = "menu" // IconNameMenuExpand is the name of theme lookup for menu expansion icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMenuExpand fyne.ThemeIconName = "menuExpand" // IconNameCheckButtonChecked is the name of theme lookup for checked check button icon. // - // Since 2.0.0 + // Since: 2.0 IconNameCheckButtonChecked fyne.ThemeIconName = "checked" // IconNameCheckButton is the name of theme lookup for unchecked check button icon. // - // Since 2.0.0 + // Since: 2.0 IconNameCheckButton fyne.ThemeIconName = "unchecked" // IconNameRadioButton is the name of theme lookup for radio button unchecked icon. // - // Since 2.0.0 + // Since: 2.0 IconNameRadioButton fyne.ThemeIconName = "radioButton" // IconNameRadioButtonChecked is the name of theme lookup for radio button checked icon. // - // Since 2.0.0 + // Since: 2.0 IconNameRadioButtonChecked fyne.ThemeIconName = "radioButtonChecked" // IconNameColorAchromatic is the name of theme lookup for greyscale color icon. // - // Since 2.0.0 + // Since: 2.0 IconNameColorAchromatic fyne.ThemeIconName = "colorAchromatic" // IconNameColorChromatic is the name of theme lookup for full color icon. // - // Since 2.0.0 + // Since: 2.0 IconNameColorChromatic fyne.ThemeIconName = "colorChromatic" // IconNameColorPalette is the name of theme lookup for color palette icon. // - // Since 2.0.0 + // Since: 2.0 IconNameColorPalette fyne.ThemeIconName = "colorPalette" // IconNameContentAdd is the name of theme lookup for content add icon. // - // Since 2.0.0 + // Since: 2.0 IconNameContentAdd fyne.ThemeIconName = "contentAdd" // IconNameContentRemove is the name of theme lookup for content remove icon. // - // Since 2.0.0 + // Since: 2.0 IconNameContentRemove fyne.ThemeIconName = "contentRemove" // IconNameContentCut is the name of theme lookup for content cut icon. // - // Since 2.0.0 + // Since: 2.0 IconNameContentCut fyne.ThemeIconName = "contentCut" // IconNameContentCopy is the name of theme lookup for content copy icon. // - // Since 2.0.0 + // Since: 2.0 IconNameContentCopy fyne.ThemeIconName = "contentCopy" // IconNameContentPaste is the name of theme lookup for content paste icon. // - // Since 2.0.0 + // Since: 2.0 IconNameContentPaste fyne.ThemeIconName = "contentPaste" // IconNameContentClear is the name of theme lookup for content clear icon. // - // Since 2.0.0 + // Since: 2.0 IconNameContentClear fyne.ThemeIconName = "contentClear" // IconNameContentRedo is the name of theme lookup for content redo icon. // - // Since 2.0.0 + // Since: 2.0 IconNameContentRedo fyne.ThemeIconName = "contentRedo" // IconNameContentUndo is the name of theme lookup for content undo icon. // - // Since 2.0.0 + // Since: 2.0 IconNameContentUndo fyne.ThemeIconName = "contentUndo" // IconNameInfo is the name of theme lookup for info icon. // - // Since 2.0.0 + // Since: 2.0 IconNameInfo fyne.ThemeIconName = "info" // IconNameQuestion is the name of theme lookup for question icon. // - // Since 2.0.0 + // Since: 2.0 IconNameQuestion fyne.ThemeIconName = "question" // IconNameWarning is the name of theme lookup for warning icon. // - // Since 2.0.0 + // Since: 2.0 IconNameWarning fyne.ThemeIconName = "warning" // IconNameError is the name of theme lookup for error icon. // - // Since 2.0.0 + // Since: 2.0 IconNameError fyne.ThemeIconName = "error" // IconNameDocument is the name of theme lookup for document icon. // - // Since 2.0.0 + // Since: 2.0 IconNameDocument fyne.ThemeIconName = "document" // IconNameDocumentCreate is the name of theme lookup for document create icon. // - // Since 2.0.0 + // Since: 2.0 IconNameDocumentCreate fyne.ThemeIconName = "documentCreate" // IconNameDocumentPrint is the name of theme lookup for document print icon. // - // Since 2.0.0 + // Since: 2.0 IconNameDocumentPrint fyne.ThemeIconName = "documentPrint" // IconNameDocumentSave is the name of theme lookup for document save icon. // - // Since 2.0.0 + // Since: 2.0 IconNameDocumentSave fyne.ThemeIconName = "documentSave" // IconNameMailAttachment is the name of theme lookup for mail attachment icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMailAttachment fyne.ThemeIconName = "mailAttachment" // IconNameMailCompose is the name of theme lookup for mail compose icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMailCompose fyne.ThemeIconName = "mailCompose" // IconNameMailForward is the name of theme lookup for mail forward icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMailForward fyne.ThemeIconName = "mailForward" // IconNameMailReply is the name of theme lookup for mail reply icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMailReply fyne.ThemeIconName = "mailReply" // IconNameMailReplyAll is the name of theme lookup for mail reply-all icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMailReplyAll fyne.ThemeIconName = "mailReplyAll" // IconNameMailSend is the name of theme lookup for mail send icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMailSend fyne.ThemeIconName = "mailSend" // IconNameMediaFastForward is the name of theme lookup for media fast-forward icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMediaFastForward fyne.ThemeIconName = "mediaFastForward" // IconNameMediaFastRewind is the name of theme lookup for media fast-rewind icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMediaFastRewind fyne.ThemeIconName = "mediaFastRewind" // IconNameMediaPause is the name of theme lookup for media pause icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMediaPause fyne.ThemeIconName = "mediaPause" // IconNameMediaPlay is the name of theme lookup for media play icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMediaPlay fyne.ThemeIconName = "mediaPlay" // IconNameMediaRecord is the name of theme lookup for media record icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMediaRecord fyne.ThemeIconName = "mediaRecord" // IconNameMediaReplay is the name of theme lookup for media replay icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMediaReplay fyne.ThemeIconName = "mediaReplay" // IconNameMediaSkipNext is the name of theme lookup for media skip next icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMediaSkipNext fyne.ThemeIconName = "mediaSkipNext" // IconNameMediaSkipPrevious is the name of theme lookup for media skip previous icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMediaSkipPrevious fyne.ThemeIconName = "mediaSkipPrevious" // IconNameMediaStop is the name of theme lookup for media stop icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMediaStop fyne.ThemeIconName = "mediaStop" // IconNameMoveDown is the name of theme lookup for move down icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMoveDown fyne.ThemeIconName = "arrowDown" // IconNameMoveUp is the name of theme lookup for move up icon. // - // Since 2.0.0 + // Since: 2.0 IconNameMoveUp fyne.ThemeIconName = "arrowUp" // IconNameNavigateBack is the name of theme lookup for navigate back icon. // - // Since 2.0.0 + // Since: 2.0 IconNameNavigateBack fyne.ThemeIconName = "arrowBack" // IconNameNavigateNext is the name of theme lookup for navigate next icon. // - // Since 2.0.0 + // Since: 2.0 IconNameNavigateNext fyne.ThemeIconName = "arrowForward" // IconNameArrowDropDown is the name of theme lookup for drop-down arrow icon. // - // Since 2.0.0 + // Since: 2.0 IconNameArrowDropDown fyne.ThemeIconName = "arrowDropDown" // IconNameArrowDropUp is the name of theme lookup for drop-up arrow icon. // - // Since 2.0.0 + // Since: 2.0 IconNameArrowDropUp fyne.ThemeIconName = "arrowDropUp" // IconNameFile is the name of theme lookup for file icon. // - // Since 2.0.0 + // Since: 2.0 IconNameFile fyne.ThemeIconName = "file" // IconNameFileApplication is the name of theme lookup for file application icon. // - // Since 2.0.0 + // Since: 2.0 IconNameFileApplication fyne.ThemeIconName = "fileApplication" // IconNameFileAudio is the name of theme lookup for file audio icon. // - // Since 2.0.0 + // Since: 2.0 IconNameFileAudio fyne.ThemeIconName = "fileAudio" // IconNameFileImage is the name of theme lookup for file image icon. // - // Since 2.0.0 + // Since: 2.0 IconNameFileImage fyne.ThemeIconName = "fileImage" // IconNameFileText is the name of theme lookup for file text icon. // - // Since 2.0.0 + // Since: 2.0 IconNameFileText fyne.ThemeIconName = "fileText" // IconNameFileVideo is the name of theme lookup for file video icon. // - // Since 2.0.0 + // Since: 2.0 IconNameFileVideo fyne.ThemeIconName = "fileVideo" // IconNameFolder is the name of theme lookup for folder icon. // - // Since 2.0.0 + // Since: 2.0 IconNameFolder fyne.ThemeIconName = "folder" // IconNameFolderNew is the name of theme lookup for folder new icon. // - // Since 2.0.0 + // Since: 2.0 IconNameFolderNew fyne.ThemeIconName = "folderNew" // IconNameFolderOpen is the name of theme lookup for folder open icon. // - // Since 2.0.0 + // Since: 2.0 IconNameFolderOpen fyne.ThemeIconName = "folderOpen" // IconNameHelp is the name of theme lookup for help icon. // - // Since 2.0.0 + // Since: 2.0 IconNameHelp fyne.ThemeIconName = "help" // IconNameHistory is the name of theme lookup for history icon. // - // Since 2.0.0 + // Since: 2.0 IconNameHistory fyne.ThemeIconName = "history" // IconNameHome is the name of theme lookup for home icon. // - // Since 2.0.0 + // Since: 2.0 IconNameHome fyne.ThemeIconName = "home" // IconNameSettings is the name of theme lookup for settings icon. // - // Since 2.0.0 + // Since: 2.0 IconNameSettings fyne.ThemeIconName = "settings" // IconNameStorage is the name of theme lookup for storage icon. // - // Since 2.0.0 + // Since: 2.0 IconNameStorage fyne.ThemeIconName = "storage" // IconNameUpload is the name of theme lookup for upload icon. // - // Since 2.0.0 + // Since: 2.0 IconNameUpload fyne.ThemeIconName = "upload" // IconNameViewFullScreen is the name of theme lookup for view fullscreen icon. // - // Since 2.0.0 + // Since: 2.0 IconNameViewFullScreen fyne.ThemeIconName = "viewFullScreen" // IconNameViewRefresh is the name of theme lookup for view refresh icon. // - // Since 2.0.0 + // Since: 2.0 IconNameViewRefresh fyne.ThemeIconName = "viewRefresh" // IconNameViewZoomFit is the name of theme lookup for view zoom fit icon. // - // Since 2.0.0 + // Since: 2.0 IconNameViewZoomFit fyne.ThemeIconName = "viewZoomFit" // IconNameViewZoomIn is the name of theme lookup for view zoom in icon. // - // Since 2.0.0 + // Since: 2.0 IconNameViewZoomIn fyne.ThemeIconName = "viewZoomIn" // IconNameViewZoomOut is the name of theme lookup for view zoom out icon. // - // Since 2.0.0 + // Since: 2.0 IconNameViewZoomOut fyne.ThemeIconName = "viewZoomOut" // IconNameViewRestore is the name of theme lookup for view restore icon. // - // Since 2.0.0 + // Since: 2.0 IconNameViewRestore fyne.ThemeIconName = "viewRestore" // IconNameVisibility is the name of theme lookup for visibility icon. // - // Since 2.0.0 + // Since: 2.0 IconNameVisibility fyne.ThemeIconName = "visibility" // IconNameVisibilityOff is the name of theme lookup for invisibility icon. // - // Since 2.0.0 + // Since: 2.0 IconNameVisibilityOff fyne.ThemeIconName = "visibilityOff" // IconNameVolumeDown is the name of theme lookup for volume down icon. // - // Since 2.0.0 + // Since: 2.0 IconNameVolumeDown fyne.ThemeIconName = "volumeDown" // IconNameVolumeMute is the name of theme lookup for volume mute icon. // - // Since 2.0.0 + // Since: 2.0 IconNameVolumeMute fyne.ThemeIconName = "volumeMute" // IconNameVolumeUp is the name of theme lookup for volume up icon. // - // Since 2.0.0 + // Since: 2.0 IconNameVolumeUp fyne.ThemeIconName = "volumeUp" // IconNameDownload is the name of theme lookup for download icon. // - // Since 2.0.0 + // Since: 2.0 IconNameDownload fyne.ThemeIconName = "download" // IconNameComputer is the name of theme lookup for computer icon. // - // Since 2.0.0 + // Since: 2.0 IconNameComputer fyne.ThemeIconName = "computer" ) @@ -666,395 +666,404 @@ func FyneLogo() fyne.Resource { // CancelIcon returns a resource containing the standard cancel icon for the current theme func CancelIcon() fyne.Resource { - return current().Icon(IconNameCancel) + return safeIconLookup(IconNameCancel) } // ConfirmIcon returns a resource containing the standard confirm icon for the current theme func ConfirmIcon() fyne.Resource { - return current().Icon(IconNameConfirm) + return safeIconLookup(IconNameConfirm) } // DeleteIcon returns a resource containing the standard delete icon for the current theme func DeleteIcon() fyne.Resource { - return current().Icon(IconNameDelete) + return safeIconLookup(IconNameDelete) } // SearchIcon returns a resource containing the standard search icon for the current theme func SearchIcon() fyne.Resource { - return current().Icon(IconNameSearch) + return safeIconLookup(IconNameSearch) } // SearchReplaceIcon returns a resource containing the standard search and replace icon for the current theme func SearchReplaceIcon() fyne.Resource { - return current().Icon(IconNameSearchReplace) + return safeIconLookup(IconNameSearchReplace) } // MenuIcon returns a resource containing the standard (mobile) menu icon for the current theme func MenuIcon() fyne.Resource { - return current().Icon(IconNameMenu) + return safeIconLookup(IconNameMenu) } // MenuExpandIcon returns a resource containing the standard (mobile) expand "submenu icon for the current theme func MenuExpandIcon() fyne.Resource { - return current().Icon(IconNameMenuExpand) + return safeIconLookup(IconNameMenuExpand) } // CheckButtonIcon returns a resource containing the standard checkbox icon for the current theme func CheckButtonIcon() fyne.Resource { - return current().Icon(IconNameCheckButton) + return safeIconLookup(IconNameCheckButton) } // CheckButtonCheckedIcon returns a resource containing the standard checkbox checked icon for the current theme func CheckButtonCheckedIcon() fyne.Resource { - return current().Icon(IconNameCheckButtonChecked) + return safeIconLookup(IconNameCheckButtonChecked) } // RadioButtonIcon returns a resource containing the standard radio button icon for the current theme func RadioButtonIcon() fyne.Resource { - return current().Icon(IconNameRadioButton) + return safeIconLookup(IconNameRadioButton) } // RadioButtonCheckedIcon returns a resource containing the standard radio button checked icon for the current theme func RadioButtonCheckedIcon() fyne.Resource { - return current().Icon(IconNameRadioButtonChecked) + return safeIconLookup(IconNameRadioButtonChecked) } // ContentAddIcon returns a resource containing the standard content add icon for the current theme func ContentAddIcon() fyne.Resource { - return current().Icon(IconNameContentAdd) + return safeIconLookup(IconNameContentAdd) } // ContentRemoveIcon returns a resource containing the standard content remove icon for the current theme func ContentRemoveIcon() fyne.Resource { - return current().Icon(IconNameContentRemove) + return safeIconLookup(IconNameContentRemove) } // ContentClearIcon returns a resource containing the standard content clear icon for the current theme func ContentClearIcon() fyne.Resource { - return current().Icon(IconNameContentClear) + return safeIconLookup(IconNameContentClear) } // ContentCutIcon returns a resource containing the standard content cut icon for the current theme func ContentCutIcon() fyne.Resource { - return current().Icon(IconNameContentCut) + return safeIconLookup(IconNameContentCut) } // ContentCopyIcon returns a resource containing the standard content copy icon for the current theme func ContentCopyIcon() fyne.Resource { - return current().Icon(IconNameContentCopy) + return safeIconLookup(IconNameContentCopy) } // ContentPasteIcon returns a resource containing the standard content paste icon for the current theme func ContentPasteIcon() fyne.Resource { - return current().Icon(IconNameContentPaste) + return safeIconLookup(IconNameContentPaste) } // ContentRedoIcon returns a resource containing the standard content redo icon for the current theme func ContentRedoIcon() fyne.Resource { - return current().Icon(IconNameContentRedo) + return safeIconLookup(IconNameContentRedo) } // ContentUndoIcon returns a resource containing the standard content undo icon for the current theme func ContentUndoIcon() fyne.Resource { - return current().Icon(IconNameContentUndo) + return safeIconLookup(IconNameContentUndo) } // ColorAchromaticIcon returns a resource containing the standard achromatic color icon for the current theme func ColorAchromaticIcon() fyne.Resource { - return current().Icon(IconNameColorAchromatic) + return safeIconLookup(IconNameColorAchromatic) } // ColorChromaticIcon returns a resource containing the standard chromatic color icon for the current theme func ColorChromaticIcon() fyne.Resource { - return current().Icon(IconNameColorChromatic) + return safeIconLookup(IconNameColorChromatic) } // ColorPaletteIcon returns a resource containing the standard color palette icon for the current theme func ColorPaletteIcon() fyne.Resource { - return current().Icon(IconNameColorPalette) + return safeIconLookup(IconNameColorPalette) } // DocumentIcon returns a resource containing the standard document icon for the current theme func DocumentIcon() fyne.Resource { - return current().Icon(IconNameDocument) + return safeIconLookup(IconNameDocument) } // DocumentCreateIcon returns a resource containing the standard document create icon for the current theme func DocumentCreateIcon() fyne.Resource { - return current().Icon(IconNameDocumentCreate) + return safeIconLookup(IconNameDocumentCreate) } // DocumentPrintIcon returns a resource containing the standard document print icon for the current theme func DocumentPrintIcon() fyne.Resource { - return current().Icon(IconNameDocumentPrint) + return safeIconLookup(IconNameDocumentPrint) } // DocumentSaveIcon returns a resource containing the standard document save icon for the current theme func DocumentSaveIcon() fyne.Resource { - return current().Icon(IconNameDocumentSave) + return safeIconLookup(IconNameDocumentSave) } // InfoIcon returns a resource containing the standard dialog info icon for the current theme func InfoIcon() fyne.Resource { - return current().Icon(IconNameInfo) + return safeIconLookup(IconNameInfo) } // QuestionIcon returns a resource containing the standard dialog question icon for the current theme func QuestionIcon() fyne.Resource { - return current().Icon(IconNameQuestion) + return safeIconLookup(IconNameQuestion) } // WarningIcon returns a resource containing the standard dialog warning icon for the current theme func WarningIcon() fyne.Resource { - return current().Icon(IconNameWarning) + return safeIconLookup(IconNameWarning) } // ErrorIcon returns a resource containing the standard dialog error icon for the current theme func ErrorIcon() fyne.Resource { - return current().Icon(IconNameError) + return safeIconLookup(IconNameError) } // FileIcon returns a resource containing the appropriate file icon for the current theme func FileIcon() fyne.Resource { - return current().Icon(IconNameFile) + return safeIconLookup(IconNameFile) } // FileApplicationIcon returns a resource containing the file icon representing application files for the current theme func FileApplicationIcon() fyne.Resource { - return current().Icon(IconNameFileApplication) + return safeIconLookup(IconNameFileApplication) } // FileAudioIcon returns a resource containing the file icon representing audio files for the current theme func FileAudioIcon() fyne.Resource { - return current().Icon(IconNameFileAudio) + return safeIconLookup(IconNameFileAudio) } // FileImageIcon returns a resource containing the file icon representing image files for the current theme func FileImageIcon() fyne.Resource { - return current().Icon(IconNameFileImage) + return safeIconLookup(IconNameFileImage) } // FileTextIcon returns a resource containing the file icon representing text files for the current theme func FileTextIcon() fyne.Resource { - return current().Icon(IconNameFileText) + return safeIconLookup(IconNameFileText) } // FileVideoIcon returns a resource containing the file icon representing video files for the current theme func FileVideoIcon() fyne.Resource { - return current().Icon(IconNameFileVideo) + return safeIconLookup(IconNameFileVideo) } // FolderIcon returns a resource containing the standard folder icon for the current theme func FolderIcon() fyne.Resource { - return current().Icon(IconNameFolder) + return safeIconLookup(IconNameFolder) } // FolderNewIcon returns a resource containing the standard folder creation icon for the current theme func FolderNewIcon() fyne.Resource { - return current().Icon(IconNameFolderNew) + return safeIconLookup(IconNameFolderNew) } // FolderOpenIcon returns a resource containing the standard folder open icon for the current theme func FolderOpenIcon() fyne.Resource { - return current().Icon(IconNameFolderOpen) + return safeIconLookup(IconNameFolderOpen) } // HelpIcon returns a resource containing the standard help icon for the current theme func HelpIcon() fyne.Resource { - return current().Icon(IconNameHelp) + return safeIconLookup(IconNameHelp) } // HistoryIcon returns a resource containing the standard history icon for the current theme func HistoryIcon() fyne.Resource { - return current().Icon(IconNameHistory) + return safeIconLookup(IconNameHistory) } // HomeIcon returns a resource containing the standard home folder icon for the current theme func HomeIcon() fyne.Resource { - return current().Icon(IconNameHome) + return safeIconLookup(IconNameHome) } // SettingsIcon returns a resource containing the standard settings icon for the current theme func SettingsIcon() fyne.Resource { - return current().Icon(IconNameSettings) + return safeIconLookup(IconNameSettings) } // MailAttachmentIcon returns a resource containing the standard mail attachment icon for the current theme func MailAttachmentIcon() fyne.Resource { - return current().Icon(IconNameMailAttachment) + return safeIconLookup(IconNameMailAttachment) } // MailComposeIcon returns a resource containing the standard mail compose icon for the current theme func MailComposeIcon() fyne.Resource { - return current().Icon(IconNameMailCompose) + return safeIconLookup(IconNameMailCompose) } // MailForwardIcon returns a resource containing the standard mail forward icon for the current theme func MailForwardIcon() fyne.Resource { - return current().Icon(IconNameMailForward) + return safeIconLookup(IconNameMailForward) } // MailReplyIcon returns a resource containing the standard mail reply icon for the current theme func MailReplyIcon() fyne.Resource { - return current().Icon(IconNameMailReply) + return safeIconLookup(IconNameMailReply) } // MailReplyAllIcon returns a resource containing the standard mail reply all icon for the current theme func MailReplyAllIcon() fyne.Resource { - return current().Icon(IconNameMailReplyAll) + return safeIconLookup(IconNameMailReplyAll) } // MailSendIcon returns a resource containing the standard mail send icon for the current theme func MailSendIcon() fyne.Resource { - return current().Icon(IconNameMailSend) + return safeIconLookup(IconNameMailSend) } // MediaFastForwardIcon returns a resource containing the standard media fast-forward icon for the current theme func MediaFastForwardIcon() fyne.Resource { - return current().Icon(IconNameMediaFastForward) + return safeIconLookup(IconNameMediaFastForward) } // MediaFastRewindIcon returns a resource containing the standard media fast-rewind icon for the current theme func MediaFastRewindIcon() fyne.Resource { - return current().Icon(IconNameMediaFastRewind) + return safeIconLookup(IconNameMediaFastRewind) } // MediaPauseIcon returns a resource containing the standard media pause icon for the current theme func MediaPauseIcon() fyne.Resource { - return current().Icon(IconNameMediaPause) + return safeIconLookup(IconNameMediaPause) } // MediaPlayIcon returns a resource containing the standard media play icon for the current theme func MediaPlayIcon() fyne.Resource { - return current().Icon(IconNameMediaPlay) + return safeIconLookup(IconNameMediaPlay) } // MediaRecordIcon returns a resource containing the standard media record icon for the current theme func MediaRecordIcon() fyne.Resource { - return current().Icon(IconNameMediaRecord) + return safeIconLookup(IconNameMediaRecord) } // MediaReplayIcon returns a resource containing the standard media replay icon for the current theme func MediaReplayIcon() fyne.Resource { - return current().Icon(IconNameMediaReplay) + return safeIconLookup(IconNameMediaReplay) } // MediaSkipNextIcon returns a resource containing the standard media skip next icon for the current theme func MediaSkipNextIcon() fyne.Resource { - return current().Icon(IconNameMediaSkipNext) + return safeIconLookup(IconNameMediaSkipNext) } // MediaSkipPreviousIcon returns a resource containing the standard media skip previous icon for the current theme func MediaSkipPreviousIcon() fyne.Resource { - return current().Icon(IconNameMediaSkipPrevious) + return safeIconLookup(IconNameMediaSkipPrevious) } // MediaStopIcon returns a resource containing the standard media stop icon for the current theme func MediaStopIcon() fyne.Resource { - return current().Icon(IconNameMediaStop) + return safeIconLookup(IconNameMediaStop) } // MoveDownIcon returns a resource containing the standard down arrow icon for the current theme func MoveDownIcon() fyne.Resource { - return current().Icon(IconNameMoveDown) + return safeIconLookup(IconNameMoveDown) } // MoveUpIcon returns a resource containing the standard up arrow icon for the current theme func MoveUpIcon() fyne.Resource { - return current().Icon(IconNameMoveUp) + return safeIconLookup(IconNameMoveUp) } // NavigateBackIcon returns a resource containing the standard backward navigation icon for the current theme func NavigateBackIcon() fyne.Resource { - return current().Icon(IconNameNavigateBack) + return safeIconLookup(IconNameNavigateBack) } // NavigateNextIcon returns a resource containing the standard forward navigation icon for the current theme func NavigateNextIcon() fyne.Resource { - return current().Icon(IconNameNavigateNext) + return safeIconLookup(IconNameNavigateNext) } // MenuDropDownIcon returns a resource containing the standard menu drop down icon for the current theme func MenuDropDownIcon() fyne.Resource { - return current().Icon(IconNameArrowDropDown) + return safeIconLookup(IconNameArrowDropDown) } // MenuDropUpIcon returns a resource containing the standard menu drop up icon for the current theme func MenuDropUpIcon() fyne.Resource { - return current().Icon(IconNameArrowDropUp) + return safeIconLookup(IconNameArrowDropUp) } // ViewFullScreenIcon returns a resource containing the standard fullscreen icon for the current theme func ViewFullScreenIcon() fyne.Resource { - return current().Icon(IconNameViewFullScreen) + return safeIconLookup(IconNameViewFullScreen) } // ViewRestoreIcon returns a resource containing the standard exit fullscreen icon for the current theme func ViewRestoreIcon() fyne.Resource { - return current().Icon(IconNameViewRestore) + return safeIconLookup(IconNameViewRestore) } // ViewRefreshIcon returns a resource containing the standard refresh icon for the current theme func ViewRefreshIcon() fyne.Resource { - return current().Icon(IconNameViewRefresh) + return safeIconLookup(IconNameViewRefresh) } // ZoomFitIcon returns a resource containing the standard zoom fit icon for the current theme func ZoomFitIcon() fyne.Resource { - return current().Icon(IconNameViewZoomFit) + return safeIconLookup(IconNameViewZoomFit) } // ZoomInIcon returns a resource containing the standard zoom in icon for the current theme func ZoomInIcon() fyne.Resource { - return current().Icon(IconNameViewZoomIn) + return safeIconLookup(IconNameViewZoomIn) } // ZoomOutIcon returns a resource containing the standard zoom out icon for the current theme func ZoomOutIcon() fyne.Resource { - return current().Icon(IconNameViewZoomOut) + return safeIconLookup(IconNameViewZoomOut) } // VisibilityIcon returns a resource containing the standard visibity icon for the current theme func VisibilityIcon() fyne.Resource { - return current().Icon(IconNameVisibility) + return safeIconLookup(IconNameVisibility) } // VisibilityOffIcon returns a resource containing the standard visibity off icon for the current theme func VisibilityOffIcon() fyne.Resource { - return current().Icon(IconNameVisibilityOff) + return safeIconLookup(IconNameVisibilityOff) } // VolumeDownIcon returns a resource containing the standard volume down icon for the current theme func VolumeDownIcon() fyne.Resource { - return current().Icon(IconNameVolumeDown) + return safeIconLookup(IconNameVolumeDown) } // VolumeMuteIcon returns a resource containing the standard volume mute icon for the current theme func VolumeMuteIcon() fyne.Resource { - return current().Icon(IconNameVolumeMute) + return safeIconLookup(IconNameVolumeMute) } // VolumeUpIcon returns a resource containing the standard volume up icon for the current theme func VolumeUpIcon() fyne.Resource { - return current().Icon(IconNameVolumeUp) + return safeIconLookup(IconNameVolumeUp) } // ComputerIcon returns a resource containing the standard computer icon for the current theme func ComputerIcon() fyne.Resource { - return current().Icon(IconNameComputer) + return safeIconLookup(IconNameComputer) } // DownloadIcon returns a resource containing the standard download icon for the current theme func DownloadIcon() fyne.Resource { - return current().Icon(IconNameDownload) + return safeIconLookup(IconNameDownload) } // StorageIcon returns a resource containing the standard storage icon for the current theme func StorageIcon() fyne.Resource { - return current().Icon(IconNameStorage) + return safeIconLookup(IconNameStorage) } // UploadIcon returns a resource containing the standard upload icon for the current theme func UploadIcon() fyne.Resource { - return current().Icon(IconNameUpload) + return safeIconLookup(IconNameUpload) +} + +func safeIconLookup(n fyne.ThemeIconName) fyne.Resource { + icon := current().Icon(n) + if icon == nil { + fyne.LogError("Loaded theme returned nil icon", nil) + return fallbackIcon + } + return icon } diff --git a/theme/icons_test.go b/theme/icons_test.go index 77dea39107..f5a526a464 100644 --- a/theme/icons_test.go +++ b/theme/icons_test.go @@ -8,8 +8,8 @@ import ( "path/filepath" "testing" - "fyne.io/fyne" - "fyne.io/fyne/internal/test" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/test" "github.com/srwiley/oksvg" "github.com/srwiley/rasterx" diff --git a/theme/legacy.go b/theme/legacy.go index 16f0c22bd3..72aaaa17ee 100644 --- a/theme/legacy.go +++ b/theme/legacy.go @@ -3,13 +3,13 @@ package theme import ( "image/color" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // FromLegacy returns a 2.0 Theme created from the given LegacyTheme data. // This is a transition path and will be removed in the future (probably version 3.0). // -// Since: 2.0.0 +// Since: 2.0 func FromLegacy(t fyne.LegacyTheme) fyne.Theme { return &legacyWrapper{old: t} } diff --git a/theme/legacy_test.go b/theme/legacy_test.go index e752a71d7b..03edceb69d 100644 --- a/theme/legacy_test.go +++ b/theme/legacy_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) var oldTheme = &legacyTheme{} diff --git a/theme/theme.go b/theme/theme.go index 4ccb8951b6..69570e3dbd 100644 --- a/theme/theme.go +++ b/theme/theme.go @@ -1,166 +1,166 @@ // Package theme defines how a Fyne app should look when rendered -package theme // import "fyne.io/fyne/theme" +package theme // import "fyne.io/fyne/v2/theme" import ( "image/color" "os" "strings" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) const ( // ColorRed is the red primary color name // - // Since: 1.4.0 + // Since: 1.4 ColorRed = "red" // ColorOrange is the orange primary color name // - // Since: 1.4.0 + // Since: 1.4 ColorOrange = "orange" // ColorYellow is the yellow primary color name // - // Since: 1.4.0 + // Since: 1.4 ColorYellow = "yellow" // ColorGreen is the green primary color name // - // Since: 1.4.0 + // Since: 1.4 ColorGreen = "green" // ColorBlue is the blue primary color name // - // Since: 1.4.0 + // Since: 1.4 ColorBlue = "blue" // ColorPurple is the purple primary color name // - // Since: 1.4.0 + // Since: 1.4 ColorPurple = "purple" // ColorBrown is the brown primary color name // - // Since: 1.4.0 + // Since: 1.4 ColorBrown = "brown" // ColorGray is the gray primary color name // - // Since: 1.4.0 + // Since: 1.4 ColorGray = "gray" // ColorNameBackground is the name of theme lookup for background color. // - // Since 2.0.0 + // Since: 2.0 ColorNameBackground fyne.ThemeColorName = "background" // ColorNameButton is the name of theme lookup for button color. // - // Since 2.0.0 + // Since: 2.0 ColorNameButton fyne.ThemeColorName = "button" // ColorNameDisabledButton is the name of theme lookup for disabled button color. // - // Since 2.0.0 + // Since: 2.0 ColorNameDisabledButton fyne.ThemeColorName = "disabledButton" // ColorNameDisabled is the name of theme lookup for disabled foreground color. // - // Since 2.0.0 + // Since: 2.0 ColorNameDisabled fyne.ThemeColorName = "disabled" // ColorNameError is the name of theme lookup for foreground error color. // - // Since 2.0.0 + // Since: 2.0 ColorNameError fyne.ThemeColorName = "error" // ColorNameFocus is the name of theme lookup for focus color. // - // Since 2.0.0 + // Since: 2.0 ColorNameFocus fyne.ThemeColorName = "focus" // ColorNameForeground is the name of theme lookup for foreground color. // - // Since 2.0.0 + // Since: 2.0 ColorNameForeground fyne.ThemeColorName = "foreground" // ColorNameHover is the name of theme lookup for hover color. // - // Since 2.0.0 + // Since: 2.0 ColorNameHover fyne.ThemeColorName = "hover" // ColorNameInputBackground is the name of theme lookup for background color of an input field. // - // Since 2.0.0 + // Since: 2.0 ColorNameInputBackground fyne.ThemeColorName = "inputBackground" // ColorNamePlaceHolder is the name of theme lookup for placeholder text color. // - // Since 2.0.0 + // Since: 2.0 ColorNamePlaceHolder fyne.ThemeColorName = "placeholder" // ColorNamePressed is the name of theme lookup for the tap overlay color. // - // Since 2.0.0 + // Since: 2.0 ColorNamePressed fyne.ThemeColorName = "pressed" // ColorNamePrimary is the name of theme lookup for primary color. // - // Since 2.0.0 + // Since: 2.0 ColorNamePrimary fyne.ThemeColorName = "primary" // ColorNameScrollBar is the name of theme lookup for scrollbar color. // - // Since 2.0.0 + // Since: 2.0 ColorNameScrollBar fyne.ThemeColorName = "scrollBar" // ColorNameShadow is the name of theme lookup for shadow color. // - // Since 2.0.0 + // Since: 2.0 ColorNameShadow fyne.ThemeColorName = "shadow" // SizeNameCaptionText is the name of theme lookup for helper text size, normally smaller than regular text size. // - // Since 2.0.0 + // Since: 2.0 SizeNameCaptionText fyne.ThemeSizeName = "helperText" // SizeNameInlineIcon is the name of theme lookup for inline icons size. // - // Since 2.0.0 + // Since: 2.0 SizeNameInlineIcon fyne.ThemeSizeName = "iconInline" // SizeNamePadding is the name of theme lookup for padding size. // - // Since 2.0.0 + // Since: 2.0 SizeNamePadding fyne.ThemeSizeName = "padding" // SizeNameScrollBar is the name of theme lookup for the scrollbar size. // - // Since 2.0.0 + // Since: 2.0 SizeNameScrollBar fyne.ThemeSizeName = "scrollBar" // SizeNameScrollBarSmall is the name of theme lookup for the shrunk scrollbar size. // - // Since 2.0.0 + // Since: 2.0 SizeNameScrollBarSmall fyne.ThemeSizeName = "scrollBarSmall" // SizeNameSeparatorThickness is the name of theme lookup for the thickness of a separator. // - // Since 2.0.0 + // Since: 2.0 SizeNameSeparatorThickness fyne.ThemeSizeName = "separator" // SizeNameText is the name of theme lookup for text size. // - // Since 2.0.0 + // Since: 2.0 SizeNameText fyne.ThemeSizeName = "text" // SizeNameInputBorder is the name of theme lookup for input border size. // - // Since 2.0.0 + // Since: 2.0 SizeNameInputBorder fyne.ThemeSizeName = "inputBorder" // VariantDark is the version of a theme that satisfies a user preference for a light look. // - // Since 2.0.0 + // Since: 2.0 VariantDark fyne.ThemeVariant = 0 // VariantLight is the version of a theme that satisfies a user preference for a dark look. // - // Since 2.0.0 + // Since: 2.0 VariantLight fyne.ThemeVariant = 1 // potential for adding theme types such as high visibility or monochrome... @@ -233,7 +233,7 @@ type builtinTheme struct { // DefaultTheme returns a built-in theme that can adapt to the user preference of light or dark colors. // -// Since 2.0.0 +// Since: 2.0 func DefaultTheme() fyne.Theme { return defaultTheme } @@ -342,12 +342,12 @@ func current() fyne.Theme { // BackgroundColor returns the theme's background color func BackgroundColor() color.Color { - return current().Color(ColorNameBackground, currentVariant()) + return safeColorLookup(ColorNameBackground, currentVariant()) } // ButtonColor returns the theme's standard button color. func ButtonColor() color.Color { - return current().Color(ColorNameButton, currentVariant()) + return safeColorLookup(ColorNameButton, currentVariant()) } // CaptionTextSize returns the size for caption text. @@ -357,69 +357,69 @@ func CaptionTextSize() float32 { // DisabledButtonColor returns the theme's disabled button color. func DisabledButtonColor() color.Color { - return current().Color(ColorNameDisabledButton, currentVariant()) + return safeColorLookup(ColorNameDisabledButton, currentVariant()) } // TextColor returns the theme's standard text color - this is actually the foreground color since 1.4. // // Deprecated: Use theme.ForegroundColor() colour instead func TextColor() color.Color { - return current().Color(ColorNameForeground, currentVariant()) + return safeColorLookup(ColorNameForeground, currentVariant()) } // DisabledColor returns the foreground color for a disabled UI element // -// Since: 2.0.0 +// Since: 2.0 func DisabledColor() color.Color { - return current().Color(ColorNameDisabled, currentVariant()) + return safeColorLookup(ColorNameDisabled, currentVariant()) } // DisabledTextColor returns the theme's disabled text color - this is actually the disabled color since 1.4. // // Deprecated: Use theme.DisabledColor() colour instead func DisabledTextColor() color.Color { - return current().Color(ColorNameDisabled, currentVariant()) + return DisabledColor() } // ErrorColor returns the theme's error text color // -// Since 2.0.0 +// Since: 2.0 func ErrorColor() color.Color { - return current().Color(ColorNameError, currentVariant()) + return safeColorLookup(ColorNameError, currentVariant()) } // PlaceHolderColor returns the theme's standard text color func PlaceHolderColor() color.Color { - return current().Color(ColorNamePlaceHolder, currentVariant()) + return safeColorLookup(ColorNamePlaceHolder, currentVariant()) } // PressedColor returns the color used to overlap tapped features // -// Since: 2.0.0 +// Since: 2.0 func PressedColor() color.Color { - return current().Color(ColorNamePressed, currentVariant()) + return safeColorLookup(ColorNamePressed, currentVariant()) } // PrimaryColor returns the color used to highlight primary features func PrimaryColor() color.Color { - return current().Color(ColorNamePrimary, currentVariant()) + return safeColorLookup(ColorNamePrimary, currentVariant()) } // HoverColor returns the color used to highlight interactive elements currently under a cursor func HoverColor() color.Color { - return current().Color(ColorNameHover, currentVariant()) + return safeColorLookup(ColorNameHover, currentVariant()) } // FocusColor returns the color used to highlight a focused widget func FocusColor() color.Color { - return current().Color(ColorNameFocus, currentVariant()) + return safeColorLookup(ColorNameFocus, currentVariant()) } // ForegroundColor returns the theme's standard foreground color for text and icons // -// Since: 2.0.0 +// Since: 2.0 func ForegroundColor() color.Color { - return current().Color(ColorNameForeground, currentVariant()) + return safeColorLookup(ColorNameForeground, currentVariant()) } // InputBackgroundColor returns the color used to draw underneath input elements. @@ -429,17 +429,17 @@ func InputBackgroundColor() color.Color { // ScrollBarColor returns the color (and translucency) for a scrollBar func ScrollBarColor() color.Color { - return current().Color(ColorNameScrollBar, currentVariant()) + return safeColorLookup(ColorNameScrollBar, currentVariant()) } // ShadowColor returns the color (and translucency) for shadows used for indicating elevation func ShadowColor() color.Color { - return current().Color(ColorNameShadow, currentVariant()) + return safeColorLookup(ColorNameShadow, currentVariant()) } // InputBorderSize returns the input border size (or underline size for an entry). // -// Since 2.0.0 +// Since: 2.0 func InputBorderSize() float32 { return current().Size(SizeNameInputBorder) } @@ -451,27 +451,27 @@ func TextSize() float32 { // TextFont returns the font resource for the regular font style func TextFont() fyne.Resource { - return current().Font(fyne.TextStyle{}) + return safeFontLookup(fyne.TextStyle{}) } // TextBoldFont returns the font resource for the bold font style func TextBoldFont() fyne.Resource { - return current().Font(fyne.TextStyle{Bold: true}) + return safeFontLookup(fyne.TextStyle{Bold: true}) } // TextItalicFont returns the font resource for the italic font style func TextItalicFont() fyne.Resource { - return current().Font(fyne.TextStyle{Italic: true}) + return safeFontLookup(fyne.TextStyle{Italic: true}) } // TextBoldItalicFont returns the font resource for the bold and italic font style func TextBoldItalicFont() fyne.Resource { - return current().Font(fyne.TextStyle{Bold: true, Italic: true}) + return safeFontLookup(fyne.TextStyle{Bold: true, Italic: true}) } // TextMonospaceFont returns the font resource for the monospace font face func TextMonospaceFont() fyne.Resource { - return current().Font(fyne.TextStyle{Monospace: true}) + return safeFontLookup(fyne.TextStyle{Monospace: true}) } // Padding is the standard gap between elements and the border around interface @@ -487,7 +487,7 @@ func IconInlineSize() float32 { // SeparatorThicknessSize is the standard thickness of the separator widget. // -// Since 2.0.0 +// Since: 2.0 func SeparatorThicknessSize() float32 { return current().Size(SizeNameSeparatorThickness) } @@ -529,14 +529,14 @@ func DefaultTextMonospaceFont() fyne.Resource { // PrimaryColorNames returns a list of the standard primary color options. // -// Since: 1.4.0 +// Since: 1.4 func PrimaryColorNames() []string { return []string{ColorRed, ColorOrange, ColorYellow, ColorGreen, ColorBlue, ColorPurple, ColorBrown, ColorGray} } // PrimaryColorNamed returns a theme specific color value for a named primary color. // -// Since 1.4.0 +// Since: 1.4 func PrimaryColorNamed(name string) color.Color { col, ok := primaryColors[name] if !ok { @@ -575,6 +575,38 @@ func loadCustomFont(env, variant string, fallback fyne.Resource) fyne.Resource { return res } +func safeColorLookup(n fyne.ThemeColorName, v fyne.ThemeVariant) color.Color { + col := current().Color(n, v) + if col == nil { + fyne.LogError("Loaded theme returned nil color", nil) + return fallbackColor + } + return col +} + +func safeFontLookup(s fyne.TextStyle) fyne.Resource { + font := current().Font(s) + if font != nil { + return font + } + fyne.LogError("Loaded theme returned nil font", nil) + + if s.Monospace { + return DefaultTextMonospaceFont() + } + if s.Bold { + if s.Italic { + return DefaultTextBoldItalicFont() + } + return DefaultTextBoldFont() + } + if s.Italic { + return DefaultTextItalicFont() + } + + return DefaultTextFont() +} + func setupDefaultTheme() fyne.Theme { theme := &builtinTheme{} diff --git a/theme/theme_hints.go b/theme/theme_hints.go new file mode 100644 index 0000000000..94f69d860e --- /dev/null +++ b/theme/theme_hints.go @@ -0,0 +1,8 @@ +// +build hints + +package theme + +var ( + fallbackColor = errorColor + fallbackIcon = NewErrorThemedResource(errorIconRes) +) diff --git a/theme/theme_other.go b/theme/theme_other.go new file mode 100644 index 0000000000..160b807e34 --- /dev/null +++ b/theme/theme_other.go @@ -0,0 +1,14 @@ +// +build !hints + +package theme + +import ( + "image/color" + + "fyne.io/fyne/v2" +) + +var ( + fallbackColor = color.Transparent + fallbackIcon = &fyne.StaticResource{} +) diff --git a/theme/theme_test.go b/theme/theme_test.go index 2b1b94065c..39172f338a 100644 --- a/theme/theme_test.go +++ b/theme/theme_test.go @@ -1,18 +1,14 @@ package theme import ( + "image/color" "testing" - "fyne.io/fyne" + "fyne.io/fyne/v2" + "github.com/stretchr/testify/assert" ) -// TODO figure how to test the default theme if we are messing with it... -//func TestThemeDefault(t *testing.T) { -// loaded := fyne.GlobalSettings().Theme() -// assert.NotEqual(t, lightBackground, loaded.BackgroundColor()) -//} - func TestThemeChange(t *testing.T) { fyne.CurrentApp().Settings().SetTheme(DarkTheme()) bg := BackgroundColor() @@ -187,3 +183,30 @@ func Test_DefaultTextMonospaceFont(t *testing.T) { result := DefaultTextMonospaceFont().Name() assert.Equal(t, expect, result, "wrong default monospace font") } + +func TestEmptyTheme(t *testing.T) { + fyne.CurrentApp().Settings().SetTheme(&emptyTheme{}) + assert.NotNil(t, ForegroundColor()) + assert.NotNil(t, TextFont()) + assert.NotNil(t, HelpIcon()) + fyne.CurrentApp().Settings().SetTheme(DarkTheme()) +} + +type emptyTheme struct { +} + +func (e *emptyTheme) Color(n fyne.ThemeColorName, v fyne.ThemeVariant) color.Color { + return nil +} + +func (e *emptyTheme) Font(s fyne.TextStyle) fyne.Resource { + return nil +} + +func (e *emptyTheme) Icon(n fyne.ThemeIconName) fyne.Resource { + return nil +} + +func (e *emptyTheme) Size(n fyne.ThemeSizeName) float32 { + return 0 +} diff --git a/theme/themedtestapp.go b/theme/themedtestapp.go index f8b8147fe6..4a972c5cf3 100644 --- a/theme/themedtestapp.go +++ b/theme/themedtestapp.go @@ -5,7 +5,7 @@ package theme import ( "net/url" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) type themedApp struct { diff --git a/tools/playground/playground.go b/tools/playground/playground.go index 1877507588..2eabe8038e 100644 --- a/tools/playground/playground.go +++ b/tools/playground/playground.go @@ -8,9 +8,9 @@ import ( "image" "image/png" - "fyne.io/fyne" - "fyne.io/fyne/driver/software" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver/software" + "fyne.io/fyne/v2/theme" ) func imageToPlayground(img image.Image) { diff --git a/tools/playground/softwarecanvas.go b/tools/playground/softwarecanvas.go index c7a16f5d1a..a4659983ac 100644 --- a/tools/playground/softwarecanvas.go +++ b/tools/playground/softwarecanvas.go @@ -1,8 +1,8 @@ package playground import ( - "fyne.io/fyne/driver/software" - "fyne.io/fyne/test" + "fyne.io/fyne/v2/driver/software" + "fyne.io/fyne/v2/test" ) // NewSoftwareCanvas creates a new canvas in memory that can render without hardware support diff --git a/uri.go b/uri.go index 5343aec0f3..36e5373116 100644 --- a/uri.go +++ b/uri.go @@ -9,8 +9,7 @@ import ( // It may refer to an item on a filesystem or data in another application that we have access to. type URIReadCloser interface { io.ReadCloser - // Deprecated, use URI().Name() instead - Name() string + URI() URI } @@ -18,19 +17,68 @@ type URIReadCloser interface { // This will normally refer to a local file resource. type URIWriteCloser interface { io.WriteCloser - // Deprecated, use URI().Name() instead - Name() string + URI() URI } -// URI represents the identifier of a resource on a target system. -// This resource may be a file or another data source such as an app or file sharing system. +// URI represents the identifier of a resource on a target system. This +// resource may be a file or another data source such as an app or file sharing +// system. +// +// In general, it is expected that URI implementations follow IETF RFC3896. +// Implementations are highly recommended to utilize net/url to implement URI +// parsing methods, especially Scheme(), AUthority(), Path(), Query(), and +// Fragment(). type URI interface { fmt.Stringer + + // Extension should return the file extension of the resource + // referenced by the URI. For example, the Extension() of + // 'file://foo/bar.baz' is 'baz'. May return an empty string if the + // referenced resource has none. Extension() string + + // Name should return the base name of the item referenced by the URI. + // For example, the Name() of 'file://foo/bar.baz' is 'bar.baz'. Name() string + + // MimeType should return the content type of the resource referenced + // by the URI. The returned string should be in the format described + // by Section 5 of RFC2045 ("Content-Type Header Field"). MimeType() string + + // Scheme should return the URI scheme of the URI as defined by IETF + // RFC3986. For example, the Scheme() of 'file://foo/bar.baz` is + // 'file'. + // + // Scheme should always return the scheme in all lower-case characters. Scheme() string + + // Authority should return the URI authority, as defined by IETF + // RFC3986. + // + // NOTE: the RFC3986 can be obtained by combining the User and Host + // Fields of net/url's URL structure. Consult IETF RFC3986, section + // 3.2, pp. 17. + // + // Since: 2.0 + Authority() string + + // Path should return the URI path, as defined by IETF RFC3986. + // + // Since: 2.0 + Path() string + + // Query should return the URI query, as defined by IETF RFC3986. + // + // Since: 2.0 + Query() string + + // Fragment should return the URI fragment, as defined by IETF + // RFC3986. + // + // Since: 2.0 + Fragment() string } // ListableURI represents a URI that can have child items, most commonly a diff --git a/widget/accordion.go b/widget/accordion.go index 39cca03c96..33ad01b086 100644 --- a/widget/accordion.go +++ b/widget/accordion.go @@ -1,10 +1,10 @@ package widget import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) const accordionDividerHeight = 1 diff --git a/widget/accordion_internal_test.go b/widget/accordion_internal_test.go index 15be3e391c..379423eed6 100644 --- a/widget/accordion_internal_test.go +++ b/widget/accordion_internal_test.go @@ -3,9 +3,9 @@ package widget import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/widget/accordion_test.go b/widget/accordion_test.go index 5834ea4be7..59900c8727 100644 --- a/widget/accordion_test.go +++ b/widget/accordion_test.go @@ -4,11 +4,11 @@ import ( "testing" "time" - "fyne.io/fyne" - "fyne.io/fyne/layout" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/widget/button.go b/widget/button.go index 8700a9674e..5c2ecbcc37 100644 --- a/widget/button.go +++ b/widget/button.go @@ -3,12 +3,12 @@ package widget import ( "image/color" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" ) // ButtonAlign represents the horizontal alignment of a button. diff --git a/widget/button_internal_test.go b/widget/button_internal_test.go index 0f6313b3d5..e37caf4e2a 100644 --- a/widget/button_internal_test.go +++ b/widget/button_internal_test.go @@ -4,10 +4,10 @@ import ( "fmt" "testing" - "fyne.io/fyne" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/widget/button_test.go b/widget/button_test.go index 4e38c771df..d2818ffbf6 100644 --- a/widget/button_test.go +++ b/widget/button_test.go @@ -4,11 +4,11 @@ import ( "testing" "time" - "fyne.io/fyne" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/widget/card.go b/widget/card.go index afedefe637..595542524c 100644 --- a/widget/card.go +++ b/widget/card.go @@ -1,10 +1,10 @@ package widget import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) // Card widget groups title, subtitle with content and a header image diff --git a/widget/card_test.go b/widget/card_test.go index 1691e3019f..1292efd2e7 100644 --- a/widget/card_test.go +++ b/widget/card_test.go @@ -4,11 +4,11 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/widget/check.go b/widget/check.go index 4e1fda87e8..2eeeeb9924 100644 --- a/widget/check.go +++ b/widget/check.go @@ -3,13 +3,13 @@ package widget import ( "fmt" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/data/binding" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/data/binding" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) type checkRenderer struct { @@ -111,7 +111,7 @@ type Check struct { // The current value will be displayed and any changes in the data will cause the widget to update. // User interactions with this Check will set the value into the data source. // -// Since: 2.0.0 +// Since: 2.0 func (c *Check) Bind(data binding.Bool) { c.Unbind() c.checkSource = data @@ -236,7 +236,7 @@ func NewCheck(label string, changed func(bool)) *Check { // NewCheckWithData returns a check widget connected with the specified data source. // -// Since: 2.0.0 +// Since: 2.0 func NewCheckWithData(label string, data binding.Bool) *Check { check := NewCheck(label, nil) check.Bind(data) @@ -277,7 +277,7 @@ func (c *Check) TypedKey(key *fyne.KeyEvent) {} // Unbind disconnects any configured data source from this Check. // The current value will remain at the last value of the data source. // -// Since: 2.0.0 +// Since: 2.0 func (c *Check) Unbind() { c.OnChanged = nil if c.checkSource == nil || c.checkListener == nil { diff --git a/widget/check_internal_test.go b/widget/check_internal_test.go index f548d083e3..32a154205d 100644 --- a/widget/check_internal_test.go +++ b/widget/check_internal_test.go @@ -4,9 +4,9 @@ import ( "fmt" "testing" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/widget/check_test.go b/widget/check_test.go index 2d84b8ac31..3078688f6e 100644 --- a/widget/check_test.go +++ b/widget/check_test.go @@ -5,11 +5,11 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" - "fyne.io/fyne/data/binding" - "fyne.io/fyne/layout" - "fyne.io/fyne/test" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/data/binding" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/widget" ) func TestCheck_Binding(t *testing.T) { diff --git a/widget/entry.go b/widget/entry.go index de5b5386d3..41a51ba4a8 100644 --- a/widget/entry.go +++ b/widget/entry.go @@ -7,14 +7,14 @@ import ( "time" "unicode" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/data/binding" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/driver/mobile" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/data/binding" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/driver/mobile" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) const ( @@ -37,11 +37,11 @@ type Entry struct { DisableableWidget shortcut fyne.ShortcutHandler Text string - // Since: 2.0.0 + // Since: 2.0 TextStyle fyne.TextStyle PlaceHolder string OnChanged func(string) `json:"-"` - // Since: 2.0.0 + // Since: 2.0 OnSubmitted func(string) `json:"-"` Password bool MultiLine bool @@ -91,7 +91,7 @@ func NewEntry() *Entry { // NewEntryWithData returns an Entry widget connected to the specified data source. // -// Since: 2.0.0 +// Since: 2.0 func NewEntryWithData(data binding.String) *Entry { entry := NewEntry() entry.Bind(data) @@ -118,7 +118,7 @@ func NewPasswordEntry() *Entry { // The current value will be displayed and any changes in the data will cause the widget to update. // User interactions with this Entry will set the value into the data source. // -// Since: 2.0.0 +// Since: 2.0 func (e *Entry) Bind(data binding.String) { e.Unbind() e.textSource = data @@ -691,7 +691,7 @@ func (e *Entry) TypedShortcut(shortcut fyne.Shortcut) { // Unbind disconnects any configured data source from this Entry. // The current value will remain at the last value of the data source. // -// Since: 2.0.0 +// Since: 2.0 func (e *Entry) Unbind() { e.OnChanged = nil if e.textSource == nil || e.textListener == nil { @@ -1215,7 +1215,7 @@ type entryContent struct { func (e *entryContent) CreateRenderer() fyne.WidgetRenderer { e.ExtendBaseWidget(e) - cursor := canvas.NewRectangle(theme.PrimaryColor()) + cursor := canvas.NewRectangle(color.Transparent) cursor.Hide() e.entry.propertyLock.Lock() @@ -1314,7 +1314,6 @@ func (r *entryContentRenderer) Refresh() { placeholder.Hide() } - r.cursor.FillColor = theme.PrimaryColor() if focused { r.cursor.Show() if r.cursorAnim == nil { diff --git a/widget/entry_internal_test.go b/widget/entry_internal_test.go index e35b801bde..8bce6d8afa 100644 --- a/widget/entry_internal_test.go +++ b/widget/entry_internal_test.go @@ -5,11 +5,11 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" ) func TestEntry_Cursor(t *testing.T) { diff --git a/widget/entry_password.go b/widget/entry_password.go index 5f9427daeb..6b73f8a08d 100644 --- a/widget/entry_password.go +++ b/widget/entry_password.go @@ -3,11 +3,11 @@ package widget import ( "image/color" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) var _ desktop.Cursorable = (*passwordRevealer)(nil) diff --git a/widget/entry_test.go b/widget/entry_test.go index 6ac502e79d..1981a9a1f7 100644 --- a/widget/entry_test.go +++ b/widget/entry_test.go @@ -5,13 +5,13 @@ import ( "testing" "time" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/data/binding" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/data/binding" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/widget/entry_validation.go b/widget/entry_validation.go index 61d1b3e38a..5a380f6f84 100644 --- a/widget/entry_validation.go +++ b/widget/entry_validation.go @@ -1,10 +1,10 @@ package widget import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) var _ fyne.Validatable = (*Entry)(nil) diff --git a/widget/entry_validation_test.go b/widget/entry_validation_test.go index fa350d25af..d190bdf12e 100644 --- a/widget/entry_validation_test.go +++ b/widget/entry_validation_test.go @@ -4,11 +4,11 @@ import ( "errors" "testing" - "fyne.io/fyne" - "fyne.io/fyne/data/validation" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/data/validation" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/widget/fileicon.go b/widget/fileicon.go index fe0f1a175d..b2c10df17e 100644 --- a/widget/fileicon.go +++ b/widget/fileicon.go @@ -3,11 +3,11 @@ package widget import ( "strings" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/storage" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/theme" ) const ( @@ -116,12 +116,11 @@ func (i *FileIcon) isDir(uri fyne.URI) bool { return true } - if luri, err := storage.ListerForURI(uri); err == nil { - i.URI = luri // Optimization to avoid having to list it next time - return true + can, err := storage.CanList(uri) + if err != nil { + return false } - - return false + return can } type fileIconRenderer struct { diff --git a/widget/fileicon_internal_test.go b/widget/fileicon_internal_test.go index b19fc284e5..0c32088567 100644 --- a/widget/fileicon_internal_test.go +++ b/widget/fileicon_internal_test.go @@ -9,10 +9,10 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" - "fyne.io/fyne/storage" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" ) // Simulate being rendered by calling CreateRenderer() to update icon @@ -70,10 +70,7 @@ func TestFileIcon_NewURI_WithFolder(t *testing.T) { } dir := filepath.Join(workingDir, "testdata") - folder, err := storage.ListerForURI(storage.NewURI("file://" + dir)) - assert.Empty(t, err) - - item := newRenderedFileIcon(folder) + item := newRenderedFileIcon(storage.NewURI("file://" + dir)) assert.Empty(t, item.extension) assert.Equal(t, theme.FolderIcon(), item.resource) @@ -163,10 +160,7 @@ func TestFileIcon_SetURI_WithFolder(t *testing.T) { item := newRenderedFileIcon(nil) assert.Empty(t, item.extension) - folder, err := storage.ListerForURI(storage.NewURI("file://" + dir)) - assert.Empty(t, err) - - item.SetURI(folder) + item.SetURI(storage.NewURI("file://" + dir)) assert.Empty(t, item.extension) assert.Equal(t, theme.FolderIcon(), item.resource) diff --git a/widget/form.go b/widget/form.go index e7a24c1ce3..c75fd82141 100644 --- a/widget/form.go +++ b/widget/form.go @@ -1,11 +1,11 @@ package widget import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" ) // FormItem provides the details for a row in a form @@ -13,7 +13,7 @@ type FormItem struct { Text string Widget fyne.CanvasObject - // Since: 2.0.0 + // Since: 2.0 HintText string validationError error diff --git a/widget/form_extend_test.go b/widget/form_extend_test.go index f73fa5d07e..b5bef19930 100644 --- a/widget/form_extend_test.go +++ b/widget/form_extend_test.go @@ -3,7 +3,7 @@ package widget import ( "testing" - "fyne.io/fyne/test" + "fyne.io/fyne/v2/test" "github.com/stretchr/testify/assert" ) diff --git a/widget/form_test.go b/widget/form_test.go index a502449c98..ad7c9f006f 100644 --- a/widget/form_test.go +++ b/widget/form_test.go @@ -3,10 +3,10 @@ package widget import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/data/validation" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/data/validation" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/widget/hyperlink.go b/widget/hyperlink.go index dc33b5e2aa..d40f00f301 100644 --- a/widget/hyperlink.go +++ b/widget/hyperlink.go @@ -4,9 +4,9 @@ import ( "image/color" "net/url" - "fyne.io/fyne" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/theme" ) // Hyperlink widget is a text component with appropriate padding and layout. diff --git a/widget/hyperlink_test.go b/widget/hyperlink_test.go index 74f0f38fb3..89897963bc 100644 --- a/widget/hyperlink_test.go +++ b/widget/hyperlink_test.go @@ -4,10 +4,10 @@ import ( "net/url" "testing" - "fyne.io/fyne" - "fyne.io/fyne/driver/desktop" - _ "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver/desktop" + _ "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/widget/icon.go b/widget/icon.go index 69cce39739..b2c6dd7e72 100644 --- a/widget/icon.go +++ b/widget/icon.go @@ -1,10 +1,10 @@ package widget import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) type iconRenderer struct { diff --git a/widget/icon_extend_test.go b/widget/icon_extend_test.go index bfa1f7ae88..c21bb0fcca 100644 --- a/widget/icon_extend_test.go +++ b/widget/icon_extend_test.go @@ -3,9 +3,9 @@ package widget import ( "testing" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/widget/icon_internal_test.go b/widget/icon_internal_test.go index b2a3e9c58c..fd88d9ab12 100644 --- a/widget/icon_internal_test.go +++ b/widget/icon_internal_test.go @@ -3,9 +3,9 @@ package widget import ( "testing" - "fyne.io/fyne/canvas" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/widget/icon_test.go b/widget/icon_test.go index d933abe08f..f47d51da13 100644 --- a/widget/icon_test.go +++ b/widget/icon_test.go @@ -3,11 +3,11 @@ package widget_test import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/layout" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) func TestIcon_Layout(t *testing.T) { diff --git a/widget/label.go b/widget/label.go index d7a873427c..f96058d8e6 100644 --- a/widget/label.go +++ b/widget/label.go @@ -3,10 +3,10 @@ package widget import ( "image/color" - "fyne.io/fyne" - "fyne.io/fyne/data/binding" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/data/binding" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/theme" ) // Label widget is a label component with appropriate padding and layout. @@ -29,7 +29,7 @@ func NewLabel(text string) *Label { // NewLabelWithData returns an Label widget connected to the specified data source. // -// Since: 2.0.0 +// Since: 2.0 func NewLabelWithData(data binding.String) *Label { label := NewLabel("") label.Bind(data) @@ -51,7 +51,7 @@ func NewLabelWithStyle(text string, alignment fyne.TextAlign, style fyne.TextSty // Bind connects the specified data source to this Label. // The current value will be displayed and any changes in the data will cause the widget to update. // -// Since: 2.0.0 +// Since: 2.0 func (l *Label) Bind(data binding.String) { l.Unbind() l.textSource = data @@ -107,7 +107,7 @@ func (l *Label) SetText(text string) { // Unbind disconnects any configured data source from this Label. // The current value will remain at the last value of the data source. // -// Since: 2.0.0 +// Since: 2.0 func (l *Label) Unbind() { if l.textSource == nil || l.textListener == nil { return diff --git a/widget/label_extend_test.go b/widget/label_extend_test.go index 41d73c6791..dcd68337cb 100644 --- a/widget/label_extend_test.go +++ b/widget/label_extend_test.go @@ -5,8 +5,8 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/cache" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/cache" ) type extendedLabel struct { diff --git a/widget/label_test.go b/widget/label_test.go index 39dd457153..eb286e0223 100644 --- a/widget/label_test.go +++ b/widget/label_test.go @@ -3,11 +3,11 @@ package widget import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/data/binding" - "fyne.io/fyne/internal/painter/software" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/data/binding" + "fyne.io/fyne/v2/internal/painter/software" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/widget/list.go b/widget/list.go index 122ad9118a..cc0be32c47 100644 --- a/widget/list.go +++ b/widget/list.go @@ -4,12 +4,12 @@ import ( "fmt" "math" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/data/binding" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/data/binding" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) // ListItemID uniquely identifies an item within a list. @@ -51,7 +51,7 @@ func NewList(length func() int, createItem func() fyne.CanvasObject, updateItem // NewListWithData creates a new list widget that will display the contents of the provided data. // -// Since: 2.0.0 +// Since: 2.0 func NewListWithData(data binding.DataList, createItem func() fyne.CanvasObject, updateItem func(binding.DataItem, fyne.CanvasObject)) *List { l := NewList( data.Length, diff --git a/widget/list_test.go b/widget/list_test.go index e86afb9d13..d4f5536d4c 100644 --- a/widget/list_test.go +++ b/widget/list_test.go @@ -7,12 +7,12 @@ import ( "testing" "time" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/layout" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/widget/menu.go b/widget/menu.go index 375bed20dd..7a69b7eaf5 100644 --- a/widget/menu.go +++ b/widget/menu.go @@ -1,11 +1,11 @@ package widget import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" ) var _ fyne.Widget = (*Menu)(nil) diff --git a/widget/menu_desktop_test.go b/widget/menu_desktop_test.go index 195833770e..52d70ff8fa 100644 --- a/widget/menu_desktop_test.go +++ b/widget/menu_desktop_test.go @@ -6,11 +6,11 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - internalWidget "fyne.io/fyne/internal/widget" - "fyne.io/fyne/test" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + internalWidget "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/widget/menu_internal_desktop_test.go b/widget/menu_internal_desktop_test.go index 06673b442b..5cad0255e7 100644 --- a/widget/menu_internal_desktop_test.go +++ b/widget/menu_internal_desktop_test.go @@ -5,10 +5,10 @@ package widget import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/widget/menu_internal_mobile_test.go b/widget/menu_internal_mobile_test.go index f6642d4441..2186468754 100644 --- a/widget/menu_internal_mobile_test.go +++ b/widget/menu_internal_mobile_test.go @@ -5,8 +5,8 @@ package widget import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/test" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/test" "github.com/stretchr/testify/assert" ) diff --git a/widget/menu_internal_test.go b/widget/menu_internal_test.go index 4bf8a0a6a9..a854b8035d 100644 --- a/widget/menu_internal_test.go +++ b/widget/menu_internal_test.go @@ -5,8 +5,8 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" - "fyne.io/fyne/test" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/test" ) func TestMenu_ItemTapped(t *testing.T) { diff --git a/widget/menu_item.go b/widget/menu_item.go index abf918e77a..34b1b38caf 100644 --- a/widget/menu_item.go +++ b/widget/menu_item.go @@ -1,11 +1,11 @@ package widget import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) var _ fyne.Widget = (*menuItem)(nil) diff --git a/widget/menu_mobile_test.go b/widget/menu_mobile_test.go index 2b1751aa47..44127b7995 100644 --- a/widget/menu_mobile_test.go +++ b/widget/menu_mobile_test.go @@ -6,11 +6,11 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - internalWidget "fyne.io/fyne/internal/widget" - "fyne.io/fyne/test" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + internalWidget "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/widget" ) func TestMenu_Layout(t *testing.T) { diff --git a/widget/menu_test.go b/widget/menu_test.go index d1f487bea6..8fd342f91c 100644 --- a/widget/menu_test.go +++ b/widget/menu_test.go @@ -3,10 +3,10 @@ package widget_test import ( "testing" - "fyne.io/fyne" - internalWidget "fyne.io/fyne/internal/widget" - "fyne.io/fyne/test" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + internalWidget "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/widget/pool.go b/widget/pool.go index 1b55123ce7..19f1cb5db6 100644 --- a/widget/pool.go +++ b/widget/pool.go @@ -3,7 +3,7 @@ package widget import ( "sync" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) type pool interface { diff --git a/widget/pool_test.go b/widget/pool_test.go index 40439057d8..8c21470de2 100644 --- a/widget/pool_test.go +++ b/widget/pool_test.go @@ -5,8 +5,8 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne/canvas" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/theme" ) func TestSyncPool(t *testing.T) { diff --git a/widget/popup.go b/widget/popup.go index ca62726523..848f33e321 100644 --- a/widget/popup.go +++ b/widget/popup.go @@ -1,10 +1,10 @@ package widget import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) // PopUp is a widget that can float above the user interface. diff --git a/widget/popup_menu.go b/widget/popup_menu.go index 4e68428bd2..8334553090 100644 --- a/widget/popup_menu.go +++ b/widget/popup_menu.go @@ -1,8 +1,8 @@ package widget import ( - "fyne.io/fyne" - "fyne.io/fyne/internal/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/widget" ) // PopUpMenu is a Menu which displays itself in an OverlayContainer. @@ -14,7 +14,7 @@ type PopUpMenu struct { // NewPopUpMenu creates a new, reusable popup menu. You can show it using ShowAtPosition. // -// Since: 2.0.0 +// Since: 2.0 func NewPopUpMenu(menu *fyne.Menu, c fyne.Canvas) *PopUpMenu { p := &PopUpMenu{Menu: NewMenu(menu), canvas: c} p.Menu.Resize(p.Menu.MinSize()) diff --git a/widget/popup_menu_test.go b/widget/popup_menu_test.go index 2a48f27c77..468f0a1eff 100644 --- a/widget/popup_menu_test.go +++ b/widget/popup_menu_test.go @@ -6,9 +6,9 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/test" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/test" ) func TestPopUpMenu_Move(t *testing.T) { diff --git a/widget/popup_test.go b/widget/popup_test.go index 74b797cad8..f693beb572 100644 --- a/widget/popup_test.go +++ b/widget/popup_test.go @@ -4,12 +4,12 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/widget/progressbar.go b/widget/progressbar.go index 0e3e9b0e29..6de273d415 100644 --- a/widget/progressbar.go +++ b/widget/progressbar.go @@ -4,12 +4,12 @@ import ( "fmt" "image/color" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/data/binding" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/data/binding" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) const defaultText = "%d%%" @@ -97,7 +97,7 @@ type ProgressBar struct { // Bind connects the specified data source to this ProgressBar. // The current value will be displayed and any changes in the data will cause the widget to update. // -// Since: 2.0.0 +// Since: 2.0 func (p *ProgressBar) Bind(data binding.Float) { p.Unbind() p.valueSource = data @@ -146,7 +146,7 @@ func (p *ProgressBar) CreateRenderer() fyne.WidgetRenderer { // Unbind disconnects any configured data source from this ProgressBar. // The current value will remain at the last value of the data source. // -// Since: 2.0.0 +// Since: 2.0 func (p *ProgressBar) Unbind() { if p.valueSource == nil || p.valueListener == nil { return @@ -169,7 +169,7 @@ func NewProgressBar() *ProgressBar { // NewProgressBarWithData returns a progress bar connected with the specified data source. // -// Since: 2.0.0 +// Since: 2.0 func NewProgressBarWithData(data binding.Float) *ProgressBar { p := NewProgressBar() p.Bind(data) diff --git a/widget/progressbar_extend_test.go b/widget/progressbar_extend_test.go index 5b7a4cbd4b..d483ef01ac 100644 --- a/widget/progressbar_extend_test.go +++ b/widget/progressbar_extend_test.go @@ -3,8 +3,8 @@ package widget import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/test" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/test" "github.com/stretchr/testify/assert" ) diff --git a/widget/progressbar_test.go b/widget/progressbar_test.go index 407e4ba5cd..385e2750f6 100644 --- a/widget/progressbar_test.go +++ b/widget/progressbar_test.go @@ -4,9 +4,9 @@ import ( "fmt" "testing" - "fyne.io/fyne" - "fyne.io/fyne/data/binding" - "fyne.io/fyne/test" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/data/binding" + "fyne.io/fyne/v2/test" "github.com/stretchr/testify/assert" ) diff --git a/widget/progressbarinfinite.go b/widget/progressbarinfinite.go index bb8d08a7bf..189460375b 100644 --- a/widget/progressbarinfinite.go +++ b/widget/progressbarinfinite.go @@ -3,11 +3,11 @@ package widget import ( "time" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) const ( @@ -51,6 +51,7 @@ func (p *infProgressRenderer) updateBar(done float32) { p.bar.Resize(barSize) p.bar.Move(barPos) + canvas.Refresh(p.bar) } // Layout the components of the infinite progress bar diff --git a/widget/progressbarinfinite_test.go b/widget/progressbarinfinite_test.go index 22e1363e1f..853255ea30 100644 --- a/widget/progressbarinfinite_test.go +++ b/widget/progressbarinfinite_test.go @@ -4,9 +4,9 @@ import ( "testing" "time" - "fyne.io/fyne" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/test" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/test" "github.com/stretchr/testify/assert" ) diff --git a/widget/radio_group.go b/widget/radio_group.go index 6f5f46697f..94d4332723 100644 --- a/widget/radio_group.go +++ b/widget/radio_group.go @@ -1,9 +1,9 @@ package widget import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/widget" ) // RadioGroup widget has a list of text labels and radio check icons next to each. diff --git a/widget/radio_group_extended_test.go b/widget/radio_group_extended_test.go index 01b0b78dd6..e61a5abec7 100644 --- a/widget/radio_group_extended_test.go +++ b/widget/radio_group_extended_test.go @@ -3,11 +3,11 @@ package widget import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/widget/radio_group_internal_test.go b/widget/radio_group_internal_test.go index 3df549d7a7..46aa2cce6a 100644 --- a/widget/radio_group_internal_test.go +++ b/widget/radio_group_internal_test.go @@ -4,11 +4,11 @@ import ( "fmt" "testing" - "fyne.io/fyne" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/widget/radio_group_test.go b/widget/radio_group_test.go index 7c4e62c70b..007e3a5b07 100644 --- a/widget/radio_group_test.go +++ b/widget/radio_group_test.go @@ -3,10 +3,10 @@ package widget_test import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/layout" - "fyne.io/fyne/test" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/widget/radio_item.go b/widget/radio_item.go index a0133b58e7..e81b66793a 100644 --- a/widget/radio_item.go +++ b/widget/radio_item.go @@ -1,11 +1,11 @@ package widget import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) var _ fyne.Widget = (*radioItem)(nil) diff --git a/widget/radio_item_test.go b/widget/radio_item_test.go index 4665f44fc2..1c8463180d 100644 --- a/widget/radio_item_test.go +++ b/widget/radio_item_test.go @@ -3,9 +3,9 @@ package widget import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/widget/select.go b/widget/select.go index b3157fc809..37d0ebbd3c 100644 --- a/widget/select.go +++ b/widget/select.go @@ -3,11 +3,10 @@ package widget import ( "image/color" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/theme" ) const defaultPlaceHolder string = "(Select one)" @@ -66,10 +65,11 @@ func (s *Select) CreateRenderer() fyne.WidgetRenderer { txtProv.ExtendBaseWidget(txtProv) background := &canvas.Rectangle{} + line := canvas.NewRectangle(theme.ShadowColor()) s.tapBG = canvas.NewRectangle(color.Transparent) - objects := []fyne.CanvasObject{background, s.tapBG, txtProv, icon} - r := &selectRenderer{widget.NewShadowingRenderer(objects, widget.ButtonLevel), icon, txtProv, background, s} - background.FillColor = r.buttonColor() + objects := []fyne.CanvasObject{background, line, s.tapBG, txtProv, icon} + r := &selectRenderer{icon, txtProv, background, line, objects, s} + background.FillColor, line.FillColor = r.bgLineColor() r.updateIcon() s.propertyLock.RUnlock() // updateLabel and some text handling isn't quite right, resolve in text refactor for 2.0 r.updateLabel() @@ -142,7 +142,7 @@ func (s *Select) Resize(size fyne.Size) { s.BaseWidget.Resize(size) if s.popUp != nil { - s.popUp.Resize(fyne.NewSize(size.Width-theme.Padding()*2, s.popUp.MinSize().Height)) + s.popUp.Resize(fyne.NewSize(size.Width, s.popUp.MinSize().Height)) } } @@ -231,7 +231,7 @@ func (s *Select) optionTapped(text string) { func (s *Select) popUpPos() fyne.Position { buttonPos := fyne.CurrentApp().Driver().AbsolutePositionForObject(s.super()) - return buttonPos.Add(fyne.NewPos(theme.Padding(), s.Size().Height-theme.Padding())) + return buttonPos.Add(fyne.NewPos(0, s.Size().Height-theme.InputBorderSize())) } func (s *Select) showPopUp() { @@ -247,7 +247,7 @@ func (s *Select) showPopUp() { c := fyne.CurrentApp().Driver().CanvasForObject(s.super()) s.popUp = NewPopUpMenu(fyne.NewMenu("", items...), c) s.popUp.ShowAtPosition(s.popUpPos()) - s.popUp.Resize(fyne.NewSize(s.Size().Width-theme.Padding()*2, s.popUp.MinSize().Height)) + s.popUp.Resize(fyne.NewSize(s.Size().Width, s.popUp.MinSize().Height)) } func (s *Select) tapAnimation() { @@ -277,7 +277,7 @@ func (s *Select) textColor() color.Color { } func (s *Select) textStyle() fyne.TextStyle { - return fyne.TextStyle{Bold: true} + return fyne.TextStyle{Bold: false} } func (s *Select) textWrap() fyne.TextWrap { @@ -295,36 +295,35 @@ func (s *Select) updateSelected(text string) { } type selectRenderer struct { - *widget.ShadowingRenderer + icon *Icon + label *textProvider + background, line *canvas.Rectangle - icon *Icon - label *textProvider - background *canvas.Rectangle - combo *Select + objects []fyne.CanvasObject + combo *Select } -// Layout the components of the button widget -func (s *selectRenderer) Layout(size fyne.Size) { - doublePad := theme.Padding() * 2 - s.LayoutShadow(size.Subtract(fyne.NewSize(doublePad, doublePad)), fyne.NewPos(theme.Padding(), theme.Padding())) - inner := size.Subtract(fyne.NewSize(doublePad*2, doublePad)) +func (s *selectRenderer) Objects() []fyne.CanvasObject { + return s.objects +} - s.background.Move(fyne.NewPos(theme.Padding(), theme.Padding())) - s.background.Resize(size.Subtract(fyne.NewSize(doublePad, doublePad))) +func (s *selectRenderer) Destroy() {} - offset := fyne.NewSize(theme.IconInlineSize(), 0) - labelSize := inner.Subtract(offset) +// Layout the components of the button widget +func (s *selectRenderer) Layout(size fyne.Size) { + s.line.Resize(fyne.NewSize(size.Width, theme.InputBorderSize())) + s.line.Move(fyne.NewPos(0, size.Height-theme.InputBorderSize())) + s.background.Resize(fyne.NewSize(size.Width, size.Height-theme.InputBorderSize()*2)) + s.background.Move(fyne.NewPos(0, theme.InputBorderSize())) - s.combo.propertyLock.RLock() - defer s.combo.propertyLock.RUnlock() + iconPos := fyne.NewPos(size.Width-theme.IconInlineSize()-theme.Padding()*2, (size.Height-theme.IconInlineSize())/2) + labelSize := fyne.NewSize(iconPos.X-theme.Padding(), s.label.MinSize().Height) s.label.Resize(labelSize) - s.label.Move(fyne.NewPos(doublePad, theme.Padding())) + s.label.Move(fyne.NewPos(theme.Padding(), (size.Height-labelSize.Height)/2)) s.icon.Resize(fyne.NewSize(theme.IconInlineSize(), theme.IconInlineSize())) - s.icon.Move(fyne.NewPos( - size.Width-theme.IconInlineSize()-doublePad, - (size.Height-theme.IconInlineSize())/2)) + s.icon.Move(iconPos) } // MinSize calculates the minimum size of a select button. @@ -333,17 +332,18 @@ func (s *selectRenderer) MinSize() fyne.Size { s.combo.propertyLock.RLock() defer s.combo.propertyLock.RUnlock() - min := fyne.MeasureText(s.combo.PlaceHolder, theme.TextSize(), s.combo.textStyle()) - - min = min.Add(fyne.NewSize(theme.Padding()*6, theme.Padding()*4)) - return min.Add(fyne.NewSize(theme.IconInlineSize()+theme.Padding(), 0)) + minPlaceholderWidth := fyne.MeasureText(s.combo.PlaceHolder, theme.TextSize(), s.combo.textStyle()).Width + min := s.label.MinSize() + min.Width = minPlaceholderWidth + min = min.Add(fyne.NewSize(theme.Padding()*6, theme.Padding()*2)) + return min.Add(fyne.NewSize(theme.IconInlineSize()+theme.Padding()*2, 0)) } func (s *selectRenderer) Refresh() { s.combo.propertyLock.RLock() s.updateLabel() s.updateIcon() - s.background.FillColor = s.buttonColor() + s.background.FillColor, s.line.FillColor = s.bgLineColor() s.combo.propertyLock.RUnlock() s.Layout(s.combo.Size()) @@ -355,17 +355,17 @@ func (s *selectRenderer) Refresh() { canvas.Refresh(s.combo.super()) } -func (s *selectRenderer) buttonColor() color.Color { +func (s *selectRenderer) bgLineColor() (bg color.Color, line color.Color) { if s.combo.Disabled() { - return theme.ButtonColor() + return theme.InputBackgroundColor(), theme.DisabledTextColor() } if s.combo.focused { - return theme.FocusColor() + return theme.FocusColor(), theme.PrimaryColor() } if s.combo.hovered { - return theme.HoverColor() + return theme.HoverColor(), theme.ShadowColor() } - return theme.ButtonColor() + return theme.InputBackgroundColor(), theme.ShadowColor() } func (s *selectRenderer) updateIcon() { diff --git a/widget/select_entry.go b/widget/select_entry.go index 1a669a0f85..c9ad3891e0 100644 --- a/widget/select_entry.go +++ b/widget/select_entry.go @@ -1,8 +1,8 @@ package widget import ( - "fyne.io/fyne" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/theme" ) // SelectEntry is an input field which supports selecting from a fixed set of options. @@ -72,7 +72,7 @@ func (e *SelectEntry) MinSize() fyne.Size { func (e *SelectEntry) Resize(size fyne.Size) { e.Entry.Resize(size) if e.popUp != nil { - e.popUp.Resize(fyne.NewSize(size.Width-theme.Padding()*2, e.popUp.Size().Height)) + e.popUp.Resize(fyne.NewSize(size.Width, e.popUp.Size().Height)) } } @@ -99,11 +99,11 @@ func (e *SelectEntry) setupDropDown() *Button { c := fyne.CurrentApp().Driver().CanvasForObject(e.super()) entryPos := fyne.CurrentApp().Driver().AbsolutePositionForObject(e.super()) - popUpPos := entryPos.Add(fyne.NewPos(theme.Padding(), e.Size().Height)) + popUpPos := entryPos.Add(fyne.NewPos(0, e.Size().Height-theme.InputBorderSize())) e.popUp = NewPopUpMenu(e.dropDown, c) e.popUp.ShowAtPosition(popUpPos) - e.popUp.Resize(fyne.NewSize(e.Size().Width-theme.Padding()*2, e.popUp.MinSize().Height)) + e.popUp.Resize(fyne.NewSize(e.Size().Width, e.popUp.MinSize().Height)) }) dropDownButton.Importance = LowImportance dropDownButton.SetIcon(theme.MenuDropDownIcon()) diff --git a/widget/select_entry_test.go b/widget/select_entry_test.go index 0b3b8da484..70eb775e9e 100644 --- a/widget/select_entry_test.go +++ b/widget/select_entry_test.go @@ -3,10 +3,10 @@ package widget_test import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/widget/select_test.go b/widget/select_test.go index ba2158d9c3..66e610b9de 100644 --- a/widget/select_test.go +++ b/widget/select_test.go @@ -4,11 +4,11 @@ import ( "testing" "time" - "fyne.io/fyne" - "fyne.io/fyne/layout" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/widget/separator.go b/widget/separator.go index 10578791ab..81a5d0654a 100644 --- a/widget/separator.go +++ b/widget/separator.go @@ -1,10 +1,10 @@ package widget import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) var _ fyne.Widget = (*Separator)(nil) diff --git a/widget/slider.go b/widget/slider.go index f4588d03c1..9623555f7a 100644 --- a/widget/slider.go +++ b/widget/slider.go @@ -4,12 +4,12 @@ import ( "fmt" "math" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/data/binding" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/data/binding" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) // Orientation controls the horizontal/vertical layout of a widget @@ -54,7 +54,7 @@ func NewSlider(min, max float64) *Slider { // NewSliderWithData returns a slider connected with the specified data source. // -// Since: 2.0.0 +// Since: 2.0 func NewSliderWithData(min, max float64, data binding.Float) *Slider { slider := NewSlider(min, max) slider.Bind(data) @@ -66,7 +66,7 @@ func NewSliderWithData(min, max float64, data binding.Float) *Slider { // The current value will be displayed and any changes in the data will cause the widget to update. // User interactions with this Slider will set the value into the data source. // -// Since: 2.0.0 +// Since: 2.0 func (s *Slider) Bind(data binding.Float) { s.Unbind() s.valueSource = data @@ -209,7 +209,7 @@ func (s *Slider) CreateRenderer() fyne.WidgetRenderer { // Unbind disconnects any configured data source from this Slider. // The current value will remain at the last value of the data source. // -// Since: 2.0.0 +// Since: 2.0 func (s *Slider) Unbind() { s.OnChanged = nil if s.valueSource == nil || s.valueListener == nil { diff --git a/widget/slider_extend_test.go b/widget/slider_extend_test.go index 76df3f65a7..7e05857da0 100644 --- a/widget/slider_extend_test.go +++ b/widget/slider_extend_test.go @@ -5,8 +5,8 @@ import ( "github.com/stretchr/testify/assert" - "fyne.io/fyne" - "fyne.io/fyne/internal/cache" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/internal/cache" ) type extendedSlider struct { diff --git a/widget/slider_test.go b/widget/slider_test.go index 501bfe8ea7..52292d76bc 100644 --- a/widget/slider_test.go +++ b/widget/slider_test.go @@ -3,10 +3,10 @@ package widget import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/data/binding" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/data/binding" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/widget/tabcontainer_desktop_test.go b/widget/tabcontainer_desktop_test.go deleted file mode 100644 index 60e4590a6a..0000000000 --- a/widget/tabcontainer_desktop_test.go +++ /dev/null @@ -1,346 +0,0 @@ -// +build !mobile - -package widget_test - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" -) - -func TestTabContainer_ApplyTheme(t *testing.T) { - test.NewApp() - defer test.NewApp() - - w := test.NewWindow( - widget.NewTabContainer(&widget.TabItem{Text: "Test", Content: widget.NewLabel("Text")}), - ) - defer w.Close() - w.SetPadded(false) - w.Resize(fyne.NewSize(150, 150)) - c := w.Canvas() - - test.AssertImageMatches(t, "tabcontainer/desktop/single_initial.png", c.Capture()) - - test.ApplyTheme(t, test.NewTheme()) - test.AssertImageMatches(t, "tabcontainer/desktop/single_custom_theme.png", c.Capture()) -} - -func TestTabContainer_ChangeItemContent(t *testing.T) { - test.NewApp() - defer test.NewApp() - - item1 := &widget.TabItem{Text: "Test1", Content: widget.NewLabel("Text1")} - item2 := &widget.TabItem{Text: "Test2", Content: widget.NewLabel("Text2")} - tabs := widget.NewTabContainer(item1, item2) - w := test.NewWindow(tabs) - defer w.Close() - w.SetPadded(false) - w.Resize(fyne.NewSize(150, 150)) - c := w.Canvas() - - test.AssertRendersToMarkup(t, "tabcontainer/desktop/change_content_initial.xml", c) - - item1.Content = widget.NewLabel("Text3") - tabs.Refresh() - test.AssertRendersToMarkup(t, "tabcontainer/desktop/change_content_change_visible.xml", c) - - item2.Content = widget.NewLabel("Text4") - tabs.Refresh() - test.AssertRendersToMarkup(t, "tabcontainer/desktop/change_content_change_hidden.xml", c) -} - -func TestTabContainer_ChangeItemIcon(t *testing.T) { - test.NewApp() - defer test.NewApp() - - item1 := &widget.TabItem{Icon: theme.CancelIcon(), Content: widget.NewLabel("Text1")} - item2 := &widget.TabItem{Icon: theme.ConfirmIcon(), Content: widget.NewLabel("Text2")} - tabs := widget.NewTabContainer(item1, item2) - w := test.NewWindow(tabs) - defer w.Close() - w.SetPadded(false) - w.Resize(fyne.NewSize(150, 150)) - c := w.Canvas() - - test.AssertRendersToMarkup(t, "tabcontainer/desktop/change_icon_initial.xml", c) - - item1.Icon = theme.InfoIcon() - tabs.Refresh() - test.AssertRendersToMarkup(t, "tabcontainer/desktop/change_icon_change_selected.xml", c) - - item2.Icon = theme.ContentAddIcon() - tabs.Refresh() - test.AssertRendersToMarkup(t, "tabcontainer/desktop/change_icon_change_unselected.xml", c) -} - -func TestTabContainer_ChangeItemText(t *testing.T) { - test.NewApp() - defer test.NewApp() - - item1 := &widget.TabItem{Text: "Test1", Content: widget.NewLabel("Text1")} - item2 := &widget.TabItem{Text: "Test2", Content: widget.NewLabel("Text2")} - tabs := widget.NewTabContainer(item1, item2) - w := test.NewWindow(tabs) - defer w.Close() - w.SetPadded(false) - w.Resize(fyne.NewSize(150, 150)) - c := w.Canvas() - - test.AssertRendersToMarkup(t, "tabcontainer/desktop/change_label_initial.xml", c) - - item1.Text = "New 1" - tabs.Refresh() - test.AssertRendersToMarkup(t, "tabcontainer/desktop/change_label_change_selected.xml", c) - - item2.Text = "New 2" - tabs.Refresh() - test.AssertRendersToMarkup(t, "tabcontainer/desktop/change_label_change_unselected.xml", c) -} - -func TestTabContainer_DynamicTabs(t *testing.T) { - test.NewApp() - defer test.NewApp() - - item1 := &widget.TabItem{Text: "Test1", Content: widget.NewLabel("Text 1")} - tabs := widget.NewTabContainer(item1) - w := test.NewWindow(tabs) - defer w.Close() - w.SetPadded(false) - w.Resize(fyne.NewSize(300, 150)) - c := w.Canvas() - - test.AssertRendersToMarkup(t, "tabcontainer/desktop/dynamic_initial.xml", c) - - appendedItem := widget.NewTabItem("Test2", widget.NewLabel("Text 2")) - tabs.Append(appendedItem) - assert.Equal(t, 2, len(tabs.Items)) - assert.Equal(t, "Test2", tabs.Items[1].Text) - test.AssertRendersToMarkup(t, "tabcontainer/desktop/dynamic_appended.xml", c) - - tabs.RemoveIndex(1) - assert.Equal(t, len(tabs.Items), 1) - assert.Equal(t, "Test1", tabs.Items[0].Text) - test.AssertRendersToMarkup(t, "tabcontainer/desktop/dynamic_initial.xml", c) - - tabs.Append(appendedItem) - tabs.Remove(tabs.Items[0]) - assert.Equal(t, len(tabs.Items), 1) - assert.Equal(t, "Test2", tabs.Items[0].Text) - test.AssertRendersToMarkup(t, "tabcontainer/desktop/dynamic_appended_and_removed.xml", c) - - tabs.Append(widget.NewTabItem("Test3", canvas.NewCircle(theme.BackgroundColor()))) - tabs.Append(widget.NewTabItem("Test4", canvas.NewCircle(theme.BackgroundColor()))) - tabs.Append(widget.NewTabItem("Test5", canvas.NewCircle(theme.BackgroundColor()))) - assert.Equal(t, 4, len(tabs.Items)) - assert.Equal(t, "Test3", tabs.Items[1].Text) - assert.Equal(t, "Test4", tabs.Items[2].Text) - assert.Equal(t, "Test5", tabs.Items[3].Text) - test.AssertRendersToMarkup(t, "tabcontainer/desktop/dynamic_appended_another_three.xml", c) - - tabs.SetItems([]*widget.TabItem{ - widget.NewTabItem("Test6", widget.NewLabel("Text 6")), - widget.NewTabItem("Test7", widget.NewLabel("Text 7")), - widget.NewTabItem("Test8", widget.NewLabel("Text 8")), - }) - assert.Equal(t, 3, len(tabs.Items)) - assert.Equal(t, "Test6", tabs.Items[0].Text) - assert.Equal(t, "Test7", tabs.Items[1].Text) - assert.Equal(t, "Test8", tabs.Items[2].Text) - test.AssertRendersToMarkup(t, "tabcontainer/desktop/dynamic_replaced_completely.xml", c) -} - -func TestTabContainer_HoverButtons(t *testing.T) { - test.NewApp() - defer test.NewApp() - - item1 := &widget.TabItem{Text: "Test1", Content: widget.NewLabel("Text1")} - item2 := &widget.TabItem{Text: "Test2", Content: widget.NewLabel("Text2")} - tabs := widget.NewTabContainer(item1, item2) - w := test.NewWindow(tabs) - defer w.Close() - w.SetPadded(false) - w.Resize(fyne.NewSize(150, 150)) - c := w.Canvas() - - test.AssertRendersToMarkup(t, "tabcontainer/desktop/hover_none.xml", c) - - test.MoveMouse(c, fyne.NewPos(10, 10)) - test.AssertRendersToMarkup(t, "tabcontainer/desktop/hover_first.xml", c) - - test.MoveMouse(c, fyne.NewPos(75, 10)) - test.AssertRendersToMarkup(t, "tabcontainer/desktop/hover_second.xml", c) - - test.MoveMouse(c, fyne.NewPos(10, 10)) - test.AssertRendersToMarkup(t, "tabcontainer/desktop/hover_first.xml", c) -} - -func TestTabContainer_Layout(t *testing.T) { - test.NewApp() - defer test.NewApp() - - w := test.NewWindow(nil) - defer w.Close() - w.SetPadded(false) - c := w.Canvas() - - tests := []struct { - name string - item *widget.TabItem - location widget.TabLocation - want string - }{ - { - name: "top: tab with icon and text", - item: widget.NewTabItemWithIcon("Text1", theme.CancelIcon(), canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationTop, - want: "tabcontainer/desktop/layout_top_icon_and_text.xml", - }, - { - name: "top: tab with text only", - item: widget.NewTabItem("Text2", canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationTop, - want: "tabcontainer/desktop/layout_top_text.xml", - }, - { - name: "top: tab with icon only", - item: widget.NewTabItemWithIcon("", theme.InfoIcon(), canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationTop, - want: "tabcontainer/desktop/layout_top_icon.xml", - }, - { - name: "bottom: tab with icon and text", - item: widget.NewTabItemWithIcon("Text1", theme.CancelIcon(), canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationBottom, - want: "tabcontainer/desktop/layout_bottom_icon_and_text.xml", - }, - { - name: "bottom: tab with text only", - item: widget.NewTabItem("Text2", canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationBottom, - want: "tabcontainer/desktop/layout_bottom_text.xml", - }, - { - name: "bottom: tab with icon only", - item: widget.NewTabItemWithIcon("", theme.InfoIcon(), canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationBottom, - want: "tabcontainer/desktop/layout_bottom_icon.xml", - }, - { - name: "leading: tab with icon and text", - item: widget.NewTabItemWithIcon("Text1", theme.CancelIcon(), canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationLeading, - want: "tabcontainer/desktop/layout_leading_icon_and_text.xml", - }, - { - name: "leading: tab with text only", - item: widget.NewTabItem("Text2", canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationLeading, - want: "tabcontainer/desktop/layout_leading_text.xml", - }, - { - name: "leading: tab with icon only", - item: widget.NewTabItemWithIcon("", theme.InfoIcon(), canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationLeading, - want: "tabcontainer/desktop/layout_leading_icon.xml", - }, - { - name: "trailing: tab with icon and text", - item: widget.NewTabItemWithIcon("Text1", theme.CancelIcon(), canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationTrailing, - want: "tabcontainer/desktop/layout_trailing_icon_and_text.xml", - }, - { - name: "trailing: tab with text only", - item: widget.NewTabItem("Text2", canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationTrailing, - want: "tabcontainer/desktop/layout_trailing_text.xml", - }, - { - name: "trailing: tab with icon only", - item: widget.NewTabItemWithIcon("", theme.InfoIcon(), canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationTrailing, - want: "tabcontainer/desktop/layout_trailing_icon.xml", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tabs := widget.NewTabContainer(tt.item) - tabs.SetTabLocation(tt.location) - w.SetContent(tabs) - w.Resize(fyne.NewSize(150, 150)) - - test.AssertRendersToMarkup(t, tt.want, c) - }) - } -} - -func TestTabContainer_SetTabLocation(t *testing.T) { - test.NewApp() - defer test.NewApp() - - item1 := &widget.TabItem{Text: "Test1", Content: widget.NewLabel("Text 1")} - item2 := &widget.TabItem{Text: "Test2", Content: widget.NewLabel("Text 2")} - item3 := &widget.TabItem{Text: "Test3", Content: widget.NewLabel("Text 3")} - tabs := widget.NewTabContainer(item1, item2, item3) - w := test.NewWindow(tabs) - defer w.Close() - w.SetPadded(false) - c := w.Canvas() - - w.Resize(tabs.MinSize()) - test.AssertRendersToMarkup(t, "tabcontainer/desktop/tab_location_top.xml", c) - - tabs.SetTabLocation(widget.TabLocationLeading) - w.Resize(tabs.MinSize()) - test.AssertRendersToMarkup(t, "tabcontainer/desktop/tab_location_leading.xml", c) - - tabs.SetTabLocation(widget.TabLocationBottom) - w.Resize(tabs.MinSize()) - test.AssertRendersToMarkup(t, "tabcontainer/desktop/tab_location_bottom.xml", c) - - tabs.SetTabLocation(widget.TabLocationTrailing) - w.Resize(tabs.MinSize()) - test.AssertRendersToMarkup(t, "tabcontainer/desktop/tab_location_trailing.xml", c) - - tabs.SetTabLocation(widget.TabLocationTop) - w.Resize(tabs.MinSize()) - test.AssertRendersToMarkup(t, "tabcontainer/desktop/tab_location_top.xml", c) -} - -func TestTabContainer_Tapped(t *testing.T) { - test.NewApp() - defer test.NewApp() - - item1 := &widget.TabItem{Text: "Test1", Content: widget.NewLabel("Text 1")} - item2 := &widget.TabItem{Text: "Test2", Content: widget.NewLabel("Text 2")} - item3 := &widget.TabItem{Text: "Test3", Content: widget.NewLabel("Text 3")} - tabs := widget.NewTabContainer(item1, item2, item3) - w := test.NewWindow(tabs) - defer w.Close() - w.SetPadded(false) - w.Resize(fyne.NewSize(200, 100)) - c := w.Canvas() - - require.Equal(t, 0, tabs.CurrentTabIndex()) - test.AssertRendersToMarkup(t, "tabcontainer/desktop/tapped_first_selected.xml", c) - - test.TapCanvas(c, fyne.NewPos(75, 10)) - assert.Equal(t, 1, tabs.CurrentTabIndex()) - test.AssertRendersToMarkup(t, "tabcontainer/desktop/tapped_second_selected.xml", c) - - test.TapCanvas(c, fyne.NewPos(150, 10)) - assert.Equal(t, 2, tabs.CurrentTabIndex()) - test.AssertRendersToMarkup(t, "tabcontainer/desktop/tapped_third_selected.xml", c) - - test.TapCanvas(c, fyne.NewPos(10, 10)) - require.Equal(t, 0, tabs.CurrentTabIndex()) - test.AssertRendersToMarkup(t, "tabcontainer/desktop/tapped_first_selected.xml", c) -} diff --git a/widget/tabcontainer_mobile_test.go b/widget/tabcontainer_mobile_test.go deleted file mode 100644 index c3c9d3efb0..0000000000 --- a/widget/tabcontainer_mobile_test.go +++ /dev/null @@ -1,346 +0,0 @@ -// +build mobile - -package widget_test - -import ( - "testing" - - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestTabContainer_ApplyTheme(t *testing.T) { - test.NewApp() - defer test.NewApp() - - w := test.NewWindow( - widget.NewTabContainer(&widget.TabItem{Text: "Test", Content: widget.NewLabel("Text")}), - ) - defer w.Close() - w.SetPadded(false) - w.Resize(fyne.NewSize(150, 150)) - c := w.Canvas() - - test.AssertImageMatches(t, "tabcontainer/mobile/theme_default.png", c.Capture()) - - test.ApplyTheme(t, test.NewTheme()) - test.AssertImageMatches(t, "tabcontainer/mobile/theme_ugly.png", c.Capture()) -} - -func TestTabContainer_ChangeItemContent(t *testing.T) { - test.NewApp() - defer test.NewApp() - - item1 := &widget.TabItem{Text: "Test1", Content: widget.NewLabel("Text1")} - item2 := &widget.TabItem{Text: "Test2", Content: widget.NewLabel("Text2")} - tabs := widget.NewTabContainer(item1, item2) - w := test.NewWindow(tabs) - defer w.Close() - w.SetPadded(false) - w.Resize(fyne.NewSize(150, 150)) - c := w.Canvas() - - test.AssertRendersToMarkup(t, "tabcontainer/mobile/change_content_initial.xml", c) - - item1.Content = widget.NewLabel("Text3") - tabs.Refresh() - test.AssertRendersToMarkup(t, "tabcontainer/mobile/change_content_change_visible.xml", c) - - item2.Content = widget.NewLabel("Text4") - tabs.Refresh() - test.AssertRendersToMarkup(t, "tabcontainer/mobile/change_content_change_hidden.xml", c) -} - -func TestTabContainer_ChangeItemIcon(t *testing.T) { - test.NewApp() - defer test.NewApp() - - item1 := &widget.TabItem{Icon: theme.CancelIcon(), Content: widget.NewLabel("Text1")} - item2 := &widget.TabItem{Icon: theme.ConfirmIcon(), Content: widget.NewLabel("Text2")} - tabs := widget.NewTabContainer(item1, item2) - w := test.NewWindow(tabs) - defer w.Close() - w.SetPadded(false) - w.Resize(fyne.NewSize(150, 150)) - c := w.Canvas() - - test.AssertRendersToMarkup(t, "tabcontainer/mobile/change_icon_initial.xml", c) - - item1.Icon = theme.InfoIcon() - tabs.Refresh() - test.AssertRendersToMarkup(t, "tabcontainer/mobile/change_icon_change_selected.xml", c) - - item2.Icon = theme.ContentAddIcon() - tabs.Refresh() - test.AssertRendersToMarkup(t, "tabcontainer/mobile/change_icon_change_unselected.xml", c) -} - -func TestTabContainer_ChangeItemText(t *testing.T) { - test.NewApp() - defer test.NewApp() - - item1 := &widget.TabItem{Text: "Test1", Content: widget.NewLabel("Text1")} - item2 := &widget.TabItem{Text: "Test2", Content: widget.NewLabel("Text2")} - tabs := widget.NewTabContainer(item1, item2) - w := test.NewWindow(tabs) - defer w.Close() - w.SetPadded(false) - w.Resize(fyne.NewSize(150, 150)) - c := w.Canvas() - - test.AssertRendersToMarkup(t, "tabcontainer/mobile/change_label_initial.xml", c) - - item1.Text = "New 1" - tabs.Refresh() - test.AssertRendersToMarkup(t, "tabcontainer/mobile/change_label_change_selected.xml", c) - - item2.Text = "New 2" - tabs.Refresh() - test.AssertRendersToMarkup(t, "tabcontainer/mobile/change_label_change_unselected.xml", c) -} - -func TestTabContainer_DynamicTabs(t *testing.T) { - test.NewApp() - defer test.NewApp() - - item1 := &widget.TabItem{Text: "Test1", Content: widget.NewLabel("Text 1")} - tabs := widget.NewTabContainer(item1) - w := test.NewWindow(tabs) - defer w.Close() - w.SetPadded(false) - w.Resize(fyne.NewSize(300, 150)) - c := w.Canvas() - - test.AssertRendersToMarkup(t, "tabcontainer/mobile/dynamic_initial.xml", c) - - appendedItem := widget.NewTabItem("Test2", widget.NewLabel("Text 2")) - tabs.Append(appendedItem) - assert.Equal(t, 2, len(tabs.Items)) - assert.Equal(t, "Test2", tabs.Items[1].Text) - test.AssertRendersToMarkup(t, "tabcontainer/mobile/dynamic_appended.xml", c) - - tabs.RemoveIndex(1) - assert.Equal(t, len(tabs.Items), 1) - assert.Equal(t, "Test1", tabs.Items[0].Text) - test.AssertRendersToMarkup(t, "tabcontainer/mobile/dynamic_initial.xml", c) - - tabs.Append(appendedItem) - tabs.Remove(tabs.Items[0]) - assert.Equal(t, len(tabs.Items), 1) - assert.Equal(t, "Test2", tabs.Items[0].Text) - test.AssertRendersToMarkup(t, "tabcontainer/mobile/dynamic_appended_and_removed.xml", c) - - tabs.Append(widget.NewTabItem("Test3", canvas.NewCircle(theme.BackgroundColor()))) - tabs.Append(widget.NewTabItem("Test4", canvas.NewCircle(theme.BackgroundColor()))) - tabs.Append(widget.NewTabItem("Test5", canvas.NewCircle(theme.BackgroundColor()))) - assert.Equal(t, 4, len(tabs.Items)) - assert.Equal(t, "Test3", tabs.Items[1].Text) - assert.Equal(t, "Test4", tabs.Items[2].Text) - assert.Equal(t, "Test5", tabs.Items[3].Text) - test.AssertRendersToMarkup(t, "tabcontainer/mobile/dynamic_appended_another_three.xml", c) - - tabs.SetItems([]*widget.TabItem{ - widget.NewTabItem("Test6", widget.NewLabel("Text 6")), - widget.NewTabItem("Test7", widget.NewLabel("Text 7")), - widget.NewTabItem("Test8", widget.NewLabel("Text 8")), - }) - assert.Equal(t, 3, len(tabs.Items)) - assert.Equal(t, "Test6", tabs.Items[0].Text) - assert.Equal(t, "Test7", tabs.Items[1].Text) - assert.Equal(t, "Test8", tabs.Items[2].Text) - test.AssertRendersToMarkup(t, "tabcontainer/mobile/dynamic_replaced_completely.xml", c) -} - -func TestTabContainer_HoverButtons(t *testing.T) { - test.NewApp() - defer test.NewApp() - test.ApplyTheme(t, theme.LightTheme()) - - item1 := &widget.TabItem{Text: "Test1", Content: widget.NewLabel("Text1")} - item2 := &widget.TabItem{Text: "Test2", Content: widget.NewLabel("Text2")} - tabs := widget.NewTabContainer(item1, item2) - w := test.NewWindow(tabs) - defer w.Close() - w.SetPadded(false) - w.Resize(fyne.NewSize(150, 150)) - c := w.Canvas() - - test.AssertRendersToMarkup(t, "tabcontainer/mobile/hover_none.xml", c) - - test.MoveMouse(c, fyne.NewPos(10, 10)) - test.AssertRendersToMarkup(t, "tabcontainer/mobile/hover_none.xml", c, "no hovering on mobile") - - test.MoveMouse(c, fyne.NewPos(75, 10)) - test.AssertRendersToMarkup(t, "tabcontainer/mobile/hover_none.xml", c, "no hovering on mobile") - - test.MoveMouse(c, fyne.NewPos(10, 10)) - test.AssertRendersToMarkup(t, "tabcontainer/mobile/hover_none.xml", c, "no hovering on mobile") -} - -func TestTabContainer_Layout(t *testing.T) { - test.NewApp() - defer test.NewApp() - - w := test.NewWindow(nil) - defer w.Close() - w.SetPadded(false) - c := w.Canvas() - - tests := []struct { - name string - item *widget.TabItem - location widget.TabLocation - want string - }{ - { - name: "top: tab with icon and text", - item: widget.NewTabItemWithIcon("Text1", theme.CancelIcon(), canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationTop, - want: "tabcontainer/mobile/layout_top_icon_and_text.xml", - }, - { - name: "top: tab with text only", - item: widget.NewTabItem("Text2", canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationTop, - want: "tabcontainer/mobile/layout_top_text.xml", - }, - { - name: "top: tab with icon only", - item: widget.NewTabItemWithIcon("", theme.InfoIcon(), canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationTop, - want: "tabcontainer/mobile/layout_top_icon.xml", - }, - { - name: "bottom: tab with icon and text", - item: widget.NewTabItemWithIcon("Text1", theme.CancelIcon(), canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationBottom, - want: "tabcontainer/mobile/layout_bottom_icon_and_text.xml", - }, - { - name: "bottom: tab with text only", - item: widget.NewTabItem("Text2", canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationBottom, - want: "tabcontainer/mobile/layout_bottom_text.xml", - }, - { - name: "bottom: tab with icon only", - item: widget.NewTabItemWithIcon("", theme.InfoIcon(), canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationBottom, - want: "tabcontainer/mobile/layout_bottom_ico.xml", - }, - { - name: "leading: tab with icon and text", - item: widget.NewTabItemWithIcon("Text1", theme.CancelIcon(), canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationLeading, - want: "tabcontainer/mobile/layout_bottom_icon_and_text.xml", - }, - { - name: "leading: tab with text only", - item: widget.NewTabItem("Text2", canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationLeading, - want: "tabcontainer/mobile/layout_bottom_text.xml", - }, - { - name: "leading: tab with icon only", - item: widget.NewTabItemWithIcon("", theme.InfoIcon(), canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationLeading, - want: "tabcontainer/mobile/layout_bottom_icon.xml", - }, - { - name: "trailing: tab with icon and text", - item: widget.NewTabItemWithIcon("Text1", theme.CancelIcon(), canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationTrailing, - want: "tabcontainer/mobile/layout_bottom_icon_and_text.xml", - }, - { - name: "trailing: tab with text only", - item: widget.NewTabItem("Text2", canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationTrailing, - want: "tabcontainer/mobile/layout_bottom_text.xml", - }, - { - name: "trailing: tab with icon only", - item: widget.NewTabItemWithIcon("", theme.InfoIcon(), canvas.NewCircle(theme.BackgroundColor())), - location: widget.TabLocationTrailing, - want: "tabcontainer/mobile/layout_bottom_icon.xml", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tabs := widget.NewTabContainer(tt.item) - tabs.SetTabLocation(tt.location) - w.SetContent(tabs) - w.Resize(fyne.NewSize(150, 150)) - - test.AssertRendersToMarkup(t, tt.want, c) - }) - } -} - -func TestTabContainer_SetTabLocation(t *testing.T) { - test.NewApp() - defer test.NewApp() - - item1 := &widget.TabItem{Text: "Test1", Content: widget.NewLabel("Text 1")} - item2 := &widget.TabItem{Text: "Test2", Content: widget.NewLabel("Text 2")} - item3 := &widget.TabItem{Text: "Test3", Content: widget.NewLabel("Text 3")} - tabs := widget.NewTabContainer(item1, item2, item3) - w := test.NewWindow(tabs) - defer w.Close() - w.SetPadded(false) - c := w.Canvas() - - w.Resize(tabs.MinSize()) - test.AssertRendersToMarkup(t, "tabcontainer/mobile/tab_location_top.xml", c) - - tabs.SetTabLocation(widget.TabLocationLeading) - w.Resize(tabs.MinSize()) - test.AssertRendersToMarkup(t, "tabcontainer/mobile/tab_location_bottom.xml", c, "leading is the same as bottom on mobile") - - tabs.SetTabLocation(widget.TabLocationBottom) - w.Resize(tabs.MinSize()) - test.AssertRendersToMarkup(t, "tabcontainer/mobile/tab_location_bottom.xml", c) - - tabs.SetTabLocation(widget.TabLocationTrailing) - w.Resize(tabs.MinSize()) - test.AssertRendersToMarkup(t, "tabcontainer/mobile/tab_location_bottom.xml", c, "trailing is the same as bottom on mobile") - - tabs.SetTabLocation(widget.TabLocationTop) - w.Resize(tabs.MinSize()) - test.AssertRendersToMarkup(t, "tabcontainer/mobile/tab_location_top.xml", c) -} - -func TestTabContainer_Tapped(t *testing.T) { - test.NewApp() - defer test.NewApp() - - item1 := &widget.TabItem{Text: "Test1", Content: widget.NewLabel("Text 1")} - item2 := &widget.TabItem{Text: "Test2", Content: widget.NewLabel("Text 2")} - item3 := &widget.TabItem{Text: "Test3", Content: widget.NewLabel("Text 3")} - tabs := widget.NewTabContainer(item1, item2, item3) - w := test.NewWindow(tabs) - defer w.Close() - w.SetPadded(false) - w.Resize(fyne.NewSize(200, 100)) - c := w.Canvas() - - require.Equal(t, 0, tabs.CurrentTabIndex()) - test.AssertRendersToMarkup(t, "tabcontainer/mobile/tapped_first_selected.xml", c) - - test.TapCanvas(c, fyne.NewPos(75, 10)) - assert.Equal(t, 1, tabs.CurrentTabIndex()) - test.AssertRendersToMarkup(t, "tabcontainer/mobile/tapped_second_selected.xml", c) - - test.TapCanvas(c, fyne.NewPos(150, 10)) - assert.Equal(t, 2, tabs.CurrentTabIndex()) - test.AssertRendersToMarkup(t, "tabcontainer/mobile/tapped_third_selected.xml", c) - - test.TapCanvas(c, fyne.NewPos(10, 10)) - require.Equal(t, 0, tabs.CurrentTabIndex()) - test.AssertRendersToMarkup(t, "tabcontainer/mobile/tapped_first_selected.xml", c) -} diff --git a/widget/table.go b/widget/table.go index 7b0bcceab0..f49c6aaee4 100644 --- a/widget/table.go +++ b/widget/table.go @@ -3,11 +3,11 @@ package widget import ( "math" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) // Declare conformity with Widget interface. diff --git a/widget/table_desktop_test.go b/widget/table_desktop_test.go index 7014abfc4b..53ce800fee 100644 --- a/widget/table_desktop_test.go +++ b/widget/table_desktop_test.go @@ -6,8 +6,8 @@ import ( "fmt" "testing" - "fyne.io/fyne" - "fyne.io/fyne/test" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/test" "github.com/stretchr/testify/assert" ) diff --git a/widget/table_test.go b/widget/table_test.go index 371b2deb88..d0b3113e91 100644 --- a/widget/table_test.go +++ b/widget/table_test.go @@ -5,10 +5,10 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/widget/testdata/select/disabled.xml b/widget/testdata/select/disabled.xml index b3acd72780..0763ccfa81 100644 --- a/widget/testdata/select/disabled.xml +++ b/widget/testdata/select/disabled.xml @@ -1,23 +1,14 @@ - - - - - - - - - - - - + + + - - (Select one) + + (Select one) - + diff --git a/widget/testdata/select/focus_focused_b_selected.xml b/widget/testdata/select/focus_focused_b_selected.xml index 1221731e0c..00c21892a3 100644 --- a/widget/testdata/select/focus_focused_b_selected.xml +++ b/widget/testdata/select/focus_focused_b_selected.xml @@ -1,23 +1,14 @@ - - - - - - - - - - - - + + + - - Option B + + Option B - + diff --git a/widget/testdata/select/focus_focused_none_selected.xml b/widget/testdata/select/focus_focused_none_selected.xml index 70566cf0f0..ed1a0f5464 100644 --- a/widget/testdata/select/focus_focused_none_selected.xml +++ b/widget/testdata/select/focus_focused_none_selected.xml @@ -1,23 +1,14 @@ - - - - - - - - - - - - + + + - - (Select one) + + (Select one) - + diff --git a/widget/testdata/select/focus_unfocused_b_selected.xml b/widget/testdata/select/focus_unfocused_b_selected.xml index d3b17f22da..c38c7deff8 100644 --- a/widget/testdata/select/focus_unfocused_b_selected.xml +++ b/widget/testdata/select/focus_unfocused_b_selected.xml @@ -1,23 +1,14 @@ - - - - - - - - - - - - + + + - - Option B + + Option B - + diff --git a/widget/testdata/select/focus_unfocused_none_selected.xml b/widget/testdata/select/focus_unfocused_none_selected.xml index bf6b2dc5f4..bae3167608 100644 --- a/widget/testdata/select/focus_unfocused_none_selected.xml +++ b/widget/testdata/select/focus_unfocused_none_selected.xml @@ -1,23 +1,14 @@ - - - - - - - - - - - - + + + - - (Select one) + + (Select one) - + diff --git a/widget/testdata/select/kbdctrl_a_selected.xml b/widget/testdata/select/kbdctrl_a_selected.xml index 5d4523ec4d..d612b4ce6f 100644 --- a/widget/testdata/select/kbdctrl_a_selected.xml +++ b/widget/testdata/select/kbdctrl_a_selected.xml @@ -1,23 +1,14 @@ - - - - - - - - - - - - + + + - - Option A + + Option A - + diff --git a/widget/testdata/select/kbdctrl_b_selected.xml b/widget/testdata/select/kbdctrl_b_selected.xml index 19967910d5..21473bd120 100644 --- a/widget/testdata/select/kbdctrl_b_selected.xml +++ b/widget/testdata/select/kbdctrl_b_selected.xml @@ -1,23 +1,14 @@ - - - - - - - - - - - - + + + - - Option B + + Option B - + diff --git a/widget/testdata/select/kbdctrl_c_selected.xml b/widget/testdata/select/kbdctrl_c_selected.xml index 80a6b060a6..8b14cf42e6 100644 --- a/widget/testdata/select/kbdctrl_c_selected.xml +++ b/widget/testdata/select/kbdctrl_c_selected.xml @@ -1,23 +1,14 @@ - - - - - - - - - - - - + + + - - Option C + + Option C - + diff --git a/widget/testdata/select/kbdctrl_none_selected.xml b/widget/testdata/select/kbdctrl_none_selected.xml index fabc4714b9..4618511e3a 100644 --- a/widget/testdata/select/kbdctrl_none_selected.xml +++ b/widget/testdata/select/kbdctrl_none_selected.xml @@ -1,23 +1,14 @@ - - - - - - - - - - - - + + + - - (Select one) + + (Select one) - + diff --git a/widget/testdata/select/kbdctrl_none_selected_popup.xml b/widget/testdata/select/kbdctrl_none_selected_popup.xml index a6ca46f86b..7359f14720 100644 --- a/widget/testdata/select/kbdctrl_none_selected_popup.xml +++ b/widget/testdata/select/kbdctrl_none_selected_popup.xml @@ -1,23 +1,14 @@ - - - - - - - - - - - - + + + - - (Select one) + + (Select one) - + @@ -25,25 +16,25 @@ - - + + - - - - - + + + + + - - - - - + + + + + Option A - + Option B diff --git a/widget/testdata/select/layout_empty.xml b/widget/testdata/select/layout_empty.xml index 414751f351..9320cdcdd1 100644 --- a/widget/testdata/select/layout_empty.xml +++ b/widget/testdata/select/layout_empty.xml @@ -1,23 +1,14 @@ - - - - - - - - - - - - + + + - - (Select one) + + (Select one) - + diff --git a/widget/testdata/select/layout_empty_expanded.xml b/widget/testdata/select/layout_empty_expanded.xml index 934e2c2e10..47f0d05c1e 100644 --- a/widget/testdata/select/layout_empty_expanded.xml +++ b/widget/testdata/select/layout_empty_expanded.xml @@ -1,23 +1,14 @@ - - - - - - - - - - + + + + + + (Select one) - - - - (Select one) - - + @@ -25,21 +16,21 @@ - - + + - - - - - + + + + + - - - - + + + + diff --git a/widget/testdata/select/layout_empty_expanded_placeholder.xml b/widget/testdata/select/layout_empty_expanded_placeholder.xml index b83e8b2bf7..29852d9ae2 100644 --- a/widget/testdata/select/layout_empty_expanded_placeholder.xml +++ b/widget/testdata/select/layout_empty_expanded_placeholder.xml @@ -2,20 +2,11 @@ - - - - - - - - - - - + + - - (Pick 1) + + (Pick 1) @@ -25,21 +16,21 @@ - - + + - - - - - + + + + + - - - - + + + + diff --git a/widget/testdata/select/layout_empty_placeholder.xml b/widget/testdata/select/layout_empty_placeholder.xml index aacad31829..f1b414e935 100644 --- a/widget/testdata/select/layout_empty_placeholder.xml +++ b/widget/testdata/select/layout_empty_placeholder.xml @@ -2,20 +2,11 @@ - - - - - - - - - - - + + - - (Pick 1) + + (Pick 1) diff --git a/widget/testdata/select/layout_multiple.xml b/widget/testdata/select/layout_multiple.xml index 414751f351..9320cdcdd1 100644 --- a/widget/testdata/select/layout_multiple.xml +++ b/widget/testdata/select/layout_multiple.xml @@ -1,23 +1,14 @@ - - - - - - - - - - - - + + + - - (Select one) + + (Select one) - + diff --git a/widget/testdata/select/layout_multiple_expanded.xml b/widget/testdata/select/layout_multiple_expanded.xml index 20145f36d7..13a365cb6f 100644 --- a/widget/testdata/select/layout_multiple_expanded.xml +++ b/widget/testdata/select/layout_multiple_expanded.xml @@ -1,23 +1,14 @@ - - - - - - - - - - + + + + + + (Select one) - - - - (Select one) - - + @@ -25,25 +16,25 @@ - - + + - - - - - + + + + + - - - - - + + + + + Foo - + Bar diff --git a/widget/testdata/select/layout_multiple_expanded_placeholder.xml b/widget/testdata/select/layout_multiple_expanded_placeholder.xml index a27bc13195..1125014a6d 100644 --- a/widget/testdata/select/layout_multiple_expanded_placeholder.xml +++ b/widget/testdata/select/layout_multiple_expanded_placeholder.xml @@ -2,20 +2,11 @@ - - - - - - - - - - - + + - - (Pick 1) + + (Pick 1) @@ -25,25 +16,25 @@ - - + + - - - - - + + + + + - - - - - + + + + + Foo - + Bar diff --git a/widget/testdata/select/layout_multiple_expanded_selected.xml b/widget/testdata/select/layout_multiple_expanded_selected.xml index 272be725f9..188be50973 100644 --- a/widget/testdata/select/layout_multiple_expanded_selected.xml +++ b/widget/testdata/select/layout_multiple_expanded_selected.xml @@ -1,23 +1,14 @@ - - - - - - - - - - + + + + + + Foo - - - - Foo - - + @@ -25,25 +16,25 @@ - - + + - - - - - + + + + + - - - - - + + + + + Foo - + Bar diff --git a/widget/testdata/select/layout_multiple_expanded_selected_placeholder.xml b/widget/testdata/select/layout_multiple_expanded_selected_placeholder.xml index 4cc3616a4f..9cad57a8e3 100644 --- a/widget/testdata/select/layout_multiple_expanded_selected_placeholder.xml +++ b/widget/testdata/select/layout_multiple_expanded_selected_placeholder.xml @@ -2,20 +2,11 @@ - - - - - - - - - - - + + - - Foo + + Foo @@ -25,25 +16,25 @@ - - + + - - - - - + + + + + - - - - - + + + + + Foo - + Bar diff --git a/widget/testdata/select/layout_multiple_placeholder.xml b/widget/testdata/select/layout_multiple_placeholder.xml index aacad31829..f1b414e935 100644 --- a/widget/testdata/select/layout_multiple_placeholder.xml +++ b/widget/testdata/select/layout_multiple_placeholder.xml @@ -2,20 +2,11 @@ - - - - - - - - - - - + + - - (Pick 1) + + (Pick 1) diff --git a/widget/testdata/select/layout_multiple_selected.xml b/widget/testdata/select/layout_multiple_selected.xml index 8691f989ab..72a04ca1f4 100644 --- a/widget/testdata/select/layout_multiple_selected.xml +++ b/widget/testdata/select/layout_multiple_selected.xml @@ -1,23 +1,14 @@ - - - - - - - - - - - - + + + - - Foo + + Foo - + diff --git a/widget/testdata/select/layout_multiple_selected_placeholder.xml b/widget/testdata/select/layout_multiple_selected_placeholder.xml index 909c32271c..9c2b23353d 100644 --- a/widget/testdata/select/layout_multiple_selected_placeholder.xml +++ b/widget/testdata/select/layout_multiple_selected_placeholder.xml @@ -2,20 +2,11 @@ - - - - - - - - - - - + + - - Foo + + Foo diff --git a/widget/testdata/select/layout_single.xml b/widget/testdata/select/layout_single.xml index 414751f351..9320cdcdd1 100644 --- a/widget/testdata/select/layout_single.xml +++ b/widget/testdata/select/layout_single.xml @@ -1,23 +1,14 @@ - - - - - - - - - - - - + + + - - (Select one) + + (Select one) - + diff --git a/widget/testdata/select/layout_single_expanded.xml b/widget/testdata/select/layout_single_expanded.xml index 025c54b336..97c554984d 100644 --- a/widget/testdata/select/layout_single_expanded.xml +++ b/widget/testdata/select/layout_single_expanded.xml @@ -1,23 +1,14 @@ - - - - - - - - - - + + + + + + (Select one) - - - - (Select one) - - + @@ -25,22 +16,22 @@ - - + + - - - - - + + + + + - - - - - + + + + + Test diff --git a/widget/testdata/select/layout_single_expanded_placeholder.xml b/widget/testdata/select/layout_single_expanded_placeholder.xml index 3e7a098ed6..9274065900 100644 --- a/widget/testdata/select/layout_single_expanded_placeholder.xml +++ b/widget/testdata/select/layout_single_expanded_placeholder.xml @@ -2,20 +2,11 @@ - - - - - - - - - - - + + - - (Pick 1) + + (Pick 1) @@ -25,22 +16,22 @@ - - + + - - - - - + + + + + - - - - - + + + + + Test diff --git a/widget/testdata/select/layout_single_expanded_selected.xml b/widget/testdata/select/layout_single_expanded_selected.xml index 3f6ceb82e6..0cb2f26efe 100644 --- a/widget/testdata/select/layout_single_expanded_selected.xml +++ b/widget/testdata/select/layout_single_expanded_selected.xml @@ -1,23 +1,14 @@ - - - - - - - - - - + + + + + + Test - - - - Test - - + @@ -25,22 +16,22 @@ - - + + - - - - - + + + + + - - - - - + + + + + Test diff --git a/widget/testdata/select/layout_single_expanded_selected_placeholder.xml b/widget/testdata/select/layout_single_expanded_selected_placeholder.xml index 7cf9f3b9fa..1b72dfac99 100644 --- a/widget/testdata/select/layout_single_expanded_selected_placeholder.xml +++ b/widget/testdata/select/layout_single_expanded_selected_placeholder.xml @@ -2,20 +2,11 @@ - - - - - - - - - - - + + - - Test + + Test @@ -25,22 +16,22 @@ - - + + - - - - - + + + + + - - - - - + + + + + Test diff --git a/widget/testdata/select/layout_single_placeholder.xml b/widget/testdata/select/layout_single_placeholder.xml index aacad31829..f1b414e935 100644 --- a/widget/testdata/select/layout_single_placeholder.xml +++ b/widget/testdata/select/layout_single_placeholder.xml @@ -2,20 +2,11 @@ - - - - - - - - - - - + + - - (Pick 1) + + (Pick 1) diff --git a/widget/testdata/select/layout_single_selected.xml b/widget/testdata/select/layout_single_selected.xml index 5eb52ba18d..c1a3dc4f68 100644 --- a/widget/testdata/select/layout_single_selected.xml +++ b/widget/testdata/select/layout_single_selected.xml @@ -1,23 +1,14 @@ - - - - - - - - - - - - + + + - - Test + + Test - + diff --git a/widget/testdata/select/layout_single_selected_placeholder.xml b/widget/testdata/select/layout_single_selected_placeholder.xml index 756d4f8224..a1bcb9541a 100644 --- a/widget/testdata/select/layout_single_selected_placeholder.xml +++ b/widget/testdata/select/layout_single_selected_placeholder.xml @@ -2,20 +2,11 @@ - - - - - - - - - - - + + - - Test + + Test diff --git a/widget/testdata/select/move_initial.xml b/widget/testdata/select/move_initial.xml index cb5db77546..1ca1779418 100644 --- a/widget/testdata/select/move_initial.xml +++ b/widget/testdata/select/move_initial.xml @@ -1,22 +1,13 @@ - - - - - - - - - - - - + + + - - (Select one) + + (Select one) - + diff --git a/widget/testdata/select/move_moved.xml b/widget/testdata/select/move_moved.xml index 4b74693ac3..955b07dc79 100644 --- a/widget/testdata/select/move_moved.xml +++ b/widget/testdata/select/move_moved.xml @@ -1,47 +1,38 @@ - - - - - - - - - - + + + + + + (Select one) - - - - (Select one) - - + - - + + - - - - - + + + + + - - - - - + + + + + 1 - + 2 diff --git a/widget/testdata/select/move_tapped.xml b/widget/testdata/select/move_tapped.xml index c074f5b0c7..5aa1b65e46 100644 --- a/widget/testdata/select/move_tapped.xml +++ b/widget/testdata/select/move_tapped.xml @@ -1,47 +1,38 @@ - - - - - - - - - - + + + + + + (Select one) - - - - (Select one) - - + - - + + - - - - - + + + + + - - - - - + + + + + 1 - + 2 diff --git a/widget/testdata/select/set_selected_2nd_selected.xml b/widget/testdata/select/set_selected_2nd_selected.xml index 5f8e097a36..99b053c442 100644 --- a/widget/testdata/select/set_selected_2nd_selected.xml +++ b/widget/testdata/select/set_selected_2nd_selected.xml @@ -1,23 +1,14 @@ - - - - - - - - - - - - + + + - - 2 + + 2 - + diff --git a/widget/testdata/select/set_selected_none_selected.xml b/widget/testdata/select/set_selected_none_selected.xml index bf6b2dc5f4..bae3167608 100644 --- a/widget/testdata/select/set_selected_none_selected.xml +++ b/widget/testdata/select/set_selected_none_selected.xml @@ -1,23 +1,14 @@ - - - - - - - - - - - - + + + - - (Select one) + + (Select one) - + diff --git a/widget/testdata/select/tapped.xml b/widget/testdata/select/tapped.xml index bf2b7b8f59..e19977ac71 100644 --- a/widget/testdata/select/tapped.xml +++ b/widget/testdata/select/tapped.xml @@ -1,47 +1,38 @@ - - - - - - - - - - + + + + + + (Select one) - - - - (Select one) - - + - - + + - - - - - + + + + + - - - - - + + + + + 1 - + 2 diff --git a/widget/testdata/select/tapped_constrained.xml b/widget/testdata/select/tapped_constrained.xml index 804781eb3e..980cb7e652 100644 --- a/widget/testdata/select/tapped_constrained.xml +++ b/widget/testdata/select/tapped_constrained.xml @@ -1,47 +1,38 @@ - - - - - - - - - - + + + + + + (Select one) - - - - (Select one) - - + - - + + - - - - - + + + + + - - - - - + + + + + 1 - + 2 diff --git a/widget/testdata/select/theme_changed.png b/widget/testdata/select/theme_changed.png index d8f9166381..f0e8eb3780 100644 Binary files a/widget/testdata/select/theme_changed.png and b/widget/testdata/select/theme_changed.png differ diff --git a/widget/testdata/select/theme_initial.png b/widget/testdata/select/theme_initial.png index e5c313c38c..64b010994d 100644 Binary files a/widget/testdata/select/theme_initial.png and b/widget/testdata/select/theme_initial.png differ diff --git a/widget/testdata/select_entry/disableable_enabled_opened.xml b/widget/testdata/select_entry/disableable_enabled_opened.xml index d90e1ac636..7578659afd 100644 --- a/widget/testdata/select_entry/disableable_enabled_opened.xml +++ b/widget/testdata/select_entry/disableable_enabled_opened.xml @@ -22,28 +22,28 @@ - - + + - - - - - + + + + + - - - - - + + + + + A - + B - + C diff --git a/widget/testdata/select_entry/dropdown_B_opened.xml b/widget/testdata/select_entry/dropdown_B_opened.xml index 914d2bfa7b..fc71f31dbc 100644 --- a/widget/testdata/select_entry/dropdown_B_opened.xml +++ b/widget/testdata/select_entry/dropdown_B_opened.xml @@ -19,28 +19,28 @@ - - + + - - - - - + + + + + - - - - - + + + + + A - + B - + C diff --git a/widget/testdata/select_entry/dropdown_empty_opened.xml b/widget/testdata/select_entry/dropdown_empty_opened.xml index d90e1ac636..7578659afd 100644 --- a/widget/testdata/select_entry/dropdown_empty_opened.xml +++ b/widget/testdata/select_entry/dropdown_empty_opened.xml @@ -22,28 +22,28 @@ - - + + - - - - - + + + + + - - - - - + + + + + A - + B - + C diff --git a/widget/testdata/select_entry/dropdown_empty_opened_shrunk.xml b/widget/testdata/select_entry/dropdown_empty_opened_shrunk.xml index cd58e65b08..761b846ef2 100644 --- a/widget/testdata/select_entry/dropdown_empty_opened_shrunk.xml +++ b/widget/testdata/select_entry/dropdown_empty_opened_shrunk.xml @@ -22,28 +22,28 @@ - - + + - - - - - + + + + + - - - - - + + + + + A - + B - + C diff --git a/widget/testdata/select_entry/dropdown_empty_setopts.xml b/widget/testdata/select_entry/dropdown_empty_setopts.xml index 00df31a60b..7fe743aac4 100644 --- a/widget/testdata/select_entry/dropdown_empty_setopts.xml +++ b/widget/testdata/select_entry/dropdown_empty_setopts.xml @@ -22,28 +22,28 @@ - - + + - - - - - + + + + + - - - - - + + + + + 1 - + 2 - + 3 diff --git a/widget/testdata/tabcontainer/mobile/theme_default.png b/widget/testdata/tabcontainer/mobile/theme_default.png deleted file mode 100644 index a18a6bbe24..0000000000 Binary files a/widget/testdata/tabcontainer/mobile/theme_default.png and /dev/null differ diff --git a/widget/text.go b/widget/text.go index 36c70eba91..94e68192b8 100644 --- a/widget/text.go +++ b/widget/text.go @@ -5,11 +5,11 @@ import ( "strings" "unicode" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) const ( diff --git a/widget/text_benchmark_test.go b/widget/text_benchmark_test.go index f397e9cc30..f9b2a3b286 100644 --- a/widget/text_benchmark_test.go +++ b/widget/text_benchmark_test.go @@ -3,7 +3,7 @@ package widget import ( "testing" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) const loremIpsum = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque quis consectetur nisi. Suspendisse id interdum felis. Sed egestas eget tellus eu pharetra. Praesent pulvinar sed massa id placerat. Etiam sem libero, semper vitae consequat ut, volutpat id mi. Mauris volutpat pellentesque convallis. Curabitur rutrum venenatis orci nec ornare. Maecenas quis pellentesque neque. Aliquam consectetur dapibus nulla, id maximus odio ultrices ac. Sed luctus at felis sed faucibus. Cras leo augue, congue in velit ut, mattis rhoncus lectus. diff --git a/widget/text_test.go b/widget/text_test.go index 3d414d3c99..3d2a1550e4 100644 --- a/widget/text_test.go +++ b/widget/text_test.go @@ -4,10 +4,10 @@ import ( "image/color" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/test" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/test" "github.com/stretchr/testify/assert" ) diff --git a/widget/textgrid.go b/widget/textgrid.go index 3641a8edcc..3788ee775f 100644 --- a/widget/textgrid.go +++ b/widget/textgrid.go @@ -6,9 +6,9 @@ import ( "math" "strings" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/theme" ) const ( diff --git a/widget/textgrid_test.go b/widget/textgrid_test.go index 65165cdc4d..63aa74839a 100644 --- a/widget/textgrid_test.go +++ b/widget/textgrid_test.go @@ -5,10 +5,10 @@ import ( "strings" "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/widget/toolbar.go b/widget/toolbar.go index 6dfed7c313..799ed10860 100644 --- a/widget/toolbar.go +++ b/widget/toolbar.go @@ -1,11 +1,11 @@ package widget import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/layout" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" ) // ToolbarItem represents any interface element that can be added to a toolbar diff --git a/widget/toolbar_test.go b/widget/toolbar_test.go index ccf7a7bd51..846db36e6e 100644 --- a/widget/toolbar_test.go +++ b/widget/toolbar_test.go @@ -3,9 +3,9 @@ package widget import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/widget/tree.go b/widget/tree.go index 67653e24fa..1dc634869c 100644 --- a/widget/tree.go +++ b/widget/tree.go @@ -1,12 +1,12 @@ package widget import ( - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/internal/widget" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/internal/widget" + "fyne.io/fyne/v2/theme" ) // TreeNodeID represents the unique id of a tree node. diff --git a/widget/tree_internal_test.go b/widget/tree_internal_test.go index ca0ff4fd42..94f8bdd320 100644 --- a/widget/tree_internal_test.go +++ b/widget/tree_internal_test.go @@ -5,11 +5,11 @@ import ( "testing" "time" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" ) diff --git a/widget/tree_test.go b/widget/tree_test.go index 44225d1cd7..56bc075a40 100644 --- a/widget/tree_test.go +++ b/widget/tree_test.go @@ -4,10 +4,10 @@ import ( "testing" "time" - "fyne.io/fyne" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/widget/widget.go b/widget/widget.go index f99489cc11..9f5be26db3 100644 --- a/widget/widget.go +++ b/widget/widget.go @@ -1,14 +1,14 @@ // Package widget defines the UI widgets within the Fyne toolkit -package widget // import "fyne.io/fyne/widget" +package widget // import "fyne.io/fyne/v2/widget" import ( "image/color" "sync" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/theme" ) // BaseWidget provides a helper that handles basic widget behaviours. diff --git a/widget/widget_test.go b/widget/widget_test.go index e792ab1f18..602bd9ca74 100644 --- a/widget/widget_test.go +++ b/widget/widget_test.go @@ -4,10 +4,10 @@ import ( "testing" "time" - "fyne.io/fyne" - "fyne.io/fyne/layout" - "fyne.io/fyne/test" - "fyne.io/fyne/theme" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/test" + "fyne.io/fyne/v2/theme" "github.com/stretchr/testify/assert" )