From 92fdc05a9b07aecf72a006ccc67059d2d040841a Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 17 Dec 2020 15:14:10 -0500 Subject: [PATCH 001/145] move Child, Exists, and Destroy into URI interface The underlying work to provide implementations of these methods has not been done yet pending discussion, so this will break the build. This also adds Destroy() as described in #1509, though again no implementation is defined yet. This also adds detailed comments to the members of the URI interface, to make it clear what is expected of URI implementations. --- storage/uri.go | 6 ++++ uri.go | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/storage/uri.go b/storage/uri.go index 61b06262c6..83fd2954f2 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -123,6 +123,8 @@ func parentGeneric(location string) (string, error) { // removing the last item. // // Since: 1.4 +// +// Deprecated: Parent() is a member of the URI interface now. func Parent(u fyne.URI) (fyne.URI, error) { s := u.String() @@ -166,6 +168,8 @@ func Parent(u fyne.URI) (fyne.URI, error) { // Child appends a new path element to a URI, separated by a '/' character. // // Since: 1.4 +// +// Deprecated: Child is now a member of the URI interface. 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 @@ -187,6 +191,8 @@ func Child(u fyne.URI, component string) (fyne.URI, error) { // return. // // Since: 1.4 +// +// Deprecated: Exists is now a member of the URI interface 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()) diff --git a/uri.go b/uri.go index 5343aec0f3..36aa10cdb8 100644 --- a/uri.go +++ b/uri.go @@ -27,10 +27,108 @@ type URIWriteCloser interface { // This resource may be a file or another data source such as an app or file sharing system. 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 no 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. For example, + // the Scheme() of 'file://foo/bar.baz` is 'file'. Scheme() string + + // Parent should return 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'. + // + // NOTE: it is not required that the implementation 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. + // + // NOTE: To the extent possible, Parent() should not modify, create, + // or interact with referenced resources. For example, it should + // usually be possible to use Parent() to create a reference to + // a resource which does not exist, though future operations on this + // resource may fail. + Parent() (URI, error) + + // Child should return 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. + // + // NOTE: To the extent possible, Child() should not modify, create, + // or interact with referenced resources. For example, it should + // usually be possible to use Child() to create a reference to + // a resource which does not exist, though future operations on this + // resource may fail. + Child(URI, string) (URI, error) + + // Exists should determine 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. + // + // In the event that an error occurs, implementations of Exists() must + // return false along with the 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. + Exists(URI) (bool, error) + + // Destroy should destroy, delete, or otherwise remove 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. + Destroy(URI) error } // ListableURI represents a URI that can have child items, most commonly a From e904cf81421d6f7f6a6131a83fca1c279b08cf4f Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 17 Dec 2020 15:17:32 -0500 Subject: [PATCH 002/145] add Since: comments --- uri.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/uri.go b/uri.go index 36aa10cdb8..4de7ae3d71 100644 --- a/uri.go +++ b/uri.go @@ -75,6 +75,8 @@ type URI interface { // usually be possible to use Parent() to create a reference to // a resource which does not exist, though future operations on this // resource may fail. + // + // Since: 2.0 Parent() (URI, error) // Child should return a URI referencing a resource nested @@ -99,6 +101,8 @@ type URI interface { // usually be possible to use Child() to create a reference to // a resource which does not exist, though future operations on this // resource may fail. + // + // Since: 2.0 Child(URI, string) (URI, error) // Exists should determine if the resource referenced by the URI @@ -115,6 +119,8 @@ type URI interface { // return false along with the 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. + // + // Since: 2.0 Exists(URI) (bool, error) // Destroy should destroy, delete, or otherwise remove the resource @@ -128,6 +134,8 @@ type URI interface { // // * If the referenced resource does not exist, attempting to destroy // it should throw an error. + // + // Since: 2.0 Destroy(URI) error } From adf04ad32e6baae8b7c0048b7517d1edd8317354 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Mon, 4 Jan 2021 12:27:52 -0500 Subject: [PATCH 003/145] add storage/rfc3986 This will be immediately reverted, but if we decide to revive it for some reason, it might be a good starting point. I started writing this and then realized Go already has an RFC3986 implementation here: https://golang.org/pkg/net/url/ I plan to use that unless there is some reason to build out or own instead. --- storage/rfc3986/parser.go | 11 +++++++ storage/rfc3986/rfc3986.go | 61 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 storage/rfc3986/parser.go create mode 100644 storage/rfc3986/rfc3986.go diff --git a/storage/rfc3986/parser.go b/storage/rfc3986/parser.go new file mode 100644 index 0000000000..59cd7ec6a6 --- /dev/null +++ b/storage/rfc3986/parser.go @@ -0,0 +1,11 @@ +package rfc3986 + +const ( + state_scheme = iota +) + +type parserState struct { + index int + text string + state int +} diff --git a/storage/rfc3986/rfc3986.go b/storage/rfc3986/rfc3986.go new file mode 100644 index 0000000000..e36c887dc9 --- /dev/null +++ b/storage/rfc3986/rfc3986.go @@ -0,0 +1,61 @@ +// package rfc3986 implements a representation of a URI as defined by IETF +// RFC3986 ( https://tools.ietf.org/html/rfc3986 ). In general, Fyne programs +// should not need to use this package directly; it is used internally by the +// storage package which for the Fyne URI type. This package is exported for +// two reasons: +// +// * Other projects may wish to use this library to implement RFC3986 parsing +// without depending on the rest of Fyne. +// +// * Implementers of storage repositories may wish to interact with raw URIs +// directly. +package rfc3986 + +import ( + "fmt" +) + +// RFC3986 implements a representation of an IEEE3986 URI. +// +// Note that Fyne programs should generally not use this directly, you almost +// certainly want storage/URI. +type RFC3986 struct { + scheme string + authority string + path string + query string + fragment string +} + +func (r *RFC3986) String() string { + + // the scheme is separated from the remainder of the URI components + // using either a ':' or '://' depending on whether or not the + // authority is present (RFC3986, pp. 16). + schemesep := ":" + if r.authority == "" { + schemesep = "://" + } + + // If a query is present, is is separated by a '?' character (RFC3986, + // pp. 16). + querysep := "" + if r.query != "" { + querysep = "?" + } + + // If a fragment is present, it is separated by a '#' character + // (RFC3986, pp. 16). + fragmentsep := "" + if r.fragment != "" { + fragmentsep = "#" + } + + return fmt.Sprintf("%s%s%s%s%s%s%s%s", r.scheme, schemesep, r.authority, r.path, querysep, r.query, fragmentsep, r.fragment) +} + +// ParseRFC3986 attempts to parse a text string into an RFC3986 complaint +// URI. It may return a nil pointer and an error if the text is invalid. +func ParseRFC3986(text string) (*RFC3986, error) { + +} From 101763312a8b93404f086338203f20652ee69bfe Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Mon, 4 Jan 2021 12:28:56 -0500 Subject: [PATCH 004/145] Revert "add storage/rfc3986" This reverts commit adf04ad32e6baae8b7c0048b7517d1edd8317354. --- storage/rfc3986/parser.go | 11 ------- storage/rfc3986/rfc3986.go | 61 -------------------------------------- 2 files changed, 72 deletions(-) delete mode 100644 storage/rfc3986/parser.go delete mode 100644 storage/rfc3986/rfc3986.go diff --git a/storage/rfc3986/parser.go b/storage/rfc3986/parser.go deleted file mode 100644 index 59cd7ec6a6..0000000000 --- a/storage/rfc3986/parser.go +++ /dev/null @@ -1,11 +0,0 @@ -package rfc3986 - -const ( - state_scheme = iota -) - -type parserState struct { - index int - text string - state int -} diff --git a/storage/rfc3986/rfc3986.go b/storage/rfc3986/rfc3986.go deleted file mode 100644 index e36c887dc9..0000000000 --- a/storage/rfc3986/rfc3986.go +++ /dev/null @@ -1,61 +0,0 @@ -// package rfc3986 implements a representation of a URI as defined by IETF -// RFC3986 ( https://tools.ietf.org/html/rfc3986 ). In general, Fyne programs -// should not need to use this package directly; it is used internally by the -// storage package which for the Fyne URI type. This package is exported for -// two reasons: -// -// * Other projects may wish to use this library to implement RFC3986 parsing -// without depending on the rest of Fyne. -// -// * Implementers of storage repositories may wish to interact with raw URIs -// directly. -package rfc3986 - -import ( - "fmt" -) - -// RFC3986 implements a representation of an IEEE3986 URI. -// -// Note that Fyne programs should generally not use this directly, you almost -// certainly want storage/URI. -type RFC3986 struct { - scheme string - authority string - path string - query string - fragment string -} - -func (r *RFC3986) String() string { - - // the scheme is separated from the remainder of the URI components - // using either a ':' or '://' depending on whether or not the - // authority is present (RFC3986, pp. 16). - schemesep := ":" - if r.authority == "" { - schemesep = "://" - } - - // If a query is present, is is separated by a '?' character (RFC3986, - // pp. 16). - querysep := "" - if r.query != "" { - querysep = "?" - } - - // If a fragment is present, it is separated by a '#' character - // (RFC3986, pp. 16). - fragmentsep := "" - if r.fragment != "" { - fragmentsep = "#" - } - - return fmt.Sprintf("%s%s%s%s%s%s%s%s", r.scheme, schemesep, r.authority, r.path, querysep, r.query, fragmentsep, r.fragment) -} - -// ParseRFC3986 attempts to parse a text string into an RFC3986 complaint -// URI. It may return a nil pointer and an error if the text is invalid. -func ParseRFC3986(text string) (*RFC3986, error) { - -} From c363bbc4b4120caa054f948dff88f545fdae30fd Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Tue, 5 Jan 2021 16:10:55 -0500 Subject: [PATCH 005/145] first pass at Repository interface In retrospect, there is a lot of redundancy In the prose of the given implementation. I will do a second pass to tidy it up at some point. --- storage/repository.go | 328 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 storage/repository.go diff --git a/storage/repository.go b/storage/repository.go new file mode 100644 index 0000000000..c019cc9ff4 --- /dev/null +++ b/storage/repository.go @@ -0,0 +1,328 @@ +package storage + +// 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. +// +// Some repositories may choose not to implement some functions; in such cases, +// they should simply return nil for un-implemented functions. +// +// Repository methods which return (func ..., bool) can use the bool flag to +// indicate if they would like to use a default/generic implementation of the +// relevant method (by returning a true value), or if the operations is not +// supported by the type of information the URI works with (a false value). +// +// Repository methods which only return a func will always use a +// default/generic implementation if the repository does not provide one (e.g. +// returns nil). These operations must be supported by all URIs. +// +// To the extent possible, Repository interfaces should attempt to use these +// methods as a surface area for optimization. For example, a repository for +// accessing ssh:// URIs might perform copy operations on the remote end, +// rather than reading all the content to the local side and then writing +// it back over the wire. +type Repository interface { + + // ParseURIImpl returns a method that given a text string creates a + // new URI instance. This may cause an error, for example if the string + // is an invalid URI or contains information that is invalid in the + // context of the repository's scheme. + // + // This method will be called only after the URI scheme has been + // verified to match the one the repository was registered to handle, + // however the URI is not validated further than this. It is required + // by convention (but not enforced by technical means) that the + // returned function should throw an error if the string is not a valid + // IETF RFC 3986 complaint URI. Fail to validate this at your own risk. + // + // NOTE: it is highly recommended to use net/url ( + // https://golang.org/pkg/net/url/ ) for parsing URI strings unless you + // have a good reason not to. It is mature and implements RFC 3986. + // + // If no implementation is provided, a generic URI based on RFC3986 is + // parsed without any special validation logic. + ParseURIImpl() func(string) (URI, error) + + // ExtensionImpl returns a method that given a URI matching the + // scheme this repository is registered to handle, will return the + // file extension for the URI. + // + // If no implementation is provided, then a generic one will be used, + // which will string split on instances of the '.' character, and the + // final such component will be returned. + ExtensionImpl() func(URI) string + + // NameImpl returns a method that given a URI matching the scheme + // this repository is registered to handle, will return the + // referenced base name of the URI. For example, the base name of + // 'file://foo/bar/baz.txt' is 'baz.txt'. + // + // If no implementation is provided, a generic one will be used. The + // generic implementation will string-split the path component of the + // URI on instances of the '/' character, and return the final such + // component. + NameImpl() func(URI) string + + // MimeTypeImpl returns a method that given a URI matching the + // scheme this repository is registered to handle, will return the + // MIME type of the resource the URI references. + // + // If no implementation is provided, a generic one will be used which + // simply returns `application/octet-stream`, which is appropriate for + // use when the MIME type is otherwise unknown per IETF RFC2046, pp. + // 12. + MimeTypeImpl() func(URI) (string, error) + + // ParentImpl returns a method that given a URI 'X' matching the + // scheme this repository is registered to handle, will return a new + // URI 'Y' such that the resource referenced by 'Y' is a parent of the + // resource referenced by 'X'. For example, the parent for + // 'file://foo/bar' is 'file://foo'. + // + // The provided Parent implementation may fail in several ways: + // + // * Determining the parent requires a hardware, network, or OS + // operation which has failed for some reason. + // + // * Determining the parent requires an operation for which different + // permissions or credentials are required. + // + // * The repository can determine the parent of certain URIs of the + // relevant scheme, but not others. + // + // * 'X' references the root of the hierarchy of resources this URI + // scheme can reference (e.g. the root directory of a UNIX + // filesystem). NOTE: in such cases, the implementation MUST return a + // URIRootError. This is especially important, as some routines which + // traverse a hierarchy of referenced resources use this to determine + // when to stop iterating. + // + // If the boolean return value is 'false', then any attempt to + // determine the parent of URIs with the scheme this repository is + // registered to handle with an error indicating the operation is not + // supported. + // + // If the boolean return value is 'true' and the returned method is + // nil, then a generic implementation will be used instead, which + // discards the query and fragment components of the URI, string splits + // the path on '/' characters to remove the final component, then uses + // this repository's URI parsing implementation to parse the result + // into a new URI, which is used as the parent. + // + ParentImpl() (func(URI) (URI, error), bool) + + // ReaderFromImpl returns a method which given a URI matching the + // scheme that this repository is registered to handle, will return a + // URIReadCloser set up to read from the resource that the URI + // references. + // + // The returned method may 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. + // + // If this method is not implemented (e.g. a nil function is returned), + // then any attempt to get a reader for a URI with the scheme this + // repository is meant to handle will fail with an 'not supported' + // error. + ReaderFromImpl() func(URI) (URIReadCloser, error) + + // WriterFromImpl returns a method which given a URI matching the + // scheme that this repository is registered to handle, will return a + // URIWriteCloser set up to write to the resource that the URI + // references. + // + // The returned method may 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 this method is not implemented (e.g. a nil function is returned), + // then any attempt to get a writer for a URI with the scheme this + // repository is meant to handle will fail with an 'not supported' + // error. + WriterToImpl() func(URI) (URIWriteCloser, error) + + // CopyImpl returns a method that given two URIs, 'src', and 'dest' + // both of the scheme this repository is registered to handle, will + // copy one to the other. + // + // The returned 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 this method is not implemented (e.g. a nil function is returned), + // and a "false" value is returned by the boolean return value, then + // any attempt to perform a copy operation for a URI with the scheme + // this repository is meant to handle will fail with a 'not supported' + // error. If a "true" value is returned by the boolean return value, a + // default implementation will be used which creates a new URI for the + // destination, reads from the source, and writes to the destination. + // + // NOTE: a generic implementation which can work for URIs of different + // schemes is provided via storage.Duplicate(). + CopyImpl() (func(URI, URI) error, bool) + + // RenameImpl returns a method that given two URIs, 'src' and 'dest' + // both of the scheme this repository is registered to handle, will + // rename 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. + // + // The returned 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 this method is not implemented (e.g. a nil function is returned), + // and a "false" value is returned by the boolean return value, then + // any attempt to perform a rename operation for a URI with the scheme + // this repository is meant to handle will fail with a 'not supported' + // error. If a "true" value is returned by the boolean return value, a + // default implementation will be used which uses this repository's + // copy implementation, and then deletes the source. + // + // NOTE: a generic implementation which can work for URIs of different + // schemes is provided via storage.Move(). + RenameImpl() (func(URI, URI) error, bool) + + // DeleteImpl returns a method that given a URI of the scheme this + // repository is registered to handle. This method should cause the + // resource referenced by the URI To be destroyed, removed, or + // otherwise deleted. + // + // The returned method may fail in several ways: + // + // * Different permissions or credentials are required to perform the + // delete operation. + // + // * This URI scheme could represent some resources that can be + // deleted, but this specific URI is not one of them. + // + // * Performing the delete operation depended on a lower level operation + // such as network or filesystem access that has failed in some way. + // + // If this method is not implemented (e.g. a nil function is returned), + // then any attempt to perform a delete operation on a URI with the + // scheme that this repository is registered to handle will + // fail with a 'not supported' error. + DeleteImpl() func(URI) error + + // ListableImpl returns a method that given a URI of the scheme this + // repository is registered to handle, will determine if it is listable + // or not. + // + // NOTE: If ListeImpl() is not implemented in this repository, then + // attempts to check the listability of URIs of the scheme it is + // registered to handle will fail, even if ListableImpl() is + // implemented. + // + // The returned 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 this method is not implemented (e.g. a nil function is returned), + // then any attempt to check if the URI is listable will fail with a + // 'not supported' error. This implies that no URI of the scheme that + // this repository is registered to handle could ever be listable. + ListableImpl() func(URI) (bool, error) + + // ListImpl returns a method that given a URI of the scheme that this + // repository is registered to handle, will return 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. + // + // NOTE: If ListableImpl() is not implemented in this repository, + // then attempts to list URIs of the scheme it is registered to handle + // will fail, even if ListImpl() is implemented. + // + // The returned 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). + // + // * Obtaining the listing depended on a lower level operation such as + // network or filesystem access that has failed in some way. + // + // If this method is not implemented (e.g. a nil function is returned), + // then any attempt to list a URI of the scheme this repository is + // registered to handle will fail with a 'not supported' error. + ListImpl() func(URI) ([]URI, error) + + // ChildImpl returns a method that given a URI of the scheme + // that this repository is registered to handle, create a new URI + // nested under it. For example, if the method is called on the URI + // file://foo/bar with the string argument 'baz.txt', then the + // URI returned would be 'file:.//foo/bar/baz.txt'. + // + // The returned method may fail in several ways: + // + // * Different permissions or credentials are required to create a + // child of the given URI. + // + // * This URI scheme could represent some resources that can be have + // children, but this specific URI is not one of them (e.g. a file on + // a filesystem, as opposed to a directory). + // + // * Creating the child depended on a lower level operation such as + // network or filesystem access that has failed in some way. + // + // NOTE: the fact that a child can be created for a given URI implies + // that the URI must be listable. If your repository is implemented + // inconsistently with this, things may break in unexpected ways. + // + // If this method is not implemented and a boolean return value of + // 'true' is given, then a default implementation will be used that + // calls the given ParseURI implementation with the string appended to + // the URI path component, separated by a '/' character. If 'false' is + // given, then attempts to create children for any URI of the scheme + // this repository is registered to handle will fail with a 'not + // supported' error. + ChildImpl() (func(URI, string) (URI, error), bool) +} From c764b375c0385ce44de26f0f426c192ec81f4ae1 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 7 Jan 2021 21:24:01 -0500 Subject: [PATCH 006/145] add stuarts suggestions --- storage/repository.go | 28 ++++++++++++++++++++++++++++ uri.go | 16 ++++++++-------- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/storage/repository.go b/storage/repository.go index c019cc9ff4..12f1d688d9 100644 --- a/storage/repository.go +++ b/storage/repository.go @@ -22,6 +22,8 @@ package storage // accessing ssh:// URIs might perform copy operations on the remote end, // rather than reading all the content to the local side and then writing // it back over the wire. +// +// Since: 2.0.0 type Repository interface { // ParseURIImpl returns a method that given a text string creates a @@ -42,6 +44,8 @@ type Repository interface { // // If no implementation is provided, a generic URI based on RFC3986 is // parsed without any special validation logic. + // + // Since 2.0.0 ParseURIImpl() func(string) (URI, error) // ExtensionImpl returns a method that given a URI matching the @@ -51,6 +55,8 @@ type Repository interface { // If no implementation is provided, then a generic one will be used, // which will string split on instances of the '.' character, and the // final such component will be returned. + // + // Since 2.0.0 ExtensionImpl() func(URI) string // NameImpl returns a method that given a URI matching the scheme @@ -62,6 +68,8 @@ type Repository interface { // generic implementation will string-split the path component of the // URI on instances of the '/' character, and return the final such // component. + // + // Since 2.0.0 NameImpl() func(URI) string // MimeTypeImpl returns a method that given a URI matching the @@ -72,6 +80,8 @@ type Repository interface { // simply returns `application/octet-stream`, which is appropriate for // use when the MIME type is otherwise unknown per IETF RFC2046, pp. // 12. + // + // Since 2.0.0 MimeTypeImpl() func(URI) (string, error) // ParentImpl returns a method that given a URI 'X' matching the @@ -110,6 +120,8 @@ type Repository interface { // this repository's URI parsing implementation to parse the result // into a new URI, which is used as the parent. // + // + // Since 2.0.0 ParentImpl() (func(URI) (URI, error), bool) // ReaderFromImpl returns a method which given a URI matching the @@ -134,6 +146,8 @@ type Repository interface { // then any attempt to get a reader for a URI with the scheme this // repository is meant to handle will fail with an 'not supported' // error. + // + // Since 2.0.0 ReaderFromImpl() func(URI) (URIReadCloser, error) // WriterFromImpl returns a method which given a URI matching the @@ -158,6 +172,8 @@ type Repository interface { // then any attempt to get a writer for a URI with the scheme this // repository is meant to handle will fail with an 'not supported' // error. + // + // Since 2.0.0 WriterToImpl() func(URI) (URIWriteCloser, error) // CopyImpl returns a method that given two URIs, 'src', and 'dest' @@ -186,6 +202,8 @@ type Repository interface { // // NOTE: a generic implementation which can work for URIs of different // schemes is provided via storage.Duplicate(). + // + // Since 2.0.0 CopyImpl() (func(URI, URI) error, bool) // RenameImpl returns a method that given two URIs, 'src' and 'dest' @@ -217,6 +235,8 @@ type Repository interface { // // NOTE: a generic implementation which can work for URIs of different // schemes is provided via storage.Move(). + // + // Since 2.0.0 RenameImpl() (func(URI, URI) error, bool) // DeleteImpl returns a method that given a URI of the scheme this @@ -239,6 +259,8 @@ type Repository interface { // then any attempt to perform a delete operation on a URI with the // scheme that this repository is registered to handle will // fail with a 'not supported' error. + // + // Since 2.0.0 DeleteImpl() func(URI) error // ListableImpl returns a method that given a URI of the scheme this @@ -266,6 +288,8 @@ type Repository interface { // then any attempt to check if the URI is listable will fail with a // 'not supported' error. This implies that no URI of the scheme that // this repository is registered to handle could ever be listable. + // + // Since 2.0.0 ListableImpl() func(URI) (bool, error) // ListImpl returns a method that given a URI of the scheme that this @@ -293,6 +317,8 @@ type Repository interface { // If this method is not implemented (e.g. a nil function is returned), // then any attempt to list a URI of the scheme this repository is // registered to handle will fail with a 'not supported' error. + // + // Since 2.0.0 ListImpl() func(URI) ([]URI, error) // ChildImpl returns a method that given a URI of the scheme @@ -324,5 +350,7 @@ type Repository interface { // given, then attempts to create children for any URI of the scheme // this repository is registered to handle will fail with a 'not // supported' error. + // + // Since 2.0.0 ChildImpl() (func(URI, string) (URI, error), bool) } diff --git a/uri.go b/uri.go index 4de7ae3d71..a8cf0dbdab 100644 --- a/uri.go +++ b/uri.go @@ -30,7 +30,7 @@ type URI interface { // 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 no the + // 'file://foo/bar.baz' is 'baz'. May return an empty string if the // referenced resource has none. Extension() string @@ -40,15 +40,15 @@ type URI interface { // 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"). + // by Section 5 of RFC2045 ("Content-Type Header Field"). MimeType() string // Scheme should return the URI scheme of the URI. For example, // the Scheme() of 'file://foo/bar.baz` is 'file'. Scheme() string - // Parent should return a URI referencing the parent resource of the - // resource referenced by the URI. For example, the Parent() of + // Parent should return a ListableURI referencing the parent resource + // of the resource referenced by the URI. For example, the Parent() of // 'file://foo/bar.baz' is 'file://foo'. // // NOTE: it is not required that the implementation return a parent URI @@ -76,7 +76,7 @@ type URI interface { // a resource which does not exist, though future operations on this // resource may fail. // - // Since: 2.0 + // Since: 2.0.0 Parent() (URI, error) // Child should return a URI referencing a resource nested @@ -102,7 +102,7 @@ type URI interface { // a resource which does not exist, though future operations on this // resource may fail. // - // Since: 2.0 + // Since: 2.0.0 Child(URI, string) (URI, error) // Exists should determine if the resource referenced by the URI @@ -120,7 +120,7 @@ type URI interface { // error value signals that the existence or non-existence of the // resource cannot be determined and is undefined. // - // Since: 2.0 + // Since: 2.0.0 Exists(URI) (bool, error) // Destroy should destroy, delete, or otherwise remove the resource @@ -135,7 +135,7 @@ type URI interface { // * If the referenced resource does not exist, attempting to destroy // it should throw an error. // - // Since: 2.0 + // Since: 2.0.0 Destroy(URI) error } From d6608cb2b7112caadf49974c2e4482b5a869a216 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 7 Jan 2021 21:33:11 -0500 Subject: [PATCH 007/145] remove functions from URI interface --- storage/uri.go | 87 +++++++++++++++++++++++++++++++++++++++------- uri.go | 94 ++------------------------------------------------ 2 files changed, 78 insertions(+), 103 deletions(-) diff --git a/storage/uri.go b/storage/uri.go index b998f97f28..1a87b27bc7 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -118,12 +118,35 @@ func parentGeneric(location string) (string, error) { return parent, nil } -// Parent gets the parent of a URI by splitting it along '/' separators and -// removing the last item. +// 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. // -// Since: 1.4 +// NOTE: it is not required that the implementation 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. +// +// NOTE: since 2.0.0, Parent() is backed by the repository system - this +// function may call into either a generic implementation, or into a +// scheme-specific implementation depending on which storage repositories have +// been registered. // -// Deprecated: Parent() is a member of the URI interface now. +// Since: 1.4 func Parent(u fyne.URI) (fyne.URI, error) { s := u.String() @@ -164,11 +187,28 @@ func Parent(u fyne.URI) (fyne.URI, error) { return NewURI(u.Scheme() + "://" + parent), nil } -// Child appends a new path element to a URI, separated by a '/' character. +// 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'. // -// Since: 1.4 +// 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. +// +// NOTE: since 2.0.0, Child() is backed by the repository system - this +// function may call into either a generic implementation, or into a +// scheme-specific implementation depending on which storage repositories have +// been registered. // -// Deprecated: Child is now a member of the URI interface. +// 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 @@ -185,13 +225,19 @@ func Child(u fyne.URI, component string) (fyne.URI, error) { return NewURI(s + component), nil } -// 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. +// Exists determines if the resource referenced by the URI exists. // -// Since: 1.4 +// 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. // -// Deprecated: Exists is now a member of the URI interface +// 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. +// +// 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()) @@ -208,3 +254,20 @@ func Exists(u fyne.URI) (bool, error) { return true, nil } + +// Destroy 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. +// +// Since: 2.0.0 +func Destroy(u fyne.URI) error { + return fmt.Errorf("TODO: implement this function") +} diff --git a/uri.go b/uri.go index a8cf0dbdab..2a913fe041 100644 --- a/uri.go +++ b/uri.go @@ -46,102 +46,14 @@ type URI interface { // Scheme should return the URI scheme of the URI. For example, // the Scheme() of 'file://foo/bar.baz` is 'file'. Scheme() string - - // Parent should return a ListableURI referencing the parent resource - // of the resource referenced by the URI. For example, the Parent() of - // 'file://foo/bar.baz' is 'file://foo'. - // - // NOTE: it is not required that the implementation 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. - // - // NOTE: To the extent possible, Parent() should not modify, create, - // or interact with referenced resources. For example, it should - // usually be possible to use Parent() to create a reference to - // a resource which does not exist, though future operations on this - // resource may fail. - // - // Since: 2.0.0 - Parent() (URI, error) - - // Child should return 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. - // - // NOTE: To the extent possible, Child() should not modify, create, - // or interact with referenced resources. For example, it should - // usually be possible to use Child() to create a reference to - // a resource which does not exist, though future operations on this - // resource may fail. - // - // Since: 2.0.0 - Child(URI, string) (URI, error) - - // Exists should determine 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. - // - // In the event that an error occurs, implementations of Exists() must - // return false along with the 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. - // - // Since: 2.0.0 - Exists(URI) (bool, error) - - // Destroy should destroy, delete, or otherwise remove 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. - // - // Since: 2.0.0 - Destroy(URI) error } // ListableURI represents a URI that can have child items, most commonly a // directory on disk in the native filesystem. // +// Deprecated: use the IsListable() and List() methods that operate on URI in +// the storage package instead. +// // Since: 1.4 type ListableURI interface { URI From a68a6b2a779cf5ef841faf9eee49f0ef49d8fe70 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 7 Jan 2021 21:41:54 -0500 Subject: [PATCH 008/145] add RFC3986 methods to the URI interface --- uri.go | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/uri.go b/uri.go index 2a913fe041..d221cc6742 100644 --- a/uri.go +++ b/uri.go @@ -23,8 +23,14 @@ type URIWriteCloser interface { 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 @@ -43,9 +49,36 @@ type URI interface { // by Section 5 of RFC2045 ("Content-Type Header Field"). MimeType() string - // Scheme should return the URI scheme of the URI. For example, - // the Scheme() of 'file://foo/bar.baz` is 'file'. + // 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() 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.0 + Authority() string + + // Path should return the URI path, as defined by IETF RFC3986. + // + // Since: 2.0.0 + Path() string + + // Query should return the URI query, as defined by IETF RFC3986. + // + // Since: 2.0.0 + Query() string + + // Fragment should return the URI fragment, as defined by IETF + // RFC3986. + // + // Since: 2.0.0 + Fragment() string } // ListableURI represents a URI that can have child items, most commonly a From a87a2058fdca184543e74f850df3395daf3699d1 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 7 Jan 2021 22:26:04 -0500 Subject: [PATCH 009/145] sketch proposed URI and Repository API changes Note that I have veered much more towards @toaster 's (Tilo) proposal than I had originally. My change of heart is documented in the relevant proposal here: https://github.com/fyne-io/fyne/wiki/Proposal%3A-The-Fyne-URI-Philosophy I have decided not to implement URINotListable on the basis that URIOperationImpossible already encompasses it's purpose, and additionally I want to encourage people to use Listable() rather than just trying to List() and then checking the error. I decided to move List and Listable() into the Repository interface, though developers can always throw URIOperatioNotSupported if they are impossible to implement. I could be convinced to move them into their own ListableRepository interface to be optionally registered, but to keep them together (since you cannot have one without the other). This was discussed a little bit, but I am on the fence. Since I decided to go with more of Tilo's approach, I did not add Move() or Duplicate(). If folks have opinions on using these names versus Rename() and Copy(), please add them on the PR. --- storage/repository.go | 398 +++++-------------- storage/uri.go | 180 ++++++++- storage/uri_operation_impossible.go | 16 + storage/uri_operation_not_supported_error.go | 17 + uri.go | 2 +- 5 files changed, 309 insertions(+), 304 deletions(-) create mode 100644 storage/uri_operation_impossible.go create mode 100644 storage/uri_operation_not_supported_error.go diff --git a/storage/repository.go b/storage/repository.go index 12f1d688d9..7506892082 100644 --- a/storage/repository.go +++ b/storage/repository.go @@ -1,32 +1,47 @@ package storage +import ( + "fyne.io/fyne" +) + // 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. // -// Some repositories may choose not to implement some functions; in such cases, -// they should simply return nil for un-implemented functions. +// 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. Some additional methods which can offer +// more optimization opportunities can also be implemented by calling the +// appropriate Register...() function inside of the Repository.Init() function. +// For example, storage.Copy() will by default use a reader and a writer to +// perform a copy operation, but a repository might use RegisterCopy() to cause +// a more optimal version to be used for URIs of the relevant scheme (e.g. by +// performing the copy on the remote side of an ssh connection). // -// Repository methods which return (func ..., bool) can use the bool flag to -// indicate if they would like to use a default/generic implementation of the -// relevant method (by returning a true value), or if the operations is not -// supported by the type of information the URI works with (a false value). +// In some cases, you may wish to omit an implementation of one of these +// functions anyway. In such cases, you should do this by returning a +// URIOperationNotSupportedError. For example, this may be appropriate when +// building a storage repository which represents only resources that are +// read-only - in such cases functions like WriterTo() may not make sense. +// Please use care when deciding to do this, and consider how it will impact +// users of your storage repository. // -// Repository methods which only return a func will always use a -// default/generic implementation if the repository does not provide one (e.g. -// returns nil). These operations must be supported by all URIs. +// 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. // -// To the extent possible, Repository interfaces should attempt to use these -// methods as a surface area for optimization. For example, a repository for -// accessing ssh:// URIs might perform copy operations on the remote end, -// rather than reading all the content to the local side and then writing -// it back over the wire. +// NOTE: functions in a particular repository can assume they will only ever be +// used on URIs which match the scheme that they have been registered to +// handle, however they should not assume that they will only be called on URIs +// of the same implementation as the ParseURI() for this repository has +// returned. // // Since: 2.0.0 type Repository interface { - // ParseURIImpl returns a method that given a text string creates a + // ParseURI returns a method that given a text string creates a // new URI instance. This may cause an error, for example if the string // is an invalid URI or contains information that is invalid in the // context of the repository's scheme. @@ -34,9 +49,9 @@ type Repository interface { // This method will be called only after the URI scheme has been // verified to match the one the repository was registered to handle, // however the URI is not validated further than this. It is required - // by convention (but not enforced by technical means) that the - // returned function should throw an error if the string is not a valid - // IETF RFC 3986 complaint URI. Fail to validate this at your own risk. + // by convention (but not enforced by technical means) that this + // function should throw an error if the string is not a valid IETF RFC + // 3986 complaint URI. Fail to validate this at your own risk. // // NOTE: it is highly recommended to use net/url ( // https://golang.org/pkg/net/url/ ) for parsing URI strings unless you @@ -46,311 +61,92 @@ type Repository interface { // parsed without any special validation logic. // // Since 2.0.0 - ParseURIImpl() func(string) (URI, error) + ParseURI() func(string) (fyne.URI, error) - // ExtensionImpl returns a method that given a URI matching the - // scheme this repository is registered to handle, will return the - // file extension for the URI. - // - // If no implementation is provided, then a generic one will be used, - // which will string split on instances of the '.' character, and the - // final such component will be returned. + // Init will be called while the repository is being registered. This + // is the appropriate place to register any optional handlers relevant + // to a particular URI scheme. // // Since 2.0.0 - ExtensionImpl() func(URI) string + Init() func() error - // NameImpl returns a method that given a URI matching the scheme - // this repository is registered to handle, will return the - // referenced base name of the URI. For example, the base name of - // 'file://foo/bar/baz.txt' is 'baz.txt'. - // - // If no implementation is provided, a generic one will be used. The - // generic implementation will string-split the path component of the - // URI on instances of the '/' character, and return the final such - // component. + // Exists will be used to implement calls to storage.Exists() for the + // registered scheme of this repository. // // Since 2.0.0 - NameImpl() func(URI) string + Exists(u fyne.URI) (bool, error) - // MimeTypeImpl returns a method that given a URI matching the - // scheme this repository is registered to handle, will return the - // MIME type of the resource the URI references. - // - // If no implementation is provided, a generic one will be used which - // simply returns `application/octet-stream`, which is appropriate for - // use when the MIME type is otherwise unknown per IETF RFC2046, pp. - // 12. + // Delete will be used to implement calls to storage.Delete() for the + // registered scheme of this repository. // // Since 2.0.0 - MimeTypeImpl() func(URI) (string, error) + Delete(u fyne.URI) error - // ParentImpl returns a method that given a URI 'X' matching the - // scheme this repository is registered to handle, will return a new - // URI 'Y' such that the resource referenced by 'Y' is a parent of the - // resource referenced by 'X'. For example, the parent for - // 'file://foo/bar' is 'file://foo'. - // - // The provided Parent implementation may fail in several ways: - // - // * Determining the parent requires a hardware, network, or OS - // operation which has failed for some reason. - // - // * Determining the parent requires an operation for which different - // permissions or credentials are required. - // - // * The repository can determine the parent of certain URIs of the - // relevant scheme, but not others. - // - // * 'X' references the root of the hierarchy of resources this URI - // scheme can reference (e.g. the root directory of a UNIX - // filesystem). NOTE: in such cases, the implementation MUST return a - // URIRootError. This is especially important, as some routines which - // traverse a hierarchy of referenced resources use this to determine - // when to stop iterating. - // - // If the boolean return value is 'false', then any attempt to - // determine the parent of URIs with the scheme this repository is - // registered to handle with an error indicating the operation is not - // supported. - // - // If the boolean return value is 'true' and the returned method is - // nil, then a generic implementation will be used instead, which - // discards the query and fragment components of the URI, string splits - // the path on '/' characters to remove the final component, then uses - // this repository's URI parsing implementation to parse the result - // into a new URI, which is used as the parent. - // + // ReaderFrom will be used to implement calls to storage.ReaderFrom() + // for the registered scheme of this repository. // // Since 2.0.0 - ParentImpl() (func(URI) (URI, error), bool) + ReaderFrom(u fyne.URI) (fyne.URIReadCloser, error) - // ReaderFromImpl returns a method which given a URI matching the - // scheme that this repository is registered to handle, will return a - // URIReadCloser set up to read from the resource that the URI - // references. - // - // The returned method may 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. - // - // If this method is not implemented (e.g. a nil function is returned), - // then any attempt to get a reader for a URI with the scheme this - // repository is meant to handle will fail with an 'not supported' - // error. + // WriterTo will be used to implement calls to storage.WriterTo() for + // the registered scheme of this repository. // // Since 2.0.0 - ReaderFromImpl() func(URI) (URIReadCloser, error) + WriterTo(u fyne.URI) (fyne.URIWriteCloser, error) - // WriterFromImpl returns a method which given a URI matching the - // scheme that this repository is registered to handle, will return a - // URIWriteCloser set up to write to the resource that the URI - // references. - // - // The returned method may 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 this method is not implemented (e.g. a nil function is returned), - // then any attempt to get a writer for a URI with the scheme this - // repository is meant to handle will fail with an 'not supported' - // error. + // Listable will be used to implement calls to storage.Listable() for + // the registered scheme of this repository. // // Since 2.0.0 - WriterToImpl() func(URI) (URIWriteCloser, error) + Listable(u fyne.URI) (bool, error) - // CopyImpl returns a method that given two URIs, 'src', and 'dest' - // both of the scheme this repository is registered to handle, will - // copy one to the other. - // - // The returned 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 this method is not implemented (e.g. a nil function is returned), - // and a "false" value is returned by the boolean return value, then - // any attempt to perform a copy operation for a URI with the scheme - // this repository is meant to handle will fail with a 'not supported' - // error. If a "true" value is returned by the boolean return value, a - // default implementation will be used which creates a new URI for the - // destination, reads from the source, and writes to the destination. - // - // NOTE: a generic implementation which can work for URIs of different - // schemes is provided via storage.Duplicate(). + // List will be used to implement calls to storage.List() for the + // registered scheme of this repository. // // Since 2.0.0 - CopyImpl() (func(URI, URI) error, bool) - - // RenameImpl returns a method that given two URIs, 'src' and 'dest' - // both of the scheme this repository is registered to handle, will - // rename 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. - // - // The returned 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 this method is not implemented (e.g. a nil function is returned), - // and a "false" value is returned by the boolean return value, then - // any attempt to perform a rename operation for a URI with the scheme - // this repository is meant to handle will fail with a 'not supported' - // error. If a "true" value is returned by the boolean return value, a - // default implementation will be used which uses this repository's - // copy implementation, and then deletes the source. - // - // NOTE: a generic implementation which can work for URIs of different - // schemes is provided via storage.Move(). - // - // Since 2.0.0 - RenameImpl() (func(URI, URI) error, bool) - - // DeleteImpl returns a method that given a URI of the scheme this - // repository is registered to handle. This method should cause the - // resource referenced by the URI To be destroyed, removed, or - // otherwise deleted. - // - // The returned method may fail in several ways: - // - // * Different permissions or credentials are required to perform the - // delete operation. - // - // * This URI scheme could represent some resources that can be - // deleted, but this specific URI is not one of them. - // - // * Performing the delete operation depended on a lower level operation - // such as network or filesystem access that has failed in some way. - // - // If this method is not implemented (e.g. a nil function is returned), - // then any attempt to perform a delete operation on a URI with the - // scheme that this repository is registered to handle will - // fail with a 'not supported' error. - // - // Since 2.0.0 - DeleteImpl() func(URI) error + List(u fyne.URI) ([]URI, error) +} - // ListableImpl returns a method that given a URI of the scheme this - // repository is registered to handle, will determine if it is listable - // or not. - // - // NOTE: If ListeImpl() is not implemented in this repository, then - // attempts to check the listability of URIs of the scheme it is - // registered to handle will fail, even if ListableImpl() is - // implemented. - // - // The returned 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 this method is not implemented (e.g. a nil function is returned), - // then any attempt to check if the URI is listable will fail with a - // 'not supported' error. This implies that no URI of the scheme that - // this repository is registered to handle could ever be listable. - // - // Since 2.0.0 - ListableImpl() func(URI) (bool, error) +// RegisterCopy registers an implementation of a Copy() function for a specific +// URI scheme. This function should only be called in Repository.Init(). If +// the scheme does not have a registered repository, then this function will +// fail with an error. If a Copy implementation is already registered for this +// scheme, it will be replaced with this one silently. +// +// If no Copy implementation is registered for a particular scheme, then copies +// will be implemented as if the URIs were of different types, that is the +// source URI will be read using ReaderFrom(), and the destination written +// using WriterTo(). This function is an opportunity to implement a more +// optimal approach, such as leveraging remote operations for a network-backed +// repository. +// +// Since 2.0.0 +func RegisterCopy(scheme string, copyImplementation func(fyne.URI, fyne.URI) error) error { + // TODO +} - // ListImpl returns a method that given a URI of the scheme that this - // repository is registered to handle, will return 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. - // - // NOTE: If ListableImpl() is not implemented in this repository, - // then attempts to list URIs of the scheme it is registered to handle - // will fail, even if ListImpl() is implemented. - // - // The returned 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). - // - // * Obtaining the listing depended on a lower level operation such as - // network or filesystem access that has failed in some way. - // - // If this method is not implemented (e.g. a nil function is returned), - // then any attempt to list a URI of the scheme this repository is - // registered to handle will fail with a 'not supported' error. - // - // Since 2.0.0 - ListImpl() func(URI) ([]URI, error) +// RegisterRename registers an implementation of a Rename() function for a +// specific URI scheme. This function should only be called in +// Repository.Init(). If the scheme does not have a registered repository, then +// this function will fail with an error. If a Rename implementation is already +// registered for this scheme, it will be replaced with this one silently. +// +// If no Rename implementation is registered for a particular scheme, then +// renames will be implemented as if the URIs were of different types, that is +// the source URI will be read using ReaderFrom(), and the destination written +// using WriterTo(), then the source will be deleted using Delete(). This +// function is an opportunity to implement a more optimal approach, such as +// leveraging remote operations for a network-backed repository. +// +// Since 2.0.0 +func RegisterRename(scheme string, renameImplementation func(fyne.URI, fyne.URI) error) error { +} - // ChildImpl returns a method that given a URI of the scheme - // that this repository is registered to handle, create a new URI - // nested under it. For example, if the method is called on the URI - // file://foo/bar with the string argument 'baz.txt', then the - // URI returned would be 'file:.//foo/bar/baz.txt'. - // - // The returned method may fail in several ways: - // - // * Different permissions or credentials are required to create a - // child of the given URI. - // - // * This URI scheme could represent some resources that can be have - // children, but this specific URI is not one of them (e.g. a file on - // a filesystem, as opposed to a directory). - // - // * Creating the child depended on a lower level operation such as - // network or filesystem access that has failed in some way. - // - // NOTE: the fact that a child can be created for a given URI implies - // that the URI must be listable. If your repository is implemented - // inconsistently with this, things may break in unexpected ways. - // - // If this method is not implemented and a boolean return value of - // 'true' is given, then a default implementation will be used that - // calls the given ParseURI implementation with the string appended to - // the URI path component, separated by a '/' character. If 'false' is - // given, then attempts to create children for any URI of the scheme - // this repository is registered to handle will fail with a 'not - // supported' error. - // - // Since 2.0.0 - ChildImpl() (func(URI, string) (URI, error), bool) +// RegisterRepository registers a storage repository so that operations on URIs +// of the registered scheme will use methods implemented by the relevant +// repository implementation. This method will call repository.Init(), and may +// error if it does. +// +// Since 2.0.0 +func RegisterRepository(scheme string, repository Repository) error { } diff --git a/storage/uri.go b/storage/uri.go index 1a87b27bc7..e147c4bfc2 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -33,6 +33,11 @@ func NewFileURI(path string) fyne.URI { // 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() +// +// NOTE: since 2.0.0, NewURI() is backed by the repository system - this +// function may call into either a generic implementation, or into a +// scheme-specific implementation depending on which storage repositories have +// been registered. func NewURI(u string) fyne.URI { if len(u) > 5 && u[:5] == "file:" { path := u[5:] @@ -237,6 +242,13 @@ func Child(u fyne.URI, component string) (fyne.URI, 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 2.0.0, Exists 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. +// +// 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) { if u.Scheme() != "file" { @@ -255,7 +267,7 @@ func Exists(u fyne.URI) (bool, error) { return true, nil } -// Destroy destroys, deletes, or otherwise removes the resource referenced +// Delete destroys, deletes, or otherwise removes the resource referenced // by the URI. // // This can fail in several ways: @@ -267,7 +279,171 @@ func Exists(u fyne.URI) (bool, error) { // * If the referenced resource does not exist, attempting to destroy it should // throw an error. // +// Delete 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.0 -func Destroy(u fyne.URI) error { +func Delete(u fyne.URI) error { + return fmt.Errorf("TODO: implement this function") +} + +// ReaderFrom 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. +// +// ReaderFrom 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.0 +func ReaderFrom(u fyne.URI) (fyne.URIReadCloser, error) { + return nil, fmt.Errorf("TODO: implement this function") +} + +// WriterFrom returns URIWriteCloser set up to write to the resource that the +// URI references. +// +// 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. +// +// WriterTo 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.0 +func WriterTo(u fyne.URI) (fyne.URIWriteCloser, error) { return fmt.Errorf("TODO: implement this function") } + +// Copy given two URIs, 'src', and 'dest' both of the same scheme , will copy +// one to the other. +// +// 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. +// +// NOTE: if the URIs do not share the same scheme, then this method will +// instead use a reader and a writer. This may have performance implications if +// either or both URIs is remote. If you wish to avoid this, explicitly compare +// the URI schemes before calling Copy(). +// +// Copy is backed by the repository system - this function may call into either +// a generic implementation, or into a scheme-specific implementation depending +// on which storage repositories have been registered. +// +// Since 2.0.0 +func Copy(source fyne.URI, destination fyne.URI) error { + return fmt.Errorf("TODO: implement this function") +} + +// RenameImpl returns a method that given two URIs, 'src' and 'dest' both of +// the same scheme this will rename 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. +// +// 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. +// +// Copy is backed by the repository system - this function may call into either +// a generic implementation, or into a scheme-specific implementation depending +// on which storage repositories have been registered. +// +// If both source and destination are not of the same URI scheme, then this +// method will instead use a reader, write, and a call to Delete(), which may +// have performance implications if either or both URIs are remote. If you wish +// to avoid this, explicitly compare the scheme of both URIs before calling +// Rename(). +// +// Since 2.0.0 +func Rename(source fyne.URI, destination fyne.URI) error { + return fmt.Errorf("TODO: implement this function") +} + +// Listable will determine if the URI is listable or not. +// +// The returned 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. +// +// Listable 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.0 +func Listable(u fyne.URI) (bool, error) { + return false, fmt.Errorf("TODO: implement this function") +} + +// 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. +// +// The returned 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. +// +// 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.0 +func List(u fyne.URI) ([]URI, error) diff --git a/storage/uri_operation_impossible.go b/storage/uri_operation_impossible.go new file mode 100644 index 0000000000..07bb344831 --- /dev/null +++ b/storage/uri_operation_impossible.go @@ -0,0 +1,16 @@ +package storage + +// Declare conformance with Error interface +var _ error = URIOperationImpossible + +type uriOperationImpossible string + +// URIOperationImpossible occurs when an operation is attempted on a URI which +// is supported by the underlying implementation, but which violates some +// internal constraints of that particular repository implementation. For +// example, creating an un-representable state might cause this error to occur. +const URIOperationImpossible uriOperationImpossible = uriOperationImpossible("The requested URI operation is not possible.") + +func (e uriOperationImpossible) Error() string { + return string(URIOperationImpossible) +} diff --git a/storage/uri_operation_not_supported_error.go b/storage/uri_operation_not_supported_error.go new file mode 100644 index 0000000000..340e97f969 --- /dev/null +++ b/storage/uri_operation_not_supported_error.go @@ -0,0 +1,17 @@ +package storage + +// Declare conformance with Error interface +var _ error = URIOperationNotSupportedError + +type uriOperationNotSupportedError string + +// URIOperationNotSupported may be thrown by certain functions in the storage +// package 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. +const URIOperationNotSupportedError uriOperationNotSupportedError = uriOperationNotSupportedError("Operation not supported for this URI.") + +func (e uriOperationNotSupportedError) Error() string { + return string(URIOperationNotSupportedError) +} diff --git a/uri.go b/uri.go index d221cc6742..4a1bcae888 100644 --- a/uri.go +++ b/uri.go @@ -84,7 +84,7 @@ type URI interface { // ListableURI represents a URI that can have child items, most commonly a // directory on disk in the native filesystem. // -// Deprecated: use the IsListable() and List() methods that operate on URI in +// Deprecated: use the Listable() and List() methods that operate on URI in // the storage package instead. // // Since: 1.4 From 22ac8119d5c7af61e72d5ff5a024ccd5d9a040a0 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Mon, 11 Jan 2021 15:56:54 -0500 Subject: [PATCH 010/145] set up new Repository interfaces --- storage/repository.go | 140 ++++++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 68 deletions(-) diff --git a/storage/repository.go b/storage/repository.go index 7506892082..f1f8358777 100644 --- a/storage/repository.go +++ b/storage/repository.go @@ -41,28 +41,6 @@ import ( // Since: 2.0.0 type Repository interface { - // ParseURI returns a method that given a text string creates a - // new URI instance. This may cause an error, for example if the string - // is an invalid URI or contains information that is invalid in the - // context of the repository's scheme. - // - // This method will be called only after the URI scheme has been - // verified to match the one the repository was registered to handle, - // however the URI is not validated further than this. It is required - // by convention (but not enforced by technical means) that this - // function should throw an error if the string is not a valid IETF RFC - // 3986 complaint URI. Fail to validate this at your own risk. - // - // NOTE: it is highly recommended to use net/url ( - // https://golang.org/pkg/net/url/ ) for parsing URI strings unless you - // have a good reason not to. It is mature and implements RFC 3986. - // - // If no implementation is provided, a generic URI based on RFC3986 is - // parsed without any special validation logic. - // - // Since 2.0.0 - ParseURI() func(string) (fyne.URI, error) - // Init will be called while the repository is being registered. This // is the appropriate place to register any optional handlers relevant // to a particular URI scheme. @@ -76,29 +54,68 @@ type Repository interface { // Since 2.0.0 Exists(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.0 - Delete(u fyne.URI) error - // ReaderFrom will be used to implement calls to storage.ReaderFrom() // for the registered scheme of this repository. // // Since 2.0.0 ReaderFrom(u fyne.URI) (fyne.URIReadCloser, error) - // WriterTo will be used to implement calls to storage.WriterTo() for + // CanRead will be used to implement calls to storage.CanRead() for the + // registered scheme of this repository. + // + // Since 2.0.0 + CanRead(u fyne.URI) (bool, error) +} + +// WriteableRepository is an extension of the Repository interface which also +// supports obtaining a writer for URIs of the scheme it is registered to. +// +// If this interface is not implemented for a repository, then attempts to use +// storage.Writer, storage.Delete, and storage.CanWrite will fail with +// URIOperationNotSupportedError when called on URIs of the scheme this is +// registered to. +// +// Since: 2.0.0 +type WriteableRepository interface { + Repository + + // Writer will be used to implement calls to storage.WriterTo() for // the registered scheme of this repository. // // Since 2.0.0 - WriterTo(u fyne.URI) (fyne.URIWriteCloser, error) + 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.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.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. +// +// If this interface is not implemented for a repository, then attempts to use +// storage.CanList and storage.List will fail with +// URIOperationNotSupportedError when called for URIs of the scheme it is +// registered to. +// +// Since: 2.0.0 +type ListableRepository interface { + Repository - // Listable will be used to implement calls to storage.Listable() for + // CanList will be used to implement calls to storage.Listable() for // the registered scheme of this repository. // // Since 2.0.0 - Listable(u fyne.URI) (bool, error) + CanList(u fyne.URI) (bool, error) // List will be used to implement calls to storage.List() for the // registered scheme of this repository. @@ -107,46 +124,33 @@ type Repository interface { List(u fyne.URI) ([]URI, error) } -// RegisterCopy registers an implementation of a Copy() function for a specific -// URI scheme. This function should only be called in Repository.Init(). If -// the scheme does not have a registered repository, then this function will -// fail with an error. If a Copy implementation is already registered for this -// scheme, it will be replaced with this one silently. -// -// If no Copy implementation is registered for a particular scheme, then copies -// will be implemented as if the URIs were of different types, that is the -// source URI will be read using ReaderFrom(), and the destination written -// using WriterTo(). This function is an opportunity to implement a more -// optimal approach, such as leveraging remote operations for a network-backed -// repository. -// -// Since 2.0.0 -func RegisterCopy(scheme string, copyImplementation func(fyne.URI, fyne.URI) error) error { - // TODO +// gets fallbacks +type HierarchicalRepository interface { + Repository + + Parent(fyne.URI) (fyne.URI, error) + + Child(Fyne.URI) (fyne.URI, error) } -// RegisterRename registers an implementation of a Rename() function for a -// specific URI scheme. This function should only be called in -// Repository.Init(). If the scheme does not have a registered repository, then -// this function will fail with an error. If a Rename implementation is already -// registered for this scheme, it will be replaced with this one silently. -// -// If no Rename implementation is registered for a particular scheme, then -// renames will be implemented as if the URIs were of different types, that is -// the source URI will be read using ReaderFrom(), and the destination written -// using WriterTo(), then the source will be deleted using Delete(). This -// function is an opportunity to implement a more optimal approach, such as -// leveraging remote operations for a network-backed repository. -// -// Since 2.0.0 -func RegisterRename(scheme string, renameImplementation func(fyne.URI, fyne.URI) error) error { +// gets fallbacks +type CopyableRepository interface { + Repository + + Copy(fyne.URI, fyne.URI) error +} + +// gets fallbacks +type MovableRepository interface { + Repository + + Move(fyne.URI, fyne.URI) error } -// RegisterRepository registers a storage repository so that operations on URIs -// of the registered scheme will use methods implemented by the relevant -// repository implementation. This method will call repository.Init(), and may -// error if it does. +// 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.0 -func RegisterRepository(scheme string, repository Repository) error { +func Register(scheme string, repository Repository) { } From eb6c77392da6ad233264d62da6e1a3ed3e8ca798 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Mon, 11 Jan 2021 20:14:30 -0500 Subject: [PATCH 011/145] write stubs described in the proposal --- storage/repository.go | 156 --------------- storage/repository/errors.go | 17 ++ storage/repository/generic.go | 68 +++++++ storage/repository/repository.go | 197 +++++++++++++++++++ storage/uri.go | 140 ++++++++----- storage/uri_operation_impossible.go | 16 -- storage/uri_operation_not_supported_error.go | 17 -- 7 files changed, 370 insertions(+), 241 deletions(-) delete mode 100644 storage/repository.go create mode 100644 storage/repository/errors.go create mode 100644 storage/repository/generic.go create mode 100644 storage/repository/repository.go delete mode 100644 storage/uri_operation_impossible.go delete mode 100644 storage/uri_operation_not_supported_error.go diff --git a/storage/repository.go b/storage/repository.go deleted file mode 100644 index f1f8358777..0000000000 --- a/storage/repository.go +++ /dev/null @@ -1,156 +0,0 @@ -package storage - -import ( - "fyne.io/fyne" -) - -// 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. Some additional methods which can offer -// more optimization opportunities can also be implemented by calling the -// appropriate Register...() function inside of the Repository.Init() function. -// For example, storage.Copy() will by default use a reader and a writer to -// perform a copy operation, but a repository might use RegisterCopy() to cause -// a more optimal version to be used for URIs of the relevant scheme (e.g. by -// performing the copy on the remote side of an ssh connection). -// -// In some cases, you may wish to omit an implementation of one of these -// functions anyway. In such cases, you should do this by returning a -// URIOperationNotSupportedError. For example, this may be appropriate when -// building a storage repository which represents only resources that are -// read-only - in such cases functions like WriterTo() may not make sense. -// Please use care when deciding to do this, and consider how it will impact -// users of your storage repository. -// -// 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. -// -// NOTE: functions in a particular repository can assume they will only ever be -// used on URIs which match the scheme that they have been registered to -// handle, however they should not assume that they will only be called on URIs -// of the same implementation as the ParseURI() for this repository has -// returned. -// -// Since: 2.0.0 -type Repository interface { - - // Init will be called while the repository is being registered. This - // is the appropriate place to register any optional handlers relevant - // to a particular URI scheme. - // - // Since 2.0.0 - Init() func() error - - // Exists will be used to implement calls to storage.Exists() for the - // registered scheme of this repository. - // - // Since 2.0.0 - Exists(u fyne.URI) (bool, error) - - // ReaderFrom will be used to implement calls to storage.ReaderFrom() - // for the registered scheme of this repository. - // - // Since 2.0.0 - ReaderFrom(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.0 - CanRead(u fyne.URI) (bool, error) -} - -// WriteableRepository is an extension of the Repository interface which also -// supports obtaining a writer for URIs of the scheme it is registered to. -// -// If this interface is not implemented for a repository, then attempts to use -// storage.Writer, storage.Delete, and storage.CanWrite will fail with -// URIOperationNotSupportedError when called on URIs of the scheme this is -// registered to. -// -// Since: 2.0.0 -type WriteableRepository interface { - Repository - - // Writer will be used to implement calls to storage.WriterTo() for - // the registered scheme of this repository. - // - // Since 2.0.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.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.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. -// -// If this interface is not implemented for a repository, then attempts to use -// storage.CanList and storage.List will fail with -// URIOperationNotSupportedError when called for URIs of the scheme it is -// registered to. -// -// Since: 2.0.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.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.0 - List(u fyne.URI) ([]URI, error) -} - -// gets fallbacks -type HierarchicalRepository interface { - Repository - - Parent(fyne.URI) (fyne.URI, error) - - Child(Fyne.URI) (fyne.URI, error) -} - -// gets fallbacks -type CopyableRepository interface { - Repository - - Copy(fyne.URI, fyne.URI) error -} - -// gets fallbacks -type MovableRepository interface { - Repository - - 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.0 -func Register(scheme string, repository Repository) { -} diff --git a/storage/repository/errors.go b/storage/repository/errors.go new file mode 100644 index 0000000000..f951f36420 --- /dev/null +++ b/storage/repository/errors.go @@ -0,0 +1,17 @@ +package repository + +// Declare conformance with Error interface +var _ error = OperationNotSupportedError + +type operationNotSupportedError string + +// operationNotSupported 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. +const OperationNotSupportedError operationNotSupportedError = operationNotSupportedError("Operation not supported for this URI.") + +func (e operationNotSupportedError) Error() string { + return string(OperationNotSupportedError) +} diff --git a/storage/repository/generic.go b/storage/repository/generic.go new file mode 100644 index 0000000000..010dfe3df8 --- /dev/null +++ b/storage/repository/generic.go @@ -0,0 +1,68 @@ +package repository + +import ( + "fmt" + "fyne.io/fyne" +) + +// 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. +// +// 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.0 +func GenericParent(u fyne.URI) (fyne.URI, error) { + return nil, fmt.Errorf("TODO") +} + +// 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.0 +func GenericChild(u fyne.URI, component string) (fyne.URI, error) { + return nil, fmt.Errorf("TODO") +} + +// 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 +// WriteableRepository. +// +// 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.0 +func GenericCopy(source fyne.URI, destination fyne.URI) error { + return fmt.Errorf("TODO") +} + +// GenericMove can be used a common-case implementation of +// MoveableRepository.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 WriteableRepository.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.0 +func GenericMove(source fyne.URI, destination fyne.URI) error { + return fmt.Errorf("TODO") +} diff --git a/storage/repository/repository.go b/storage/repository/repository.go new file mode 100644 index 0000000000..9787d3d3f3 --- /dev/null +++ b/storage/repository/repository.go @@ -0,0 +1,197 @@ +package repository + +import ( + "fmt" + "fyne.io/fyne" +) + +// 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. +// +// 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.0 +type Repository interface { + + // Exists will be used to implement calls to storage.Exists() for the + // registered scheme of this repository. + // + // Since 2.0.0 + Exists(u fyne.URI) (bool, error) + + // ReaderFrom will be used to implement calls to storage.ReaderFrom() + // for the registered scheme of this repository. + // + // Since 2.0.0 + ReaderFrom(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.0 + CanRead(u fyne.URI) (bool, error) + + // Destroy is called when the repository is un-registered from a given + // URI scheme. + // + // Since 2.0.0 + Destroy() +} + +// WriteableRepository 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.0 +type WriteableRepository interface { + Repository + + // Writer will be used to implement calls to storage.WriterTo() for + // the registered scheme of this repository. + // + // Since 2.0.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.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.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.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.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.0 + List(u fyne.URI) ([]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.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.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.0 + Child(Fyne.URI) (fyne.URI, error) +} + +// CopyableRepository is an extension of the Repository interface which also +// supports copying referenced resources from one URI to another. +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.0 + Copy(fyne.URI, fyne.URI) error +} + +// CopyableRepository is an extension of the Repository interface which also +// supports moving referenced resources from one URI to another. +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.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.0 +func Register(scheme string, repository Repository) { +} + +// RepositoryForURI 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. +func RepositoryForURI(u fyne.URI) (Repository, error) { + return nil, fmt.Errorf("TODO") +} diff --git a/storage/uri.go b/storage/uri.go index e147c4bfc2..2a73edee21 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -127,8 +127,8 @@ func parentGeneric(location string) (string, error) { // 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 required that the implementation return a parent URI with -// the same Scheme(), though this will normally be the case. +// 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: // @@ -146,10 +146,13 @@ func parentGeneric(location string) (string, error) { // 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.OperationNotSupportedError. +// // NOTE: since 2.0.0, Parent() is backed by the repository system - this -// function may call into either a generic implementation, or into a -// scheme-specific implementation depending on which storage repositories have -// been registered. +// 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) { @@ -208,10 +211,13 @@ func Parent(u fyne.URI) (fyne.URI, error) { // 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.OperationNotSupportedError. +// // NOTE: since 2.0.0, Child() is backed by the repository system - this -// function may call into either a generic implementation, or into a -// scheme-specific implementation depending on which storage repositories have -// been registered. +// 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) { @@ -243,8 +249,7 @@ func Child(u fyne.URI, component string) (fyne.URI, error) { // non-existence of the resource cannot be determined and is undefined. // // NOTE: since 2.0.0, Exists 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. +// calls into a scheme-specific implementation from a registered repository. // // may call into either a generic implementation, or into a scheme-specific // implementation depending on which storage repositories have been registered. @@ -279,16 +284,19 @@ func Exists(u fyne.URI) (bool, error) { // * If the referenced resource does not exist, attempting to destroy it should // throw an error. // -// Delete 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. +// * If the scheme of the given URI does not have a registered +// WriteableRepository instance, then this method will fail with a +// repository.OperationNotSupportedError. +// +// Delete is backed by the repository system - this function calls +// into a scheme-specific implementation from a registered repository. // // Since: 2.0.0 func Delete(u fyne.URI) error { return fmt.Errorf("TODO: implement this function") } -// ReaderFrom returns URIReadCloser set up to read from the resource that the +// Reader returns URIReadCloser set up to read from the resource that the // URI references. // // This method can fail in several ways: @@ -304,16 +312,28 @@ func Delete(u fyne.URI) error { // operation such as a network or filesystem access that has failed // in some way. // -// ReaderFrom 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. +// ReaderFrom is backed by the repository system - this function calls +// into a scheme-specific implementation from a registered repository. // // Since 2.0.0 func ReaderFrom(u fyne.URI) (fyne.URIReadCloser, error) { return nil, fmt.Errorf("TODO: implement this function") } -// WriterFrom returns URIWriteCloser set up to write to the resource that the +// CanRead determines if a given URI could be written to using the Reader() +// method. It is preferred to check if a URI is writable using this method +// before calling Reader(), 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. +// +// CanRead is backed by the repository system - this function calls into a +// scheme-specific implementation from a registered repository. +// +// Since 2.0.0 +func CanRead(u fyne.URI) (bool, error) { +} + +// Writer returns URIWriteCloser set up to write to the resource that the // URI references. // // This method can fail in several ways: @@ -329,15 +349,31 @@ func ReaderFrom(u fyne.URI) (fyne.URIReadCloser, error) { // operation such as a network or filesystem access that has failed // in some way. // -// WriterTo 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. +// * If the scheme of the given URI does not have a registered +// WriteableRepository instance, then this method will fail with a +// repository.OperationNotSupportedError. +// +// Writer is backed by the repository system - this function calls into a +// scheme-specific implementation from a registered repository. // // Since 2.0.0 -func WriterTo(u fyne.URI) (fyne.URIWriteCloser, error) { +func Writer(u fyne.URI) (fyne.URIWriteCloser, error) { return fmt.Errorf("TODO: implement this function") } +// 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. +// +// CanWrite is backed by the repository system - this function calls into a +// scheme-specific implementation from a registered repository. +// +// Since 2.0.0 +func CanWrite(u fyne.URI) (bool, error) { +} + // Copy given two URIs, 'src', and 'dest' both of the same scheme , will copy // one to the other. // @@ -353,25 +389,22 @@ func WriterTo(u fyne.URI) (fyne.URIWriteCloser, error) { // * Performing the copy operation depended on a lower level operation // such as network or filesystem access that has failed in some way. // -// NOTE: if the URIs do not share the same scheme, then this method will -// instead use a reader and a writer. This may have performance implications if -// either or both URIs is remote. If you wish to avoid this, explicitly compare -// the URI schemes before calling Copy(). +// * If the scheme of the given URI does not have a registered +// CopyableRepository instance, then this method will fail with a +// repository.OperationNotSupportedError. // -// Copy is backed by the repository system - this function may call into either -// a generic implementation, or into a scheme-specific implementation depending -// on which storage repositories have been registered. +// Copy is backed by the repository system - this function calls into a +// scheme-specific implementation from a registered repository. // // Since 2.0.0 func Copy(source fyne.URI, destination fyne.URI) error { return fmt.Errorf("TODO: implement this function") } -// RenameImpl returns a method that given two URIs, 'src' and 'dest' both of -// the same scheme this will rename 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. +// 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. // // This method may fail in several ways: // @@ -385,22 +418,19 @@ func Copy(source fyne.URI, destination fyne.URI) error { // * Performing the rename operation depended on a lower level operation // such as network or filesystem access that has failed in some way. // -// Copy is backed by the repository system - this function may call into either -// a generic implementation, or into a scheme-specific implementation depending -// on which storage repositories have been registered. +// * If the scheme of the given URI does not have a registered +// MoveableRepository instance, then this method will fail with a +// repository.OperationNotSupportedError. // -// If both source and destination are not of the same URI scheme, then this -// method will instead use a reader, write, and a call to Delete(), which may -// have performance implications if either or both URIs are remote. If you wish -// to avoid this, explicitly compare the scheme of both URIs before calling -// Rename(). +// Move is backed by the repository system - this function calls into a +// scheme-specific implementation from a registered repository. // // Since 2.0.0 -func Rename(source fyne.URI, destination fyne.URI) error { +func Move(source fyne.URI, destination fyne.URI) error { return fmt.Errorf("TODO: implement this function") } -// Listable will determine if the URI is listable or not. +// CanList will determine if the URI is listable or not. // // The returned method may fail in several ways: // @@ -414,19 +444,21 @@ func Rename(source fyne.URI, destination fyne.URI) error { // * Checking for listability depended on a lower level operation // such as network or filesystem access that has failed in some way. // -// Listable 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. +// * If the scheme of the given URI does not have a registered +// ListableRepository instance, then this method will fail with a +// repository.OperationNotSupportedError. +// +// CanList is backed by the repository system - this function calls into a +// scheme-specific implementation from a registered repository. // // Since 2.0.0 -func Listable(u fyne.URI) (bool, error) { +func CanList(u fyne.URI) (bool, error) { return false, fmt.Errorf("TODO: implement this function") } -// 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. +// 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. // // The returned method may fail in several ways: // @@ -441,6 +473,10 @@ func Listable(u fyne.URI) (bool, error) { // * 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.OperationNotSupportedError. +// // 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. diff --git a/storage/uri_operation_impossible.go b/storage/uri_operation_impossible.go deleted file mode 100644 index 07bb344831..0000000000 --- a/storage/uri_operation_impossible.go +++ /dev/null @@ -1,16 +0,0 @@ -package storage - -// Declare conformance with Error interface -var _ error = URIOperationImpossible - -type uriOperationImpossible string - -// URIOperationImpossible occurs when an operation is attempted on a URI which -// is supported by the underlying implementation, but which violates some -// internal constraints of that particular repository implementation. For -// example, creating an un-representable state might cause this error to occur. -const URIOperationImpossible uriOperationImpossible = uriOperationImpossible("The requested URI operation is not possible.") - -func (e uriOperationImpossible) Error() string { - return string(URIOperationImpossible) -} diff --git a/storage/uri_operation_not_supported_error.go b/storage/uri_operation_not_supported_error.go deleted file mode 100644 index 340e97f969..0000000000 --- a/storage/uri_operation_not_supported_error.go +++ /dev/null @@ -1,17 +0,0 @@ -package storage - -// Declare conformance with Error interface -var _ error = URIOperationNotSupportedError - -type uriOperationNotSupportedError string - -// URIOperationNotSupported may be thrown by certain functions in the storage -// package 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. -const URIOperationNotSupportedError uriOperationNotSupportedError = uriOperationNotSupportedError("Operation not supported for this URI.") - -func (e uriOperationNotSupportedError) Error() string { - return string(URIOperationNotSupportedError) -} From 2ccf744a81dd5e8f18f7fe86992ee4647a18e11c Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Mon, 11 Jan 2021 20:27:56 -0500 Subject: [PATCH 012/145] add storage.ParseURI() --- storage/uri.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/storage/uri.go b/storage/uri.go index 2a73edee21..a00fc78436 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -123,6 +123,14 @@ func parentGeneric(location string) (string, error) { return parent, nil } +// ParseURI creates a new URI instance by parsing a URI string, which must +// conform to IETF RFC3986. +// +// Since 2.0.0 +func ParseURI(string) (fyne.URI, error) { + return nil, fmt.Errorf("TODO") +} + // 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. From a1f5bf8288230f15a0b7797c6783b4f63b89774c Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Mon, 11 Jan 2021 20:52:31 -0500 Subject: [PATCH 013/145] bring storage.uri up to compliance with fyne.URI --- storage/repository/repository.go | 4 +- storage/uri.go | 95 +++++++++++++++++++++++--------- 2 files changed, 72 insertions(+), 27 deletions(-) diff --git a/storage/repository/repository.go b/storage/repository/repository.go index 9787d3d3f3..5886faad09 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -105,7 +105,7 @@ type ListableRepository interface { // registered scheme of this repository. // // Since 2.0.0 - List(u fyne.URI) ([]URI, error) + List(u fyne.URI) ([]fyne.URI, error) } // HierarchicalRepository is an extension of the Repository interface which @@ -131,7 +131,7 @@ type HierarchicalRepository interface { // is based on RFC3986. // // Since 2.0.0 - Child(Fyne.URI) (fyne.URI, error) + Child(fyne.URI) (fyne.URI, error) } // CopyableRepository is an extension of the Repository interface which also diff --git a/storage/uri.go b/storage/uri.go index a00fc78436..96157ad22b 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -4,6 +4,7 @@ import ( "bufio" "fmt" "mime" + "net/url" "os" "path/filepath" "runtime" @@ -13,6 +14,9 @@ import ( "fyne.io/fyne" ) +// Declare conformance with fyne.URI interface +var _ fyne.URI = &uri{} + type uri struct { raw string } @@ -31,25 +35,6 @@ func NewFileURI(path string) fyne.URI { return &uri{raw: "file://" + 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() -// -// NOTE: since 2.0.0, NewURI() is backed by the repository system - this -// function may call into either a generic implementation, or into a -// scheme-specific implementation depending on which storage repositories have -// been registered. -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} -} - func (u *uri) Extension() string { return filepath.Ext(u.raw) } @@ -88,6 +73,40 @@ func (u *uri) String() string { return u.raw } +func (u *uri) Authority() string { + // NOTE: we verified in ParseURI() that this would not error. + r, _ := url.Parse(u.raw) + + a := "" + if len(r.User.String()) > 0 { + a = r.User.String() + "@" + } + a = a + r.Host + + return a +} + +func (u *uri) Path() string { + // NOTE: we verified in ParseURI() that this would not error. + r, _ := url.Parse(u.raw) + + return r.Path +} + +func (u *uri) Query() string { + // NOTE: we verified in ParseURI() that this would not error. + r, _ := url.Parse(u.raw) + + return r.RawQuery +} + +func (u *uri) Fragment() string { + // NOTE: we verified in ParseURI() that this would not error. + r, _ := url.Parse(u.raw) + + return r.Fragment +} + // 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) { @@ -123,12 +142,34 @@ func parentGeneric(location string) (string, error) { return parent, nil } +// 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 +} + // ParseURI creates a new URI instance by parsing a URI string, which must // conform to IETF RFC3986. // // Since 2.0.0 -func ParseURI(string) (fyne.URI, error) { - return nil, fmt.Errorf("TODO") +func ParseURI(s string) (fyne.URI, error) { + _, err := url.Parse(s) + if err != nil { + return nil, err + } + + if len(s) > 5 && s[:5] == "file:" { + path := s[5:] + if len(path) > 2 && path[:2] == "//" { + path = path[2:] + } + return NewFileURI(path), nil + } + + return &uri{raw: s}, nil } // Parent returns a URI referencing the parent resource of the resource @@ -200,7 +241,7 @@ func Parent(u fyne.URI) (fyne.URI, error) { } } - return NewURI(u.Scheme() + "://" + parent), nil + return ParseURI(u.Scheme() + "://" + parent) } // Child returns a URI referencing a resource nested hierarchically below the @@ -241,7 +282,7 @@ func Child(u fyne.URI, component string) (fyne.URI, error) { s += "/" } - return NewURI(s + component), nil + return ParseURI(s + component) } // Exists determines if the resource referenced by the URI exists. @@ -339,6 +380,7 @@ func ReaderFrom(u fyne.URI) (fyne.URIReadCloser, error) { // // Since 2.0.0 func CanRead(u fyne.URI) (bool, error) { + return false, fmt.Errorf("TODO") } // Writer returns URIWriteCloser set up to write to the resource that the @@ -366,7 +408,7 @@ func CanRead(u fyne.URI) (bool, error) { // // Since 2.0.0 func Writer(u fyne.URI) (fyne.URIWriteCloser, error) { - return fmt.Errorf("TODO: implement this function") + return nil, fmt.Errorf("TODO: implement this function") } // CanWrite determines if a given URI could be written to using the Writer() @@ -380,6 +422,7 @@ func Writer(u fyne.URI) (fyne.URIWriteCloser, error) { // // Since 2.0.0 func CanWrite(u fyne.URI) (bool, error) { + return false, fmt.Errorf("TODO") } // Copy given two URIs, 'src', and 'dest' both of the same scheme , will copy @@ -490,4 +533,6 @@ func CanList(u fyne.URI) (bool, error) { // URIOperationNotSupported error. // // Since 2.0.0 -func List(u fyne.URI) ([]URI, error) +func List(u fyne.URI) ([]fyne.URI, error) { + return nil, fmt.Errorf("TODO") +} From 724aeeb439cf91631851e8eb0176b914c923a5aa Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Mon, 11 Jan 2021 20:57:08 -0500 Subject: [PATCH 014/145] fix goimports checks --- storage/repository/generic.go | 1 + storage/repository/repository.go | 1 + 2 files changed, 2 insertions(+) diff --git a/storage/repository/generic.go b/storage/repository/generic.go index 010dfe3df8..1db6421bfc 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -2,6 +2,7 @@ package repository import ( "fmt" + "fyne.io/fyne" ) diff --git a/storage/repository/repository.go b/storage/repository/repository.go index 5886faad09..daf514077b 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -2,6 +2,7 @@ package repository import ( "fmt" + "fyne.io/fyne" ) From d29bd29e7d0ff9c6bbee803a88f2d6bbaaa58ed9 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Mon, 11 Jan 2021 21:02:07 -0500 Subject: [PATCH 015/145] fix linter errors Most notably, I have renamed RepositoryForURI() to RegisteredRepository(), to placate the linter. --- storage/repository/errors.go | 10 +++++----- storage/repository/repository.go | 6 +++--- storage/uri.go | 18 +++++++++++------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/storage/repository/errors.go b/storage/repository/errors.go index f951f36420..62d2000e08 100644 --- a/storage/repository/errors.go +++ b/storage/repository/errors.go @@ -5,11 +5,11 @@ var _ error = OperationNotSupportedError type operationNotSupportedError string -// operationNotSupported 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. +// OperationNotSupportedError 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. const OperationNotSupportedError operationNotSupportedError = operationNotSupportedError("Operation not supported for this URI.") func (e operationNotSupportedError) Error() string { diff --git a/storage/repository/repository.go b/storage/repository/repository.go index daf514077b..d9014f3c5b 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -157,7 +157,7 @@ type CopyableRepository interface { Copy(fyne.URI, fyne.URI) error } -// CopyableRepository is an extension of the Repository interface which also +// MovableRepository is an extension of the Repository interface which also // supports moving referenced resources from one URI to another. type MovableRepository interface { Repository @@ -187,12 +187,12 @@ type MovableRepository interface { func Register(scheme string, repository Repository) { } -// RepositoryForURI returns the Repository instance which is registered to +// RegisteredRepository 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. -func RepositoryForURI(u fyne.URI) (Repository, error) { +func RegisteredRepository(u fyne.URI) (Repository, error) { return nil, fmt.Errorf("TODO") } diff --git a/storage/uri.go b/storage/uri.go index 96157ad22b..8120d6471e 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -156,17 +156,21 @@ func NewURI(s string) fyne.URI { // // Since 2.0.0 func ParseURI(s string) (fyne.URI, error) { - _, err := url.Parse(s) - if err != nil { - return nil, err - } if len(s) > 5 && s[:5] == "file:" { path := s[5:] if len(path) > 2 && path[:2] == "//" { path = path[2:] } - return NewFileURI(path), nil + + // this looks weird, but it makes sure that we still pass + // url.Parse() + s = NewFileURI(path).String() + } + + _, err := url.Parse(s) + if err != nil { + return nil, err } return &uri{raw: s}, nil @@ -361,11 +365,11 @@ func Delete(u fyne.URI) error { // operation such as a network or filesystem access that has failed // in some way. // -// ReaderFrom is backed by the repository system - this function calls +// Reader is backed by the repository system - this function calls // into a scheme-specific implementation from a registered repository. // // Since 2.0.0 -func ReaderFrom(u fyne.URI) (fyne.URIReadCloser, error) { +func Reader(u fyne.URI) (fyne.URIReadCloser, error) { return nil, fmt.Errorf("TODO: implement this function") } From 21953caa441dd4964148b9ed68477644e0ed0666 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Mon, 11 Jan 2021 21:21:11 -0500 Subject: [PATCH 016/145] add test cases for the new URI methods --- storage/uri_test.go | 60 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/storage/uri_test.go b/storage/uri_test.go index a67b7f3f28..029dff67fb 100644 --- a/storage/uri_test.go +++ b/storage/uri_test.go @@ -11,6 +11,66 @@ import ( "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()) + + // NOTE: this is currently broken, because net/url is not fully RFC3986 + // compliant - it returns an empty string rather than the proper 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) From 546d5baf56319786f1d06533335057cc910393f5 Mon Sep 17 00:00:00 2001 From: FPabl0 Date: Tue, 12 Jan 2021 13:38:34 -0500 Subject: [PATCH 017/145] refactor selectRenderer to make Select widget look similar to SelectEntry --- widget/select.go | 49 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/widget/select.go b/widget/select.go index 9e334f2f87..38aaa6e5db 100644 --- a/widget/select.go +++ b/widget/select.go @@ -7,7 +7,6 @@ import ( "fyne.io/fyne" "fyne.io/fyne/canvas" "fyne.io/fyne/driver/desktop" - "fyne.io/fyne/internal/widget" "fyne.io/fyne/theme" ) @@ -67,7 +66,7 @@ func (s *Select) CreateRenderer() fyne.WidgetRenderer { bg := canvas.NewRectangle(color.Transparent) objects := []fyne.CanvasObject{bg, txtProv, icon} - r := &selectRenderer{widget.NewShadowingRenderer(objects, widget.ButtonLevel), icon, txtProv, bg, s} + r := &selectRenderer{icon, txtProv, bg, objects, s} bg.FillColor = r.buttonColor() r.updateIcon() s.propertyLock.RUnlock() // updateLabel and some text handling isn't quite right, resolve in text refactor for 2.0 @@ -235,7 +234,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(theme.Padding(), s.Size().Height+1)) } func (s *Select) showPopUp() { @@ -266,7 +265,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 { @@ -284,40 +283,40 @@ func (s *Select) updateSelected(text string) { } type selectRenderer struct { - *widget.ShadowingRenderer - icon *Icon label *textProvider bg *canvas.Rectangle - combo *Select + + objects []fyne.CanvasObject + combo *Select } func (s *selectRenderer) BackgroundColor() color.Color { return color.Transparent } +func (s *selectRenderer) Objects() []fyne.CanvasObject { + return s.objects +} + +func (s *selectRenderer) Destroy() {} + // 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)) - - s.bg.Move(fyne.NewPos(theme.Padding(), theme.Padding())) - s.bg.Resize(size.Subtract(fyne.NewSize(doublePad, doublePad))) + s.bg.Move(fyne.NewPos(0, 0)) + s.bg.Resize(size) - offset := fyne.NewSize(theme.IconInlineSize(), 0) - labelSize := inner.Subtract(offset) + iconPos := fyne.NewPos(size.Width-theme.IconInlineSize()-theme.Padding()*2, (size.Height-theme.IconInlineSize())/2) + labelSize := fyne.NewSize(iconPos.X-theme.Padding(), size.Height) s.combo.propertyLock.RLock() defer s.combo.propertyLock.RUnlock() s.label.Resize(labelSize) - s.label.Move(fyne.NewPos(doublePad, theme.Padding())) + s.label.Move(fyne.NewPos(theme.Padding(), theme.Padding())) 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. @@ -326,10 +325,10 @@ 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)) + // pad - label - pad - icon - pad*2 + min := s.label.MinSize() + min = min.Add(fyne.NewSize(theme.Padding()*2, theme.Padding()*2)) + return min.Add(fyne.NewSize(theme.IconInlineSize()+theme.Padding()*2, 0)) } func (s *selectRenderer) Refresh() { @@ -349,7 +348,7 @@ func (s *selectRenderer) Refresh() { func (s *selectRenderer) buttonColor() color.Color { if s.combo.Disabled() { - return theme.ButtonColor() + return theme.FocusColor() } if s.combo.focused { return theme.PrimaryColor() @@ -357,7 +356,7 @@ func (s *selectRenderer) buttonColor() color.Color { if s.combo.hovered || s.combo.tapped { // TODO tapped will be different to hovered when we have animation return theme.HoverColor() } - return theme.ButtonColor() + return theme.FocusColor() } func (s *selectRenderer) updateIcon() { From 39665e5b619fe3501b876c340ad29bcde76cbd48 Mon Sep 17 00:00:00 2001 From: FPabl0 Date: Tue, 12 Jan 2021 15:24:39 -0500 Subject: [PATCH 018/145] adding some padding to popup menu in Select widget --- widget/select.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/select.go b/widget/select.go index 38aaa6e5db..25fc99e106 100644 --- a/widget/select.go +++ b/widget/select.go @@ -250,7 +250,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-theme.Padding()*2, s.popUp.MinSize().Height+theme.Padding()/2)) } func (s *Select) textAlign() fyne.TextAlign { From e26c2881fbbfe09a516e9453d52fe7294dd88728 Mon Sep 17 00:00:00 2001 From: FPabl0 Date: Tue, 12 Jan 2021 15:42:47 -0500 Subject: [PATCH 019/145] fix bad indent --- widget/select.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/widget/select.go b/widget/select.go index ce175ff7bd..51138d8e6d 100644 --- a/widget/select.go +++ b/widget/select.go @@ -65,14 +65,9 @@ func (s *Select) CreateRenderer() fyne.WidgetRenderer { txtProv.ExtendBaseWidget(txtProv) bg := canvas.NewRectangle(color.Transparent) -<<<<<<< HEAD - objects := []fyne.CanvasObject{bg, txtProv, icon} - r := &selectRenderer{icon, txtProv, bg, objects, s} -======= s.tapBG = canvas.NewRectangle(color.Transparent) objects := []fyne.CanvasObject{bg, s.tapBG, txtProv, icon} - r := &selectRenderer{widget.NewShadowingRenderer(objects, widget.ButtonLevel), icon, txtProv, bg, s} ->>>>>>> upstream/develop + r := &selectRenderer{icon, txtProv, bg, objects, s} bg.FillColor = r.buttonColor() r.updateIcon() s.propertyLock.RUnlock() // updateLabel and some text handling isn't quite right, resolve in text refactor for 2.0 From 188d6764d48a731559a84f349ea959e35798e0a8 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Tue, 12 Jan 2021 16:38:41 -0500 Subject: [PATCH 020/145] change to ForURI, add scheme to Destroy --- storage/repository/repository.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/storage/repository/repository.go b/storage/repository/repository.go index d9014f3c5b..67897a8892 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -58,8 +58,12 @@ type Repository interface { // 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.0 - Destroy() + Destroy(string) } // WriteableRepository is an extension of the Repository interface which also @@ -187,12 +191,12 @@ type MovableRepository interface { func Register(scheme string, repository Repository) { } -// RegisteredRepository returns the Repository instance which is registered to -// handle URIs of the given scheme. +// ForURI 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. -func RegisteredRepository(u fyne.URI) (Repository, error) { +func ForURI(u fyne.URI) (Repository, error) { return nil, fmt.Errorf("TODO") } From 3c08c793dbaf11dffd55ec7ca500afbee1e47304 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Tue, 12 Jan 2021 17:14:07 -0500 Subject: [PATCH 021/145] move URIRootError to repository --- storage/repository/errors.go | 15 +++++++++++++++ storage/uri_root_error.go | 18 +++++------------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/storage/repository/errors.go b/storage/repository/errors.go index 62d2000e08..ab25ea632b 100644 --- a/storage/repository/errors.go +++ b/storage/repository/errors.go @@ -15,3 +15,18 @@ const OperationNotSupportedError operationNotSupportedError = operationNotSuppor func (e operationNotSupportedError) Error() string { return string(OperationNotSupportedError) } + +// 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) +} diff --git a/storage/uri_root_error.go b/storage/uri_root_error.go index c595516e18..22fab8af3c 100644 --- a/storage/uri_root_error.go +++ b/storage/uri_root_error.go @@ -1,16 +1,8 @@ package storage -// Declare conformance with Error interface -var _ error = URIRootError +import ( + "fyne.io/fyne/storage/repository" +) -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) -} +// URIRootError is deprecated, you should use repository.URIRootError instead +const URIRootError = repository.URIRootError From 64f22c217cb35ce0fe410b8a103be569fbee9cd2 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Tue, 12 Jan 2021 17:23:45 -0500 Subject: [PATCH 022/145] rename ReaderFrom to Reader in repository.Repository --- storage/repository/repository.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/repository/repository.go b/storage/repository/repository.go index 67897a8892..fdf3218824 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -43,11 +43,11 @@ type Repository interface { // Since 2.0.0 Exists(u fyne.URI) (bool, error) - // ReaderFrom will be used to implement calls to storage.ReaderFrom() + // Reader will be used to implement calls to storage.Reader() // for the registered scheme of this repository. // // Since 2.0.0 - ReaderFrom(u fyne.URI) (fyne.URIReadCloser, error) + Reader(u fyne.URI) (fyne.URIReadCloser, error) // CanRead will be used to implement calls to storage.CanRead() for the // registered scheme of this repository. From a8a4855ec9b5cc522c7aaed202c8e13353699abd Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Tue, 12 Jan 2021 17:55:42 -0500 Subject: [PATCH 023/145] add Since annotations to errors --- storage/repository/errors.go | 4 ++++ storage/uri_root_error.go | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/storage/repository/errors.go b/storage/repository/errors.go index ab25ea632b..743523fb74 100644 --- a/storage/repository/errors.go +++ b/storage/repository/errors.go @@ -10,6 +10,8 @@ type operationNotSupportedError string // 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.0 const OperationNotSupportedError operationNotSupportedError = operationNotSupportedError("Operation not supported for this URI.") func (e operationNotSupportedError) Error() string { @@ -25,6 +27,8 @@ type uriRootError string // 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.0 const URIRootError uriRootError = uriRootError("Cannot take the parent of the root element in a URI") func (e uriRootError) Error() string { diff --git a/storage/uri_root_error.go b/storage/uri_root_error.go index 22fab8af3c..7d7c5e2d41 100644 --- a/storage/uri_root_error.go +++ b/storage/uri_root_error.go @@ -4,5 +4,7 @@ import ( "fyne.io/fyne/storage/repository" ) -// URIRootError is deprecated, you should use repository.URIRootError instead +// URIRootError +// +// Deprecated - use repository.URIRootError instead const URIRootError = repository.URIRootError From 101b02cc6893bbff274918f57e5c85629f89a215 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Tue, 12 Jan 2021 18:22:48 -0500 Subject: [PATCH 024/145] Add CanonicalRepository interface --- storage/repository/repository.go | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/storage/repository/repository.go b/storage/repository/repository.go index fdf3218824..f4f50574a0 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -66,6 +66,24 @@ type Repository interface { Destroy(string) } +// CanonicalRepository 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.0 +type CanonicalRepository interface { + Repository + + // ParseURI will be used to implement calls to storage.ParseURI() + // for the registered scheme of this repository. + ParseURI(string) (fyne.URI, error) +} + // WriteableRepository is an extension of the Repository interface which also // supports obtaining a writer for URIs of the scheme it is registered to. // @@ -79,8 +97,8 @@ type WriteableRepository interface { // Since 2.0.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. + // CanWrite will be used to implement calls to storage.CanWrite() for + // the registered scheme of this repository. // // Since 2.0.0 CanWrite(u fyne.URI) (bool, error) From 74e6b6d54b055aaa93a7f4737248ee13ddf4b144 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Tue, 12 Jan 2021 20:34:22 -0500 Subject: [PATCH 025/145] implement initial version of MemoryRepository Currently it only implements WriteableRepository and Repository. --- internal/repository/memory.go | 219 ++++++++++++++++++++++++++++ internal/repository/memory_test.go | 224 +++++++++++++++++++++++++++++ storage/repository/repository.go | 22 ++- storage/uri.go | 81 ++++++++--- storage/uri_test.go | 11 ++ 5 files changed, 540 insertions(+), 17 deletions(-) create mode 100644 internal/repository/memory.go create mode 100644 internal/repository/memory_test.go diff --git a/internal/repository/memory.go b/internal/repository/memory.go new file mode 100644 index 0000000000..b6232e418f --- /dev/null +++ b/internal/repository/memory.go @@ -0,0 +1,219 @@ +package repository + +import ( + "fyne.io/fyne" + "fyne.io/fyne/storage" + "fyne.io/fyne/storage/repository" + + "fmt" + "io" +) + +// declare conformance to interfaces +var _ io.ReadCloser = &nodeReaderWriter{} +var _ io.WriteCloser = &nodeReaderWriter{} +var _ fyne.URIReadCloser = &nodeReaderWriter{} +var _ fyne.URIWriteCloser = &nodeReaderWriter{} + +// nodeReaderWriter allows reading or writing to elements in a MemoryRepository +type nodeReaderWriter struct { + path string + repo *MemoryRepository + writing bool + readCursor int + writeCursor int +} + +// 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 MemoryRepository", 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.URI*Closer.Name +func (n *nodeReaderWriter) Name() string { + return n.URI().Name() +} + +// Name implements fyne.URI*Closer.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 +} + +// declare conformance with repository types +var _ repository.Repository = &MemoryRepository{} +var _ repository.WriteableRepository = &MemoryRepository{} + +// MemoryRepository 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. +// +// Since 2.0.0 +type MemoryRepository struct { + data map[string][]byte + scheme string +} + +// NewMemoryRepository creates a new MemoryRepository 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.0 +func NewMemoryRepository(scheme string) *MemoryRepository { + return &MemoryRepository{ + data: make(map[string][]byte), + scheme: scheme, + } +} + +// Exists implements repository.Repository.Exists +// +// Since 2.0.0 +func (m *MemoryRepository) Exists(u fyne.URI) (bool, error) { + if u.Path() == "" { + return false, fmt.Errorf("Invalid path '%s'", u.Path()) + } + + _, ok := m.data[u.Path()] + return ok, nil +} + +// Reader implements repository.Repository.Reader +// +// Since 2.0.0 +func (m *MemoryRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { + if u.Path() == "" { + return nil, fmt.Errorf("Invalid path '%s'", u.Path()) + } + + _, ok := m.data[u.Path()] + if !ok { + return nil, fmt.Errorf("No such path '%s' in MemoryRepository", u.Path()) + } + + return &nodeReaderWriter{path: u.Path(), repo: m}, nil +} + +// CanRead implements repository.Repository.CanRead +// +// Since 2.0.0 +func (m *MemoryRepository) CanRead(u fyne.URI) (bool, error) { + if u.Path() == "" { + return false, fmt.Errorf("Invalid path '%s'", u.Path()) + } + + _, ok := m.data[u.Path()] + if !ok { + return false, fmt.Errorf("No such path '%s' in MemoryRepository", u.Path()) + } + + return true, nil +} + +// Destroy implements repository.Repository.Destroy +func (m *MemoryRepository) Destroy(scheme string) { + // do nothing +} + +// Writeer implements repository.Repository.Writer +// +// Since 2.0.0 +func (m *MemoryRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { + if u.Path() == "" { + return nil, fmt.Errorf("Invalid path '%s'", u.Path()) + } + + return &nodeReaderWriter{path: u.Path(), repo: m}, nil +} + +// CanWrite implements repository.Repository.CanWrite +// +// Since 2.0.0 +func (m *MemoryRepository) CanWrite(u fyne.URI) (bool, error) { + if u.Path() == "" { + return false, fmt.Errorf("Invalid path '%s'", u.Path()) + } + + return true, nil +} + +// Delete implements repository.Repository.Delete +// +// Since 2.0.0 +func (m *MemoryRepository) Delete(u fyne.URI) error { + _, ok := m.data[u.Path()] + if ok { + delete(m.data, u.Path()) + } + + return nil +} diff --git a/internal/repository/memory_test.go b/internal/repository/memory_test.go new file mode 100644 index 0000000000..5a1494cae6 --- /dev/null +++ b/internal/repository/memory_test.go @@ -0,0 +1,224 @@ +package repository + +import ( + "io/ioutil" + "testing" + + "fyne.io/fyne/storage" + "fyne.io/fyne/storage/repository" + + _ "fyne.io/fyne/test" + + "github.com/stretchr/testify/assert" +) + +func TestMemoryRepositoryRegistration(t *testing.T) { + m := NewMemoryRepository("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 := NewMemoryRepository("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 TestMemoryRepositoryExists(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewMemoryRepository("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 TestMemoryRepositoryReader(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewMemoryRepository("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 TestMemoryRepositoryCanRead(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewMemoryRepository("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.NotNil(t, err) +} + +func TestMemoryRepositoryWriter(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewMemoryRepository("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 TestMemoryRepositoryCanWrite(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewMemoryRepository("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) +} diff --git a/storage/repository/repository.go b/storage/repository/repository.go index f4f50574a0..8c1255edb3 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -6,6 +6,10 @@ import ( "fyne.io/fyne" ) +// 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 @@ -207,6 +211,13 @@ type MovableRepository interface { // // Since 2.0.0 func Register(scheme string, repository Repository) { + prev, ok := repositoryTable[scheme] + + if ok { + prev.Destroy(scheme) + } + + repositoryTable[scheme] = repository } // ForURI returns the Repository instance which is registered to handle URIs of @@ -215,6 +226,15 @@ func Register(scheme string, repository Repository) { // 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.0 func ForURI(u fyne.URI) (Repository, error) { - return nil, fmt.Errorf("TODO") + scheme := u.Scheme() + repo, ok := repositoryTable[scheme] + + if !ok { + return nil, fmt.Errorf("No repository registered for scheme '%s'", scheme) + } + + return repo, nil } diff --git a/storage/uri.go b/storage/uri.go index 8120d6471e..427de2e741 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -5,13 +5,13 @@ import ( "fmt" "mime" "net/url" - "os" "path/filepath" "runtime" "strings" "unicode/utf8" "fyne.io/fyne" + "fyne.io/fyne/storage/repository" ) // Declare conformance with fyne.URI interface @@ -309,20 +309,28 @@ func Child(u fyne.URI, component string) (fyne.URI, error) { // // 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()) - } - - _, err := os.Stat(u.String()[len(u.Scheme())+3:]) - if os.IsNotExist(err) { - return false, nil - } - + repo, err := repository.ForURI(u) if err != nil { return false, err } - return true, nil + return repo.Exists(u) + + // TODO: this needs to move to the file:// repository + // if u.Scheme() != "file" { + // return false, fmt.Errorf("don't know how to check existence of %s scheme", u.Scheme()) + // } + // + // _, err := os.Stat(u.String()[len(u.Scheme())+3:]) + // if os.IsNotExist(err) { + // return false, nil + // } + // + // if err != nil { + // return false, err + // } + // + // return true, nil } // Delete destroys, deletes, or otherwise removes the resource referenced @@ -346,7 +354,18 @@ func Exists(u fyne.URI) (bool, error) { // // Since: 2.0.0 func Delete(u fyne.URI) error { - return fmt.Errorf("TODO: implement this function") + repo, err := repository.ForURI(u) + if err != nil { + return err + } + + wrepo, ok := repo.(repository.WriteableRepository) + if !ok { + return repository.OperationNotSupportedError + } + + return wrepo.Delete(u) + } // Reader returns URIReadCloser set up to read from the resource that the @@ -370,7 +389,12 @@ func Delete(u fyne.URI) error { // // Since 2.0.0 func Reader(u fyne.URI) (fyne.URIReadCloser, error) { - return nil, fmt.Errorf("TODO: implement this function") + repo, err := repository.ForURI(u) + if err != nil { + return nil, err + } + + return repo.Reader(u) } // CanRead determines if a given URI could be written to using the Reader() @@ -384,7 +408,12 @@ func Reader(u fyne.URI) (fyne.URIReadCloser, error) { // // Since 2.0.0 func CanRead(u fyne.URI) (bool, error) { - return false, fmt.Errorf("TODO") + repo, err := repository.ForURI(u) + if err != nil { + return false, err + } + + return repo.CanRead(u) } // Writer returns URIWriteCloser set up to write to the resource that the @@ -412,7 +441,17 @@ func CanRead(u fyne.URI) (bool, error) { // // Since 2.0.0 func Writer(u fyne.URI) (fyne.URIWriteCloser, error) { - return nil, fmt.Errorf("TODO: implement this function") + repo, err := repository.ForURI(u) + if err != nil { + return nil, err + } + + wrepo, ok := repo.(repository.WriteableRepository) + if !ok { + return nil, repository.OperationNotSupportedError + } + + return wrepo.Writer(u) } // CanWrite determines if a given URI could be written to using the Writer() @@ -426,7 +465,17 @@ func Writer(u fyne.URI) (fyne.URIWriteCloser, error) { // // Since 2.0.0 func CanWrite(u fyne.URI) (bool, error) { - return false, fmt.Errorf("TODO") + repo, err := repository.ForURI(u) + if err != nil { + return false, err + } + + wrepo, ok := repo.(repository.WriteableRepository) + if !ok { + return false, repository.OperationNotSupportedError + } + + return wrepo.CanWrite(u) } // Copy given two URIs, 'src', and 'dest' both of the same scheme , will copy diff --git a/storage/uri_test.go b/storage/uri_test.go index 029dff67fb..4659f33b06 100644 --- a/storage/uri_test.go +++ b/storage/uri_test.go @@ -33,6 +33,17 @@ func TestURIPath(t *testing.T) { 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()) + // NOTE: this is currently broken, because net/url is not fully RFC3986 // compliant - it returns an empty string rather than the proper path. // From 99baec0291f4aa3e649d3fc2b0d10e83f6d56fc3 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Tue, 12 Jan 2021 20:36:12 -0500 Subject: [PATCH 026/145] fix linter errors --- internal/repository/memory.go | 2 +- storage/uri_root_error.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/repository/memory.go b/internal/repository/memory.go index b6232e418f..026150626f 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -184,7 +184,7 @@ func (m *MemoryRepository) Destroy(scheme string) { // do nothing } -// Writeer implements repository.Repository.Writer +// Writer implements repository.Repository.Writer // // Since 2.0.0 func (m *MemoryRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { diff --git a/storage/uri_root_error.go b/storage/uri_root_error.go index 7d7c5e2d41..ac843e2bf0 100644 --- a/storage/uri_root_error.go +++ b/storage/uri_root_error.go @@ -4,7 +4,7 @@ import ( "fyne.io/fyne/storage/repository" ) -// URIRootError +// URIRootError is a wrapper for repository.URIRootError // // Deprecated - use repository.URIRootError instead const URIRootError = repository.URIRootError From 930dd9c1fd2790ed8364709b038356b7999edb8b Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Tue, 12 Jan 2021 21:17:34 -0500 Subject: [PATCH 027/145] implement HierarchicalRepository for MemoryRepository --- internal/repository/memory.go | 35 ++++++++++---- internal/repository/memory_test.go | 32 +++++++++++++ storage/repository/generic.go | 67 ++++++++++++++++++++++++-- storage/repository/repository.go | 4 +- storage/uri.go | 76 ++++++++++++++++++------------ 5 files changed, 167 insertions(+), 47 deletions(-) diff --git a/internal/repository/memory.go b/internal/repository/memory.go index 026150626f..698f7c3d32 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -30,7 +30,7 @@ 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 MemoryRepository", n.path) + return 0, fmt.Errorf("path '%s' not present in MemoryRepository", n.path) } // copy it into p - we maintain counts since len(data) may be smaller @@ -110,6 +110,7 @@ func (n *nodeReaderWriter) URI() fyne.URI { // declare conformance with repository types var _ repository.Repository = &MemoryRepository{} var _ repository.WriteableRepository = &MemoryRepository{} +var _ repository.HierarchicalRepository = &MemoryRepository{} // MemoryRepository implements an in-memory version of the // repository.Repository type. It is useful for writing test cases, and may @@ -140,7 +141,7 @@ func NewMemoryRepository(scheme string) *MemoryRepository { // Since 2.0.0 func (m *MemoryRepository) Exists(u fyne.URI) (bool, error) { if u.Path() == "" { - return false, fmt.Errorf("Invalid path '%s'", u.Path()) + return false, fmt.Errorf("invalid path '%s'", u.Path()) } _, ok := m.data[u.Path()] @@ -152,12 +153,12 @@ func (m *MemoryRepository) Exists(u fyne.URI) (bool, error) { // Since 2.0.0 func (m *MemoryRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { if u.Path() == "" { - return nil, fmt.Errorf("Invalid path '%s'", u.Path()) + return nil, fmt.Errorf("invalid path '%s'", u.Path()) } _, ok := m.data[u.Path()] if !ok { - return nil, fmt.Errorf("No such path '%s' in MemoryRepository", u.Path()) + return nil, fmt.Errorf("no such path '%s' in MemoryRepository", u.Path()) } return &nodeReaderWriter{path: u.Path(), repo: m}, nil @@ -168,7 +169,7 @@ func (m *MemoryRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { // Since 2.0.0 func (m *MemoryRepository) CanRead(u fyne.URI) (bool, error) { if u.Path() == "" { - return false, fmt.Errorf("Invalid path '%s'", u.Path()) + return false, fmt.Errorf("invalid path '%s'", u.Path()) } _, ok := m.data[u.Path()] @@ -184,29 +185,29 @@ func (m *MemoryRepository) Destroy(scheme string) { // do nothing } -// Writer implements repository.Repository.Writer +// Writer implements repository.WriteableRepository.Writer // // Since 2.0.0 func (m *MemoryRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { if u.Path() == "" { - return nil, fmt.Errorf("Invalid path '%s'", u.Path()) + return nil, fmt.Errorf("invalid path '%s'", u.Path()) } return &nodeReaderWriter{path: u.Path(), repo: m}, nil } -// CanWrite implements repository.Repository.CanWrite +// CanWrite implements repository.WriteableRepository.CanWrite // // Since 2.0.0 func (m *MemoryRepository) CanWrite(u fyne.URI) (bool, error) { if u.Path() == "" { - return false, fmt.Errorf("Invalid path '%s'", u.Path()) + return false, fmt.Errorf("invalid path '%s'", u.Path()) } return true, nil } -// Delete implements repository.Repository.Delete +// Delete implements repository.WriteableRepository.Delete // // Since 2.0.0 func (m *MemoryRepository) Delete(u fyne.URI) error { @@ -217,3 +218,17 @@ func (m *MemoryRepository) Delete(u fyne.URI) error { return nil } + +// Parent implements repository.HierarchicalRepository.Parent +// +// Since 2.0.0 +func (m *MemoryRepository) Parent(u fyne.URI) (fyne.URI, error) { + return repository.GenericParent(u, storage.ParseURI) +} + +// Child implements repository.HierarchicalRepository.Child +// +// Since 2.0.0 +func (m *MemoryRepository) Child(u fyne.URI, component string) (fyne.URI, error) { + return repository.GenericChild(u, component, storage.ParseURI) +} diff --git a/internal/repository/memory_test.go b/internal/repository/memory_test.go index 5a1494cae6..e2933ca869 100644 --- a/internal/repository/memory_test.go +++ b/internal/repository/memory_test.go @@ -222,3 +222,35 @@ func TestMemoryRepositoryCanWrite(t *testing.T) { assert.True(t, bazCanWrite) assert.Nil(t, err) } + +func TestMemoryRepositoryParent(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewMemoryRepository("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 TestMemoryRepositoryChild(t *testing.T) { + // set up our repository - it's OK if we already registered it + m := NewMemoryRepository("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()) +} diff --git a/storage/repository/generic.go b/storage/repository/generic.go index 1db6421bfc..5bc444e83d 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -2,6 +2,7 @@ package repository import ( "fmt" + "strings" "fyne.io/fyne" ) @@ -14,12 +15,49 @@ import ( // 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 duplicate of the URI is returned, +// along with URIRootError. +// +// The parseURI parameter should be a function that you wish GenericParent to +// use to generate any new URIs it creates. Usually, storage.ParseURI is +// suitable here. +// // 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.0 -func GenericParent(u fyne.URI) (fyne.URI, error) { - return nil, fmt.Errorf("TODO") +func GenericParent(u fyne.URI, parseURI func(string) (fyne.URI, error)) (fyne.URI, error) { + + if u.Path() == "" || u.Path() == "/" { + parent, err := parseURI(u.String()) + if err != nil { + return nil, err + } + return parent, URIRootError + } + + components := strings.Split(u.Path(), "/") + + newURI := u.Scheme() + "://" + u.Authority() + + // there will be at least one component, since we know we don't have + // '/' or ''. + if len(components) == 1 { + // the immediate parent is the root + newURI += "/" + } else { + newURI += strings.Join(components[:len(components)-1], "/") + } + + // stick the query and fragment back on the end + if len(u.Query()) > 0 { + newURI += "?" + u.Query() + } + if len(u.Fragment()) > 0 { + newURI += "#" + u.Fragment() + } + + return parseURI(newURI) } // GenericChild can be used as a common-case implementation of @@ -28,12 +66,33 @@ func GenericParent(u fyne.URI) (fyne.URI, error) { // "/" + component to the path, then concatenating the result and parsing it as // a new URI. // +// The parseURI parameter should be a function that you wish GenericParent to +// use to generate any new URIs it creates. Usually, storage.ParseURI is +// suitable here. +// // 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.0 -func GenericChild(u fyne.URI, component string) (fyne.URI, error) { - return nil, fmt.Errorf("TODO") +func GenericChild(u fyne.URI, component string, parseURI func(string) (fyne.URI, error)) (fyne.URI, error) { + + // split into components and add the new one + components := strings.Split(u.Path(), "/") + components = append(components, component) + + // generate the scheme, authority, and path + newURI := u.Scheme() + "://" + u.Authority() + newURI += "/" + strings.Join(components[:len(components)-1], "/") + + // stick the query and fragment back on the end + if len(u.Query()) > 0 { + newURI += "?" + u.Query() + } + if len(u.Fragment()) > 0 { + newURI += "#" + u.Fragment() + } + + return parseURI(newURI) } // GenericCopy can be used a common-case implementation of diff --git a/storage/repository/repository.go b/storage/repository/repository.go index 8c1255edb3..fa14fc4f92 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -158,7 +158,7 @@ type HierarchicalRepository interface { // is based on RFC3986. // // Since 2.0.0 - Child(fyne.URI) (fyne.URI, error) + Child(fyne.URI, string) (fyne.URI, error) } // CopyableRepository is an extension of the Repository interface which also @@ -233,7 +233,7 @@ func ForURI(u fyne.URI) (Repository, error) { repo, ok := repositoryTable[scheme] if !ok { - return nil, fmt.Errorf("No repository registered for scheme '%s'", scheme) + return nil, fmt.Errorf("no repository registered for scheme '%s'", scheme) } return repo, nil diff --git a/storage/uri.go b/storage/uri.go index 427de2e741..25209f3a69 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -209,43 +209,57 @@ func ParseURI(s string) (fyne.URI, error) { // // Since: 1.4 func Parent(u fyne.URI) (fyne.URI, error) { - s := u.String() - // trim trailing slash - if s[len(s)-1] == '/' { - s = s[0 : len(s)-1] + repo, err := repository.ForURI(u) + if err != nil { + return nil, err } - // trim the scheme - s = s[len(u.Scheme())+3:] - - // Completely empty URI with just a scheme - if len(s) == 0 { - return nil, URIRootError + hrepo, ok := repo.(repository.HierarchicalRepository) + if !ok { + return nil, repository.OperationNotSupportedError } - parent := "" - if u.Scheme() == "file" { - // 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, URIRootError - } - - } else { - var err error - parent, err = parentGeneric(s) - if err != nil { - return nil, err - } - } + return hrepo.Parent(u) - return ParseURI(u.Scheme() + "://" + parent) + // TODO: move this to the file:// repository + // s := u.String() + // + // // trim trailing slash + // if s[len(s)-1] == '/' { + // s = s[0 : len(s)-1] + // } + // + // // trim the scheme + // s = s[len(u.Scheme())+3:] + // + // // Completely empty URI with just a scheme + // if len(s) == 0 { + // return nil, URIRootError + // } + // + // parent := "" + // if u.Scheme() == "file" { + // // 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, URIRootError + // } + // + // } else { + // var err error + // parent, err = parentGeneric(s) + // if err != nil { + // return nil, err + // } + // } + // + // return ParseURI(u.Scheme() + "://" + parent) } // Child returns a URI referencing a resource nested hierarchically below the From 5c58f5f45108671158da7d746917f71a8a05e3d0 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Tue, 12 Jan 2021 21:59:14 -0500 Subject: [PATCH 028/145] first-pass implementation of FileRepository This still does not implement CopyableRepository or MoveableRepository. We may want to look at the URI parsing, and put some of the smarts used for path separator handling into a `CanonicalRepository` for it. We also still need to decide where/how the driver will register it to the `file://` repository during start-up. I also have no idea if this even works or compiles, haven't tested it yet at all. --- internal/repository/file.go | 255 ++++++++++++++++++++++++++++++++++ internal/repository/memory.go | 13 +- storage/uri.go | 80 +---------- 3 files changed, 274 insertions(+), 74 deletions(-) create mode 100644 internal/repository/file.go diff --git a/internal/repository/file.go b/internal/repository/file.go new file mode 100644 index 0000000000..3432e07ad2 --- /dev/null +++ b/internal/repository/file.go @@ -0,0 +1,255 @@ +package repository + +import ( + "fyne.io/fyne" + "fyne.io/fyne/storage" + "fyne.io/fyne/storage/repository" + + "fmt" + "io" + "os" + "path/filepath" +) + +// declare conformance with repository types +var _ repository.Repository = &FileRepository{} +var _ repository.WriteableRepository = &FileRepository{} +var _ repository.HierarchicalRepository = &FileRepository{} +var _ repository.ListableRepository = &FileRepository{} + +type file struct { + *os.File + path string +} + +// 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 file:// schemes. +// +// Since 2.0.0 +type FileRepository struct { +} + +// NewFileRepository creates a new FileRepository 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.0 +func NewFileRepository(scheme string) *FileRepository { + return &FileRepository{} +} + +// Exists implements repository.Repository.Exists +// +// Since 2.0.0 +func (r *FileRepository) Exists(u fyne.URI) (bool, error) { + p := u.Path() + + _, err := os.Stat(p) + ok := false + + if err == nil { + ok = true + } + + if os.IsNotExist(err) { + err = nil + } + + return ok, err +} + +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 +} + +// Reader implements repository.Repository.Reader +// +// Since 2.0.0 +func (r *FileRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { + return openFile(u, false) +} + +// CanRead implements repository.Repository.CanRead +// +// Since 2.0.0 +func (r *FileRepository) CanRead(u fyne.URI) (bool, error) { + f, err := os.OpenFile(u.Path(), os.RDONLY, 0666) + defer f.Close() + + if os.IsPermission(err) { + return false, nil + } + + if os.IsNotExist(err) { + return false, nil + } + + if err != nil { + return false, err + } + + return true, nil +} + +// Destroy implements repository.Repository.Destroy +func (r *FileRepository) Destroy(scheme string) { + // do nothing +} + +// Writer implements repository.WriteableRepository.Writer +// +// Since 2.0.0 +func (r *FileRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { + return openFile(uri, true) +} + +// CanWrite implements repository.WriteableRepository.CanWrite +// +// Since 2.0.0 +func (r *FileRepository) CanWrite(u fyne.URI) (bool, error) { + f, err := os.OpenFile(u.Path(), os.WRONLY, 0666) + defer f.Close() + + if os.IsPermission(err) { + return false, nil + } + + if err != nil { + return false, err + } + + return true, nil +} + +// Delete implements repository.WriteableRepository.Delete +// +// Since 2.0.0 +func (r *FileRepository) Delete(u fyne.URI) error { + return os.Remove(u.Path()) +} + +// Parent implements repository.HierarchicalRepository.Parent +// +// Since 2.0.0 +func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { + s := u.String() + + // trim trailing slash + if s[len(s)-1] == '/' { + s = s[0 : len(s)-1] + } + + // trim the scheme + s = s[len(u.Scheme())+3:] + + // Completely empty URI with just a scheme + if len(s) == 0 { + return nil, repository.URIRootError + } + + parent := "" + if u.Scheme() == "file" { + // 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.URIRootError + } + + } else { + var err error + parent, err = parentGeneric(s) + if err != nil { + return nil, err + } + } + + return ParseURI(u.Scheme() + "://" + parent) +} + +// Child implements repository.HierarchicalRepository.Child +// +// Since 2.0.0 +func (r *FileRepository) Child(u fyne.URI, component string) (fyne.URI, error) { + // TODO: make sure that this works on Windows - might cause trouble + // if the path sep isn't normalized out on ingest. + return repository.GenericChild(u, component, storage.ParseURI) +} + +// List implements repository.HierarchicalRepository.List() +// +// Since 2.0.0 +func (r *FileRepository) List(u fyne.URI) ([]fyne.URI, error) { + if u.Scheme() != "file" { + return nil, fmt.Errorf("unsupported URL protocol") + } + + path := u.Path() + files, err := ioutil.ReadDir(path) + if err != nil { + return nil, err + } + + urilist := []fyne.URI{} + + for _, f := range files { + uri, err := storage.ParseURI("file://" + filepath.Join(path, f.Name())) + if err != nil { + return nil, err + } + urilist = append(urilist, uri) + } + + return urilist, nil +} + +// CanList implements repository.HierarchicalRepository.CanList() +// +// Since 2.0.0 +func (r *FileRepository) CanList(u fyne.URI) (bool, error) { + info, err := os.Stat(u.Path()) + + if os.IsNotExist(err) { + return false, nil + } + + if err != 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. + _, err := ioutil.ReadDir(path) + if os.IsPermission(err) { + return false, nil + } + if err != nil { + return false, err + } + + // it is a directory, and checking the permissions did not error out + return true, nil +} diff --git a/internal/repository/memory.go b/internal/repository/memory.go index 698f7c3d32..d6017cbb0a 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -118,6 +118,17 @@ var _ repository.HierarchicalRepository = &MemoryRepository{} // "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.0 type MemoryRepository struct { data map[string][]byte @@ -174,7 +185,7 @@ func (m *MemoryRepository) CanRead(u fyne.URI) (bool, error) { _, ok := m.data[u.Path()] if !ok { - return false, fmt.Errorf("No such path '%s' in MemoryRepository", u.Path()) + return false, fmt.Errorf("no such path '%s' in MemoryRepository", u.Path()) } return true, nil diff --git a/storage/uri.go b/storage/uri.go index 25209f3a69..967bb0456d 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -14,9 +14,13 @@ import ( "fyne.io/fyne/storage/repository" ) -// Declare conformance with fyne.URI interface +// Declare conformance with fyne.URI interface. var _ fyne.URI = &uri{} +// For backwards-compatibility with the now-deprecated ListableURI type, we +// also declare conformance with that. +var _ fyne.ListableURI = &uri{} + type uri struct { raw string } @@ -107,39 +111,8 @@ func (u *uri) Fragment() string { return r.Fragment } -// 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) { - - // trim leading forward slashes - trimmed := 0 - for location[0] == '/' { - location = location[1:] - trimmed++ - - // if all we have left is an empty string, than this URI - // pointed to a UNIX-style root - if len(location) == 0 { - return "", URIRootError - } - } - - components := strings.Split(location, "/") - - if len(components) == 1 { - return "", URIRootError - } - - 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 + "/" - } - parent = parent + strings.Join(components[0:len(components)-1], "/") + "/" - - return parent, nil +func (u *uri) List() ([]fyne.URI, error) { + return List(u) } // NewURI creates a new URI from the given string representation. This could be @@ -221,45 +194,6 @@ func Parent(u fyne.URI) (fyne.URI, error) { } return hrepo.Parent(u) - - // TODO: move this to the file:// repository - // s := u.String() - // - // // trim trailing slash - // if s[len(s)-1] == '/' { - // s = s[0 : len(s)-1] - // } - // - // // trim the scheme - // s = s[len(u.Scheme())+3:] - // - // // Completely empty URI with just a scheme - // if len(s) == 0 { - // return nil, URIRootError - // } - // - // parent := "" - // if u.Scheme() == "file" { - // // 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, URIRootError - // } - // - // } else { - // var err error - // parent, err = parentGeneric(s) - // if err != nil { - // return nil, err - // } - // } - // - // return ParseURI(u.Scheme() + "://" + parent) } // Child returns a URI referencing a resource nested hierarchically below the From 4310b9a53ebf9924429ef2af976cf79e92703439 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 13 Jan 2021 16:52:44 +0000 Subject: [PATCH 029/145] Fix compile errors --- internal/repository/file.go | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index 3432e07ad2..6e0ffe34d9 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -1,14 +1,14 @@ package repository import ( - "fyne.io/fyne" - "fyne.io/fyne/storage" - "fyne.io/fyne/storage/repository" - "fmt" - "io" + "io/ioutil" "os" "path/filepath" + + "fyne.io/fyne" + "fyne.io/fyne/storage" + "fyne.io/fyne/storage/repository" ) // declare conformance with repository types @@ -17,9 +17,16 @@ var _ repository.WriteableRepository = &FileRepository{} var _ repository.HierarchicalRepository = &FileRepository{} var _ repository.ListableRepository = &FileRepository{} +var _ fyne.URIReadCloser = &file{} +var _ fyne.URIWriteCloser = &file{} + type file struct { *os.File - path string + uri fyne.URI +} + +func (f *file) URI() fyne.URI { + return f.uri } // FileRepository implements a simple wrapper around golang's filesystem @@ -74,7 +81,7 @@ func openFile(uri fyne.URI, create bool) (*file, error) { } else { f, err = os.Open(path) } - return &file{File: f, path: path}, err + return &file{File: f, uri: uri}, err } // Reader implements repository.Repository.Reader @@ -88,7 +95,7 @@ func (r *FileRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { // // Since 2.0.0 func (r *FileRepository) CanRead(u fyne.URI) (bool, error) { - f, err := os.OpenFile(u.Path(), os.RDONLY, 0666) + f, err := os.OpenFile(u.Path(), os.O_RDONLY, 0666) defer f.Close() if os.IsPermission(err) { @@ -115,14 +122,14 @@ func (r *FileRepository) Destroy(scheme string) { // // Since 2.0.0 func (r *FileRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { - return openFile(uri, true) + return openFile(u, true) } // CanWrite implements repository.WriteableRepository.CanWrite // // Since 2.0.0 func (r *FileRepository) CanWrite(u fyne.URI) (bool, error) { - f, err := os.OpenFile(u.Path(), os.WRONLY, 0666) + f, err := os.OpenFile(u.Path(), os.O_WRONLY, 0666) defer f.Close() if os.IsPermission(err) { @@ -175,15 +182,15 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { return nil, repository.URIRootError } + return storage.ParseURI(u.Scheme() + "://" + parent) } else { var err error - parent, err = parentGeneric(s) + parent, err := repository.GenericParent(u, storage.ParseURI) if err != nil { return nil, err } + return parent, nil } - - return ParseURI(u.Scheme() + "://" + parent) } // Child implements repository.HierarchicalRepository.Child @@ -242,7 +249,7 @@ func (r *FileRepository) CanList(u fyne.URI) (bool, error) { // 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. - _, err := ioutil.ReadDir(path) + _, err = ioutil.ReadDir(u.Path()) if os.IsPermission(err) { return false, nil } From 543d4b986b56de8672572900e956b98ddff6d6b9 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 13 Jan 2021 17:12:42 +0000 Subject: [PATCH 030/145] Complete the list behaviour, many previous tests now passing We should not always implement ListableURI, it means we can list, so we default to not implementing it. --- storage/uri.go | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/storage/uri.go b/storage/uri.go index 967bb0456d..eb02bb7ee9 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -17,10 +17,6 @@ import ( // Declare conformance with fyne.URI interface. var _ fyne.URI = &uri{} -// For backwards-compatibility with the now-deprecated ListableURI type, we -// also declare conformance with that. -var _ fyne.ListableURI = &uri{} - type uri struct { raw string } @@ -111,10 +107,6 @@ func (u *uri) Fragment() string { return r.Fragment } -func (u *uri) List() ([]fyne.URI, error) { - return List(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() // @@ -505,7 +497,17 @@ func Move(source fyne.URI, destination fyne.URI) error { // // Since 2.0.0 func CanList(u fyne.URI) (bool, error) { - return false, fmt.Errorf("TODO: implement this function") + repo, err := repository.ForURI(u) + if err != nil { + return false, err + } + + lrepo, ok := repo.(repository.ListableRepository) + if !ok { + return false, repository.OperationNotSupportedError + } + + return lrepo.CanList(u) } // List returns a list of URIs that reference resources which are nested below @@ -535,5 +537,15 @@ func CanList(u fyne.URI) (bool, error) { // // Since 2.0.0 func List(u fyne.URI) ([]fyne.URI, error) { - return nil, fmt.Errorf("TODO") + repo, err := repository.ForURI(u) + if err != nil { + return nil, err + } + + lrepo, ok := repo.(repository.ListableRepository) + if !ok { + return nil, repository.OperationNotSupportedError + } + + return lrepo.List(u) } From febdb5f1eb12e06d6aeb498e8af03e05a2e1588e Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 13 Jan 2021 17:16:07 +0000 Subject: [PATCH 031/145] Hook up test file repository and disable a couple of tests until we have an http repository Now tests all pass --- internal/repository/file.go | 13 +++++------ internal/repository/memory_test.go | 2 -- storage/uri_test.go | 35 +++++++++++++++--------------- test/testdriver.go | 3 +++ 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index 6e0ffe34d9..451dac1374 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -183,14 +183,13 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { } return storage.ParseURI(u.Scheme() + "://" + parent) - } else { - var err error - parent, err := repository.GenericParent(u, storage.ParseURI) - if err != nil { - return nil, err - } - return parent, nil } + + uri, err := repository.GenericParent(u, storage.ParseURI) + if err != nil { + return nil, err + } + return uri, nil } // Child implements repository.HierarchicalRepository.Child diff --git a/internal/repository/memory_test.go b/internal/repository/memory_test.go index e2933ca869..d1f9c7c4f1 100644 --- a/internal/repository/memory_test.go +++ b/internal/repository/memory_test.go @@ -7,8 +7,6 @@ import ( "fyne.io/fyne/storage" "fyne.io/fyne/storage/repository" - _ "fyne.io/fyne/test" - "github.com/stretchr/testify/assert" ) diff --git a/storage/uri_test.go b/storage/uri_test.go index 4659f33b06..9736ccd2e9 100644 --- a/storage/uri_test.go +++ b/storage/uri_test.go @@ -134,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, 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()) if runtime.GOOS == "windows" { // Only the Windows version of filepath will know how to handle diff --git a/test/testdriver.go b/test/testdriver.go index 0895512486..0edf80f4dd 100644 --- a/test/testdriver.go +++ b/test/testdriver.go @@ -9,6 +9,8 @@ import ( "fyne.io/fyne/internal/driver" "fyne.io/fyne/internal/painter" "fyne.io/fyne/internal/painter/software" + intRepo "fyne.io/fyne/internal/repository" + "fyne.io/fyne/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("file")) // make a single dummy window for rendering tests drv.CreateWindow("") From 1e1b49bf5529b59797e163c1cf380611ca1a575e Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 13 Jan 2021 17:17:19 +0000 Subject: [PATCH 032/145] Wrap the current mobile code in the new repository scheme --- internal/driver/gomobile/driver.go | 2 ++ internal/driver/gomobile/file_android.go | 7 +++++ internal/driver/gomobile/file_desktop.go | 7 +++++ internal/driver/gomobile/file_ios.go | 7 +++++ internal/driver/gomobile/repository.go | 34 ++++++++++++++++++++++++ 5 files changed, 57 insertions(+) create mode 100644 internal/driver/gomobile/repository.go diff --git a/internal/driver/gomobile/driver.go b/internal/driver/gomobile/driver.go index 002ab8ff88..0d8574740c 100644 --- a/internal/driver/gomobile/driver.go +++ b/internal/driver/gomobile/driver.go @@ -414,5 +414,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_android.go b/internal/driver/gomobile/file_android.go index 4e049f9abb..05bc8f03ff 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/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..98b74cac49 100644 --- a/internal/driver/gomobile/file_desktop.go +++ b/internal/driver/gomobile/file_desktop.go @@ -6,6 +6,9 @@ import ( "errors" "io" "os" + + intRepo "fyne.io/fyne/internal/repository" + "fyne.io/fyne/storage/repository" ) func nativeFileOpen(f *fileOpen) (io.ReadCloser, error) { @@ -15,3 +18,7 @@ func nativeFileOpen(f *fileOpen) (io.ReadCloser, error) { return os.Open(f.uri.String()[7:]) } + +func registerRepository(d *mobileDriver) { + repository.Register("file", intRepo.NewFileRepository("file")) +} diff --git a/internal/driver/gomobile/file_ios.go b/internal/driver/gomobile/file_ios.go index bc69585190..d76d9cb2bd 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/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/repository.go b/internal/driver/gomobile/repository.go new file mode 100644 index 0000000000..2cf8f2cb9c --- /dev/null +++ b/internal/driver/gomobile/repository.go @@ -0,0 +1,34 @@ +package gomobile + +import ( + "fyne.io/fyne" +) + +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 m.driver.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) +} + +// TODO add write support (not yet supported on mobile) From c754994f496522986252f7c986f2cf0dd71737eb Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 13 Jan 2021 17:27:56 +0000 Subject: [PATCH 033/145] Use internal file handling for mobile simulator Fixes #1470 --- internal/driver/gomobile/folder_desktop.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/internal/driver/gomobile/folder_desktop.go b/internal/driver/gomobile/folder_desktop.go index 72218bc25f..0aa3e488a5 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" + "fyne.io/fyne/storage" +) -func canListURI(fyne.URI) bool { - return false +func canListURI(u fyne.URI) bool { + listable, _ := storage.CanList(u) + return listable } -func listURI(fyne.URI) ([]fyne.URI, error) { - return nil, nil +func listURI(u fyne.URI) ([]fyne.URI, error) { + return storage.List(u) } From a568809b5a27d10449df8d8aaf9c2ca08600c5e4 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 13 Jan 2021 17:55:27 +0000 Subject: [PATCH 034/145] Fix staticcheck errors --- internal/driver/gomobile/repository.go | 2 ++ internal/repository/file.go | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/internal/driver/gomobile/repository.go b/internal/driver/gomobile/repository.go index 2cf8f2cb9c..4c626786e1 100644 --- a/internal/driver/gomobile/repository.go +++ b/internal/driver/gomobile/repository.go @@ -1,3 +1,5 @@ +// +build ios android + package gomobile import ( diff --git a/internal/repository/file.go b/internal/repository/file.go index 451dac1374..d0f7b7549a 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -96,7 +96,9 @@ func (r *FileRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { // Since 2.0.0 func (r *FileRepository) CanRead(u fyne.URI) (bool, error) { f, err := os.OpenFile(u.Path(), os.O_RDONLY, 0666) - defer f.Close() + if err == nil { + defer f.Close() + } if os.IsPermission(err) { return false, nil @@ -130,7 +132,9 @@ func (r *FileRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { // Since 2.0.0 func (r *FileRepository) CanWrite(u fyne.URI) (bool, error) { f, err := os.OpenFile(u.Path(), os.O_WRONLY, 0666) - defer f.Close() + if err == nil { + defer f.Close() + } if os.IsPermission(err) { return false, nil From 66f8334becd5e190d8e03d59264403fd18d2c515 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Wed, 13 Jan 2021 14:53:07 -0500 Subject: [PATCH 035/145] keep parsed URI components in uri type also hook up the file repository in the GLFW driver --- internal/driver/glfw/driver.go | 4 ++ storage/uri.go | 87 ++++++++++++++++++++-------------- 2 files changed, 55 insertions(+), 36 deletions(-) diff --git a/internal/driver/glfw/driver.go b/internal/driver/glfw/driver.go index 4d58d9ff7b..3a39baa274 100644 --- a/internal/driver/glfw/driver.go +++ b/internal/driver/glfw/driver.go @@ -12,6 +12,8 @@ import ( "fyne.io/fyne/internal/animation" "fyne.io/fyne/internal/driver" "fyne.io/fyne/internal/painter" + intRepo "fyne.io/fyne/internal/repository" + "fyne.io/fyne/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("file")) + return d } diff --git a/storage/uri.go b/storage/uri.go index eb02bb7ee9..09f2d72a15 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -18,7 +18,15 @@ import ( var _ fyne.URI = &uri{} type uri struct { - raw string + 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 } // NewFileURI creates a new URI from the given file path. @@ -32,22 +40,30 @@ func NewFileURI(path string) fyne.URI { // double-backslashes path = filepath.ToSlash(path) } - return &uri{raw: "file://" + path} + + return &uri{ + scheme: "file", + haveAuthority: true, + authority: "", + path: path, + query: "", + fragment: "", + } } func (u *uri) Extension() string { - return filepath.Ext(u.raw) + return filepath.Ext(u.path) } func (u *uri) Name() string { - return filepath.Base(u.raw) + return filepath.Base(u.path) } func (u *uri) MimeType() string { mimeTypeFull := mime.TypeByExtension(u.Extension()) if mimeTypeFull == "" { mimeTypeFull = "text/plain" - readCloser, err := fyne.CurrentApp().Driver().FileReaderForURI(u) + readCloser, err := Reader(u) if err == nil { defer readCloser.Close() scanner := bufio.NewScanner(readCloser) @@ -61,50 +77,41 @@ func (u *uri) MimeType() string { } func (u *uri) Scheme() string { - pos := strings.Index(u.raw, ":") - if pos == -1 { - return "" - } - - return strings.ToLower(u.raw[:pos]) + return u.scheme } func (u *uri) String() string { - return u.raw -} - -func (u *uri) Authority() string { - // NOTE: we verified in ParseURI() that this would not error. - r, _ := url.Parse(u.raw) + // NOTE: this string reconstruction is mandated by IETF RFC3986, + // section 5.3, pp. 35. - a := "" - if len(r.User.String()) > 0 { - a = r.User.String() + "@" + s := u.scheme + ":" + if u.haveAuthority { + s += "//" + u.authority } - a = a + r.Host + s += u.path + if len(u.query) > 0 { + s += "?" + u.query + } + if len(u.fragment) > 0 { + s += "#" + u.fragment + } + return s +} - return a +func (u *uri) Authority() string { + return u.authority } func (u *uri) Path() string { - // NOTE: we verified in ParseURI() that this would not error. - r, _ := url.Parse(u.raw) - - return r.Path + return u.path } func (u *uri) Query() string { - // NOTE: we verified in ParseURI() that this would not error. - r, _ := url.Parse(u.raw) - - return r.RawQuery + return u.query } func (u *uri) Fragment() string { - // NOTE: we verified in ParseURI() that this would not error. - r, _ := url.Parse(u.raw) - - return r.Fragment + return u.fragment } // NewURI creates a new URI from the given string representation. This could be @@ -133,12 +140,20 @@ func ParseURI(s string) (fyne.URI, error) { s = NewFileURI(path).String() } - _, err := url.Parse(s) + l, err := url.Parse(s) if err != nil { return nil, err } - return &uri{raw: s}, nil + return &uri{ + scheme: l.Scheme, + authority: l.User.String() + l.Host, + // workaround for net/url, see type uri struct comments + haveAuthority: true, + path: l.Path, + query: l.RawQuery, + fragment: l.Fragment, + }, nil } // Parent returns a URI referencing the parent resource of the resource From 4849b1dee34ba627e5950edfdc3d1f193fd85b7a Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 13 Jan 2021 21:04:54 +0000 Subject: [PATCH 036/145] Deprecate the old storage API, and remove it from most usages internally File dialog exposes ListablURI and it will take some time to unpick that one --- canvas/image.go | 2 +- dialog/file.go | 39 ++++++++++++++++++++------------ storage/file.go | 6 +++++ storage/resource.go | 2 +- widget/fileicon.go | 9 ++++---- widget/fileicon_internal_test.go | 10 ++------ 6 files changed, 38 insertions(+), 30 deletions(-) diff --git a/canvas/image.go b/canvas/image.go index 154c10d529..24bec7a4d2 100644 --- a/canvas/image.go +++ b/canvas/image.go @@ -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 diff --git a/dialog/file.go b/dialog/file.go index 77dbc74429..65631f3753 100644 --- a/dialog/file.go +++ b/dialog/file.go @@ -1,6 +1,7 @@ package dialog import ( + "errors" "fmt" "os" "path/filepath" @@ -91,16 +92,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) @@ -114,7 +115,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) } @@ -125,7 +126,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() @@ -257,11 +258,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)) } @@ -273,13 +274,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.Children = nil @@ -300,10 +305,14 @@ 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.Append( widget.NewButton(d, func() { err := f.setLocation(newDir) @@ -318,7 +327,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 } @@ -329,11 +338,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/storage/file.go b/storage/file.go index 67e401823f..a8e5913cc5 100644 --- a/storage/file.go +++ b/storage/file.go @@ -7,12 +7,16 @@ import ( // 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) } // 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) } @@ -21,6 +25,8 @@ func SaveFileToURI(uri fyne.URI) (fyne.URIWriteCloser, error) { // standard URI into a listable URI. // // Since: 1.4 +// +// Deprecated: this has been replaced by storage.List(URI) func ListerForURI(uri fyne.URI) (fyne.ListableURI, error) { if lister, ok := uri.(fyne.ListableURI); ok { return lister, nil diff --git a/storage/resource.go b/storage/resource.go index 1e1c13087d..fee1e80ac1 100644 --- a/storage/resource.go +++ b/storage/resource.go @@ -10,7 +10,7 @@ import ( // 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/widget/fileicon.go b/widget/fileicon.go index 3550ad890e..2038e778c9 100644 --- a/widget/fileicon.go +++ b/widget/fileicon.go @@ -112,12 +112,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..f2da8f11c1 100644 --- a/widget/fileicon_internal_test.go +++ b/widget/fileicon_internal_test.go @@ -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) From 24e1c32e67cb9e4237917f4449f15f6c25fbb67a Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 13 Jan 2021 21:09:07 +0000 Subject: [PATCH 037/145] Deprecations of driver and remove old URI.Name() --- driver.go | 6 ++++++ internal/driver/glfw/file.go | 4 ---- internal/driver/gomobile/file.go | 4 ---- internal/repository/memory.go | 5 ----- uri.go | 6 ++---- 5 files changed, 8 insertions(+), 17 deletions(-) diff --git a/driver.go b/driver.go index 9cfc81d150..d03450afcc 100644 --- a/driver.go +++ b/driver.go @@ -14,13 +14,19 @@ type Driver interface { // FileReaderForURI opens a file reader for the given resource indicator. // This may refer to a filesystem (typical on desktop) or data from another application. + // + // Deprecated: this has been replaced by storage.Reader(URI) 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. + // + // Deprecated: this has been replaced by storage.Writer(URI) FileWriterForURI(URI) (URIWriteCloser, error) // ListerForURI converts a URI to a listable URI, if it is possible to do so. + // + // Deprecated: this has been replaced by storage.List(URI) ListerForURI(URI) (ListableURI, error) // CanvasForObject returns the canvas that is associated with a given CanvasObject. diff --git a/internal/driver/glfw/file.go b/internal/driver/glfw/file.go index ad11c9bb26..8d87ca923f 100644 --- a/internal/driver/glfw/file.go +++ b/internal/driver/glfw/file.go @@ -65,10 +65,6 @@ 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) } diff --git a/internal/driver/gomobile/file.go b/internal/driver/gomobile/file.go index b723464d15..7d1b172c47 100644 --- a/internal/driver/gomobile/file.go +++ b/internal/driver/gomobile/file.go @@ -16,10 +16,6 @@ type fileOpen struct { done func() } -func (f *fileOpen) Name() string { - return f.uri.Name() -} - func (f *fileOpen) URI() fyne.URI { return f.uri } diff --git a/internal/repository/memory.go b/internal/repository/memory.go index d6017cbb0a..3cd3d87912 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -93,11 +93,6 @@ func (n *nodeReaderWriter) Write(p []byte) (int, error) { return count, nil } -// Name implements fyne.URI*Closer.Name -func (n *nodeReaderWriter) Name() string { - return n.URI().Name() -} - // Name implements fyne.URI*Closer.URI func (n *nodeReaderWriter) URI() fyne.URI { diff --git a/uri.go b/uri.go index 4a1bcae888..3862319464 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,8 +17,7 @@ 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 } From cb7f485e88852f9b9649c763b686bcaf90c6b6dd Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 13 Jan 2021 21:20:16 +0000 Subject: [PATCH 038/145] Stop using the old driver code --- storage/file.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/file.go b/storage/file.go index a8e5913cc5..7341460be6 100644 --- a/storage/file.go +++ b/storage/file.go @@ -10,7 +10,7 @@ import ( // // 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. @@ -18,7 +18,7 @@ func OpenFileFromURI(uri fyne.URI) (fyne.URIReadCloser, error) { // // 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 From f12172d17270a7fa55098ccd785aa056a9fc8fb3 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 13 Jan 2021 21:38:23 +0000 Subject: [PATCH 039/145] Add listing wrapper for legacy support --- storage/file.go | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/storage/file.go b/storage/file.go index 7341460be6..fa2493da83 100644 --- a/storage/file.go +++ b/storage/file.go @@ -2,6 +2,8 @@ package storage import ( + "errors" + "fyne.io/fyne" ) @@ -28,8 +30,21 @@ func SaveFileToURI(uri fyne.URI) (fyne.URIWriteCloser, error) { // // Deprecated: this has been replaced by storage.List(URI) 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 + } + if !listable { + return nil, errors.New("uri is not listable") } - return fyne.CurrentApp().Driver().ListerForURI(uri) + + return &legacyListable{uri}, nil +} + +type legacyListable struct { + fyne.URI +} + +func (l *legacyListable) List() ([]fyne.URI, error) { + return List(l.URI) } From 722558e684bab63dec5bdd07431b955011149ab8 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Wed, 13 Jan 2021 16:55:43 -0500 Subject: [PATCH 040/145] remove unused glfw/file.go codepaths What is left is just a wrapper around the storage.* methods. --- internal/driver/glfw/file.go | 81 +++--------------------------------- 1 file changed, 6 insertions(+), 75 deletions(-) diff --git a/internal/driver/glfw/file.go b/internal/driver/glfw/file.go index 8d87ca923f..4d7e734ac8 100644 --- a/internal/driver/glfw/file.go +++ b/internal/driver/glfw/file.go @@ -1,90 +1,21 @@ 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 -} - +// ListerForURI - deprecated in 2.0.0 - use storage.List() and storage.CanList() instead 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 + return storage.ListerForURI(uri) } +// FileReaderForURI - deprecated in 2.0.0 - use storage.Reader() instead func (d *gLDriver) FileReaderForURI(uri fyne.URI) (fyne.URIReadCloser, error) { - return openFile(uri, false) -} - -func (f *file) URI() fyne.URI { - return storage.NewURI("file://" + f.path) + return storage.Reader(uri) } +// FileWriterForURI - deprecated in 2.0.0 - use storage.Writer() instead 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 + return storage.Writer(uri) } From 26e7a0e31c5018fff46f5d15980ee52527291fd2 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Wed, 13 Jan 2021 17:05:26 -0500 Subject: [PATCH 041/145] implement Stuart's suggestions --- internal/driver/glfw/file.go | 12 +++++++++--- internal/repository/file.go | 36 +++++++++++++++++------------------ storage/repository/generic.go | 14 +++++++++----- 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/internal/driver/glfw/file.go b/internal/driver/glfw/file.go index 4d7e734ac8..f9b9179f72 100644 --- a/internal/driver/glfw/file.go +++ b/internal/driver/glfw/file.go @@ -5,17 +5,23 @@ import ( "fyne.io/fyne/storage" ) -// ListerForURI - deprecated in 2.0.0 - use storage.List() and storage.CanList() instead +// ListerForURI - wrapper for backwards-compatibility +// +// Deprecated: in 2.0.0 - use storage.List() and storage.CanList() instead func (d *gLDriver) ListerForURI(uri fyne.URI) (fyne.ListableURI, error) { return storage.ListerForURI(uri) } -// FileReaderForURI - deprecated in 2.0.0 - use storage.Reader() instead +// FileReaderForURI - wrapper for backwards-compatibility +// +// Deprecated: in 2.0.0 - use storage.Reader() instead func (d *gLDriver) FileReaderForURI(uri fyne.URI) (fyne.URIReadCloser, error) { return storage.Reader(uri) } -// FileWriterForURI - deprecated in 2.0.0 - use storage.Writer() instead +// FileWriterForURI - wrapper for backwards-compatibility +// +// Deprecated: in 2.0.0 - use storage.Writer() instead func (d *gLDriver) FileWriterForURI(uri fyne.URI) (fyne.URIWriteCloser, error) { return storage.Writer(uri) } diff --git a/internal/repository/file.go b/internal/repository/file.go index d0f7b7549a..0f6ddca3e9 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -59,9 +59,7 @@ func (r *FileRepository) Exists(u fyne.URI) (bool, error) { if err == nil { ok = true - } - - if os.IsNotExist(err) { + } else if os.IsNotExist(err) { err = nil } @@ -98,18 +96,19 @@ func (r *FileRepository) CanRead(u fyne.URI) (bool, error) { f, err := os.OpenFile(u.Path(), os.O_RDONLY, 0666) if err == nil { defer f.Close() - } + } else { - if os.IsPermission(err) { - return false, nil - } + if os.IsPermission(err) { + return false, nil + } - if os.IsNotExist(err) { - return false, nil - } + if os.IsNotExist(err) { + return false, nil + } - if err != nil { - return false, err + if err != nil { + return false, err + } } return true, nil @@ -134,14 +133,15 @@ func (r *FileRepository) CanWrite(u fyne.URI) (bool, error) { f, err := os.OpenFile(u.Path(), os.O_WRONLY, 0666) if err == nil { defer f.Close() - } + } else { - if os.IsPermission(err) { - return false, nil - } + if os.IsPermission(err) { + return false, nil + } - if err != nil { - return false, err + if err != nil { + return false, err + } } return true, nil diff --git a/storage/repository/generic.go b/storage/repository/generic.go index 5bc444e83d..a8aa9c0c47 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -27,8 +27,9 @@ import ( // // Since 2.0.0 func GenericParent(u fyne.URI, parseURI func(string) (fyne.URI, error)) (fyne.URI, error) { + p := u.Path() - if u.Path() == "" || u.Path() == "/" { + if p == "" || p == "/" { parent, err := parseURI(u.String()) if err != nil { return nil, err @@ -50,11 +51,14 @@ func GenericParent(u fyne.URI, parseURI func(string) (fyne.URI, error)) (fyne.UR } // stick the query and fragment back on the end - if len(u.Query()) > 0 { - newURI += "?" + u.Query() + q := u.Query() + if len(q) > 0 { + newURI += "?" + q } - if len(u.Fragment()) > 0 { - newURI += "#" + u.Fragment() + + f := u.Fragment() + if len(f) > 0 { + newURI += "#" + f } return parseURI(newURI) From 31da787f8dc500ac4b148d38e278e7f8342cd7e8 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Wed, 13 Jan 2021 17:08:30 -0500 Subject: [PATCH 042/145] improve performance of FileRepository.CanList() Thank you @AlbinoGeek --- internal/repository/file.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index 0f6ddca3e9..0b35ebef3a 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -252,14 +252,21 @@ func (r *FileRepository) CanList(u fyne.URI) (bool, error) { // 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. - _, err = ioutil.ReadDir(u.Path()) - if os.IsPermission(err) { - return false, nil + p := u.Path() + f, err := os.Open(p) + if err == nil { + _, err = f.Readdir(1) + f.Close() } + if err != nil { 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 } From 77d4b90124271a3a8fa051cf15c2f024a9dc17fc Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Wed, 13 Jan 2021 17:10:29 -0500 Subject: [PATCH 043/145] InMemoryRepository instead of MemoryRepository thanks @stuartmscott --- internal/repository/memory.go | 44 +++++++++++++++--------------- internal/repository/memory_test.go | 34 +++++++++++------------ 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/internal/repository/memory.go b/internal/repository/memory.go index 3cd3d87912..59b779ad71 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -15,10 +15,10 @@ var _ io.WriteCloser = &nodeReaderWriter{} var _ fyne.URIReadCloser = &nodeReaderWriter{} var _ fyne.URIWriteCloser = &nodeReaderWriter{} -// nodeReaderWriter allows reading or writing to elements in a MemoryRepository +// nodeReaderWriter allows reading or writing to elements in a InMemoryRepository type nodeReaderWriter struct { path string - repo *MemoryRepository + repo *InMemoryRepository writing bool readCursor int writeCursor int @@ -30,7 +30,7 @@ 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 MemoryRepository", n.path) + 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 @@ -103,11 +103,11 @@ func (n *nodeReaderWriter) URI() fyne.URI { } // declare conformance with repository types -var _ repository.Repository = &MemoryRepository{} -var _ repository.WriteableRepository = &MemoryRepository{} -var _ repository.HierarchicalRepository = &MemoryRepository{} +var _ repository.Repository = &InMemoryRepository{} +var _ repository.WriteableRepository = &InMemoryRepository{} +var _ repository.HierarchicalRepository = &InMemoryRepository{} -// MemoryRepository implements an in-memory version of the +// 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 @@ -125,18 +125,18 @@ var _ repository.HierarchicalRepository = &MemoryRepository{} // elsewhere. // // Since 2.0.0 -type MemoryRepository struct { +type InMemoryRepository struct { data map[string][]byte scheme string } -// NewMemoryRepository creates a new MemoryRepository instance. It must be +// 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.0 -func NewMemoryRepository(scheme string) *MemoryRepository { - return &MemoryRepository{ +func NewInMemoryRepository(scheme string) *InMemoryRepository { + return &InMemoryRepository{ data: make(map[string][]byte), scheme: scheme, } @@ -145,7 +145,7 @@ func NewMemoryRepository(scheme string) *MemoryRepository { // Exists implements repository.Repository.Exists // // Since 2.0.0 -func (m *MemoryRepository) Exists(u fyne.URI) (bool, error) { +func (m *InMemoryRepository) Exists(u fyne.URI) (bool, error) { if u.Path() == "" { return false, fmt.Errorf("invalid path '%s'", u.Path()) } @@ -157,14 +157,14 @@ func (m *MemoryRepository) Exists(u fyne.URI) (bool, error) { // Reader implements repository.Repository.Reader // // Since 2.0.0 -func (m *MemoryRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { +func (m *InMemoryRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { if u.Path() == "" { return nil, fmt.Errorf("invalid path '%s'", u.Path()) } _, ok := m.data[u.Path()] if !ok { - return nil, fmt.Errorf("no such path '%s' in MemoryRepository", u.Path()) + return nil, fmt.Errorf("no such path '%s' in InMemoryRepository", u.Path()) } return &nodeReaderWriter{path: u.Path(), repo: m}, nil @@ -173,28 +173,28 @@ func (m *MemoryRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { // CanRead implements repository.Repository.CanRead // // Since 2.0.0 -func (m *MemoryRepository) CanRead(u fyne.URI) (bool, error) { +func (m *InMemoryRepository) CanRead(u fyne.URI) (bool, error) { if u.Path() == "" { return false, fmt.Errorf("invalid path '%s'", u.Path()) } _, ok := m.data[u.Path()] if !ok { - return false, fmt.Errorf("no such path '%s' in MemoryRepository", u.Path()) + return false, fmt.Errorf("no such path '%s' in InMemoryRepository", u.Path()) } return true, nil } // Destroy implements repository.Repository.Destroy -func (m *MemoryRepository) Destroy(scheme string) { +func (m *InMemoryRepository) Destroy(scheme string) { // do nothing } // Writer implements repository.WriteableRepository.Writer // // Since 2.0.0 -func (m *MemoryRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { +func (m *InMemoryRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { if u.Path() == "" { return nil, fmt.Errorf("invalid path '%s'", u.Path()) } @@ -205,7 +205,7 @@ func (m *MemoryRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { // CanWrite implements repository.WriteableRepository.CanWrite // // Since 2.0.0 -func (m *MemoryRepository) CanWrite(u fyne.URI) (bool, error) { +func (m *InMemoryRepository) CanWrite(u fyne.URI) (bool, error) { if u.Path() == "" { return false, fmt.Errorf("invalid path '%s'", u.Path()) } @@ -216,7 +216,7 @@ func (m *MemoryRepository) CanWrite(u fyne.URI) (bool, error) { // Delete implements repository.WriteableRepository.Delete // // Since 2.0.0 -func (m *MemoryRepository) Delete(u fyne.URI) error { +func (m *InMemoryRepository) Delete(u fyne.URI) error { _, ok := m.data[u.Path()] if ok { delete(m.data, u.Path()) @@ -228,13 +228,13 @@ func (m *MemoryRepository) Delete(u fyne.URI) error { // Parent implements repository.HierarchicalRepository.Parent // // Since 2.0.0 -func (m *MemoryRepository) Parent(u fyne.URI) (fyne.URI, error) { +func (m *InMemoryRepository) Parent(u fyne.URI) (fyne.URI, error) { return repository.GenericParent(u, storage.ParseURI) } // Child implements repository.HierarchicalRepository.Child // // Since 2.0.0 -func (m *MemoryRepository) Child(u fyne.URI, component string) (fyne.URI, error) { +func (m *InMemoryRepository) Child(u fyne.URI, component string) (fyne.URI, error) { return repository.GenericChild(u, component, storage.ParseURI) } diff --git a/internal/repository/memory_test.go b/internal/repository/memory_test.go index d1f9c7c4f1..cadb1694ce 100644 --- a/internal/repository/memory_test.go +++ b/internal/repository/memory_test.go @@ -10,8 +10,8 @@ import ( "github.com/stretchr/testify/assert" ) -func TestMemoryRepositoryRegistration(t *testing.T) { - m := NewMemoryRepository("mem") +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 @@ -25,7 +25,7 @@ func TestMemoryRepositoryRegistration(t *testing.T) { assert.Equal(t, m, repo) // test that re-registration also works - m2 := NewMemoryRepository("mem") + 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) @@ -33,9 +33,9 @@ func TestMemoryRepositoryRegistration(t *testing.T) { assert.Equal(t, m2, repo) } -func TestMemoryRepositoryExists(t *testing.T) { +func TestInMemoryRepositoryExists(t *testing.T) { // set up our repository - it's OK if we already registered it - m := NewMemoryRepository("mem") + m := NewInMemoryRepository("mem") repository.Register("mem", m) m.data["/foo"] = []byte{} m.data["/bar"] = []byte{1, 2, 3} @@ -58,9 +58,9 @@ func TestMemoryRepositoryExists(t *testing.T) { assert.Nil(t, err) } -func TestMemoryRepositoryReader(t *testing.T) { +func TestInMemoryRepositoryReader(t *testing.T) { // set up our repository - it's OK if we already registered it - m := NewMemoryRepository("mem") + m := NewInMemoryRepository("mem") repository.Register("mem", m) m.data["/foo"] = []byte{} m.data["/bar"] = []byte{1, 2, 3} @@ -87,9 +87,9 @@ func TestMemoryRepositoryReader(t *testing.T) { assert.NotNil(t, err) } -func TestMemoryRepositoryCanRead(t *testing.T) { +func TestInMemoryRepositoryCanRead(t *testing.T) { // set up our repository - it's OK if we already registered it - m := NewMemoryRepository("mem") + m := NewInMemoryRepository("mem") repository.Register("mem", m) m.data["/foo"] = []byte{} m.data["/bar"] = []byte{1, 2, 3} @@ -112,9 +112,9 @@ func TestMemoryRepositoryCanRead(t *testing.T) { assert.NotNil(t, err) } -func TestMemoryRepositoryWriter(t *testing.T) { +func TestInMemoryRepositoryWriter(t *testing.T) { // set up our repository - it's OK if we already registered it - m := NewMemoryRepository("mem") + m := NewInMemoryRepository("mem") repository.Register("mem", m) m.data["/foo"] = []byte{} m.data["/bar"] = []byte{1, 2, 3} @@ -196,9 +196,9 @@ func TestMemoryRepositoryWriter(t *testing.T) { } -func TestMemoryRepositoryCanWrite(t *testing.T) { +func TestInMemoryRepositoryCanWrite(t *testing.T) { // set up our repository - it's OK if we already registered it - m := NewMemoryRepository("mem") + m := NewInMemoryRepository("mem") repository.Register("mem", m) m.data["/foo"] = []byte{} m.data["/bar"] = []byte{1, 2, 3} @@ -221,9 +221,9 @@ func TestMemoryRepositoryCanWrite(t *testing.T) { assert.Nil(t, err) } -func TestMemoryRepositoryParent(t *testing.T) { +func TestInMemoryRepositoryParent(t *testing.T) { // set up our repository - it's OK if we already registered it - m := NewMemoryRepository("mem") + m := NewInMemoryRepository("mem") repository.Register("mem", m) m.data["/foo/bar/baz"] = []byte{} @@ -239,9 +239,9 @@ func TestMemoryRepositoryParent(t *testing.T) { assert.Equal(t, fooExpectedParent.String(), fooParent.String()) } -func TestMemoryRepositoryChild(t *testing.T) { +func TestInMemoryRepositoryChild(t *testing.T) { // set up our repository - it's OK if we already registered it - m := NewMemoryRepository("mem") + m := NewInMemoryRepository("mem") repository.Register("mem", m) // and some URIs - we know that they will not fail parsing From 3b79728860d636ea6a55be83397e0c1e8b5a22c4 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Wed, 13 Jan 2021 17:13:20 -0500 Subject: [PATCH 044/145] use more consistent conformance check --- internal/repository/memory.go | 64 +++++++++++++++++------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/internal/repository/memory.go b/internal/repository/memory.go index 59b779ad71..8529891c5e 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -10,10 +10,15 @@ import ( ) // declare conformance to interfaces -var _ io.ReadCloser = &nodeReaderWriter{} -var _ io.WriteCloser = &nodeReaderWriter{} -var _ fyne.URIReadCloser = &nodeReaderWriter{} -var _ fyne.URIWriteCloser = &nodeReaderWriter{} +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.WriteableRepository = (*InMemoryRepository)(nil) +var _ repository.HierarchicalRepository = (*InMemoryRepository)(nil) // nodeReaderWriter allows reading or writing to elements in a InMemoryRepository type nodeReaderWriter struct { @@ -24,6 +29,29 @@ type nodeReaderWriter struct { 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.0 +type InMemoryRepository struct { + data map[string][]byte + scheme string +} + // Read implements io.Reader.Read func (n *nodeReaderWriter) Read(p []byte) (int, error) { @@ -102,34 +130,6 @@ func (n *nodeReaderWriter) URI() fyne.URI { return u } -// declare conformance with repository types -var _ repository.Repository = &InMemoryRepository{} -var _ repository.WriteableRepository = &InMemoryRepository{} -var _ repository.HierarchicalRepository = &InMemoryRepository{} - -// 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.0 -type InMemoryRepository struct { - data map[string][]byte - scheme string -} - // 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. From e3e68d7b2990185c8cc623b253377680c82ca357 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Wed, 13 Jan 2021 17:19:38 -0500 Subject: [PATCH 045/145] add missing : --- storage/repository/generic.go | 8 +++---- storage/repository/repository.go | 38 ++++++++++++++++---------------- storage/uri.go | 20 ++++++++--------- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/storage/repository/generic.go b/storage/repository/generic.go index a8aa9c0c47..a27c0a0f37 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -25,7 +25,7 @@ import ( // 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.0 +// Since: 2.0.0 func GenericParent(u fyne.URI, parseURI func(string) (fyne.URI, error)) (fyne.URI, error) { p := u.Path() @@ -77,7 +77,7 @@ func GenericParent(u fyne.URI, parseURI func(string) (fyne.URI, error)) (fyne.UR // 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.0 +// Since: 2.0.0 func GenericChild(u fyne.URI, component string, parseURI func(string) (fyne.URI, error)) (fyne.URI, error) { // split into components and add the new one @@ -110,7 +110,7 @@ func GenericChild(u fyne.URI, component string, parseURI func(string) (fyne.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.0 +// Since: 2.0.0 func GenericCopy(source fyne.URI, destination fyne.URI) error { return fmt.Errorf("TODO") } @@ -126,7 +126,7 @@ func GenericCopy(source fyne.URI, destination fyne.URI) error { // 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.0 +// Since: 2.0.0 func GenericMove(source fyne.URI, destination fyne.URI) error { return fmt.Errorf("TODO") } diff --git a/storage/repository/repository.go b/storage/repository/repository.go index fa14fc4f92..d9c5d668d7 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -44,19 +44,19 @@ type Repository interface { // Exists will be used to implement calls to storage.Exists() for the // registered scheme of this repository. // - // Since 2.0.0 + // Since: 2.0.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.0 + // Since: 2.0.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.0 + // Since: 2.0.0 CanRead(u fyne.URI) (bool, error) // Destroy is called when the repository is un-registered from a given @@ -66,7 +66,7 @@ type Repository interface { // registered for. This may be useful for repositories that need to // handle more than one URI scheme internally. // - // Since 2.0.0 + // Since: 2.0.0 Destroy(string) } @@ -79,7 +79,7 @@ type Repository interface { // with 'scheme:', or storage.ParseURI() will not be able to determine which // storage repository to delegate to for parsing. // -// Since 2.0.0 +// Since: 2.0.0 type CanonicalRepository interface { Repository @@ -91,26 +91,26 @@ type CanonicalRepository interface { // WriteableRepository 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.0 +// Since: 2.0.0 type WriteableRepository interface { Repository // Writer will be used to implement calls to storage.WriterTo() for // the registered scheme of this repository. // - // Since 2.0.0 + // Since: 2.0.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.0 + // Since: 2.0.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.0 + // Since: 2.0.0 Delete(u fyne.URI) error } @@ -118,27 +118,27 @@ type WriteableRepository interface { // supports obtaining directory listings (generally analogous to a directory // listing) for URIs of the scheme it is registered to. // -// Since 2.0.0 +// Since: 2.0.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.0 + // Since: 2.0.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.0 + // Since: 2.0.0 List(u fyne.URI) ([]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.0 +// Since: 2.0.0 type HierarchicalRepository interface { Repository @@ -148,7 +148,7 @@ type HierarchicalRepository interface { // A generic implementation is provided in GenericParent(), which // is based on the RFC3986 definition of a URI parent. // - // Since 2.0.0 + // Since: 2.0.0 Parent(fyne.URI) (fyne.URI, error) // Child will be used to implement calls to storage.Child() for @@ -157,7 +157,7 @@ type HierarchicalRepository interface { // A generic implementation is provided in GenericParent(), which // is based on RFC3986. // - // Since 2.0.0 + // Since: 2.0.0 Child(fyne.URI, string) (fyne.URI, error) } @@ -179,7 +179,7 @@ type CopyableRepository interface { // repository is registered to handle. In such cases, implementations // are suggested to fail-over to GenericCopy(). // - // Since 2.0.0 + // Since: 2.0.0 Copy(fyne.URI, fyne.URI) error } @@ -201,7 +201,7 @@ type MovableRepository interface { // repository is registered to handle. In such cases, implementations // are suggested to fail-over to GenericMove(). // - // Since 2.0.0 + // Since: 2.0.0 Move(fyne.URI, fyne.URI) error } @@ -209,7 +209,7 @@ type MovableRepository interface { // registered scheme will use methods implemented by the relevant repository // implementation. // -// Since 2.0.0 +// Since: 2.0.0 func Register(scheme string, repository Repository) { prev, ok := repositoryTable[scheme] @@ -227,7 +227,7 @@ func Register(scheme string, repository Repository) { // 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.0 +// Since: 2.0.0 func ForURI(u fyne.URI) (Repository, error) { scheme := u.Scheme() repo, ok := repositoryTable[scheme] diff --git a/storage/uri.go b/storage/uri.go index 09f2d72a15..185afa92ce 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -117,7 +117,7 @@ func (u *uri) Fragment() string { // 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 +// Deprecated: use ParseURI instead func NewURI(s string) fyne.URI { u, _ := ParseURI(s) return u @@ -126,7 +126,7 @@ func NewURI(s string) fyne.URI { // ParseURI creates a new URI instance by parsing a URI string, which must // conform to IETF RFC3986. // -// Since 2.0.0 +// Since: 2.0.0 func ParseURI(s string) (fyne.URI, error) { if len(s) > 5 && s[:5] == "file:" { @@ -342,7 +342,7 @@ func Delete(u fyne.URI) error { // Reader is backed by the repository system - this function calls // into a scheme-specific implementation from a registered repository. // -// Since 2.0.0 +// Since: 2.0.0 func Reader(u fyne.URI) (fyne.URIReadCloser, error) { repo, err := repository.ForURI(u) if err != nil { @@ -361,7 +361,7 @@ func Reader(u fyne.URI) (fyne.URIReadCloser, error) { // CanRead is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // -// Since 2.0.0 +// Since: 2.0.0 func CanRead(u fyne.URI) (bool, error) { repo, err := repository.ForURI(u) if err != nil { @@ -394,7 +394,7 @@ func CanRead(u fyne.URI) (bool, error) { // Writer is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // -// Since 2.0.0 +// Since: 2.0.0 func Writer(u fyne.URI) (fyne.URIWriteCloser, error) { repo, err := repository.ForURI(u) if err != nil { @@ -418,7 +418,7 @@ func Writer(u fyne.URI) (fyne.URIWriteCloser, error) { // CanWrite is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // -// Since 2.0.0 +// Since: 2.0.0 func CanWrite(u fyne.URI) (bool, error) { repo, err := repository.ForURI(u) if err != nil { @@ -455,7 +455,7 @@ func CanWrite(u fyne.URI) (bool, error) { // Copy is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // -// Since 2.0.0 +// Since: 2.0.0 func Copy(source fyne.URI, destination fyne.URI) error { return fmt.Errorf("TODO: implement this function") } @@ -484,7 +484,7 @@ func Copy(source fyne.URI, destination fyne.URI) error { // Move is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // -// Since 2.0.0 +// Since: 2.0.0 func Move(source fyne.URI, destination fyne.URI) error { return fmt.Errorf("TODO: implement this function") } @@ -510,7 +510,7 @@ func Move(source fyne.URI, destination fyne.URI) error { // CanList is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // -// Since 2.0.0 +// Since: 2.0.0 func CanList(u fyne.URI) (bool, error) { repo, err := repository.ForURI(u) if err != nil { @@ -550,7 +550,7 @@ func CanList(u fyne.URI) (bool, error) { // scheme-specific implementation from a registered repository, or fails with a // URIOperationNotSupported error. // -// Since 2.0.0 +// Since: 2.0.0 func List(u fyne.URI) ([]fyne.URI, error) { repo, err := repository.ForURI(u) if err != nil { From d5c91dfb9acb96390457141846a0e8ed2a04a915 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Wed, 13 Jan 2021 17:33:53 -0500 Subject: [PATCH 046/145] remove parseURI parameter from Generic{Parent,Child} --- internal/repository/file.go | 4 +- internal/repository/memory.go | 4 +- storage/repository/generic.go | 81 +++++++++++++++++---- storage/repository/uri.go | 96 +++++++++++++++++++++++++ storage/uri.go | 131 +--------------------------------- 5 files changed, 170 insertions(+), 146 deletions(-) create mode 100644 storage/repository/uri.go diff --git a/internal/repository/file.go b/internal/repository/file.go index 0b35ebef3a..8d5e932e67 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -189,7 +189,7 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { return storage.ParseURI(u.Scheme() + "://" + parent) } - uri, err := repository.GenericParent(u, storage.ParseURI) + uri, err := repository.GenericParent(u) if err != nil { return nil, err } @@ -202,7 +202,7 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { func (r *FileRepository) Child(u fyne.URI, component string) (fyne.URI, error) { // TODO: make sure that this works on Windows - might cause trouble // if the path sep isn't normalized out on ingest. - return repository.GenericChild(u, component, storage.ParseURI) + return repository.GenericChild(u, component) } // List implements repository.HierarchicalRepository.List() diff --git a/internal/repository/memory.go b/internal/repository/memory.go index 8529891c5e..9b04e09287 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -229,12 +229,12 @@ func (m *InMemoryRepository) Delete(u fyne.URI) error { // // Since 2.0.0 func (m *InMemoryRepository) Parent(u fyne.URI) (fyne.URI, error) { - return repository.GenericParent(u, storage.ParseURI) + return repository.GenericParent(u) } // Child implements repository.HierarchicalRepository.Child // // Since 2.0.0 func (m *InMemoryRepository) Child(u fyne.URI, component string) (fyne.URI, error) { - return repository.GenericChild(u, component, storage.ParseURI) + return repository.GenericChild(u, component) } diff --git a/storage/repository/generic.go b/storage/repository/generic.go index a27c0a0f37..f0231e50dc 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -2,6 +2,9 @@ package repository import ( "fmt" + "net/url" + "path/filepath" + "runtime" "strings" "fyne.io/fyne" @@ -18,19 +21,15 @@ import ( // If the URI path is empty or '/', then a duplicate of the URI is returned, // along with URIRootError. // -// The parseURI parameter should be a function that you wish GenericParent to -// use to generate any new URIs it creates. Usually, storage.ParseURI is -// suitable here. -// // 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.0 -func GenericParent(u fyne.URI, parseURI func(string) (fyne.URI, error)) (fyne.URI, error) { +func GenericParent(u fyne.URI) (fyne.URI, error) { p := u.Path() if p == "" || p == "/" { - parent, err := parseURI(u.String()) + parent, err := ParseURI(u.String()) if err != nil { return nil, err } @@ -61,7 +60,7 @@ func GenericParent(u fyne.URI, parseURI func(string) (fyne.URI, error)) (fyne.UR newURI += "#" + f } - return parseURI(newURI) + return ParseURI(newURI) } // GenericChild can be used as a common-case implementation of @@ -70,15 +69,11 @@ func GenericParent(u fyne.URI, parseURI func(string) (fyne.URI, error)) (fyne.UR // "/" + component to the path, then concatenating the result and parsing it as // a new URI. // -// The parseURI parameter should be a function that you wish GenericParent to -// use to generate any new URIs it creates. Usually, storage.ParseURI is -// suitable here. -// // 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.0 -func GenericChild(u fyne.URI, component string, parseURI func(string) (fyne.URI, error)) (fyne.URI, error) { +func GenericChild(u fyne.URI, component string) (fyne.URI, error) { // split into components and add the new one components := strings.Split(u.Path(), "/") @@ -96,7 +91,7 @@ func GenericChild(u fyne.URI, component string, parseURI func(string) (fyne.URI, newURI += "#" + u.Fragment() } - return parseURI(newURI) + return ParseURI(newURI) } // GenericCopy can be used a common-case implementation of @@ -130,3 +125,63 @@ func GenericCopy(source fyne.URI, destination fyne.URI) error { func GenericMove(source fyne.URI, destination fyne.URI) error { return fmt.Errorf("TODO") } + +// 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.0 +func ParseURI(s string) (fyne.URI, error) { + + if len(s) > 5 && s[:5] == "file:" { + path := s[5:] + if len(path) > 2 && path[:2] == "//" { + path = path[2:] + } + + // this looks weird, but it makes sure that we still pass + // url.Parse() + s = NewFileURI(path).String() + } + + l, err := url.Parse(s) + if err != nil { + return nil, err + } + + return &uri{ + scheme: l.Scheme, + authority: l.User.String() + l.Host, + // workaround for net/url, see type uri struct comments + haveAuthority: true, + path: l.Path, + query: l.RawQuery, + fragment: l.Fragment, + }, nil +} + +// 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.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: "", + } +} diff --git a/storage/repository/uri.go b/storage/repository/uri.go new file mode 100644 index 0000000000..46c875b4c2 --- /dev/null +++ b/storage/repository/uri.go @@ -0,0 +1,96 @@ +package repository + +import ( + "bufio" + "mime" + "path/filepath" + "strings" + "unicode/utf8" + + "fyne.io/fyne" +) + +// 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/uri.go b/storage/uri.go index 185afa92ce..63d9757934 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -1,117 +1,15 @@ package storage import ( - "bufio" "fmt" - "mime" - "net/url" - "path/filepath" - "runtime" - "strings" - "unicode/utf8" "fyne.io/fyne" "fyne.io/fyne/storage/repository" ) -// 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 -} - // 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{ - scheme: "file", - haveAuthority: true, - authority: "", - path: path, - query: "", - fragment: "", - } -} - -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" - readCloser, err := 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 + return repository.NewFileURI(path) } // NewURI creates a new URI from the given string representation. This could be @@ -128,32 +26,7 @@ func NewURI(s string) fyne.URI { // // Since: 2.0.0 func ParseURI(s string) (fyne.URI, error) { - - if len(s) > 5 && s[:5] == "file:" { - path := s[5:] - if len(path) > 2 && path[:2] == "//" { - path = path[2:] - } - - // this looks weird, but it makes sure that we still pass - // url.Parse() - s = NewFileURI(path).String() - } - - l, err := url.Parse(s) - if err != nil { - return nil, err - } - - return &uri{ - scheme: l.Scheme, - authority: l.User.String() + l.Host, - // workaround for net/url, see type uri struct comments - haveAuthority: true, - path: l.Path, - query: l.RawQuery, - fragment: l.Fragment, - }, nil + return repository.ParseURI(s) } // Parent returns a URI referencing the parent resource of the resource From 6bb54c004f85ed8ad5f546fa7f6aaef7da43bf40 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Wed, 13 Jan 2021 17:40:23 -0500 Subject: [PATCH 047/145] finish up TODOs in storage/uri.go --- storage/repository/repository.go | 7 +++++ storage/uri.go | 44 +++++++++++++++++--------------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/storage/repository/repository.go b/storage/repository/repository.go index d9c5d668d7..678d625657 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -163,6 +163,8 @@ type HierarchicalRepository interface { // CopyableRepository is an extension of the Repository interface which also // supports copying referenced resources from one URI to another. +// +// Since: 2.0.0 type CopyableRepository interface { Repository @@ -185,6 +187,11 @@ type CopyableRepository interface { // 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.0 type MovableRepository interface { Repository diff --git a/storage/uri.go b/storage/uri.go index 63d9757934..dd54cbd3fa 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -1,8 +1,6 @@ package storage import ( - "fmt" - "fyne.io/fyne" "fyne.io/fyne/storage/repository" ) @@ -143,22 +141,6 @@ func Exists(u fyne.URI) (bool, error) { } return repo.Exists(u) - - // TODO: this needs to move to the file:// repository - // if u.Scheme() != "file" { - // return false, fmt.Errorf("don't know how to check existence of %s scheme", u.Scheme()) - // } - // - // _, err := os.Stat(u.String()[len(u.Scheme())+3:]) - // if os.IsNotExist(err) { - // return false, nil - // } - // - // if err != nil { - // return false, err - // } - // - // return true, nil } // Delete destroys, deletes, or otherwise removes the resource referenced @@ -330,7 +312,17 @@ func CanWrite(u fyne.URI) (bool, error) { // // Since: 2.0.0 func Copy(source fyne.URI, destination fyne.URI) error { - return fmt.Errorf("TODO: implement this function") + repo, err := repository.ForURI(source) + if err != nil { + return err + } + + crepo, ok := repo.(repository.CopyableRepository) + if !ok { + return repository.OperationNotSupportedError + } + + return crepo.Copy(source, destination) } // Move returns a method that given two URIs, 'src' and 'dest' both of the same @@ -351,7 +343,7 @@ func Copy(source fyne.URI, destination fyne.URI) error { // such as network or filesystem access that has failed in some way. // // * If the scheme of the given URI does not have a registered -// MoveableRepository instance, then this method will fail with a +// MovableRepository instance, then this method will fail with a // repository.OperationNotSupportedError. // // Move is backed by the repository system - this function calls into a @@ -359,7 +351,17 @@ func Copy(source fyne.URI, destination fyne.URI) error { // // Since: 2.0.0 func Move(source fyne.URI, destination fyne.URI) error { - return fmt.Errorf("TODO: implement this function") + repo, err := repository.ForURI(source) + if err != nil { + return err + } + + mrepo, ok := repo.(repository.MovableRepository) + if !ok { + return repository.OperationNotSupportedError + } + + return mrepo.Move(source, destination) } // CanList will determine if the URI is listable or not. From 3937730fc072406a536d209b773a5a308ddb73f6 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Wed, 13 Jan 2021 17:52:25 -0500 Subject: [PATCH 048/145] implement GenericCopy and GenericChild --- storage/repository/generic.go | 98 +++++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 3 deletions(-) diff --git a/storage/repository/generic.go b/storage/repository/generic.go index f0231e50dc..d2f1b48823 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -1,7 +1,7 @@ package repository import ( - "fmt" + "io/ioutil" "net/url" "path/filepath" "runtime" @@ -60,6 +60,9 @@ func GenericParent(u fyne.URI) (fyne.URI, error) { newURI += "#" + f } + // NOTE: we specifically want to use ParseURI, rather than &uri{}, + // since the repository for the URI we just created might be a + // CanonicalRepository that implements it's own ParseURI. return ParseURI(newURI) } @@ -91,6 +94,9 @@ func GenericChild(u fyne.URI, component string) (fyne.URI, error) { newURI += "#" + u.Fragment() } + // NOTE: we specifically want to use ParseURI, rather than &uri{}, + // since the repository for the URI we just created might be a + // CanonicalRepository that implements it's own ParseURI. return ParseURI(newURI) } @@ -107,7 +113,44 @@ func GenericChild(u fyne.URI, component string) (fyne.URI, error) { // // Since: 2.0.0 func GenericCopy(source fyne.URI, destination fyne.URI) error { - return fmt.Errorf("TODO") + // 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 writeable. + destwrepo, ok := dstrepo.(WriteableRepository) + if !ok { + return OperationNotSupportedError + } + + // Create a reader and a writer. + srcReader, err := srcrepo.Reader(source) + if err != nil { + return err + } + + dstWriter, err := destwrepo.Writer(destination) + if err != nil { + return err + } + + // Read all the contents into memory... + contents, err := ioutil.ReadAll(srcReader) + if err != nil { + return err + } + + // ...and write it back out. + _, err = dstWriter.Write(contents) + + return err } // GenericMove can be used a common-case implementation of @@ -123,7 +166,56 @@ func GenericCopy(source fyne.URI, destination fyne.URI) error { // // Since: 2.0.0 func GenericMove(source fyne.URI, destination fyne.URI) error { - return fmt.Errorf("TODO") + // 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 WriteableRepository. + destwrepo, ok := dstrepo.(WriteableRepository) + if !ok { + return OperationNotSupportedError + } + + srcwrepo, ok := srcrepo.(WriteableRepository) + if !ok { + return OperationNotSupportedError + } + + // 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 + } + + // Read everything into memory and then write it back out. + contents, err := ioutil.ReadAll(srcReader) + if err != nil { + return err + } + + _, err = dstWriter.Write(contents) + if err != nil { + return err + } + + // Finally, delete the source only if the move finished without error. + return srcwrepo.Delete(source) } // ParseURI implements the back-end logic for storage.ParseURI, which you From 89d4c5ba5dffd565a91c4d079924784ff75c4be0 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Wed, 13 Jan 2021 18:04:29 -0500 Subject: [PATCH 049/145] implement Copy and Move --- internal/repository/file.go | 60 ++++++++++++++++++++++++----------- internal/repository/memory.go | 17 ++++++++++ storage/repository/generic.go | 24 ++++---------- 3 files changed, 65 insertions(+), 36 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index 8d5e932e67..c296f92e61 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -12,13 +12,15 @@ import ( ) // declare conformance with repository types -var _ repository.Repository = &FileRepository{} -var _ repository.WriteableRepository = &FileRepository{} -var _ repository.HierarchicalRepository = &FileRepository{} -var _ repository.ListableRepository = &FileRepository{} +var _ repository.Repository = (*FileRepository)(nil) +var _ repository.WriteableRepository = (*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{} -var _ fyne.URIWriteCloser = &file{} +var _ fyne.URIReadCloser = (*file)(nil) +var _ fyne.URIWriteCloser = (*file)(nil) type file struct { *os.File @@ -35,7 +37,7 @@ func (f *file) URI() fyne.URI { // // This repository is suitable to handle file:// schemes. // -// Since 2.0.0 +// Since: 2.0.0 type FileRepository struct { } @@ -43,14 +45,14 @@ type FileRepository struct { // given the scheme it is registered for. The caller needs to call // repository.Register() on the result of this function. // -// Since 2.0.0 +// Since: 2.0.0 func NewFileRepository(scheme string) *FileRepository { return &FileRepository{} } // Exists implements repository.Repository.Exists // -// Since 2.0.0 +// Since: 2.0.0 func (r *FileRepository) Exists(u fyne.URI) (bool, error) { p := u.Path() @@ -84,14 +86,14 @@ func openFile(uri fyne.URI, create bool) (*file, error) { // Reader implements repository.Repository.Reader // -// Since 2.0.0 +// Since: 2.0.0 func (r *FileRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { return openFile(u, false) } // CanRead implements repository.Repository.CanRead // -// Since 2.0.0 +// Since: 2.0.0 func (r *FileRepository) CanRead(u fyne.URI) (bool, error) { f, err := os.OpenFile(u.Path(), os.O_RDONLY, 0666) if err == nil { @@ -121,14 +123,14 @@ func (r *FileRepository) Destroy(scheme string) { // Writer implements repository.WriteableRepository.Writer // -// Since 2.0.0 +// Since: 2.0.0 func (r *FileRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { return openFile(u, true) } // CanWrite implements repository.WriteableRepository.CanWrite // -// Since 2.0.0 +// Since: 2.0.0 func (r *FileRepository) CanWrite(u fyne.URI) (bool, error) { f, err := os.OpenFile(u.Path(), os.O_WRONLY, 0666) if err == nil { @@ -149,14 +151,14 @@ func (r *FileRepository) CanWrite(u fyne.URI) (bool, error) { // Delete implements repository.WriteableRepository.Delete // -// Since 2.0.0 +// Since: 2.0.0 func (r *FileRepository) Delete(u fyne.URI) error { return os.Remove(u.Path()) } // Parent implements repository.HierarchicalRepository.Parent // -// Since 2.0.0 +// Since: 2.0.0 func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { s := u.String() @@ -198,7 +200,7 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { // Child implements repository.HierarchicalRepository.Child // -// Since 2.0.0 +// Since: 2.0.0 func (r *FileRepository) Child(u fyne.URI, component string) (fyne.URI, error) { // TODO: make sure that this works on Windows - might cause trouble // if the path sep isn't normalized out on ingest. @@ -207,7 +209,7 @@ func (r *FileRepository) Child(u fyne.URI, component string) (fyne.URI, error) { // List implements repository.HierarchicalRepository.List() // -// Since 2.0.0 +// Since: 2.0.0 func (r *FileRepository) List(u fyne.URI) ([]fyne.URI, error) { if u.Scheme() != "file" { return nil, fmt.Errorf("unsupported URL protocol") @@ -234,7 +236,7 @@ func (r *FileRepository) List(u fyne.URI) ([]fyne.URI, error) { // CanList implements repository.HierarchicalRepository.CanList() // -// Since 2.0.0 +// Since: 2.0.0 func (r *FileRepository) CanList(u fyne.URI) (bool, error) { info, err := os.Stat(u.Path()) @@ -270,3 +272,25 @@ func (r *FileRepository) CanList(u fyne.URI) (bool, error) { // it is a directory, and checking the permissions did not error out return true, nil } + +// Copy implements repository.CopyableRepository.Copy() +// +// Since: 2.0.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.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/memory.go b/internal/repository/memory.go index 9b04e09287..0a74bb8ee4 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -19,6 +19,8 @@ var _ fyne.URIWriteCloser = (*nodeReaderWriter)(nil) var _ repository.Repository = (*InMemoryRepository)(nil) var _ repository.WriteableRepository = (*InMemoryRepository)(nil) var _ repository.HierarchicalRepository = (*InMemoryRepository)(nil) +var _ repository.CopyableRepository = (*InMemoryRepository)(nil) +var _ repository.MovableRepository = (*InMemoryRepository)(nil) // nodeReaderWriter allows reading or writing to elements in a InMemoryRepository type nodeReaderWriter struct { @@ -238,3 +240,18 @@ func (m *InMemoryRepository) Parent(u fyne.URI) (fyne.URI, error) { 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.0 +func (m *InMemoryRepository) Copy(source, destination fyne.URI) error { + + return repository.GenericCopy(source, destination) +} + +// Move implements repository.MovableRepository.Move() +// +// Since: 2.0.0 +func (m *InMemoryRepository) Move(source, destination fyne.URI) error { + return repository.GenericMove(source, destination) +} diff --git a/storage/repository/generic.go b/storage/repository/generic.go index d2f1b48823..c8a38307b8 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -1,7 +1,7 @@ package repository import ( - "io/ioutil" + "io" "net/url" "path/filepath" "runtime" @@ -141,20 +141,13 @@ func GenericCopy(source fyne.URI, destination fyne.URI) error { return err } - // Read all the contents into memory... - contents, err := ioutil.ReadAll(srcReader) - if err != nil { - return err - } - - // ...and write it back out. - _, err = dstWriter.Write(contents) - + // Perform the copy. + _, err = io.Copy(dstWriter, srcReader) return err } // GenericMove can be used a common-case implementation of -// MoveableRepository.Move(). It will perform the move by obtaining a reader +// 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 WriteableRepository.Delete. @@ -203,13 +196,8 @@ func GenericMove(source fyne.URI, destination fyne.URI) error { return err } - // Read everything into memory and then write it back out. - contents, err := ioutil.ReadAll(srcReader) - if err != nil { - return err - } - - _, err = dstWriter.Write(contents) + // Perform the copy. + _, err = io.Copy(dstWriter, srcReader) if err != nil { return err } From ef0e08577ebd85509828695fc809d342f3488446 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Wed, 13 Jan 2021 18:12:12 -0500 Subject: [PATCH 050/145] attempt to fix Windows build failures I am suspicious that the performance optimizations that @AlbinoGeek suggested which were added in 31da787f8dc500ac4b148d38e278e7f8342cd7e8 may be breaking on Windows. --- internal/repository/file.go | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index c296f92e61..e8b5e7f3db 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -255,22 +255,29 @@ func (r *FileRepository) CanList(u fyne.URI) (bool, error) { // 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. p := u.Path() - f, err := os.Open(p) + _, err = ioutil.ReadDir(p) if err == nil { - _, err = f.Readdir(1) - f.Close() - } - - if err != nil { - return false, err - } - - if os.IsPermission(err) { + return true, nil + } else if os.IsPermission(err) { return false, nil } - + return false, err + // f, err := os.Open(p) + // if err == nil { + // _, err = f.Readdir(1) + // f.Close() + // } + // + // if err != nil { + // 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 + // return true, nil } // Copy implements repository.CopyableRepository.Copy() From 9a398a5458de3c696d128a523fdc3cdce171c24d Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Wed, 13 Jan 2021 18:19:11 -0500 Subject: [PATCH 051/145] undo previous commit --- internal/repository/file.go | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index e8b5e7f3db..c296f92e61 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -255,29 +255,22 @@ func (r *FileRepository) CanList(u fyne.URI) (bool, error) { // 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. p := u.Path() - _, err = ioutil.ReadDir(p) + f, err := os.Open(p) if err == nil { - return true, nil - } else if os.IsPermission(err) { + _, err = f.Readdir(1) + f.Close() + } + + if err != nil { + return false, err + } + + if os.IsPermission(err) { return false, nil } - return false, err - // f, err := os.Open(p) - // if err == nil { - // _, err = f.Readdir(1) - // f.Close() - // } - // - // if err != nil { - // 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 + return true, nil } // Copy implements repository.CopyableRepository.Copy() From d701802aeb38f01f3f79e31f6fa24c3e13c8d4e8 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Wed, 13 Jan 2021 18:24:08 -0500 Subject: [PATCH 052/145] try one more thing to fix the Windows build I have heard that golang's stat() on Windows is not-so-good, so we short this out and do the slower "try it and see what happens" CanList check if GOOS is windows. --- internal/repository/file.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index c296f92e61..7af574ae00 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "os" "path/filepath" + "runtime" "fyne.io/fyne" "fyne.io/fyne/storage" @@ -238,7 +239,8 @@ func (r *FileRepository) List(u fyne.URI) ([]fyne.URI, error) { // // Since: 2.0.0 func (r *FileRepository) CanList(u fyne.URI) (bool, error) { - info, err := os.Stat(u.Path()) + p := u.Path() + info, err := os.Stat(p) if os.IsNotExist(err) { return false, nil @@ -248,13 +250,13 @@ func (r *FileRepository) CanList(u fyne.URI) (bool, error) { return false, err } - if !info.IsDir() { + // TODO: on a hunch - this might be why things are breaking on Windows + if (!info.IsDir()) && runtime.GOOS == "windows" { 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. - p := u.Path() f, err := os.Open(p) if err == nil { _, err = f.Readdir(1) From 16651ed36f27abf8c9441f0aeb759878ddd67e2c Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Wed, 13 Jan 2021 18:28:03 -0500 Subject: [PATCH 053/145] OK, IDK why the Windows build is broken --- internal/repository/file.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index 7af574ae00..7f819b86b3 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -5,7 +5,6 @@ import ( "io/ioutil" "os" "path/filepath" - "runtime" "fyne.io/fyne" "fyne.io/fyne/storage" @@ -250,8 +249,7 @@ func (r *FileRepository) CanList(u fyne.URI) (bool, error) { return false, err } - // TODO: on a hunch - this might be why things are breaking on Windows - if (!info.IsDir()) && runtime.GOOS == "windows" { + if !info.IsDir() { return false, nil } From 7d75419f93eea1413d8daed37ab9f02848e0343e Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Wed, 13 Jan 2021 18:37:29 -0500 Subject: [PATCH 054/145] actually use CannicalRepository.Parse if present --- storage/repository/generic.go | 63 ----------------------- storage/repository/repository.go | 88 ++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 63 deletions(-) diff --git a/storage/repository/generic.go b/storage/repository/generic.go index c8a38307b8..bb2f7616be 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -2,9 +2,6 @@ package repository import ( "io" - "net/url" - "path/filepath" - "runtime" "strings" "fyne.io/fyne" @@ -205,63 +202,3 @@ func GenericMove(source fyne.URI, destination fyne.URI) error { // Finally, delete the source only if the move finished without error. return srcwrepo.Delete(source) } - -// 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.0 -func ParseURI(s string) (fyne.URI, error) { - - if len(s) > 5 && s[:5] == "file:" { - path := s[5:] - if len(path) > 2 && path[:2] == "//" { - path = path[2:] - } - - // this looks weird, but it makes sure that we still pass - // url.Parse() - s = NewFileURI(path).String() - } - - l, err := url.Parse(s) - if err != nil { - return nil, err - } - - return &uri{ - scheme: l.Scheme, - authority: l.User.String() + l.Host, - // workaround for net/url, see type uri struct comments - haveAuthority: true, - path: l.Path, - query: l.RawQuery, - fragment: l.Fragment, - }, nil -} - -// 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.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: "", - } -} diff --git a/storage/repository/repository.go b/storage/repository/repository.go index 678d625657..f713ad973a 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -2,6 +2,9 @@ package repository import ( "fmt" + "net/url" + "path/filepath" + "runtime" "fyne.io/fyne" ) @@ -245,3 +248,88 @@ func ForURI(u fyne.URI) (Repository, error) { return repo, nil } + +// 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.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]) + } + + 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:] + } + + // this looks weird, but it makes sure that we still pass + // url.Parse() + s = NewFileURI(path).String() + } + + repo, err := ForURI(&uri{scheme: scheme}) + crepo, ok := repo.(CanonicalRepository) + if !ok || err != nil { + // Either the repository registered for this scheme does not + // implement a parser, or there is no registered repository. + // Either way, we'll do our best-effort default. + l, err := url.Parse(s) + if err != nil { + return nil, err + } + + return &uri{ + scheme: l.Scheme, + authority: l.User.String() + l.Host, + // workaround for net/url, see type uri struct comments + haveAuthority: true, + path: l.Path, + query: l.RawQuery, + fragment: l.Fragment, + }, nil + } + + return crepo.ParseURI(s) + +} + +// 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.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: "", + } +} From c20538b06594a42a57cfe31fc1770f79d07986f1 Mon Sep 17 00:00:00 2001 From: FPabl0 Date: Thu, 14 Jan 2021 02:06:49 -0500 Subject: [PATCH 055/145] revert changes in popUp.Resize as those changes are useless --- widget/select.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/select.go b/widget/select.go index 51138d8e6d..aa478d2963 100644 --- a/widget/select.go +++ b/widget/select.go @@ -246,7 +246,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+theme.Padding()/2)) + s.popUp.Resize(fyne.NewSize(s.Size().Width-theme.Padding()*2, s.popUp.MinSize().Height)) } func (s *Select) tapAnimation() { From e0f53663e295066ac52e45c68d643e81f635de34 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Thu, 14 Jan 2021 10:52:34 +0000 Subject: [PATCH 056/145] some simple tests whilst hunting Windows issues --- storage/repository/parse.go | 94 ++++++++++++++++++++++++++++++++ storage/repository/parse_test.go | 22 ++++++++ storage/repository/repository.go | 88 ------------------------------ 3 files changed, 116 insertions(+), 88 deletions(-) create mode 100644 storage/repository/parse.go create mode 100644 storage/repository/parse_test.go diff --git a/storage/repository/parse.go b/storage/repository/parse.go new file mode 100644 index 0000000000..37a42c65fc --- /dev/null +++ b/storage/repository/parse.go @@ -0,0 +1,94 @@ +package repository + +import ( + "net/url" + "path/filepath" + "runtime" + + "fyne.io/fyne" +) + +// 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.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.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]) + } + + 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:] + } + + // this looks weird, but it makes sure that we still pass + // url.Parse() + s = NewFileURI(path).String() + } + + repo, err := ForURI(&uri{scheme: scheme}) + crepo, ok := repo.(CanonicalRepository) + if !ok || err != nil { + // Either the repository registered for this scheme does not + // implement a parser, or there is no registered repository. + // Either way, we'll do our best-effort default. + l, err := url.Parse(s) + if err != nil { + return nil, err + } + + return &uri{ + scheme: l.Scheme, + authority: l.User.String() + l.Host, + // workaround for net/url, see type uri struct comments + haveAuthority: true, + path: l.Path, + query: l.RawQuery, + fragment: l.Fragment, + }, nil + } + + return crepo.ParseURI(s) + +} diff --git a/storage/repository/parse_test.go b/storage/repository/parse_test.go new file mode 100644 index 0000000000..3b7e50a84f --- /dev/null +++ b/storage/repository/parse_test.go @@ -0,0 +1,22 @@ +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://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 index f713ad973a..678d625657 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -2,9 +2,6 @@ package repository import ( "fmt" - "net/url" - "path/filepath" - "runtime" "fyne.io/fyne" ) @@ -248,88 +245,3 @@ func ForURI(u fyne.URI) (Repository, error) { return repo, nil } - -// 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.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]) - } - - 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:] - } - - // this looks weird, but it makes sure that we still pass - // url.Parse() - s = NewFileURI(path).String() - } - - repo, err := ForURI(&uri{scheme: scheme}) - crepo, ok := repo.(CanonicalRepository) - if !ok || err != nil { - // Either the repository registered for this scheme does not - // implement a parser, or there is no registered repository. - // Either way, we'll do our best-effort default. - l, err := url.Parse(s) - if err != nil { - return nil, err - } - - return &uri{ - scheme: l.Scheme, - authority: l.User.String() + l.Host, - // workaround for net/url, see type uri struct comments - haveAuthority: true, - path: l.Path, - query: l.RawQuery, - fragment: l.Fragment, - }, nil - } - - return crepo.ParseURI(s) - -} - -// 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.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: "", - } -} From ab448b2f9ee9c9cc523735abc71f7d8684d2dfef Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Thu, 14 Jan 2021 11:01:16 +0000 Subject: [PATCH 057/145] Review feedback etc --- storage/repository/parse.go | 37 ++++++++++++++++---------------- storage/repository/parse_test.go | 4 ++++ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/storage/repository/parse.go b/storage/repository/parse.go index 37a42c65fc..46c3bcac4c 100644 --- a/storage/repository/parse.go +++ b/storage/repository/parse.go @@ -68,27 +68,26 @@ func ParseURI(s string) (fyne.URI, error) { } repo, err := ForURI(&uri{scheme: scheme}) - crepo, ok := repo.(CanonicalRepository) - if !ok || err != nil { - // Either the repository registered for this scheme does not - // implement a parser, or there is no registered repository. - // Either way, we'll do our best-effort default. - l, err := url.Parse(s) - if err != nil { - return nil, err + if err == nil { + // If the repository registered for this scheme implements a parser + if c, ok := repo.(CanonicalRepository); ok { + return c.ParseURI(s) } - - return &uri{ - scheme: l.Scheme, - authority: l.User.String() + l.Host, - // workaround for net/url, see type uri struct comments - haveAuthority: true, - path: l.Path, - query: l.RawQuery, - fragment: l.Fragment, - }, nil } - return crepo.ParseURI(s) + // There was no repository registered, or it did not provide a parser + l, err := url.Parse(s) + if err != nil { + return nil, err + } + return &uri{ + scheme: l.Scheme, + authority: l.User.String() + l.Host, + // workaround for net/url, see type uri struct comments + haveAuthority: true, + path: l.Path, + query: l.RawQuery, + fragment: l.Fragment, + }, nil } diff --git a/storage/repository/parse_test.go b/storage/repository/parse_test.go index 3b7e50a84f..87c8ada016 100644 --- a/storage/repository/parse_test.go +++ b/storage/repository/parse_test.go @@ -16,6 +16,10 @@ func TestParseURI(t *testing.T) { 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()) From 3e773699d8b177a155fd77a4059c30a2be4e5b18 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Thu, 14 Jan 2021 12:00:30 +0000 Subject: [PATCH 058/145] Fix windows file parse issues --- storage/repository/parse.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/storage/repository/parse.go b/storage/repository/parse.go index 46c3bcac4c..36170dfefa 100644 --- a/storage/repository/parse.go +++ b/storage/repository/parse.go @@ -62,9 +62,8 @@ func ParseURI(s string) (fyne.URI, error) { path = path[2:] } - // this looks weird, but it makes sure that we still pass - // url.Parse() - s = NewFileURI(path).String() + // Windows files can break authority checks, so just return the parsed file URI + return NewFileURI(path), nil } repo, err := ForURI(&uri{scheme: scheme}) From 58dd77845eb48254c47c8ea60bcadff8d5f23d98 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Thu, 14 Jan 2021 12:08:44 +0000 Subject: [PATCH 059/145] Add missed test files on merge --- driver/software/testdata/entry.png | Bin 126 -> 125 bytes driver/software/testdata/entry_focus.png | Bin 153 -> 155 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/driver/software/testdata/entry.png b/driver/software/testdata/entry.png index 72d2c10619903dafd6d32935a6a39db7596b97aa..1691f1e6e5069ca819b3956461cf5741ab6bdc37 100644 GIT binary patch delta 94 zcmb=couCrw;_2cTQZeVv`9Mwv10Lp!IU!E=+DiYfo^|DVeD1*GQ`x oj1w}b^O!f2b29gIeFldA|E0b&=JnU61~CAEr>mdKI;Vst04-@G$^ZZW delta 95 zcmb=eo1hZq>gnPbQZeVv1xH?nKpv)xXO{^HG}YU3{M37~u(?q@EvNqO-_-X!mXl6B r>D@2^3Cw4Q_6M03GGquS@s$*?f}kZ}rK#c`n*VY)uUl c1H=FS)BmwAVNrcOl>rDmUHx3vIVCg!04w=67XSbN delta 124 zcmbQuIFoULN@;?pi(^Q|oFqd7gMuHePI?1geu<%woP&30m78VAE|Nj%b V*q5j^9+hGM0#8>zmvv4FO#o!RG9dr} From 3200caa6454217c5874941ad20153200b3b49e8a Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 14 Jan 2021 13:50:40 -0500 Subject: [PATCH 060/145] add tests for GenericParent and GenericChild --- storage/repository/generic.go | 24 +++++++++---- storage/repository/generic_test.go | 56 ++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 storage/repository/generic_test.go diff --git a/storage/repository/generic.go b/storage/repository/generic.go index bb2f7616be..a547e79359 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -7,6 +7,18 @@ import ( "fyne.io/fyne" ) +// 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. @@ -33,16 +45,14 @@ func GenericParent(u fyne.URI) (fyne.URI, error) { return parent, URIRootError } - components := strings.Split(u.Path(), "/") + components := splitNonEmpty(u.Path(), "/") newURI := u.Scheme() + "://" + u.Authority() // there will be at least one component, since we know we don't have // '/' or ''. - if len(components) == 1 { - // the immediate parent is the root - newURI += "/" - } else { + newURI += "/" + if len(components) > 1 { newURI += strings.Join(components[:len(components)-1], "/") } @@ -76,12 +86,12 @@ func GenericParent(u fyne.URI) (fyne.URI, error) { func GenericChild(u fyne.URI, component string) (fyne.URI, error) { // split into components and add the new one - components := strings.Split(u.Path(), "/") + components := splitNonEmpty(u.Path(), "/") components = append(components, component) // generate the scheme, authority, and path newURI := u.Scheme() + "://" + u.Authority() - newURI += "/" + strings.Join(components[:len(components)-1], "/") + newURI += "/" + strings.Join(components, "/") // stick the query and fragment back on the end if len(u.Query()) > 0 { diff --git a/storage/repository/generic_test.go b/storage/repository/generic_test.go new file mode 100644 index 0000000000..cd9c0023a2 --- /dev/null +++ b/storage/repository/generic_test.go @@ -0,0 +1,56 @@ +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:///", URIRootError}, + {"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) + + 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()) + } +} From 50641c35083bba4eb97a81dba47c327ce140bc09 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 14 Jan 2021 14:36:07 -0500 Subject: [PATCH 061/145] make InMemoryRepository listable and add tests --- internal/repository/memory.go | 84 +++++++++++++--- internal/repository/memory_test.go | 83 +++++++++++++-- storage/filter_test.go | 2 +- storage/uri.go | 18 ++-- storage/uri_test.go | 155 +++++++++++++++++++++++++++++ 5 files changed, 305 insertions(+), 37 deletions(-) diff --git a/internal/repository/memory.go b/internal/repository/memory.go index 0a74bb8ee4..16487e3535 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -7,6 +7,7 @@ import ( "fmt" "io" + "strings" ) // declare conformance to interfaces @@ -21,6 +22,7 @@ var _ repository.WriteableRepository = (*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 { @@ -50,7 +52,10 @@ type nodeReaderWriter struct { // // Since 2.0.0 type InMemoryRepository struct { - data map[string][]byte + // 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 } @@ -58,7 +63,7 @@ type InMemoryRepository struct { func (n *nodeReaderWriter) Read(p []byte) (int, error) { // first make sure the requested path actually exists - data, ok := n.repo.data[n.path] + data, ok := n.repo.Data[n.path] if !ok { return 0, fmt.Errorf("path '%s' not present in InMemoryRepository", n.path) } @@ -97,14 +102,14 @@ func (n *nodeReaderWriter) Close() error { func (n *nodeReaderWriter) Write(p []byte) (int, error) { // guarantee that the path exists - _, ok := n.repo.data[n.path] + _, ok := n.repo.Data[n.path] if !ok { - n.repo.data[n.path] = []byte{} + 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.repo.Data[n.path] = make([]byte, 0) n.writing = true } @@ -113,10 +118,10 @@ func (n *nodeReaderWriter) Write(p []byte) (int, error) { 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) + 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] + n.repo.Data[n.path][n.writeCursor] = p[n.writeCursor-start] count++ } @@ -139,7 +144,7 @@ func (n *nodeReaderWriter) URI() fyne.URI { // Since 2.0.0 func NewInMemoryRepository(scheme string) *InMemoryRepository { return &InMemoryRepository{ - data: make(map[string][]byte), + Data: make(map[string][]byte), scheme: scheme, } } @@ -152,7 +157,7 @@ func (m *InMemoryRepository) Exists(u fyne.URI) (bool, error) { return false, fmt.Errorf("invalid path '%s'", u.Path()) } - _, ok := m.data[u.Path()] + _, ok := m.Data[u.Path()] return ok, nil } @@ -164,7 +169,7 @@ func (m *InMemoryRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { return nil, fmt.Errorf("invalid path '%s'", u.Path()) } - _, ok := m.data[u.Path()] + _, ok := m.Data[u.Path()] if !ok { return nil, fmt.Errorf("no such path '%s' in InMemoryRepository", u.Path()) } @@ -180,7 +185,7 @@ func (m *InMemoryRepository) CanRead(u fyne.URI) (bool, error) { return false, fmt.Errorf("invalid path '%s'", u.Path()) } - _, ok := m.data[u.Path()] + _, ok := m.Data[u.Path()] if !ok { return false, fmt.Errorf("no such path '%s' in InMemoryRepository", u.Path()) } @@ -219,9 +224,9 @@ func (m *InMemoryRepository) CanWrite(u fyne.URI) (bool, error) { // // Since 2.0.0 func (m *InMemoryRepository) Delete(u fyne.URI) error { - _, ok := m.data[u.Path()] + _, ok := m.Data[u.Path()] if ok { - delete(m.data, u.Path()) + delete(m.Data, u.Path()) } return nil @@ -245,7 +250,6 @@ func (m *InMemoryRepository) Child(u fyne.URI, component string) (fyne.URI, erro // // Since: 2.0.0 func (m *InMemoryRepository) Copy(source, destination fyne.URI) error { - return repository.GenericCopy(source, destination) } @@ -255,3 +259,53 @@ func (m *InMemoryRepository) Copy(source, destination fyne.URI) error { func (m *InMemoryRepository) Move(source, destination fyne.URI) error { return repository.GenericMove(source, destination) } + +// CanList implements repository.MovableRepository.CanList() +// +// Since: 2.0.0 +func (m *InMemoryRepository) CanList(u fyne.URI) (bool, error) { + return m.Exists(u) +} + +// List implements repository.MovableRepository.List() +// +// Since: 2.0.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, "/") + + // 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 == len(prefixSplit) { + uri, err := storage.ParseURI(m.scheme + "://" + p) + if err != nil { + return nil, err + } + + listing = append(listing, uri) + } + } + + return listing, nil +} diff --git a/internal/repository/memory_test.go b/internal/repository/memory_test.go index cadb1694ce..3701e9c872 100644 --- a/internal/repository/memory_test.go +++ b/internal/repository/memory_test.go @@ -37,8 +37,8 @@ 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} + 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") @@ -62,8 +62,8 @@ 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} + 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") @@ -91,8 +91,8 @@ 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} + 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") @@ -116,8 +116,8 @@ 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} + 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") @@ -200,8 +200,8 @@ 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} + 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") @@ -225,7 +225,7 @@ 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{} + m.Data["/foo/bar/baz"] = []byte{} // and some URIs - we know that they will not fail parsing foo, _ := storage.ParseURI("mem:///foo/bar/baz") @@ -252,3 +252,64 @@ func TestInMemoryRepositoryChild(t *testing.T) { 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) + +} diff --git a/storage/filter_test.go b/storage/filter_test.go index 2aed27850a..7fd465c3af 100644 --- a/storage/filter_test.go +++ b/storage/filter_test.go @@ -10,7 +10,7 @@ import ( "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/uri.go b/storage/uri.go index dd54cbd3fa..6aceda4415 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -100,19 +100,17 @@ func Parent(u fyne.URI) (fyne.URI, error) { // // 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() + repo, err := repository.ForURI(u) + if err != nil { + return nil, err + } - // guarantee that there will be a path separator - if s[len(s)-1:] != "/" { - s += "/" + hrepo, ok := repo.(repository.HierarchicalRepository) + if !ok { + return nil, repository.OperationNotSupportedError } - return ParseURI(s + component) + return hrepo.Child(u, component) } // Exists determines if the resource referenced by the URI exists. diff --git a/storage/uri_test.go b/storage/uri_test.go index 9736ccd2e9..ed327f62a1 100644 --- a/storage/uri_test.go +++ b/storage/uri_test.go @@ -1,10 +1,13 @@ package storage_test import ( + "io/ioutil" "runtime" "testing" + intRepo "fyne.io/fyne/internal/repository" "fyne.io/fyne/storage" + "fyne.io/fyne/storage/repository" _ "fyne.io/fyne/test" @@ -210,3 +213,155 @@ 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.NotNil(t, err) +} From 844d52579ce3f6e5c5b75eb46c2c6538efc4c5e7 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 14 Jan 2021 14:41:00 -0500 Subject: [PATCH 062/145] fix linter error --- internal/repository/memory.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/repository/memory.go b/internal/repository/memory.go index 16487e3535..7807b8067a 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -286,7 +286,7 @@ func (m *InMemoryRepository) List(u fyne.URI) ([]fyne.URI, error) { // appropriate prefix, then eliminate those with too many path // components. listing := []fyne.URI{} - for p, _ := range m.Data { + 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 From 82796e9d062edbb68d224a431e9c37b596c2b52a Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 14 Jan 2021 14:55:04 -0500 Subject: [PATCH 063/145] start on file repository tests --- internal/repository/file_test.go | 101 +++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 internal/repository/file_test.go diff --git a/internal/repository/file_test.go b/internal/repository/file_test.go new file mode 100644 index 0000000000..3efd4dba43 --- /dev/null +++ b/internal/repository/file_test.go @@ -0,0 +1,101 @@ +package repository + +import ( + "io/ioutil" + "os" + "path" + "testing" + + "fyne.io/fyne/storage" + "fyne.io/fyne/storage/repository" + + "github.com/stretchr/testify/assert" +) + +func TestFileRepositoryRegistration(t *testing.T) { + f := NewFileRepository("file") + 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 tests 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("file") + 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) +} From e6f78d042ad45c5270623ed76a6cb16b5572781e Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 14 Jan 2021 14:59:28 -0500 Subject: [PATCH 064/145] use path.Join for FileRepository.Child Hopefully this will fix the test failures on Windows. --- internal/repository/file.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index 7f819b86b3..f3253c515a 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -4,6 +4,7 @@ import ( "fmt" "io/ioutil" "os" + "path" "path/filepath" "fyne.io/fyne" @@ -202,9 +203,18 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { // // Since: 2.0.0 func (r *FileRepository) Child(u fyne.URI, component string) (fyne.URI, error) { - // TODO: make sure that this works on Windows - might cause trouble - // if the path sep isn't normalized out on ingest. - return repository.GenericChild(u, component) + newURI := u.Scheme() + "://" + u.Authority() + newURI += path.Join(u.Path(), component) + + // stick the query and fragment back on the end + if len(u.Query()) > 0 { + newURI += "?" + u.Query() + } + if len(u.Fragment()) > 0 { + newURI += "#" + u.Fragment() + } + + return storage.ParseURI(newURI) } // List implements repository.HierarchicalRepository.List() From ef3285dba96aeda9f9a17b96ce5b052483e56ea2 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 14 Jan 2021 15:34:41 -0500 Subject: [PATCH 065/145] finish up FileRepository tests --- internal/repository/file.go | 15 +- internal/repository/file_test.go | 330 ++++++++++++++++++++++++++++- internal/repository/memory_test.go | 2 - 3 files changed, 339 insertions(+), 8 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index f3253c515a..ec99adefd5 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -142,6 +142,13 @@ func (r *FileRepository) CanWrite(u fyne.URI) (bool, error) { return false, nil } + if os.IsNotExist(err) { + // We may need to do extra logic to check if the + // directory is writeable, but presumably the + // IsPermission check covers this. + return true, nil + } + if err != nil { return false, err } @@ -192,11 +199,9 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { return storage.ParseURI(u.Scheme() + "://" + parent) } - uri, err := repository.GenericParent(u) - if err != nil { - return nil, err - } - return uri, nil + // Per the spec for storage.Parent(), we should only need to handle + // it for schemes we are registered to. + return nil, fmt.Errorf("FileRepository cannot handle unknown scheme '%s'", u.Scheme()) } // Child implements repository.HierarchicalRepository.Child diff --git a/internal/repository/file_test.go b/internal/repository/file_test.go index 3efd4dba43..ef9299f5c0 100644 --- a/internal/repository/file_test.go +++ b/internal/repository/file_test.go @@ -4,6 +4,7 @@ import ( "io/ioutil" "os" "path" + "runtime" "testing" "fyne.io/fyne/storage" @@ -59,7 +60,7 @@ func TestFileRepositoryReader(t *testing.T) { } defer os.RemoveAll(dir) - // Create some files to tests with. + // Create some files to test with. fooPath := path.Join(dir, "foo") barPath := path.Join(dir, "bar") bazPath := path.Join(dir, "baz") @@ -98,4 +99,331 @@ func TestFileRepositoryReader(t *testing.T) { // 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") + 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("file") + 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) + + // 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 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("file") + 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("file") + 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, storage.URIRootError, 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, storage.URIRootError, 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("file") + 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) + + listing, err := storage.List(foo) + assert.Nil(t, err) + stringListing := []string{} + for _, u := range listing { + stringListing = append(stringListing, u.String()) + } + assert.ElementsMatch(t, []string{"file://" + dir + "/foo/bar", "file://" + dir + "/foo/baz"}, stringListing) + } diff --git a/internal/repository/memory_test.go b/internal/repository/memory_test.go index 3701e9c872..528cc21324 100644 --- a/internal/repository/memory_test.go +++ b/internal/repository/memory_test.go @@ -266,7 +266,6 @@ func TestInMemoryRepositoryCopy(t *testing.T) { assert.Nil(t, err) assert.Equal(t, m.Data["/foo"], m.Data["/bar"]) - } func TestInMemoryRepositoryMove(t *testing.T) { @@ -286,7 +285,6 @@ func TestInMemoryRepositoryMove(t *testing.T) { exists, err := m.Exists(foo) assert.Nil(t, err) assert.False(t, exists) - } func TestInMemoryRepositoryListing(t *testing.T) { From d9d4a037b03b212d3a0c3d289d5bd133caf4ce22 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 14 Jan 2021 15:40:51 -0500 Subject: [PATCH 066/145] add more tests to storage --- storage/uri_test.go | 58 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/storage/uri_test.go b/storage/uri_test.go index ed327f62a1..f804576880 100644 --- a/storage/uri_test.go +++ b/storage/uri_test.go @@ -365,3 +365,61 @@ func TestCanRead(t *testing.T) { assert.False(t, bazCanRead) assert.NotNil(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 TestInMemoryRepositoryMove(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 TestInMemoryRepositoryListing(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) +} From 89b5339a7a6f75ed8008403a03cb1ef59c3926e0 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 14 Jan 2021 15:43:11 -0500 Subject: [PATCH 067/145] close handles before read --- internal/repository/file_test.go | 7 ++++++- internal/repository/memory_test.go | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/internal/repository/file_test.go b/internal/repository/file_test.go index ef9299f5c0..e7a48cc267 100644 --- a/internal/repository/file_test.go +++ b/internal/repository/file_test.go @@ -192,6 +192,12 @@ func TestFileRepositoryWriter(t *testing.T) { 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) @@ -425,5 +431,4 @@ func TestFileRepositoryListing(t *testing.T) { stringListing = append(stringListing, u.String()) } assert.ElementsMatch(t, []string{"file://" + dir + "/foo/bar", "file://" + dir + "/foo/baz"}, stringListing) - } diff --git a/internal/repository/memory_test.go b/internal/repository/memory_test.go index 528cc21324..932a3841eb 100644 --- a/internal/repository/memory_test.go +++ b/internal/repository/memory_test.go @@ -309,5 +309,4 @@ func TestInMemoryRepositoryListing(t *testing.T) { stringListing = append(stringListing, u.String()) } assert.ElementsMatch(t, []string{"mem:///foo/bar", "mem:///foo/baz/"}, stringListing) - } From 4ecf4afdff2f0dd5b98159147bf9fc392d0ef3d7 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 14 Jan 2021 15:48:22 -0500 Subject: [PATCH 068/145] hopefully fix Windows listing failures --- internal/repository/file_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/repository/file_test.go b/internal/repository/file_test.go index e7a48cc267..1f3c5981e3 100644 --- a/internal/repository/file_test.go +++ b/internal/repository/file_test.go @@ -430,5 +430,5 @@ func TestFileRepositoryListing(t *testing.T) { for _, u := range listing { stringListing = append(stringListing, u.String()) } - assert.ElementsMatch(t, []string{"file://" + dir + "/foo/bar", "file://" + dir + "/foo/baz"}, stringListing) + assert.ElementsMatch(t, []string{"file://" + path.Join(dir, "foo", "bar"), "file://" + path.Join(dir, "foo", "baz")}, stringListing) } From 6599c040d83b314ae71f4c2113df733a83ae75a1 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Thu, 14 Jan 2021 20:38:06 +0000 Subject: [PATCH 069/145] The ListableURI is still part of our public API, undeprecate We will track bringing this change back in at https://github.com/fyne-io/fyne/issues/1802 --- storage/file.go | 2 -- uri.go | 3 --- 2 files changed, 5 deletions(-) diff --git a/storage/file.go b/storage/file.go index fa2493da83..b399344aa2 100644 --- a/storage/file.go +++ b/storage/file.go @@ -27,8 +27,6 @@ func SaveFileToURI(uri fyne.URI) (fyne.URIWriteCloser, error) { // standard URI into a listable URI. // // Since: 1.4 -// -// Deprecated: this has been replaced by storage.List(URI) func ListerForURI(uri fyne.URI) (fyne.ListableURI, error) { listable, err := CanList(uri) if err != nil { diff --git a/uri.go b/uri.go index 3862319464..d5fcfedadb 100644 --- a/uri.go +++ b/uri.go @@ -82,9 +82,6 @@ type URI interface { // ListableURI represents a URI that can have child items, most commonly a // directory on disk in the native filesystem. // -// Deprecated: use the Listable() and List() methods that operate on URI in -// the storage package instead. -// // Since: 1.4 type ListableURI interface { URI From 521a7e557ceb53c89993c54d1ffd7de9cf505a8f Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Thu, 14 Jan 2021 20:51:01 +0000 Subject: [PATCH 070/145] Rip off the plaster and remove the largely-internal but public driver calls we have replaced --- driver.go | 17 ----- internal/driver/glfw/file.go | 27 ------- internal/driver/glfw/file_test.go | 112 ----------------------------- internal/driver/gomobile/file.go | 11 +-- internal/driver/gomobile/folder.go | 2 +- 5 files changed, 4 insertions(+), 165 deletions(-) delete mode 100644 internal/driver/glfw/file.go delete mode 100644 internal/driver/glfw/file_test.go diff --git a/driver.go b/driver.go index d03450afcc..e425614238 100644 --- a/driver.go +++ b/driver.go @@ -12,23 +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. - // - // Deprecated: this has been replaced by storage.Reader(URI) - 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. - // - // Deprecated: this has been replaced by storage.Writer(URI) - FileWriterForURI(URI) (URIWriteCloser, error) - - // ListerForURI converts a URI to a listable URI, if it is possible to do so. - // - // Deprecated: this has been replaced by storage.List(URI) - 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/internal/driver/glfw/file.go b/internal/driver/glfw/file.go deleted file mode 100644 index f9b9179f72..0000000000 --- a/internal/driver/glfw/file.go +++ /dev/null @@ -1,27 +0,0 @@ -package glfw - -import ( - "fyne.io/fyne" - "fyne.io/fyne/storage" -) - -// ListerForURI - wrapper for backwards-compatibility -// -// Deprecated: in 2.0.0 - use storage.List() and storage.CanList() instead -func (d *gLDriver) ListerForURI(uri fyne.URI) (fyne.ListableURI, error) { - return storage.ListerForURI(uri) -} - -// FileReaderForURI - wrapper for backwards-compatibility -// -// Deprecated: in 2.0.0 - use storage.Reader() instead -func (d *gLDriver) FileReaderForURI(uri fyne.URI) (fyne.URIReadCloser, error) { - return storage.Reader(uri) -} - -// FileWriterForURI - wrapper for backwards-compatibility -// -// Deprecated: in 2.0.0 - use storage.Writer() instead -func (d *gLDriver) FileWriterForURI(uri fyne.URI) (fyne.URIWriteCloser, error) { - return storage.Writer(uri) -} 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/gomobile/file.go b/internal/driver/gomobile/file.go index 7d1b172c47..22d05bb096 100644 --- a/internal/driver/gomobile/file.go +++ b/internal/driver/gomobile/file.go @@ -1,7 +1,6 @@ package gomobile import ( - "errors" "io" "github.com/fyne-io/mobile/app" @@ -20,7 +19,7 @@ func (f *fileOpen) URI() fyne.URI { return f.uri } -func (d *mobileDriver) FileReaderForURI(u fyne.URI) (fyne.URIReadCloser, error) { +func (d *mobileDriver) fileReaderForURI(u fyne.URI) (fyne.URIReadCloser, error) { file := &fileOpen{uri: u} read, err := nativeFileOpen(file) if read == nil { @@ -30,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{} @@ -57,7 +52,7 @@ 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)) + f, err := drv.fileReaderForURI(storage.NewURI(uri)) if f != nil { f.(*fileOpen).done = closer } @@ -72,7 +67,7 @@ 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)) + f, err := drv.listerForURI(storage.NewURI(uri)) callback(f, err) }, mobileFilter(filter)) } diff --git a/internal/driver/gomobile/folder.go b/internal/driver/gomobile/folder.go index 1d098039c9..08af6e64fb 100644 --- a/internal/driver/gomobile/folder.go +++ b/internal/driver/gomobile/folder.go @@ -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 (d *mobileDriver) listerForURI(uri fyne.URI) (fyne.ListableURI, error) { if !canListURI(uri) { return nil, fmt.Errorf("specified URI is not listable") } From 2f46934e7e7906ddb5c899b5d29a7369be4e5858 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 14 Jan 2021 15:56:49 -0500 Subject: [PATCH 071/145] use ToSlash() --- internal/repository/file_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/repository/file_test.go b/internal/repository/file_test.go index 1f3c5981e3..9e82c83f54 100644 --- a/internal/repository/file_test.go +++ b/internal/repository/file_test.go @@ -4,6 +4,7 @@ import ( "io/ioutil" "os" "path" + "path/filepath" "runtime" "testing" @@ -430,5 +431,5 @@ func TestFileRepositoryListing(t *testing.T) { for _, u := range listing { stringListing = append(stringListing, u.String()) } - assert.ElementsMatch(t, []string{"file://" + path.Join(dir, "foo", "bar"), "file://" + path.Join(dir, "foo", "baz")}, stringListing) + assert.ElementsMatch(t, []string{"file://" + filepath.ToSlash(path.Join(dir, "foo", "bar")), "file://" + filepath.ToSlash(path.Join(dir, "foo", "baz"))}, stringListing) } From 94404504a1923cec50b8b2c7746540c112d3c091 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 14 Jan 2021 16:03:22 -0500 Subject: [PATCH 072/145] close readers and writers in Generic* --- storage/repository/generic.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/storage/repository/generic.go b/storage/repository/generic.go index a547e79359..252870d8fb 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -142,11 +142,13 @@ func GenericCopy(source fyne.URI, destination fyne.URI) error { 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) @@ -197,11 +199,13 @@ func GenericMove(source fyne.URI, destination fyne.URI) error { 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) From 5b674f391f62b33f7d9d8a079d9d5aabbf0afb0e Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 14 Jan 2021 16:07:16 -0500 Subject: [PATCH 073/145] clarify documentation for CanRead and CanWrite --- storage/uri.go | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/storage/uri.go b/storage/uri.go index 6aceda4415..951fad47e5 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -128,8 +128,9 @@ func Child(u fyne.URI, component string) (fyne.URI, error) { // NOTE: since 2.0.0, Exists is backed by the repository system - this function // calls into a scheme-specific implementation from a registered repository. // -// may call into either a generic implementation, or into a scheme-specific -// implementation depending on which storage repositories have been registered. +// 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) { @@ -206,10 +207,13 @@ func Reader(u fyne.URI) (fyne.URIReadCloser, error) { } // CanRead determines if a given URI could be written to using the Reader() -// method. It is preferred to check if a URI is writable using this method +// 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 write and then report an error may be slower than the operations -// needed to test if a URI is writable. +// 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. // // CanRead is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. @@ -266,7 +270,11 @@ func Writer(u fyne.URI) (fyne.URIWriteCloser, error) { // 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. +// 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. + // // CanWrite is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. From 6607db59c6a4b0d1e38eeec163b70272c73b9763 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 14 Jan 2021 16:12:19 -0500 Subject: [PATCH 074/145] GenericMove: close reader before Delete() --- storage/repository/generic.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/repository/generic.go b/storage/repository/generic.go index 252870d8fb..cb30414640 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -199,7 +199,6 @@ func GenericMove(source fyne.URI, destination fyne.URI) error { if err != nil { return err } - defer srcReader.Close() dstWriter, err := destwrepo.Writer(destination) if err != nil { @@ -214,5 +213,6 @@ func GenericMove(source fyne.URI, destination fyne.URI) error { } // Finally, delete the source only if the move finished without error. + srcReader.Close() return srcwrepo.Delete(source) } From 86a3b24171752f628dda1145e18285cd3cebc70a Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 14 Jan 2021 16:18:24 -0500 Subject: [PATCH 075/145] clarify docs on storage.ParseURI --- storage/uri.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/storage/uri.go b/storage/uri.go index 951fad47e5..ba5e863384 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -19,8 +19,16 @@ func NewURI(s string) fyne.URI { return u } -// ParseURI creates a new URI instance by parsing a URI string, which must -// conform to IETF RFC3986. +// 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.0 func ParseURI(s string) (fyne.URI, error) { From 13558feab02a86987d40af2166358d4195f7703d Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 14 Jan 2021 16:31:16 -0500 Subject: [PATCH 076/145] Rename CanonicalRepository to CustomURIRepository As discussed here: https://github.com/fyne-io/fyne/pull/1768#issuecomment-760487057 --- storage/repository/generic.go | 4 ++-- storage/repository/parse.go | 2 +- storage/repository/repository.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/storage/repository/generic.go b/storage/repository/generic.go index cb30414640..15640c270b 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -69,7 +69,7 @@ func GenericParent(u fyne.URI) (fyne.URI, error) { // NOTE: we specifically want to use ParseURI, rather than &uri{}, // since the repository for the URI we just created might be a - // CanonicalRepository that implements it's own ParseURI. + // CustomURIRepository that implements it's own ParseURI. return ParseURI(newURI) } @@ -103,7 +103,7 @@ func GenericChild(u fyne.URI, component string) (fyne.URI, error) { // NOTE: we specifically want to use ParseURI, rather than &uri{}, // since the repository for the URI we just created might be a - // CanonicalRepository that implements it's own ParseURI. + // CustomURIRepository that implements it's own ParseURI. return ParseURI(newURI) } diff --git a/storage/repository/parse.go b/storage/repository/parse.go index 36170dfefa..3ba0f397fe 100644 --- a/storage/repository/parse.go +++ b/storage/repository/parse.go @@ -69,7 +69,7 @@ func ParseURI(s string) (fyne.URI, error) { repo, err := ForURI(&uri{scheme: scheme}) if err == nil { // If the repository registered for this scheme implements a parser - if c, ok := repo.(CanonicalRepository); ok { + if c, ok := repo.(CustomURIRepository); ok { return c.ParseURI(s) } } diff --git a/storage/repository/repository.go b/storage/repository/repository.go index 678d625657..bcd1f41830 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -70,7 +70,7 @@ type Repository interface { Destroy(string) } -// CanonicalRepository is an extension of the repository interface which +// 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. @@ -80,7 +80,7 @@ type Repository interface { // storage repository to delegate to for parsing. // // Since: 2.0.0 -type CanonicalRepository interface { +type CustomURIRepository interface { Repository // ParseURI will be used to implement calls to storage.ParseURI() From 877798ab70227f6e12c4bf724efc92c44fc7b8c7 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Thu, 14 Jan 2021 21:58:58 +0000 Subject: [PATCH 077/145] As themes can override these methods now we add some safety --- theme/theme.go | 70 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/theme/theme.go b/theme/theme.go index 6daf643e22..3de6e09d18 100644 --- a/theme/theme.go +++ b/theme/theme.go @@ -325,12 +325,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. @@ -340,79 +340,79 @@ 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 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 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 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 func ForegroundColor() color.Color { - return current().Color(ColorNameForeground, currentVariant()) + return safeColorLookup(ColorNameForeground, currentVariant()) } // 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). @@ -429,27 +429,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 @@ -545,6 +545,36 @@ 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 { + return &color.NRGBA{} + } + return col +} + +func safeFontLookup(s fyne.TextStyle) fyne.Resource { + col := current().Font(s) + if col != nil { + return col + } + + 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{} From 1dc3d2f299833045cc394ccc56f7a026c2ae9433 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Thu, 14 Jan 2021 19:24:32 -0500 Subject: [PATCH 078/145] document registered-scheme guarntee --- storage/repository/repository.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/storage/repository/repository.go b/storage/repository/repository.go index bcd1f41830..f6049f59e1 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -33,6 +33,11 @@ var repositoryTable map[string]Repository = map[string]Repository{} // 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 From 140a14387bad2d1cb2d340a7421bb25a18d0d4ca Mon Sep 17 00:00:00 2001 From: FPabl0 Date: Fri, 15 Jan 2021 03:49:34 -0500 Subject: [PATCH 079/145] remove popup pos offset, added some X-axis padding to MinSize --- widget/select.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/widget/select.go b/widget/select.go index f028e9470a..e71d9a933d 100644 --- a/widget/select.go +++ b/widget/select.go @@ -230,7 +230,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+1)) + return buttonPos.Add(fyne.NewPos(theme.Padding(), s.Size().Height)) } func (s *Select) showPopUp() { @@ -332,9 +332,10 @@ func (s *selectRenderer) MinSize() fyne.Size { s.combo.propertyLock.RLock() defer s.combo.propertyLock.RUnlock() - // pad - label - pad - icon - pad*2 + // x1 x4 (reserved) x1 x1 x2 + // pad - label - pad - icon - pad*2 min := s.label.MinSize() - min = min.Add(fyne.NewSize(theme.Padding()*2, theme.Padding()*2)) + min = min.Add(fyne.NewSize(theme.Padding()*6, theme.Padding()*2)) return min.Add(fyne.NewSize(theme.IconInlineSize()+theme.Padding()*2, 0)) } From 50f0d9b91dd65f2702b2c864561522244c63c9b4 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Fri, 15 Jan 2021 10:54:37 +0000 Subject: [PATCH 080/145] Add icon safety as well --- theme/icons.go | 166 ++++++++++++++++++++++++++----------------------- 1 file changed, 87 insertions(+), 79 deletions(-) diff --git a/theme/icons.go b/theme/icons.go index 5fcae9c4ef..c5386eed4d 100644 --- a/theme/icons.go +++ b/theme/icons.go @@ -666,395 +666,403 @@ 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 { + return &fyne.StaticResource{} + } + return icon } From 7faf52670ab97e123f29220c0bd98e684d1a3377 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Fri, 15 Jan 2021 10:59:01 +0000 Subject: [PATCH 081/145] Add test for theme not crashing Also remove old comment - we now have DefaultTheme() if we need it --- theme/theme_test.go | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/theme/theme_test.go b/theme/theme_test.go index 2b1b94065c..9d88072cd0 100644 --- a/theme/theme_test.go +++ b/theme/theme_test.go @@ -1,17 +1,13 @@ package theme import ( + "image/color" "testing" - "fyne.io/fyne" "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()) -//} + "fyne.io/fyne" +) func TestThemeChange(t *testing.T) { fyne.CurrentApp().Settings().SetTheme(DarkTheme()) @@ -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 +} From 7975740ad9a33ee00095d1a584a8a8ad78be0979 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Fri, 15 Jan 2021 14:39:09 +0000 Subject: [PATCH 082/145] Tidy up mobile code, remove un-needed lines --- internal/driver/gomobile/file.go | 6 +++--- internal/driver/gomobile/file_desktop.go | 11 +++-------- internal/driver/gomobile/folder.go | 2 +- internal/driver/gomobile/folder_desktop.go | 12 ++++++------ internal/driver/gomobile/repository.go | 2 +- 5 files changed, 14 insertions(+), 19 deletions(-) diff --git a/internal/driver/gomobile/file.go b/internal/driver/gomobile/file.go index 22d05bb096..aafd8e39af 100644 --- a/internal/driver/gomobile/file.go +++ b/internal/driver/gomobile/file.go @@ -19,7 +19,7 @@ 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 { @@ -52,7 +52,7 @@ 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)) + f, err := fileReaderForURI(storage.NewURI(uri)) if f != nil { f.(*fileOpen).done = closer } @@ -67,7 +67,7 @@ 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)) + f, err := listerForURI(storage.NewURI(uri)) callback(f, err) }, mobileFilter(filter)) } diff --git a/internal/driver/gomobile/file_desktop.go b/internal/driver/gomobile/file_desktop.go index 98b74cac49..31bd59fbde 100644 --- a/internal/driver/gomobile/file_desktop.go +++ b/internal/driver/gomobile/file_desktop.go @@ -3,20 +3,15 @@ package gomobile import ( - "errors" "io" - "os" intRepo "fyne.io/fyne/internal/repository" "fyne.io/fyne/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") - } - - return os.Open(f.uri.String()[7:]) +func nativeFileOpen(*fileOpen) (io.ReadCloser, error) { + // no-op as we use the internal FileRepository + return nil, nil } func registerRepository(d *mobileDriver) { diff --git a/internal/driver/gomobile/folder.go b/internal/driver/gomobile/folder.go index 08af6e64fb..70540e58a3 100644 --- a/internal/driver/gomobile/folder.go +++ b/internal/driver/gomobile/folder.go @@ -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_desktop.go b/internal/driver/gomobile/folder_desktop.go index 0aa3e488a5..006a98942f 100644 --- a/internal/driver/gomobile/folder_desktop.go +++ b/internal/driver/gomobile/folder_desktop.go @@ -4,14 +4,14 @@ package gomobile import ( "fyne.io/fyne" - "fyne.io/fyne/storage" ) -func canListURI(u fyne.URI) bool { - listable, _ := storage.CanList(u) - return listable +func canListURI(fyne.URI) bool { + // no-op as we use the internal FileRepository + return false } -func listURI(u fyne.URI) ([]fyne.URI, error) { - return storage.List(u) +func listURI(fyne.URI) ([]fyne.URI, error) { + // no-op as we use the internal FileRepository + return nil, nil } diff --git a/internal/driver/gomobile/repository.go b/internal/driver/gomobile/repository.go index 4c626786e1..d68c4cccb5 100644 --- a/internal/driver/gomobile/repository.go +++ b/internal/driver/gomobile/repository.go @@ -15,7 +15,7 @@ func (m *mobileFileRepo) Exists(u fyne.URI) (bool, error) { } func (m *mobileFileRepo) Reader(u fyne.URI) (fyne.URIReadCloser, error) { - return m.driver.FileReaderForURI(u) + return fileReaderForURI(u) } func (m *mobileFileRepo) CanRead(u fyne.URI) (bool, error) { From 5aa2dcd11c3120eeeae3ad0fbc3da3f5bb747900 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Fri, 15 Jan 2021 16:06:48 +0000 Subject: [PATCH 083/145] use single values for fallbacks --- theme/icons.go | 2 +- theme/theme.go | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/theme/icons.go b/theme/icons.go index c5386eed4d..6cda4e13ef 100644 --- a/theme/icons.go +++ b/theme/icons.go @@ -1062,7 +1062,7 @@ func UploadIcon() fyne.Resource { func safeIconLookup(n fyne.ThemeIconName) fyne.Resource { icon := current().Icon(n) if icon == nil { - return &fyne.StaticResource{} + return fallbackIcon } return icon } diff --git a/theme/theme.go b/theme/theme.go index 3de6e09d18..ab713cb5d7 100644 --- a/theme/theme.go +++ b/theme/theme.go @@ -163,7 +163,9 @@ const ( ) var ( - defaultTheme = setupDefaultTheme() + defaultTheme = setupDefaultTheme() + fallbackColor = color.Transparent + fallbackIcon = &fyne.StaticResource{} errorColor = color.NRGBA{0xf4, 0x43, 0x36, 0xff} primaryColors = map[string]color.Color{ @@ -548,7 +550,7 @@ func loadCustomFont(env, variant string, fallback fyne.Resource) fyne.Resource { func safeColorLookup(n fyne.ThemeColorName, v fyne.ThemeVariant) color.Color { col := current().Color(n, v) if col == nil { - return &color.NRGBA{} + return fallbackColor } return col } From a8e33e8d9f9b1c12e53ccdd9617486dfda14591b Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Fri, 15 Jan 2021 19:51:46 +0000 Subject: [PATCH 084/145] Log errors when theme is incomplete --- theme/icons.go | 1 + theme/theme.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/theme/icons.go b/theme/icons.go index 6cda4e13ef..9bf4fc02aa 100644 --- a/theme/icons.go +++ b/theme/icons.go @@ -1062,6 +1062,7 @@ func UploadIcon() fyne.Resource { 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/theme.go b/theme/theme.go index ab713cb5d7..0f94b1b306 100644 --- a/theme/theme.go +++ b/theme/theme.go @@ -550,6 +550,7 @@ func loadCustomFont(env, variant string, fallback fyne.Resource) fyne.Resource { 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 @@ -560,6 +561,7 @@ func safeFontLookup(s fyne.TextStyle) fyne.Resource { if col != nil { return col } + fyne.LogError("Loaded theme returned nil font", nil) if s.Monospace { return DefaultTextMonospaceFont() From 537b8b4fe4341847164f44111567c9824a77cf8e Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Fri, 15 Jan 2021 20:03:30 +0000 Subject: [PATCH 085/145] Use ugly colors in hints mode for missing icon or color --- theme/theme.go | 4 +--- theme/theme_hints.go | 8 ++++++++ theme/theme_other.go | 14 ++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 theme/theme_hints.go create mode 100644 theme/theme_other.go diff --git a/theme/theme.go b/theme/theme.go index 0f94b1b306..a00feb3ef1 100644 --- a/theme/theme.go +++ b/theme/theme.go @@ -163,9 +163,7 @@ const ( ) var ( - defaultTheme = setupDefaultTheme() - fallbackColor = color.Transparent - fallbackIcon = &fyne.StaticResource{} + defaultTheme = setupDefaultTheme() errorColor = color.NRGBA{0xf4, 0x43, 0x36, 0xff} primaryColors = map[string]color.Color{ 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..753e925e32 --- /dev/null +++ b/theme/theme_other.go @@ -0,0 +1,14 @@ +// +build !hints + +package theme + +import ( + "image/color" + + "fyne.io/fyne" +) + +var ( + fallbackColor = color.Transparent + fallbackIcon = &fyne.StaticResource{} +) From 93b9c6d35ec00638cbee43dd1eee9ef0a776bbe4 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Fri, 15 Jan 2021 21:36:21 +0000 Subject: [PATCH 086/145] Refactoring the tabcontainer to apptabs --- cmd/fyne_settings/main.go | 8 +- cmd/fyne_settings/settings/appearance.go | 12 +- .../appTabs_test.go | 47 +-- .../tabcontainer.go => container/apptabs.go | 110 +++--- container/apptabs_desktop_test.go | 347 ++++++++++++++++++ .../apptabs_extend_test.go | 12 +- .../apptabs_internal_test.go | 9 +- container/apptabs_mobile_test.go | 347 ++++++++++++++++++ container/tabs.go | 56 --- .../desktop/change_content_change_hidden.xml | 6 +- .../desktop/change_content_change_visible.xml | 6 +- .../desktop/change_content_initial.xml | 6 +- .../desktop/change_icon_change_selected.xml | 6 +- .../desktop/change_icon_change_unselected.xml | 6 +- .../apptabs}/desktop/change_icon_initial.xml | 6 +- .../desktop/change_label_change_selected.xml | 6 +- .../change_label_change_unselected.xml | 6 +- .../apptabs}/desktop/change_label_initial.xml | 6 +- .../apptabs}/desktop/dynamic_appended.xml | 6 +- .../desktop/dynamic_appended_and_removed.xml | 4 +- .../dynamic_appended_another_three.xml | 10 +- .../apptabs}/desktop/dynamic_initial.xml | 4 +- .../desktop/dynamic_replaced_completely.xml | 8 +- .../testdata/apptabs}/desktop/hover_first.xml | 6 +- .../testdata/apptabs}/desktop/hover_none.xml | 6 +- .../apptabs}/desktop/hover_second.xml | 6 +- .../apptabs}/desktop/layout_bottom_icon.xml | 4 +- .../desktop/layout_bottom_icon_and_text.xml | 4 +- .../apptabs}/desktop/layout_bottom_text.xml | 4 +- .../apptabs}/desktop/layout_leading_icon.xml | 4 +- .../desktop/layout_leading_icon_and_text.xml | 4 +- .../apptabs}/desktop/layout_leading_text.xml | 4 +- .../apptabs}/desktop/layout_top_icon.xml | 4 +- .../desktop/layout_top_icon_and_text.xml | 4 +- .../apptabs}/desktop/layout_top_text.xml | 4 +- .../apptabs}/desktop/layout_trailing_icon.xml | 4 +- .../desktop/layout_trailing_icon_and_text.xml | 4 +- .../apptabs}/desktop/layout_trailing_text.xml | 4 +- .../apptabs}/desktop/single_custom_theme.png | Bin .../apptabs}/desktop/single_initial.png | Bin .../apptabs}/desktop/tab_location_bottom.xml | 8 +- .../apptabs}/desktop/tab_location_leading.xml | 8 +- .../apptabs}/desktop/tab_location_top.xml | 8 +- .../desktop/tab_location_trailing.xml | 8 +- .../desktop/tapped_first_selected.xml | 8 +- .../desktop/tapped_second_selected.xml | 8 +- .../desktop/tapped_third_selected.xml | 8 +- .../mobile/change_content_change_hidden.xml | 6 +- .../mobile/change_content_change_visible.xml | 6 +- .../mobile/change_content_initial.xml | 6 +- .../mobile/change_icon_change_selected.xml | 6 +- .../mobile/change_icon_change_unselected.xml | 6 +- .../apptabs}/mobile/change_icon_initial.xml | 6 +- .../mobile/change_label_change_selected.xml | 6 +- .../mobile/change_label_change_unselected.xml | 6 +- .../apptabs}/mobile/change_label_initial.xml | 6 +- .../apptabs}/mobile/dynamic_appended.xml | 6 +- .../mobile/dynamic_appended_and_removed.xml | 4 +- .../mobile/dynamic_appended_another_three.xml | 10 +- .../apptabs}/mobile/dynamic_initial.xml | 4 +- .../mobile/dynamic_replaced_completely.xml | 8 +- .../testdata/apptabs}/mobile/hover_none.xml | 6 +- .../apptabs}/mobile/layout_bottom_ico.xml | 4 +- .../apptabs}/mobile/layout_bottom_icon.xml | 4 +- .../mobile/layout_bottom_icon_and_text.xml | 4 +- .../apptabs}/mobile/layout_bottom_text.xml | 4 +- .../apptabs}/mobile/layout_top_icon.xml | 4 +- .../mobile/layout_top_icon_and_text.xml | 4 +- .../apptabs}/mobile/layout_top_text.xml | 4 +- .../apptabs}/mobile/single_custom_theme.png | Bin .../testdata/apptabs}/mobile/single_dark.png | Bin .../apptabs}/mobile/single_initial.png | Bin .../apptabs}/mobile/tab_location_bottom.xml | 8 +- .../apptabs}/mobile/tab_location_top.xml | 8 +- .../apptabs}/mobile/tapped_first_selected.xml | 8 +- .../mobile/tapped_second_selected.xml | 8 +- .../apptabs}/mobile/tapped_third_selected.xml | 8 +- .../testdata/apptabs/mobile/theme_default.png | Bin 0 -> 1898 bytes .../testdata/apptabs}/mobile/theme_ugly.png | Bin widget/tabcontainer_desktop_test.go | 346 ----------------- widget/tabcontainer_mobile_test.go | 346 ----------------- .../tabcontainer/mobile/theme_default.png | Bin 1899 -> 0 bytes 82 files changed, 981 insertions(+), 1027 deletions(-) rename widget/tabcontainer_test.go => container/appTabs_test.go (60%) rename widget/tabcontainer.go => container/apptabs.go (85%) create mode 100644 container/apptabs_desktop_test.go rename widget/tabcontainer_extend_test.go => container/apptabs_extend_test.go (90%) rename widget/tabcontainer_internal_test.go => container/apptabs_internal_test.go (75%) create mode 100644 container/apptabs_mobile_test.go delete mode 100644 container/tabs.go rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/change_content_change_hidden.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/change_content_change_visible.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/change_content_initial.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/change_icon_change_selected.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/change_icon_change_unselected.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/change_icon_initial.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/change_label_change_selected.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/change_label_change_unselected.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/change_label_initial.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/dynamic_appended.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/dynamic_appended_and_removed.xml (81%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/dynamic_appended_another_three.xml (70%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/dynamic_initial.xml (81%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/dynamic_replaced_completely.xml (72%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/hover_first.xml (77%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/hover_none.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/hover_second.xml (77%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/layout_bottom_icon.xml (78%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/layout_bottom_icon_and_text.xml (81%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/layout_bottom_text.xml (78%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/layout_leading_icon.xml (78%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/layout_leading_icon_and_text.xml (81%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/layout_leading_text.xml (78%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/layout_top_icon.xml (78%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/layout_top_icon_and_text.xml (81%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/layout_top_text.xml (78%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/layout_trailing_icon.xml (78%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/layout_trailing_icon_and_text.xml (81%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/layout_trailing_text.xml (78%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/single_custom_theme.png (100%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/single_initial.png (100%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/tab_location_bottom.xml (72%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/tab_location_leading.xml (72%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/tab_location_top.xml (72%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/tab_location_trailing.xml (72%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/tapped_first_selected.xml (72%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/tapped_second_selected.xml (72%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/desktop/tapped_third_selected.xml (72%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/change_content_change_hidden.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/change_content_change_visible.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/change_content_initial.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/change_icon_change_selected.xml (74%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/change_icon_change_unselected.xml (74%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/change_icon_initial.xml (74%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/change_label_change_selected.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/change_label_change_unselected.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/change_label_initial.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/dynamic_appended.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/dynamic_appended_and_removed.xml (80%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/dynamic_appended_another_three.xml (70%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/dynamic_initial.xml (80%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/dynamic_replaced_completely.xml (72%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/hover_none.xml (75%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/layout_bottom_ico.xml (77%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/layout_bottom_icon.xml (77%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/layout_bottom_icon_and_text.xml (81%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/layout_bottom_text.xml (78%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/layout_top_icon.xml (77%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/layout_top_icon_and_text.xml (81%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/layout_top_text.xml (78%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/single_custom_theme.png (100%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/single_dark.png (100%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/single_initial.png (100%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/tab_location_bottom.xml (72%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/tab_location_top.xml (72%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/tapped_first_selected.xml (72%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/tapped_second_selected.xml (72%) rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/tapped_third_selected.xml (72%) create mode 100644 container/testdata/apptabs/mobile/theme_default.png rename {widget/testdata/tabcontainer => container/testdata/apptabs}/mobile/theme_ugly.png (100%) delete mode 100644 widget/tabcontainer_desktop_test.go delete mode 100644 widget/tabcontainer_mobile_test.go delete mode 100644 widget/testdata/tabcontainer/mobile/theme_default.png diff --git a/cmd/fyne_settings/main.go b/cmd/fyne_settings/main.go index 39b0f577f5..f6f337cf65 100644 --- a/cmd/fyne_settings/main.go +++ b/cmd/fyne_settings/main.go @@ -4,7 +4,7 @@ import ( "fyne.io/fyne" "fyne.io/fyne/app" "fyne.io/fyne/cmd/fyne_settings/settings" - "fyne.io/fyne/widget" + "fyne.io/fyne/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..f599c73838 100644 --- a/cmd/fyne_settings/settings/appearance.go +++ b/cmd/fyne_settings/settings/appearance.go @@ -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/widget/tabcontainer_test.go b/container/appTabs_test.go similarity index 60% rename from widget/tabcontainer_test.go rename to container/appTabs_test.go index df22fc1767..3a03955c39 100644 --- a/widget/tabcontainer_test.go +++ b/container/appTabs_test.go @@ -1,9 +1,10 @@ -package widget_test +package container_test import ( "testing" "fyne.io/fyne" + "fyne.io/fyne/container" "fyne.io/fyne/theme" "fyne.io/fyne/widget" @@ -11,23 +12,23 @@ import ( ) 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 85% rename from widget/tabcontainer.go rename to container/apptabs.go index fbfacf6e9f..c21bfc8e40 100644 --- a/widget/tabcontainer.go +++ b/container/apptabs.go @@ -1,4 +1,4 @@ -package widget +package container import ( "fyne.io/fyne" @@ -7,14 +7,16 @@ import ( "fyne.io/fyne/internal" "fyne.io/fyne/layout" "fyne.io/fyne/theme" + "fyne.io/fyne/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..dbd558bf4d --- /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" + "fyne.io/fyne/canvas" + "fyne.io/fyne/container" + "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( + 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 90% rename from widget/tabcontainer_extend_test.go rename to container/apptabs_extend_test.go index e4005bae61..b8f32feaa6 100644 --- a/widget/tabcontainer_extend_test.go +++ b/container/apptabs_extend_test.go @@ -1,4 +1,4 @@ -package widget +package container import ( "testing" @@ -6,12 +6,14 @@ import ( "fyne.io/fyne" "fyne.io/fyne/test" "fyne.io/fyne/theme" + "fyne.io/fyne/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 75% rename from widget/tabcontainer_internal_test.go rename to container/apptabs_internal_test.go index 4766868418..2675a07d1a 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/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..e1f1ef4e90 --- /dev/null +++ b/container/apptabs_mobile_test.go @@ -0,0 +1,347 @@ +// +build mobile + +package container_test + +import ( + "testing" + + "fyne.io/fyne" + "fyne.io/fyne/canvas" + "fyne.io/fyne/container" + "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( + 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/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 0000000000000000000000000000000000000000..6a60930a41978d4a5f28465d32875dba9b44b092 GIT binary patch literal 1898 zcmds2={MU67k1hg6;)@fb5xPoTGCOpQ617Y(h_ScD5auDEk`Akpe12Oc~Nbrm0~R6 z5UPnrYa2`alG>tZEz#P=61Bx1TP(?I&YYezbI$w)?}vNubMLtyo)6D`ZpsZuYdMe_ zNJ2tF4rPOMKCBsk#<3%Zxzcy0T0%nF7=^s*@-TOC^iD8(_Eg)Nc+E3@>BrgDNQ8}r zcjb*Qehwy*gX}9Q$Fh5(D^b9lO6?VX(eYzxnP>2&$u8|S$*yl1KBUZJ5K{-YY*0w* zjVfhqV#X60w+r$A5u};<<_?3O^9JFuuUnvyVhXI$Jx;LaH6$-@-EEE`hZky((Aezj zN4k`Tyd|Kj3KdBSi(qh!%}0&zkQQvDg{8kM+hgBu=J5crdQ==?q5mZ7(}XZcTm429QWmZ9_}&uY!1y()|<%ZRAgqH+E-vMHIzBqwp+2NoK-H1?Ib^{ zTWI6r=y)#Bwff}KVT*5r_olN048R&9>vRNdEU-#xrgbWXuMPgq%pO^4w|?JDrRy4R z^W-xmo_KykOTBw$x%f9s)9Prm%Y#QEj+ttvrsbTcnexGUHH}bhB8+?p+2Ai<#e{ZM zIfqX@%RI~8Z_Qd^#)VIdf&)7BQchzi(J|xxklj{IIAEeqSl+9G?km85y;CW#iPO4}*$*H47p8^{C`cU?r-|rN`G?E)KqoiOOQ3jD zONl|S?D4v#mYT{;RUGmbp*yGv#n%J_?VKj%GRy_&37T?;@*~@AYwpU|-j+ZHm6nLRi@j@s&>!+hal1K&4)5G!Yk>w%5fSLUq-wW6 z|G0ed>{eDgHKEzpR5l9vHBr2Cw7@;=oD)4+zXkLx3}zr+BE=kJ0wJQ>-JgxpU0hY5 zZnsKx5|Q>!9l5qUlL4e=#ez-0-SLBlnW=z$#opbpvCnH+QPCkxuDb{0!MBOA`K;u9 z4x-_tc7YHbX@WqirLU9o0Sm>K<9ng|93QQby_b2p(I52m-yCe`iwSYo2H{xIjV}^75`oQs3}rS1t8_FlAHL~O?czr zGqD8|(0lSSLsp2b7cVSz{tW`Unv%(u7y@UF*Cs73ozJ6b$=NB?kKxFU)<`)y zxy{W@eWyJ8=P>}cWDp+_vB?Euu&@!++XjR>T^XZ0(L1H`dL-)W*Zw{}6S9?p_4R(b zr+z~11Kxk3oyejAe)Vm7_pE2GFD$2da`n?Edo-GKol@=&MNSKZ2@~59k}8~9RoqZT z>pVUZk5{*h-q@J$I|&Q6k>W2b443;_hjnc&jWFu#?e+Q^A4^9q4ZFI!ZjMMs18`r) zYN6fcePjPh;m4QSC643;KA)sR1pt6Tp%fRl^42b@Kkx7FFTM2+1U{jDaU%30Zmd3H zszoLdaktz(6#Ti$rMrpEW>cwDCKC=(Kx}MnWn^Z0(%m3obzW9hR!Q=jaQs|PPtS|a zZyl@IcT*1cpF9CkdI$UZNQ6=sgOoQ#Mblm6pApHvZO_fsPoUBc$tJ~c!!v>q;Fh_$ zH)FUsd?Yf)ZX=h(3D0hDg0K~5}S5RV8Fl=SC&Q$1x#bRSw ztdf$pc|4aD$D-5En#0Y_>-;}w7ZyTLX+0+4&XyHuG#ZvefB*hHgTY|2#GkTE9UL5x zUq(m0Fqn{<5kC({9fe2+P*#T9ULHf@mq+V-&OO{(^r#uZ!g5R-w2jKDE?d(E__83- zkzcRqCJob5mGou78pP0}S-*HH{oS6wi}jzT{r@@L d9zT4WV)4*ZbK;UbPvfwWKwWc0mLYuN{|BQh!ejsd literal 0 HcmV?d00001 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/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/testdata/tabcontainer/mobile/theme_default.png b/widget/testdata/tabcontainer/mobile/theme_default.png deleted file mode 100644 index a18a6bbe24a13cc7ff5ab5b7c8b43e26bf9dc8ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1899 zcmds2`#0MO7Pr$aOKFBlwQH!xTc>Cd)2d;r-+GjWif2h^C|asff@;N(c(gMZk$N=L zjvy1MSJE`o5IM#pG`g8kI^IPw@kkm*JR(eX_w1fM-Tz>JxX*LX=iVRg=iZ0DFn28t zJq;BV6)jH>z)xvQ{~>?*M5!5(3rrOiHCs>Mf`3}&$^;@FzG%Rc?n~oZ3?j{2ujuH2 z{0OH0+0ZnNmVzvTw*3#{=%JJ>jj+FA{8azk&j+&ufQBd&{HM#-zVkU3qU!rE<30r9 z>5Z#_!PN4I0AoVL)EY`Z&!jt1f1D>EmS3ukw}%{Cmh3towYZno@-(T#ak1Q3{^PB< zIQ6sesPsRz1bg%y*P-X(S0Ir4|8}XioNo@srE%gB6;hE@#s%#-YdP@_HGm11EicXW zA8lo8zAO7BdSt9|hr+v}y0OlQ;ENkx4Ne%gXWS5a@inpP)6xll%epsB%_pH9`$buH zRh#)1dL{7BzH*laex*raqwsoGUww&s4~p-u*_r z@p55{v>b1?x-yU|m}a|xZ{CY+1c>CT9gI{fZN)4{(7aLD@%!y-V61v|XKfH=M{qeHi(O1)5K8P>srqGi8b+ds2L}HeQXzW2d^A{k(<3yc%&8o;8ki~ zzWAVV#Z>-5egl3w9ctrF*8C2z8E9{o?#}Nik(TZ<029x_0gOK*J!el4bRe@$+o+}( zy?blZgA;kl3F2rCica4aSkiQw`a&HPlyf{e?aAl`reCW!?RSOUhe=Fn^JwxNahRfa zb7iVXE=ZXoalGlJ0qXM=W;hU8nX1+=>M1F<+@_c}4RfO9GpUcf8rcYD9XxRxWGIVC zXtnVUG+kK*33er}8$#|yjh%fDWmC!~!}I($aevST&14)n<(C6s`5)UGMjbV4I zj#x%}Xi6Z@ojJ3PB<2$}ET@0ec6HJ(;wSk$$<=>+wOO;E2c?cxXDk7ZUs!*uMurc$ zC|Kc3uVJU5TST6#g4#!V-aB6C1zqHd-y*TD@ol26tMLi2#p6SZ- zsd5|^3L&0;a5y|EXPi}`sUI*rG2GuIbh<8Zj*zB0q6NPE317=<@id}CCUEFNb`l$Zd~ z+w6$Ogri5>ws_X7%(`bzT3=sZQ)86ldYyTVb$h&Yht}KM>ud35WMn~_mYbWa_xb1W zxvs7*T43WVKEK37-D)VN<9+YWO!*za7BAvIj)hTe}?hKpu zqguUTu)?Au8&vU!Q-`o&u4%na=7%6p+Y=9nzVQP8=Qw}7djE61|Gx@0tCfFqe;-LX Un>AxVgeU_Q&r2|%$u%PT5BUJadH?_b From c0dc44a2d1c73ea6fb37a30063b367dc70bc2707 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sat, 16 Jan 2021 15:10:42 -0500 Subject: [PATCH 087/145] switch to more ideomatic error naming thank you @stuartmscott context: https://github.com/fyne-io/fyne/pull/1768#discussion_r558489594 --- dialog/file.go | 3 +- internal/repository/file.go | 4 +-- internal/repository/file_test.go | 4 +-- storage/repository/errors.go | 56 ++++++++++++------------------ storage/repository/generic.go | 10 +++--- storage/repository/generic_test.go | 2 +- storage/uri.go | 34 +++++++++--------- storage/uri_root_error.go | 4 +-- storage/uri_test.go | 8 ++--- 9 files changed, 57 insertions(+), 68 deletions(-) diff --git a/dialog/file.go b/dialog/file.go index 49005f4dc3..bce08d5b98 100644 --- a/dialog/file.go +++ b/dialog/file.go @@ -11,6 +11,7 @@ import ( "fyne.io/fyne/container" "fyne.io/fyne/layout" "fyne.io/fyne/storage" + "fyne.io/fyne/storage/repository" "fyne.io/fyne/theme" "fyne.io/fyne/widget" ) @@ -243,7 +244,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 } diff --git a/internal/repository/file.go b/internal/repository/file.go index ec99adefd5..b61229bcbc 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -180,7 +180,7 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { // Completely empty URI with just a scheme if len(s) == 0 { - return nil, repository.URIRootError + return nil, repository.ErrURIRoot } parent := "" @@ -193,7 +193,7 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { // only root is it's own parent if filepath.Clean(parent) == filepath.Clean(s) { - return nil, repository.URIRootError + return nil, repository.ErrURIRoot } return storage.ParseURI(u.Scheme() + "://" + parent) diff --git a/internal/repository/file_test.go b/internal/repository/file_test.go index 9e82c83f54..d3873e1e1e 100644 --- a/internal/repository/file_test.go +++ b/internal/repository/file_test.go @@ -299,7 +299,7 @@ func TestFileRepositoryParent(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 @@ -309,7 +309,7 @@ func TestFileRepositoryParent(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. diff --git a/storage/repository/errors.go b/storage/repository/errors.go index 743523fb74..6c5c5ffc69 100644 --- a/storage/repository/errors.go +++ b/storage/repository/errors.go @@ -1,36 +1,24 @@ package repository -// Declare conformance with Error interface -var _ error = OperationNotSupportedError - -type operationNotSupportedError string - -// OperationNotSupportedError 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.0 -const OperationNotSupportedError operationNotSupportedError = operationNotSupportedError("Operation not supported for this URI.") - -func (e operationNotSupportedError) Error() string { - return string(OperationNotSupportedError) -} - -// 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. -// -// Since 2.0.0 -const URIRootError uriRootError = uriRootError("Cannot take the parent of the root element in a URI") - -func (e uriRootError) Error() string { - return string(URIRootError) -} +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.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.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 index 15640c270b..7bf6321b88 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -28,7 +28,7 @@ func splitNonEmpty(str, sep string) []string { // result is concatenated and parsed as a new URI. // // If the URI path is empty or '/', then a duplicate of the URI is returned, -// along with URIRootError. +// 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. @@ -42,7 +42,7 @@ func GenericParent(u fyne.URI) (fyne.URI, error) { if err != nil { return nil, err } - return parent, URIRootError + return parent, ErrURIRoot } components := splitNonEmpty(u.Path(), "/") @@ -134,7 +134,7 @@ func GenericCopy(source fyne.URI, destination fyne.URI) error { // The destination must be writeable. destwrepo, ok := dstrepo.(WriteableRepository) if !ok { - return OperationNotSupportedError + return ErrOperationNotSupported } // Create a reader and a writer. @@ -186,12 +186,12 @@ func GenericMove(source fyne.URI, destination fyne.URI) error { // is being deleted, which requires WriteableRepository. destwrepo, ok := dstrepo.(WriteableRepository) if !ok { - return OperationNotSupportedError + return ErrOperationNotSupported } srcwrepo, ok := srcrepo.(WriteableRepository) if !ok { - return OperationNotSupportedError + return ErrOperationNotSupported } // Create the reader and writer to perform the copy operation. diff --git a/storage/repository/generic_test.go b/storage/repository/generic_test.go index cd9c0023a2..f211f0cd28 100644 --- a/storage/repository/generic_test.go +++ b/storage/repository/generic_test.go @@ -13,7 +13,7 @@ func TestGenericParent(t *testing.T) { err error }{ {"foo://example.com:8042/over/there?name=ferret#nose", "foo://example.com:8042/over?name=ferret#nose", nil}, - {"file:///", "file:///", URIRootError}, + {"file:///", "file:///", ErrURIRoot}, {"file:///foo", "file:///", nil}, } diff --git a/storage/uri.go b/storage/uri.go index ba5e863384..cc4217fb6d 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -60,7 +60,7 @@ func ParseURI(s string) (fyne.URI, error) { // // * If the scheme of the given URI does not have a registered // HierarchicalRepository instance, then this method will fail with a -// repository.OperationNotSupportedError. +// repository.ErrOperationNotSupported. // // NOTE: since 2.0.0, Parent() is backed by the repository system - this // function is a helper which calls into an appropriate repository instance for @@ -76,7 +76,7 @@ func Parent(u fyne.URI) (fyne.URI, error) { hrepo, ok := repo.(repository.HierarchicalRepository) if !ok { - return nil, repository.OperationNotSupportedError + return nil, repository.ErrOperationNotSupported } return hrepo.Parent(u) @@ -100,7 +100,7 @@ func Parent(u fyne.URI) (fyne.URI, error) { // // * If the scheme of the given URI does not have a registered // HierarchicalRepository instance, then this method will fail with a -// repository.OperationNotSupportedError. +// repository.ErrOperationNotSupported. // // NOTE: since 2.0.0, Child() is backed by the repository system - this // function is a helper which calls into an appropriate repository instance for @@ -115,7 +115,7 @@ func Child(u fyne.URI, component string) (fyne.URI, error) { hrepo, ok := repo.(repository.HierarchicalRepository) if !ok { - return nil, repository.OperationNotSupportedError + return nil, repository.ErrOperationNotSupported } return hrepo.Child(u, component) @@ -164,7 +164,7 @@ func Exists(u fyne.URI) (bool, error) { // // * If the scheme of the given URI does not have a registered // WriteableRepository instance, then this method will fail with a -// repository.OperationNotSupportedError. +// repository.ErrOperationNotSupported. // // Delete is backed by the repository system - this function calls // into a scheme-specific implementation from a registered repository. @@ -178,7 +178,7 @@ func Delete(u fyne.URI) error { wrepo, ok := repo.(repository.WriteableRepository) if !ok { - return repository.OperationNotSupportedError + return repository.ErrOperationNotSupported } return wrepo.Delete(u) @@ -254,7 +254,7 @@ func CanRead(u fyne.URI) (bool, error) { // // * If the scheme of the given URI does not have a registered // WriteableRepository instance, then this method will fail with a -// repository.OperationNotSupportedError. +// repository.ErrOperationNotSupported. // // Writer is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. @@ -268,7 +268,7 @@ func Writer(u fyne.URI) (fyne.URIWriteCloser, error) { wrepo, ok := repo.(repository.WriteableRepository) if !ok { - return nil, repository.OperationNotSupportedError + return nil, repository.ErrOperationNotSupported } return wrepo.Writer(u) @@ -296,7 +296,7 @@ func CanWrite(u fyne.URI) (bool, error) { wrepo, ok := repo.(repository.WriteableRepository) if !ok { - return false, repository.OperationNotSupportedError + return false, repository.ErrOperationNotSupported } return wrepo.CanWrite(u) @@ -319,7 +319,7 @@ func CanWrite(u fyne.URI) (bool, error) { // // * If the scheme of the given URI does not have a registered // CopyableRepository instance, then this method will fail with a -// repository.OperationNotSupportedError. +// repository.ErrOperationNotSupported. // // Copy is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. @@ -333,7 +333,7 @@ func Copy(source fyne.URI, destination fyne.URI) error { crepo, ok := repo.(repository.CopyableRepository) if !ok { - return repository.OperationNotSupportedError + return repository.ErrOperationNotSupported } return crepo.Copy(source, destination) @@ -358,7 +358,7 @@ func Copy(source fyne.URI, destination fyne.URI) error { // // * If the scheme of the given URI does not have a registered // MovableRepository instance, then this method will fail with a -// repository.OperationNotSupportedError. +// repository.ErrOperationNotSupported. // // Move is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. @@ -372,7 +372,7 @@ func Move(source fyne.URI, destination fyne.URI) error { mrepo, ok := repo.(repository.MovableRepository) if !ok { - return repository.OperationNotSupportedError + return repository.ErrOperationNotSupported } return mrepo.Move(source, destination) @@ -394,7 +394,7 @@ func Move(source fyne.URI, destination fyne.URI) error { // // * If the scheme of the given URI does not have a registered // ListableRepository instance, then this method will fail with a -// repository.OperationNotSupportedError. +// repository.ErrOperationNotSupported. // // CanList is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. @@ -408,7 +408,7 @@ func CanList(u fyne.URI) (bool, error) { lrepo, ok := repo.(repository.ListableRepository) if !ok { - return false, repository.OperationNotSupportedError + return false, repository.ErrOperationNotSupported } return lrepo.CanList(u) @@ -433,7 +433,7 @@ func CanList(u fyne.URI) (bool, error) { // // * If the scheme of the given URI does not have a registered // ListableRepository instance, then this method will fail with a -// repository.OperationNotSupportedError. +// 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 @@ -448,7 +448,7 @@ func List(u fyne.URI) ([]fyne.URI, error) { lrepo, ok := repo.(repository.ListableRepository) if !ok { - return nil, repository.OperationNotSupportedError + return nil, repository.ErrOperationNotSupported } return lrepo.List(u) diff --git a/storage/uri_root_error.go b/storage/uri_root_error.go index ac843e2bf0..75a5a2d221 100644 --- a/storage/uri_root_error.go +++ b/storage/uri_root_error.go @@ -6,5 +6,5 @@ import ( // URIRootError is a wrapper for repository.URIRootError // -// Deprecated - use repository.URIRootError instead -const URIRootError = repository.URIRootError +// Deprecated - use repository.ErrURIRoot instead +var URIRootError = repository.ErrURIRoot diff --git a/storage/uri_test.go b/storage/uri_test.go index f804576880..4fb500c01f 100644 --- a/storage/uri_test.go +++ b/storage/uri_test.go @@ -147,10 +147,10 @@ func TestURI_Parent(t *testing.T) { //assert.Equal(t, "http://foo/bar/", parent.String()) // //_, err = storage.Parent(storage.NewURI("http://foo")) - //assert.Equal(t, storage.URIRootError, err) + //assert.Equal(t, repository.ErrURIRoot, err) // //_, err = storage.Parent(storage.NewURI("http:///")) - //assert.Equal(t, storage.URIRootError, err) + //assert.Equal(t, repository.ErrURIRoot, err) // //parent, err = storage.Parent(storage.NewURI("https://///foo/bar/")) //assert.Nil(t, err) @@ -170,7 +170,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 @@ -180,7 +180,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. From 4fc4c73ef4aa0b427dfb9f8f5986c8f95e33013f Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sat, 16 Jan 2021 15:12:54 -0500 Subject: [PATCH 088/145] fix linter error --- storage/repository/errors.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/repository/errors.go b/storage/repository/errors.go index 6c5c5ffc69..3458bd43cd 100644 --- a/storage/repository/errors.go +++ b/storage/repository/errors.go @@ -12,7 +12,7 @@ var ( // or has explicitly returned this error. // // Since 2.0.0 - ErrOperationNotSupported = errors.New("Operation not supported for this URI.") + 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 @@ -20,5 +20,5 @@ var ( // iterating. // // Since 2.0.0 - ErrURIRoot = errors.New("Cannot take the parent of the root element in a URI") + ErrURIRoot = errors.New("cannot take the parent of the root element in a URI") ) From 50de2256dca0a032b8033207b40ad9ee6c650ecb Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sat, 16 Jan 2021 15:15:55 -0500 Subject: [PATCH 089/145] drop scheme requirement from NewFileRepository thanks @stuartmscott context: https://github.com/fyne-io/fyne/pull/1768#discussion_r557769564 --- internal/driver/glfw/driver.go | 2 +- internal/driver/gomobile/file_desktop.go | 2 +- internal/repository/file.go | 2 +- internal/repository/file_test.go | 12 ++++++------ test/testdriver.go | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/driver/glfw/driver.go b/internal/driver/glfw/driver.go index 3a39baa274..294b6860c5 100644 --- a/internal/driver/glfw/driver.go +++ b/internal/driver/glfw/driver.go @@ -130,7 +130,7 @@ func NewGLDriver() fyne.Driver { d.drawDone = make(chan interface{}) d.animation = &animation.Runner{} - repository.Register("file", intRepo.NewFileRepository("file")) + repository.Register("file", intRepo.NewFileRepository()) return d } diff --git a/internal/driver/gomobile/file_desktop.go b/internal/driver/gomobile/file_desktop.go index 31bd59fbde..7d1389694a 100644 --- a/internal/driver/gomobile/file_desktop.go +++ b/internal/driver/gomobile/file_desktop.go @@ -15,5 +15,5 @@ func nativeFileOpen(*fileOpen) (io.ReadCloser, error) { } func registerRepository(d *mobileDriver) { - repository.Register("file", intRepo.NewFileRepository("file")) + repository.Register("file", intRepo.NewFileRepository()) } diff --git a/internal/repository/file.go b/internal/repository/file.go index b61229bcbc..f97f2337e6 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -47,7 +47,7 @@ type FileRepository struct { // repository.Register() on the result of this function. // // Since: 2.0.0 -func NewFileRepository(scheme string) *FileRepository { +func NewFileRepository() *FileRepository { return &FileRepository{} } diff --git a/internal/repository/file_test.go b/internal/repository/file_test.go index d3873e1e1e..59349ed801 100644 --- a/internal/repository/file_test.go +++ b/internal/repository/file_test.go @@ -15,7 +15,7 @@ import ( ) func TestFileRepositoryRegistration(t *testing.T) { - f := NewFileRepository("file") + f := NewFileRepository() repository.Register("file", f) // this should never fail, and we assume it doesn't in other tests here @@ -75,7 +75,7 @@ func TestFileRepositoryReader(t *testing.T) { } // Set up our repository - it's OK if we already registered it... - f := NewFileRepository("file") + f := NewFileRepository() repository.Register("file", f) // ...and some URIs - we know that they will not fail parsing @@ -137,7 +137,7 @@ func TestFileRepositoryWriter(t *testing.T) { } // Set up our repository - it's OK if we already registered it... - f := NewFileRepository("file") + f := NewFileRepository() repository.Register("file", f) // ...and some URIs - we know that they will not fail parsing @@ -244,7 +244,7 @@ func TestFileRepositoryCanWrite(t *testing.T) { } // Set up our repository - it's OK if we already registered it... - f := NewFileRepository("file") + f := NewFileRepository() repository.Register("file", f) // ...and some URIs - we know that they will not fail parsing @@ -267,7 +267,7 @@ func TestFileRepositoryCanWrite(t *testing.T) { func TestFileRepositoryParent(t *testing.T) { // Set up our repository - it's OK if we already registered it. - f := NewFileRepository("file") + f := NewFileRepository() repository.Register("file", f) // note the trailing slashes are significant, as they tend to belie a @@ -320,7 +320,7 @@ func TestFileRepositoryParent(t *testing.T) { func TestFileRepositoryChild(t *testing.T) { // Set up our repository - it's OK if we already registered it. - f := NewFileRepository("file") + f := NewFileRepository() repository.Register("file", f) p, _ := storage.Child(storage.NewURI("file:///foo/bar"), "baz") diff --git a/test/testdriver.go b/test/testdriver.go index 0edf80f4dd..db0823f509 100644 --- a/test/testdriver.go +++ b/test/testdriver.go @@ -35,7 +35,7 @@ var _ fyne.Driver = (*testDriver)(nil) func NewDriver() fyne.Driver { drv := new(testDriver) drv.windowsMutex = sync.RWMutex{} - repository.Register("file", intRepo.NewFileRepository("file")) + repository.Register("file", intRepo.NewFileRepository()) // make a single dummy window for rendering tests drv.CreateWindow("") From 9f4f3429ace865d32c3d9b214e1e3e8f83279de5 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sat, 16 Jan 2021 15:18:57 -0500 Subject: [PATCH 090/145] tidy up error handling and calls to Scheme() thanks @stuartmscott --- internal/repository/file.go | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index f97f2337e6..6a34dc9bd7 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -109,9 +109,7 @@ func (r *FileRepository) CanRead(u fyne.URI) (bool, error) { return false, nil } - if err != nil { - return false, err - } + return false, err } return true, nil @@ -149,9 +147,7 @@ func (r *FileRepository) CanWrite(u fyne.URI) (bool, error) { return true, nil } - if err != nil { - return false, err - } + return false, err } return true, nil @@ -169,6 +165,7 @@ func (r *FileRepository) Delete(u fyne.URI) error { // Since: 2.0.0 func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { s := u.String() + scheme := u.Scheme() // trim trailing slash if s[len(s)-1] == '/' { @@ -176,7 +173,7 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { } // trim the scheme - s = s[len(u.Scheme())+3:] + s = s[len(scheme)+3:] // Completely empty URI with just a scheme if len(s) == 0 { @@ -184,7 +181,7 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { } parent := "" - if u.Scheme() == "file" { + if scheme == "file" { // use the system native path resolution parent = filepath.Dir(s) if parent[len(parent)-1] != filepath.Separator { @@ -196,12 +193,12 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { return nil, repository.ErrURIRoot } - return storage.ParseURI(u.Scheme() + "://" + parent) + return storage.ParseURI(scheme + "://" + parent) } // Per the spec for storage.Parent(), we should only need to handle // it for schemes we are registered to. - return nil, fmt.Errorf("FileRepository cannot handle unknown scheme '%s'", u.Scheme()) + return nil, fmt.Errorf("FileRepository cannot handle unknown scheme '%s'", scheme) } // Child implements repository.HierarchicalRepository.Child From 17be7f19dd30bd331fd5dee0c2d943878ca7e946 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sat, 16 Jan 2021 15:23:34 -0500 Subject: [PATCH 091/145] clean up more nits from code review thanks @stuartmscott --- internal/repository/file.go | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index 6a34dc9bd7..8fdd746b3a 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -208,12 +208,15 @@ func (r *FileRepository) Child(u fyne.URI, component string) (fyne.URI, error) { newURI := u.Scheme() + "://" + u.Authority() newURI += path.Join(u.Path(), component) + query := u.Query() + fragment := u.Fragment() + // stick the query and fragment back on the end - if len(u.Query()) > 0 { - newURI += "?" + u.Query() + if len(query) > 0 { + newURI += "?" + query } - if len(u.Fragment()) > 0 { - newURI += "#" + u.Fragment() + if len(fragment) > 0 { + newURI += "#" + fragment } return storage.ParseURI(newURI) @@ -223,9 +226,6 @@ func (r *FileRepository) Child(u fyne.URI, component string) (fyne.URI, error) { // // Since: 2.0.0 func (r *FileRepository) List(u fyne.URI) ([]fyne.URI, error) { - if u.Scheme() != "file" { - return nil, fmt.Errorf("unsupported URL protocol") - } path := u.Path() files, err := ioutil.ReadDir(path) @@ -253,11 +253,10 @@ func (r *FileRepository) CanList(u fyne.URI) (bool, error) { p := u.Path() info, err := os.Stat(p) - if os.IsNotExist(err) { - return false, nil - } - if err != nil { + if os.IsNotExist(err) { + return false, nil + } return false, err } From 04351246d0661fb94c7a1717e31ef1b3844ce911 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sat, 16 Jan 2021 15:26:58 -0500 Subject: [PATCH 092/145] Update storage/repository/generic.go Co-authored-by: Stuart Scott --- storage/repository/generic.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/repository/generic.go b/storage/repository/generic.go index 7bf6321b88..31f3d1f971 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -94,8 +94,8 @@ func GenericChild(u fyne.URI, component string) (fyne.URI, error) { newURI += "/" + strings.Join(components, "/") // stick the query and fragment back on the end - if len(u.Query()) > 0 { - newURI += "?" + u.Query() + if q := u.Query(); len(q) > 0 { + newURI += "?" + q } if len(u.Fragment()) > 0 { newURI += "#" + u.Fragment() From 901d12ba0bef8f65b544928c5a0df6811cabb263 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sat, 16 Jan 2021 15:29:49 -0500 Subject: [PATCH 093/145] lower case scheme --- storage/repository/parse.go | 2 ++ storage/repository/repository.go | 5 ++++- uri.go | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/storage/repository/parse.go b/storage/repository/parse.go index 3ba0f397fe..f9972440a8 100644 --- a/storage/repository/parse.go +++ b/storage/repository/parse.go @@ -4,6 +4,7 @@ import ( "net/url" "path/filepath" "runtime" + "strings" "fyne.io/fyne" ) @@ -48,6 +49,7 @@ func ParseURI(s string) (fyne.URI, error) { } scheme += string(s[i]) } + scheme = strings.ToLower(scheme) if scheme == "file" { // Does this really deserve to be special? In principle, the diff --git a/storage/repository/repository.go b/storage/repository/repository.go index f6049f59e1..dd620b6d7c 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -2,6 +2,7 @@ package repository import ( "fmt" + "strings" "fyne.io/fyne" ) @@ -223,6 +224,8 @@ type MovableRepository interface { // // Since: 2.0.0 func Register(scheme string, repository Repository) { + scheme = strings.ToLower(scheme) + prev, ok := repositoryTable[scheme] if ok { @@ -241,7 +244,7 @@ func Register(scheme string, repository Repository) { // // Since: 2.0.0 func ForURI(u fyne.URI) (Repository, error) { - scheme := u.Scheme() + scheme := strings.ToLower(u.Scheme()) repo, ok := repositoryTable[scheme] if !ok { diff --git a/uri.go b/uri.go index d5fcfedadb..eb1f3b8b66 100644 --- a/uri.go +++ b/uri.go @@ -50,6 +50,8 @@ type URI interface { // 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 From 41d1dabafadfd00ac0e9a2e9a4a1850fff0423c3 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sat, 16 Jan 2021 21:32:50 +0000 Subject: [PATCH 094/145] Stop exiting early in GLFW tests --- internal/driver/glfw/window_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/internal/driver/glfw/window_test.go b/internal/driver/glfw/window_test.go index 7652010951..a119386450 100644 --- a/internal/driver/glfw/window_test.go +++ b/internal/driver/glfw/window_test.go @@ -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() } From 47a22ebd916495dd6589a185ec29849e4a8c8c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tilo=20Pr=C3=BCtz?= Date: Sat, 16 Jan 2021 22:36:07 +0100 Subject: [PATCH 095/145] fix #1811: some tests were missed on main menu keyboard control --- internal/driver/glfw/canvas_other_test.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/internal/driver/glfw/canvas_other_test.go b/internal/driver/glfw/canvas_other_test.go index f7e2ab4efe..8c97dc21d1 100644 --- a/internal/driver/glfw/canvas_other_test.go +++ b/internal/driver/glfw/canvas_other_test.go @@ -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) From ebedbf7d2e76ee0a2cdfc2705db85b779915eeb9 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sat, 16 Jan 2021 16:43:37 -0500 Subject: [PATCH 096/145] simplify FileRepository.Parent() --- internal/repository/file.go | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index 8fdd746b3a..eb21ae85d4 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -181,24 +181,18 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { } parent := "" - if scheme == "file" { - // 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 - } + // use the system native path resolution + parent = filepath.Dir(s) + if parent[len(parent)-1] != filepath.Separator { + parent += "/" + } - return storage.ParseURI(scheme + "://" + parent) + // only root is it's own parent + if filepath.Clean(parent) == filepath.Clean(s) { + return nil, repository.ErrURIRoot } - // Per the spec for storage.Parent(), we should only need to handle - // it for schemes we are registered to. - return nil, fmt.Errorf("FileRepository cannot handle unknown scheme '%s'", scheme) + return storage.ParseURI(scheme + "://" + parent) } // Child implements repository.HierarchicalRepository.Child From f2883d0c66d2de8a94a5bb4236db60653a3fc9eb Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sat, 16 Jan 2021 16:49:02 -0500 Subject: [PATCH 097/145] fix some more nits thanks @stuartmscott --- storage/repository/generic.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/storage/repository/generic.go b/storage/repository/generic.go index 31f3d1f971..f5a5cfd880 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -45,7 +45,7 @@ func GenericParent(u fyne.URI) (fyne.URI, error) { return parent, ErrURIRoot } - components := splitNonEmpty(u.Path(), "/") + components := splitNonEmpty(p, "/") newURI := u.Scheme() + "://" + u.Authority() @@ -57,13 +57,11 @@ func GenericParent(u fyne.URI) (fyne.URI, error) { } // stick the query and fragment back on the end - q := u.Query() - if len(q) > 0 { + if q := u.Query(); len(q) > 0 { newURI += "?" + q } - f := u.Fragment() - if len(f) > 0 { + if f := u.Fragment(); len(f) > 0 { newURI += "#" + f } @@ -97,8 +95,8 @@ func GenericChild(u fyne.URI, component string) (fyne.URI, error) { if q := u.Query(); len(q) > 0 { newURI += "?" + q } - if len(u.Fragment()) > 0 { - newURI += "#" + u.Fragment() + if f := u.Fragment(); len(f) > 0 { + newURI += "#" + f } // NOTE: we specifically want to use ParseURI, rather than &uri{}, From dd1202cd317b8062eee476a45059c19acbccafe5 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sat, 16 Jan 2021 16:56:58 -0500 Subject: [PATCH 098/145] CanRead should not treat non-existence as an error --- internal/repository/memory.go | 6 +----- internal/repository/memory_test.go | 2 +- storage/uri.go | 10 ++++++++++ storage/uri_test.go | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/internal/repository/memory.go b/internal/repository/memory.go index 7807b8067a..4cb864b306 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -186,11 +186,7 @@ func (m *InMemoryRepository) CanRead(u fyne.URI) (bool, error) { } _, ok := m.Data[u.Path()] - if !ok { - return false, fmt.Errorf("no such path '%s' in InMemoryRepository", u.Path()) - } - - return true, nil + return ok, nil } // Destroy implements repository.Repository.Destroy diff --git a/internal/repository/memory_test.go b/internal/repository/memory_test.go index 932a3841eb..39e03612f5 100644 --- a/internal/repository/memory_test.go +++ b/internal/repository/memory_test.go @@ -109,7 +109,7 @@ func TestInMemoryRepositoryCanRead(t *testing.T) { bazCanRead, err := storage.CanRead(baz) assert.False(t, bazCanRead) - assert.NotNil(t, err) + assert.Nil(t, err) } func TestInMemoryRepositoryWriter(t *testing.T) { diff --git a/storage/uri.go b/storage/uri.go index cc4217fb6d..a8bf8c2d83 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -223,6 +223,10 @@ func Reader(u fyne.URI) (fyne.URIReadCloser, error) { // 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. // @@ -239,6 +243,12 @@ func CanRead(u fyne.URI) (bool, error) { // 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 diff --git a/storage/uri_test.go b/storage/uri_test.go index 4fb500c01f..2619d492d7 100644 --- a/storage/uri_test.go +++ b/storage/uri_test.go @@ -363,7 +363,7 @@ func TestCanRead(t *testing.T) { bazCanRead, err := storage.CanRead(baz) assert.False(t, bazCanRead) - assert.NotNil(t, err) + assert.Nil(t, err) } func TestCopy(t *testing.T) { From 38eade5c84c8a03f75da8c0d17e4bd26aa8a91a4 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sat, 16 Jan 2021 22:41:24 +0000 Subject: [PATCH 099/145] If we want to be relative to a moving object we really need to track it's movements --- internal/driver/glfw/window.go | 48 +++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/internal/driver/glfw/window.go b/internal/driver/glfw/window.go index cbb7456de4..40c2aba545 100644 --- a/internal/driver/glfw/window.go +++ b/internal/driver/glfw/window.go @@ -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,17 @@ 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 { + dragged := w.mouseDragged.(interface{}).(fyne.CanvasObject) + _, tapable := dragged.(desktop.Mouseable) + if dragged != nil && tapable { + mev.Position = w.mousePos.Subtract(w.mouseDraggedOffset) + w.queueEvent(func() { dragged.(desktop.Mouseable).MouseUp(mev) }) + } else { + w.queueEvent(func() { wid.MouseUp(mev) }) + } } } } From a1ebd5f70ad3affa588e815430f06854517301e6 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sat, 16 Jan 2021 20:22:08 -0500 Subject: [PATCH 100/145] apply stuarts suggestions Co-authored-by: Stuart Scott --- internal/repository/file.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index eb21ae85d4..f22c246206 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -36,7 +36,7 @@ func (f *file) URI() fyne.URI { // interface libraries. It should be registered by the driver on platforms // where it is appropriate to do so. // -// This repository is suitable to handle file:// schemes. +// This repository is suitable to handle the file:// scheme. // // Since: 2.0.0 type FileRepository struct { @@ -44,7 +44,7 @@ type FileRepository struct { // NewFileRepository creates a new FileRepository instance. It must be // given the scheme it is registered for. The caller needs to call -// repository.Register() on the result of this function. +// repository.Register() with the result of this function. // // Since: 2.0.0 func NewFileRepository() *FileRepository { @@ -74,7 +74,7 @@ func openFile(uri fyne.URI, create bool) (*file, error) { return nil, fmt.Errorf("invalid URI for file: %s", uri) } - path := uri.String()[7:] + path := uri.Path() var f *os.File var err error if create { @@ -168,12 +168,10 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { scheme := u.Scheme() // trim trailing slash - if s[len(s)-1] == '/' { - s = s[0 : len(s)-1] - } + s = strings.TrimSuffix(s, "/") // trim the scheme - s = s[len(scheme)+3:] + s = strings.TrimPrefix(s, "file://") // Completely empty URI with just a scheme if len(s) == 0 { From 97c801b7da72e6bc37dd010538143712fee9147d Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sat, 16 Jan 2021 20:57:49 -0500 Subject: [PATCH 101/145] Implement suggested changes from code review thanks @stuartmscott --- internal/repository/file.go | 26 +++++++++----------- internal/repository/memory.go | 38 +++++++++++++++++------------- storage/repository/generic.go | 10 +++----- storage/repository/generic_test.go | 7 +++++- storage/uri.go | 21 +++++++++++++++-- 5 files changed, 61 insertions(+), 41 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index f22c246206..126f2d753c 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -1,17 +1,21 @@ package repository import ( - "fmt" "io/ioutil" "os" "path" "path/filepath" + "strings" "fyne.io/fyne" "fyne.io/fyne/storage" "fyne.io/fyne/storage/repository" ) +// fileSchemePrefix is used for concatenating with paths when we must construct +// them from strings. +const fileSchemePrefix string = "file://" + // declare conformance with repository types var _ repository.Repository = (*FileRepository)(nil) var _ repository.WriteableRepository = (*FileRepository)(nil) @@ -70,10 +74,6 @@ func (r *FileRepository) Exists(u fyne.URI) (bool, error) { } 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.Path() var f *os.File var err error @@ -98,7 +98,7 @@ func (r *FileRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { func (r *FileRepository) CanRead(u fyne.URI) (bool, error) { f, err := os.OpenFile(u.Path(), os.O_RDONLY, 0666) if err == nil { - defer f.Close() + f.Close() } else { if os.IsPermission(err) { @@ -133,7 +133,7 @@ func (r *FileRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { func (r *FileRepository) CanWrite(u fyne.URI) (bool, error) { f, err := os.OpenFile(u.Path(), os.O_WRONLY, 0666) if err == nil { - defer f.Close() + f.Close() } else { if os.IsPermission(err) { @@ -165,7 +165,6 @@ func (r *FileRepository) Delete(u fyne.URI) error { // Since: 2.0.0 func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { s := u.String() - scheme := u.Scheme() // trim trailing slash s = strings.TrimSuffix(s, "/") @@ -190,7 +189,7 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { return nil, repository.ErrURIRoot } - return storage.ParseURI(scheme + "://" + parent) + return storage.ParseURI(fileSchemePrefix + parent) } // Child implements repository.HierarchicalRepository.Child @@ -200,14 +199,11 @@ func (r *FileRepository) Child(u fyne.URI, component string) (fyne.URI, error) { newURI := u.Scheme() + "://" + u.Authority() newURI += path.Join(u.Path(), component) - query := u.Query() - fragment := u.Fragment() - // stick the query and fragment back on the end - if len(query) > 0 { + if query := u.Query(); len(query) > 0 { newURI += "?" + query } - if len(fragment) > 0 { + if fragment := u.Fragment(); len(fragment) > 0 { newURI += "#" + fragment } @@ -228,7 +224,7 @@ func (r *FileRepository) List(u fyne.URI) ([]fyne.URI, error) { urilist := []fyne.URI{} for _, f := range files { - uri, err := storage.ParseURI("file://" + filepath.Join(path, f.Name())) + uri, err := storage.ParseURI(fileSchemePrefix + filepath.Join(path, f.Name())) if err != nil { return nil, err } diff --git a/internal/repository/memory.go b/internal/repository/memory.go index 4cb864b306..fab55a6d1f 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -153,8 +153,8 @@ func NewInMemoryRepository(scheme string) *InMemoryRepository { // // Since 2.0.0 func (m *InMemoryRepository) Exists(u fyne.URI) (bool, error) { - if u.Path() == "" { - return false, fmt.Errorf("invalid path '%s'", u.Path()) + if p := u.Path(); p == "" { + return false, fmt.Errorf("invalid path '%s'", p) } _, ok := m.Data[u.Path()] @@ -165,27 +165,30 @@ func (m *InMemoryRepository) Exists(u fyne.URI) (bool, error) { // // Since 2.0.0 func (m *InMemoryRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { - if u.Path() == "" { - return nil, fmt.Errorf("invalid path '%s'", u.Path()) + path := u.Path() + + if path == "" { + return nil, fmt.Errorf("invalid path '%s'", path) } - _, ok := m.Data[u.Path()] + _, ok := m.Data[path] if !ok { - return nil, fmt.Errorf("no such path '%s' in InMemoryRepository", u.Path()) + return nil, fmt.Errorf("no such path '%s' in InMemoryRepository", path) } - return &nodeReaderWriter{path: u.Path(), repo: m}, nil + return &nodeReaderWriter{path: path, repo: m}, nil } // CanRead implements repository.Repository.CanRead // // Since 2.0.0 func (m *InMemoryRepository) CanRead(u fyne.URI) (bool, error) { - if u.Path() == "" { - return false, fmt.Errorf("invalid path '%s'", u.Path()) + path := u.Path() + if path == "" { + return false, fmt.Errorf("invalid path '%s'", path) } - _, ok := m.Data[u.Path()] + _, ok := m.Data[path] return ok, nil } @@ -198,11 +201,12 @@ func (m *InMemoryRepository) Destroy(scheme string) { // // Since 2.0.0 func (m *InMemoryRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { - if u.Path() == "" { - return nil, fmt.Errorf("invalid path '%s'", u.Path()) + path := u.Path() + if path == "" { + return nil, fmt.Errorf("invalid path '%s'", path) } - return &nodeReaderWriter{path: u.Path(), repo: m}, nil + return &nodeReaderWriter{path: path, repo: m}, nil } // CanWrite implements repository.WriteableRepository.CanWrite @@ -220,9 +224,10 @@ func (m *InMemoryRepository) CanWrite(u fyne.URI) (bool, error) { // // Since 2.0.0 func (m *InMemoryRepository) Delete(u fyne.URI) error { - _, ok := m.Data[u.Path()] + path := u.Path() + _, ok := m.Data[path] if ok { - delete(m.Data, u.Path()) + delete(m.Data, path) } return nil @@ -277,6 +282,7 @@ func (m *InMemoryRepository) List(u fyne.URI) ([]fyne.URI, error) { } 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 @@ -293,7 +299,7 @@ func (m *InMemoryRepository) List(u fyne.URI) ([]fyne.URI, error) { ncomp-- } - if strings.HasPrefix(p, prefix) && ncomp == len(prefixSplit) { + if strings.HasPrefix(p, prefix) && ncomp == prefixSplitLen { uri, err := storage.ParseURI(m.scheme + "://" + p) if err != nil { return nil, err diff --git a/storage/repository/generic.go b/storage/repository/generic.go index f5a5cfd880..8e7442d97b 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -27,8 +27,8 @@ func splitNonEmpty(str, sep string) []string { // 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 duplicate of the URI is returned, -// along with ErrURIRoot. +// 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. @@ -38,11 +38,7 @@ func GenericParent(u fyne.URI) (fyne.URI, error) { p := u.Path() if p == "" || p == "/" { - parent, err := ParseURI(u.String()) - if err != nil { - return nil, err - } - return parent, ErrURIRoot + return nil, ErrURIRoot } components := splitNonEmpty(p, "/") diff --git a/storage/repository/generic_test.go b/storage/repository/generic_test.go index f211f0cd28..32e87d83da 100644 --- a/storage/repository/generic_test.go +++ b/storage/repository/generic_test.go @@ -26,7 +26,12 @@ func TestGenericParent(t *testing.T) { res, err := GenericParent(u) assert.Equal(t, c.err, err) - assert.Equal(t, c.expect, res.String()) + // 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()) + } } } diff --git a/storage/uri.go b/storage/uri.go index a8bf8c2d83..199464891c 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -312,8 +312,15 @@ func CanWrite(u fyne.URI) (bool, error) { return wrepo.CanWrite(u) } -// Copy given two URIs, 'src', and 'dest' both of the same scheme , will copy -// one to the other. +// 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: // @@ -354,6 +361,16 @@ func Copy(source fyne.URI, destination fyne.URI) error { // 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 From d87b625b75c0b3daa89f9e8e3cdd93b833874d25 Mon Sep 17 00:00:00 2001 From: FPabl0 Date: Sat, 16 Jan 2021 21:03:04 -0500 Subject: [PATCH 102/145] added underline decoration to widget.Select and fix its MinSize --- widget/select.go | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/widget/select.go b/widget/select.go index a3fad0b4c5..47bc6b6d86 100644 --- a/widget/select.go +++ b/widget/select.go @@ -65,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{icon, txtProv, background, objects, 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() @@ -294,9 +295,9 @@ func (s *Select) updateSelected(text string) { } type selectRenderer struct { - icon *Icon - label *textProvider - background *canvas.Rectangle + icon *Icon + label *textProvider + background, line *canvas.Rectangle objects []fyne.CanvasObject combo *Select @@ -310,17 +311,20 @@ func (s *selectRenderer) Destroy() {} // Layout the components of the button widget func (s *selectRenderer) Layout(size fyne.Size) { - s.background.Move(fyne.NewPos(0, 0)) - s.background.Resize(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())) iconPos := fyne.NewPos(size.Width-theme.IconInlineSize()-theme.Padding()*2, (size.Height-theme.IconInlineSize())/2) - labelSize := fyne.NewSize(iconPos.X-theme.Padding(), size.Height) + labelSize := fyne.NewSize(iconPos.X-theme.Padding(), s.label.MinSize().Height) + // TODO are these needed? s.combo.propertyLock.RLock() defer s.combo.propertyLock.RUnlock() s.label.Resize(labelSize) - s.label.Move(fyne.NewPos(theme.Padding(), 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(iconPos) @@ -332,9 +336,11 @@ func (s *selectRenderer) MinSize() fyne.Size { s.combo.propertyLock.RLock() defer s.combo.propertyLock.RUnlock() - // x1 x4 (reserved) x1 x1 x2 - // pad - label - pad - icon - pad*2 + // x1 x4 (reserved) x1 x1 x2 + // pad - label (placeholder) - pad - icon - pad*2 + 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)) } @@ -343,7 +349,7 @@ 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 +361,18 @@ func (s *selectRenderer) Refresh() { canvas.Refresh(s.combo.super()) } -func (s *selectRenderer) buttonColor() color.Color { +// TODO define colors +func (s *selectRenderer) bgLineColor() (bg color.Color, line color.Color) { if s.combo.Disabled() { - return theme.FocusColor() + return theme.InputBackgroundColor(), theme.DisabledTextColor() } if s.combo.focused { - return theme.FocusColor() + return theme.InputBackgroundColor(), theme.PrimaryColor() } if s.combo.hovered { - return theme.HoverColor() + return theme.HoverColor(), theme.ShadowColor() } - return theme.FocusColor() + return theme.InputBackgroundColor(), theme.ShadowColor() } func (s *selectRenderer) updateIcon() { From d1b869b3edf46e13f3131e4c4ab79409ddeac85d Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sun, 17 Jan 2021 00:19:37 -0500 Subject: [PATCH 103/145] more code review nits thanks @stuartmscott --- internal/repository/file.go | 2 +- internal/repository/memory.go | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index 126f2d753c..254731bf33 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -170,7 +170,7 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { s = strings.TrimSuffix(s, "/") // trim the scheme - s = strings.TrimPrefix(s, "file://") + s = strings.TrimPrefix(s, fileSchemePrefix) // Completely empty URI with just a scheme if len(s) == 0 { diff --git a/internal/repository/memory.go b/internal/repository/memory.go index fab55a6d1f..42ebc59fe7 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -153,11 +153,12 @@ func NewInMemoryRepository(scheme string) *InMemoryRepository { // // Since 2.0.0 func (m *InMemoryRepository) Exists(u fyne.URI) (bool, error) { - if p := u.Path(); p == "" { - return false, fmt.Errorf("invalid path '%s'", p) + path := u.Path() + if path == "" { + return false, fmt.Errorf("invalid path '%s'", path) } - _, ok := m.Data[u.Path()] + _, ok := m.Data[path] return ok, nil } @@ -213,8 +214,8 @@ func (m *InMemoryRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { // // Since 2.0.0 func (m *InMemoryRepository) CanWrite(u fyne.URI) (bool, error) { - if u.Path() == "" { - return false, fmt.Errorf("invalid path '%s'", u.Path()) + if p := u.Path(); p == "" { + return false, fmt.Errorf("invalid path '%s'", p) } return true, nil From da5dc73598ff276b45fd2e1dc9bdf06cba0e6121 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sun, 17 Jan 2021 13:00:27 +0000 Subject: [PATCH 104/145] PR feedback --- theme/theme.go | 6 +++--- theme/theme_test.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/theme/theme.go b/theme/theme.go index a00feb3ef1..5b3751188c 100644 --- a/theme/theme.go +++ b/theme/theme.go @@ -555,9 +555,9 @@ func safeColorLookup(n fyne.ThemeColorName, v fyne.ThemeVariant) color.Color { } func safeFontLookup(s fyne.TextStyle) fyne.Resource { - col := current().Font(s) - if col != nil { - return col + font := current().Font(s) + if font != nil { + return font } fyne.LogError("Loaded theme returned nil font", nil) diff --git a/theme/theme_test.go b/theme/theme_test.go index 9d88072cd0..b7cbdfab1e 100644 --- a/theme/theme_test.go +++ b/theme/theme_test.go @@ -4,9 +4,9 @@ import ( "image/color" "testing" - "github.com/stretchr/testify/assert" - "fyne.io/fyne" + + "github.com/stretchr/testify/assert" ) func TestThemeChange(t *testing.T) { From cb8fff6de860872f1373a296351fcfd0706bb408 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sun, 17 Jan 2021 13:05:05 +0000 Subject: [PATCH 105/145] Tidy up code, much nicer --- internal/driver/glfw/window.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/internal/driver/glfw/window.go b/internal/driver/glfw/window.go index 40c2aba545..75afac4f33 100644 --- a/internal/driver/glfw/window.go +++ b/internal/driver/glfw/window.go @@ -729,11 +729,9 @@ func (w *window) mouseClicked(_ *glfw.Window, btn glfw.MouseButton, action glfw. if w.mouseDragged == nil { w.queueEvent(func() { wid.MouseUp(mev) }) } else { - dragged := w.mouseDragged.(interface{}).(fyne.CanvasObject) - _, tapable := dragged.(desktop.Mouseable) - if dragged != nil && tapable { + if dragged, ok := w.mouseDragged.(desktop.Mouseable); ok { mev.Position = w.mousePos.Subtract(w.mouseDraggedOffset) - w.queueEvent(func() { dragged.(desktop.Mouseable).MouseUp(mev) }) + w.queueEvent(func() { dragged.MouseUp(mev) }) } else { w.queueEvent(func() { wid.MouseUp(mev) }) } From 5ef175a53a71d177f37128e4bc102ee2ef22bb86 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sun, 17 Jan 2021 13:32:47 +0000 Subject: [PATCH 106/145] Fix initial state of cursor now it's animated --- widget/entry.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/widget/entry.go b/widget/entry.go index de5b5386d3..d19239284b 100644 --- a/widget/entry.go +++ b/widget/entry.go @@ -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 { From d9fb9cde2f08f7310bf446827158e0744019e5a2 Mon Sep 17 00:00:00 2001 From: FPabl0 Date: Sun, 17 Jan 2021 11:37:33 -0500 Subject: [PATCH 107/145] background and underline color for widget.Select defined --- widget/select.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/widget/select.go b/widget/select.go index 47bc6b6d86..e5f4ad8279 100644 --- a/widget/select.go +++ b/widget/select.go @@ -361,13 +361,12 @@ func (s *selectRenderer) Refresh() { canvas.Refresh(s.combo.super()) } -// TODO define colors func (s *selectRenderer) bgLineColor() (bg color.Color, line color.Color) { if s.combo.Disabled() { return theme.InputBackgroundColor(), theme.DisabledTextColor() } if s.combo.focused { - return theme.InputBackgroundColor(), theme.PrimaryColor() + return theme.FocusColor(), theme.PrimaryColor() } if s.combo.hovered { return theme.HoverColor(), theme.ShadowColor() From 53e2a547b10df763a9d65cfb43131e22a9d902c4 Mon Sep 17 00:00:00 2001 From: FPabl0 Date: Sun, 17 Jan 2021 12:03:34 -0500 Subject: [PATCH 108/145] update tests --- widget/testdata/select/disabled.xml | 21 +++----- .../select/focus_focused_b_selected.xml | 21 +++----- .../select/focus_focused_none_selected.xml | 21 +++----- .../select/focus_unfocused_b_selected.xml | 21 +++----- .../select/focus_unfocused_none_selected.xml | 21 +++----- widget/testdata/select/kbdctrl_a_selected.xml | 21 +++----- widget/testdata/select/kbdctrl_b_selected.xml | 21 +++----- widget/testdata/select/kbdctrl_c_selected.xml | 21 +++----- .../testdata/select/kbdctrl_none_selected.xml | 21 +++----- .../select/kbdctrl_none_selected_popup.xml | 47 +++++++---------- widget/testdata/select/layout_empty.xml | 21 +++----- .../testdata/select/layout_empty_expanded.xml | 45 +++++++--------- .../layout_empty_expanded_placeholder.xml | 19 ++----- .../select/layout_empty_placeholder.xml | 17 ++---- widget/testdata/select/layout_multiple.xml | 21 +++----- .../select/layout_multiple_expanded.xml | 49 +++++++----------- .../layout_multiple_expanded_placeholder.xml | 19 ++----- .../layout_multiple_expanded_selected.xml | 49 +++++++----------- ...multiple_expanded_selected_placeholder.xml | 19 ++----- .../select/layout_multiple_placeholder.xml | 17 ++---- .../select/layout_multiple_selected.xml | 21 +++----- .../layout_multiple_selected_placeholder.xml | 17 ++---- widget/testdata/select/layout_single.xml | 21 +++----- .../select/layout_single_expanded.xml | 47 +++++++---------- .../layout_single_expanded_placeholder.xml | 19 ++----- .../layout_single_expanded_selected.xml | 47 +++++++---------- ...t_single_expanded_selected_placeholder.xml | 19 ++----- .../select/layout_single_placeholder.xml | 17 ++---- .../select/layout_single_selected.xml | 21 +++----- .../layout_single_selected_placeholder.xml | 17 ++---- widget/testdata/select/move_initial.xml | 21 +++----- widget/testdata/select/move_moved.xml | 49 +++++++----------- widget/testdata/select/move_tapped.xml | 49 +++++++----------- .../select/set_selected_2nd_selected.xml | 21 +++----- .../select/set_selected_none_selected.xml | 21 +++----- widget/testdata/select/tapped.xml | 49 +++++++----------- widget/testdata/select/tapped_constrained.xml | 49 +++++++----------- widget/testdata/select/theme_changed.png | Bin 4156 -> 3836 bytes widget/testdata/select/theme_initial.png | Bin 3660 -> 3295 bytes 39 files changed, 342 insertions(+), 675 deletions(-) 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..971bce5f39 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..7d888ae859 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..0075bfd5ca 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,7 +16,7 @@ - + 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..57e34aafdf 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..69b33df466 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,7 +16,7 @@ - + diff --git a/widget/testdata/select/layout_multiple_expanded_selected.xml b/widget/testdata/select/layout_multiple_expanded_selected.xml index 272be725f9..a3e75c5edd 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..02bbcee4d6 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,7 +16,7 @@ - + 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..cf0dc05a37 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..043390305e 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,7 +16,7 @@ - + diff --git a/widget/testdata/select/layout_single_expanded_selected.xml b/widget/testdata/select/layout_single_expanded_selected.xml index 3f6ceb82e6..3096f72f15 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..140f202360 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,7 +16,7 @@ - + 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..db2b541989 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..01efbeaa6a 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..5835cb01ae 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..02a98c69e6 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 d8f91663814a4f6c5254b987ceb763d42cb6cf4a..6ff552b4f9743c9f97c96d9628a564d9f610beaa 100644 GIT binary patch literal 3836 zcmbVPc{CK>9+x%|S+a%f`!bCz*$aar)u?PCO`1>`vK1*2V;S3s38N^UWfEd+Ln$Ns z7Gszhp)tt5&M?fI-+6z%<@eq@zkANT_k7Ry-tYPD=ktYMwYTQwKE=(!!NGgc#uCiF zNq=lEPWFjB=QP5>!T0r|<%R2ExeH{TtJi7d_EjiALt_EN|H|k)h(F$PIy38{WpqZt zC_yI+pT;%d(`}?#Vlh;5xoG&Cl3vZH?qA>>%L@m+#gYfav;~Exa~z}bX8?b@_3ar~ zw0a%S0%v0vn#?EJXu(n6fR6gLEne)<8*WS^QgfE~PmWFa!JUCu^%tSyCPmf>x0WxLWePo62fTAnKjwe;_V*U0i zawRP+EEv6cMLGK9hzO>T&X_vs$CG{*4W_csvZ<{nAm7RqjqJjt&6rW1BX_p zA5w?*Ui1_UusYIJO-s>(C5I-fMP#IHA9P z5aY^_b|aD9a80if($cpSAP;QP?O(n@wzwT~Zo9u1uzj?FdOQ0)C zjEz5(bQBYSH4=PLVASJ{`{%*wle^2BR)vla%G++MxYx`-CSp*024I8%N+O}R z8Wb`+kOBhuGRH*6ie_i$juTE>DN&Xc9#J8?TkOah&d*!Qr5Vaa!!23cWgdA^>zCU@ zu!eab(D`SizKRcTep)_mfSg}R5cXD7gw{S(pQ!Qmxx!4z2?9J~N=NjE zZI%|=;GMkuKHMq{-`JS@DXebAREJ0Hx}FCQvNJ8*OuOnnrKy0iE)G#QWnR^gV!Sb( zp~q34jzCH<^ ziWSZC*)I*X*CwN*bA*MDnw#@!Ii*VT2TbffkXN8_ ztQi!WLWd4)Erv#f+9!dFz^c$5AJ(MzZm3Zx`UzFIudeP>dU|nb=~Q*q5tfe|v^&1H z`+;#txe_47qo6TtbqZ~gked3L+7-8ar+YOpS!s=C=C2L_>@E5mRHJ}+XAOirDXe>s z3IKuU<`x!~eiImqV^viNxsqN^PIO2L?`daLMqy*v05G{Bno~6Ml9X^80RCjj0B*O{ z;##}Gm+LaRxOH~CmZHBOH&j`uB&0wWmpQbx^tFpw(Y zz8J*BW$|ZhNaNnP8S|}-ag&^KJDH#l)Yr!~o1RgHd;Dhod?5#aS6rj3qS&??=Rp-0 zIvXJhL2SDG zy04i&73u73>mKfP0|xWFj;yRFlKWDCBGujw-ETy7(PhQ7mBl0j3Ym}v)T1*!3x1ut ze8u;7YAjh(6M-|@sIA$%ol5RKqE+R0d3eG@E(5dATptL9j?8`2CdT+#lXN4Zd02Go zVv#wL3I>PUGYSZ8S>(u=V|hg7!EUuKktb73ZlZF!T3XSObMMEPOxYKjW=*$g$p(}W zg8q&q{^`jhFCO5NWO>|r}z8OfVjAyyZcwd7O&*|FH_UPg(5UIQx=~mX00?7HaF-Po_0`pTq@)7h;*^j=a$uqtBOQ88~j1J{1$SgTRXFKwYu+JAS1WC`;D-A z>DB_OfA_iWlWi;L-EXG5<#Olh_E#p+uSDuA{C}=d*{x%Z;6B|>*Kkot>u~W4IvBMR z;D>ZXoaVi3%i~&Ibnj%{o0Jt7&Jx zfF*hTTq1Q0E`&9LNCZV(c1I82b@>EoxA4cc0p|WzGD!%Gj8q=M*oL$A-fdGLNjDaW zXN@o6onS6w=>+#gaucJuT;pjk^yzk^fWHr-6%WgQ_fBJfDF2S0-*HBt1pFm?rI>{z z9b@ao5{TTHi>ZxRhAkNxg6oY7-@l(8d~ad<>YT`>yV@zwI7;H;oGWMmh_!-4i7_YV zxr~lc(t~Q3b`l|bntCcZ2a7GiMSgeAv(dO|Z51ezIN6zbtrqag=H!*aO>M|uD_kd!5}N+Zv{~rg*7$5J2PKwEIClTdXv+EdH^FM&+R2hit*reur@WB z+{JExf9Uhua0$`|0jqpSY`m)MvrY1JFgLNSlN<52Rh zlCIQM%cf)y1Kz}56d2DgMyp!wBL**mh$p*!X3k&$(+UoGl6F@F5ey$`Sdc%Lle zYMIOrfM)&xrSl1?*Am`=+osx*`^+XjdL@28>=AqnYq$0L{qms?jk~R_v3iN1&juV9 zIP)C}Y{cy8JW|hO{{#mkQkQ3s-^@fRY@B??EvfpaK>43_|9|22U;ia|?b3BM=c}os z!#8H(9LLP9RMTyAa`f9BZ)znAoId z=~q?Neb54#N6(11#OIl{tTpel=>y6~S_QQ`M+hDSX_Hc;NAavmO|yxy5s{TaTgvYd z?}?|bpW)9x#zZid>ca-EDO60;VfbuU%b0)+&dId8epqVha1zkgx2#|2fb2lR;O`D) zRL=-(A^Q(nAOW10K9z^2)Q0-|Kg9G09gw{SABUkt87zSoCf zFoVk6J=VX==MJcBJUV~7)p|}uTzs9HRZF4F|GL{%<7ENyZX^10HRx%5!W$%6OL5%40E7yFelmC|dnL z*rGwISzYE9;t=-~Gt&snR9#as+`mE0=cl$(Zr5)M~0Ay^C?~ zuXf|gMV};XJaOp~?H_6&1p}W?xLGM79 zr%GFs6KDC%0Ag1j@W(7{ti~-t_U0ZAr1rP4T%BgUve>DFyL_opG3gr(>MD$uuQKS- z2M*9p9GAM~b?}vE;q+4q{~SWfw7dtzj3uhH(fn~N?0tl{p9>>c36Y-F z%REm*6d`W5Kxc)sqV;qDwX1Cj0gH3%`<64>-5jLtNY8&~pT8fW72N0~(f93TdXt|8 zFxnIi@qisI<8Z^BQF}k_-Mu3?*9ck9j4RMbk4z~!eZ$)3a#s_Ft&)j} zP8N~a*-8ab`}iQ8O&ObTeyP_CY}gb2WA@@Vt^2=8Oi<`S+j-ekH9;PkcgMWu5x3}w zVS((~c4>Qp3FUM$&FC%oWI-G`MW@PS7dNR}jJMnqh>I}*lL=|IN&2Kp)(Yg3Nw63lZhieZc zR}*^Z?#j3IUd$@Be>+udIXZ@K_D{ZT8sF%xB;k2dgbh_dX?H@qK7MS*V7>-YW{>9M zyE!?l?7{spY=wd6*x?+qgw?dzdtF^8IH|V94`1g7%p8mzLXau~{U!MLxE?5Q(2W@D zE>5YO1GsFHc$lAXahpS-oyGd?^omZU`<6W&5yE2Wy_TDA$|q;*BGuJ18eK9$f=u(6 zjxL(BgSasHgAQb8)Q$z%&()FmJNizJsI{{Ol}_4I2yr_|{uJpl8PpYfVbx8Swoz}gFF@r%qKeI7~^&DBU*Z9bmw-NZ58}3W(#7~zwhB3NNT$B0c>)6MCc{Q;XIX!69{L5PZ6qmv z)_j2KE59pBm&`6}mcp>*HW%(LF5=~KdJ`8Yk8 zFjGrsUJFf7MZGR78S3o~zz-$_T@QJ`)Sp6q;}*o-mV0z^@^%nO>(l0{({QN=8<1Qv zJ+~6LBIVl5=EoQg%l9H4-hb+Rk8b=;gQeLNWJP&>dt6>si;sl`YO@+G=ePZ}T1Sq8 zAVn~=-{MJ3;DyN0y>B6mCf7)4jG34W85pWDMeaY$891L^aGghHsxy%>`k;KFC(l#T z?4>gMV>$5qc(&?*7RaViSZ{x;upqUZ7Zq&h5iqD1g)jno8_ zWM;B<4Q8FWL%!~d>A?3|5){KSBBNXcRQUOzv+CsrM-4o){M-Bc zVFCEeU2Efdy_1t0Zgq1FO9Tos(^TmBu%Xec2n&jrTPHB^?9tBg`{6BFPBmVdpHGG- z$4#UX)XkIoj@E4p!}db_Qx_DGR>}^3tTq5SN?$PcI!zM0ti&;X=nr~&UcIehR&mHe z;KJ}Ick?l>5h{ztzO#08!XCh78>Nc-`uffmgIxE@Wc_Epx=b>Sm-WFwW|MZQSZ}xD zMyUVkwD8K+F0(th#euA|uK*LFOvG{TS*lRSUaqQW9>$wP8`ric=Dw=x@-BD8w~VJo zFJKw;^3}&R(+*#wq6Z>FXSreFMF-pCDE~9|X|Q!b>;B6ZmM`azcI3+QS^~^{XiuiB z>(2C#$bRN-atXwuJT$uC%YgXP;lWumru(NZ?;g;>Pe{}^ZdM@_h8;6CG&oqNzNcT? zov?OndObUt7}I(h0J&fVv8=SrrL>|xSlThkWl6E^q*HwSFIL28YTn6^e0(}>XKjH1 z`xuQ+SAz^Hol^JLSL+vOG*#pK*7VSG&t!dZr4^?-Su-oK_bc8M*SVHPM5G_?Hf09{ zwA-~;!tu_9P6avs{LgQYdUg1DAKuM=`rzqaw-LMIV@lPT&VWK~t`O81a_z+7E3x`r_DxPq`1YvEJ){NIynY93H+Z+A;xTg)^PF}Fp2d-F$t zM13kVmGdf!N2U!&W15un_KA`(ubQM}B4osJNQoa$I8GHvKAkZ&*D<6+iaj0HDi{Sy z%_I1PjRccFe4xrIN7vLGdrGquV>~x?S<=6t^E+UXxKD3wvvZJiPyKz(VX#Kx^USs# zF9efIbl$+c5d*%zUZLy=^v}7(q|R< zBzK=*k7e<0=qn2eWMgo9l)z}zeMYbTKrm+GQLRK}Hq~T&;BB~hCzAdYmE7#u)0R!; z8ug`FlQ^Vq%_y0WPEz5AFc=G;S zpoj2<1x&Gh>-ui%p7SqN_TSa-zopHepa{`XQG>m#=DJ)*T;D#PfKSVfMFk&gh(huQ zX3cOWe_j*K^YZXyYxVc*iRF-Nf;otbfj(U|rW03>(EQ9U-+B_lLaw%r0SU8s&|4}E z$OqXuJM>1x0e?+f07B2=dNz_C(Yx}KLug(C|G^`u4D4-A^=F03zop7@&;LJri~j)i zKOE%mKE@a%Ks1~;74nzFz|>^uXt~JyoyDnEAY(aje`S1U%%sFPD4m=xHP>x z*ZP7jdv?Y)o-j6J-CdFsIA1g__)wc*j)vI0nd{uN&wKrN*^*0GH1EsQ*MfHx@@bqr z^Zb|T+J0UAm9~JEA$=Xgg8Xpld*K=bA`4}yBD0Z<5`Y()pj{s2a3EuNTxUpZjAj8h z>L~J7)%DAw2a$T!_H^l*F@F)`MtB4`sU-MnPJxD#o<8*2HLIa3R?GASDw>+czKy~n z6(<|=EPl+itWl4C{b)zU0wg6QR);=0IJ+|YvD2oXfE&X?l{uc-j&2=()^Tg|P{et> zL~yHYy|4md4pwYiUL238%tl6aa!{qw;@8n;s^M$*re`9pd8ZhJ)LDS_$nLl%s%ztW zzn-lcwQV2G9|Gq$i^`ZBBxuupz=DkB-@k+MO)3}Hk6*W(38N5}5zGa-RR>={+!OO3 z#1AT3FE{?bXK@Sf))ODErmoBi_0b(;AmlWOGtK2ZFH%$H&=XVd!Sp-&$6hd2!hq?e z63B*&^cNSIS)o^Tk)b8cMY)sXr>Y8r-;;Detp>KdTmKUkV3jmr(j?v5-Z_@k_$f`q z$?7>e{1$9N!s`BYzC0NkllY8NldQkP{5&7MEf5OY0hiW}3?UUq z=K1D_jK+Jl66mT+fq{L!gx-ZMlko~2f754ChDJwES-LbJB&4qv0AzJ?n$fed)20p2 z$jHymb~>HIGcq23@x{30WX4$iZ@(3vIPvZ0pL_Vbp^=f9Sy?|EJ=)yZ*poH%wh8m* z#U>^m-n6N&7ve*_-%^Ih#?D-`=KC+ca5|ldX=yLy|eX~^6Ardf16Fx zb^d`Mlf6?|*n9KcT{?bzct*yUr=PwzUk-Y-r5rzdc5P*4`K3#Yu@Ms{G*nmr^@9(@ zo0P@HZSEX7Xi!*mbp5ScI*q2Ifx!_G(FqAgt@ie>zqYw4JT^9R&>*wHP*YxRx7q$H zGt)mPC}QA1##mEBgVk(qbAOKGe+EAAKtM=H-OZcsUokv3Rag3@N@bhB z+kOqrjg1$-`YJOk>&H{4yn39V+q{o*%#u%EG#hF=Iy4u>1$jIu_(ofc{GwSt>G5?^TIU6^of2OA!bvnPG zpv$LDsjggk=JnS(o?o_S4`b}e=FQi?`_6q-OhUr*n>R-c9B9z#LLwtePM-WSCr8|J zum0?_zwO;SVg7uF&E_8*Y-w)Zw`x^QdAa8`l$<=7nUxivl2Uc!hSv`lbe)$`MhzYu z91)?qd|A9$Tu?A!-n^x|e|DYTv**V7^G>JJb^iQYuD1Hx2|6g2nkubYuD4Sz4qmnEsU}0D_7o^lJbAgKYzQTLZ(po z1qK?lTD#3Qd;R+No_VJI!gxV=am$vvTeo&BTxd0$W0R6z-m&A!f0tf5-C8hX?6LXt zcduAct5W#|2EM#==j0_z{<3bJ=QU_5D~)>nkdY&M9wpE7Q8s;f_Z^pV5i z=;8eS!OLUH=pjQGW3?)kcu`+h_u-;N^;K0bs!~ai@VF>f`X9~C${{=$mMBIJ@rj~{_Tni#+c1w zF=(}(7nV4B^nm#I!n{0jn|-^Y;)kP0$IYDSx`2Q!-r9%i!a&d<&c zkBdv6J^R@=-iS+1KAM{w789cg2zct%SD#q8P`q1Ec(`kK=@LD3=-?3}-a2wbyr>8a z3=9nwWU|ocXqiGG7THCSg9o>?=yp_EQ&tuf5#b*kY-(y^jMZ0Fxo$EWjdFi~&ub9( z`$nxcC@ie|e~;5$+^MPAy<){HAAT4f7uRx8t=_$2h4%JsNrv|iUPkG#+j&9YIL>`f z%^1_F)df3u>NT3F%a<4I*dgBf_kH^+fBMOFA8T`Sn`usmeeBHh7VU=y((TaXv7GuT5awusgBkl3LY>(-JK0~r^GJBA7cr}_77ej zQ&yLje~RCG@!~_%r#~=mTxe8OKuAbpTH54SUQreon+yhr-G2Vip~n_181=*x3V(lv zzkkB$(eWuMZKi#D;6T!Y4^CRVI4C?^kjdhblZQR>NXtQ_)q3&x@yF)RPkHoFxu0Kn zZ0wMcBgI%bj!PapRy=HVA5~LUrYtUgcGaq=f5C$VnQVA^`nVZ0zCC!b(|=J%YhaAY z{rqB+lB!w{HzjnZrshsfjkGiS2QRmjM!o*lFTbRYAAh5$h%pwEnD{?y*NQtzyUq4v zVPRojo_NoHeEc!T^RwQ5+pqQQP6n;^@O$sInWii$Iq=Rq)0QuPa?zre{kz$G?$b|8 zf4~2pF;NW53dYzs`S~}mT~l4T@~?B}7H{8fvsjMi<`$ng;XW-tJA2k! zZ>>IXpk5khu!j2|ewZ;qj4R~iDYtlNK}-m zsmcAEq_|1b*VWy1nqOdGKxk-VU0t`%E!}kui?(eu8I7Nj_+G#iZ_9lAN4PLsi4Y4Y8?)Tf2pa- zX0fA766vWc#PF`cS`*()-;v^p$?U`^JlWfgD5$E$IlOYQe4dTxLnKf&c zv;)BhVM~$@F_Yj86n~C1?`BL&N?NdBL0VdxAP7pOa_`=~KmYu*B$L4hNwB4q$z<=o z`>s~2-LPT9n{U2ZUtj(*n(j*S^J=FFKh zJs%D}NSb3x_YbGE+wF`oj^iYm3_eKuUv$#b)9rTq#fujupMMNKLgFZ6Vq#XVT)BV$ z{yTT>NIMyPhm=u9L`3A|>^h&GVF@ zp`p3Cxn*T#Teog?I-Qct1fL~Al)=Hlxw*L(i>08TAT>2rywYm5mY0|Jd^q?Z38EY} zY*j)=gytm^WorwB#5%4q-65s$x@A_W!^;&veCsFb|F9?EME@zD4)w_L&<2booE(ik8_y3(+ z=TRyY3h@&M5M>|YI8G1*g+hTSnV2Kb^A3jtQT8G62+9|V?COhredpl-3XmF;VG0?u nAPo@#li&>=8=QX!00960%Z6sK-laMd00000NkvXXu0mjfBB+u@ delta 3171 zcmV-p44m`d8O$7zBYzGPNkl+9>|dHx=64BQUKaT6v?80)PV4I_%OudlDYz1`t(-23f;Taw9S{{H^n z(B+7t3>JTk^oY*A7C2)@Y)XpVYCW}g?^tgO zj4{!oj7v>@=&7d)_wBoQ;snQW2?j&riWS{v-&-fiw45E}aM(@$Hw zyYD7Sg;MFX+nu9zC<-h%Q)wy${^N3zToZYwolqrU7+axmCm5)DWj6Jk& z-HLx7|2QZ-obkLusnqH9v*yhc<$-P^boT7mPM%D9^2vMsKprJ|d6NPHo_ysMg;F_c z59$rXnJMRg|NHU@6Fxn7P?)9SQd1dYg*iDVva@9h#jN;vb7Q0D#@dh&onFtoT*m5Z zV^!6y#+1rr;faaIv2TkA?o`?|Xa{*!+$HulCe>~LJGtZb~V<~S~C)v6oIfa%jC zl9GBYmTMIiL&wwx2Z!nPQkkr&wzmGt72!&WR5~j@zT0g6=F2a2dVOG6nC1HQFN=!@ z&bTUH-|)mlAC;=Dq2cO<3oe(7G1lAJdEqaAnV*)XU$W%f(W9a~lOS4@`lU;Gp1*%o zP#|2KFmWPtA2Mf*Ic&Bs{`yzXEx-5t^N()W;JJAD)Ts|%e|_i)Gh?jm*s=L(X|X9Oh*Cr%L>Vw`np&f2uB+>@ScGdT&Yn$N zx$@Bs8-l{aPh@8|*3<~sM=d0&zjW#6xw(I8jYcT)#Jlg-l$1RB?6c9y$%bv)a<*@0j5StQ+j@F} zqoQOAg~MhW$2>ZxhDVZw^e?A za~3U%TCgB$!Ge;!yxh!8hut2Vl5!*2GiU0`${1tkKKyXmmMsxUNrQi)ye~8~Bs!Wg zcItP(>uhcP^x(k+gF!uca&S~sPe(^^WF%wk|6Y6T>+*8XT}txvlh>}Dq}6_P`Ev2$ z!$UVxzhntxtg@)+qhJ1#G1l79@XQ-;%zf;!qZt{V+nmVG7VfKyjSYR^fq-e#7-O>^ zepsPYnj0HG&&|EDCfR?tFFH9nJRyPOIG*QSF4y&I*McJ>wZXy7SFeub>2kST#fK07 z`)_{ZKXt0-N^@gl{;z+HA_XEusr2=|vB2t|CK+RPt9Ad*onc3gJpO|p=wf5%Enn`m z+mB{uYVNMxDe(^2f-SHy?wpzk1=q|7_m8VhNZ&-B+v4TEE`Z*jQUyIx{YA)s7u;%a%!HvXJQL|4dDF zc6GHGjZ^vbhm8Dn8FF`*AU&{$I=?3z#Q z+0)U|;xlpLcOH63J>)Mp+MAl*+q~IWRizCHnHd*n>+L=H-g|{PIm7;RPKRUf%P(Il zD46K)pSW^m;>wlxO`q;reTK)!a~xN5{=9#e{Gr0=;70OIzP-J@ZEbD0`5T?M)YO0d z$xlAd&HeBfzxeyO9H-W3c%JWaziAl6N2OA0G`*djJpCQt6`?jAS-$8r8sr#fu5&bGE&jj8hWRj5>!mXu1Hsmlqa} zLXloYoG4vR=l-2LBN7vZkB7VjCy{>~*|qC$r%#XdhKx6&oh8)K(sKS!e-dl7Z-v^@ z(%RC}vEGVt2q*ahIU|}WU2c8&hKw;Kyb5Ez6{BJJC>;)m)oQid?d>-^-~pq?Zns;l zRv#Z9*^q;02$eV zUL7Ux_V=5*4;aFjai1zb@D&-aM)V6Om&?83Kmu_}rBdF1mecq)(!IdAUtH7YJuks{ zUYfwS6q5l79)HA)a_-!@@4WNQ!i5V(922~dXopi*uU@@o%^I0ZHfho%vBm`NB+g9v zgxl7wTl;V#Fx)k9X3As7j-5Vzx}&2*DwT>dAb2xzq7+Wk7iA~_y!!@n5G9a0wbnDiw zi;0PmN~N{6wR`sLsi>$BWn}O|BFvOBnJhg$y}iAC=gytmw{LH2YumMJS3p337@G&) zNQ9Zv;c#r+xY6@ffSH+@AAR(ZUav1GD7gEk7)MzxjckeDPF8<(y4@4Xm zyp3p4`uX|o-o3l3s_Lz`-V$p}@J`}pTAh)R zVYAut^Yf#kqJ%5$c6&`t&D{?UUPy!}BO)SnIvryyD=W)$WgS~v+nP0N?tXCaLLx+2 zR#vun@nSJH27uv&44?>;u?Zw;&M+rraQ!3_$yZ-}HCkH*HzAQoJTJ#sZ_B+kOq3Fd zL@Jfa<#NUt&fXnc9LLG!a;a1*k&N^G+wf5;6bj)R2N31h;y6w!l`0epZ;w*QQ6iDJ zTrNa8wuD90xG!>~C;58Ga{)vkHM5}$BLS0+3^N<^{{a91|NlXC-f)hAOjZB@002ov JPDHLkV1ioBcq9M- From 04dbdd4d8e5e5341a47e1bd9e28325fae244b428 Mon Sep 17 00:00:00 2001 From: FPabl0 Date: Sun, 17 Jan 2021 13:15:05 -0500 Subject: [PATCH 109/145] resize Select.popup to make it wider, move Select.popup up to hide underline when it appears --- widget/select.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/widget/select.go b/widget/select.go index e5f4ad8279..94f8f69bec 100644 --- a/widget/select.go +++ b/widget/select.go @@ -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)) + 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() { From 8ca66b46d4498a02cbe25db07931e011a1898269 Mon Sep 17 00:00:00 2001 From: FPabl0 Date: Sun, 17 Jan 2021 13:19:50 -0500 Subject: [PATCH 110/145] update tests --- .../select/kbdctrl_none_selected_popup.xml | 26 +++++++++--------- .../testdata/select/layout_empty_expanded.xml | 22 +++++++-------- .../layout_empty_expanded_placeholder.xml | 22 +++++++-------- .../select/layout_multiple_expanded.xml | 26 +++++++++--------- .../layout_multiple_expanded_placeholder.xml | 26 +++++++++--------- .../layout_multiple_expanded_selected.xml | 26 +++++++++--------- ...multiple_expanded_selected_placeholder.xml | 26 +++++++++--------- .../select/layout_single_expanded.xml | 24 ++++++++-------- .../layout_single_expanded_placeholder.xml | 24 ++++++++-------- .../layout_single_expanded_selected.xml | 24 ++++++++-------- ...t_single_expanded_selected_placeholder.xml | 24 ++++++++-------- widget/testdata/select/move_moved.xml | 26 +++++++++--------- widget/testdata/select/move_tapped.xml | 26 +++++++++--------- widget/testdata/select/tapped.xml | 26 +++++++++--------- widget/testdata/select/tapped_constrained.xml | 26 +++++++++--------- widget/testdata/select/theme_changed.png | Bin 3836 -> 3735 bytes widget/testdata/select/theme_initial.png | Bin 3295 -> 3259 bytes 17 files changed, 187 insertions(+), 187 deletions(-) diff --git a/widget/testdata/select/kbdctrl_none_selected_popup.xml b/widget/testdata/select/kbdctrl_none_selected_popup.xml index 971bce5f39..7359f14720 100644 --- a/widget/testdata/select/kbdctrl_none_selected_popup.xml +++ b/widget/testdata/select/kbdctrl_none_selected_popup.xml @@ -16,25 +16,25 @@ - - + + - - - - - + + + + + - - - - - + + + + + Option A - + Option B diff --git a/widget/testdata/select/layout_empty_expanded.xml b/widget/testdata/select/layout_empty_expanded.xml index 7d888ae859..47f0d05c1e 100644 --- a/widget/testdata/select/layout_empty_expanded.xml +++ b/widget/testdata/select/layout_empty_expanded.xml @@ -16,21 +16,21 @@ - - + + - - - - - + + + + + - - - - + + + + diff --git a/widget/testdata/select/layout_empty_expanded_placeholder.xml b/widget/testdata/select/layout_empty_expanded_placeholder.xml index 0075bfd5ca..29852d9ae2 100644 --- a/widget/testdata/select/layout_empty_expanded_placeholder.xml +++ b/widget/testdata/select/layout_empty_expanded_placeholder.xml @@ -16,21 +16,21 @@ - - + + - - - - - + + + + + - - - - + + + + diff --git a/widget/testdata/select/layout_multiple_expanded.xml b/widget/testdata/select/layout_multiple_expanded.xml index 57e34aafdf..13a365cb6f 100644 --- a/widget/testdata/select/layout_multiple_expanded.xml +++ b/widget/testdata/select/layout_multiple_expanded.xml @@ -16,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 69b33df466..1125014a6d 100644 --- a/widget/testdata/select/layout_multiple_expanded_placeholder.xml +++ b/widget/testdata/select/layout_multiple_expanded_placeholder.xml @@ -16,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 a3e75c5edd..188be50973 100644 --- a/widget/testdata/select/layout_multiple_expanded_selected.xml +++ b/widget/testdata/select/layout_multiple_expanded_selected.xml @@ -16,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 02bbcee4d6..9cad57a8e3 100644 --- a/widget/testdata/select/layout_multiple_expanded_selected_placeholder.xml +++ b/widget/testdata/select/layout_multiple_expanded_selected_placeholder.xml @@ -16,25 +16,25 @@ - - + + - - - - - + + + + + - - - - - + + + + + Foo - + Bar diff --git a/widget/testdata/select/layout_single_expanded.xml b/widget/testdata/select/layout_single_expanded.xml index cf0dc05a37..97c554984d 100644 --- a/widget/testdata/select/layout_single_expanded.xml +++ b/widget/testdata/select/layout_single_expanded.xml @@ -16,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 043390305e..9274065900 100644 --- a/widget/testdata/select/layout_single_expanded_placeholder.xml +++ b/widget/testdata/select/layout_single_expanded_placeholder.xml @@ -16,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 3096f72f15..0cb2f26efe 100644 --- a/widget/testdata/select/layout_single_expanded_selected.xml +++ b/widget/testdata/select/layout_single_expanded_selected.xml @@ -16,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 140f202360..1b72dfac99 100644 --- a/widget/testdata/select/layout_single_expanded_selected_placeholder.xml +++ b/widget/testdata/select/layout_single_expanded_selected_placeholder.xml @@ -16,22 +16,22 @@ - - + + - - - - - + + + + + - - - - - + + + + + Test diff --git a/widget/testdata/select/move_moved.xml b/widget/testdata/select/move_moved.xml index db2b541989..955b07dc79 100644 --- a/widget/testdata/select/move_moved.xml +++ b/widget/testdata/select/move_moved.xml @@ -14,25 +14,25 @@ - - + + - - - - - + + + + + - - - - - + + + + + 1 - + 2 diff --git a/widget/testdata/select/move_tapped.xml b/widget/testdata/select/move_tapped.xml index 01efbeaa6a..5aa1b65e46 100644 --- a/widget/testdata/select/move_tapped.xml +++ b/widget/testdata/select/move_tapped.xml @@ -14,25 +14,25 @@ - - + + - - - - - + + + + + - - - - - + + + + + 1 - + 2 diff --git a/widget/testdata/select/tapped.xml b/widget/testdata/select/tapped.xml index 5835cb01ae..e19977ac71 100644 --- a/widget/testdata/select/tapped.xml +++ b/widget/testdata/select/tapped.xml @@ -14,25 +14,25 @@ - - + + - - - - - + + + + + - - - - - + + + + + 1 - + 2 diff --git a/widget/testdata/select/tapped_constrained.xml b/widget/testdata/select/tapped_constrained.xml index 02a98c69e6..980cb7e652 100644 --- a/widget/testdata/select/tapped_constrained.xml +++ b/widget/testdata/select/tapped_constrained.xml @@ -14,25 +14,25 @@ - - + + - - - - - + + + + + - - - - - + + + + + 1 - + 2 diff --git a/widget/testdata/select/theme_changed.png b/widget/testdata/select/theme_changed.png index 6ff552b4f9743c9f97c96d9628a564d9f610beaa..f0e8eb3780de6727e52096dc079174618e1433a3 100644 GIT binary patch delta 3282 zcmV;@3@!8g9hV)DB!6B>L_t(|ob26uP*nHb$MN4@SXfwCMOf}2u!2A&TCY4zA`+Yw z#XhFFG>$}wR%2#bQirBfn@p>TO>AmunaQO#iGl{wFdCyVWF#iWCyxY;5A#5jix?5* z;tDR8UDykIb~|#?9RkZm?b-b;c92C1HcYPlQ9b+lV1!Gk-!jtj?1F-R4RQVBV~Smclrl2j~vM=FBfJ}K!P)( zOfM>0*VriY_2s`z*tl_BW8=o2p6r&EO})Jvu3u04$3J8W#U%GOBQbGiQj(DCbpfSX zovYFOX!~|oFNA~%e#Q3Qsh@ZvJ}2kY(@&dqI>y-j+qV5zL4mHhxq8kNUV(uj zsj1-^8D_m+=#@B>vU_)bM@Ma8p-X1B>%DyWQgQK;mtMMl;zVclbpOR>(fI#l$vr+j zB9SP&x!Gbey&oUXZ`pY3mepc;KQ7MH+iM>t_42Y9jg#Exy2eJSm)F6lsC!%5_sh%G zXzJd6`|JxZ-22|{k<8aOSEFfv|MJV@t5&&sEiNYPkuqw{8bwr8<+g47mmc2Up8o#V zPn;NDBx7tuks^_3_D_BimY(k60>((jf%&{1Mjh*Mue^*vE zI51#;G(00i5gy)9R1~;yq5AR1y;Q3H*48VB4|mnnjM$GNJUs5HrjrP ze{O%stkX4>md@R@NvT%%UcNkuXLrgH_DK2Afdg?*J#`>FyuYoD-?Fi*%gS-3v9V*l zUdw!aGmjk$O-s{#_nldPulG+(H0yNbt5@Hs`hKM&j+7IQ_f#q~j~)$KzTC!f{q61E zK|wZ-+pkik78J~0vql~qJlNM~>gi#OU3~M+>OcKy^pfJ%uTS5p(S|NGzLH*7e!V@JyF-91fBB9TZL8_PtZ|NZ5EFTZ``4f}p#AA9Vf zk`l&o+WLA$XsA3mxT&P%WOlZFK*Y+GSrrv$w{NfBz5Cvtc=smkg-*x=59qI5vlq!2 zt1T>)t5lDiITNvRrNcjx`q#gPrlp;F`sw%7>azLs%N8tPjII3O1F_WcL4CsU55DzQ z$nxbifBy5^K0XJ3BO~AO^*y|7*`Qwk<(4hwSy_y+Z(o1?U{ut>s3?a;&Pq;BFDmM; zuRj&{Y=I7@-dv@0kPuu@**RJy~zdSQ3DXXI5$-27ayu9H*TF)6X;&XFb zjvsF*D&n_jFJ8R3cdsHcGHk_)(Njz~UanH9fA+J^>gvkh{Dw1`7-O8-Y(K(H#=Kwr zLL`-*$aGJ z`=6~_4MV3EHkY>F;k}r)ud^V^`OR+grx2F0Wa$?s~Pt8QrBoMGAYNBU37G|KC4!x;BFD z+O^7m{QPq-yl`J$-qM#}UR_>Z8W*Q;ZS@WgW{f3l-kdP(MUCej*bx<``g>?v)dUuJAW|9W@AGaS>G=;Bt#;Ut@-S;@uxFswPKmBhzxEn`E>IFrew)t23V|M=5+C=|?U zC0HcS9-?qX3LB;I=1u#H_&E6cCj1YczZIg0h|ssTPG*V;$MdhDGZPc<>N~ityP+X} za`kF?K!9P`Z6^Pr9ct_AC%>P*%a_A4GB~r@F!Z#H#cS3qlcU!bIt0y;C*V1yp{vWJ z)eb*rl6ZKG9v1V{pWglf4_$m{zW%zuwKYB`$1f&kGE+=AzT>N}Oj>PxPL7wq|L8{t zhYoe}z`${)xKvuo7)yTcx#1g=fAuSW#@LlZhbFT~-sQ3~#@LdVUK(eN#KS`wAKzV9 zH~HO8Ny6SdzfoBkwR*LuQpw*f4^B;8v2Wk?ii%scwWgjPc|btqkAEDInR%nKviayy z{xazFGtaF0_~XZ`t84!9ms{U{D-w(SlagkyU3(-Yg)^H+?0>@XR*R)FKYzu4{{4@9 z{dMi%{?^~t<`Wtkm6=)bY)+}!Y$E9>^|y`%R78}{vs&&f%A<{3pq#FZmQ2HM-@K|x_FR&>|b zSHJoyKPGVTVu?)FKE@6F=|k9mD6bwn7L}D1y>@NG&^e#JwbjtsnYei~6Muh%Hfgmr zd-j~)xzlE~@>^QU%a5j~FMZ{e#s5C2aAtGc$&+K9u}wI>p{U4WG%nt`^T9XYf;L~u zr+q>~{+X0C`lJweKEc83nwpwQN=|Rx>gu()p5RgPFH9bOe&+5IZtJ*r@}@I9MZ-BG zN`O0pUmOFIF$yPM`8UrEOwq??YEdmXo#QAqETVeNixyeUW^nNc)up95 zZ7y(YI8u}G3xAQo3V%+DQsU<)3lA52dOBx1aBIRwDUwK3Tec+E)-LMpU2y&SBAqV& z=uyw;XhA0hcPH$>%^0(9U%-Y9eP4WWGcS+p>rl1Wpa9_ek z+40(I-N%k;4?|&}basZm_+r5N^_sWd5_D>CU&6k84}V;|XfKl2bK(SJ%quol z(0ReFIs58cs#G$@%pDz0o)_GRv!nEX;t6K8_8dR%x` z&I|6vc~N@Ln>VMd%urw7vTd8wCIxroq$s`S%t`p{GfQ`O!^01AdcAWd1vll4D81C` zgfG6Z8VvR6>3`<7HYdyoZcXqgy<%e%PMxwDjdc$`XliK@dODZ_guQw086AE57&$P2 zV15{`nD)w(r_C*wrQ6?BKqHj8ZO_MMW{j{2zO4^rM>B zUq_VSkbqHIdV0=^M8fSKrYig;Umyoj0y&5h$U&4q4wFj^C6T}vk_-x3$H6CLh?rHv zI4K+SX1YgMvny5w)0%@Q{aCj@(}b}rj4=!IaK)-%T5}Mkoav)j17l3ZS~(_h#j0Rh z6IG4zfPpFc*i0KvI>G72{M0o$)5{q?oE%&L2SSrS3^9?w4IBAa00030|6INam1*&x QmH+?%07*qoM6N<$f_xLZ?*IS* delta 3387 zcmV-B4aD-79sC`TB!9z6L_t(|ob25TP*msL$MI(`EG+Cr5SBa0MG%NY&^wG7=Nxn^%IyFfXWF#DEBb zE4T~n0=vte-3}bPLjbwDo`2-`8K+auc|7OY<(sqToSj{zWeE&`7O~J102m6B0RbeF zJ_-j5BOQHp`Q4fafCG+`!3sZ3ktCb-kGL>qge=+s&;k4pn=S&JnxEoO> z=jE-ft(7U2{EsmkHmt3!-O$mI-q^UYvvYk@Q_?^GDN`uMxwRRwv7T{p&YZ6R)RB>y zTI~bdwh28E62|z5?bJm+`DAoP#>r=%u^0@DvHQ1f{jZ!HLqkLP&Yh;4H{E=HeEbs= zgHlo~Mx(Q5GNOcCySiIjD|2%N*}FsM<;$1y^B2GTa?|nSZROMbgUzDR|H+amK0P9l zD7~SeY(S(9*42`5#@}-Ce!BnvNeI zTqI*`NRc9uXx2}E8kn5y;^CpIs;b?;-_+hd%3j7CFA|ADQd0wylH4>JOK0cx)2AB_ zA9hhH=e_WPn~#t0(xvl$^BcyP_RN{qufHB~7s`;3*=yITXV12pOl{|X&V650)YsGF zSR0g*q6iAA$;ZF?R8-x61$g=iyU|TDLBF-##W5cU-z8mC2M55yq=m zi&w9{Sy{;sSoV*9M6X|ecKh~(UAsE!>O>-uIwFFJMF01zU!8w{^G(NgA|8MI;erCj zak}biML>Yu&#$ha;6!@5V?gkV6=@|UXSQuC-?eLMPyCOYb1!uKAAHbw^{S&t##m); zu3V#e^z`ZA6)Q&kD~W&mTR>9M$!DHU>=J<{P8{UAEJFe>W9`1ro=?j^6j>X?Q) zGV}MccPOXSa{| zXVLcUcYJqFj8djjDQC@U|KVx-cRP2Ud*v0+xVW^ElBcSw;?X zCNGa)qPuwU;+{QFMn3?(5fo`6b%2vWlD>Wms7FV~-6US(%fgyLiztjkrxxklD6PG{{X1}XzwH2%>HlAUopD@$!tUMSk3CkIo6En#o_*=1+Wh<>gDpS2 zVCRiF-qzPQ`W(i76b6HA#*85gT?XEW;szd|gPr3>*$!tmn{~RP`|lrpcPaOFP^^@q6iK)HaCxF7h{g+Uqd}(V<+_p`sr(GLRPJR zl6!mi4!X_cHLyWlb@lkS({=fBU`h&SvGfi+Ew|$~bEbKu*A_aQnj_DN=ajwe?Pi^B z@Hvyj#bx-g@Spvx{}()P@uB_Zo9^c3=!^_ic=&jBG3NNzufI0ybkP|ZZeCu)*Y*t@ z>f}B?qwL~RVIgBI{`uzzFO2{7uNh;1^#>1*XOg_jMMaFU#V@}+${2}@i#j@5UsW~! z&EAuod-MEyX=&)HRjz6^f4AH(F>(3cy-g)0H!Ca69UXFS?~tGTBsewodTD9Hkt6(N z(5YviUHQo;Pn4He{PnLl&z~2G#a?l7v(~IRoRGj-EJLgw{> zUgO93ELtRy$y#o61AqE(Zj@Jljvft7OAA}Gre@%r&)D4D+twDlX%iFQIzpRux{BSq z&+XV@x7qk5jm5=Bl9QLb`s$+p98@@q<=Tl8w>x7Sb9_x+p4DVpv}4CZZ@tAY>8PpU z*K&P*C)TY?dH?;S_ugZSRqfd`JW9q`aa!7v*ItX=y!pPYEPl>se)qe75pQaa!p3o* zq@*nV)1P8CZVdU)8;OR7hK7$nc8m#Iv!?$MefsHywtVk#?mIeCxjdt#rQ_12Lra!8 z7D{9?kAMKFhlg3O=PzSNBvYw80s=Ub$=KX%vs%a8*O=qw8jYK`x2e5-$XT68ELKNG zau$o>%9T;JFP2CY!NGQa#*B@PcK*tGQp6I8M_`~-q3FGFWANLd5}7QcwYBTYm4o!| zQ{H9Hjgm1oFFQM7_wHklJknHBGUbik%i^=L5_5AuUAgk=XP*f@7lAoFN|8wP-=|J_ z`1}7WE^hcqA@Dr>{MOdh)fE(++OkFHxd_kcQSvWLE-IBpueXg5dM9r>!&5Za-G~xk zLh!*clK~7Mlh6wke~j^I#{Zf82c!TdX|f-&H7c0ili6^fg-H?Hn5Uj8M*fb{Nk!Qd z%xdN^tuNywQ=J@4PZEy#YT29`7Th#^<;0^jD*B83ZUL(gXMH1l4GX~7T>4meegFR% z>3BKuDD|HG$H@9{R<@KGly_>9Fuf=Z{r?-(+@I4#qbw5*CS7u!iN9l#a^_Obl!sZ^ zot-L76OXcn2hO`Z@Q!2w6Z;KYiz^kA0Sq9M&ZN2Dp^pF*wt0&i2w;gMk$g=G@CcaS5_|U?3~}! zw9sIPK61o0EKI;D0R=+-+l=9R_j<2i-}U8}H?p$0t}aDFg60>$h@C&b^1l1Ht}X#5 z2Er0D%GTFk*B?EqJ9LQuu`NH}+SV5E(o5d!)@k2(NQF?6uY{{o;)cF3DF%q=>NhCL)NzJ+}YROF3{9KV8TTym&-y!8Dn0LKR$e| z_Ki0X<+LSOl-7=pGa`{tdk4ydzxoCk0#O1vh!V&_lt2!m1ac6Q4*?dF-U=dM9ijQ`Votq{I{;jnelc8TLhRQ9O{#B3mKD84ip>CzXJdO|No^wEJ2GV R{`UX?002ovPDHLkV1lZ-@fQF9 diff --git a/widget/testdata/select/theme_initial.png b/widget/testdata/select/theme_initial.png index e306431d9129f67c39b4945fc881624c803db182..64b010994d7502fb27373f670d5222c35ffc8850 100644 GIT binary patch delta 2778 zcmV<03MKX58M_&fB!7ZQL_t(|ob23raFg}E$MN5@B;C`7u2{CFLJOA*MU+umEGj6V z!j&0@tttX8EQ11r;uOVy1WS>*fKvw;@N%^>vM2{B6gcMy9t8zj0XYh7Q-eZVNL!N7 zq*960W?>x`bY~r|a;}`%Xd<9Pr0MHhb0SO)!5G9Z! z`o8#ni{;On1n$<^$jF`^p?i~#2_Jv-Sd^;7#0d))M8w4O)Br%%9iC?NZRDg$gL86< z^Yh(q_u!nIN1lH^B|V)n*6`bJWrq%Z^Vw%UzE%|&Uw{CT1hVC|I=FH@@ zw7qNA^ziy z%gWkZIlfPy*u=z!t5=PB{p}WvR;v>S46qms*MIq?%|&s^$?<*q*v#hIsw$V$`CqxY z;ZafQ-n|)PO^uBXo2||DIgWqpJ#b(|OicZ+zj}Yixa4G$Ue60cYG$V7a@A?IZN9es z49&N0o%!<1+`POWjvVppc7jgxKgtmkCLI6xWBLCUlPNqZN)Z;;z7J(Y#EjLe?;SPD zq}Ru#q?|c$z|*d`ar5To=H(f0+=z*fuc@f`c;!lq$;227kBXYUdUbzhcDBW642z07 zcjSof{Q0L|eU;<+h1<3<#`djUd+FP6y_ZTFFyPs>Yt_Abn~lbp`1ta}hrcK&khk2+ zKK=Bs+qaLIHA`|j!=t0^&CNTOF0HMq@;yWO;lsIkd8rv0*Dhc7`{shX=Vz1&efvhM z)w*-%jwuvk0}%T^<#|P(COrpruzC1=FV-ncI~->f)#uBJ~(wM$8qw(-+dD&{$tlJv(d;H ztJ7+=XU`7J&24|P+Ndd0E`IgZ)k~M;-DO!x$wR3vY+uUA)pzkmOzDN{UGC_8jW9@}QITs(d}DJ{+S42&_i+pWKH zC9!{h|86U9k|dqlx35oT=FqWYJ^xZOGEVK?iy}Sz+){r=s8lY8!+U4lSW{D+pC6Z! zl09wO)33djlAgZ5urM|$Nf{CG_{%RpI%kf2wWzo_&+gJAv48)*Lx#MuZ=ZZp85tR= zQVF7{N=y`$O1a3p6yLXRON(AdrL~onQEGK~bhNdpi80o2?V9Hzo5i9C5BEKTyx+GN z3{kPMoxgvbI&ibLcI)EBFMaSqTuMsI$-26&ix(TNUk}LQ!NJccC6|jA1dijp_tcCr zLtS0T=FKL(e&V726FlueC|9M4C_ z#&)GgJtB{eg%^7Lu%^IHnz zxb}Am##l}3B7FuA)?K(DpVMc^5JO#^?M_MEZU$L&uU>VX*o4`FAg$y#L832aX!0N=S%^iAl@K8voKu+OjgM*(|wSC->}mc=qgJk3Oml4_AhV z4;Vf?H6x?VYTxYIrMd6Ear5Ry#l;Dtn3A48=)nhD4k8_nGY1boJZo0QLk}s!!s3#X z`wbl`$I5YB`pA*;VXOC2wUw3Hva+X_E=_;v+gA|9!P(iPCQtrm_wGCXM7NuPF{TI$ zOV((vwH|H;(9PP~o3*upT{AfNxuvw2Ojm#YIdk;r%co8;#*)&~{%6Gsc}MATI)5lF zEiEdNule_nKH_+O>YHzdwZ7fSY%uJ7_uV$DY0JxZz5Vv2MT;JrJGW*3ZnK^EKxC@wyE7g73{;ob)xV2o9lm-}~HL1%HkKgrj}yBSALn)LM2rE4ZnwznQ5 z@`4c4s~6)qlV0C`ugVL8Dj~t;bT)rAHnzX?_fa@5TCEn8N|RpiIhd1)3Pnspg0-p1 z`#DK@lV+-~?{KxS$jAtl>Q;Syr=DBtaE7@XHdrl|PgkwF`*pfi(7&5e&}cM1F23hB ze-_A(wq%YT9haP}ZGBS5?RMKNmfIb=x!rE7*=%q3Cr%so=4NYCQ~PQqNwR-7H975e z?=u}%tL^sp8JEM+vQ+0EXK6EoX2gixyu9N4d^*q3*R<}Df|&nNy4~)|)2G8CBkQ!< z?wO5*Ua6_&hYz=Z7^?>beU$$1zM-cC{q7qt@&$4bC6I$Cft=euPARprcIRt#!9Px? zlW*12gLIdUqjWl*cDvo>av5c;)<1nDxPxYn69hr2RElDk-pxW*2S1f0Np`#4X0tgQ z4n#>%Gh>R@M}>lQd)aZ6E|<&Ua9FKYL%Ua!LywcU6QU?ek`yXYy8j?ak~nZ+PfP{A zNIIS8chu9fbc-OopTU1RlYt8*e_f4o*sx(mMMXI|IRTmnplhFbK7IQ188c>xq8NkE z(}%$Ee@i*J)v{&Ftau?X1eE_<%F@!(6DLj>jYdHb0y+|eI{%}zw+iSm01SV914W1u z$U&4q4x$8d5G9a+eD258sZ#?n3Bd2Lr37*iC6I$CfgD5$#sL7 zG`#oTdkF~%fgTS+k)K;ir_(uq{(R3z0j^)a{=k6)BSwrkcI;R{$AeJh|1qWahf}&- zF2)$gaRHhNLRw({(8WnX?cTjRKqEn@>r#}lv9SdO1r-$)8#ZhR+(;1W{C}KMrBW3Z7FJePu3x|2 z?RE!rDhO$QMj0I)U07IXx7$lfN-{Guoy0AsaV( z&TMFCm@#8U;AVpmlkYj}P=P01Pk40E&|V3?*Z9@PZ8P4?NH7bh@6H3Vh*t z-t#-^=~=o(2T}4oF9?D{p7^c}x`boRfA+N`=%srNGc&0wV)B zGcd#4=PcN#Srf-+T7UKlQs0V3G?Q~ zCMF)C<+9n@!Sn z{(&Hqy;E4&d-L60I(~e3M#h+@pT0L=4tlhu96x(@ZDnQorAv&l5fdgfR9FA?gAc@; zl*Pqu?i@L2P*`+y{jFO%ji#f4!4VPB2?<86_V%y8wz(-hHa2q5AhW?xQ(kVj+5Rgt z(?2LEV&Fi=SW`oT)ogBae~#mS20rjWKuAd4&71CDF+4U_uhH;=5TBaru-ny2Wt+d- zehtlyjTgWADl;qV$5W@gdYqu!ypM9slqqLF`9%D)QLpz83X=QzweLd_5HNS+#{0*O z(`z*0ad8)q9dotoZqnk#nORx7+S-uF$m-J4Pu8t7>h+8<|Dd2b8#ktZrl%WqI=`Tx z%coAMu3UNM_18I`U$$otW9-Q0&DX#C&V5u&Lc;T#H%AN{Xwd0GA|p#qp8PT=N8EC+ z{_L~A?cFQ)PYE?~nx#u;MoIIJCl@*_oQg!2o*AEwTotIHY4IUgE z5uv(#S-ejIrq}SKgPB@_)}if4ibWrcn3= z1{$N-lagNEvE#{qmtH#ES}_>oz&IF1t!{vMn<^`8e07<4+u zm|Ce+Ub-|gGqcTqv~e?MUiLKhoeWw&7A4FL-C0d;pZm6!#&(02y zi%Xw9``I_%h)YgBnwuLI6Qc+ScR7;efuhZ`pI=4Yjbm(X-%I>mr*t~G;lm0 z7#4Qd{pp>W8jj}$nM_w(+uYa~6c$!fR_0-vx}qXt;K26x(Q7moqcJ`;wd}$L_v>2< zSWQ5F}Q3NfehduI0%R!{odhz)2$L7yZdGt}apI>-v z?2wTo#aKCxOCCE`JZyCzRZ~``EG~X_)vBm}!Gi^vYC3L5z=1xtGv@`n$FSnFNz5doOzod>If1{{~F&2}U_&;mciaScX&Gutq zVPRgLc+Y=){4vM#v)+E&ul4Ot2Ceq+d+)WGrYtEr@XkBamM?#D(V~|9yV-p1(@#r( zzyF>wR+yJ3$YfcYHpvtU#@ILc`8Tg!Q(d|8uXE=XZ{KdSSdQlA7N0obJ}o~xd)8ZT ztv+y|Wt7QuEMDY{v=-y?`9l3ZQ8S|R&AOw!_s<; z$O}TqfB}r-^cqe3y(%vVp;1wGo2{vTp`rb)|5*yh1xG{(3WZ*yaUINwWO8{(RFtWy z$^D$9xJlF3)!lWPUtnNBXlP?yUAN9H-E|F%wrw*Rji0Sw-}O1Ys^7nxQAkQk@^JHg z9sF7#KHHKyetdXrtg`i_j??Kh8;uQFECK8 zRQAr=NEi?wUvlzf`=_z`P`{7T``tJ6m43hb#*2J`97GA^AW9$yQ35%L63FS&86CUB zVRJa{{**V|6C7hQo)^0F+LS+kug;@1+iV7_)#`9`bS4Jw0gmJ3JRc;N`^kFrUcWzu zPX2}e`@xfyYHd|*V}q{Qj#r`f9f9WugayRMgba-fpT41}ub0!iI*GE`Y;7`H8g$J! z)jG4a7vG==p83gJzEfere$D0%&$0Czot)9JTCL5$OGrq#hYN#0P^nZ60l$;?_tT6% zao`MpE|Vb)C4Z!ha@43%d3kvm85t7J1Ro^XD@NzcnKO6pT$xN3g8vH%^o%rH${DRz zuU>63nIstqzD$}eWnp3AxpU`qI-MX0k_-f2CQX!s~2-LPT9n{U2ZUtj(*n(j*S^J=FFKhJs%D}NSb3x_YbGE+wF`oj^iYm3_eKuUv$#b z)9rTq#fujupMMNKLgFZ6Vq#XVT)BV${yTT>NIMyPhm=u9L`3A|>^h&GVF@p`p3Cxn*T#Teog?I-Qct1fL~Al)=Hlxw*L( zi>08TAT>2rywYm5mY0|Jd^q?Z38EY}Y*j)=gytm^WorwB#5%4 zq-65s$x zTrOvf;nll+h~qf9TrLO#&-eeGTjx Date: Sun, 17 Jan 2021 16:11:41 -0500 Subject: [PATCH 111/145] remove useless comments and code --- widget/select.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/widget/select.go b/widget/select.go index 94f8f69bec..49e848ee30 100644 --- a/widget/select.go +++ b/widget/select.go @@ -319,10 +319,6 @@ func (s *selectRenderer) Layout(size fyne.Size) { 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) - // TODO are these needed? - s.combo.propertyLock.RLock() - defer s.combo.propertyLock.RUnlock() - s.label.Resize(labelSize) s.label.Move(fyne.NewPos(theme.Padding(), (size.Height-labelSize.Height)/2)) @@ -336,8 +332,6 @@ func (s *selectRenderer) MinSize() fyne.Size { s.combo.propertyLock.RLock() defer s.combo.propertyLock.RUnlock() - // x1 x4 (reserved) x1 x1 x2 - // pad - label (placeholder) - pad - icon - pad*2 minPlaceholderWidth := fyne.MeasureText(s.combo.PlaceHolder, theme.TextSize(), s.combo.textStyle()).Width min := s.label.MinSize() min.Width = minPlaceholderWidth From fa994f811d5792f72d5ef4cf1169bb1a7a68fe44 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sun, 17 Jan 2021 16:46:04 -0500 Subject: [PATCH 112/145] add CreateListable to ListableRepository --- internal/repository/file.go | 11 +++++-- internal/repository/memory.go | 20 ++++++++++-- storage/repository/repository.go | 7 ++++ storage/uri.go | 56 ++++++++++++++++++++++++++++++-- 4 files changed, 88 insertions(+), 6 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index 254731bf33..858b99e797 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -210,7 +210,7 @@ func (r *FileRepository) Child(u fyne.URI, component string) (fyne.URI, error) { return storage.ParseURI(newURI) } -// List implements repository.HierarchicalRepository.List() +// List implements repository.ListableRepository.List() // // Since: 2.0.0 func (r *FileRepository) List(u fyne.URI) ([]fyne.URI, error) { @@ -234,7 +234,14 @@ func (r *FileRepository) List(u fyne.URI) ([]fyne.URI, error) { return urilist, nil } -// CanList implements repository.HierarchicalRepository.CanList() +// 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.0 func (r *FileRepository) CanList(u fyne.URI) (bool, error) { diff --git a/internal/repository/memory.go b/internal/repository/memory.go index 42ebc59fe7..4773e23658 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -262,14 +262,14 @@ func (m *InMemoryRepository) Move(source, destination fyne.URI) error { return repository.GenericMove(source, destination) } -// CanList implements repository.MovableRepository.CanList() +// CanList implements repository.ListableRepository.CanList() // // Since: 2.0.0 func (m *InMemoryRepository) CanList(u fyne.URI) (bool, error) { return m.Exists(u) } -// List implements repository.MovableRepository.List() +// List implements repository.ListableRepository.List() // // Since: 2.0.0 func (m *InMemoryRepository) List(u fyne.URI) ([]fyne.URI, error) { @@ -312,3 +312,19 @@ func (m *InMemoryRepository) List(u fyne.URI) ([]fyne.URI, error) { return listing, nil } + +// CreateListable impelements repository.ListableRepository.CreateListable. +// +// Since: 2.0.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/storage/repository/repository.go b/storage/repository/repository.go index dd620b6d7c..33f203edc0 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -139,6 +139,13 @@ type ListableRepository interface { // // Since: 2.0.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.0 + CreateListable(u fyne.URI) error } // HierarchicalRepository is an extension of the Repository interface which diff --git a/storage/uri.go b/storage/uri.go index 199464891c..c65d12af47 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -407,7 +407,7 @@ func Move(source fyne.URI, destination fyne.URI) error { // CanList will determine if the URI is listable or not. // -// The returned method may fail in several ways: +// This method may fail in several ways: // // * Different permissions or credentials are required to check if the // URI supports listing. @@ -445,7 +445,7 @@ func CanList(u fyne.URI) (bool, error) { // the resource referenced by the argument. For example, listing a directory on // a filesystem should return a list of files and directories it contains. // -// The returned method may fail in several ways: +// This method may fail in several ways: // // * Different permissions or credentials are required to obtain a // listing for the given URI. @@ -480,3 +480,55 @@ func List(u fyne.URI) ([]fyne.URI, error) { 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.0 +func CreateListable(u fyne.URI) error { + repo, err := repository.ForURI(u) + if err != nil { + return err + } + + lrepo, ok := repo.(repository.ListableRepository) + if !ok { + return repository.ErrOperationNotSupported + } + + return lrepo.CreateListable(u) + +} From 03aca1248060a87f8c057db5c3c84887606f5021 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sun, 17 Jan 2021 17:07:29 -0500 Subject: [PATCH 113/145] add CreateListable tests --- internal/repository/file_test.go | 44 ++++++++++++++++++++++++++++++ internal/repository/memory_test.go | 20 ++++++++++++++ storage/uri_test.go | 24 ++++++++++++++-- 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/internal/repository/file_test.go b/internal/repository/file_test.go index 59349ed801..595ff0a4e1 100644 --- a/internal/repository/file_test.go +++ b/internal/repository/file_test.go @@ -14,6 +14,17 @@ import ( "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) @@ -433,3 +444,36 @@ func TestFileRepositoryListing(t *testing.T) { } 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_test.go b/internal/repository/memory_test.go index 39e03612f5..9d4d4907b1 100644 --- a/internal/repository/memory_test.go +++ b/internal/repository/memory_test.go @@ -310,3 +310,23 @@ func TestInMemoryRepositoryListing(t *testing.T) { } 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/storage/uri_test.go b/storage/uri_test.go index 2619d492d7..59e4cd0f21 100644 --- a/storage/uri_test.go +++ b/storage/uri_test.go @@ -381,7 +381,7 @@ func TestCopy(t *testing.T) { assert.Equal(t, m.Data["/foo"], m.Data["/bar"]) } -func TestInMemoryRepositoryMove(t *testing.T) { +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) @@ -400,7 +400,7 @@ func TestInMemoryRepositoryMove(t *testing.T) { assert.False(t, exists) } -func TestInMemoryRepositoryListing(t *testing.T) { +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) @@ -423,3 +423,23 @@ func TestInMemoryRepositoryListing(t *testing.T) { } 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. +} From 635f0bf2c27b2522d4a097c6024513c35a215c46 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sun, 17 Jan 2021 17:11:48 -0500 Subject: [PATCH 114/145] text that Writer() errors for non-existant parent --- internal/repository/file_test.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/internal/repository/file_test.go b/internal/repository/file_test.go index 595ff0a4e1..1c6c7fa1a1 100644 --- a/internal/repository/file_test.go +++ b/internal/repository/file_test.go @@ -138,6 +138,7 @@ func TestFileRepositoryWriter(t *testing.T) { 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) @@ -155,6 +156,18 @@ func TestFileRepositoryWriter(t *testing.T) { 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) From c294f1620b5489bee2ed93bccef2310c42f5fc31 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sun, 17 Jan 2021 17:19:22 -0500 Subject: [PATCH 115/145] use NewFileURI in repository/file.go --- internal/repository/file.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index 858b99e797..dd2b279998 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -12,8 +12,8 @@ import ( "fyne.io/fyne/storage/repository" ) -// fileSchemePrefix is used for concatenating with paths when we must construct -// them from strings. +// 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 @@ -189,7 +189,7 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { return nil, repository.ErrURIRoot } - return storage.ParseURI(fileSchemePrefix + parent) + return storage.NewFileURI(parent), nil } // Child implements repository.HierarchicalRepository.Child @@ -224,10 +224,7 @@ func (r *FileRepository) List(u fyne.URI) ([]fyne.URI, error) { urilist := []fyne.URI{} for _, f := range files { - uri, err := storage.ParseURI(fileSchemePrefix + filepath.Join(path, f.Name())) - if err != nil { - return nil, err - } + uri := storage.NewFileURI(filepath.Join(path, f.Name())) urilist = append(urilist, uri) } From 00c6c3fb8a2d729adde5c952feff5d82c97bcab2 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sun, 17 Jan 2021 22:43:40 +0000 Subject: [PATCH 116/145] Match select popup position --- widget/select_entry.go | 6 ++-- .../disableable_enabled_opened.xml | 28 +++++++++---------- .../select_entry/dropdown_B_opened.xml | 28 +++++++++---------- .../select_entry/dropdown_empty_opened.xml | 28 +++++++++---------- .../dropdown_empty_opened_shrunk.xml | 28 +++++++++---------- .../select_entry/dropdown_empty_setopts.xml | 28 +++++++++---------- 6 files changed, 73 insertions(+), 73 deletions(-) diff --git a/widget/select_entry.go b/widget/select_entry.go index 1a669a0f85..b73ecaeffa 100644 --- a/widget/select_entry.go +++ b/widget/select_entry.go @@ -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/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 From 80b10726f90edc180cf7195c58b5b9a0afdbcf08 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sun, 17 Jan 2021 22:46:26 +0000 Subject: [PATCH 117/145] Simplify demo so we don't need file metadata --- cmd/fyne_demo/tutorials/dialog.go | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/cmd/fyne_demo/tutorials/dialog.go b/cmd/fyne_demo/tutorials/dialog.go index 27b0b078a9..0612a784d9 100644 --- a/cmd/fyne_demo/tutorials/dialog.go +++ b/cmd/fyne_demo/tutorials/dialog.go @@ -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) { @@ -194,13 +186,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() -} From 442a50c80e29252b8d92c00609236de29f882c68 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sun, 17 Jan 2021 22:59:36 +0000 Subject: [PATCH 118/145] remove dead code --- cmd/fyne_demo/tutorials/dialog.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/cmd/fyne_demo/tutorials/dialog.go b/cmd/fyne_demo/tutorials/dialog.go index 0612a784d9..5415e6f507 100644 --- a/cmd/fyne_demo/tutorials/dialog.go +++ b/cmd/fyne_demo/tutorials/dialog.go @@ -161,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 { From d95d323bcc5d4b8f2be7cfd5df5f8071b07ad8f9 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sun, 17 Jan 2021 17:59:51 -0500 Subject: [PATCH 119/145] add fredbi/uri as the URI parser --- go.mod | 1 + go.sum | 3 ++ internal/repository/memory_test.go | 21 +++++++++++++ storage/repository/parse.go | 47 +++++++++++++++++++++++++----- storage/uri_test.go | 11 +++---- 5 files changed, 69 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index 76ff9402a4..696901eea3 100644 --- a/go.mod +++ b/go.mod @@ -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/repository/memory_test.go b/internal/repository/memory_test.go index 9d4d4907b1..d37869a782 100644 --- a/internal/repository/memory_test.go +++ b/internal/repository/memory_test.go @@ -33,6 +33,27 @@ func TestInMemoryRepositoryRegistration(t *testing.T) { 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") diff --git a/storage/repository/parse.go b/storage/repository/parse.go index f9972440a8..96a6208fc5 100644 --- a/storage/repository/parse.go +++ b/storage/repository/parse.go @@ -1,11 +1,12 @@ package repository import ( - "net/url" "path/filepath" "runtime" "strings" + uriParser "github.com/fredbi/uri" + "fyne.io/fyne" ) @@ -77,18 +78,50 @@ func ParseURI(s string) (fyne.URI, error) { } // There was no repository registered, or it did not provide a parser - l, err := url.Parse(s) + + // 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 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: l.User.String() + l.Host, + scheme: l.Scheme(), + authority: authority, // workaround for net/url, see type uri struct comments haveAuthority: true, - path: l.Path, - query: l.RawQuery, - fragment: l.Fragment, + path: l.Authority().Path(), + query: l.Query().Encode(), + fragment: l.Fragment(), }, nil } diff --git a/storage/uri_test.go b/storage/uri_test.go index 59e4cd0f21..cd73eaddda 100644 --- a/storage/uri_test.go +++ b/storage/uri_test.go @@ -47,14 +47,11 @@ func TestURIPath(t *testing.T) { // assert.Nil(t, err) // assert.Equal(t, "over/there", u.Path()) - // NOTE: this is currently broken, because net/url is not fully RFC3986 - // compliant - it returns an empty string rather than the proper 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()) + 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 a4aa5511302da040b88069e18126780b65ef4748 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sun, 17 Jan 2021 18:23:42 -0500 Subject: [PATCH 120/145] add type assertions to gomobile/repository.go --- internal/driver/gomobile/repository.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/internal/driver/gomobile/repository.go b/internal/driver/gomobile/repository.go index d68c4cccb5..38bb0bd9e5 100644 --- a/internal/driver/gomobile/repository.go +++ b/internal/driver/gomobile/repository.go @@ -6,6 +6,16 @@ import ( "fyne.io/fyne" ) +// declare conformance with repository types +var _ repository.Repository = (*mobileFileRepo)(nil) +var _ repository.HierarchicalRepository = (*mobileFileRepo)(nil) +var _ repository.CopyableRepository = (*mobileFileRepo)(nil) +var _ repository.MovableRepository = (*mobileFileRepo)(nil) +var _ repository.ListableRepository = (*mobileFileRepo)(nil) + +// TODO add write support (not yet supported on mobile) +// var _ repository.WriteableRepository = (*mobileFileRepo)(nil) + type mobileFileRepo struct { driver *mobileDriver } @@ -33,4 +43,7 @@ func (m *mobileFileRepo) List(u fyne.URI) ([]fyne.URI, error) { return listURI(u) } -// TODO add write support (not yet supported on mobile) +func (m *mobileFileRepo) CreateListable(u fyne.URI) error { + // TODO: implement this + return nil +} From c65a8978ffbc7e607065d2f83eaf26899a29243e Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sun, 17 Jan 2021 18:25:59 -0500 Subject: [PATCH 121/145] return ErrOperationNotSupported instead --- internal/driver/gomobile/repository.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/driver/gomobile/repository.go b/internal/driver/gomobile/repository.go index 38bb0bd9e5..ab86a4319a 100644 --- a/internal/driver/gomobile/repository.go +++ b/internal/driver/gomobile/repository.go @@ -4,6 +4,8 @@ package gomobile import ( "fyne.io/fyne" + + "fyne.io/fyne/storage/repository" ) // declare conformance with repository types @@ -45,5 +47,5 @@ func (m *mobileFileRepo) List(u fyne.URI) ([]fyne.URI, error) { func (m *mobileFileRepo) CreateListable(u fyne.URI) error { // TODO: implement this - return nil + return repository.ErrOperationNotSupported } From b1ed0dbd922398718ddae415fef07b0fdc23caf6 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sun, 17 Jan 2021 23:46:52 +0000 Subject: [PATCH 122/145] Mobile does not yet have all of these functions --- internal/driver/gomobile/repository.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/internal/driver/gomobile/repository.go b/internal/driver/gomobile/repository.go index ab86a4319a..b9f9c11062 100644 --- a/internal/driver/gomobile/repository.go +++ b/internal/driver/gomobile/repository.go @@ -10,9 +10,6 @@ import ( // declare conformance with repository types var _ repository.Repository = (*mobileFileRepo)(nil) -var _ repository.HierarchicalRepository = (*mobileFileRepo)(nil) -var _ repository.CopyableRepository = (*mobileFileRepo)(nil) -var _ repository.MovableRepository = (*mobileFileRepo)(nil) var _ repository.ListableRepository = (*mobileFileRepo)(nil) // TODO add write support (not yet supported on mobile) From 184d27b8a5552fa0eaf258e4ab7bb35460ee8132 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sun, 17 Jan 2021 20:42:38 -0500 Subject: [PATCH 123/145] add ForScheme --- storage/repository/parse.go | 2 +- storage/repository/repository.go | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/storage/repository/parse.go b/storage/repository/parse.go index 96a6208fc5..93ab12ee38 100644 --- a/storage/repository/parse.go +++ b/storage/repository/parse.go @@ -69,7 +69,7 @@ func ParseURI(s string) (fyne.URI, error) { return NewFileURI(path), nil } - repo, err := ForURI(&uri{scheme: scheme}) + repo, err := ForScheme(scheme) if err == nil { // If the repository registered for this scheme implements a parser if c, ok := repo.(CustomURIRepository); ok { diff --git a/storage/repository/repository.go b/storage/repository/repository.go index 33f203edc0..1476164ae8 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -243,7 +243,8 @@ func Register(scheme string, repository Repository) { } // ForURI returns the Repository instance which is registered to handle URIs of -// the given scheme. +// 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 - @@ -251,7 +252,18 @@ func Register(scheme string, repository Repository) { // // Since: 2.0.0 func ForURI(u fyne.URI) (Repository, error) { - scheme := strings.ToLower(u.Scheme()) + 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.0 +func ForScheme(scheme string) (Repository, error) { repo, ok := repositoryTable[scheme] if !ok { From 5aa3556f3a8427b235cf35375efb1e84b11f8eac Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sun, 17 Jan 2021 20:43:52 -0500 Subject: [PATCH 124/145] improve docs for NewFileRepository Co-authored-by: Stuart Scott --- internal/repository/file.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index dd2b279998..d011e2aff5 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -46,9 +46,8 @@ func (f *file) URI() fyne.URI { type FileRepository struct { } -// NewFileRepository creates a new FileRepository instance. It must be -// given the scheme it is registered for. The caller needs to call -// repository.Register() with the result of this function. +// NewFileRepository creates a new FileRepository instance. +// The caller needs to call repository.Register() with the result of this function. // // Since: 2.0.0 func NewFileRepository() *FileRepository { From cf845be9c5af83786bc20f6f823654e00b3c1ced Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sun, 17 Jan 2021 20:46:05 -0500 Subject: [PATCH 125/145] s/Writeable/Writable/g --- internal/driver/gomobile/repository.go | 2 +- internal/repository/file.go | 8 ++++---- internal/repository/memory.go | 8 ++++---- storage/repository/generic.go | 12 ++++++------ storage/repository/repository.go | 4 ++-- storage/uri.go | 10 +++++----- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/internal/driver/gomobile/repository.go b/internal/driver/gomobile/repository.go index b9f9c11062..988725b64c 100644 --- a/internal/driver/gomobile/repository.go +++ b/internal/driver/gomobile/repository.go @@ -13,7 +13,7 @@ var _ repository.Repository = (*mobileFileRepo)(nil) var _ repository.ListableRepository = (*mobileFileRepo)(nil) // TODO add write support (not yet supported on mobile) -// var _ repository.WriteableRepository = (*mobileFileRepo)(nil) +// var _ repository.WritableRepository = (*mobileFileRepo)(nil) type mobileFileRepo struct { driver *mobileDriver diff --git a/internal/repository/file.go b/internal/repository/file.go index d011e2aff5..76d93a7041 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -18,7 +18,7 @@ const fileSchemePrefix string = "file://" // declare conformance with repository types var _ repository.Repository = (*FileRepository)(nil) -var _ repository.WriteableRepository = (*FileRepository)(nil) +var _ repository.WritableRepository = (*FileRepository)(nil) var _ repository.HierarchicalRepository = (*FileRepository)(nil) var _ repository.ListableRepository = (*FileRepository)(nil) var _ repository.MovableRepository = (*FileRepository)(nil) @@ -119,14 +119,14 @@ func (r *FileRepository) Destroy(scheme string) { // do nothing } -// Writer implements repository.WriteableRepository.Writer +// Writer implements repository.WritableRepository.Writer // // Since: 2.0.0 func (r *FileRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { return openFile(u, true) } -// CanWrite implements repository.WriteableRepository.CanWrite +// CanWrite implements repository.WritableRepository.CanWrite // // Since: 2.0.0 func (r *FileRepository) CanWrite(u fyne.URI) (bool, error) { @@ -152,7 +152,7 @@ func (r *FileRepository) CanWrite(u fyne.URI) (bool, error) { return true, nil } -// Delete implements repository.WriteableRepository.Delete +// Delete implements repository.WritableRepository.Delete // // Since: 2.0.0 func (r *FileRepository) Delete(u fyne.URI) error { diff --git a/internal/repository/memory.go b/internal/repository/memory.go index 4773e23658..768d17fc9a 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -18,7 +18,7 @@ var _ fyne.URIWriteCloser = (*nodeReaderWriter)(nil) // declare conformance with repository types var _ repository.Repository = (*InMemoryRepository)(nil) -var _ repository.WriteableRepository = (*InMemoryRepository)(nil) +var _ repository.WritableRepository = (*InMemoryRepository)(nil) var _ repository.HierarchicalRepository = (*InMemoryRepository)(nil) var _ repository.CopyableRepository = (*InMemoryRepository)(nil) var _ repository.MovableRepository = (*InMemoryRepository)(nil) @@ -198,7 +198,7 @@ func (m *InMemoryRepository) Destroy(scheme string) { // do nothing } -// Writer implements repository.WriteableRepository.Writer +// Writer implements repository.WritableRepository.Writer // // Since 2.0.0 func (m *InMemoryRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { @@ -210,7 +210,7 @@ func (m *InMemoryRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { return &nodeReaderWriter{path: path, repo: m}, nil } -// CanWrite implements repository.WriteableRepository.CanWrite +// CanWrite implements repository.WritableRepository.CanWrite // // Since 2.0.0 func (m *InMemoryRepository) CanWrite(u fyne.URI) (bool, error) { @@ -221,7 +221,7 @@ func (m *InMemoryRepository) CanWrite(u fyne.URI) (bool, error) { return true, nil } -// Delete implements repository.WriteableRepository.Delete +// Delete implements repository.WritableRepository.Delete // // Since 2.0.0 func (m *InMemoryRepository) Delete(u fyne.URI) error { diff --git a/storage/repository/generic.go b/storage/repository/generic.go index 8e7442d97b..f375d1947c 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -107,7 +107,7 @@ func GenericChild(u fyne.URI, component string) (fyne.URI, error) { // contents of the source to the destination. // // For obvious reasons, the destination URI must have a registered -// WriteableRepository. +// WritableRepository. // // NOTE: this function should not be called except by an implementation of // the Repository interface - using this for unknown URIs may break. @@ -126,7 +126,7 @@ func GenericCopy(source fyne.URI, destination fyne.URI) error { } // The destination must be writeable. - destwrepo, ok := dstrepo.(WriteableRepository) + destwrepo, ok := dstrepo.(WritableRepository) if !ok { return ErrOperationNotSupported } @@ -153,7 +153,7 @@ func GenericCopy(source fyne.URI, destination fyne.URI) error { // 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 WriteableRepository.Delete. +// will be deleted using WritableRepository.Delete. // // For obvious reasons, the source and destination URIs must both be writable. // @@ -177,13 +177,13 @@ func GenericMove(source fyne.URI, destination fyne.URI) error { } // The source and destination must both be writable, since the source - // is being deleted, which requires WriteableRepository. - destwrepo, ok := dstrepo.(WriteableRepository) + // is being deleted, which requires WritableRepository. + destwrepo, ok := dstrepo.(WritableRepository) if !ok { return ErrOperationNotSupported } - srcwrepo, ok := srcrepo.(WriteableRepository) + srcwrepo, ok := srcrepo.(WritableRepository) if !ok { return ErrOperationNotSupported } diff --git a/storage/repository/repository.go b/storage/repository/repository.go index 1476164ae8..5caebea359 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -94,11 +94,11 @@ type CustomURIRepository interface { ParseURI(string) (fyne.URI, error) } -// WriteableRepository is an extension of the Repository interface which also +// 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.0 -type WriteableRepository interface { +type WritableRepository interface { Repository // Writer will be used to implement calls to storage.WriterTo() for diff --git a/storage/uri.go b/storage/uri.go index c65d12af47..3f211278cc 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -163,7 +163,7 @@ func Exists(u fyne.URI) (bool, error) { // throw an error. // // * If the scheme of the given URI does not have a registered -// WriteableRepository instance, then this method will fail with a +// WritableRepository instance, then this method will fail with a // repository.ErrOperationNotSupported. // // Delete is backed by the repository system - this function calls @@ -176,7 +176,7 @@ func Delete(u fyne.URI) error { return err } - wrepo, ok := repo.(repository.WriteableRepository) + wrepo, ok := repo.(repository.WritableRepository) if !ok { return repository.ErrOperationNotSupported } @@ -263,7 +263,7 @@ func CanRead(u fyne.URI) (bool, error) { // in some way. // // * If the scheme of the given URI does not have a registered -// WriteableRepository instance, then this method will fail with a +// WritableRepository instance, then this method will fail with a // repository.ErrOperationNotSupported. // // Writer is backed by the repository system - this function calls into a @@ -276,7 +276,7 @@ func Writer(u fyne.URI) (fyne.URIWriteCloser, error) { return nil, err } - wrepo, ok := repo.(repository.WriteableRepository) + wrepo, ok := repo.(repository.WritableRepository) if !ok { return nil, repository.ErrOperationNotSupported } @@ -304,7 +304,7 @@ func CanWrite(u fyne.URI) (bool, error) { return false, err } - wrepo, ok := repo.(repository.WriteableRepository) + wrepo, ok := repo.(repository.WritableRepository) if !ok { return false, repository.ErrOperationNotSupported } From 35ed6d4ee25ea505145b287295e9785e00aca7e4 Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sun, 17 Jan 2021 20:47:18 -0500 Subject: [PATCH 126/145] wording nit --- internal/repository/memory.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/repository/memory.go b/internal/repository/memory.go index 768d17fc9a..8e084be7a8 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -128,7 +128,7 @@ func (n *nodeReaderWriter) Write(p []byte) (int, error) { return count, nil } -// Name implements fyne.URI*Closer.URI +// Name implements fyne.URIReadCloser.URI and fyne.URIWriteCloser.URI func (n *nodeReaderWriter) URI() fyne.URI { // discarding the error because this should never fail From bafe9c8ae48d43f7c2537005d6e1498e65adbeff Mon Sep 17 00:00:00 2001 From: Charles Daniels Date: Sun, 17 Jan 2021 20:52:40 -0500 Subject: [PATCH 127/145] s/writeable/writable/g --- internal/repository/file.go | 2 +- storage/repository/generic.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index 76d93a7041..07d35056fd 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -141,7 +141,7 @@ func (r *FileRepository) CanWrite(u fyne.URI) (bool, error) { if os.IsNotExist(err) { // We may need to do extra logic to check if the - // directory is writeable, but presumably the + // directory is writable, but presumably the // IsPermission check covers this. return true, nil } diff --git a/storage/repository/generic.go b/storage/repository/generic.go index f375d1947c..f4a2aa9ffb 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -125,7 +125,7 @@ func GenericCopy(source fyne.URI, destination fyne.URI) error { return err } - // The destination must be writeable. + // The destination must be writable. destwrepo, ok := dstrepo.(WritableRepository) if !ok { return ErrOperationNotSupported From bf9593021fff6095142f6aa400c02c812e3024d2 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 18 Jan 2021 11:42:29 +0000 Subject: [PATCH 128/145] Add a background colour to the mobile menu button overlay --- internal/driver/gomobile/menubutton.go | 52 ++++++++++++++++++++++++++ internal/driver/gomobile/window.go | 4 +- 2 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 internal/driver/gomobile/menubutton.go diff --git a/internal/driver/gomobile/menubutton.go b/internal/driver/gomobile/menubutton.go new file mode 100644 index 0000000000..7ce91bdfcb --- /dev/null +++ b/internal/driver/gomobile/menubutton.go @@ -0,0 +1,52 @@ +package gomobile + +import ( + "fyne.io/fyne" + "fyne.io/fyne/canvas" + "fyne.io/fyne/theme" + "fyne.io/fyne/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/window.go b/internal/driver/gomobile/window.go index a0b6fbe185..7320ad25fc 100644 --- a/internal/driver/gomobile/window.go +++ b/internal/driver/gomobile/window.go @@ -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() } From 2546f228ec750b00c28b4809946e8c4791fb7ff4 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 18 Jan 2021 11:45:36 +0000 Subject: [PATCH 129/145] missed formatting --- internal/driver/gomobile/menubutton.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/driver/gomobile/menubutton.go b/internal/driver/gomobile/menubutton.go index 7ce91bdfcb..0fec8fec5c 100644 --- a/internal/driver/gomobile/menubutton.go +++ b/internal/driver/gomobile/menubutton.go @@ -9,7 +9,7 @@ import ( type menuButton struct { widget.BaseWidget - win *window + win *window menu *fyne.MainMenu } @@ -27,7 +27,7 @@ func (m *menuButton) CreateRenderer() fyne.WidgetRenderer { type menuButtonRenderer struct { btn *widget.Button - bg *canvas.Rectangle + bg *canvas.Rectangle } func (m *menuButtonRenderer) Destroy() { From 907fb3b7df82737935c2c77823d5a3427f1593dd Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 18 Jan 2021 11:47:36 +0000 Subject: [PATCH 130/145] Don't crash on mobile sim exit --- internal/driver/gomobile/driver.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/driver/gomobile/driver.go b/internal/driver/gomobile/driver.go index d4b0545ab2..0ba15d0221 100644 --- a/internal/driver/gomobile/driver.go +++ b/internal/driver/gomobile/driver.go @@ -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() From d405bf284f2279a26738de393aa5d9e9cf984dec Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 18 Jan 2021 12:01:54 +0000 Subject: [PATCH 131/145] Identify and fix an issue with empty directories They were marked as not listable if no child elements exist --- internal/repository/file.go | 3 ++- internal/repository/file_test.go | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/internal/repository/file.go b/internal/repository/file.go index 07d35056fd..ea9467557e 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -1,6 +1,7 @@ package repository import ( + "io" "io/ioutil" "os" "path" @@ -263,7 +264,7 @@ func (r *FileRepository) CanList(u fyne.URI) (bool, error) { f.Close() } - if err != nil { + if err != nil && err != io.EOF { return false, err } diff --git a/internal/repository/file_test.go b/internal/repository/file_test.go index 1c6c7fa1a1..f147953ccf 100644 --- a/internal/repository/file_test.go +++ b/internal/repository/file_test.go @@ -449,6 +449,12 @@ func TestFileRepositoryListing(t *testing.T) { 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) stringListing := []string{} From d3dd5fc06aefa1c13be8e562cdd6d307780fe5c3 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 18 Jan 2021 13:54:00 +0000 Subject: [PATCH 132/145] Tidying up since lines to follow documented naming --- animation.go | 14 +-- canvas.go | 4 +- canvas/animation.go | 10 +- canvas/image.go | 6 +- container/container.go | 4 +- data/binding/binding.go | 6 +- data/binding/binditems.go | 40 ++++---- data/binding/bindlists.go | 40 ++++---- data/binding/convert.go | 24 ++--- data/binding/gen.go | 26 ++--- data/binding/listbinding.go | 2 +- data/binding/mapbinding.go | 16 ++-- data/binding/preference.go | 8 +- dialog/form.go | 4 +- driver/desktop/cursor.go | 6 +- driver/desktop/mouse.go | 6 +- internal/repository/file.go | 28 +++--- internal/repository/file_test.go | 1 + internal/repository/memory.go | 30 +++--- internal/widget/scroller.go | 4 +- settings.go | 4 +- storage/repository/errors.go | 4 +- storage/repository/generic.go | 8 +- storage/repository/parse.go | 4 +- storage/repository/repository.go | 48 +++++----- storage/uri.go | 28 +++--- test/test.go | 2 +- theme.go | 14 +-- theme/icons.go | 158 +++++++++++++++---------------- theme/legacy.go | 2 +- theme/theme.go | 82 ++++++++-------- uri.go | 8 +- widget/check.go | 6 +- widget/entry.go | 10 +- widget/form.go | 2 +- widget/label.go | 6 +- widget/list.go | 2 +- widget/popup_menu.go | 2 +- widget/progressbar.go | 6 +- widget/slider.go | 6 +- 40 files changed, 341 insertions(+), 340 deletions(-) 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/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..b6ecb2c743 100644 --- a/canvas/animation.go +++ b/canvas/animation.go @@ -10,11 +10,11 @@ import ( 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/image.go b/canvas/image.go index 24bec7a4d2..7600eebdaa 100644 --- a/canvas/image.go +++ b/canvas/image.go @@ -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{ @@ -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/container/container.go b/container/container.go index 1adc9d3943..8ed76b2740 100644 --- a/container/container.go +++ b/container/container.go @@ -7,14 +7,14 @@ import ( // 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/data/binding/binding.go b/data/binding/binding.go index 4aee1c96a0..54297e4810 100644 --- a/data/binding/binding.go +++ b/data/binding/binding.go @@ -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..7c1b786a53 100644 --- a/data/binding/gen.go +++ b/data/binding/gen.go @@ -14,7 +14,7 @@ import ( 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) 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..7ac6981b10 100644 --- a/data/binding/mapbinding.go +++ b/data/binding/mapbinding.go @@ -9,7 +9,7 @@ import ( // 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..b469ca0575 100644 --- a/data/binding/preference.go +++ b/data/binding/preference.go @@ -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/dialog/form.go b/dialog/form.go index 9e149452cd..d9d9e1b9c1 100644 --- a/dialog/form.go +++ b/dialog/form.go @@ -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/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/mouse.go b/driver/desktop/mouse.go index 3e1c9b507c..1295e5c43d 100644 --- a/driver/desktop/mouse.go +++ b/driver/desktop/mouse.go @@ -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/internal/repository/file.go b/internal/repository/file.go index ea9467557e..d0243e3b0a 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -43,21 +43,21 @@ func (f *file) URI() fyne.URI { // // This repository is suitable to handle the file:// scheme. // -// Since: 2.0.0 +// 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.0 +// Since: 2.0 func NewFileRepository() *FileRepository { return &FileRepository{} } // Exists implements repository.Repository.Exists // -// Since: 2.0.0 +// Since: 2.0 func (r *FileRepository) Exists(u fyne.URI) (bool, error) { p := u.Path() @@ -87,14 +87,14 @@ func openFile(uri fyne.URI, create bool) (*file, error) { // Reader implements repository.Repository.Reader // -// Since: 2.0.0 +// 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.0 +// 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 { @@ -122,14 +122,14 @@ func (r *FileRepository) Destroy(scheme string) { // Writer implements repository.WritableRepository.Writer // -// Since: 2.0.0 +// 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.0 +// 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 { @@ -155,14 +155,14 @@ func (r *FileRepository) CanWrite(u fyne.URI) (bool, error) { // Delete implements repository.WritableRepository.Delete // -// Since: 2.0.0 +// Since: 2.0 func (r *FileRepository) Delete(u fyne.URI) error { return os.Remove(u.Path()) } // Parent implements repository.HierarchicalRepository.Parent // -// Since: 2.0.0 +// Since: 2.0 func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { s := u.String() @@ -194,7 +194,7 @@ func (r *FileRepository) Parent(u fyne.URI) (fyne.URI, error) { // Child implements repository.HierarchicalRepository.Child // -// Since: 2.0.0 +// 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) @@ -212,7 +212,7 @@ func (r *FileRepository) Child(u fyne.URI, component string) (fyne.URI, error) { // List implements repository.ListableRepository.List() // -// Since: 2.0.0 +// Since: 2.0 func (r *FileRepository) List(u fyne.URI) ([]fyne.URI, error) { path := u.Path() @@ -240,7 +240,7 @@ func (r *FileRepository) CreateListable(u fyne.URI) error { // CanList implements repository.ListableRepository.CanList() // -// Since: 2.0.0 +// Since: 2.0 func (r *FileRepository) CanList(u fyne.URI) (bool, error) { p := u.Path() info, err := os.Stat(p) @@ -278,7 +278,7 @@ func (r *FileRepository) CanList(u fyne.URI) (bool, error) { // Copy implements repository.CopyableRepository.Copy() // -// Since: 2.0.0 +// 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 @@ -289,7 +289,7 @@ func (r *FileRepository) Copy(source, destination fyne.URI) error { // Move implements repository.MovableRepository.Move() // -// Since: 2.0.0 +// 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 diff --git a/internal/repository/file_test.go b/internal/repository/file_test.go index f147953ccf..2e2e002c69 100644 --- a/internal/repository/file_test.go +++ b/internal/repository/file_test.go @@ -457,6 +457,7 @@ func TestFileRepositoryListing(t *testing.T) { 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()) diff --git a/internal/repository/memory.go b/internal/repository/memory.go index 8e084be7a8..1122ff93bb 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -50,7 +50,7 @@ type nodeReaderWriter struct { // rather to be simple and easy to read. If you need performance, look // elsewhere. // -// Since 2.0.0 +// 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 @@ -141,7 +141,7 @@ func (n *nodeReaderWriter) URI() fyne.URI { // given the scheme it is registered for. The caller needs to call // repository.Register() on the result of this function. // -// Since 2.0.0 +// Since: 2.0 func NewInMemoryRepository(scheme string) *InMemoryRepository { return &InMemoryRepository{ Data: make(map[string][]byte), @@ -151,7 +151,7 @@ func NewInMemoryRepository(scheme string) *InMemoryRepository { // Exists implements repository.Repository.Exists // -// Since 2.0.0 +// Since: 2.0 func (m *InMemoryRepository) Exists(u fyne.URI) (bool, error) { path := u.Path() if path == "" { @@ -164,7 +164,7 @@ func (m *InMemoryRepository) Exists(u fyne.URI) (bool, error) { // Reader implements repository.Repository.Reader // -// Since 2.0.0 +// Since: 2.0 func (m *InMemoryRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { path := u.Path() @@ -182,7 +182,7 @@ func (m *InMemoryRepository) Reader(u fyne.URI) (fyne.URIReadCloser, error) { // CanRead implements repository.Repository.CanRead // -// Since 2.0.0 +// Since: 2.0 func (m *InMemoryRepository) CanRead(u fyne.URI) (bool, error) { path := u.Path() if path == "" { @@ -200,7 +200,7 @@ func (m *InMemoryRepository) Destroy(scheme string) { // Writer implements repository.WritableRepository.Writer // -// Since 2.0.0 +// Since: 2.0 func (m *InMemoryRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { path := u.Path() if path == "" { @@ -212,7 +212,7 @@ func (m *InMemoryRepository) Writer(u fyne.URI) (fyne.URIWriteCloser, error) { // CanWrite implements repository.WritableRepository.CanWrite // -// Since 2.0.0 +// 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) @@ -223,7 +223,7 @@ func (m *InMemoryRepository) CanWrite(u fyne.URI) (bool, error) { // Delete implements repository.WritableRepository.Delete // -// Since 2.0.0 +// Since: 2.0 func (m *InMemoryRepository) Delete(u fyne.URI) error { path := u.Path() _, ok := m.Data[path] @@ -236,42 +236,42 @@ func (m *InMemoryRepository) Delete(u fyne.URI) error { // Parent implements repository.HierarchicalRepository.Parent // -// Since 2.0.0 +// 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.0 +// 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.0 +// 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.0 +// 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.0 +// Since: 2.0 func (m *InMemoryRepository) CanList(u fyne.URI) (bool, error) { return m.Exists(u) } // List implements repository.ListableRepository.List() // -// Since: 2.0.0 +// 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 @@ -315,7 +315,7 @@ func (m *InMemoryRepository) List(u fyne.URI) ([]fyne.URI, error) { // CreateListable impelements repository.ListableRepository.CreateListable. // -// Since: 2.0.0 +// Since: 2.0 func (m *InMemoryRepository) CreateListable(u fyne.URI) error { ex, err := m.Exists(u) if err != nil { diff --git a/internal/widget/scroller.go b/internal/widget/scroller.go index d1d484671c..1e6de4b40a 100644 --- a/internal/widget/scroller.go +++ b/internal/widget/scroller.go @@ -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/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/repository/errors.go b/storage/repository/errors.go index 3458bd43cd..734d1dc599 100644 --- a/storage/repository/errors.go +++ b/storage/repository/errors.go @@ -11,7 +11,7 @@ var ( // the underlying repository has either not implemented the relevant function, // or has explicitly returned this error. // - // Since 2.0.0 + // Since: 2.0 ErrOperationNotSupported = errors.New("operation not supported for this URI") // ErrURIRoot should be thrown by fyne.URI implementations when the caller @@ -19,6 +19,6 @@ var ( // wants to programmatically walk up a URIs parent's will know when to stop // iterating. // - // Since 2.0.0 + // 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 index f4a2aa9ffb..4e2517ef51 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -33,7 +33,7 @@ func splitNonEmpty(str, sep string) []string { // 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.0 +// Since: 2.0 func GenericParent(u fyne.URI) (fyne.URI, error) { p := u.Path() @@ -76,7 +76,7 @@ func GenericParent(u fyne.URI) (fyne.URI, error) { // 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.0 +// Since: 2.0 func GenericChild(u fyne.URI, component string) (fyne.URI, error) { // split into components and add the new one @@ -112,7 +112,7 @@ func GenericChild(u fyne.URI, component string) (fyne.URI, error) { // 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.0 +// Since: 2.0 func GenericCopy(source fyne.URI, destination fyne.URI) error { // Look up repositories for the source and destination. srcrepo, err := ForURI(source) @@ -160,7 +160,7 @@ func GenericCopy(source fyne.URI, destination fyne.URI) error { // 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.0 +// 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. diff --git a/storage/repository/parse.go b/storage/repository/parse.go index 93ab12ee38..b60489183f 100644 --- a/storage/repository/parse.go +++ b/storage/repository/parse.go @@ -14,7 +14,7 @@ import ( // 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.0 +// 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 @@ -40,7 +40,7 @@ func NewFileURI(path string) fyne.URI { // 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.0 +// Since: 2.0 func ParseURI(s string) (fyne.URI, error) { // Extract the scheme. scheme := "" diff --git a/storage/repository/repository.go b/storage/repository/repository.go index 5caebea359..e8d8d579d7 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -44,25 +44,25 @@ var repositoryTable map[string]Repository = map[string]Repository{} // package, which will automatically detect the scheme of a URI and call into // the appropriate repository. // -// Since: 2.0.0 +// 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.0 + // 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.0 + // 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.0 + // Since: 2.0 CanRead(u fyne.URI) (bool, error) // Destroy is called when the repository is un-registered from a given @@ -72,7 +72,7 @@ type Repository interface { // registered for. This may be useful for repositories that need to // handle more than one URI scheme internally. // - // Since: 2.0.0 + // Since: 2.0 Destroy(string) } @@ -85,7 +85,7 @@ type Repository interface { // with 'scheme:', or storage.ParseURI() will not be able to determine which // storage repository to delegate to for parsing. // -// Since: 2.0.0 +// Since: 2.0 type CustomURIRepository interface { Repository @@ -97,26 +97,26 @@ type CustomURIRepository interface { // 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.0 +// 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.0 + // 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.0 + // 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.0 + // Since: 2.0 Delete(u fyne.URI) error } @@ -124,34 +124,34 @@ type WritableRepository interface { // supports obtaining directory listings (generally analogous to a directory // listing) for URIs of the scheme it is registered to. // -// Since: 2.0.0 +// 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.0 + // 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.0 + // 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.0 + // 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.0 +// Since: 2.0 type HierarchicalRepository interface { Repository @@ -161,7 +161,7 @@ type HierarchicalRepository interface { // A generic implementation is provided in GenericParent(), which // is based on the RFC3986 definition of a URI parent. // - // Since: 2.0.0 + // Since: 2.0 Parent(fyne.URI) (fyne.URI, error) // Child will be used to implement calls to storage.Child() for @@ -170,14 +170,14 @@ type HierarchicalRepository interface { // A generic implementation is provided in GenericParent(), which // is based on RFC3986. // - // Since: 2.0.0 + // 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.0 +// Since: 2.0 type CopyableRepository interface { Repository @@ -194,7 +194,7 @@ type CopyableRepository interface { // repository is registered to handle. In such cases, implementations // are suggested to fail-over to GenericCopy(). // - // Since: 2.0.0 + // Since: 2.0 Copy(fyne.URI, fyne.URI) error } @@ -204,7 +204,7 @@ type CopyableRepository interface { // 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.0 +// Since: 2.0 type MovableRepository interface { Repository @@ -221,7 +221,7 @@ type MovableRepository interface { // repository is registered to handle. In such cases, implementations // are suggested to fail-over to GenericMove(). // - // Since: 2.0.0 + // Since: 2.0 Move(fyne.URI, fyne.URI) error } @@ -229,7 +229,7 @@ type MovableRepository interface { // registered scheme will use methods implemented by the relevant repository // implementation. // -// Since: 2.0.0 +// Since: 2.0 func Register(scheme string, repository Repository) { scheme = strings.ToLower(scheme) @@ -250,7 +250,7 @@ func Register(scheme string, repository Repository) { // 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.0 +// Since: 2.0 func ForURI(u fyne.URI) (Repository, error) { return ForScheme(u.Scheme()) } @@ -262,7 +262,7 @@ func ForURI(u fyne.URI) (Repository, error) { // 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.0 +// Since: 2.0 func ForScheme(scheme string) (Repository, error) { repo, ok := repositoryTable[scheme] diff --git a/storage/uri.go b/storage/uri.go index 3f211278cc..8895839176 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -30,7 +30,7 @@ func NewURI(s string) fyne.URI { // NewFileURI(), which will correctly handle back-slashes appearing in the URI // path component on Windows. // -// Since: 2.0.0 +// Since: 2.0 func ParseURI(s string) (fyne.URI, error) { return repository.ParseURI(s) } @@ -62,7 +62,7 @@ func ParseURI(s string) (fyne.URI, error) { // HierarchicalRepository instance, then this method will fail with a // repository.ErrOperationNotSupported. // -// NOTE: since 2.0.0, Parent() is backed by the repository system - this +// 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. // @@ -102,7 +102,7 @@ func Parent(u fyne.URI) (fyne.URI, error) { // HierarchicalRepository instance, then this method will fail with a // repository.ErrOperationNotSupported. // -// NOTE: since 2.0.0, Child() is backed by the repository system - this +// 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. // @@ -133,7 +133,7 @@ func Child(u fyne.URI, component string) (fyne.URI, 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 2.0.0, Exists is backed by the repository system - this function +// 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 @@ -169,7 +169,7 @@ func Exists(u fyne.URI) (bool, error) { // Delete is backed by the repository system - this function calls // into a scheme-specific implementation from a registered repository. // -// Since: 2.0.0 +// Since: 2.0 func Delete(u fyne.URI) error { repo, err := repository.ForURI(u) if err != nil { @@ -204,7 +204,7 @@ func Delete(u fyne.URI) error { // Reader is backed by the repository system - this function calls // into a scheme-specific implementation from a registered repository. // -// Since: 2.0.0 +// Since: 2.0 func Reader(u fyne.URI) (fyne.URIReadCloser, error) { repo, err := repository.ForURI(u) if err != nil { @@ -230,7 +230,7 @@ func Reader(u fyne.URI) (fyne.URIReadCloser, error) { // CanRead is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // -// Since: 2.0.0 +// Since: 2.0 func CanRead(u fyne.URI) (bool, error) { repo, err := repository.ForURI(u) if err != nil { @@ -269,7 +269,7 @@ func CanRead(u fyne.URI) (bool, error) { // Writer is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // -// Since: 2.0.0 +// Since: 2.0 func Writer(u fyne.URI) (fyne.URIWriteCloser, error) { repo, err := repository.ForURI(u) if err != nil { @@ -297,7 +297,7 @@ func Writer(u fyne.URI) (fyne.URIWriteCloser, error) { // CanWrite is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // -// Since: 2.0.0 +// Since: 2.0 func CanWrite(u fyne.URI) (bool, error) { repo, err := repository.ForURI(u) if err != nil { @@ -341,7 +341,7 @@ func CanWrite(u fyne.URI) (bool, error) { // Copy is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // -// Since: 2.0.0 +// Since: 2.0 func Copy(source fyne.URI, destination fyne.URI) error { repo, err := repository.ForURI(source) if err != nil { @@ -390,7 +390,7 @@ func Copy(source fyne.URI, destination fyne.URI) error { // Move is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // -// Since: 2.0.0 +// Since: 2.0 func Move(source fyne.URI, destination fyne.URI) error { repo, err := repository.ForURI(source) if err != nil { @@ -426,7 +426,7 @@ func Move(source fyne.URI, destination fyne.URI) error { // CanList is backed by the repository system - this function calls into a // scheme-specific implementation from a registered repository. // -// Since: 2.0.0 +// Since: 2.0 func CanList(u fyne.URI) (bool, error) { repo, err := repository.ForURI(u) if err != nil { @@ -466,7 +466,7 @@ func CanList(u fyne.URI) (bool, error) { // scheme-specific implementation from a registered repository, or fails with a // URIOperationNotSupported error. // -// Since: 2.0.0 +// Since: 2.0 func List(u fyne.URI) ([]fyne.URI, error) { repo, err := repository.ForURI(u) if err != nil { @@ -517,7 +517,7 @@ func List(u fyne.URI) ([]fyne.URI, error) { // calls into a scheme-specific implementation from a registered repository, or // fails with a URIOperationNotSupported error. // -// Since: 2.0.0 +// Since: 2.0 func CreateListable(u fyne.URI) error { repo, err := repository.ForURI(u) if err != nil { diff --git a/test/test.go b/test/test.go index 234ebdf801..c6d9e8e071 100644 --- a/test/test.go +++ b/test/test.go @@ -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/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/icons.go b/theme/icons.go index 9bf4fc02aa..6d17d2b962 100644 --- a/theme/icons.go +++ b/theme/icons.go @@ -12,397 +12,397 @@ import ( 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" ) diff --git a/theme/legacy.go b/theme/legacy.go index 16f0c22bd3..28f44cb95f 100644 --- a/theme/legacy.go +++ b/theme/legacy.go @@ -9,7 +9,7 @@ import ( // 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/theme.go b/theme/theme.go index 47b57109f2..f0cf8f035f 100644 --- a/theme/theme.go +++ b/theme/theme.go @@ -12,155 +12,155 @@ import ( 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 } @@ -369,7 +369,7 @@ func TextColor() color.Color { // DisabledColor returns the foreground color for a disabled UI element // -// Since: 2.0.0 +// Since: 2.0 func DisabledColor() color.Color { return safeColorLookup(ColorNameDisabled, currentVariant()) } @@ -383,7 +383,7 @@ func DisabledTextColor() color.Color { // ErrorColor returns the theme's error text color // -// Since 2.0.0 +// Since: 2.0 func ErrorColor() color.Color { return safeColorLookup(ColorNameError, currentVariant()) } @@ -395,7 +395,7 @@ func PlaceHolderColor() color.Color { // PressedColor returns the color used to overlap tapped features // -// Since: 2.0.0 +// Since: 2.0 func PressedColor() color.Color { return safeColorLookup(ColorNamePressed, currentVariant()) } @@ -417,7 +417,7 @@ func FocusColor() color.Color { // ForegroundColor returns the theme's standard foreground color for text and icons // -// Since: 2.0.0 +// Since: 2.0 func ForegroundColor() color.Color { return safeColorLookup(ColorNameForeground, currentVariant()) } @@ -439,7 +439,7 @@ func ShadowColor() color.Color { // 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) } @@ -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 { diff --git a/uri.go b/uri.go index eb1f3b8b66..36e5373116 100644 --- a/uri.go +++ b/uri.go @@ -61,23 +61,23 @@ type URI interface { // Fields of net/url's URL structure. Consult IETF RFC3986, section // 3.2, pp. 17. // - // Since: 2.0.0 + // Since: 2.0 Authority() string // Path should return the URI path, as defined by IETF RFC3986. // - // Since: 2.0.0 + // Since: 2.0 Path() string // Query should return the URI query, as defined by IETF RFC3986. // - // Since: 2.0.0 + // Since: 2.0 Query() string // Fragment should return the URI fragment, as defined by IETF // RFC3986. // - // Since: 2.0.0 + // Since: 2.0 Fragment() string } diff --git a/widget/check.go b/widget/check.go index 4e1fda87e8..fa8c9eaf70 100644 --- a/widget/check.go +++ b/widget/check.go @@ -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/entry.go b/widget/entry.go index d19239284b..44ce4187e1 100644 --- a/widget/entry.go +++ b/widget/entry.go @@ -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 { diff --git a/widget/form.go b/widget/form.go index e7a24c1ce3..413ce6f6f1 100644 --- a/widget/form.go +++ b/widget/form.go @@ -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/label.go b/widget/label.go index d7a873427c..053a35357c 100644 --- a/widget/label.go +++ b/widget/label.go @@ -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/list.go b/widget/list.go index 122ad9118a..b36339c7d4 100644 --- a/widget/list.go +++ b/widget/list.go @@ -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/popup_menu.go b/widget/popup_menu.go index 4e68428bd2..949ee9cc53 100644 --- a/widget/popup_menu.go +++ b/widget/popup_menu.go @@ -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/progressbar.go b/widget/progressbar.go index 0e3e9b0e29..81382fa097 100644 --- a/widget/progressbar.go +++ b/widget/progressbar.go @@ -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/slider.go b/widget/slider.go index f4588d03c1..d97434a782 100644 --- a/widget/slider.go +++ b/widget/slider.go @@ -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 { From c0dffa8c905dd925412b7a16b16f2acef0e9eef9 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 18 Jan 2021 14:23:55 +0000 Subject: [PATCH 133/145] Don't forget to refresh our animated elements --- widget/progressbarinfinite.go | 1 + 1 file changed, 1 insertion(+) diff --git a/widget/progressbarinfinite.go b/widget/progressbarinfinite.go index bb8d08a7bf..b5ca3d8133 100644 --- a/widget/progressbarinfinite.go +++ b/widget/progressbarinfinite.go @@ -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 From d79277fa2982823f5f0b7eb7894fc6c30b137b8c Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 18 Jan 2021 14:34:08 +0000 Subject: [PATCH 134/145] Proposed release notes --- CHANGELOG.md | 41 ++++++++++++++++++++++++++++++++++++----- README.md | 15 ++++++++------- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0dba88bed..27337a87ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,11 +3,11 @@ 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 * Coordinate system to float32 @@ -39,24 +39,55 @@ These changes likely break some apps, please read the - `widget.SplitContainer` (now `container.Spilt`) - `widget.Group` (replaced by `widget.Card`) - `widget.Box` (now `container.NewH/VBox`) +* 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 -* Add MouseButtonTertiary for middle mouse button events on desktop +* 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 simple x/y coordinates +* Add MouseButtonTertiary for middle mouse button events on desktop +* Add `canvas.ImageScaleFastest` for faster, less precise, scaling +* Add new `dialog.Form` that will phase out `dialog.Entry` +* 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 +* Desktop left and right mouse buttons renaming to `MouseButtonPrimary` and `MouseButtonSecondary` * Many optimisations and widget performance enhancements +* Moving to new `container.New()` and `container.NewWithoutLayout()` constructors +* 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..9e1cb0e38e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

Go API Reference - 1.4.3 release + 2.0.0 release Join us on Slack
Code 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 From 404ef84d5067992b7c7cfe46af4d19fd7905aff6 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 18 Jan 2021 15:22:39 +0000 Subject: [PATCH 135/145] Declare that we are a v2 api --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 696901eea3..07c230894f 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module fyne.io/fyne +module fyne.io/fyne/v2 go 1.12 From 3264d0ece05762f2e145dc756a5c4be2683f45a2 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 18 Jan 2021 15:56:26 +0000 Subject: [PATCH 136/145] We must use v2 in all imports now --- .travis.yml | 2 +- README.md | 14 +++++++------- app/app.go | 8 ++++---- app/app_darwin.go | 4 ++-- app/app_debug.go | 2 +- app/app_gl.go | 4 ++-- app/app_mobile.go | 4 ++-- app/app_mobile_and.go | 4 ++-- app/app_mobile_ios.go | 4 ++-- app/app_other.go | 4 ++-- app/app_release.go | 2 +- app/app_software.go | 6 +++--- app/app_standard.go | 2 +- app/app_test.go | 4 ++-- app/app_windows.go | 4 ++-- app/app_xdg.go | 4 ++-- app/preferences.go | 4 ++-- app/settings.go | 4 ++-- app/settings_desktop.go | 2 +- app/settings_desktop_test.go | 4 ++-- app/settings_test.go | 6 +++--- app/storage.go | 4 ++-- canvas/animation.go | 2 +- canvas/animation_test.go | 2 +- canvas/base.go | 4 ++-- canvas/base_internal_test.go | 2 +- canvas/circle.go | 2 +- canvas/circle_test.go | 4 ++-- canvas/gradient_test.go | 6 +++--- canvas/image.go | 4 ++-- canvas/image_test.go | 4 ++-- canvas/line.go | 2 +- canvas/line_test.go | 4 ++-- canvas/raster.go | 2 +- canvas/raster_test.go | 2 +- canvas/rectangle.go | 2 +- canvas/rectangle_test.go | 2 +- canvas/text.go | 2 +- canvas/text_test.go | 8 ++++---- cmd/fyne/commands/bundle.go | 4 ++-- cmd/fyne/commands/get.go | 2 +- cmd/fyne/commands/install.go | 4 ++-- cmd/fyne/commands/package-darwin.go | 4 ++-- cmd/fyne/commands/package-mobile.go | 8 ++++---- cmd/fyne/commands/package-unix.go | 4 ++-- cmd/fyne/commands/package-windows.go | 2 +- cmd/fyne/commands/package.go | 2 +- cmd/fyne/commands/release.go | 8 ++++---- cmd/fyne/env.go | 6 +++--- cmd/fyne/internal/mobile/build_androidapp.go | 2 +- cmd/fyne/internal/mobile/env.go | 2 +- cmd/fyne/internal/templates/bundled.go | 2 +- cmd/fyne/internal/util/file.go | 2 +- cmd/fyne/main.go | 4 ++-- cmd/fyne/vendor.go | 6 +++--- cmd/fyne/version.go | 4 ++-- cmd/fyne_demo/data/bundled-scene.go | 2 +- cmd/fyne_demo/data/gen.go | 4 ++-- cmd/fyne_demo/data/icons.go | 4 ++-- cmd/fyne_demo/main.go | 16 ++++++++-------- cmd/fyne_demo/tutorials/advanced.go | 8 ++++---- cmd/fyne_demo/tutorials/animation.go | 8 ++++---- cmd/fyne_demo/tutorials/bind.go | 8 ++++---- cmd/fyne_demo/tutorials/canvas.go | 8 ++++---- cmd/fyne_demo/tutorials/collection.go | 8 ++++---- cmd/fyne_demo/tutorials/container.go | 10 +++++----- cmd/fyne_demo/tutorials/data.go | 2 +- cmd/fyne_demo/tutorials/dialog.go | 16 ++++++++-------- cmd/fyne_demo/tutorials/icons.go | 12 ++++++------ cmd/fyne_demo/tutorials/theme.go | 4 ++-- cmd/fyne_demo/tutorials/welcome.go | 10 +++++----- cmd/fyne_demo/tutorials/widget.go | 14 +++++++------- cmd/fyne_demo/tutorials/window.go | 10 +++++----- cmd/fyne_settings/data/gen.go | 4 ++-- cmd/fyne_settings/main.go | 8 ++++---- cmd/fyne_settings/settings/appearance.go | 18 +++++++++--------- cmd/fyne_settings/settings/bundled.go | 2 +- cmd/fyne_settings/settings/scale.go | 12 ++++++------ cmd/fyne_settings/settings/scale_test.go | 8 ++++---- cmd/hello/main.go | 6 +++--- container/appTabs_test.go | 8 ++++---- container/apptabs.go | 14 +++++++------- container/apptabs_desktop_test.go | 12 ++++++------ container/apptabs_extend_test.go | 8 ++++---- container/apptabs_internal_test.go | 4 ++-- container/apptabs_mobile_test.go | 12 ++++++------ container/container.go | 2 +- container/layouts.go | 6 +++--- container/scroll.go | 4 ++-- container/split.go | 10 +++++----- container/split_test.go | 6 +++--- data/binding/binding.go | 2 +- data/binding/gen.go | 4 ++-- data/binding/mapbinding.go | 2 +- data/binding/preference.go | 2 +- data/binding/preference_test.go | 2 +- data/validation/regexp.go | 2 +- data/validation/regexp_test.go | 2 +- dialog/base.go | 14 +++++++------- dialog/base_test.go | 8 ++++---- dialog/color.go | 10 +++++----- dialog/color_button.go | 12 ++++++------ dialog/color_button_test.go | 8 ++++---- dialog/color_channel.go | 10 +++++----- dialog/color_channel_test.go | 4 ++-- dialog/color_picker.go | 14 +++++++------- dialog/color_picker_test.go | 8 ++++---- dialog/color_test.go | 6 +++--- dialog/color_wheel.go | 12 ++++++------ dialog/color_wheel_test.go | 4 ++-- dialog/confirm.go | 6 +++--- dialog/confirm_test.go | 6 +++--- dialog/entry.go | 4 ++-- dialog/file.go | 14 +++++++------- dialog/file_darwin.go | 4 ++-- dialog/file_mobile.go | 6 +++--- dialog/file_other_test.go | 4 ++-- dialog/file_test.go | 14 +++++++------- dialog/file_unix.go | 6 +++--- dialog/file_windows.go | 6 +++--- dialog/file_windows_test.go | 2 +- dialog/file_xdg.go | 4 ++-- dialog/file_xdg_test.go | 2 +- dialog/fileitem.go | 8 ++++---- dialog/fileitem_test.go | 4 ++-- dialog/folder.go | 4 ++-- dialog/folder_test.go | 10 +++++----- dialog/form.go | 10 +++++----- dialog/form_test.go | 6 +++--- dialog/information.go | 6 +++--- dialog/information_test.go | 6 +++--- dialog/progress.go | 6 +++--- dialog/progressinfinite.go | 6 +++--- dialog/progressinfinite_test.go | 8 ++++---- driver/desktop/canvas.go | 2 +- driver/desktop/driver.go | 2 +- driver/desktop/key.go | 2 +- driver/desktop/mouse.go | 2 +- driver/desktop/shortcut.go | 2 +- driver/desktop/shortcut_test.go | 2 +- driver/mobile/keyboard.go | 2 +- driver/mobile/touch.go | 2 +- driver/software/render.go | 4 ++-- driver/software/render_test.go | 10 +++++----- driver/software/softwarecanvas.go | 4 ++-- fyne.go | 6 +++--- internal/animation/animation.go | 2 +- internal/animation/animation_test.go | 2 +- internal/animation/runner.go | 2 +- internal/app/focus_manager.go | 4 ++-- internal/app/focus_manager_test.go | 10 +++++----- internal/app/theme.go | 4 ++-- internal/app/theme_test.go | 4 ++-- internal/cache/widget.go | 2 +- internal/clip.go | 2 +- internal/clip_test.go | 2 +- internal/driver/glfw/animation.go | 2 +- internal/driver/glfw/canvas.go | 18 +++++++++--------- internal/driver/glfw/canvas_other_test.go | 4 ++-- internal/driver/glfw/canvas_test.go | 10 +++++----- internal/driver/glfw/clipboard.go | 2 +- internal/driver/glfw/device.go | 2 +- internal/driver/glfw/driver.go | 12 ++++++------ internal/driver/glfw/driver_test.go | 8 ++++---- internal/driver/glfw/loop.go | 8 ++++---- internal/driver/glfw/menu.go | 2 +- internal/driver/glfw/menu_bar.go | 12 ++++++------ internal/driver/glfw/menu_bar_item.go | 12 ++++++------ internal/driver/glfw/menu_bar_test.go | 8 ++++---- internal/driver/glfw/menu_darwin.go | 2 +- internal/driver/glfw/menu_darwin_test.go | 2 +- internal/driver/glfw/menu_other.go | 2 +- internal/driver/glfw/menu_test.go | 2 +- internal/driver/glfw/scale.go | 2 +- internal/driver/glfw/scale_test.go | 4 ++-- internal/driver/glfw/window.go | 14 +++++++------- internal/driver/glfw/window_linux.go | 2 +- internal/driver/glfw/window_other.go | 2 +- internal/driver/glfw/window_test.go | 18 +++++++++--------- internal/driver/gomobile/animation.go | 2 +- internal/driver/gomobile/canvas.go | 18 +++++++++--------- internal/driver/gomobile/canvas_test.go | 16 ++++++++-------- internal/driver/gomobile/clipboard.go | 2 +- internal/driver/gomobile/clipboard_desktop.go | 2 +- internal/driver/gomobile/device.go | 4 ++-- internal/driver/gomobile/device_android.go | 2 +- internal/driver/gomobile/device_desktop.go | 2 +- internal/driver/gomobile/device_ios.go | 2 +- internal/driver/gomobile/driver.go | 16 ++++++++-------- internal/driver/gomobile/file.go | 4 ++-- internal/driver/gomobile/file_android.go | 2 +- internal/driver/gomobile/file_desktop.go | 4 ++-- internal/driver/gomobile/file_ios.go | 2 +- internal/driver/gomobile/folder.go | 2 +- internal/driver/gomobile/folder_android.go | 4 ++-- internal/driver/gomobile/folder_desktop.go | 2 +- internal/driver/gomobile/folder_ios.go | 4 ++-- internal/driver/gomobile/keyboard.go | 4 ++-- internal/driver/gomobile/menu.go | 12 ++++++------ internal/driver/gomobile/menu_test.go | 10 +++++----- internal/driver/gomobile/menubutton.go | 8 ++++---- internal/driver/gomobile/repository.go | 4 ++-- internal/driver/gomobile/window.go | 12 ++++++------ internal/driver/util.go | 4 ++-- internal/driver/util_test.go | 16 ++++++++-------- internal/overlay_stack.go | 6 +++--- internal/overlay_stack_test.go | 10 +++++----- internal/painter/draw.go | 2 +- internal/painter/font.go | 4 ++-- internal/painter/gl/capture.go | 2 +- internal/painter/gl/draw.go | 6 +++--- internal/painter/gl/draw_test.go | 4 ++-- internal/painter/gl/gl_common.go | 6 +++--- internal/painter/gl/gl_core.go | 6 +++--- internal/painter/gl/gl_es.go | 6 +++--- internal/painter/gl/gl_gomobile.go | 6 +++--- internal/painter/gl/gl_test.go | 6 +++--- internal/painter/gl/painter.go | 6 +++--- internal/painter/image.go | 6 +++--- internal/painter/image_internal_test.go | 2 +- internal/painter/image_test.go | 8 ++++---- internal/painter/software/draw.go | 8 ++++---- internal/painter/software/painter.go | 8 ++++---- internal/painter/software/painter_test.go | 16 ++++++++-------- internal/painter/svg_cache.go | 4 ++-- internal/painter/svg_cache_test.go | 4 ++-- internal/painter/vector.go | 4 ++-- internal/preferences.go | 2 +- internal/repository/file.go | 6 +++--- internal/repository/file_test.go | 4 ++-- internal/repository/memory.go | 6 +++--- internal/repository/memory_test.go | 4 ++-- internal/scale.go | 2 +- internal/test/util_test.go | 4 ++-- internal/widget/base.go | 6 +++--- internal/widget/base_renderer.go | 2 +- internal/widget/overlay_container.go | 4 ++-- internal/widget/scroller.go | 10 +++++----- internal/widget/scroller_test.go | 10 +++++----- internal/widget/shadow.go | 6 +++--- internal/widget/shadow_test.go | 6 +++--- internal/widget/shadowing_renderer.go | 2 +- internal/widget/shadowing_renderer_test.go | 6 +++--- layout/borderlayout.go | 4 ++-- layout/borderlayout_test.go | 10 +++++----- layout/boxlayout.go | 4 ++-- layout/boxlayout_test.go | 8 ++++---- layout/centerlayout.go | 2 +- layout/centerlayout_test.go | 6 +++--- layout/formlayout.go | 4 ++-- layout/formlayout_test.go | 8 ++++---- layout/gridlayout.go | 4 ++-- layout/gridlayout_test.go | 8 ++++---- layout/gridwraplayout.go | 4 ++-- layout/gridwraplayout_test.go | 8 ++++---- layout/maxlayout.go | 4 ++-- layout/maxlayout_test.go | 6 +++--- layout/paddedlayout.go | 4 ++-- layout/paddedlayout_test.go | 8 ++++---- layout/spacer.go | 2 +- storage/file.go | 2 +- storage/filter.go | 2 +- storage/filter_test.go | 4 ++-- storage/repository/generic.go | 2 +- storage/repository/parse.go | 2 +- storage/repository/repository.go | 2 +- storage/repository/uri.go | 2 +- storage/resource.go | 2 +- storage/uri.go | 4 ++-- storage/uri_root_error.go | 2 +- storage/uri_test.go | 8 ++++---- test/device.go | 2 +- test/markup_renderer.go | 10 +++++----- test/markup_renderer_test.go | 12 ++++++------ test/notification.go | 2 +- test/notification_test.go | 4 ++-- test/storage.go | 4 ++-- test/test.go | 10 +++++----- test/test_test.go | 8 ++++---- test/testapp.go | 12 ++++++------ test/testcanvas.go | 10 +++++----- test/testcanvas_test.go | 4 ++-- test/testclipboard.go | 2 +- test/testdriver.go | 12 ++++++------ test/testfile.go | 4 ++-- test/testtheme.go | 4 ++-- test/testwindow.go | 2 +- test/theme.go | 4 ++-- theme/bundled-fonts.go | 2 +- theme/bundled-icons.go | 2 +- theme/gen.go | 6 +++--- theme/icons.go | 2 +- theme/icons_test.go | 4 ++-- theme/legacy.go | 2 +- theme/legacy_test.go | 2 +- theme/theme.go | 4 ++-- theme/theme_other.go | 2 +- theme/theme_test.go | 2 +- theme/themedtestapp.go | 2 +- tools/playground/playground.go | 6 +++--- tools/playground/softwarecanvas.go | 4 ++-- widget/accordion.go | 8 ++++---- widget/accordion_internal_test.go | 6 +++--- widget/accordion_test.go | 10 +++++----- widget/button.go | 12 ++++++------ widget/button_internal_test.go | 8 ++++---- widget/button_test.go | 10 +++++----- widget/card.go | 8 ++++---- widget/card_test.go | 10 +++++----- widget/check.go | 14 +++++++------- widget/check_internal_test.go | 6 +++--- widget/check_test.go | 10 +++++----- widget/entry.go | 16 ++++++++-------- widget/entry_internal_test.go | 10 +++++----- widget/entry_password.go | 10 +++++----- widget/entry_test.go | 14 +++++++------- widget/entry_validation.go | 8 ++++---- widget/entry_validation_test.go | 10 +++++----- widget/fileicon.go | 10 +++++----- widget/fileicon_internal_test.go | 8 ++++---- widget/form.go | 10 +++++----- widget/form_extend_test.go | 2 +- widget/form_test.go | 8 ++++---- widget/hyperlink.go | 6 +++--- widget/hyperlink_test.go | 8 ++++---- widget/icon.go | 8 ++++---- widget/icon_extend_test.go | 6 +++--- widget/icon_internal_test.go | 6 +++--- widget/icon_test.go | 10 +++++----- widget/label.go | 8 ++++---- widget/label_extend_test.go | 4 ++-- widget/label_test.go | 10 +++++----- widget/list.go | 12 ++++++------ widget/list_test.go | 12 ++++++------ widget/menu.go | 10 +++++----- widget/menu_desktop_test.go | 10 +++++----- widget/menu_internal_desktop_test.go | 8 ++++---- widget/menu_internal_mobile_test.go | 4 ++-- widget/menu_internal_test.go | 4 ++-- widget/menu_item.go | 10 +++++----- widget/menu_mobile_test.go | 10 +++++----- widget/menu_test.go | 8 ++++---- widget/pool.go | 2 +- widget/pool_test.go | 4 ++-- widget/popup.go | 8 ++++---- widget/popup_menu.go | 4 ++-- widget/popup_menu_test.go | 6 +++--- widget/popup_test.go | 12 ++++++------ widget/progressbar.go | 12 ++++++------ widget/progressbar_extend_test.go | 4 ++-- widget/progressbar_test.go | 6 +++--- widget/progressbarinfinite.go | 10 +++++----- widget/progressbarinfinite_test.go | 6 +++--- widget/radio_group.go | 6 +++--- widget/radio_group_extended_test.go | 10 +++++----- widget/radio_group_internal_test.go | 10 +++++----- widget/radio_group_test.go | 8 ++++---- widget/radio_item.go | 10 +++++----- widget/radio_item_test.go | 6 +++--- widget/select.go | 8 ++++---- widget/select_entry.go | 4 ++-- widget/select_entry_test.go | 8 ++++---- widget/select_test.go | 10 +++++----- widget/separator.go | 8 ++++---- widget/slider.go | 12 ++++++------ widget/slider_extend_test.go | 4 ++-- widget/slider_test.go | 8 ++++---- widget/table.go | 10 +++++----- widget/table_desktop_test.go | 4 ++-- widget/table_test.go | 8 ++++---- widget/text.go | 10 +++++----- widget/text_benchmark_test.go | 2 +- widget/text_test.go | 8 ++++---- widget/textgrid.go | 6 +++--- widget/textgrid_test.go | 8 ++++---- widget/toolbar.go | 10 +++++----- widget/toolbar_test.go | 6 +++--- widget/tree.go | 12 ++++++------ widget/tree_internal_test.go | 10 +++++----- widget/tree_test.go | 8 ++++---- widget/widget.go | 10 +++++----- widget/widget_test.go | 8 ++++---- 382 files changed, 1158 insertions(+), 1158 deletions(-) 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/README.md b/README.md index c49d9a07eb..7661123703 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@

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

@@ -29,7 +29,7 @@ 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 @@ -62,9 +62,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() { @@ -125,7 +125,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/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/animation.go b/canvas/animation.go index b6ecb2c743..68d5112998 100644 --- a/canvas/animation.go +++ b/canvas/animation.go @@ -4,7 +4,7 @@ import ( "image/color" "time" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) const ( 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 7600eebdaa..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. 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 5415e6f507..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) { 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 f6f337cf65..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/container" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/cmd/fyne_settings/settings" + "fyne.io/fyne/v2/container" ) func main() { diff --git a/cmd/fyne_settings/settings/appearance.go b/cmd/fyne_settings/settings/appearance.go index f599c73838..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 ( 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/container/appTabs_test.go b/container/appTabs_test.go index 3a03955c39..f7e0f4cc1b 100644 --- a/container/appTabs_test.go +++ b/container/appTabs_test.go @@ -3,10 +3,10 @@ package container_test import ( "testing" - "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" "github.com/stretchr/testify/assert" ) diff --git a/container/apptabs.go b/container/apptabs.go index c21bfc8e40..9f2631e1e0 100644 --- a/container/apptabs.go +++ b/container/apptabs.go @@ -1,13 +1,13 @@ 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/widget" + "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" ) // AppTabs container is used to split your application into various different areas identified by tabs. diff --git a/container/apptabs_desktop_test.go b/container/apptabs_desktop_test.go index dbd558bf4d..8a2ed0a6bc 100644 --- a/container/apptabs_desktop_test.go +++ b/container/apptabs_desktop_test.go @@ -8,12 +8,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/container" - "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/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" ) func TestTabContainer_ApplyTheme(t *testing.T) { diff --git a/container/apptabs_extend_test.go b/container/apptabs_extend_test.go index b8f32feaa6..9f0ef06de6 100644 --- a/container/apptabs_extend_test.go +++ b/container/apptabs_extend_test.go @@ -3,10 +3,10 @@ package container 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" "github.com/stretchr/testify/require" diff --git a/container/apptabs_internal_test.go b/container/apptabs_internal_test.go index 2675a07d1a..57199b8240 100644 --- a/container/apptabs_internal_test.go +++ b/container/apptabs_internal_test.go @@ -3,8 +3,8 @@ package container import ( "testing" - "fyne.io/fyne/internal/cache" - "fyne.io/fyne/widget" + "fyne.io/fyne/v2/internal/cache" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" ) diff --git a/container/apptabs_mobile_test.go b/container/apptabs_mobile_test.go index e1f1ef4e90..8a7533d5cb 100644 --- a/container/apptabs_mobile_test.go +++ b/container/apptabs_mobile_test.go @@ -5,12 +5,12 @@ package container_test import ( "testing" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/container" - "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/test" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/container/container.go b/container/container.go index 8ed76b2740..fa4525fe61 100644 --- a/container/container.go +++ b/container/container.go @@ -2,7 +2,7 @@ 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. 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/data/binding/binding.go b/data/binding/binding.go index 54297e4810..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 ( diff --git a/data/binding/gen.go b/data/binding/gen.go index 7c1b786a53..f5040fa3eb 100644 --- a/data/binding/gen.go +++ b/data/binding/gen.go @@ -8,7 +8,7 @@ import ( "runtime" "text/template" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) const itemBindTemplate = ` @@ -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/mapbinding.go b/data/binding/mapbinding.go index 7ac6981b10..c7c400f6ff 100644 --- a/data/binding/mapbinding.go +++ b/data/binding/mapbinding.go @@ -4,7 +4,7 @@ import ( "errors" "reflect" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // DataMap is the base interface for all bindable data maps. diff --git a/data/binding/preference.go b/data/binding/preference.go index b469ca0575..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: " 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 784b26f3c1..d81c620abc 100644 --- a/dialog/file.go +++ b/dialog/file.go @@ -7,13 +7,13 @@ import ( "path/filepath" "strings" - "fyne.io/fyne" - "fyne.io/fyne/container" - "fyne.io/fyne/layout" - "fyne.io/fyne/storage" - "fyne.io/fyne/storage/repository" - "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 { 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 d9d9e1b9c1..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. 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/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/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 1295e5c43d..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 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/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 8c97dc21d1..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" ) 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 294b6860c5..4964b5c022 100644 --- a/internal/driver/glfw/driver.go +++ b/internal/driver/glfw/driver.go @@ -8,12 +8,12 @@ import ( "strings" "sync" - "fyne.io/fyne" - "fyne.io/fyne/internal/animation" - "fyne.io/fyne/internal/driver" - "fyne.io/fyne/internal/painter" - intRepo "fyne.io/fyne/internal/repository" - "fyne.io/fyne/storage/repository" + "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 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/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 75afac4f33..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" ) 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 a119386450..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" 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 0ba15d0221..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 ( diff --git a/internal/driver/gomobile/file.go b/internal/driver/gomobile/file.go index aafd8e39af..960f590890 100644 --- a/internal/driver/gomobile/file.go +++ b/internal/driver/gomobile/file.go @@ -5,8 +5,8 @@ import ( "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 { diff --git a/internal/driver/gomobile/file_android.go b/internal/driver/gomobile/file_android.go index 05bc8f03ff..5c69c8af45 100644 --- a/internal/driver/gomobile/file_android.go +++ b/internal/driver/gomobile/file_android.go @@ -18,7 +18,7 @@ import ( "os" "unsafe" - "fyne.io/fyne/storage/repository" + "fyne.io/fyne/v2/storage/repository" "github.com/fyne-io/mobile/app" ) diff --git a/internal/driver/gomobile/file_desktop.go b/internal/driver/gomobile/file_desktop.go index 7d1389694a..d8833575f2 100644 --- a/internal/driver/gomobile/file_desktop.go +++ b/internal/driver/gomobile/file_desktop.go @@ -5,8 +5,8 @@ package gomobile import ( "io" - intRepo "fyne.io/fyne/internal/repository" - "fyne.io/fyne/storage/repository" + intRepo "fyne.io/fyne/v2/internal/repository" + "fyne.io/fyne/v2/storage/repository" ) func nativeFileOpen(*fileOpen) (io.ReadCloser, error) { diff --git a/internal/driver/gomobile/file_ios.go b/internal/driver/gomobile/file_ios.go index d76d9cb2bd..21cc47697b 100644 --- a/internal/driver/gomobile/file_ios.go +++ b/internal/driver/gomobile/file_ios.go @@ -16,7 +16,7 @@ import ( "io" "unsafe" - "fyne.io/fyne/storage/repository" + "fyne.io/fyne/v2/storage/repository" ) type secureReadCloser struct { diff --git a/internal/driver/gomobile/folder.go b/internal/driver/gomobile/folder.go index 70540e58a3..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 { 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 006a98942f..6229b7a434 100644 --- a/internal/driver/gomobile/folder_desktop.go +++ b/internal/driver/gomobile/folder_desktop.go @@ -3,7 +3,7 @@ package gomobile import ( - "fyne.io/fyne" + "fyne.io/fyne/v2" ) func canListURI(fyne.URI) bool { 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 index 0fec8fec5c..330c14328c 100644 --- a/internal/driver/gomobile/menubutton.go +++ b/internal/driver/gomobile/menubutton.go @@ -1,10 +1,10 @@ package gomobile import ( - "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" ) type menuButton struct { diff --git a/internal/driver/gomobile/repository.go b/internal/driver/gomobile/repository.go index 988725b64c..4b2d33f5a6 100644 --- a/internal/driver/gomobile/repository.go +++ b/internal/driver/gomobile/repository.go @@ -3,9 +3,9 @@ package gomobile import ( - "fyne.io/fyne" + "fyne.io/fyne/v2" - "fyne.io/fyne/storage/repository" + "fyne.io/fyne/v2/storage/repository" ) // declare conformance with repository types diff --git a/internal/driver/gomobile/window.go b/internal/driver/gomobile/window.go index 7320ad25fc..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 { 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 index d0243e3b0a..8cba9fe4a9 100644 --- a/internal/repository/file.go +++ b/internal/repository/file.go @@ -8,9 +8,9 @@ import ( "path/filepath" "strings" - "fyne.io/fyne" - "fyne.io/fyne/storage" - "fyne.io/fyne/storage/repository" + "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://" diff --git a/internal/repository/file_test.go b/internal/repository/file_test.go index 2e2e002c69..bc78fbaa26 100644 --- a/internal/repository/file_test.go +++ b/internal/repository/file_test.go @@ -8,8 +8,8 @@ import ( "runtime" "testing" - "fyne.io/fyne/storage" - "fyne.io/fyne/storage/repository" + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/storage/repository" "github.com/stretchr/testify/assert" ) diff --git a/internal/repository/memory.go b/internal/repository/memory.go index 1122ff93bb..25ac22886c 100644 --- a/internal/repository/memory.go +++ b/internal/repository/memory.go @@ -1,9 +1,9 @@ package repository import ( - "fyne.io/fyne" - "fyne.io/fyne/storage" - "fyne.io/fyne/storage/repository" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/storage/repository" "fmt" "io" diff --git a/internal/repository/memory_test.go b/internal/repository/memory_test.go index d37869a782..2f3047b96b 100644 --- a/internal/repository/memory_test.go +++ b/internal/repository/memory_test.go @@ -4,8 +4,8 @@ import ( "io/ioutil" "testing" - "fyne.io/fyne/storage" - "fyne.io/fyne/storage/repository" + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/storage/repository" "github.com/stretchr/testify/assert" ) 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 1e6de4b40a..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. 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/storage/file.go b/storage/file.go index b399344aa2..42813fd8f5 100644 --- a/storage/file.go +++ b/storage/file.go @@ -4,7 +4,7 @@ package storage import ( "errors" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // OpenFileFromURI loads a file read stream from a resource identifier. 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 7fd465c3af..549d8a7657 100644 --- a/storage/filter_test.go +++ b/storage/filter_test.go @@ -3,9 +3,9 @@ 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" ) diff --git a/storage/repository/generic.go b/storage/repository/generic.go index 4e2517ef51..ebe314c5d9 100644 --- a/storage/repository/generic.go +++ b/storage/repository/generic.go @@ -4,7 +4,7 @@ import ( "io" "strings" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // splitNonEmpty works exactly like strings.Split(), but only returns non-empty diff --git a/storage/repository/parse.go b/storage/repository/parse.go index b60489183f..7939f18376 100644 --- a/storage/repository/parse.go +++ b/storage/repository/parse.go @@ -7,7 +7,7 @@ import ( uriParser "github.com/fredbi/uri" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // NewFileURI implements the back-end logic to storage.NewFileURI, which you diff --git a/storage/repository/repository.go b/storage/repository/repository.go index e8d8d579d7..530c469015 100644 --- a/storage/repository/repository.go +++ b/storage/repository/repository.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // repositoryTable stores the mapping of schemes to Repository implementations. diff --git a/storage/repository/uri.go b/storage/repository/uri.go index 46c875b4c2..c3c96eed23 100644 --- a/storage/repository/uri.go +++ b/storage/repository/uri.go @@ -7,7 +7,7 @@ import ( "strings" "unicode/utf8" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // Declare conformance with fyne.URI interface. diff --git a/storage/resource.go b/storage/resource.go index fee1e80ac1..18118efab3 100644 --- a/storage/resource.go +++ b/storage/resource.go @@ -3,7 +3,7 @@ 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. diff --git a/storage/uri.go b/storage/uri.go index 8895839176..768a59b99e 100644 --- a/storage/uri.go +++ b/storage/uri.go @@ -1,8 +1,8 @@ package storage import ( - "fyne.io/fyne" - "fyne.io/fyne/storage/repository" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/storage/repository" ) // NewFileURI creates a new URI from the given file path. diff --git a/storage/uri_root_error.go b/storage/uri_root_error.go index 75a5a2d221..d397181b31 100644 --- a/storage/uri_root_error.go +++ b/storage/uri_root_error.go @@ -1,7 +1,7 @@ package storage import ( - "fyne.io/fyne/storage/repository" + "fyne.io/fyne/v2/storage/repository" ) // URIRootError is a wrapper for repository.URIRootError diff --git a/storage/uri_test.go b/storage/uri_test.go index cd73eaddda..48c40db4f6 100644 --- a/storage/uri_test.go +++ b/storage/uri_test.go @@ -5,11 +5,11 @@ import ( "runtime" "testing" - intRepo "fyne.io/fyne/internal/repository" - "fyne.io/fyne/storage" - "fyne.io/fyne/storage/repository" + 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" ) 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 c6d9e8e071..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" 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 db0823f509..6c26e49465 100644 --- a/test/testdriver.go +++ b/test/testdriver.go @@ -5,12 +5,12 @@ import ( "log" "sync" - "fyne.io/fyne" - "fyne.io/fyne/internal/driver" - "fyne.io/fyne/internal/painter" - "fyne.io/fyne/internal/painter/software" - intRepo "fyne.io/fyne/internal/repository" - "fyne.io/fyne/storage/repository" + "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" 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/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 6d17d2b962..927913845c 100644 --- a/theme/icons.go +++ b/theme/icons.go @@ -6,7 +6,7 @@ import ( "fmt" "image/color" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) const ( 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 28f44cb95f..72aaaa17ee 100644 --- a/theme/legacy.go +++ b/theme/legacy.go @@ -3,7 +3,7 @@ package theme import ( "image/color" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) // FromLegacy returns a 2.0 Theme created from the given LegacyTheme data. 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 f0cf8f035f..69570e3dbd 100644 --- a/theme/theme.go +++ b/theme/theme.go @@ -1,12 +1,12 @@ // 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 ( diff --git a/theme/theme_other.go b/theme/theme_other.go index 753e925e32..160b807e34 100644 --- a/theme/theme_other.go +++ b/theme/theme_other.go @@ -5,7 +5,7 @@ package theme import ( "image/color" - "fyne.io/fyne" + "fyne.io/fyne/v2" ) var ( diff --git a/theme/theme_test.go b/theme/theme_test.go index b7cbdfab1e..39172f338a 100644 --- a/theme/theme_test.go +++ b/theme/theme_test.go @@ -4,7 +4,7 @@ import ( "image/color" "testing" - "fyne.io/fyne" + "fyne.io/fyne/v2" "github.com/stretchr/testify/assert" ) 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/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 fa8c9eaf70..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 { 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 44ce4187e1..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 ( 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 1bcb5d2270..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 ( diff --git a/widget/fileicon_internal_test.go b/widget/fileicon_internal_test.go index f2da8f11c1..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 diff --git a/widget/form.go b/widget/form.go index 413ce6f6f1..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 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 053a35357c..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. 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 b36339c7d4..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. 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 949ee9cc53..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. 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 81382fa097..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%%" 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 b5ca3d8133..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 ( 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 49e848ee30..37d0ebbd3c 100644 --- a/widget/select.go +++ b/widget/select.go @@ -3,10 +3,10 @@ package widget import ( "image/color" - "fyne.io/fyne" - "fyne.io/fyne/canvas" - "fyne.io/fyne/driver/desktop" - "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)" diff --git a/widget/select_entry.go b/widget/select_entry.go index b73ecaeffa..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. 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 d97434a782..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 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/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/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" ) From 61b069e3356da0d7173230233cb438125f3592a7 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 18 Jan 2021 16:13:35 +0000 Subject: [PATCH 137/145] Fixing up v2 docs for README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7661123703..8314d52748 100644 --- a/README.md +++ b/README.md @@ -29,13 +29,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@v2 + $ 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): @@ -108,7 +108,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 From 68855a6b3a5594b3d13240dddef52c45615d0cd2 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 18 Jan 2021 16:44:00 +0000 Subject: [PATCH 138/145] Note the new import as well --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27337a87ef..f08df1f8cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ More detailed release notes can be found on the [releases page](https://github.c 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 From 6f1ad3e4bd8f6611f9dc488b272706689f999a67 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 18 Jan 2021 19:28:24 +0000 Subject: [PATCH 139/145] Fix typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f08df1f8cb..741b7fba93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ The import path is now `fyne.io/fyne/v2` when you are ready to make the update. * `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) + * DraggedEvent.DraggedX and DraggedY (int, int) to DraggedEvent.Dragged (Delta) * ScrollEvent.DeltaX and DeltaY (int, int) moved to ScrollEvent.Scrolled (Delta) * Theme API update From 547e07423f9d5f811502bd98c369c17a846e0382 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 18 Jan 2021 19:33:09 +0000 Subject: [PATCH 140/145] Avoid possible crashes with some string safety --- internal/driver/gomobile/file.go | 8 ++++++++ storage/repository/parse.go | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/internal/driver/gomobile/file.go b/internal/driver/gomobile/file.go index 960f590890..8afe32e5ba 100644 --- a/internal/driver/gomobile/file.go +++ b/internal/driver/gomobile/file.go @@ -52,6 +52,10 @@ 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()) { + if uri == "" { + callback(nil, nil) + return + } f, err := fileReaderForURI(storage.NewURI(uri)) if f != nil { f.(*fileOpen).done = closer @@ -67,6 +71,10 @@ 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()) { + if uri == "" { + callback(nil, nil) + return + } f, err := listerForURI(storage.NewURI(uri)) callback(f, err) }, mobileFilter(filter)) diff --git a/storage/repository/parse.go b/storage/repository/parse.go index 7939f18376..71ae590d78 100644 --- a/storage/repository/parse.go +++ b/storage/repository/parse.go @@ -85,7 +85,7 @@ func ParseURI(s string) (fyne.URI, error) { // leading ":///" to "://". rest := strings.TrimPrefix(s, scheme+":") dummyHost := false - if rest[0:3] == "///" { + if len(rest) >= 3 && rest[0:3] == "///" { rest = "//" + "TEMP.TEMP/" + strings.TrimPrefix(rest, "///") dummyHost = true } From 45408eb6f93d2b02f0752f9b3e0b6298a6e7a5aa Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Tue, 19 Jan 2021 09:41:22 +0000 Subject: [PATCH 141/145] Add suggested changes --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 741b7fba93..0892bcadd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,7 +57,7 @@ The import path is now `fyne.io/fyne/v2` when you are ready to make the update. - 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 simple x/y coordinates +* Add fyne.Vector for managing x/y float32 coordinates * Add MouseButtonTertiary for middle mouse button events on desktop * Add `canvas.ImageScaleFastest` for faster, less precise, scaling * Add new `dialog.Form` that will phase out `dialog.Entry` @@ -71,10 +71,10 @@ The import path is now `fyne.io/fyne/v2` when you are ready to make the update. * 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 renaming 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 +* 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 From dbb2c005d42a5fe748c53830380539e6fcd7b926 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Tue, 19 Jan 2021 13:29:17 +0000 Subject: [PATCH 142/145] Add missed suggestions --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0892bcadd7..4c467796f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ The import path is now `fyne.io/fyne/v2` when you are ready to make the update. * 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 + * 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) @@ -39,7 +39,7 @@ The import path is now `fyne.io/fyne/v2` when you are ready to make the update. - `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`) * 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/ From 189c459d4d14c6015439a9b7769f4c1a753a91b7 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Wed, 20 Jan 2021 16:42:56 +0000 Subject: [PATCH 143/145] Missed 2 elements --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c467796f9..5e46023c30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ The import path is now `fyne.io/fyne/v2` when you are ready to make the update. - `widget.SplitContainer` (now `container.Spilt`) - `widget.Group` (replaced by `widget.Card`) - `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/ @@ -61,6 +62,7 @@ The import path is now `fyne.io/fyne/v2` when you are ready to make the update. * Add MouseButtonTertiary for middle mouse button events on desktop * 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 From 96d506c0fc9f687ac9cfc29acd4e02fe8fbd182c Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Fri, 22 Jan 2021 20:30:32 +0000 Subject: [PATCH 144/145] Update authors --- AUTHORS | 2 ++ 1 file changed, 2 insertions(+) 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 From 651acada684ed855fb84b3f47380c40784790e40 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Mon, 18 Jan 2021 19:58:54 +0000 Subject: [PATCH 145/145] Add doc metadata --- .godocdown.import | 1 + 1 file changed, 1 insertion(+) create mode 100644 .godocdown.import 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