filter function

This commit is contained in:
iTob 2024-09-19 15:14:28 +02:00
parent d1a22778b2
commit 2314cb91d2
7 changed files with 245 additions and 145 deletions

View File

@ -1,11 +1,39 @@
using Android.App; using Android.App;
using Android.Content;
using Android.Content.PM; using Android.Content.PM;
using Android.OS; using Android.OS;
using Android.Views;
using Android.Views.InputMethods;
using Android.Widget;
namespace RBLNews.Maui namespace RBLNews.Maui
{ {
[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)] [Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
public class MainActivity : MauiAppCompatActivity public class MainActivity : MauiAppCompatActivity
{ {
public override bool DispatchTouchEvent(MotionEvent? e)
{
if (e!.Action == MotionEventActions.Down)
{
var focusedElement = CurrentFocus;
if (focusedElement is EditText editText)
{
var editTextLocation = new int[2];
editText.GetLocationOnScreen(editTextLocation);
var clearTextButtonWidth = 100;
var editTextRect = new Rect(editTextLocation[0], editTextLocation[1], editText.Width + clearTextButtonWidth, editText.Height);
var touchPosX = (int)e.RawX;
var touchPosY = (int)e.RawY;
if (!editTextRect.Contains(touchPosX, touchPosY))
{
editText.ClearFocus();
var inputService = GetSystemService(Context.InputMethodService) as InputMethodManager;
inputService?.HideSoftInputFromWindow(editText.WindowToken, 0);
}
}
}
return base.DispatchTouchEvent(e);
}
} }
} }

View File

@ -11,8 +11,8 @@
<link href="_content/RBLNews.Shared/blazor.bootstrap.css" rel="stylesheet" /> <link href="_content/RBLNews.Shared/blazor.bootstrap.css" rel="stylesheet" />
<!--<link rel="stylesheet" href="_content/RBLNews.Shared/css/bootstrap/bootstrap.min.css" />--> <!--<link rel="stylesheet" href="_content/RBLNews.Shared/css/bootstrap/bootstrap.min.css" />-->
<!-- <link rel="stylesheet" href="_content/Blazor.Bootstrap/Blazor.Bootstrap.bundle.scp.css" />-->
<link rel="stylesheet" href="_content/RBLNews.Shared/css/app.css" /> <link rel="stylesheet" href="_content/RBLNews.Shared/css/app.css" />
<link rel="stylesheet" href="RBLNews.Maui.styles.css" />
<link rel="icon" type="image/ico" href="favicon.ico" /> <link rel="icon" type="image/ico" href="favicon.ico" />
</head> </head>

View File

@ -1,12 +1,13 @@
@using RBLFeederCommon.Enums @using RBLFeederCommon.Enums
@if (ShowCount)
{ <Button Size="ButtonSize.Small" Type="ButtonType.Button" @onclick="OnClicked" Color="ButtonColor.Primary" Outline="@outline" Position="Position.Relative">
<Button Color="ButtonColor.Info" Size="ButtonSize.Small" Clicked="@OnClicked()" Outline>@Text <small>@Count</small></Button> @Text
} <Badge Color="BadgeColor.Info"
else Position="Position.Absolute"
{ Placement="BadgePlacement.TopRight"
<Button Size="ButtonSize.Small">@Text</Button> IndicatorType="BadgeIndicatorType.RoundedPill"
} VisuallyHiddenText="Anz. News">@Count</Badge>
</Button>
@code { @code {
@ -14,7 +15,7 @@ else
public RssFeedSources Source { get; set; } public RssFeedSources Source { get; set; }
[Parameter] [Parameter]
public string Text { get; set; } public string Text { get; set; } = "";
[Parameter] [Parameter]
public bool ShowCount { get; set; } public bool ShowCount { get; set; }
@ -25,14 +26,15 @@ else
[Parameter] [Parameter]
public EventCallback<RssFeedSources> OnClickedCallback { get; set; } public EventCallback<RssFeedSources> OnClickedCallback { get; set; }
protected override void OnInitialized() bool outline = true;
{
base.OnInitialized();
}
private async Task OnClicked() Task OnClicked()
{ {
await OnClickedCallback.InvokeAsync(Source); outline = !outline;
OnClickedCallback.InvokeAsync(Source);
return Task.CompletedTask;
} }
} }

View File

@ -13,7 +13,7 @@
} }
else else
{ {
<text>Letztes Update @FeedDataService.Feeds?.LastUpdate.ToString("dd.MM.yyyy HH:mm")</text> <text>Letzter Check: @FeedDataService.Feeds?.LastUpdate.ToString("dd.MM.yyyy HH:mm")</text>
} }
</div> </div>
</div> </div>

View File

@ -10,125 +10,155 @@
@if (FeedGroups == null) @if (FeedGroups == null)
{ {
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
Lade Feeds ...<br /><br /> <Spinner Type="SpinnerType.Grow" Color="SpinnerColor.Primary" Size="SpinnerSize.Large"/>
<Spinner Type="SpinnerType.Grow" Color="SpinnerColor.Primary" Size="SpinnerSize.Large" /> </div>
</div>
} }
else else
{ {
<br /> <div id="feeds-page">
<div id="feeds-page" class="row"> <div class="container-fluid">
<div class="container"> <section id="filter">
<div class="FilterButtons"> @foreach (IGrouping<int, int> sGrouping in SourceGroupings)
@foreach (IGrouping<int, int> sGrouping in SourceGroupings) {
{ <BadgeWithCounter
@* <BadgeWithCounter ShowCount="true" Source="(RssFeedSources)sGrouping.Key" OnClickedCallback="OnClicked" Text="@GetRssSourceName((RssFeedSources)sGrouping.Key)" Count="@sGrouping.Count()"></BadgeWithCounter> *@ ShowCount="true"
} Source="(RssFeedSources)sGrouping.Key"
</div> OnClickedCallback="OnClicked"
@foreach (FeedGroupVM feedGrp in FeedGroups) Text="@GetRssSourceName((RssFeedSources)sGrouping.Key)"
{ Count="@sGrouping.Count()">
<h4><Icon Name="IconName.Calendar2Event" /> @feedGrp.PublishDate.ToLocalTime().ToString("dd.MM.yyyy")</h4> </BadgeWithCounter>
@foreach (FeedVM feed in feedGrp.Feeds) }
{ </section>
<div class="col-xs-12 col-sm-12 col-md-8 col-lg-4"> <section id="feeds-list">
<Card> @foreach (FeedGroupVM feedGrp in FeedGroups)
<CardBody> {
<CardTitle>@feed.Title</CardTitle> <h1>
<CardText>@feed.Description</CardText> <Icon Name="IconName.Calendar2Event"/> @feedGrp.PublishDate.ToLocalTime().ToString("dd.MM.yyyy")
</CardBody> </h1>
<ul class="list-group list-group-flush"> @foreach (FeedVM feed in feedGrp.Feeds)
<li class="list-group-item"> {
@GetRssSourceName((RssFeedSources)@feed.Source) | @feed.PubDate?.ToLocalTime() <div class="col-xs-12 col-sm-12 col-md-8 col-lg-4">
</li> <Card>
</ul> <CardBody>
<CardFooter> <CardTitle>@feed.Title</CardTitle>
<div class="row"> <CardText>@feed.Description</CardText>
<Button Color="ButtonColor.Primary" Class="btn-sm align-self-end ml-auto" To="@feed.Link" Type="ButtonType.Link"><Icon Name="IconName.Link" /> Öffnen</Button> <div class="row">
</div> <Button Outline="true" Color="ButtonColor.Primary" Class="btn-sm align-self-end ml-auto" To="@feed.Link" Type="ButtonType.Link"><Icon Name="IconName.Link"/> Öffnen</Button>
</CardFooter> </div>
</Card> </CardBody>
<br /> @* <ul class="list-group list-group-flush"> *@
</div> @* <li class="list-group-item"> *@
@* <div class="row"> *@
@* <Button Outline="true" Color="ButtonColor.Primary" Class="btn-sm align-self-end ml-auto" To="@feed.Link" Type="ButtonType.Link"><Icon Name="IconName.Link"/> Öffnen</Button> *@
@* </div> *@
@* </li> *@
@* </ul> *@
<CardFooter>
} @GetRssSourceName((RssFeedSources)@feed.Source) | @feed.PubDate?.ToLocalTime()
}
</div> </CardFooter>
</div> </Card>
<br/>
</div>
}
}
</section>
</div>
</div>
} }
@code { @code {
[Inject] [Inject] private IFeedDataService FeedDataService { get; set; }
private IFeedDataService FeedDataService { get; set; }
[Inject] [Inject] private AppLifecycleService AppLifecycleService { get; set; }
private AppLifecycleService AppLifecycleService { get; set; }
private List<FeedGroupVM>? FeedGroups { get; set; } private List<FeedGroupVM>? FeedGroups { get; set; }
private IEnumerable<IGrouping<int, int>> SourceGroupings { get; set; } = new List<IGrouping<int, int>>(); private IEnumerable<IGrouping<int, int>> SourceGroupings { get; set; } = new List<IGrouping<int, int>>();
protected override void OnInitialized() private List<RssFeedSources> activeFilters = new List<RssFeedSources>();
{
AppLifecycleService.OnActivated = LoadFeeds;
LoadFeeds();
}
private async void LoadFeeds() protected override void OnInitialized()
{ {
// Copy feed list to keep original list AppLifecycleService.OnActivated = LoadFeeds;
await FeedDataService.LoadFeeds();
FeedGroups = [..FeedDataService.Feeds.FeedGroups];
List<FeedGroupVM> listTmp = [.. FeedDataService.Feeds.FeedGroups]; LoadFeeds();
}
SourceGroupings = listTmp.SelectMany(fg => fg.Feeds.Select(f => f.Source)).GroupBy(sources => sources);
StateHasChanged(); private async void LoadFeeds()
} {
// Copy feed list to keep original list
await FeedDataService.LoadFeeds();
FeedGroups = [.. FeedDataService.Feeds.FeedGroups];
private string GetRssSourceName(RssFeedSources source) List<FeedGroupVM> listTmp = [.. FeedDataService.Feeds.FeedGroups];
{
switch (source)
{
case RssFeedSources.RbLive:
case RssFeedSources.NitterRbLive:
return "RBLive!";
case RssFeedSources.NitterFabrizioRomano:
return "Fabrizio Romano";
case RssFeedSources.Lvz:
return "LVZ";
case RssFeedSources.Kicker:
return "Kicker";
case RssFeedSources.Bild:
return "BILD";
case RssFeedSources.Transfermarkt:
return "Transfermarkt";
default:
return "?";
}
}
private void OnClicked(RssFeedSources source) SourceGroupings = listTmp.SelectMany(fg => fg.Feeds.Select(f => f.Source)).GroupBy(sources => sources);
{
FeedGroups = new List<FeedGroupVM>();
foreach (FeedGroupVM fg in FeedDataService.Feeds.FeedGroups) StateHasChanged();
{ }
List<FeedVM> feeds = fg.Feeds.Where(f => (RssFeedSources)f.Source == source).ToList();
if (feeds.Any())
{ private string GetRssSourceName(RssFeedSources source)
FeedGroups.Add(new FeedGroupVM {
{ switch (source)
Feeds = feeds, {
PublishDate = fg.PublishDate case RssFeedSources.RbLive:
}); case RssFeedSources.NitterRbLive:
return "RBLive!";
case RssFeedSources.NitterFabrizioRomano:
return "Fabrizio Romano";
case RssFeedSources.Lvz:
return "LVZ";
case RssFeedSources.Kicker:
return "Kicker";
case RssFeedSources.Bild:
return "BILD";
case RssFeedSources.Transfermarkt:
return "Transfermarkt";
default:
return "?";
}
}
private void OnClicked(RssFeedSources source)
{
if (activeFilters.Contains(source))
activeFilters.Remove(source);
else
{
activeFilters.Add(source);
}
if (!activeFilters.Any())
{
FeedGroups = [.. FeedDataService.Feeds.FeedGroups];
return;
}
FeedGroups = new List<FeedGroupVM>();
foreach (FeedGroupVM fg in FeedDataService.Feeds.FeedGroups)
{
List<FeedVM> feeds = fg.Feeds.Where(f => activeFilters.Contains((RssFeedSources)f.Source)).ToList();
if (feeds.Any())
{
FeedGroups.Add(
new FeedGroupVM
{
Feeds = feeds,
PublishDate = fg.PublishDate
});
}
}
StateHasChanged();
}
}
}
StateHasChanged();
}
} }

View File

@ -1,5 +1,6 @@
/** /**
rot: #DD0741 rot: #DD0741
schrift: #4b4b4b
*/ */
@font-face { @font-face {
@ -9,11 +10,27 @@ rot: #DD0741
src: url('../fonts/NanumMyeongjo-Regular.ttf'); src: url('../fonts/NanumMyeongjo-Regular.ttf');
} }
h1, h2, h3, h4, h5, h6, h7 { #feeds-page {
color: rgb(221, 7, 65) !important; color: #4b4b4b;
}
.card {
color: #4b4b4b;
font-size: 1em;
}
.card .card-title {
color: #DD0741;
font-size: 1em;
text-transform: uppercase; text-transform: uppercase;
} }
.card .card-footer {
color: #4b4b4b;
background-color: #fff;
font-size: 0.8em;
}
nav .container-fluid { nav .container-fluid {
padding-right: 0px !important; padding-right: 0px !important;
padding-left: 0px !important; padding-left: 0px !important;
@ -22,14 +39,55 @@ nav .container-fluid {
nav .top-row { nav .top-row {
height: 1.8rem; height: 1.8rem;
background-color: rgb(221, 7, 65); background-color: rgb(221, 7, 65);
color: #eee !important; color: #eee;
} }
nav .top-row h1, h2, h3, h4, h5 { /*nav .top-row h1, h2, h3, h4, h5 {*/
color: #eee !important; /* color: #eee;*/
} /*}*/
#filter button {
margin-top: 13px;
margin-bottom: 13px;
margin-right: 16px;
}
/*#feeds-page #feeds-list h1, h2, h3, h4, h5 {*/
/* color: rgb(221, 7, 65);*/
/* text-transform: uppercase;*/
/*}*/
.btn-primary {
color: #fff;
background-color: #f75581;
border-color: #DD0741;
}
.btn-primary:hover {
color: #fff;
background-color: #DD0741;
border-color: #DD0741;
}
.btn-outline-primary {
color: #DD0741;
background-color: #fff;
border-color: #DD0741;
}
.btn-outline-primary:hover {
color: #fff;
background-color: #DD0741;
border-color: #DD0741;
}
.text-bg-info {
color: #DD0741 !important;
background-color: #fff !important;
border-top: 1px solid #DD0741 !important;
border-right: 1px solid #DD0741 !important;
}
.navbar-toggler { .navbar-toggler {
appearance: none; appearance: none;
cursor: pointer; cursor: pointer;
@ -131,9 +189,6 @@ nav .top-row {
.list-group-item {
font-size: 0.8rem !important;
}
.loading { .loading {
position: absolute; position: absolute;
@ -146,13 +201,6 @@ nav .top-row {
border-color: rgb(221, 7, 65); border-color: rgb(221, 7, 65);
} }
.btn-primary {
background-color: #fff !important;
color: rgb(221, 7, 65) !important;
border: 1px solid rgb(221, 7, 65) !important;
}
.valid.modified:not([type=checkbox]) { .valid.modified:not([type=checkbox]) {
outline: 1px solid #26b050; outline: 1px solid #26b050;
} }
@ -214,14 +262,6 @@ nav .top-row {
} }
} }
.FilterButtons {
margin: 10px;
}
#feeds-page h4, h5 {
color: rgb(221, 7, 65) !important;
text-transform: uppercase;
}
/*html, body { /*html, body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;

View File

@ -7,11 +7,11 @@
<base href="/" /> <base href="/" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet" /> <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet" />
<link href="_content/RBLNews.Shared/blazor.bootstrap.css" rel="stylesheet" /> @* <link href="_content/RBLNews.Shared/blazor.bootstrap.css" rel="stylesheet" /> *@
@* <link rel="stylesheet" href="_content/RBLNews.Shared/css/bootstrap/bootstrap.min.css" /> *@ @* <link rel="stylesheet" href="_content/RBLNews.Shared/css/bootstrap/bootstrap.min.css" /> *@
@* <link rel="stylesheet" href="RBLNews.Web.styles.css" /> *@
<link rel="stylesheet" href="_content/RBLNews.Shared/css/app.css" /> <link rel="stylesheet" href="_content/RBLNews.Shared/css/app.css" />
<link rel="stylesheet" href="RBLNews.Web.styles.css" />
<HeadOutlet @rendermode="InteractiveServer" /> <HeadOutlet @rendermode="InteractiveServer" />
</head> </head>