mirror of
https://github.com/awatertrevi/xamarin-neo4j.git
synced 2026-09-22 09:05:29 +00:00
Pretty much finished the app
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// QueryEditorRenderer.cs
|
||||
//
|
||||
// Trevi Awater
|
||||
// 13-01-2022
|
||||
//
|
||||
// © Xamarin.Neo4j.iOS
|
||||
//
|
||||
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
using Xamarin.Neo4j.Controls;
|
||||
using Xamarin.Neo4j.iOS.CustomRenderers;
|
||||
|
||||
[assembly: ExportRenderer(typeof(QueryEditor), typeof(QueryEditorRenderer))]
|
||||
namespace Xamarin.Neo4j.iOS.CustomRenderers
|
||||
{
|
||||
public class QueryEditorRenderer : EditorRenderer
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -23,15 +23,15 @@
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>14.2</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Pocket Graph</string>
|
||||
<string>PocketGraph</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>nl.resoftware.xamarin-neo4j</string>
|
||||
<string>nl.resoftware.pocketgraph</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<string>1.0.1</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Pocket Graph</string>
|
||||
<string>PocketGraph</string>
|
||||
<key>XSAppIconAssets</key>
|
||||
<string>Assets.xcassets/AppIcon.appiconset</string>
|
||||
<key>UIAppFonts</key>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" image="logo.png" translatesAutoresizingMaskIntoConstraints="NO" id="198">
|
||||
<rect key="frame" x="87" y="384" width="240" height="128"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="240" id="623"/>
|
||||
<constraint firstAttribute="height" constant="128" id="830"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="1038"/>
|
||||
<color key="backgroundColor" red="0.19136750699999999" green="0.2006954849" blue="0.2327556908" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="198" firstAttribute="centerX" secondItem="1038" secondAttribute="centerX" id="201"/>
|
||||
<constraint firstItem="1038" firstAttribute="centerY" secondItem="198" secondAttribute="centerY" id="203"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="logo.png" width="512" height="512"/>
|
||||
</resources>
|
||||
</document>
|
||||
@@ -1,39 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6245" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="X5k-f2-b5h">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="gAE-YM-kbH">
|
||||
<objects>
|
||||
<viewController id="X5k-f2-b5h" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="Y8P-hJ-Z43"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="9ZL-r4-8FZ"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="yd7-JS-zBw">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" misplaced="YES" image="Icon-60.png" translatesAutoresizingMaskIntoConstraints="NO" id="23">
|
||||
<rect key="frame" x="270" y="270" width="60" height="60"/>
|
||||
<rect key="contentStretch" x="0.0" y="0.0" width="0.0" height="0.0"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.20392156862745098" green="0.59607843137254901" blue="0.85882352941176465" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="23" firstAttribute="centerY" secondItem="yd7-JS-zBw" secondAttribute="centerY" priority="1" id="39"/>
|
||||
<constraint firstItem="23" firstAttribute="centerX" secondItem="yd7-JS-zBw" secondAttribute="centerX" priority="1" id="41"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="XAI-xm-WK6" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="349" y="339"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="Icon-60.png" width="180" height="180"/>
|
||||
</resources>
|
||||
</document>
|
||||
BIN
Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j.iOS/Resources/logo.png
Normal file
BIN
Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j.iOS/Resources/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// ScreenSizeService.cs
|
||||
//
|
||||
// Trevi Awater
|
||||
// 13-01-2022
|
||||
//
|
||||
// © Xamarin.Neo4j.iOS
|
||||
//
|
||||
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Neo4j.iOS.Services;
|
||||
using Xamarin.Neo4j.Services;
|
||||
|
||||
[assembly: Dependency(typeof(ScreenSizeService))]
|
||||
namespace Xamarin.Neo4j.iOS.Services
|
||||
{
|
||||
public class ScreenSizeService : IScreenSizeService
|
||||
{
|
||||
public int GetScreenHeight()
|
||||
{
|
||||
return (int)UIScreen.MainScreen.Bounds.Height;
|
||||
}
|
||||
|
||||
public int GetScreenWidth()
|
||||
{
|
||||
return (int)UIScreen.MainScreen.Bounds.Width;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,8 +94,10 @@
|
||||
<MtouchLink>SdkOnly</MtouchLink>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CustomRenderers\QueryEditorRenderer.cs" />
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="AppDelegate.cs" />
|
||||
<Compile Include="Services\ScreenSizeService.cs" />
|
||||
<None Include="Entitlements.plist" />
|
||||
<None Include="Info.plist" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
@@ -119,7 +121,7 @@
|
||||
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-76x76@2x.png" />
|
||||
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-83.5@2x.png" />
|
||||
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Icon-marketing-1024x1024.png" />
|
||||
<InterfaceDefinition Include="Resources\LaunchScreen.storyboard" />
|
||||
<InterfaceDefinition Include="LaunchScreen.storyboard" />
|
||||
<ImageAsset Include="Assets.xcassets\AppIcon.appiconset\Contents.json">
|
||||
<Visible>false</Visible>
|
||||
</ImageAsset>
|
||||
@@ -143,6 +145,8 @@
|
||||
<BundleResource Include="Resources\iconize-fontawesome-brands.ttf" />
|
||||
<BundleResource Include="Resources\iconize-fontawesome-regular.ttf" />
|
||||
<BundleResource Include="Resources\iconize-fontawesome-solid.ttf" />
|
||||
<BundleResource Include="Resources\logo.png" />
|
||||
<BundleResource Include="Resources\resoftware.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -2,36 +2,4 @@
|
||||
<Application xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Xamarin.Neo4j.App">
|
||||
<Application.Resources>
|
||||
<Color x:Key="Glitter">#e4ecf5</Color>
|
||||
<Color x:Key="EbonyClay">#31333b</Color>
|
||||
|
||||
<OnPlatform x:TypeArguments="x:String" x:Key="FontAwesomeBrands">
|
||||
<On Platform="Android" Value="FontAwesome5Brands.ttf#Regular" />
|
||||
<On Platform="iOS" Value="FontAwesome5Brands-Regular" />
|
||||
</OnPlatform>
|
||||
|
||||
<OnPlatform x:TypeArguments="x:String" x:Key="FontAwesomeSolid">
|
||||
<On Platform="Android" Value="FontAwesome5Solid.ttf#Regular" />
|
||||
<On Platform="iOS" Value="FontAwesome5Free-Solid" />
|
||||
</OnPlatform>
|
||||
|
||||
<OnPlatform x:TypeArguments="x:String" x:Key="FontAwesomeRegular">
|
||||
<On Platform="Android" Value="FontAwesome5Regular.ttf#Regular" />
|
||||
<On Platform="iOS" Value="FontAwesome5Free-Regular" />
|
||||
</OnPlatform>
|
||||
|
||||
<Style TargetType="ContentPage" ApplyToDerivedTypes="True">
|
||||
<Setter Property="BackgroundColor" Value="{StaticResource Glitter}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="ListView">
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="NavigationPage">
|
||||
<Setter Property="BarBackgroundColor" Value="{StaticResource EbonyClay}"/>
|
||||
<Setter Property="BarTextColor" Value="White" />
|
||||
</Style>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
using Xamarin.Neo4j.Pages;
|
||||
using Xamarin.Neo4j.Themes;
|
||||
|
||||
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
|
||||
@@ -13,9 +14,24 @@ namespace Xamarin.Neo4j
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
SetTheme(Current.RequestedTheme);
|
||||
|
||||
MainPage = new NavigationPage(new RootPage());
|
||||
}
|
||||
|
||||
|
||||
private void SetTheme(OSAppTheme theme)
|
||||
{
|
||||
Resources = theme switch
|
||||
{
|
||||
OSAppTheme.Dark => new DarkTheme(),
|
||||
OSAppTheme.Light => new LightTheme(),
|
||||
|
||||
_ => new LightTheme()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
// Handle when your app starts
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:fonts="clr-namespace:Xamarin.Neo4j.Fonts;assembly=Xamarin.Neo4j"
|
||||
x:Class="Xamarin.Neo4j.Controls.ConnectionCell">
|
||||
<Grid Padding="15, 10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Column="0" x:Name="isActiveIndicator" Text="{x:Static fonts:FontAwesomeSolid.Circle}" FontFamily="{StaticResource FontAwesomeSolid}" VerticalOptions="Center" TextColor="#34C759" Margin="0 ,0, 7.5, 0"/>
|
||||
|
||||
<StackLayout Grid.Column="1" Spacing="2">
|
||||
<Label Text="{Binding Name}" />
|
||||
<Label Text="{Binding Host}" FontSize="Small" TextColor="{StaticResource SecondaryTextColor}" />
|
||||
</StackLayout>
|
||||
</Grid>
|
||||
</ViewCell>
|
||||
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Xamarin.Neo4j.Controls
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class ConnectionCell : ViewCell
|
||||
{
|
||||
public ConnectionCell()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
isActiveIndicator.SetBinding(VisualElement.IsVisibleProperty, new Binding(nameof(IsActive), source: this));
|
||||
}
|
||||
|
||||
#region Bindable Properties
|
||||
|
||||
public bool IsActive
|
||||
{
|
||||
get => (bool)GetValue(IsActiveProperty);
|
||||
set => SetValue(IsActiveProperty, value);
|
||||
}
|
||||
|
||||
public static BindableProperty IsActiveProperty = BindableProperty.Create("IsActive", typeof(bool),
|
||||
typeof(ConnectionCell), false, BindingMode.OneWay);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:pancakeView="clr-namespace:Xamarin.Forms.PancakeView;assembly=Xamarin.Forms.PancakeView"
|
||||
xmlns:fonts="clr-namespace:Xamarin.Neo4j.Fonts;assembly=Xamarin.Neo4j"
|
||||
x:Class="Xamarin.Neo4j.Controls.QueryBuilder">
|
||||
<pancakeView:PancakeView BackgroundColor="White" CornerRadius="2" Padding="4" Margin="16">
|
||||
<pancakeView:PancakeView CornerRadius="2">
|
||||
<pancakeView:PancakeView.Border>
|
||||
<pancakeView:Border Thickness="2" Color="#d8e5f1" />
|
||||
</pancakeView:PancakeView.Border>
|
||||
|
||||
<StackLayout Orientation="Horizontal">
|
||||
<Editor x:Name="editor" HorizontalOptions="FillAndExpand" AutoSize="TextChanges" />
|
||||
|
||||
<Button Clicked="InvokeExecuteQuery" Text="{x:Static fonts:FontAwesomeSolid.Play}" FontFamily="{StaticResource FontAwesomeSolid}" VerticalOptions="CenterAndExpand" HorizontalOptions="End" FontSize="20" Margin="0, 0, 5, 0" />
|
||||
</StackLayout>
|
||||
</pancakeView:PancakeView>
|
||||
</pancakeView:PancakeView>
|
||||
</ContentView>
|
||||
@@ -1,42 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Xamarin.Neo4j.Controls
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class QueryBuilder : ContentView
|
||||
{
|
||||
public event EventHandler ExecuteQuery;
|
||||
|
||||
public QueryBuilder()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
editor.SetBinding(Editor.TextProperty, new Binding(nameof(Query), source: this));
|
||||
}
|
||||
|
||||
#region Bindable Properties
|
||||
|
||||
public string Query
|
||||
{
|
||||
get => (string)GetValue(QueryProperty);
|
||||
set => SetValue(QueryProperty, value);
|
||||
}
|
||||
|
||||
public static BindableProperty QueryProperty = BindableProperty.Create("Query", typeof(string),
|
||||
typeof(QueryBuilder), string.Empty, BindingMode.TwoWay);
|
||||
|
||||
#endregion
|
||||
|
||||
private void InvokeExecuteQuery (object sender, EventArgs e)
|
||||
{
|
||||
ExecuteQuery?.Invoke(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// QueryEditor.cs
|
||||
//
|
||||
// Trevi Awater
|
||||
// 13-01-2022
|
||||
//
|
||||
// © Xamarin.Neo4j
|
||||
//
|
||||
|
||||
using System;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Xamarin.Neo4j.Controls
|
||||
{
|
||||
public class QueryEditor : Editor
|
||||
{
|
||||
public double MaxHeight { get; set; }
|
||||
|
||||
protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
|
||||
{
|
||||
var sizeRequest = base.OnMeasure(widthConstraint, heightConstraint);
|
||||
|
||||
var newHeight = sizeRequest.Request.Height;
|
||||
|
||||
if (newHeight > MaxHeight)
|
||||
newHeight = MaxHeight;
|
||||
|
||||
return new SizeRequest(new Size(sizeRequest.Request.Width, newHeight));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:fonts="clr-namespace:Xamarin.Neo4j.Fonts;assembly=Xamarin.Neo4j"
|
||||
x:Class="Xamarin.Neo4j.Controls.QueryResultCell">
|
||||
<StackLayout Orientation="Horizontal">
|
||||
<Label Text="{Binding Query}" />
|
||||
<Button Clicked="OpenNeovis" Text="{x:Static fonts:FontAwesomeSolid.ProjectDiagram}" FontFamily="{StaticResource FontAwesomeSolid}" VerticalOptions="CenterAndExpand" FontSize="20" Margin="0, 0, 5, 0" />
|
||||
</StackLayout>
|
||||
</ViewCell>
|
||||
@@ -1,31 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
using Xamarin.Neo4j.Models;
|
||||
using Xamarin.Neo4j.Pages;
|
||||
|
||||
namespace Xamarin.Neo4j.Controls
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class QueryResultCell : ViewCell
|
||||
{
|
||||
public QueryResult QueryResult => (QueryResult) BindingContext;
|
||||
|
||||
public QueryResultCell()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
|
||||
}
|
||||
|
||||
private async void OpenNeovis(object sender, EventArgs e)
|
||||
{
|
||||
await App.Current.MainPage.Navigation.PushAsync(new VisualizationPage(QueryResult));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:fonts="clr-namespace:Xamarin.Neo4j.Fonts;assembly=Xamarin.Neo4j"
|
||||
xmlns:pancakeView="clr-namespace:Xamarin.Forms.PancakeView;assembly=Xamarin.Forms.PancakeView"
|
||||
Margin="0, 0, 0, 25"
|
||||
x:Class="Xamarin.Neo4j.Controls.QueryResultView">
|
||||
<StackLayout Orientation="Vertical" Spacing="0">
|
||||
<pancakeView:PancakeView>
|
||||
<pancakeView:PancakeView.Border>
|
||||
<pancakeView:Border Thickness="4" Color="{StaticResource QueryTextBorder}" />
|
||||
</pancakeView:PancakeView.Border>
|
||||
<Label Text="{Binding Query}" Padding="8" HorizontalOptions="FillAndExpand" BackgroundColor="{StaticResource Extreme}" />
|
||||
</pancakeView:PancakeView>
|
||||
|
||||
<WebView x:Name="graphView" HorizontalOptions="FillAndExpand" IsVisible="{Binding CanDisplayGraph}" HeightRequest="200" />
|
||||
|
||||
<Grid BackgroundColor="{StaticResource QueryActionBar}" Padding="5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Grid.Column="0" Clicked="SaveQuery" Text="{x:Static fonts:FontAwesomeSolid.Star}" BackgroundColor="Transparent" TextColor="White" FontFamily="{StaticResource FontAwesomeSolid}" FontSize="20" />
|
||||
<Button Grid.Column="1" Clicked="OpenNeovis" Text="{x:Static fonts:FontAwesomeSolid.Expand}" BackgroundColor="Transparent" IsEnabled="{Binding CanDisplayGraph}" TextColor="White" FontFamily="{StaticResource FontAwesomeSolid}" FontSize="20 "/>
|
||||
<Button Grid.Column="2" Clicked="OpenTableView" Text="{x:Static fonts:FontAwesomeSolid.List}" BackgroundColor="Transparent" TextColor="White" FontFamily="{StaticResource FontAwesomeSolid}" FontSize="20 "/>
|
||||
<Button Grid.Column="3" Clicked="CloseResultView" Text="{x:Static fonts:FontAwesomeSolid.Times}" BackgroundColor="Transparent" TextColor="White" FontFamily="{StaticResource FontAwesomeSolid}" FontSize="20 "/>
|
||||
</Grid>
|
||||
</StackLayout>
|
||||
</ContentView>
|
||||
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Acr.UserDialogs;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
using Xamarin.Neo4j.Managers;
|
||||
using Xamarin.Neo4j.Models;
|
||||
using Xamarin.Neo4j.Pages;
|
||||
using Xamarin.Neo4j.Utilities;
|
||||
|
||||
namespace Xamarin.Neo4j.Controls
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class QueryResultView : ContentView
|
||||
{
|
||||
private QueryResult QueryResult => (QueryResult) BindingContext;
|
||||
|
||||
public event EventHandler<GenericEventArgs<QueryResult>> CloseRequested;
|
||||
|
||||
private string _neovisHtml;
|
||||
|
||||
public QueryResultView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(string propertyName = null)
|
||||
{
|
||||
base.OnPropertyChanged(propertyName);
|
||||
|
||||
if (propertyName == nameof(BindingContext))
|
||||
{
|
||||
ParseNeovisHtml();
|
||||
|
||||
graphView.Source = new HtmlWebViewSource()
|
||||
{
|
||||
Html = _neovisHtml
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseNeovisHtml()
|
||||
{
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
var resourceName = "Xamarin.Neo4j.Visualization.neovis.html";
|
||||
|
||||
using (var stream = assembly.GetManifestResourceStream(resourceName))
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
var result = reader.ReadToEnd();
|
||||
|
||||
result = result.Replace("{{host}}", QueryResult.ConnectionString.Host);
|
||||
result = result.Replace("{{port}}", QueryResult.ConnectionString.Port.ToString());
|
||||
result = result.Replace("{{database}}", QueryResult.ConnectionString.Database);
|
||||
result = result.Replace("{{username}}", QueryResult.ConnectionString.Username);
|
||||
result = result.Replace("{{password}}", QueryResult.ConnectionString.Password);
|
||||
result = result.Replace("{{encryption}}", QueryResult.ConnectionString.Encrypted ? "ENCRYPTION_ON" : "ENCRYPTION_OFF");
|
||||
result = result.Replace("{{query}}", QueryResult.Query);
|
||||
result = result.Replace("{{backgroundColor}}", App.Current.RequestedTheme == OSAppTheme.Dark ? "#292C31" : "#FFFFFF");
|
||||
|
||||
_neovisHtml = result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async void OpenNeovis(object sender, EventArgs e)
|
||||
{
|
||||
await Application.Current.MainPage.Navigation.PushAsync(new GraphPage(_neovisHtml));
|
||||
}
|
||||
|
||||
private async void SaveQuery(object sender, EventArgs e)
|
||||
{
|
||||
var queryNameResult = await UserDialogs.Instance.PromptAsync("How should the query be called?");
|
||||
|
||||
if (queryNameResult.Ok)
|
||||
{
|
||||
var query = new Query()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
QueryText = QueryResult.Query,
|
||||
Name = queryNameResult.Value,
|
||||
};
|
||||
|
||||
SavedQueryManager.AddSavedQuery(query);
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseResultView(object sender, EventArgs e)
|
||||
{
|
||||
CloseRequested?.Invoke(sender, new GenericEventArgs<QueryResult>(QueryResult));
|
||||
}
|
||||
|
||||
private async void OpenTableView(object sender, EventArgs e)
|
||||
{
|
||||
await Application.Current.MainPage.Navigation.PushAsync(new TablePage(QueryResult));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// IsActiveConnectionConverter.cs
|
||||
//
|
||||
// Trevi Awater
|
||||
// 13-01-2022
|
||||
//
|
||||
// © Xamarin.Neo4j
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Neo4j.Managers;
|
||||
using Xamarin.Neo4j.Models;
|
||||
|
||||
namespace Xamarin.Neo4j.Converters
|
||||
{
|
||||
public class IsActiveConnectionConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is Neo4jConnectionString targetConnection)
|
||||
return targetConnection.Id == ConnectionStringManager.ActiveConnectionString?.Id;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// JsonConvertConverter.cs
|
||||
//
|
||||
// Trevi Awater
|
||||
// 13-01-2022
|
||||
//
|
||||
// © Xamarin.Neo4j
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Newtonsoft.Json;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Xamarin.Neo4j.Converters
|
||||
{
|
||||
public class JsonConvertConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return JsonConvert.SerializeObject(value, Formatting.Indented);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,8 @@ namespace Xamarin.Neo4j.Managers
|
||||
{
|
||||
private const string ConnectionStringsKey = "connection_strings";
|
||||
|
||||
public static Neo4jConnectionString ActiveConnectionString { get; set; }
|
||||
|
||||
public static async Task<List<Neo4jConnectionString>> GetConnectionStrings()
|
||||
{
|
||||
var json = await SecureStorage.GetAsync(ConnectionStringsKey);
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// SavedQueryManager.cs
|
||||
//
|
||||
// Trevi Awater
|
||||
// 11-01-2022
|
||||
//
|
||||
// © Xamarin.Neo4j
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Xamarin.Essentials;
|
||||
using Xamarin.Neo4j.Models;
|
||||
|
||||
namespace Xamarin.Neo4j.Managers
|
||||
{
|
||||
public class SavedQueryManager
|
||||
{
|
||||
private const string SavedQueriesKey = "saved_queries";
|
||||
|
||||
public static List<Query> GetSavedQueries()
|
||||
{
|
||||
var json = Preferences.Get(SavedQueriesKey, null);
|
||||
|
||||
if (string.IsNullOrEmpty(json))
|
||||
return new List<Query>();
|
||||
|
||||
return JsonConvert.DeserializeObject<List<Query>>(json);
|
||||
}
|
||||
|
||||
public static void AddSavedQuery(Query query)
|
||||
{
|
||||
var savedQueries = GetSavedQueries();
|
||||
|
||||
savedQueries.Add(query);
|
||||
|
||||
SaveSavedQueries(savedQueries);
|
||||
}
|
||||
|
||||
private static void SaveSavedQueries(IEnumerable<Query> savedQueries)
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(savedQueries);
|
||||
|
||||
Preferences.Set(SavedQueriesKey, json);
|
||||
}
|
||||
|
||||
public static void DeleteSavedQuery(Query query)
|
||||
{
|
||||
var savedQueries = GetSavedQueries();
|
||||
|
||||
savedQueries = savedQueries.Where(cs => cs.Id != query.Id)
|
||||
.ToList();
|
||||
|
||||
SaveSavedQueries(savedQueries);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Models/Query.cs
Normal file
22
Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Models/Query.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// Query.cs
|
||||
//
|
||||
// Trevi Awater
|
||||
// 11-01-2022
|
||||
//
|
||||
// © Xamarin.Neo4j
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace Xamarin.Neo4j.Models
|
||||
{
|
||||
public class Query
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string QueryText { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
// © Xamarin.Neo4j
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Neo4j.Driver;
|
||||
@@ -15,16 +16,18 @@ namespace Xamarin.Neo4j.Models
|
||||
{
|
||||
public class QueryResult
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public bool Success { get; set; }
|
||||
|
||||
public bool CanDisplayGraph { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
|
||||
public string Query { get; set; }
|
||||
|
||||
public Neo4jConnectionString ConnectionString { get; set; }
|
||||
|
||||
public IEnumerable<INode> Nodes { get; set; }
|
||||
|
||||
public IEnumerable<IRelationship> Relationships { get; set; }
|
||||
public Dictionary<string, List<object>> Results { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,17 +32,9 @@
|
||||
<Entry Text="{Binding Password}" IsPassword="True" />
|
||||
</StackLayout>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Grid.Column="0" Text="Connect" Command="{Binding Commands[Connect]}" />
|
||||
<Button Grid.Column="1" Text="Test" Command="{Binding Commands[Test]}" />
|
||||
<Button Grid.Column="2" Text="Save" Command="{Binding Commands[Save]}" />
|
||||
</Grid>
|
||||
<Button Text="Connect" BackgroundColor="#2DB4A8" TextColor="White" Command="{Binding Commands[Connect]}" />
|
||||
<Button Text="Test" BackgroundColor="Orange" TextColor="White" Command="{Binding Commands[Test]}" />
|
||||
<Button Text="Save" BackgroundColor="#89972E" TextColor="White" Command="{Binding Commands[Save]}" />
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
</ContentPage.Content>
|
||||
|
||||
@@ -3,9 +3,17 @@
|
||||
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:fonts="clr-namespace:Xamarin.Neo4j.Fonts;assembly=Xamarin.Neo4j"
|
||||
xmlns:controls="clr-namespace:Xamarin.Neo4j.Controls;assembly=Xamarin.Neo4j"
|
||||
xmlns:converters="clr-namespace:Xamarin.Neo4j.Converters;assembly=Xamarin.Neo4j"
|
||||
x:Class="Xamarin.Neo4j.Pages.ConnectionsPage"
|
||||
x:Name="connectionsPage"
|
||||
Title="Connections">
|
||||
<ContentPage.Resources>
|
||||
<ResourceDictionary>
|
||||
<converters:IsActiveConnectionConverter x:Key="isActiveConnection" />
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
|
||||
<ContentPage.IconImageSource>
|
||||
<FontImageSource
|
||||
FontFamily="{StaticResource FontAwesomeSolid}"
|
||||
@@ -14,6 +22,14 @@
|
||||
</ContentPage.IconImageSource>
|
||||
|
||||
<ContentPage.ToolbarItems>
|
||||
<ToolbarItem Command="{Binding Commands[StartSession]}">
|
||||
<ToolbarItem.IconImageSource>
|
||||
<FontImageSource
|
||||
FontFamily="{StaticResource FontAwesomeSolid}"
|
||||
Glyph="{x:Static fonts:FontAwesomeSolid.Terminal}" Size="20" />
|
||||
</ToolbarItem.IconImageSource>
|
||||
</ToolbarItem>
|
||||
|
||||
<ToolbarItem Command="{Binding Commands[AddConnection]}">
|
||||
<ToolbarItem.IconImageSource>
|
||||
<FontImageSource
|
||||
@@ -24,14 +40,14 @@
|
||||
</ContentPage.ToolbarItems>
|
||||
|
||||
<ContentPage.Content>
|
||||
<ListView ItemsSource="{Binding ConnectionStrings}" ItemTapped="StartSession">
|
||||
<ListView ItemsSource="{Binding ConnectionStrings}" HasUnevenRows="True" SelectionMode="None" ItemTapped="SetActive">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextCell Text="{Binding Name}" Detail="{Binding Host}">
|
||||
<TextCell.ContextActions>
|
||||
<controls:ConnectionCell IsActive="{Binding ., Converter={StaticResource isActiveConnection}}">
|
||||
<controls:ConnectionCell.ContextActions>
|
||||
<MenuItem Text="Delete" Command="{Binding BindingContext.Commands[DeleteConnectionString], Source={x:Reference connectionsPage} }" CommandParameter="{Binding .}" IsDestructive="true" />
|
||||
</TextCell.ContextActions>
|
||||
</TextCell>
|
||||
</controls:ConnectionCell.ContextActions>
|
||||
</controls:ConnectionCell>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
using Xamarin.Neo4j.Managers;
|
||||
using Xamarin.Neo4j.Models;
|
||||
using Xamarin.Neo4j.ViewModels;
|
||||
|
||||
@@ -30,11 +31,9 @@ namespace Xamarin.Neo4j.Pages
|
||||
base.OnAppearing();
|
||||
}
|
||||
|
||||
private async void StartSession(object sender, ItemTappedEventArgs e)
|
||||
private void SetActive(object sender, ItemTappedEventArgs e)
|
||||
{
|
||||
var connectionString = (Neo4jConnectionString)e.Item;
|
||||
|
||||
await Navigation.PushAsync(new SessionPage(connectionString));
|
||||
ViewModel.SetActiveConnectionString((Neo4jConnectionString)e.Item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
Title="Graph"
|
||||
x:Class="Xamarin.Neo4j.Pages.VisualizationPage">
|
||||
x:Class="Xamarin.Neo4j.Pages.GraphPage">
|
||||
<ContentPage.Content>
|
||||
<WebView Source="{Binding Source}" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
|
||||
</ContentPage.Content>
|
||||
@@ -12,13 +12,13 @@ using Xamarin.Neo4j.ViewModels;
|
||||
namespace Xamarin.Neo4j.Pages
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class VisualizationPage : ContentPage
|
||||
public partial class GraphPage : ContentPage
|
||||
{
|
||||
public VisualizationPage(QueryResult queryResult)
|
||||
public GraphPage(string html)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
BindingContext = new VisualizationViewModel(Navigation, queryResult);
|
||||
BindingContext = new GraphViewModel(Navigation, html);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:fonts="clr-namespace:Xamarin.Neo4j.Fonts;assembly=Xamarin.Neo4j"
|
||||
Title="Queries"
|
||||
x:Name="queriesPage"
|
||||
x:Class="Xamarin.Neo4j.Pages.QueriesPage">
|
||||
<ContentPage.IconImageSource>
|
||||
<FontImageSource
|
||||
@@ -13,10 +14,16 @@
|
||||
</ContentPage.IconImageSource>
|
||||
|
||||
<ContentPage.Content>
|
||||
<StackLayout>
|
||||
<Label Text="Hello, world!"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="CenterAndExpand" />
|
||||
</StackLayout>
|
||||
<ListView ItemsSource="{Binding Queries}" ItemTapped="StartSessionWithQuery">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextCell Text="{Binding Name}" Detail="{Binding QueryText}">
|
||||
<TextCell.ContextActions>
|
||||
<MenuItem Text="Delete" Command="{Binding BindingContext.Commands[DeleteQuery], Source={x:Reference queriesPage} }" CommandParameter="{Binding .}" IsDestructive="true" />
|
||||
</TextCell.ContextActions>
|
||||
</TextCell>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
using Xamarin.Neo4j.Models;
|
||||
using Xamarin.Neo4j.ViewModels;
|
||||
|
||||
namespace Xamarin.Neo4j.Pages
|
||||
@@ -13,11 +14,25 @@ namespace Xamarin.Neo4j.Pages
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class QueriesPage : ContentPage
|
||||
{
|
||||
private QueriesViewModel ViewModel => (QueriesViewModel)BindingContext;
|
||||
|
||||
public QueriesPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
BindingContext = new QueriesViewModel(Navigation);
|
||||
}
|
||||
|
||||
protected override void OnAppearing()
|
||||
{
|
||||
ViewModel.LoadQueries();
|
||||
|
||||
base.OnAppearing();
|
||||
}
|
||||
|
||||
private void StartSessionWithQuery(object sender, ItemTappedEventArgs e)
|
||||
{
|
||||
ViewModel.StartSession((Query)e.Item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,5 +7,6 @@
|
||||
<TabbedPage.Children>
|
||||
<pages:ConnectionsPage />
|
||||
<pages:QueriesPage />
|
||||
<pages:SettingsPage />
|
||||
</TabbedPage.Children>
|
||||
</TabbedPage>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:fonts="clr-namespace:Xamarin.Neo4j.Fonts;assembly=Xamarin.Neo4j"
|
||||
xmlns:controls="clr-namespace:Xamarin.Neo4j.Controls;assembly=Xamarin.Neo4j"
|
||||
xmlns:pancakeView="clr-namespace:Xamarin.Forms.PancakeView;assembly=Xamarin.Forms.PancakeView"
|
||||
x:Class="Xamarin.Neo4j.Pages.SessionPage">
|
||||
<NavigationPage.TitleView>
|
||||
<StackLayout Spacing="0">
|
||||
@@ -24,17 +25,35 @@
|
||||
</StackLayout>
|
||||
</NavigationPage.TitleView>
|
||||
|
||||
<ContentPage.ToolbarItems>
|
||||
<ToolbarItem Command="{Binding Commands[ExecuteQuery]}">
|
||||
<ToolbarItem.IconImageSource>
|
||||
<FontImageSource
|
||||
FontFamily="{StaticResource FontAwesomeSolid}"
|
||||
Glyph="{x:Static fonts:FontAwesomeSolid.Play}" Size="20" />
|
||||
</ToolbarItem.IconImageSource>
|
||||
</ToolbarItem>
|
||||
</ContentPage.ToolbarItems>
|
||||
|
||||
<ContentPage.Content>
|
||||
<StackLayout>
|
||||
<controls:QueryBuilder ExecuteQuery="OnExecuteQuery" Query="{Binding Query}" />
|
||||
<pancakeView:PancakeView BackgroundColor="White" CornerRadius="2" Padding="4" Margin="16">
|
||||
<pancakeView:PancakeView CornerRadius="2">
|
||||
<pancakeView:PancakeView.Border>
|
||||
<pancakeView:Border Thickness="2" Color="#d8e5f1" />
|
||||
</pancakeView:PancakeView.Border>
|
||||
|
||||
<ListView ItemsSource="{Binding QueryResults}">
|
||||
<ListView.ItemTemplate>
|
||||
<controls:QueryEditor Text="{Binding Query}" MaxHeight="200" HorizontalOptions="FillAndExpand" AutoSize="TextChanges" />
|
||||
</pancakeView:PancakeView>
|
||||
</pancakeView:PancakeView>
|
||||
|
||||
<CollectionView x:Name="resultsCollection" ItemsSource="{Binding QueryResults}">
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<controls:QueryResultCell />
|
||||
<controls:QueryResultView CloseRequested="CloseResultView" />
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
</StackLayout>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
using Xamarin.Neo4j.Models;
|
||||
using Xamarin.Neo4j.Utilities;
|
||||
using Xamarin.Neo4j.ViewModels;
|
||||
|
||||
namespace Xamarin.Neo4j.Pages
|
||||
@@ -16,11 +17,16 @@ namespace Xamarin.Neo4j.Pages
|
||||
{
|
||||
private SessionViewModel ViewModel => (SessionViewModel) BindingContext;
|
||||
|
||||
public SessionPage(Neo4jConnectionString connectionString)
|
||||
public SessionPage(Neo4jConnectionString connectionString, string initialQuery = null)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
BindingContext = new SessionViewModel(Navigation, connectionString);
|
||||
BindingContext = new SessionViewModel(Navigation, connectionString, initialQuery);
|
||||
|
||||
MessagingCenter.Subscribe<SessionViewModel>(this, "ResetScroll", (sender) =>
|
||||
{
|
||||
resultsCollection.ScrollTo(0, 0, ScrollToPosition.Start, true);
|
||||
});
|
||||
}
|
||||
|
||||
private void FocusDatabasePicker(object sender, EventArgs e)
|
||||
@@ -28,9 +34,9 @@ namespace Xamarin.Neo4j.Pages
|
||||
databasePicker.Focus();
|
||||
}
|
||||
|
||||
private void OnExecuteQuery(object sender, EventArgs e)
|
||||
private void CloseResultView(object sender, GenericEventArgs<QueryResult> e)
|
||||
{
|
||||
ViewModel.ExecuteQuery();
|
||||
ViewModel.DeleteQueryResult(e.Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:fonts="clr-namespace:Xamarin.Neo4j.Fonts;assembly=Xamarin.Neo4j"
|
||||
Title="Settings"
|
||||
x:Class="Xamarin.Neo4j.Pages.SettingsPage">
|
||||
<ContentPage.IconImageSource>
|
||||
<FontImageSource
|
||||
FontFamily="{StaticResource FontAwesomeSolid}"
|
||||
Glyph="{x:Static fonts:FontAwesomeSolid.Cogs}"
|
||||
Size="20" />
|
||||
</ContentPage.IconImageSource>
|
||||
|
||||
<ContentPage.Content>
|
||||
<ScrollView>
|
||||
<StackLayout Spacing="15" Padding="25">
|
||||
<StackLayout Spacing="15" VerticalOptions="EndAndExpand">
|
||||
<Label Text="A product of" HorizontalOptions="Center" FontAttributes="Italic" FontSize="12" TextColor="{StaticResource SecondaryTextColor}" />
|
||||
<Image Source="resoftware.png" HorizontalOptions="Center" WidthRequest="100">
|
||||
<Image.GestureRecognizers>
|
||||
<TapGestureRecognizer Command="{Binding Commands[OpenReSoftwareSite]}" />
|
||||
</Image.GestureRecognizers>
|
||||
</Image>
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
using Xamarin.Neo4j.ViewModels;
|
||||
|
||||
namespace Xamarin.Neo4j.Pages
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class SettingsPage : ContentPage
|
||||
{
|
||||
public SettingsPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
BindingContext = new SettingsViewModel(Navigation);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:converters="clr-namespace:Xamarin.Neo4j.Converters;assembly=Xamarin.Neo4j"
|
||||
Title="{Binding Title}"
|
||||
x:Class="Xamarin.Neo4j.Pages.TablePage">
|
||||
<ContentPage.Resources>
|
||||
<ResourceDictionary>
|
||||
<converters:JsonConvertConverter x:Key="jsonConvert" />
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
|
||||
<ContentPage.Content>
|
||||
<CarouselView ItemsSource="{Binding Rows}" Position="{Binding Position}" HorizontalScrollBarVisibility="Never" VerticalScrollBarVisibility="Never">
|
||||
<CarouselView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<CollectionView ItemsSource="{Binding .}">
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackLayout Margin="0, 0, 0, 25" Padding="10">
|
||||
<Label Text="{Binding Key, StringFormat='{0}:'}" FontAttributes="Bold" />
|
||||
<Label Text="{Binding Value, Converter={StaticResource jsonConvert}}" FontSize="Small" />
|
||||
</StackLayout>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
</DataTemplate>
|
||||
</CarouselView.ItemTemplate>
|
||||
</CarouselView>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
using Xamarin.Neo4j.Models;
|
||||
using Xamarin.Neo4j.ViewModels;
|
||||
|
||||
namespace Xamarin.Neo4j.Pages
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class TablePage : ContentPage
|
||||
{
|
||||
public TablePage(QueryResult queryResult)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
BindingContext = new TableViewModel(Navigation, queryResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Xamarin.Neo4j.Services
|
||||
{
|
||||
public interface IScreenSizeService
|
||||
{
|
||||
int GetScreenHeight();
|
||||
|
||||
int GetScreenWidth();
|
||||
}
|
||||
}
|
||||
@@ -87,16 +87,21 @@ namespace Xamarin.Neo4j.Services
|
||||
|
||||
public async Task<QueryResult> ExecuteQuery(string query, Neo4jConnectionString connectionString)
|
||||
{
|
||||
var results = new Dictionary<string, List<object>>();
|
||||
|
||||
var canDisplayGraph = false;
|
||||
|
||||
try
|
||||
{
|
||||
var session = GraphClient.Driver.AsyncSession(d => d.WithDatabase(connectionString.Database));
|
||||
var cursor = await session.RunAsync(query);
|
||||
|
||||
var nodes = new List<INode>();
|
||||
var relationships = new List<IRelationship>();
|
||||
|
||||
while (await cursor.FetchAsync())
|
||||
{
|
||||
foreach (var key in cursor.Current.Keys)
|
||||
if (results.ContainsKey(key) == false)
|
||||
results.Add(key, new List<object>());
|
||||
|
||||
foreach (var record in cursor.Current.Values)
|
||||
{
|
||||
var value = record.Value;
|
||||
@@ -104,11 +109,16 @@ namespace Xamarin.Neo4j.Services
|
||||
switch (value)
|
||||
{
|
||||
case INode _:
|
||||
nodes.Add(value.As<INode>());
|
||||
canDisplayGraph = true;
|
||||
results[record.Key].Add(value.As<INode>());
|
||||
break;
|
||||
|
||||
case IRelationship _:
|
||||
relationships.Add(value.As<IRelationship>());
|
||||
results[record.Key].Add(value.As<IRelationship>());
|
||||
break;
|
||||
|
||||
default:
|
||||
results[record.Key].Add(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -116,11 +126,12 @@ namespace Xamarin.Neo4j.Services
|
||||
|
||||
return new QueryResult()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Success = true,
|
||||
CanDisplayGraph = canDisplayGraph,
|
||||
Query = query,
|
||||
ConnectionString = connectionString,
|
||||
Nodes = nodes,
|
||||
Relationships = relationships
|
||||
Results = results
|
||||
};
|
||||
}
|
||||
|
||||
@@ -128,6 +139,7 @@ namespace Xamarin.Neo4j.Services
|
||||
{
|
||||
return new QueryResult()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Success = false,
|
||||
Query = query,
|
||||
ConnectionString = connectionString,
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Xamarin.Neo4j.Themes.DarkTheme">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Fonts.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<Color x:Key="PageBackground">#545863</Color>
|
||||
<Color x:Key="SecondaryTextColor">#a6a7b2</Color>
|
||||
<Color x:Key="Accent">#31333b</Color>
|
||||
<Color x:Key="QueryTextBackground">Black</Color>
|
||||
<Color x:Key="QueryTextBorder">#686868</Color>
|
||||
<Color x:Key="QueryActionBar">#686868</Color>
|
||||
<Color x:Key="Extreme">Black</Color>
|
||||
|
||||
<Style TargetType="ContentPage" ApplyToDerivedTypes="True">
|
||||
<Setter Property="BackgroundColor" Value="{StaticResource PageBackground}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="ListView">
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
<Setter Property="SeparatorColor" Value="LightGray" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="NavigationPage">
|
||||
<Setter Property="BarBackgroundColor" Value="{StaticResource Accent}"/>
|
||||
<Setter Property="BarTextColor" Value="White" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="TabbedPage" ApplyToDerivedTypes="True">
|
||||
<Setter Property="BackgroundColor" Value="White"/>
|
||||
<Setter Property="BarTextColor" Value="Black"/>
|
||||
<Setter Property="SelectedTabColor" Value="White"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Editor" ApplyToDerivedTypes="True">
|
||||
<Setter Property="BackgroundColor" Value="White"/>
|
||||
<Setter Property="TextColor" Value="Black"/>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// DarkTheme_xaml.cs
|
||||
//
|
||||
// Trevi Awater
|
||||
// 14-01-2022
|
||||
//
|
||||
// © Xamarin.Neo4j
|
||||
//
|
||||
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Xamarin.Neo4j.Themes
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class DarkTheme : ResourceDictionary
|
||||
{
|
||||
public DarkTheme()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
21
Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Themes/Fonts.xaml
Normal file
21
Xamarin.Neo4j/Xamarin.Neo4j/Xamarin.Neo4j/Themes/Fonts.xaml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Xamarin.Neo4j.Themes.Fonts">
|
||||
|
||||
<OnPlatform x:TypeArguments="x:String" x:Key="FontAwesomeBrands">
|
||||
<On Platform="Android" Value="FontAwesome5Brands.ttf#Regular" />
|
||||
<On Platform="iOS" Value="FontAwesome5Brands-Regular" />
|
||||
</OnPlatform>
|
||||
|
||||
<OnPlatform x:TypeArguments="x:String" x:Key="FontAwesomeSolid">
|
||||
<On Platform="Android" Value="FontAwesome5Solid.ttf#Regular" />
|
||||
<On Platform="iOS" Value="FontAwesome5Free-Solid" />
|
||||
</OnPlatform>
|
||||
|
||||
<OnPlatform x:TypeArguments="x:String" x:Key="FontAwesomeRegular">
|
||||
<On Platform="Android" Value="FontAwesome5Regular.ttf#Regular" />
|
||||
<On Platform="iOS" Value="FontAwesome5Free-Regular" />
|
||||
</OnPlatform>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Xamarin.Neo4j.Themes
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class Fonts : ResourceDictionary
|
||||
{
|
||||
public Fonts()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Xamarin.Neo4j.Themes.LightTheme">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Fonts.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<Color x:Key="PageBackground">#e4ecf5</Color>
|
||||
<Color x:Key="SecondaryTextColor">#868a92</Color>
|
||||
<Color x:Key="Accent">#31333b</Color>
|
||||
<Color x:Key="QueryTextBackground">#e0e0e0</Color>
|
||||
<Color x:Key="QueryTextBorder">#31333b</Color>
|
||||
<Color x:Key="QueryActionBar">#31343B</Color>
|
||||
<Color x:Key="Extreme">#FFFFFF</Color>
|
||||
|
||||
<Style TargetType="ContentPage" ApplyToDerivedTypes="True">
|
||||
<Setter Property="BackgroundColor" Value="{StaticResource PageBackground}" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="ListView">
|
||||
<Setter Property="BackgroundColor" Value="Transparent" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="NavigationPage">
|
||||
<Setter Property="BarBackgroundColor" Value="{StaticResource Accent}"/>
|
||||
<Setter Property="BarTextColor" Value="White" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="TabbedPage" ApplyToDerivedTypes="True">
|
||||
<Setter Property="BackgroundColor" Value="White"/>
|
||||
<Setter Property="BarTextColor" Value="Black"/>
|
||||
<Setter Property="SelectedTabColor" Value="{StaticResource Accent}"/>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Xamarin.Neo4j.Themes
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class LightTheme : ResourceDictionary
|
||||
{
|
||||
public LightTheme()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// GenericEventArgs.cs
|
||||
//
|
||||
// Trevi Awater
|
||||
// 13-01-2022
|
||||
//
|
||||
// © Xamarin.Neo4j
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace Xamarin.Neo4j.Utilities
|
||||
{
|
||||
public class GenericEventArgs<T> : EventArgs
|
||||
{
|
||||
public T Data { get; }
|
||||
|
||||
public GenericEventArgs(T data)
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Acr.UserDialogs;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Neo4j.Annotations;
|
||||
using Xamarin.Neo4j.Managers;
|
||||
@@ -40,6 +41,18 @@ namespace Xamarin.Neo4j.ViewModels
|
||||
|
||||
LoadConnectionStrings();
|
||||
}));
|
||||
|
||||
Commands.Add("StartSession", new Command(async () =>
|
||||
{
|
||||
if (ConnectionStringManager.ActiveConnectionString == null)
|
||||
{
|
||||
await UserDialogs.Instance.AlertAsync("Please select a connection before starting a session.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await Navigation.PushAsync(new SessionPage(ConnectionStringManager.ActiveConnectionString));
|
||||
}));
|
||||
}
|
||||
|
||||
[NotifyPropertyChangedInvocator]
|
||||
@@ -53,6 +66,14 @@ namespace Xamarin.Neo4j.ViewModels
|
||||
ConnectionStrings = await ConnectionStringManager.GetConnectionStrings();
|
||||
}
|
||||
|
||||
public void SetActiveConnectionString(Neo4jConnectionString connectionString)
|
||||
{
|
||||
ConnectionStringManager.ActiveConnectionString = ConnectionStringManager.ActiveConnectionString?.Id == connectionString.Id ? null : connectionString;
|
||||
|
||||
// HACK: This causes the Converter to re-execute. This can be done much cleaner.
|
||||
LoadConnectionStrings();
|
||||
}
|
||||
|
||||
#region Bindable Properties
|
||||
|
||||
public IEnumerable<Neo4jConnectionString> ConnectionStrings
|
||||
@@ -63,7 +84,7 @@ namespace Xamarin.Neo4j.ViewModels
|
||||
{
|
||||
_connectionStrings = value;
|
||||
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(ConnectionStrings));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// VisualizationViewModel.cs
|
||||
//
|
||||
// Trevi Awater
|
||||
// 10-01-2022
|
||||
//
|
||||
// © Xamarin.Neo4j
|
||||
//
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Neo4j.Annotations;
|
||||
using Xamarin.Neo4j.Models;
|
||||
|
||||
namespace Xamarin.Neo4j.ViewModels
|
||||
{
|
||||
public class GraphViewModel : ViewModelBase, INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private HtmlWebViewSource _source;
|
||||
|
||||
public GraphViewModel(INavigation navigation, string html) : base(navigation)
|
||||
{
|
||||
Source = new HtmlWebViewSource
|
||||
{
|
||||
Html = html
|
||||
};
|
||||
}
|
||||
|
||||
[NotifyPropertyChangedInvocator]
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
#region Bindable Properties
|
||||
|
||||
public HtmlWebViewSource Source
|
||||
{
|
||||
get => _source;
|
||||
|
||||
set
|
||||
{
|
||||
_source = value;
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,15 @@
|
||||
// © Xamarin.Neo4j
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Acr.UserDialogs;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Neo4j.Annotations;
|
||||
using Xamarin.Neo4j.Managers;
|
||||
using Xamarin.Neo4j.Models;
|
||||
using Xamarin.Neo4j.Pages;
|
||||
|
||||
namespace Xamarin.Neo4j.ViewModels
|
||||
{
|
||||
@@ -18,9 +23,31 @@ namespace Xamarin.Neo4j.ViewModels
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private IEnumerable<Query> _queries;
|
||||
|
||||
public QueriesViewModel(INavigation navigation) : base(navigation)
|
||||
{
|
||||
Commands.Add("DeleteQuery", new Command((o) =>
|
||||
{
|
||||
if (!(o is Query query))
|
||||
return;
|
||||
|
||||
SavedQueryManager.DeleteSavedQuery(query);
|
||||
|
||||
LoadQueries();
|
||||
}));
|
||||
}
|
||||
|
||||
public async void StartSession(Query query)
|
||||
{
|
||||
if (ConnectionStringManager.ActiveConnectionString == null)
|
||||
{
|
||||
await UserDialogs.Instance.AlertAsync("Please select a connection before starting a session.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await Navigation.PushAsync(new SessionPage(ConnectionStringManager.ActiveConnectionString, query.QueryText));
|
||||
}
|
||||
|
||||
[NotifyPropertyChangedInvocator]
|
||||
@@ -28,5 +55,26 @@ namespace Xamarin.Neo4j.ViewModels
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
public void LoadQueries()
|
||||
{
|
||||
Queries = SavedQueryManager.GetSavedQueries();
|
||||
}
|
||||
|
||||
#region Bindable Properties
|
||||
|
||||
public IEnumerable<Query> Queries
|
||||
{
|
||||
get => _queries;
|
||||
|
||||
set
|
||||
{
|
||||
_queries = value;
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,12 @@ using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Acr.UserDialogs;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Internals;
|
||||
using Xamarin.Neo4j.Annotations;
|
||||
using Xamarin.Neo4j.Models;
|
||||
using Xamarin.Neo4j.Pages;
|
||||
using Xamarin.Neo4j.Services;
|
||||
using Xamarin.Neo4j.Utilities;
|
||||
|
||||
namespace Xamarin.Neo4j.ViewModels
|
||||
{
|
||||
@@ -29,6 +31,8 @@ namespace Xamarin.Neo4j.ViewModels
|
||||
|
||||
private readonly Neo4jService _neo4jService;
|
||||
|
||||
private readonly IScreenSizeService _screenSizeService;
|
||||
|
||||
private Database _currentDatabase;
|
||||
|
||||
private List<Database> _availableDatabases;
|
||||
@@ -39,28 +43,34 @@ namespace Xamarin.Neo4j.ViewModels
|
||||
|
||||
private string _query;
|
||||
|
||||
public SessionViewModel(INavigation navigation, Neo4jConnectionString connectionString) : base(navigation)
|
||||
public SessionViewModel(INavigation navigation, Neo4jConnectionString connectionString, string initialQuery) : base(navigation)
|
||||
{
|
||||
_connectionString = connectionString;
|
||||
|
||||
_neo4jService = DependencyService.Resolve<Neo4jService>();
|
||||
_screenSizeService = DependencyService.Resolve<IScreenSizeService>();
|
||||
|
||||
Query = initialQuery;
|
||||
QueryResults = new ObservableCollection<QueryResult>();
|
||||
|
||||
InitializeConnection(connectionString);
|
||||
}
|
||||
|
||||
public async void ExecuteQuery()
|
||||
Commands.Add("ExecuteQuery", new Command(async () =>
|
||||
{
|
||||
_connectionString.Database = CurrentDatabase.Name;
|
||||
|
||||
var result = await _neo4jService.ExecuteQuery(Query, _connectionString);
|
||||
|
||||
if (result.Success)
|
||||
QueryResults.Add(result);
|
||||
{
|
||||
QueryResults.Insert(0, result);
|
||||
|
||||
MessagingCenter.Send(this, "ResetScroll");
|
||||
}
|
||||
|
||||
else
|
||||
UserDialogs.Instance.Alert(result.ErrorMessage);
|
||||
await UserDialogs.Instance.AlertAsync(result.ErrorMessage);
|
||||
}));
|
||||
|
||||
InitializeConnection(connectionString);
|
||||
}
|
||||
|
||||
private async void InitializeConnection(Neo4jConnectionString connectionString)
|
||||
@@ -76,6 +86,13 @@ namespace Xamarin.Neo4j.ViewModels
|
||||
CurrentDatabase = AvailableDatabases.Single(ad => ad.Default);
|
||||
}
|
||||
|
||||
public void DeleteQueryResult(QueryResult queryResult)
|
||||
{
|
||||
var index = QueryResults.IndexOf(qr => qr.Id == queryResult.Id);
|
||||
|
||||
QueryResults.RemoveAt(index);
|
||||
}
|
||||
|
||||
[NotifyPropertyChangedInvocator]
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// SettingsViewModel.cs
|
||||
//
|
||||
// Trevi Awater
|
||||
// 13-01-2022
|
||||
//
|
||||
// © Xamarin.Neo4j
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Xamarin.Essentials;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Neo4j.Annotations;
|
||||
|
||||
namespace Xamarin.Neo4j.ViewModels
|
||||
{
|
||||
public class SettingsViewModel : ViewModelBase, INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public SettingsViewModel(INavigation navigation) : base(navigation)
|
||||
{
|
||||
Commands.Add("OpenReSoftwareSite", new Command(async () =>
|
||||
{
|
||||
await Launcher.OpenAsync(new Uri("https://resoftware.nl/"));
|
||||
}));
|
||||
}
|
||||
|
||||
[NotifyPropertyChangedInvocator]
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// TableViewModel.cs
|
||||
//
|
||||
// Trevi Awater
|
||||
// 13-01-2022
|
||||
//
|
||||
// © Xamarin.Neo4j
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Neo4j.Annotations;
|
||||
using Xamarin.Neo4j.Models;
|
||||
|
||||
namespace Xamarin.Neo4j.ViewModels
|
||||
{
|
||||
public class TableViewModel : ViewModelBase, INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private IEnumerable<List<KeyValuePair<string, object>>> _rows;
|
||||
|
||||
private int _position;
|
||||
|
||||
public TableViewModel(INavigation navigation, QueryResult queryResult) : base(navigation)
|
||||
{
|
||||
var headers = queryResult.Results.Keys;
|
||||
var transposed = Transpose(queryResult.Results.Select(a => a.Value.ToArray()).ToArray());
|
||||
|
||||
Rows = transposed.Select(row => row.Select((t, i) => new KeyValuePair<string, object>(headers.ElementAt(i), t)).ToList()).ToList();
|
||||
}
|
||||
|
||||
private static IEnumerable<T[]> Transpose<T>(T[][] arr)
|
||||
{
|
||||
var rowCount = arr.Length;
|
||||
var columnCount = arr[0].Length;
|
||||
var transposed = new T[columnCount][];
|
||||
|
||||
if (rowCount == columnCount)
|
||||
{
|
||||
transposed = (T[][])arr.Clone();
|
||||
|
||||
for (var i = 1; i < rowCount; i++)
|
||||
for (var j = 0; j < i; j++)
|
||||
(transposed[i][j], transposed[j][i]) = (transposed[j][i], transposed[i][j]);
|
||||
}
|
||||
|
||||
else
|
||||
for (var column = 0; column < columnCount; column++)
|
||||
{
|
||||
transposed[column] = new T[rowCount];
|
||||
|
||||
for (var row = 0; row < rowCount; row++)
|
||||
transposed[column][row] = arr[row][column];
|
||||
}
|
||||
|
||||
return transposed;
|
||||
}
|
||||
|
||||
[NotifyPropertyChangedInvocator]
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
#region Bindable Properties
|
||||
|
||||
public IEnumerable<List<KeyValuePair<string, object>>> Rows
|
||||
{
|
||||
get => _rows;
|
||||
|
||||
set
|
||||
{
|
||||
_rows = value;
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public int Position
|
||||
{
|
||||
get => _position;
|
||||
|
||||
set
|
||||
{
|
||||
_position = value;
|
||||
|
||||
OnPropertyChanged(nameof(Position));
|
||||
OnPropertyChanged(nameof(Title));
|
||||
}
|
||||
}
|
||||
|
||||
public string Title => $"{Position + 1}/{Rows.Count()}";
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
//
|
||||
// VisualizationViewModel.cs
|
||||
//
|
||||
// Trevi Awater
|
||||
// 10-01-2022
|
||||
//
|
||||
// © Xamarin.Neo4j
|
||||
//
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Neo4j.Annotations;
|
||||
using Xamarin.Neo4j.Models;
|
||||
|
||||
namespace Xamarin.Neo4j.ViewModels
|
||||
{
|
||||
public class VisualizationViewModel : ViewModelBase, INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private HtmlWebViewSource _source;
|
||||
|
||||
public VisualizationViewModel(INavigation navigation, QueryResult queryResult) : base(navigation)
|
||||
{
|
||||
ParseNeovisHtml(queryResult);
|
||||
}
|
||||
|
||||
private void ParseNeovisHtml(QueryResult queryResult)
|
||||
{
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
var resourceName = "Xamarin.Neo4j.Visualization.neovis.html";
|
||||
|
||||
using (var stream = assembly.GetManifestResourceStream(resourceName))
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
var result = reader.ReadToEnd();
|
||||
|
||||
result = result.Replace("{{host}}", queryResult.ConnectionString.Host);
|
||||
result = result.Replace("{{port}}", queryResult.ConnectionString.Port.ToString());
|
||||
result = result.Replace("{{database}}", queryResult.ConnectionString.Database);
|
||||
result = result.Replace("{{username}}", queryResult.ConnectionString.Username);
|
||||
result = result.Replace("{{password}}", queryResult.ConnectionString.Password);
|
||||
result = result.Replace("{{encryption}}", queryResult.ConnectionString.Encrypted ? "ENCRYPTION_ON" : "ENCRYPTION_OFF");
|
||||
result = result.Replace("{{query}}", queryResult.Query);
|
||||
|
||||
Source = new HtmlWebViewSource
|
||||
{
|
||||
Html = result
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[NotifyPropertyChangedInvocator]
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
#region Bindable Properties
|
||||
|
||||
public HtmlWebViewSource Source
|
||||
{
|
||||
get => _source;
|
||||
|
||||
set
|
||||
{
|
||||
_source = value;
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,41 +1,46 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<title>Neovis.js Simple Example</title>
|
||||
<title>Graph</title>
|
||||
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
font: 16pt arial;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
background-color: {{backgroundColor}};
|
||||
}
|
||||
|
||||
#viz {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
border: 1px solid lightgray;
|
||||
font: 22pt arial;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="https://cdn.neo4jlabs.com/neovis.js/v1.5.0/neovis.js"></script>
|
||||
</head>
|
||||
|
||||
<body onload="draw()">
|
||||
<div id="viz"></div>
|
||||
</body>
|
||||
|
||||
<script type="text/javascript">
|
||||
var viz;
|
||||
let viz;
|
||||
|
||||
function draw() {
|
||||
var config = {
|
||||
const config = {
|
||||
container_id: "viz",
|
||||
server_url: "bolt://{{host}}:{{port}}",
|
||||
server_user: "{{username}}",
|
||||
server_database: "{{database}}",
|
||||
server_password: "{{password}}",
|
||||
encrypted: "{{encryption}}",
|
||||
initial_cypher: "{{query}}"
|
||||
server_url: `bolt://{{host}}:{{port}}`,
|
||||
server_user: `{{username}}`,
|
||||
server_database: `{{database}}`,
|
||||
server_password: `{{password}}`,
|
||||
encrypted: `{{encryption}}`,
|
||||
initial_cypher: `{{query}}`
|
||||
};
|
||||
|
||||
viz = new NeoVis.default(config);
|
||||
viz.render();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
@@ -17,10 +18,6 @@
|
||||
<PackageReference Include="Xamarin.Forms.PancakeView" Version="2.3.0.759" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Converters" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Visualization\neovis.html" />
|
||||
<EmbeddedResource Include="Visualization\neovis.html" />
|
||||
|
||||
Reference in New Issue
Block a user