Skip to content

Commit 8433b24

Browse files
Merge pull request #758 from unoplatform/dev/mazi/mediagallery
2 parents 20e1481 + ad19c9f commit 8433b24

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2440
-0
lines changed

UI/MediaGallery/README.md

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# MediaGallery
2+
3+
## Summary
4+
5+
`MediaGallery` is a static class that allows interaction with the device's media gallery, providing methods to check access permissions and save media files.
6+
7+
## Remarks
8+
9+
This class is designed to work on iOS, Mac Catalyst and Android platforms, utilizing platform-specific implementations for its methods.
10+
11+
The API allows setting the `targetFileName`, which **should ideally be unique** - otherwise the OS will either overwrite an existing file with the same name (Android behavior), or generate a new name instead (iOS behavior).
12+
13+
## Methods
14+
15+
### CheckAccessAsync
16+
17+
```csharp
18+
public static async Task<bool> CheckAccessAsync()
19+
```
20+
21+
#### Summary
22+
23+
Checks the user's permission to access the device's gallery. Will trigger the permission request if not already granted.
24+
25+
#### Returns
26+
27+
A `Task<bool>` that completes with `true` if access is granted, and `false` otherwise.
28+
29+
### SaveAsync (Stream)
30+
31+
```csharp
32+
public static async Task SaveAsync(MediaFileType type, Stream stream, string targetFileName)
33+
```
34+
35+
#### Summary
36+
37+
Saves a media file to the device's gallery using a stream.
38+
39+
#### Parameters
40+
41+
- `MediaFileType type`: The type of the media file (e.g., image, video).
42+
- `Stream stream`: A stream representing the media file.
43+
- `string targetFileName`: The desired file name for the saved media.
44+
45+
#### Returns
46+
47+
A `Task` that completes when the save operation is finished.
48+
49+
### SaveAsync (byte array)
50+
51+
```csharp
52+
public static async Task SaveAsync(MediaFileType type, byte[] data, string targetFileName)
53+
```
54+
55+
#### Summary
56+
57+
Saves a media file to the device's gallery using a byte array.
58+
59+
#### Parameters
60+
61+
- `MediaFileType type`: The type of the media file (e.g., image, video).
62+
- `byte[] data`: A byte array representing the media file.
63+
- `string targetFileName`: The desired file name for the saved media.
64+
65+
#### Returns
66+
67+
A `Task` that completes when the save operation is finished.
68+
69+
## Permissions
70+
71+
### Android
72+
73+
If your app supports only Android 10 and newer, no manifest changes are required. If you support earlier versions of Android, add the following into your manifest:
74+
75+
```xml
76+
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
77+
```
78+
79+
### iOS & Mac Catalyst
80+
81+
If your app only supports iOS 14 and newer, update your `Info.plist` as follows:
82+
83+
```xml
84+
<key>NSPhotoLibraryAddUsageDescription</key>
85+
<string>This app needs access to the photo gallery for saving photos and videos</string>
86+
```
87+
88+
If you want to support earlier versions iOS, add the following as well:
89+
90+
```xml
91+
<key>NSPhotoLibraryUsageDescription</key>
92+
<string>This app needs access to the photo gallery for saving photos and videos</string>
93+
```
94+
95+
## Usage
96+
97+
Make sure to wrap the usage of `MediaGallery` in a `#if __ANDROID__ || __IOS__` ... `#endif` block, as the class is only available on these targets.
98+
99+
### Checking for gallery access
100+
101+
```csharp
102+
#if __ANDROID__ || __IOS__
103+
bool hasAccess = await MediaGallery.CheckAccessAsync();
104+
#endif
105+
```
106+
107+
### Saving an image to the gallery using a byte array
108+
109+
```csharp
110+
#if __ANDROID__ || __IOS__
111+
byte[] imageData = ...; // Image data
112+
await MediaGallery.SaveAsync(MediaFileType.Image, imageData, "MyImage.jpg");
113+
#endif
114+
```
115+
116+
### Saving a video to the gallery using a stream
117+
118+
```csharp
119+
#if __ANDROID__ || __IOS__
120+
using Stream videoStream = ...; // Video stream
121+
await MediaGallery.SaveAsync(MediaFileType.Video, videoStream, "MyVideo.mp4");
122+
#endif
123+
```
124+
125+
### Copying an application package file to gallery
126+
127+
```csharp
128+
#if __ANDROID__ || __IOS__
129+
if (await MediaGallery.CheckAccessAsync())
130+
{
131+
var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/UnoLogo.png", UriKind.Absolute));
132+
using var stream = await file.OpenStreamForReadAsync();
133+
await MediaGallery.SaveAsync(MediaFileType.Image, stream, "UnoLogo.png");
134+
}
135+
else
136+
{
137+
await new ContentDialog
138+
{
139+
Title = "Permission required",
140+
Content = "The app requires access to the device's gallery to save the image.",
141+
CloseButtonText = "OK",
142+
XamlRoot = XamlRoot
143+
}.ShowAsync();
144+
}
145+
#endif
146+
```

UI/MediaGallery/src/.editorconfig

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
; This file is for unifying the coding style for different editors and IDEs.
2+
; More information at http://editorconfig.org
3+
4+
# This file is the top-most EditorConfig file
5+
root = true
6+
7+
##########################################
8+
# Common Settings
9+
##########################################
10+
11+
[*]
12+
indent_style = space
13+
end_of_line = crlf
14+
trim_trailing_whitespace = true
15+
insert_final_newline = true
16+
charset = utf-8
17+
18+
##########################################
19+
# File Extension Settings
20+
##########################################
21+
22+
[*.{yml,yaml}]
23+
indent_size = 2
24+
25+
[.vsconfig]
26+
indent_size = 2
27+
end_of_line = lf
28+
29+
[*.sln]
30+
indent_style = tab
31+
indent_size = 2
32+
33+
[*.{csproj,proj,projitems,shproj}]
34+
indent_size = 2
35+
36+
[*.{json,slnf}]
37+
indent_size = 2
38+
end_of_line = lf
39+
40+
[*.{props,targets}]
41+
indent_size = 2
42+
43+
[*.xaml]
44+
indent_size = 2
45+
charset = utf-8-bom
46+
47+
[*.xml]
48+
indent_size = 2
49+
end_of_line = lf
50+
51+
[*.plist]
52+
indent_size = 2
53+
indent_style = tab
54+
end_of_line = lf
55+
56+
[*.manifest]
57+
indent_size = 2
58+
59+
[*.appxmanifest]
60+
indent_size = 2
61+
62+
[*.{json,css,webmanifest}]
63+
indent_size = 2
64+
end_of_line = lf
65+
66+
[web.config]
67+
indent_size = 2
68+
end_of_line = lf
69+
70+
[*.sh]
71+
indent_size = 2
72+
end_of_line = lf
73+
74+
[*.cs]
75+
# EOL should be normalized by Git. See https://github.com/dotnet/format/issues/1099
76+
end_of_line = unset
77+
78+
# See https://github.com/dotnet/roslyn/issues/20356#issuecomment-310143926
79+
trim_trailing_whitespace = false
80+
81+
tab_width = 4
82+
indent_size = 4
83+
84+
# Sort using and Import directives with System.* appearing first
85+
dotnet_sort_system_directives_first = true
86+
87+
# Avoid "this." and "Me." if not necessary
88+
dotnet_style_qualification_for_field = false:suggestion
89+
dotnet_style_qualification_for_property = false:suggestion
90+
dotnet_style_qualification_for_method = false:suggestion
91+
dotnet_style_qualification_for_event = false:suggestion
92+
93+
#### Naming styles ####
94+
95+
# Naming rules
96+
97+
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
98+
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
99+
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
100+
101+
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
102+
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
103+
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
104+
105+
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
106+
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
107+
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
108+
109+
# Symbol specifications
110+
111+
dotnet_naming_symbols.interface.applicable_kinds = interface
112+
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
113+
dotnet_naming_symbols.interface.required_modifiers =
114+
115+
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
116+
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
117+
dotnet_naming_symbols.types.required_modifiers =
118+
119+
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
120+
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
121+
dotnet_naming_symbols.non_field_members.required_modifiers =
122+
123+
# Naming styles
124+
125+
dotnet_naming_style.begins_with_i.required_prefix = I
126+
dotnet_naming_style.begins_with_i.required_suffix =
127+
dotnet_naming_style.begins_with_i.word_separator =
128+
dotnet_naming_style.begins_with_i.capitalization = pascal_case
129+
130+
dotnet_naming_style.pascal_case.required_prefix =
131+
dotnet_naming_style.pascal_case.required_suffix =
132+
dotnet_naming_style.pascal_case.word_separator =
133+
dotnet_naming_style.pascal_case.capitalization = pascal_case
134+
135+
dotnet_naming_style.pascal_case.required_prefix =
136+
dotnet_naming_style.pascal_case.required_suffix =
137+
dotnet_naming_style.pascal_case.word_separator =
138+
dotnet_naming_style.pascal_case.capitalization = pascal_case
139+
dotnet_style_operator_placement_when_wrapping = beginning_of_line
140+
dotnet_style_coalesce_expression = true:suggestion
141+
dotnet_style_null_propagation = true:suggestion
142+
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
143+
dotnet_style_prefer_auto_properties = true:silent
144+
dotnet_style_object_initializer = true:suggestion
145+
dotnet_style_collection_initializer = true:suggestion
146+
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
147+
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
148+
dotnet_style_prefer_conditional_expression_over_return = true:silent
149+
dotnet_style_explicit_tuple_names = true:suggestion
150+
dotnet_style_prefer_inferred_tuple_names = true:suggestion
151+
152+
csharp_indent_labels = one_less_than_current
153+
csharp_using_directive_placement = outside_namespace:silent
154+
csharp_prefer_simple_using_statement = true:suggestion
155+
csharp_prefer_braces = true:silent
156+
csharp_style_namespace_declarations = file_scoped:warning
157+
csharp_style_prefer_method_group_conversion = true:silent
158+
csharp_style_prefer_top_level_statements = true:silent
159+
csharp_style_prefer_primary_constructors = true:suggestion
160+
csharp_style_expression_bodied_methods = false:silent
161+
csharp_style_expression_bodied_constructors = false:silent
162+
csharp_style_expression_bodied_operators = false:silent
163+
csharp_style_expression_bodied_properties = true:silent
164+
csharp_style_expression_bodied_indexers = true:silent
165+
csharp_style_expression_bodied_accessors = true:silent
166+
csharp_style_expression_bodied_lambdas = true:silent
167+
csharp_style_expression_bodied_local_functions = false:silent

0 commit comments

Comments
 (0)